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