diff options
author | Lars Wirzenius <liw@liw.fi> | 2021-07-25 10:45:27 +0300 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2021-07-25 11:44:44 +0300 |
commit | 40f951a3adbbba94942e007434946a2192eb8989 (patch) | |
tree | 47653653c827b3899d95a4bf37e8ce5d528c02ff | |
parent | be53a50f86c3f9dcbc003d2ced9824829ee81f19 (diff) | |
download | vmadm-40f951a3adbbba94942e007434946a2192eb8989.tar.gz |
feat: allow use to add a VM on virtual networks
Sponsored-by: author
-rw-r--r-- | src/cmd/config.rs | 4 | ||||
-rw-r--r-- | src/cmd/spec.rs | 10 | ||||
-rw-r--r-- | src/config.rs | 3 | ||||
-rw-r--r-- | src/install.rs | 22 | ||||
-rw-r--r-- | src/spec.rs | 1 | ||||
-rw-r--r-- | vmadm.md | 57 |
6 files changed, 91 insertions, 6 deletions
diff --git a/src/cmd/config.rs b/src/cmd/config.rs index 396f089..0a78a64 100644 --- a/src/cmd/config.rs +++ b/src/cmd/config.rs @@ -6,7 +6,9 @@ use crate::config::Configuration; /// The `config` sub-command. /// -/// Write the actual run-time configuration to stdout. +/// Write the actual run-time configuration to stdout as JSON. We +/// convert the config to JSON to make it clear we parse it the right +/// way. pub fn config(config: &Configuration) -> Result<(), std::io::Error> { let config = serde_json::to_vec(&config).unwrap(); std::io::stdout().write_all(&config)?; diff --git a/src/cmd/spec.rs b/src/cmd/spec.rs index b41f234..7922cb5 100644 --- a/src/cmd/spec.rs +++ b/src/cmd/spec.rs @@ -6,11 +6,11 @@ use crate::spec::Specification; /// The `spec` sub-command. /// -/// Write the actual VM specifications to stdout. +/// Write the actual VM specifications to stdout as JSON. We convert +/// the spec to JSON to make it more clear that we parse the config +/// and spec in the right way. pub fn spec(specs: &[Specification]) -> Result<(), std::io::Error> { - for spec in specs { - let spec = serde_yaml::to_vec(&spec).unwrap(); - std::io::stdout().write_all(&spec)?; - } + let spec = serde_json::to_vec(specs).unwrap(); + std::io::stdout().write_all(&spec)?; Ok(()) } diff --git a/src/config.rs b/src/config.rs index 7a38942..4786bdb 100644 --- a/src/config.rs +++ b/src/config.rs @@ -29,6 +29,9 @@ pub struct Configuration { /// Should new VM be started automatically on host boot? pub default_autostart: Option<bool>, + /// List of default networks to add to hosts. + pub default_networks: Option<Vec<String>>, + /// Directory where new VM images should be created, if given. pub image_directory: Option<PathBuf>, diff --git a/src/install.rs b/src/install.rs index 94c703c..c84f30a 100644 --- a/src/install.rs +++ b/src/install.rs @@ -40,6 +40,7 @@ pub struct VirtInstallArgs { vcpus: u64, image: VirtualMachineImage, init: CloudInitConfig, + networks: Vec<String>, } impl VirtInstallArgs { @@ -51,6 +52,7 @@ impl VirtInstallArgs { vcpus: 1, image: image.clone(), init: init.clone(), + networks: vec![], } } @@ -88,12 +90,31 @@ impl VirtInstallArgs { pub fn init(&self) -> &CloudInitConfig { &self.init } + + /// Add another network to add to the VM. + pub fn add_network(&mut self, network: &str) { + self.networks.push(network.to_string()); + } + + /// Return list of networks to add to the VM. + pub fn networks(&self) -> Vec<String> { + self.networks.clone() + } } /// Create new VM with virt-install. pub fn virt_install(args: &VirtInstallArgs, iso: &Path) -> Result<PathBuf, VirtInstallError> { args.init().create_iso(&iso)?; + let networks: Vec<String> = if args.networks.is_empty() { + vec!["--network=default".to_string()] + } else { + args.networks + .iter() + .map(|s| format!("--network={}", s)) + .collect() + }; + let r = Command::new("virt-install") .arg("--name") .arg(args.name()) @@ -115,6 +136,7 @@ pub fn virt_install(args: &VirtInstallArgs, iso: &Path) -> Result<PathBuf, VirtI .arg("--graphics=spice") .arg("--noautoconsole") .arg("--quiet") + .args(&networks) .output() .map_err(VirtInstallError::Run)?; if !r.status.success() { diff --git a/src/spec.rs b/src/spec.rs index bf622c0..1470fdb 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -31,6 +31,7 @@ struct OneVmInputSpecification { pub cpus: Option<u64>, pub generate_host_certificate: Option<bool>, pub autostart: Option<bool>, + pub networks: Option<Vec<String>>, pub ca_key: Option<PathBuf>, } @@ -50,6 +50,8 @@ default_memory_mib: 2048 default_cpus: 1 default_generate_host_certificate: true default_autostart: true +default_networks: +- default ca_key: ca_key authorized_keys: - ~/.ssh/id_rsa.pub @@ -64,6 +66,9 @@ authorized_keys: "default_cpus": 1, "default_generate_host_certificate": true, "default_autostart": true, + "default_networks": [ + "default" + ], "ca_key": "ca_key", "authorized_keys": [ "~/.ssh/id_rsa.pub" @@ -71,6 +76,39 @@ authorized_keys: } ~~~ +~~~{#spec.yaml .file .yaml} +foo: + networks: ["lan", "wan"] +~~~ + +~~~{#fullspec.json .file .json} +[ + { + "name": "foo", + "ssh_keys": [ + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQChZ6mVuGLBpW7SarFU/Tu6TemquNxatbMUZuTk8RqVtbkvTKeWFZ5h5tntWPHgST8ykYFaIrr8eYuKQkKdBxHW7H8kejTNwRu/rDbRYX5wxTn4jw4RVopGTpxMlGrWeu5CkWPoLAhQtIzzUAnrDGp9sqG6P1G4ohI61wZMFQta9R2uNxXnnes+e2r4Y78GxmlQH/o0ouI8fBnsxRK0IoSfFs2LutO6wjyzR59FdC9TT7wufd5kXMRzxsmPGeXzNcaqvHGxBvRucGFclCkqSRwk3GNEpXZQhlCIoTIoRu0IPAp/430tlx9zJMhhwDlZsOOXRrFYpdWVMSTAAKECLSYx liw@exolobe1" + ], + "networks": ["lan", "wan"], + "rsa_host_key": null, + "rsa_host_cert": null, + "dsa_host_key": null, + "dsa_host_cert": null, + "ecdsa_host_key": null, + "ecdsa_host_cert": null, + "ed25519_host_key": null, + "ed25519_host_cert": null, + "base": "~/base.qcow2", + "image": "~/images/foo.qcow2", + "image_size_gib": 5, + "memory_mib": 2048, + "cpus": 1, + "generate_host_certificate": true, + "autostart": true, + "ca_key": "ca_key" + } +] +~~~ + ~~~{#ssh_key_pub .file} ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQChZ6mVuGLBpW7SarFU/Tu6TemquNxatbMUZuTk8RqVtbkvTKeWFZ5h5tntWPHgST8ykYFaIrr8eYuKQkKdBxHW7H8kejTNwRu/rDbRYX5wxTn4jw4RVopGTpxMlGrWeu5CkWPoLAhQtIzzUAnrDGp9sqG6P1G4ohI61wZMFQta9R2uNxXnnes+e2r4Y78GxmlQH/o0ouI8fBnsxRK0IoSfFs2LutO6wjyzR59FdC9TT7wufd5kXMRzxsmPGeXzNcaqvHGxBvRucGFclCkqSRwk3GNEpXZQhlCIoTIoRu0IPAp/430tlx9zJMhhwDlZsOOXRrFYpdWVMSTAAKECLSYx liw@exolobe1 ~~~ @@ -231,6 +269,25 @@ when I run vmadm config then stdout, as JSON, matches file fullconfig.json with tilde expansion ~~~ +# Dump specification + +This scenario verifies that vmadm can show the actual specification it +will use. + +~~~scenario +given an installed vmadm +given a Debian 10 OpenStack cloud image +given file .config/vmadm/config.yaml from config.yaml +given file ca_key +given file .ssh/id_rsa from ssh_key +given file .ssh/id_rsa.pub from ssh_key_pub +given file .ssh/config from ssh_config +given file .ssh/known_hosts from known_hosts +given file spec.yaml +given file fullspec.json +when I run vmadm spec spec.yaml +then stdout, as JSON, matches file fullspec.json with tilde expansion +~~~ # Colophon |