Skip to main content

mvm_runtime/vm/
lima.rs

1use anyhow::{Context, Result};
2
3use crate::config::VM_NAME;
4use crate::shell::{run_host, run_host_visible};
5use crate::ui;
6
7#[derive(Debug, PartialEq)]
8pub enum LimaStatus {
9    Running,
10    Stopped,
11    NotFound,
12}
13
14// ---------------------------------------------------------------------------
15// Parameterized functions (accept vm_name)
16// ---------------------------------------------------------------------------
17
18/// Get the current status of a named Lima VM.
19pub fn get_vm_status(vm_name: &str) -> Result<LimaStatus> {
20    // On native KVM hosts, Lima isn't required—skip external call to limactl.
21    if mvm_core::platform::current().has_kvm() {
22        return Ok(LimaStatus::NotFound);
23    }
24
25    let output = run_host("limactl", &["list", "--format", "{{.Status}}", vm_name])?;
26    let stdout = String::from_utf8_lossy(&output.stdout).trim().to_string();
27
28    if !output.status.success() || stdout.is_empty() {
29        return Ok(LimaStatus::NotFound);
30    }
31
32    match stdout.as_str() {
33        "Running" => Ok(LimaStatus::Running),
34        "Stopped" => Ok(LimaStatus::Stopped),
35        _ => Ok(LimaStatus::NotFound),
36    }
37}
38
39/// Create and start a new named Lima VM from the given yaml config.
40pub fn create_vm(vm_name: &str, lima_yaml: &std::path::Path) -> Result<()> {
41    let yaml_str = lima_yaml.to_str().context("Invalid lima.yaml path")?;
42    run_host_visible("limactl", &["start", "--name", vm_name, yaml_str])
43}
44
45/// Start an existing stopped named Lima VM.
46pub fn start_vm(vm_name: &str) -> Result<()> {
47    run_host_visible("limactl", &["start", vm_name])
48}
49
50/// Ensure a named Lima VM is running. Creates, starts, or does nothing as needed.
51pub fn ensure_vm_running(vm_name: &str, lima_yaml: &std::path::Path) -> Result<()> {
52    match get_vm_status(vm_name)? {
53        LimaStatus::Running => {
54            ui::info(&format!("Lima VM '{}' is running.", vm_name));
55            Ok(())
56        }
57        LimaStatus::Stopped => {
58            ui::info(&format!("Starting Lima VM '{}'...", vm_name));
59            start_vm(vm_name)
60        }
61        LimaStatus::NotFound => {
62            ui::info(&format!("Creating Lima VM '{}'...", vm_name));
63            create_vm(vm_name, lima_yaml)
64        }
65    }
66}
67
68/// Delete a named Lima VM forcefully.
69pub fn destroy_vm(vm_name: &str) -> Result<()> {
70    run_host_visible("limactl", &["delete", "--force", vm_name])
71}
72
73// ---------------------------------------------------------------------------
74// Default VM_NAME wrappers (used by setup, start, stop, ssh, etc.)
75// ---------------------------------------------------------------------------
76
77/// Get the current status of the default Lima VM.
78pub fn get_status() -> Result<LimaStatus> {
79    get_vm_status(VM_NAME)
80}
81
82/// Create and start the default Lima VM from the given yaml config.
83pub fn create(lima_yaml: &std::path::Path) -> Result<()> {
84    create_vm(VM_NAME, lima_yaml)
85}
86
87/// Start the default Lima VM.
88pub fn start() -> Result<()> {
89    start_vm(VM_NAME)
90}
91
92/// Ensure the default Lima VM is running.
93pub fn ensure_running(lima_yaml: &std::path::Path) -> Result<()> {
94    ensure_vm_running(VM_NAME, lima_yaml)
95}
96
97/// Require that the default Lima VM is currently running.
98pub fn require_running() -> Result<()> {
99    match get_vm_status(VM_NAME)? {
100        LimaStatus::Running => Ok(()),
101        LimaStatus::Stopped => {
102            anyhow::bail!(
103                "Lima VM '{}' is stopped. Run 'mvm start' or 'mvm setup'.",
104                VM_NAME
105            )
106        }
107        LimaStatus::NotFound => {
108            anyhow::bail!(
109                "Lima VM '{}' does not exist. Run 'mvm setup' first.",
110                VM_NAME
111            )
112        }
113    }
114}
115
116/// Delete the default Lima VM forcefully.
117pub fn destroy() -> Result<()> {
118    destroy_vm(VM_NAME)
119}