sal/src/virt/rfs/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

7.8 KiB

SAL RFS (Remote File System) Module (sal::virt::rfs)

Overview

The sal::virt::rfs module provides a Rust interface for interacting with an underlying rfs command-line tool. This tool facilitates mounting various types of remote and local filesystems and managing packed filesystem layers.

The module allows Rust applications and herodo Rhai scripts to:

  • Mount and unmount filesystems from different sources (e.g., local paths, SSH, S3, WebDAV).
  • List currently mounted filesystems and retrieve information about specific mounts.
  • Pack directories into filesystem layers, potentially using specified storage backends.
  • Unpack, list contents of, and verify these filesystem layers.

All operations are performed by invoking the rfs CLI tool and parsing its output.

Key Design Points

  • CLI Wrapper: This module acts as a wrapper around an external rfs command-line utility. The actual filesystem operations and layer management are delegated to this tool.
  • Asynchronous Operations (Implicit): While the Rust functions themselves might be synchronous, the underlying execute_rfs_command (presumably from super::cmd) likely handles command execution, which could be asynchronous or blocking depending on its implementation.
  • Filesystem Abstraction: Supports mounting diverse filesystem types such as local, ssh, s3, and webdav through the rfs tool's capabilities.
  • Layer Management: Provides functionalities to pack directories into portable layers, unpack them, list_contents, and verify their integrity. This is useful for creating and managing reproducible filesystem snapshots or components.
  • Store Specifications (StoreSpec): The packing functionality allows specifying StoreSpec types, suggesting that packed layers can be stored or referenced using different backend mechanisms (e.g., local files, S3 buckets). This enables flexible storage and retrieval of filesystem layers.
  • Builder Pattern: Uses RfsBuilder for constructing mount commands with various options and PackBuilder for packing operations, providing a fluent interface for complex configurations.
  • Rhai Scriptability: Most functionalities are exposed to Rhai scripts via herodo through the sal::rhai::rfs bridge, enabling automation of filesystem and layer management tasks.
  • Structured Error Handling: Defines RfsError for specific error conditions encountered during rfs command execution or output parsing.

Rhai Scripting with herodo

The sal::virt::rfs module is scriptable via herodo. The following functions are available in Rhai, prefixed with rfs_:

Mount Operations

  • rfs_mount(source: String, target: String, mount_type: String, options: Map) -> Map

    • Mounts a filesystem.
    • source: The source path or URL (e.g., /path/to/local_dir, ssh://user@host:/remote/path, s3://bucket/key).
    • target: The local path where the filesystem will be mounted.
    • mount_type: A string specifying the type of filesystem (e.g., "local", "ssh", "s3", "webdav").
    • options: A Rhai map of additional mount options (e.g., #{ "read_only": true, "uid": 1000 }).
    • Returns a map containing details of the mount (id, source, target, fs_type, options) on success.
  • rfs_unmount(target: String) -> ()

    • Unmounts the filesystem at the specified target path.
  • rfs_list_mounts() -> Array

    • Lists all currently mounted filesystems managed by rfs.
    • Returns an array of maps, each representing a mount with its details.
  • rfs_unmount_all() -> ()

    • Unmounts all filesystems currently managed by rfs.
  • rfs_get_mount_info(target: String) -> Map

    • Retrieves information about a specific mounted filesystem.
    • Returns a map with mount details if found.

Pack/Layer Operations

  • rfs_pack(directory: String, output: String, store_specs: String) -> ()

    • Packs the contents of a directory into an output file (layer).
    • store_specs: A comma-separated string defining storage specifications for the layer (e.g., "file:path=/path/to/local_store,s3:bucket=my-archive,region=us-west-1"). Each spec is type:key=value,key2=value2.
  • rfs_unpack(input: String, directory: String) -> ()

    • Unpacks an input layer file into the specified directory.
  • rfs_list_contents(input: String) -> String

    • Lists the contents of an input layer file.
    • Returns a string containing the file listing (raw output from the rfs tool).
  • rfs_verify(input: String) -> bool

    • Verifies the integrity of an input layer file.
    • Returns true if the layer is valid, false otherwise.

Rhai Example

// Example: Mounting a local directory (ensure /mnt/my_local_mount exists)
let source_dir = "/tmp/my_data_source"; // Create this directory first
let target_mount = "/mnt/my_local_mount";

// Create source_dir if it doesn't exist for the example to run
// In a real script, you might use sal::os::dir_create or ensure it exists.
// For this example, assume it's manually created or use: os_run_command(`mkdir -p ${source_dir}`);

print(`Mounting ${source_dir} to ${target_mount}...`);
let mount_result = rfs_mount(source_dir, target_mount, "local", #{});
if mount_result.is_ok() {
    print(`Mount successful: ${mount_result}`);
} else {
    print(`Mount failed: ${mount_result}`);
}

// List mounts
print("\nCurrent mounts:");
let mounts = rfs_list_mounts();
if mounts.is_ok() {
    for m in mounts {
        print(`  Target: ${m.target}, Source: ${m.source}, Type: ${m.fs_type}`);
    }
} else {
    print(`Error listing mounts: ${mounts}`);
}

// Example: Packing a directory
let dir_to_pack = "/tmp/pack_this_dir"; // Create and populate this directory
let packed_file = "/tmp/my_layer.pack";
// os_run_command(`mkdir -p ${dir_to_pack}`); 
// os_run_command(`echo 'hello' > ${dir_to_pack}/file1.txt`);

print(`\nPacking ${dir_to_pack} to ${packed_file}...`);
// Using a file-based store spec for simplicity
let pack_store_specs = "file:path=/tmp/rfs_store"; 
// os_run_command(`mkdir -p /tmp/rfs_store`);

let pack_result = rfs_pack(dir_to_pack, packed_file, pack_store_specs);
if pack_result.is_ok() {
    print("Packing successful.");

    // List contents of the packed file
    print(`\nContents of ${packed_file}:`);
    let contents = rfs_list_contents(packed_file);
    if contents.is_ok() {
        print(contents);
    } else {
        print(`Error listing contents: ${contents}`);
    }

    // Verify the packed file
    print(`\nVerifying ${packed_file}...`);
    let verify_result = rfs_verify(packed_file);
    if verify_result.is_ok() && verify_result {
        print("Verification successful: Layer is valid.");
    } else {
        print(`Verification failed or error: ${verify_result}`);
    }

    // Example: Unpacking
    let unpack_dir = "/tmp/unpacked_layer_here";
    // os_run_command(`mkdir -p ${unpack_dir}`);
    print(`\nUnpacking ${packed_file} to ${unpack_dir}...`);
    let unpack_result = rfs_unpack(packed_file, unpack_dir);
    if unpack_result.is_ok() {
        print("Unpacking successful.");
        // You would typically check contents of unpack_dir here
        // os_run_command(`ls -la ${unpack_dir}`);
    } else {
        print(`Error unpacking: ${unpack_result}`);
    }

} else {
    print(`Error packing: ${pack_result}`);
}

// Cleanup: Unmount the local mount
if mount_result.is_ok() {
    print(`\nUnmounting ${target_mount}...`);
    rfs_unmount(target_mount);
}

// To run this example, ensure the 'rfs' command-line tool is installed and configured,
// and that the necessary directories (/tmp/my_data_source, /mnt/my_local_mount, etc.)
// exist and have correct permissions.
// You might need to run herodo with sudo for mount/unmount operations.

print("\nRFS Rhai script finished.");

This module provides a flexible way to manage diverse filesystems and filesystem layers, making it a powerful tool for system automation and deployment tasks within the SAL ecosystem.