summaryrefslogtreecommitdiff
path: root/src/spec.rs
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2021-03-01 10:13:15 +0200
committerLars Wirzenius <liw@liw.fi>2021-03-01 12:28:31 +0200
commita4e59f7f6363c2bc62b91298f41b5b645842385e (patch)
tree46659f0fa296fe2128d1a7bcb929008d034f51c1 /src/spec.rs
parent05dbbc46d7b3fad9e7a1b85e10469022e07e0b40 (diff)
downloadvmadm-a4e59f7f6363c2bc62b91298f41b5b645842385e.tar.gz
feat: change how command line interface works
Easier to use now. --config before subcommand was annoying.
Diffstat (limited to 'src/spec.rs')
-rw-r--r--src/spec.rs94
1 files changed, 84 insertions, 10 deletions
diff --git a/src/spec.rs b/src/spec.rs
index 2cb61f6..0a3d097 100644
--- a/src/spec.rs
+++ b/src/spec.rs
@@ -1,9 +1,13 @@
+use crate::config::Configuration;
+
+use log::debug;
use serde::{Deserialize, Serialize};
-use std::path::PathBuf;
+use std::fs;
+use std::path::{Path, PathBuf};
#[derive(Debug, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
-pub struct Specification {
+struct InputSpecification {
pub name: String,
#[serde(default)]
@@ -18,6 +22,26 @@ pub struct Specification {
pub ed25519_host_key: Option<String>,
pub ed25519_host_cert: Option<String>,
+ pub base: Option<PathBuf>,
+ pub image: PathBuf,
+ pub image_size_gib: u64,
+ pub memory_mib: u64,
+ pub cpus: u64,
+}
+
+#[derive(Debug)]
+pub struct Specification {
+ pub name: String,
+ pub ssh_keys: Vec<String>,
+ pub rsa_host_key: Option<String>,
+ pub rsa_host_cert: Option<String>,
+ pub dsa_host_key: Option<String>,
+ pub dsa_host_cert: Option<String>,
+ pub ecdsa_host_key: Option<String>,
+ pub ecdsa_host_cert: Option<String>,
+ pub ed25519_host_key: Option<String>,
+ pub ed25519_host_cert: Option<String>,
+
pub base: PathBuf,
pub image: PathBuf,
pub image_size_gib: u64,
@@ -27,21 +51,71 @@ pub struct Specification {
#[derive(Debug, thiserror::Error)]
pub enum SpecificationError {
+ #[error("No base image or default base image specified: {0}")]
+ NoBaseImage(PathBuf),
+
+ #[error("Failed to read SSH public key file {0}")]
+ SshKeyRead(PathBuf, #[source] std::io::Error),
+
#[error(transparent)]
IoError(#[from] std::io::Error),
#[error(transparent)]
FromUtf8Error(#[from] std::string::FromUtf8Error),
+
+ #[error(transparent)]
+ YamlError(#[from] serde_yaml::Error),
}
impl Specification {
- pub fn ssh_keys(&self) -> Result<String, SpecificationError> {
- let mut keys = String::new();
- for filename in self.ssh_key_files.iter() {
- let key = std::fs::read(filename)?;
- let key = String::from_utf8(key)?;
- keys.push_str(&key);
- }
- Ok(keys)
+ pub fn from_file(
+ config: &Configuration,
+ filename: &Path,
+ ) -> Result<Specification, SpecificationError> {
+ debug!("reading specification from {}", filename.display());
+ let spec = fs::read(filename)?;
+ let input: InputSpecification = serde_yaml::from_slice(&spec)?;
+ debug!("specification as read from file: {:#?}", input);
+
+ 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()));
+ };
+
+ let spec = Specification {
+ name: input.name.clone(),
+ ssh_keys: ssh_keys(&input.ssh_key_files)?,
+ rsa_host_key: input.rsa_host_key,
+ rsa_host_cert: input.rsa_host_cert,
+ dsa_host_key: input.dsa_host_key,
+ dsa_host_cert: input.dsa_host_cert,
+ ecdsa_host_key: input.ecdsa_host_key,
+ ecdsa_host_cert: input.ecdsa_host_cert,
+ ed25519_host_key: input.ed25519_host_key,
+ ed25519_host_cert: input.ed25519_host_cert,
+ base,
+ image: input.image.clone(),
+ image_size_gib: input.image_size_gib,
+ memory_mib: input.memory_mib,
+ cpus: input.cpus,
+ };
+
+ debug!("specification as with defaults applied: {:#?}", spec);
+ Ok(spec)
+ }
+}
+
+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 key = String::from_utf8(key)?;
+ let key = key.strip_suffix("\n").or(Some(&key)).unwrap();
+ keys.push(key.to_string());
}
+ Ok(keys)
}