- Migrate individual modules to independent crates - Refactor dependencies for improved modularity - Update build system and testing infrastructure - Update documentation to reflect new structure
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 
rfscommand-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 fromsuper::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, andwebdavthrough therfstool's capabilities. - Layer Management: Provides functionalities to 
packdirectories into portable layers,unpackthem,list_contents, andverifytheir integrity. This is useful for creating and managing reproducible filesystem snapshots or components. - Store Specifications (
StoreSpec): The packing functionality allows specifyingStoreSpectypes, 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 
RfsBuilderfor constructing mount commands with various options andPackBuilderfor packing operations, providing a fluent interface for complex configurations. - Rhai Scriptability: Most functionalities are exposed to Rhai scripts via 
herodothrough thesal::rhai::rfsbridge, enabling automation of filesystem and layer management tasks. - Structured Error Handling: Defines 
RfsErrorfor specific error conditions encountered duringrfscommand 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.
 
 - Lists all currently mounted filesystems managed by 
 - 
rfs_unmount_all() -> ()- Unmounts all filesystems currently managed by 
rfs. 
 - Unmounts all filesystems currently managed by 
 - 
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 
directoryinto anoutputfile (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 istype:key=value,key2=value2.
 - Packs the contents of a 
 - 
rfs_unpack(input: String, directory: String) -> ()- Unpacks an 
inputlayer file into the specifieddirectory. 
 - Unpacks an 
 - 
rfs_list_contents(input: String) -> String- Lists the contents of an 
inputlayer file. - Returns a string containing the file listing (raw output from the 
rfstool). 
 - Lists the contents of an 
 - 
rfs_verify(input: String) -> bool- Verifies the integrity of an 
inputlayer file. - Returns 
trueif the layer is valid,falseotherwise. 
 - Verifies the integrity of an 
 
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.