use itertools::Itertools; use log::{info, warn}; use std::collections::BTreeSet as Set; use tokio::process::Command; use super::{format_err, retry_or_ignore, Result}; use crate::{ udev, utils::{select_n_by_regex, select_n_by_udev, NameAliases}, }; use dkl::bootstrap::{Config, Network}; pub async fn setup(cfg: &Config) { if cfg.networks.is_empty() { warn!("no networks configured"); return; } let mut assigned = Set::new(); for net in &cfg.networks { retry_or_ignore(async || setup_network(net, &mut assigned).await).await; } } async fn setup_network(net: &Network, assigned: &mut Set) -> Result<()> { info!("setting up network {}", net.name); let netdevs = (get_interfaces().await?) .filter(|dev| !assigned.contains(dev.name())) .collect::>(); for dev in &netdevs { let names = [dev.name()].into_iter().chain(dev.aliases()).join(", "); info!("- available network device: {}", names); } let mut cmd = Command::new("ash"); cmd.arg("-c"); cmd.arg(&net.script); let mut selected = Vec::new(); for iface in &net.interfaces { let var = &iface.var; let if_names = if let Some(ref udev_filter) = iface.udev { select_n_by_udev( iface.n, "net", "INTERFACE", &udev_filter.clone().into(), &assigned, ) .await? } else { let netdevs = netdevs.iter().filter(|na| !assigned.contains(na.name())); select_n_by_regex(iface.n, &iface.regexps, netdevs) }; if if_names.is_empty() { return Err(format_err!("- no interface match for {var:?}")); } let value = if_names.join(" "); info!("- {var}={value}"); cmd.env(var, value); selected.extend(if_names); } info!("- running script"); let status = cmd.status().await?; if !status.success() { return Err(format_err!("setup script failed: {status}")); } assigned.extend(selected); Ok(()) } async fn get_interfaces() -> Result> { let nas: Vec<_> = (udev::all().await?.of_subsystem("net")) .filter_map(|dev| { let name = dev.property("INTERFACE")?; let mut na = NameAliases::new(name.to_string()); for (p, v) in dev.properties() { if p.starts_with("ID_NET_NAME") { na.push(v.to_string()); } } Some(na) }) .collect(); Ok(nas.into_iter()) }