cubic 0.18.0

Cubic is a lightweight command line manager for virtual machines. It has a simple, daemon-less and rootless design. All Cubic virtual machines run isolated in the user context. Cubic is built on top of QEMU, KVM and cloud-init. https://cubic-vm.org https://github.com/cubic-vm/cubic Show all supported images: $ cubic images Create a new virtual machine instance: $ cubic create mymachine --image ubuntu:noble List all virtual machine instances: $ cubic instances Start an instance: $ cubic start <instance name> Stop an instance: $ cubic stop <instance name> Open a shell in the instance: $ cubic ssh <machine name> Copy a file from the host to the instance: $ cubic scp <path/to/host/file> <machine>:<path/to/guest/file> Copy a file from the instance to the hots: $ cubic scp <machine>:<path/to/guest/file> <path/to/host/file>
use crate::actions::CreateInstanceAction;
use crate::commands::{
    Command,
    image::{fetch_image, fetch_image_info},
};
use crate::env::Environment;
use crate::error::Error;
use crate::fs::FS;
use crate::image::{ImageName, ImageStore};
use crate::instance::{Instance, InstanceName, InstanceStore, PortForward};
use crate::model::DataSize;
use crate::ssh_cmd::PortChecker;
use crate::view::Console;
use crate::view::SpinnerView;
use clap::Parser;

pub const DEFAULT_CPU_COUNT: u16 = 4;
pub const DEFAULT_MEM_SIZE: &str = "4G";
pub const DEFAULT_DISK_SIZE: &str = "100G";

/// Create a new virtual machine instance
#[derive(Parser)]
pub struct CreateInstanceCommand {
    /// Name of the virtual machine instance
    pub instance_name: InstanceName,
    /// Name of the virtual machine image
    #[clap(short, long)]
    image: ImageName,
    /// Name of the user
    #[clap(short, long, default_value = "cubic")]
    user: String,
    /// Number of CPUs for the virtual machine instance
    #[clap(short, long, default_value_t = DEFAULT_CPU_COUNT)]
    cpus: u16,
    /// Memory size of the virtual machine instance (e.g. 1G for 1 gigabyte)
    #[clap(short, long, default_value = DEFAULT_MEM_SIZE)]
    mem: DataSize,
    /// Disk size of the virtual machine instance (e.g. 10G for 10 gigabytes)
    #[clap(short, long, default_value = DEFAULT_DISK_SIZE)]
    disk: DataSize,
    /// Forward ports from guest to host (e.g. -p 8000:80 or -p 127.0.0.1:9000:90/tcp)
    #[clap(short, long)]
    port: Vec<PortForward>,
}

impl Command for CreateInstanceCommand {
    fn run(
        &self,
        _console: &mut dyn Console,
        env: &Environment,
        image_store: &dyn ImageStore,
        instance_store: &dyn InstanceStore,
    ) -> Result<(), Error> {
        if instance_store.exists(self.instance_name.as_str()) {
            return Result::Err(Error::InstanceAlreadyExists(self.instance_name.to_string()));
        }

        // Fetch image
        let image = &fetch_image_info(env, &self.image)?;
        fetch_image(env, image_store, image)?;

        let mut create_spinner = SpinnerView::new("Creating virtual machine instance".to_string());

        let instance = Instance {
            name: self.instance_name.to_string(),
            arch: image.arch,
            user: self.user.to_string(),
            cpus: self.cpus,
            mem: self.mem.clone(),
            disk_capacity: self.disk.clone(),
            ssh_port: PortChecker::new().get_new_port(),
            hostfwd: self.port.clone(),
            ..Instance::default()
        };
        CreateInstanceAction::new().run(env, &FS::new(), instance_store, image, instance)?;

        create_spinner.stop();
        Result::Ok(())
    }
}