# SAL `nerdctl` Module (`sal::virt::nerdctl`) ## Overview The `sal::virt::nerdctl` module provides a comprehensive Rust interface for interacting with `nerdctl`, a command-line tool for `containerd`. It allows for managing container lifecycles, images, and other `nerdctl` functionalities programmatically from Rust and through Rhai scripts via `herodo`. This module offers two primary ways to interact with `nerdctl`: 1. A fluent **`Container` builder pattern** for defining, creating, and managing containers with detailed configurations. 2. **Direct static functions** that wrap common `nerdctl` commands for quick operations on containers and images. ## Core Components ### 1. `NerdctlError` (in `mod.rs`) An enum defining specific error types for `nerdctl` operations: - `CommandExecutionFailed(io::Error)`: `nerdctl` command failed to start (e.g., not found). - `CommandFailed(String)`: `nerdctl` command executed but returned an error. - `JsonParseError(String)`: Failure to parse JSON output from `nerdctl`. - `ConversionError(String)`: Error during data type conversions. - `Other(String)`: Generic errors. ### 2. `execute_nerdctl_command` (in `cmd.rs`) The core function for executing `nerdctl` commands. It takes an array of string arguments, runs the command, and returns a `CommandResult` or `NerdctlError`. ```rust // Example (internal usage) // use sal::virt::nerdctl::execute_nerdctl_command; // let result = execute_nerdctl_command(&["ps", "-a"]); ``` ### 3. `Container` Struct (defined in `container_types.rs`, builder in `container_builder.rs`, operations in `container_operations.rs`) Represents a `nerdctl` container and is the centerpiece of the builder pattern. **Fields (Configuration):** - `name: String`: Name of the container. - `container_id: Option`: ID of the container (populated after creation). - `image: Option`: Base image for the container. - `ports: Vec`: Port mappings (e.g., `"8080:80"`). - `volumes: Vec`: Volume mounts (e.g., `"/host/path:/container/path"`). - `env_vars: HashMap`: Environment variables. - `network: Option`: Network to connect to. - `network_aliases: Vec`: Network aliases. - `cpu_limit: Option`, `memory_limit: Option`, `memory_swap_limit: Option`, `cpu_shares: Option`: Resource limits. - `restart_policy: Option`: Restart policy (e.g., `"always"`). - `health_check: Option`: Health check configuration. - `detach: bool`: Whether to run in detached mode (default: `false`, but Rhai `container_build` implies `true` often). - `snapshotter: Option`: Snapshotter to use. **Builder Methods (Fluent Interface - `impl Container` in `container_builder.rs`):** These methods configure the `Container` object and return `Self` for chaining. - `Container::new(name: &str, image: &str)`: Constructor (Note: Rhai uses `nerdctl_container_new(name)` and `nerdctl_container_from_image(name, image)` which call underlying Rust constructors). - `reset()`: Resets configuration, stops/removes existing container with the same name. - `with_port(port: &str)`, `with_ports(ports: &[&str])` - `with_volume(volume: &str)`, `with_volumes(volumes: &[&str])` - `with_env(key: &str, value: &str)`, `with_envs(env_map: &HashMap<&str, &str>)` - `with_network(network: &str)` - `with_network_alias(alias: &str)`, `with_network_aliases(aliases: &[&str])` - `with_cpu_limit(cpus: &str)` - `with_memory_limit(memory: &str)` - `with_memory_swap_limit(memory_swap: &str)` - `with_cpu_shares(shares: &str)` - `with_restart_policy(policy: &str)` - `with_health_check(cmd: &str)` - `with_health_check_options(cmd, interval, timeout, retries, start_period)` - `with_snapshotter(snapshotter: &str)` - `with_detach(detach: bool)` **Action Methods (on `Container` instances): - `build()` (in `container_builder.rs`): Assembles and executes `nerdctl run` with all configured options. Populates `container_id` on success. - `start()` (in `container_operations.rs`): Starts the container. If not yet built, it attempts to pull the image and build the container first. Verifies the container is running and provides detailed logs/status on failure. - `stop()` (in `container_operations.rs`): Stops the container. - `remove()` (in `container_operations.rs`): Removes the container. - `exec(command: &str)` (in `container_operations.rs`): Executes a command in the container. - `copy(source: &str, dest: &str)` (in `container_operations.rs`): Copies files/folders. `source`/`dest` must be formatted like `container_name_or_id:/path` or `/local/path`. - `status()` (in `container_operations.rs`): Returns `ContainerStatus` by parsing `nerdctl inspect`. - `health_status()` (in `container_operations.rs`): Returns the health status string from `nerdctl inspect`. - `logs()` (in `container_operations.rs`): Fetches container logs. - `resources()` (in `container_operations.rs`): Returns `ResourceUsage` by parsing `nerdctl stats`. - `commit(image_name: &str)` (in `container_operations.rs`): Commits the container to a new image. - `export(path: &str)` (in `container_operations.rs`): Exports the container's filesystem as a tarball. ### 4. `HealthCheck` Struct (in `container_types.rs`) Defines health check parameters: - `cmd: String`: Command to execute. - `interval: Option` - `timeout: Option` - `retries: Option` - `start_period: Option` ### 5. `prepare_health_check_command` (in `health_check_script.rs`) A helper function that takes a health check command string. If it's multi-line, it attempts to save it as an executable script in `/root/hero/var/containers/healthcheck_.sh` and returns the script path. Otherwise, returns the command as is. The path `/root/hero/var/containers` implies this script needs to be accessible from within the target container at that specific location if a multi-line script is used. ### 6. `Image` Struct (in `images.rs`) Represents a `nerdctl` image, typically from `nerdctl images` output. - `id: String` - `repository: String` - `tag: String` - `size: String` - `created: String` ### 7. Static Image Functions (in `images.rs`) These functions operate on images: - `images() -> Result`: Lists images (`nerdctl images`). - `image_remove(image: &str)`: Removes an image (`nerdctl rmi`). - `image_push(image: &str, destination: &str)`: Pushes an image (`nerdctl push`). - `image_tag(image: &str, new_name: &str)`: Tags an image (`nerdctl tag`). - `image_pull(image: &str)`: Pulls an image (`nerdctl pull`). - `image_commit(container: &str, image_name: &str)`: Commits a container to an image (`nerdctl commit`). - `image_build(tag: &str, context_path: &str)`: Builds an image from a Dockerfile (`nerdctl build -t `). ### 8. Static Container Functions (in `container_functions.rs`) Direct wrappers for `nerdctl` commands, an alternative to the builder pattern: - `run(image: &str, name: Option<&str>, detach: bool, ports: Option<&[&str]>, snapshotter: Option<&str>)`: Runs a container. - `exec(container: &str, command: &str)`: Executes a command in a running container. - `copy(source: &str, dest: &str)`: Copies files. - `stop(container: &str)`: Stops a container. - `remove(container: &str)`: Removes a container. - `list(all: bool)`: Lists containers (`nerdctl ps`). - `logs(container: &str)`: Fetches logs for a container. ### 9. `ContainerStatus` and `ResourceUsage` Structs (in `container_types.rs`) - `ContainerStatus`: Holds parsed data from `nerdctl inspect` (state, status, created, started, health info). - `ResourceUsage`: Holds parsed data from `nerdctl stats` (CPU, memory, network, block I/O, PIDs). ## Usage Examples ### Rust Example (Builder Pattern) ```rust use sal::virt::nerdctl::{Container, NerdctlError}; use std::collections::HashMap; fn main() -> Result<(), NerdctlError> { let mut envs = HashMap::new(); envs.insert("MY_VAR", "my_value"); let container_config = Container::new("my_nginx_container", "nginx:latest") // Assuming a constructor like this exists or is adapted .with_port("8080:80") .with_envs(&envs) .with_detach(true) .with_restart_policy("always"); // Build (create and run) the container let built_container = container_config.build()?; println!("Container {} created with ID: {:?}", built_container.name, built_container.container_id); // Perform operations let status = built_container.status()?; println!("Status: {}, State: {}", status.status, status.state); // Stop and remove built_container.stop()?; built_container.remove()?; println!("Container stopped and removed."); Ok(()) } ``` *Note: The direct `Container::new(name, image)` constructor isn't explicitly shown in the provided Rust code snippets for `Container` itself, but the Rhai bindings `nerdctl_container_new` and `nerdctl_container_from_image` imply underlying Rust constructors that initialize a `Container` struct. The `build()` method is the primary way to run it after configuration.* ### Rhai Script Example (using `herodo`) ```rhai // Create and configure a container using the builder pattern let c = nerdctl_container_from_image("my_redis", "redis:alpine") .with_port("6379:6379") .with_restart_policy("unless-stopped"); // Build and run the container let running_container = c.build(); if running_container.is_ok() { print(`Container ${running_container.name} ID: ${running_container.container_id}`); // Get status let status = running_container.status(); if status.is_ok() { print(`Status: ${status.state}, Health: ${status.health_status}`); } // Stop the container (example, might need a mutable borrow or re-fetch) // running_container.stop(); // Assuming stop is available and works on the result // running_container.remove(); } else { print(`Error building container: ${running_container.error()}`); } // Direct command example let images = nerdctl_images(); print(images.stdout); nerdctl_image_pull("alpine:latest"); ``` ## Key Design Points - **Fluent Builder**: The `Container` struct uses a builder pattern, allowing for clear and chainable configuration of container parameters before execution. - **Comprehensive Operations**: Covers most common `nerdctl` functionalities for containers and images. - **Error Handling**: `NerdctlError` provides typed errors. The Rhai layer adds more descriptive error messages for common scenarios. - **Dual API**: Offers both a detailed builder pattern and simpler static functions for flexibility. - **Health Check Scripting**: Supports multi-line shell scripts for health checks by saving them to a file, though care must be taken regarding the script's accessibility from within the target container. - **Resource Parsing**: Includes parsing for `nerdctl inspect` (JSON) and `nerdctl stats` (tabular text) to provide structured information. ## File Structure - `src/virt/nerdctl/mod.rs`: Main module file, error definitions, sub-module declarations. - `src/virt/nerdctl/cmd.rs`: Core `execute_nerdctl_command` function. - `src/virt/nerdctl/container_types.rs`: Definitions for `Container`, `HealthCheck`, `ContainerStatus`, `ResourceUsage`. - `src/virt/nerdctl/container_builder.rs`: Implements the builder pattern methods for the `Container` struct. - `src/virt/nerdctl/container_operations.rs`: Implements instance methods on `Container` (start, stop, status, etc.). - `src/virt/nerdctl/images.rs`: `Image` struct and static functions for image management. - `src/virt/nerdctl/container_functions.rs`: Static functions for direct container commands. - `src/virt/nerdctl/health_check_script.rs`: Logic for `prepare_health_check_command`. - `src/rhai/nerdctl.rs`: Rhai script bindings for `herodo`.