summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2021-11-10 10:34:05 +0200
committerLars Wirzenius <liw@liw.fi>2021-11-10 10:34:05 +0200
commit22cc382f9e9aa38f3adad18acd426bf0292bbf00 (patch)
tree96a392797b77e98d3ce2b26358b9c250db65e1e2 /src
parent96c3606757750dadfcf31ec5ccd7787292da9273 (diff)
downloadvmadm-22cc382f9e9aa38f3adad18acd426bf0292bbf00.tar.gz
feat: check that virtual network names are syntactically correct
Sponsored-by: author
Diffstat (limited to 'src')
-rw-r--r--src/config.rs10
-rw-r--r--src/spec.rs12
-rw-r--r--src/util.rs48
3 files changed, 67 insertions, 3 deletions
diff --git a/src/config.rs b/src/config.rs
index a444d4e..f85ef38 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -1,6 +1,6 @@
//! Tool configuration.
-use crate::util::{expand_optional_pathbuf, expand_optional_pathbufs};
+use crate::util::{check_network_names, expand_optional_pathbuf, expand_optional_pathbufs};
use log::debug;
use serde::{Deserialize, Serialize};
use std::default::Default;
@@ -46,6 +46,10 @@ pub struct Configuration {
/// Errors from this module.
#[derive(Debug, thiserror::Error)]
pub enum ConfigurationError {
+ /// Network name error.
+ #[error(transparent)]
+ NetworkNameError(#[from] crate::util::NetworkNameError),
+
/// Error reading configuration file.
#[error("couldn't read configuration file {0}")]
ReadError(PathBuf, #[source] std::io::Error),
@@ -67,6 +71,10 @@ impl Configuration {
let config = fs::read(filename)
.map_err(|err| ConfigurationError::ReadError(filename.to_path_buf(), err))?;
let mut config: Configuration = serde_yaml::from_slice(&config)?;
+ eprintln!("raw config: {:#?}", config);
+ if let Some(ref networks) = config.default_networks {
+ check_network_names(networks)?;
+ }
config.expand_tildes()?;
config.fill_in_missing_networks();
debug!("config: {:#?}", config);
diff --git a/src/spec.rs b/src/spec.rs
index 4e5665e..e91c044 100644
--- a/src/spec.rs
+++ b/src/spec.rs
@@ -1,7 +1,7 @@
//! Virtual machine specification.
use crate::config::Configuration;
-use crate::util::expand_tilde;
+use crate::util::{check_network_names, expand_tilde};
use log::debug;
use serde::{Deserialize, Serialize};
@@ -238,6 +238,10 @@ pub enum SpecificationError {
#[error("Failed to read SSH public key file {0}")]
SshKeyRead(PathBuf, #[source] std::io::Error),
+ /// Network name error.
+ #[error(transparent)]
+ NetworkNameError(#[from] crate::util::NetworkNameError),
+
/// Error parsing string as UTF8.
#[error(transparent)]
FromUtf8Error(#[from] std::string::FromUtf8Error),
@@ -300,6 +304,10 @@ impl Specification {
false
};
+ let networks = input.networks(config);
+ check_network_names(&networks)?;
+ eprintln!("checked names: {:?}", networks);
+
let spec = Specification {
name: name.to_string(),
ssh_keys,
@@ -319,7 +327,7 @@ impl Specification {
generate_host_certificate: gen_cert,
autostart: input.autostart(config),
ca_key,
- networks: input.networks(config),
+ networks,
};
debug!("specification as with defaults applied: {:#?}", spec);
diff --git a/src/util.rs b/src/util.rs
index c3565e0..cf60bf9 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -2,7 +2,9 @@
use home_dir::HomeDirExt;
+use lazy_static::lazy_static;
use log::debug;
+use regex::Regex;
use std::net::TcpStream;
use std::path::{Path, PathBuf};
@@ -43,3 +45,49 @@ pub fn expand_optional_pathbufs(
}
Ok(())
}
+
+pub fn check_network_names(networks: &[String]) -> Result<(), NetworkNameError> {
+ lazy_static! {
+ static ref RE: Regex = Regex::new("^(network|bridge)=[a-z0-9-]*$").unwrap();
+ }
+ for name in networks.iter() {
+ if !RE.is_match(name) {
+ return Err(NetworkNameError::BadNetworkName(name.to_string()));
+ }
+ }
+ Ok(())
+}
+
+#[derive(Debug, thiserror::Error)]
+pub enum NetworkNameError {
+ /// Bad network name.
+ #[error("Network name should be network=foo or bridge=bar, not: {0}")]
+ BadNetworkName(String),
+}
+
+#[cfg(test)]
+mod test {
+ use super::check_network_names;
+
+ fn networks(names: &[&str]) -> Vec<String> {
+ names.iter().map(|s| s.to_string()).collect()
+ }
+
+ #[test]
+ fn accepts_network_name() {
+ let names = networks(&["network=foo"]);
+ assert!(check_network_names(&names).is_ok());
+ }
+
+ #[test]
+ fn accepts_bridge_name() {
+ let names = networks(&["bridge=foo"]);
+ assert!(check_network_names(&names).is_ok());
+ }
+
+ #[test]
+ fn rejects_plain_name() {
+ let names = networks(&["foo"]);
+ assert!(check_network_names(&names).is_err());
+ }
+}