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

166 lines
7.8 KiB
Markdown

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