1use anyhow::{Context, Result};
2use std::process::{Command, Output};
3
4pub trait LxcCommander {
5 fn create(&self, name: &str, template: &str) -> Result<()>;
6 fn start(&self, name: &str) -> Result<()>;
7 fn stop(&self, name: &str) -> Result<()>;
8 fn delete(&self, name: &str) -> Result<()>;
9 fn list(&self) -> Result<String>;
10 fn shutdown(&self, name: &str) -> Result<()>;
11}
12
13pub struct RealLxcCommander;
14
15impl RealLxcCommander {
16 fn execute_command(&self, program: &str, args: &[&str]) -> Result<Output> {
17 let output = Command::new(program)
18 .args(args)
19 .output()
20 .context(format!("Failed to execute {}", program))?;
21
22 if output.status.success() {
23 Ok(output)
24 } else {
25 let error = String::from_utf8_lossy(&output.stderr);
26 Err(anyhow::anyhow!("{} failed: {}", program, error))
27 }
28 }
29}
30
31impl LxcCommander for RealLxcCommander {
32 fn create(&self, name: &str, template: &str) -> Result<()> {
33 let args = if template == "download" {
34 vec!["-n", name, "-t", template, "--", "-d", "ubuntu", "-r", "focal", "-a", "amd64"]
35 } else {
36 vec!["-n", name, "-t", template]
37 };
38 self.execute_command("lxc-create", &args)?;
39 Ok(())
40 }
41
42 fn start(&self, name: &str) -> Result<()> {
43 self.execute_command("lxc-start", &["-n", name])?;
44 Ok(())
45 }
46
47 fn stop(&self, name: &str) -> Result<()> {
48 self.execute_command("lxc-stop", &["-n", name])?;
49 Ok(())
50 }
51
52 fn delete(&self, name: &str) -> Result<()> {
53 self.execute_command("lxc-destroy", &["-n", name])?;
54 Ok(())
55 }
56
57 fn list(&self) -> Result<String> {
58 let output = self.execute_command("lxc-ls", &["-f"])?;
59 let list = String::from_utf8_lossy(&output.stdout);
60 Ok(list.to_string())
61 }
62
63 fn shutdown(&self, name: &str) -> Result<()> {
64 self.execute_command("lxc-stop", &["-n", name])?;
65 Ok(())
66 }
67}
68
69pub fn lxc_create(name: &str, template: &str) -> Result<()> {
70 let commander = RealLxcCommander;
71 commander.create(name, template)
72}
73
74pub fn lxc_start(name: &str) -> Result<()> {
75 let commander = RealLxcCommander;
76 commander.start(name)
77}
78
79pub fn lxc_stop(name: &str) -> Result<()> {
80 let commander = RealLxcCommander;
81 commander.stop(name)
82}
83
84pub fn lxc_delete(name: &str) -> Result<()> {
85 let commander = RealLxcCommander;
86 commander.delete(name)
87}
88
89pub fn lxc_list() -> Result<String> {
90 let commander = RealLxcCommander;
91 commander.list()
92}
93
94pub fn lxc_shutdown(name: &str) -> Result<()> {
95 let commander = RealLxcCommander;
96 commander.shutdown(name)
97}