herolib-virt 0.3.13

Virtualization and container management for herolib (buildah, nerdctl, kubernetes)
Documentation
# QCOW2 Module (`herolib_virt::qcow2`)

## Overview

The QCOW2 module provides a comprehensive Rust interface for creating and managing QCOW2 disk images. QCOW2 (QEMU Copy-On-Write version 2) is a widely-used disk image format that supports snapshots, compression, and sparse allocation, making it ideal for virtual machines and containerized environments.

## Requirements

This module requires `qemu-img` to be installed:

- **Debian/Ubuntu**: `sudo apt-get install qemu-utils`
- **macOS**: `brew install qemu`
- **RedHat/CentOS**: `sudo yum install qemu-img`
- **Arch**: `pacman -S qemu-img`

## Quick Start

### Creating a Disk Image

```rust
use herolib_virt::qcow2;

// Create a 50 GiB QCOW2 disk image
let disk_path = qcow2::create("/var/vms/my-vm.qcow2", 50)?;
println!("Created disk: {}", disk_path);
```

### Creating Snapshots

```rust
use herolib_virt::qcow2;

let disk = "/var/vms/my-vm.qcow2";

// Create a snapshot before making changes
qcow2::snapshot_create(disk, "before-update")?;

// ... make changes ...

// Create another snapshot after successful changes
qcow2::snapshot_create(disk, "after-update")?;

// List all snapshots
let snapshots = qcow2::snapshot_list(disk)?;
for snap in snapshots {
    println!("Snapshot: {:?}", snap.name);
}

// Delete old snapshot
qcow2::snapshot_delete(disk, "before-update")?;
```

### Getting Image Information

```rust
use herolib_virt::qcow2;

// Get detailed image information
let info = qcow2::info("/var/vms/disk.qcow2")?;
println!("Image info: {:?}", info);

// Access specific fields from JSON
if let Some(size) = info.get("virtual-size") {
    println!("Virtual size: {} bytes", size);
}
if let Some(disk_size) = info.get("actual-size") {
    println!("Actual size on disk: {} bytes", disk_size);
}
```

### Using Ubuntu Cloud Images

```rust
use herolib_virt::qcow2;

// Download and prepare Ubuntu 24.04 image
let base = qcow2::build_ubuntu_24_04_base("/var/vms/images", Some(100))?;
println!("Base image: {}", base.base_image_path);
println!("Snapshot: {}", base.snapshot);

// You can now use this as a base for cloning or snapshot-based VMs
```

## API Reference

### Functions

#### `create(path: &str, size_gb: i64) -> Result<String, Qcow2Error>`

Creates a new QCOW2 disk image with the specified virtual size. The actual file size will be smaller due to QCOW2's sparse allocation.

**Parameters:**
- `path`: Full path where the image should be created
- `size_gb`: Virtual size in GiB (must be > 0)

**Returns:** Path to the created image

**Example:**
```rust
let disk = qcow2::create("/tmp/disk.qcow2", 20)?;
```

#### `info(path: &str) -> Result<Value, Qcow2Error>`

Retrieves detailed information about a QCOW2 image. Returns the data as JSON parsed by `serde_json`.

**Parameters:**
- `path`: Path to the QCOW2 image

**Returns:** JSON object with image information

**Example:**
```rust
let info = qcow2::info("/tmp/disk.qcow2")?;
if let Some(virtual_size) = info.get("virtual-size") {
    println!("Size: {}", virtual_size);
}
```

#### `snapshot_create(path: &str, name: &str) -> Result<(), Qcow2Error>`

Creates a snapshot of the QCOW2 image. Useful for creating restore points.

**Parameters:**
- `path`: Path to the QCOW2 image
- `name`: Name for the snapshot (cannot be empty)

**Note:** The image must not be in use by a running VM.

**Example:**
```rust
qcow2::snapshot_create("/tmp/disk.qcow2", "checkpoint")?;
```

#### `snapshot_delete(path: &str, name: &str) -> Result<(), Qcow2Error>`

Deletes a snapshot from the QCOW2 image.

**Parameters:**
- `path`: Path to the QCOW2 image
- `name`: Name of the snapshot to delete

**Example:**
```rust
qcow2::snapshot_delete("/tmp/disk.qcow2", "checkpoint")?;
```

#### `snapshot_list(path: &str) -> Result<Vec<Qcow2Snapshot>, Qcow2Error>`

Lists all snapshots in a QCOW2 image.

**Parameters:**
- `path`: Path to the QCOW2 image

**Returns:** Vector of `Qcow2Snapshot` structures

**Example:**
```rust
let snapshots = qcow2::snapshot_list("/tmp/disk.qcow2")?;
for snap in snapshots {
    println!("Snapshot: {:?}", snap.name);
}
```

#### `build_ubuntu_24_04_base(dest_dir: &str, size_gb: Option<i64>) -> Result<BuildBaseResult, Qcow2Error>`

Downloads the Canonical Ubuntu 24.04 (Noble) cloud image and optionally resizes it.

**Parameters:**
- `dest_dir`: Directory to store the image
- `size_gb`: Optional new virtual size (None = use cloud image default)

**Returns:** `BuildBaseResult` with image path, snapshot name, and URL

**Example:**
```rust
let base = qcow2::build_ubuntu_24_04_base("/var/vms/images", Some(100))?;
println!("Image at: {}", base.base_image_path);
```

### Types

#### `Qcow2Snapshot`

Represents a snapshot of a QCOW2 image.

**Fields:**
- `id: Option<String>` - Internal QEMU snapshot ID
- `name: Option<String>` - Human-readable snapshot name
- `vm_state_size: Option<i64>` - Size of VM state data (bytes)
- `date_sec: Option<i64>` - Unix timestamp (seconds)
- `date_nsec: Option<i64>` - Nanoseconds component
- `vm_clock_nsec: Option<i64>` - VM clock value

#### `BuildBaseResult`

Result of building a base image.

**Fields:**
- `base_image_path: String` - Path to the downloaded/resized image
- `snapshot: String` - Name of the base snapshot
- `url: String` - Source download URL
- `resized_to_gb: Option<i64>` - Size if resized, None otherwise

## Common Patterns

### Pattern: VM Disk Lifecycle

```rust
use herolib_virt::qcow2;

// 1. Create a disk for a new VM
let disk = qcow2::create("/var/vms/production.qcow2", 100)?;

// 2. Create a snapshot before major changes
qcow2::snapshot_create(&disk, "pre-deployment")?;

// 3. ... perform updates/deployments ...

// 4. Check disk usage
let info = qcow2::info(&disk)?;
println!("Actual size: {:?}", info.get("actual-size"));

// 5. Clean up old snapshots
let snapshots = qcow2::snapshot_list(&disk)?;
for snap in snapshots {
    if let Some(name) = snap.name {
        if name.starts_with("old-") {
            qcow2::snapshot_delete(&disk, &name)?;
        }
    }
}
```

### Pattern: Multi-Tier Image Hierarchy

```rust
use herolib_virt::qcow2;

// 1. Create a base image from cloud image
let base = qcow2::build_ubuntu_24_04_base("/images", Some(50))?;
println!("Base image: {}", base.base_image_path);

// 2. Create snapshots for different configurations
qcow2::snapshot_create(&base.base_image_path, "web-server")?;
qcow2::snapshot_create(&base.base_image_path, "database")?;
qcow2::snapshot_create(&base.base_image_path, "cache")?;

// 3. Now each of these snapshots can serve as base for specific VM classes
```

### Pattern: Snapshot Workflow for Testing

```rust
use herolib_virt::qcow2;

let disk = "/var/vms/test.qcow2";
qcow2::create(disk, 30)?;

// Create clean state
qcow2::snapshot_create(disk, "clean")?;

// Test 1
qcow2::snapshot_create(disk, "test1-start")?;
// ... run test 1 ...
qcow2::snapshot_delete(disk, "test1-start")?;

// Test 2
qcow2::snapshot_create(disk, "test2-start")?;
// ... run test 2 ...
qcow2::snapshot_delete(disk, "test2-start")?;

// Keep the clean snapshot for future tests
```

## Error Handling

All functions return `Result<T, Qcow2Error>`. Errors include:

- **CommandExecutionFailed**: `qemu-img` not found or couldn't be executed
- **CommandFailed**: `qemu-img` executed but returned an error
- **JsonParseError**: Failed to parse JSON output from `qemu-img info`
- **IoError**: Filesystem or permission error
- **Other**: Various validation or dependency errors

**Example:**
```rust
use herolib_virt::qcow2;

match qcow2::create("/tmp/disk.qcow2", 50) {
    Ok(path) => println!("Created: {}", path),
    Err(e) => eprintln!("Failed to create disk: {}", e),
}
```

## Performance Considerations

1. **Sparse Allocation**: QCOW2 files start small and grow as data is written. The virtual size is not immediately consumed on disk.

2. **Snapshot Overhead**: Each snapshot adds metadata overhead. Keep the number of snapshots reasonable (typically < 10 active snapshots).

3. **Format Efficiency**: QCOW2 is good for development/testing but raw images may be faster for high-performance production workloads.

4. **Defragmentation**: Large numbers of snapshots can fragment the image file. Consider consolidating snapshots periodically.

## Rhai Integration

The QCOW2 module is fully accessible from Rhai scripts:

```rhai
// Create a disk
let disk = qcow2_create("/tmp/vm.qcow2", 50);

// Create snapshots
qcow2_snapshot_create(disk, "initial");

// List snapshots
let snaps = qcow2_snapshot_list(disk);
for snap in snaps {
    print("Snapshot: " + snap.name);
}

// Get info
let info = qcow2_info(disk);
print("Info: " + info);
```

## Troubleshooting

### "qemu-img not found"
**Solution**: Install QEMU tools for your platform (see Requirements above)

### "Image is locked or in use"
**Solution**: Ensure no VMs are running with the image attached, then try again

### "Snapshot name cannot be empty"
**Solution**: Provide a non-empty string for the snapshot name

### "Size must be > 0"
**Solution**: Specify a positive GiB size

## See Also

- [Cloud Hypervisor]../cloudhv/README.md - Use QCOW2 images with VMs
- [QEMU Documentation]https://www.qemu.org/docs/master/tools/qemu-img.html - Official qemu-img reference
- [QCOW2 Format]https://github.com/qemu/qemu/blob/master/docs/interop/qcow2.txt - Technical format specification