diff options
author | Lars Wirzenius <liw@liw.fi> | 2021-03-04 10:40:21 +0200 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2021-03-04 11:46:17 +0200 |
commit | 458305fa48338de178739af2e3e86b85c0036a54 (patch) | |
tree | 9ad0731c2142d8fa49dda598d5a929556d221f3f /src/spec.rs | |
parent | 9ec059250bacd1b17547e40b95709fac8d4f164a (diff) | |
download | vmadm-458305fa48338de178739af2e3e86b85c0036a54.tar.gz |
feat: use configured defaults to unspecified machine attributes
Diffstat (limited to 'src/spec.rs')
-rw-r--r-- | src/spec.rs | 148 |
1 files changed, 114 insertions, 34 deletions
diff --git a/src/spec.rs b/src/spec.rs index c99da6b..d01abcf 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -10,7 +10,7 @@ use std::path::{Path, PathBuf}; #[serde(deny_unknown_fields)] struct OneVmInputSpecification { #[serde(default)] - pub ssh_key_files: Vec<PathBuf>, + pub ssh_key_files: Option<Vec<PathBuf>>, pub rsa_host_key: Option<String>, pub rsa_host_cert: Option<String>, @@ -23,9 +23,94 @@ struct OneVmInputSpecification { pub base: Option<PathBuf>, pub image: Option<PathBuf>, - pub image_size_gib: u64, - pub memory_mib: u64, - pub cpus: u64, + pub image_size_gib: Option<u64>, + pub memory_mib: Option<u64>, + pub cpus: Option<u64>, +} + +impl OneVmInputSpecification { + fn ssh_key_files( + &self, + config: &Configuration, + name: &str, + ) -> Result<Vec<PathBuf>, SpecificationError> { + get( + &self.ssh_key_files, + &config.authorized_keys, + SpecificationError::NoAuthorizedKeys(name.to_string()), + ) + } + + fn base_image( + &self, + config: &Configuration, + name: &str, + ) -> Result<PathBuf, SpecificationError> { + get( + &self.base, + &config.default_base_image, + SpecificationError::NoBaseImage(name.to_string()), + ) + } + + fn image(&self, config: &Configuration, name: &str) -> Result<PathBuf, SpecificationError> { + let default_image = if let Some(dirname) = &config.image_directory { + Some(dirname.join(format!("{}.qcow2", name))) + } else { + None + }; + + get( + &self.image, + &default_image, + SpecificationError::NoBaseImage(name.to_string()), + ) + } + + fn image_size_gib( + &self, + config: &Configuration, + name: &str, + ) -> Result<u64, SpecificationError> { + get( + &self.image_size_gib, + &config.default_image_gib, + SpecificationError::NoBaseImage(name.to_string()), + ) + } + + fn memory_mib(&self, config: &Configuration, name: &str) -> Result<u64, SpecificationError> { + get( + &self.memory_mib, + &config.default_memory_mib, + SpecificationError::NoBaseImage(name.to_string()), + ) + } + + fn cpus(&self, config: &Configuration, name: &str) -> Result<u64, SpecificationError> { + get( + &self.cpus, + &config.default_cpus, + SpecificationError::NoBaseImage(name.to_string()), + ) + } +} + +fn get<'a, T>( + input: &'a Option<T>, + default: &'a Option<T>, + error: SpecificationError, +) -> Result<T, SpecificationError> +where + T: Clone, +{ + if let Some(input) = input { + Ok((*input).clone()) + } else if let Some(default) = default { + Ok((*default).clone()) + } else { + Err(error) + } } #[derive(Debug)] @@ -50,11 +135,23 @@ pub struct Specification { #[derive(Debug, thiserror::Error)] pub enum SpecificationError { - #[error("No base image or default base image specified in {0} for {1}")] - NoBaseImage(PathBuf, String), + #[error("No base image or default base image specified for {0}")] + NoBaseImage(String), + + #[error("No image filename specified for {0} and no image_directory in configuration")] + NoImage(String), - #[error("No image filename and no image directory specified in configuration")] - NoImage, + #[error("No image size specified for {0} and no default configured")] + NoImageSize(String), + + #[error("No memory size specified for {0} and no default configured")] + NoMemorySize(String), + + #[error("No CPU count specified for {0} and no default configured")] + NoCpuCount(String), + + #[error("No SSH authorized keys specified for {0} and no default configured")] + NoAuthorizedKeys(String), #[error("Failed to read SSH public key file {0}")] SshKeyRead(PathBuf, #[source] std::io::Error), @@ -81,7 +178,7 @@ impl Specification { let mut machines = vec![]; for (name, machine) in input.iter() { - let spec = Specification::one_machine(config, &filename, &name, &machine)?; + let spec = Specification::one_machine(config, &name, &machine)?; debug!("machine with defaults applied: {:#?}", spec); machines.push(spec); } @@ -91,32 +188,15 @@ impl Specification { fn one_machine( config: &Configuration, - filename: &Path, name: &str, input: &OneVmInputSpecification, ) -> Result<Specification, SpecificationError> { - let base = if let Some(base) = &input.base { - base.to_path_buf() - } else if let Some(ref base) = config.default_base_image { - base.to_path_buf() - } else { - return Err(SpecificationError::NoBaseImage( - filename.to_path_buf(), - name.to_string(), - )); - }; - - let image = if let Some(image) = &input.image { - image.to_path_buf() - } else if let Some(dirname) = &config.image_directory { - dirname.join(format!("{}.qcow2", name)) - } else { - return Err(SpecificationError::NoImage.into()); - }; + let key_filenames = input.ssh_key_files(config, name)?; + let ssh_keys = ssh_keys(&key_filenames)?; let spec = Specification { name: name.to_string(), - ssh_keys: ssh_keys(&input.ssh_key_files)?, + ssh_keys: ssh_keys, rsa_host_key: input.rsa_host_key.clone(), rsa_host_cert: input.rsa_host_cert.clone(), dsa_host_key: input.dsa_host_key.clone(), @@ -125,11 +205,11 @@ 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, - image, - image_size_gib: input.image_size_gib, - memory_mib: input.memory_mib, - cpus: input.cpus, + base: input.base_image(config, name)?, + image: 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)?, }; debug!("specification as with defaults applied: {:#?}", spec); |