diff options
author | Lars Wirzenius <liw@liw.fi> | 2021-03-25 12:29:44 +0200 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2021-03-25 13:16:13 +0200 |
commit | 00dc4a7a85b32c4337dd3672adec2cbfe3597bfe (patch) | |
tree | 20df497a743e8442f9725c2f5ab552747363a9d1 | |
parent | 7d906d7f5436705ec3f2f3f5c4d8629c79f98fde (diff) | |
download | vmadm-00dc4a7a85b32c4337dd3672adec2cbfe3597bfe.tar.gz |
feat: allow ~/ in config, specification files
-rw-r--r-- | src/config.rs | 12 | ||||
-rw-r--r-- | src/libvirt.rs | 2 | ||||
-rw-r--r-- | src/spec.rs | 10 | ||||
-rw-r--r-- | src/util.rs | 34 | ||||
-rw-r--r-- | vmadm.md | 12 |
5 files changed, 61 insertions, 9 deletions
diff --git a/src/config.rs b/src/config.rs index 1866971..3f1b341 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,5 +1,6 @@ //! Tool configuration. +use crate::util::{expand_optional_pathbuf, expand_optional_pathbufs}; use log::debug; use serde::Deserialize; use std::default::Default; @@ -57,11 +58,20 @@ impl Configuration { debug!("reading configuration file {}", filename.display()); let config = fs::read(filename) .map_err(|err| ConfigurationError::ReadError(filename.to_path_buf(), err))?; - let config: Configuration = serde_yaml::from_slice(&config)?; + let mut config: Configuration = serde_yaml::from_slice(&config)?; + config.expand_tildes(); debug!("config: {:#?}", config); Ok(config) } else { Ok(Self::default()) } } + + fn expand_tildes(&mut self) { + expand_optional_pathbuf(&mut self.default_base_image); + expand_optional_pathbuf(&mut self.image_directory); + expand_optional_pathbuf(&mut self.image_directory); + expand_optional_pathbuf(&mut self.ca_key); + expand_optional_pathbufs(&mut self.authorized_keys) + } } diff --git a/src/libvirt.rs b/src/libvirt.rs index b144d11..4bf8590 100644 --- a/src/libvirt.rs +++ b/src/libvirt.rs @@ -116,7 +116,7 @@ impl Libvirt { let disk = find_iso_xml(&xml); let flags = VIR_DOMAIN_AFFECT_CONFIG | VIR_DOMAIN_AFFECT_CURRENT | VIR_DOMAIN_AFFECT_LIVE; - if disk.is_empty() { + if !disk.is_empty() { domain .detach_device_flags(&disk, flags) .map_err(|err| VirtError::DetachIso(name.to_string(), err))?; diff --git a/src/spec.rs b/src/spec.rs index a1d1c2f..a00a5e8 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -1,6 +1,7 @@ //! Virtual machine specification. use crate::config::Configuration; +use crate::util::expand_tilde; use log::debug; use serde::{Deserialize, Serialize}; @@ -293,8 +294,8 @@ impl Specification { ecdsa_host_cert: input.ecdsa_host_cert.clone(), ed25519_host_key: input.ed25519_host_key.clone(), ed25519_host_cert: input.ed25519_host_cert.clone(), - base: input.base_image(config, name)?, - image: input.image(config, name)?, + base: expand_tilde(&input.base_image(config, name)?), + image: expand_tilde(&input.image(config, name)?), image_size_gib: input.image_size_gib(config, name)?, memory_mib: input.memory_mib(config, name)?, cpus: input.cpus(config, name)?, @@ -311,8 +312,9 @@ impl Specification { fn ssh_keys(filenames: &[PathBuf]) -> Result<Vec<String>, SpecificationError> { let mut keys = vec![]; for filename in filenames { - let key = std::fs::read(filename) - .map_err(|e| SpecificationError::SshKeyRead(filename.to_path_buf(), e))?; + let filename = expand_tilde(filename); + let key = + std::fs::read(&filename).map_err(|e| SpecificationError::SshKeyRead(filename, e))?; let key = String::from_utf8(key)?; let key = key.strip_suffix("\n").or(Some(&key)).unwrap(); keys.push(key.to_string()); diff --git a/src/util.rs b/src/util.rs index f3e104b..c641ea6 100644 --- a/src/util.rs +++ b/src/util.rs @@ -2,6 +2,7 @@ use log::debug; use std::net::TcpStream; +use std::path::{Path, PathBuf}; const SSH_PORT: i32 = 22; @@ -15,3 +16,36 @@ pub fn wait_for_ssh(name: &str) { } } } + +/// Expand a ~/ at the beginning of a Path to refer to the home directory. +pub fn expand_tilde(path: &Path) -> PathBuf { + if path.starts_with("~/") { + if let Some(home) = std::env::var_os("HOME") { + let mut expanded = PathBuf::from(home); + for comp in path.components().skip(1) { + expanded.push(comp); + } + expanded + } else { + path.to_path_buf() + } + } else { + path.to_path_buf() + } +} + +pub fn expand_optional_pathbuf(maybe_path: &mut Option<PathBuf>) { + if let Some(path) = maybe_path { + *maybe_path = Some(expand_tilde(path)); + } +} + +pub fn expand_optional_pathbufs(maybe_paths: &mut Option<Vec<PathBuf>>) { + if let Some(paths) = maybe_paths { + let mut expanded = vec![]; + for path in paths { + expanded.push(expand_tilde(&path)); + } + *maybe_paths = Some(expanded); + } +} @@ -36,9 +36,15 @@ V4cecTlFJGBtUOUAAAAMbGl3QGV4b2xvYmUxAQIDBAUGBw== -----END OPENSSH PRIVATE KEY----- ~~~ +Note that we use *tilde expansion* in filenames to indicate they go +into the home directory. The Subplot test runner sets the `HOME` +environment variable to a suitable directory, so that the files don't +go into the actual home directory of the person running the generated +test program + ~~~{#config.yaml .file .yaml} -image_directory: images -default_base_image: base.qcow2 +image_directory: ~/images +default_base_image: ~/base.qcow2 default_image_gib: 5 default_memory_mib: 2048 default_cpus: 1 @@ -46,7 +52,7 @@ default_generate_host_certificate: true default_autostart: true ca_key: ca_key authorized_keys: - - .ssh/id_rsa.pub + - ~/.ssh/id_rsa.pub ~~~ ~~~{#ssh_key_pub .file} |