# 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<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)

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