bootstrap: add UdevFilter

This commit is contained in:
Mikaël Cluseau
2025-11-10 13:55:14 +01:00
parent 1e047afac3
commit 3cc2111ca7
3 changed files with 337 additions and 363 deletions

617
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -12,7 +12,7 @@ use dkl::dls;
#[derive(Parser)] #[derive(Parser)]
#[command()] #[command()]
struct Cli { struct Cli {
#[arg(long, default_value = "http://[::1]:7606")] #[arg(long, default_value = "http://[::1]:7606", env = "DLS_URL")]
dls: String, dls: String,
#[command(subcommand)] #[command(subcommand)]

View File

@ -57,7 +57,10 @@ pub struct Network {
pub struct NetworkInterface { pub struct NetworkInterface {
pub var: String, pub var: String,
pub n: i16, pub n: i16,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub regexps: Vec<String>, pub regexps: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub udev: Option<UdevFilter>,
} }
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
@ -142,41 +145,77 @@ pub enum LvSize {
#[derive(Debug, serde::Deserialize, serde::Serialize)] #[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct LvmPV { pub struct LvmPV {
pub n: i16, pub n: i16,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub regexps: Vec<String>, pub regexps: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub udev: Option<UdevFilter>,
} }
#[derive(Debug, serde::Deserialize, serde::Serialize)] #[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct CryptDev { pub struct CryptDev {
pub name: String, pub name: String,
#[serde(flatten)] // hit the limit of enum representation here (flatten + enum variant case)
pub filter: DevFilter, #[serde(skip_serializing_if = "Option::is_none")]
pub dev: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub prefix: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub udev: Option<UdevFilter>,
#[serde(skip_serializing_if = "Option::is_none")]
pub optional: Option<bool>, pub optional: Option<bool>,
} }
impl CryptDev { impl CryptDev {
pub fn optional(&self) -> bool { pub fn filter(&self) -> DevFilter<'_> {
self.optional.unwrap_or_else(|| self.filter.is_prefix()) if let Some(dev) = self.dev.as_deref() {
DevFilter::Dev(dev)
} else if let Some(prefix) = self.prefix.as_deref() {
DevFilter::Prefix(prefix)
} else if let Some(udev) = self.udev.as_ref() {
DevFilter::Udev(udev)
} else {
DevFilter::None
} }
} }
#[derive(Debug, serde::Deserialize, serde::Serialize)] pub fn optional(&self) -> bool {
self.optional.unwrap_or_else(|| match self.filter() {
DevFilter::None => true,
DevFilter::Dev(_) => false,
DevFilter::Prefix(_) => true,
DevFilter::Udev(_) => true,
})
}
}
#[test]
fn test_parse_crypt_dev() {
for s in [
"name: sys0\ndev: /dev/sda\n",
"name: crypt-\nprefix: /dev/sd\n",
"name: crypt-${name}\nudev: !glob [ DEVNAME, /dev/sd* ]\n",
] {
let dev: CryptDev = serde_yaml::from_str(s).unwrap();
dev.filter();
dev.optional();
}
}
pub enum DevFilter<'t> {
None,
Dev(&'t str),
Prefix(&'t str),
Udev(&'t UdevFilter),
}
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub enum DevFilter { pub enum UdevFilter {
Dev(String), Has(String),
Prefix(String), Eq(String, String),
} Glob(String, String),
impl DevFilter { And(Vec<UdevFilter>),
pub fn is_dev(&self) -> bool { Or(Vec<UdevFilter>),
match self { Not(Box<UdevFilter>),
Self::Dev(_) => true,
_ => false,
}
}
pub fn is_prefix(&self) -> bool {
match self {
Self::Prefix(_) => true,
_ => false,
}
}
} }
#[derive(Debug, Default, Clone, serde::Deserialize, serde::Serialize)] #[derive(Debug, Default, Clone, serde::Deserialize, serde::Serialize)]