summaryrefslogtreecommitdiffhomepage
path: root/test/test-manager/src/vm/mod.rs
blob: 591aa095c2c37f2007e2cc533ef3d17e85a58558 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
use anyhow::{Context, Result};
use std::net::IpAddr;

use crate::config::{Config, ConfigFile, VmConfig, VmType};

mod logging;
pub mod network;
pub mod provision;
mod qemu;
mod ssh;
#[cfg(target_os = "macos")]
mod tart;
mod update;
mod util;

#[async_trait::async_trait]
pub trait VmInstance {
    /// Path to pty on the host that corresponds to the serial device
    fn get_pty(&self) -> &str;

    /// Get initial IP address of guest
    fn get_ip(&self) -> &IpAddr;

    /// Wait for VM to destruct
    async fn wait(&mut self);
}

pub async fn set_config(config: &mut ConfigFile, vm_name: &str, vm_config: VmConfig) -> Result<()> {
    config
        .edit(|config| {
            config.vms.insert(vm_name.to_owned(), vm_config);
        })
        .await
        .context("Failed to update VM config")
}

pub async fn run(config: &Config, name: &str) -> Result<Box<dyn VmInstance>> {
    let vm_conf = get_vm_config(config, name)?;

    log::info!("Starting VM \"{name}\"");

    let instance = match vm_conf.vm_type {
        VmType::Qemu => Box::new(
            qemu::run(config, vm_conf)
                .await
                .context("Failed to run QEMU VM")?,
        ) as Box<_>,
        #[cfg(target_os = "macos")]
        VmType::Tart => Box::new(
            tart::run(config, vm_conf)
                .await
                .context("Failed to run Tart VM")?,
        ) as Box<_>,
        #[cfg(not(target_os = "macos"))]
        VmType::Tart => return Err(anyhow::anyhow!("Failed to run Tart VM on a non-macOS host")),
    };

    log::debug!("Started instance of \"{name}\" vm");

    Ok(instance)
}

pub async fn update_packages(
    config: VmConfig,
    instance: &dyn VmInstance,
) -> Result<crate::vm::update::Update> {
    let guest_ip = *instance.get_ip();
    tokio::task::spawn_blocking(move || update::packages(&config, guest_ip)).await?
}

pub fn get_vm_config<'a>(config: &'a Config, name: &str) -> Result<&'a VmConfig> {
    config
        .get_vm(name)
        .with_context(|| format!("Could not find config: {name}"))
}