99 lines
2.6 KiB
Rust
99 lines
2.6 KiB
Rust
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<String>) -> Result<()> {
|
|
info!("setting up network {}", net.name);
|
|
|
|
let netdevs = (get_interfaces().await?)
|
|
.filter(|dev| !assigned.contains(dev.name()))
|
|
.collect::<Vec<_>>();
|
|
|
|
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<impl Iterator<Item = NameAliases>> {
|
|
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())
|
|
}
|