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 filter(&self) -> DevFilter<'_> {
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
}
}
pub fn optional(&self) -> bool { pub fn optional(&self) -> bool {
self.optional.unwrap_or_else(|| self.filter.is_prefix()) self.optional.unwrap_or_else(|| match self.filter() {
DevFilter::None => true,
DevFilter::Dev(_) => false,
DevFilter::Prefix(_) => true,
DevFilter::Udev(_) => true,
})
} }
} }
#[derive(Debug, serde::Deserialize, serde::Serialize)] #[test]
#[serde(rename_all = "snake_case")] fn test_parse_crypt_dev() {
pub enum DevFilter { for s in [
Dev(String), "name: sys0\ndev: /dev/sda\n",
Prefix(String), "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();
}
} }
impl DevFilter {
pub fn is_dev(&self) -> bool { pub enum DevFilter<'t> {
match self { None,
Self::Dev(_) => true, Dev(&'t str),
_ => false, Prefix(&'t str),
} Udev(&'t UdevFilter),
} }
pub fn is_prefix(&self) -> bool {
match self { #[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
Self::Prefix(_) => true, #[serde(rename_all = "snake_case")]
_ => false, pub enum UdevFilter {
} Has(String),
} Eq(String, String),
Glob(String, String),
And(Vec<UdevFilter>),
Or(Vec<UdevFilter>),
Not(Box<UdevFilter>),
} }
#[derive(Debug, Default, Clone, serde::Deserialize, serde::Serialize)] #[derive(Debug, Default, Clone, serde::Deserialize, serde::Serialize)]