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

223 lines
12 KiB
Markdown

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