summaryrefslogtreecommitdiff
path: root/src/spec.rs
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2021-03-04 10:40:21 +0200
committerLars Wirzenius <liw@liw.fi>2021-03-04 11:46:17 +0200
commit458305fa48338de178739af2e3e86b85c0036a54 (patch)
tree9ad0731c2142d8fa49dda598d5a929556d221f3f /src/spec.rs
parent9ec059250bacd1b17547e40b95709fac8d4f164a (diff)
downloadvmadm-458305fa48338de178739af2e3e86b85c0036a54.tar.gz
feat: use configured defaults to unspecified machine attributes
Diffstat (limited to 'src/spec.rs')
-rw-r--r--src/spec.rs148
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);