...
This commit is contained in:
		| @@ -23,6 +23,7 @@ members = [ | ||||
|     "zinit_client", | ||||
|     "process", | ||||
|     "virt", | ||||
|     "zos", | ||||
|     "postgresclient", | ||||
|     "kubernetes", | ||||
|     "rhai", | ||||
|   | ||||
							
								
								
									
										37
									
								
								zos/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								zos/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| [package] | ||||
| name = "zos-slicer" | ||||
| version = "0.1.0" | ||||
| edition = "2021" | ||||
| authors = ["PlanetFirst <info@incubaid.com>"] | ||||
| description = "ZOS Talos Slicer - VM provisioning tool for Talos OS with Cloud Hypervisor" | ||||
|  | ||||
| [[bin]] | ||||
| name = "talos-slicer" | ||||
| path = "src/main.rs" | ||||
|  | ||||
| [dependencies] | ||||
| # CLI and argument parsing | ||||
| clap = { version = "4.0", features = ["derive"] } | ||||
|  | ||||
| # System information | ||||
| sysinfo = "0.30" | ||||
|  | ||||
| # Network utilities | ||||
| ipnetwork = "0.20" | ||||
|  | ||||
| # Error handling | ||||
| anyhow = "1.0" | ||||
| thiserror = "2.0" | ||||
|  | ||||
| # Serialization for Talos config | ||||
| serde = { version = "1.0", features = ["derive"] } | ||||
| serde_json = "1.0" | ||||
| serde_yaml = "0.9" | ||||
|  | ||||
| # UUID generation | ||||
| uuid = { version = "1.0", features = ["v4"] } | ||||
|  | ||||
| # SAL dependencies (relative paths) | ||||
| sal-os = { path = "../os" } | ||||
| sal-process = { path = "../process" } | ||||
| sal-net = { path = "../net" } | ||||
							
								
								
									
										43
									
								
								zos/src/slicer/cli.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								zos/src/slicer/cli.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| use clap::{Parser, Subcommand}; | ||||
|  | ||||
| #[derive(Debug, Parser)] | ||||
| #[command(name = "talos-slicer")] | ||||
| #[command(author = "PlanetFirst <info@incubaid.com>")] | ||||
| #[command(version = "0.1.0")] | ||||
| #[command(about = "ZOS Talos Slicer - VM provisioning tool for Talos OS with Cloud Hypervisor", long_about = None)] | ||||
| pub struct Cli { | ||||
|     #[command(subcommand)] | ||||
|     pub command: Commands, | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Subcommand)] | ||||
| pub enum Commands { | ||||
|     /// Create a new Talos VM | ||||
|     Create { | ||||
|         /// Name of the VM | ||||
|         #[arg(short, long)] | ||||
|         name: String, | ||||
|  | ||||
|         /// Number of vCPUs | ||||
|         #[arg(long, default_value_t = 1)] | ||||
|         cpus: u8, | ||||
|  | ||||
|         /// Memory size in MB | ||||
|         #[arg(long, default_value_t = 512)] | ||||
|         memory: u32, | ||||
|     }, | ||||
|     /// Delete a Talos VM | ||||
|     Delete { | ||||
|         /// Name of the VM to delete | ||||
|         #[arg(short, long)] | ||||
|         name: String, | ||||
|     }, | ||||
|     /// List all Talos VMs | ||||
|     List, | ||||
|     /// Get information about a specific Talos VM | ||||
|     Info { | ||||
|         /// Name of the VM | ||||
|         #[arg(short, long)] | ||||
|         name: String, | ||||
|     }, | ||||
| } | ||||
							
								
								
									
										28
									
								
								zos/src/slicer/error.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								zos/src/slicer/error.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| use thiserror::Error; | ||||
|  | ||||
| /// A specialized `Result` type for slicer operations. | ||||
| pub type Result<T> = std::result::Result<T, SlicerError>; | ||||
|  | ||||
| /// The error type for slicer operations. | ||||
| #[derive(Debug, Error)] | ||||
| pub enum SlicerError { | ||||
|     /// Errors related to configuration. | ||||
|     #[error("configuration error: {0}")] | ||||
|     Config(String), | ||||
|  | ||||
|     /// Errors related to virtual machine management. | ||||
|     #[error("vm error: {0}")] | ||||
|     Vm(String), | ||||
|  | ||||
|     /// Errors related to resource management. | ||||
|     #[error("resource error: {0}")] | ||||
|     Resource(String), | ||||
|  | ||||
|     /// Errors originating from I/O operations. | ||||
|     #[error("io error: {0}")] | ||||
|     Io(#[from] std::io::Error), | ||||
|  | ||||
|     /// Errors from the SAL OS library. | ||||
|     #[error("os error: {0}")] | ||||
|     SalOs(#[from] sal_os::fs::FsError), | ||||
| } | ||||
							
								
								
									
										37
									
								
								zos/src/slicer/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								zos/src/slicer/main.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| use clap::Parser; | ||||
|  | ||||
| mod cli; | ||||
| mod error; | ||||
| mod resource; | ||||
|  | ||||
| use cli::{Cli, Commands}; | ||||
| use error::Result; | ||||
|  | ||||
| fn main() -> Result<()> { | ||||
|     let cli = Cli::parse(); | ||||
|  | ||||
|     match cli.command { | ||||
|         Commands::Create { name, cpus, memory } => { | ||||
|             println!("Creating VM '{}' with {} CPUs and {}MB memory", name, cpus, memory); | ||||
|             // Placeholder for create logic | ||||
|         } | ||||
|         Commands::Delete { name } => { | ||||
|             println!("Deleting VM '{}'", name); | ||||
|             // Placeholder for delete logic | ||||
|         } | ||||
|         Commands::List => { | ||||
|             let resources = resource::Resources::new(); | ||||
|             println!("Detected System Resources:"); | ||||
|             println!("  - CPU Cores: {}", resources.cpu_cores); | ||||
|             println!("  - Total Memory: {} MB", resources.total_memory_mb); | ||||
|             println!("\nListing all VMs..."); | ||||
|             // Placeholder for list logic | ||||
|         } | ||||
|         Commands::Info { name } => { | ||||
|             println!("Getting info for VM '{}'", name); | ||||
|             // Placeholder for info logic | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     Ok(()) | ||||
| } | ||||
							
								
								
									
										31
									
								
								zos/src/slicer/resource.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								zos/src/slicer/resource.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| use sysinfo::System; | ||||
|  | ||||
| /// A struct to hold system resource information. | ||||
| pub struct Resources { | ||||
|     /// Total memory in megabytes. | ||||
|     pub total_memory_mb: u64, | ||||
|     /// Number of CPU cores. | ||||
|     pub cpu_cores: usize, | ||||
| } | ||||
|  | ||||
| impl Resources { | ||||
|     /// Detects the system's resources. | ||||
|     pub fn new() -> Self { | ||||
|         let mut sys = System::new(); | ||||
|         sys.refresh_all(); | ||||
|  | ||||
|         let total_memory_mb = sys.total_memory() / 1024 / 1024; | ||||
|         let cpu_cores = sys.cpus().len(); | ||||
|  | ||||
|         Self { | ||||
|             total_memory_mb, | ||||
|             cpu_cores, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Default for Resources { | ||||
|     fn default() -> Self { | ||||
|         Self::new() | ||||
|     } | ||||
| } | ||||
							
								
								
									
										190
									
								
								zos/src/specs.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										190
									
								
								zos/src/specs.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,190 @@ | ||||
|  | ||||
| ## Goal | ||||
|  | ||||
| Build a Rust CLI tool called `talos-slicer` that provisions a single Kubernetes VM using Talos OS with: | ||||
|  | ||||
| - An **immutable boot disk** cloned from a QCOW2 base image | ||||
| - **Persistent storage** provisioned via a Btrfs subvolume | ||||
| - Dynamic allocation of **RAM**, **vCPU**, and **disk** based on requested slices | ||||
| - **Multi-homed networking**: | ||||
|     - **IPv6** for Mycelium network connectivity via a TUN interface. | ||||
|     - **IPv4** for access to the outside world via a NATed interface. | ||||
| - VM launched via **Cloud Hypervisor** | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## CLI Interface | ||||
|  | ||||
| ```bash | ||||
| talos-slicer --name <vm_name> --slices <n_slices> --ipv6-range <ipv6_cidr> | ||||
| ```` | ||||
|  | ||||
| ### Parameters | ||||
|  | ||||
| | Flag           | Type   | Description                             | | ||||
| | -------------- | ------ | --------------------------------------- | | ||||
| | `--name`       | String | Unique name of the VM                   | | ||||
| | `--slices`     | u8     | Number of slices to allocate (2GB each) | | ||||
| | `--ipv6-range` | String | IPv6 /64 subnet (e.g. `2a02:abcd::/64`) | | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## Assumptions | ||||
|  | ||||
| * A Talos base image exists at `/var/lib/images/talos-base.qcow2` | ||||
| * Btrfs is mounted at `/mnt/btrfs` with sufficient capacity | ||||
| * Cloud Hypervisor and Mycelium are installed and accessible | ||||
| * Talos kernel binary is located at `/boot/vmlinux-talos` | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## Kubernetes VM Resource Allocation | ||||
|  | ||||
| ### Memory | ||||
|  | ||||
| * Detect total system RAM | ||||
| * Reserve 1 GB if RAM < 32 GB, otherwise 2 GB | ||||
| * Remaining RAM / 2 = max slices | ||||
| * Validate `--slices ≤ max slices` | ||||
| * Allocate `slices × 2 GB` RAM to the VM | ||||
|  | ||||
| ### CPU | ||||
|  | ||||
| * Detect total logical CPU cores | ||||
| * Allow 4x oversubscription | ||||
| * vCPU = floor(`(total_cores × 4) / max_slices × requested_slices`) | ||||
|  | ||||
| ### Disk (Btrfs) | ||||
|  | ||||
| * Calculate usable disk space: `total_capacity - 2GB` | ||||
| * Compute `disk_per_slice = usable / max_slices` | ||||
| * Create Btrfs subvolume at `/mnt/btrfs/vms/<name>` | ||||
| * Allocate `requested_slices × disk_per_slice` for that subvolume | ||||
| * Expose subvolume to VM via `virtiofs` | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## Boot Disk | ||||
|  | ||||
| * Create VM boot disk at `/var/lib/talos-slicer/<name>/boot.qcow2` | ||||
| * Clone from base image: | ||||
|  | ||||
|   ```bash | ||||
|   qemu-img create -f qcow2 -b /var/lib/images/talos-base.qcow2 /var/lib/talos-slicer/<name>/boot.qcow2 | ||||
|   ``` | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## Networking | ||||
|  | ||||
| The VM will be multi-homed, with two network interfaces. | ||||
|  | ||||
| ### Can Talos be made multi-homed? | ||||
|  | ||||
| Yes, Talos can be configured with multiple network interfaces. This is achieved by specifying multiple network interfaces in the `machineconfig.yaml`. Talos will detect them on boot and configure them as specified. | ||||
|  | ||||
| ### Interface 1: IPv6 (Mycelium) | ||||
|  | ||||
| This interface connects the VM to the Mycelium mesh network. | ||||
|  | ||||
| *   Network connectivity via a **Mycelium-managed TUN interface**. | ||||
| *   Parse the `--ipv6-range` as a `/64` CIDR. | ||||
| *   Assign a unique static IPv6 address (e.g., `::10 + index`). | ||||
| *   Save to `/var/lib/talos-slicer/<name>/ipv6.txt`. | ||||
|  | ||||
| ### Interface 2: IPv4 (NAT) | ||||
|  | ||||
| This interface provides the VM with outbound internet access. | ||||
|  | ||||
| *   A dedicated tap device will be created for the VM (`nat-<name>`). | ||||
| *   The host is responsible for bridging this tap device and applying NAT rules to provide internet connectivity. | ||||
| *   The VM will be configured to use DHCP to get an IP address on this interface. Talos supports DHCP on network interfaces by default if not configured statically. | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## Talos Config | ||||
|  | ||||
| * Generate `machineconfig.yaml` to configure both network interfaces. | ||||
| * Save config to `/var/lib/talos-slicer/<name>/machineconfig.yaml` | ||||
|  | ||||
| Example `machineconfig.yaml` for a multi-homed setup: | ||||
|  | ||||
| ```yaml | ||||
| machine: | ||||
|   network: | ||||
|     interfaces: | ||||
|       - interface: eth0 | ||||
|         addresses: | ||||
|           - <ipv6_address>/64 | ||||
|       - interface: eth1 | ||||
|         dhcp: true | ||||
|   hostname: <name> | ||||
| install: | ||||
|   extraData: | ||||
|     - path: /mnt/data | ||||
|       source: virtiofs | ||||
|       type: virtiofs | ||||
| ``` | ||||
|  | ||||
| *   The config defines `eth0` for the Mycelium IPv6 network and `eth1` for the NATed IPv4 network. | ||||
| *   `eth1` will be configured via DHCP. | ||||
| *   If `virtiofs` is used, it will be configured as a data mount. | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## Cloud Hypervisor Launch | ||||
|  | ||||
| Launch VM with: | ||||
|  | ||||
| *   Boot disk: `/var/lib/talos-slicer/<name>/boot.qcow2` | ||||
| *   Virtiofs mount: `/mnt/btrfs/vms/<name>` with tag `vmdata` | ||||
| *   Two network interfaces: | ||||
|     1.  `mycelium-<name>` for IPv6 | ||||
|     2.  `nat-<name>` for IPv4 (NAT) | ||||
|  | ||||
| Command pattern: | ||||
|  | ||||
| ```bash | ||||
| cloud-hypervisor \ | ||||
|   --kernel /boot/vmlinux-talos \ | ||||
|   --disk path=/var/lib/talos-slicer/<name>/boot.qcow2 \ | ||||
|   --fs tag=vmdata,path=/mnt/btrfs/vms/<name> \ | ||||
|   --cpus <vcpus> \ | ||||
|   --memory size=<ram_mb>M \ | ||||
|   --net "tap=mycelium-<name>,ip=<ipv6>/64" \ | ||||
|   --net "tap=nat-<name>" | ||||
| ``` | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## Directory Structure | ||||
|  | ||||
| ```text | ||||
| /var/lib/images/ | ||||
|   └── talos-base.qcow2           # Immutable base image | ||||
|  | ||||
| /var/lib/talos-slicer/ | ||||
|   └── <name>/ | ||||
|       ├── boot.qcow2             # VM-specific boot disk | ||||
|       ├── machineconfig.yaml | ||||
|       └── ipv6.txt | ||||
|  | ||||
| /mnt/btrfs/vms/ | ||||
|   └── <name>/                    # Persistent storage subvolume | ||||
|       └── ...                    # VM data (etcd, kubelet, etc.) | ||||
| ``` | ||||
|  | ||||
| ## Remarks | ||||
|  | ||||
| - if base image missing then download from Internet | ||||
| - if Btrfs subvol/mount missing then create it | ||||
|  | ||||
| ## Error Handling | ||||
|  | ||||
| * Exit if: | ||||
|  | ||||
|   * Not enough available slices | ||||
|   * Invalid IPv6 subnet, get from the tun adaptor | ||||
|   * Required tap devices (Mycelium, NAT) can't be created | ||||
|   * Btrfs mount not available | ||||
|   * Failure to set up NAT on the host | ||||
		Reference in New Issue
	
	Block a user