sal/src/virt/nerdctl/README.md
timurgordon 65e404e517
Some checks are pending
Rhai Tests / Run Rhai Tests (push) Waiting to run
merge branches and document
2025-05-23 21:12:17 +03:00

12 KiB

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.

// 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<String>: ID of the container (populated after creation).
  • image: Option<String>: Base image for the container.
  • ports: Vec<String>: Port mappings (e.g., "8080:80").
  • volumes: Vec<String>: Volume mounts (e.g., "/host/path:/container/path").
  • env_vars: HashMap<String, String>: Environment variables.
  • network: Option<String>: Network to connect to.
  • network_aliases: Vec<String>: Network aliases.
  • cpu_limit: Option<String>, memory_limit: Option<String>, memory_swap_limit: Option<String>, cpu_shares: Option<String>: Resource limits.
  • restart_policy: Option<String>: Restart policy (e.g., "always").
  • health_check: Option<HealthCheck>: Health check configuration.
  • detach: bool: Whether to run in detached mode (default: false, but Rhai container_build implies true often).
  • snapshotter: Option<String>: 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<String>
  • timeout: Option<String>
  • retries: Option<u32>
  • start_period: Option<String>

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_<container_name>.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<CommandResult, NerdctlError>: 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 <tag> <context_path>).

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)

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)

// 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.