Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add global static dns migration via loopback interface #76

Merged
merged 8 commits into from
Sep 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/migrate-wicked-integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
uses: actions/checkout@v3

- name: Start container
run: podman run --privileged --detach --name migrate-wicked --ipc=host -e CARGO_TERM_COLOR=always -v /dev:/dev -v .:/checkout registry.opensuse.org/home/jcronenberg/github-ci/containers/opensuse/migrate-wicked-testing:latest
run: podman run --detach --name migrate-wicked -e CARGO_TERM_COLOR=always -v .:/checkout registry.opensuse.org/home/jcronenberg/github-ci/containers/opensuse/migrate-wicked-testing:latest

- name: Build migrate-wicked
run: podman exec migrate-wicked bash -c "cd /checkout/rust/migrate-wicked/ && cargo build"
Expand Down
7 changes: 7 additions & 0 deletions rust/migrate-wicked/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions rust/migrate-wicked/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ tokio = { version = "1.33.0", features = ["macros", "rt-multi-thread"] }
serde_ignored = "0.1.9"
uuid = { version = "1.3.4", features = ["v4"] }
macaddr = "1.0"
dotenv = "0.15.0"

[[bin]]
name = "migrate-wicked"
Expand Down
6 changes: 1 addition & 5 deletions rust/migrate-wicked/src/bond.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,11 +329,7 @@ mod tests {

#[allow(dead_code)]
fn setup_default_migration_settings() {
let _ = MIGRATION_SETTINGS.set(crate::MigrationSettings {
continue_migration: false,
dry_run: false,
activate_connections: true,
});
let _ = MIGRATION_SETTINGS.set(crate::MigrationSettings::default());
}

#[test]
Expand Down
6 changes: 1 addition & 5 deletions rust/migrate-wicked/src/infiniband.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,7 @@ mod tests {

#[allow(dead_code)]
fn setup_default_migration_settings() {
let _ = MIGRATION_SETTINGS.set(crate::MigrationSettings {
continue_migration: false,
dry_run: false,
activate_connections: true,
});
let _ = MIGRATION_SETTINGS.set(crate::MigrationSettings::default());
}

#[test]
Expand Down
6 changes: 1 addition & 5 deletions rust/migrate-wicked/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -363,11 +363,7 @@ mod tests {

#[allow(dead_code)]
fn setup_default_migration_settings() {
let _ = MIGRATION_SETTINGS.set(crate::MigrationSettings {
continue_migration: false,
dry_run: false,
activate_connections: true,
});
let _ = MIGRATION_SETTINGS.set(crate::MigrationSettings::default());
}

#[test]
Expand Down
54 changes: 46 additions & 8 deletions rust/migrate-wicked/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod bridge;
mod infiniband;
mod interface;
mod migrate;
mod netconfig;
mod reader;
mod tuntap;
mod vlan;
Expand All @@ -13,9 +14,13 @@ use clap::{Args, Parser, Subcommand};
use log::*;
use migrate::migrate;
use reader::read as wicked_read;
use serde::Serialize;
use std::process::{ExitCode, Termination};
use tokio::sync::OnceCell;

use crate::interface::Interface;
use crate::netconfig::Netconfig;

#[derive(Parser)]
#[command(name = "migrate-wicked", version(concat!(env!("CARGO_PKG_VERSION"),"~",env!("GIT_HEAD"))), about, long_about = None)]
struct Cli {
Expand All @@ -30,6 +35,12 @@ struct Cli {
struct GlobalOpts {
#[arg(long, global = true, default_value_t = LevelFilter::Warn, value_parser = clap::builder::PossibleValuesParser::new(["TRACE", "DEBUG", "INFO", "WARN", "ERROR"]).map(|s| s.parse::<LevelFilter>().unwrap()),)]
pub log_level: LevelFilter,

#[arg(long, global = true, env = "MIGRATE_WICKED_WITHOUT_NETCONFIG")]
pub without_netconfig: bool,

#[arg(long, global = true, default_value_t = String::from("/etc/sysconfig/network/config"), env = "MIGRATE_WICKED_NETCONFIG_PATH")]
pub netconfig_path: String,
}

#[derive(Subcommand)]
Expand Down Expand Up @@ -80,18 +91,29 @@ async fn run_command(cli: Cli) -> anyhow::Result<()> {
continue_migration: true,
dry_run: false,
activate_connections: true,
with_netconfig: !cli.global_opts.without_netconfig,
netconfig_path: cli.global_opts.netconfig_path,
})
.expect("MIGRATION_SETTINGS was set too early");

let interfaces_result = wicked_read(paths)?;
let output: String = match format {
Format::Json => serde_json::to_string(&interfaces_result.interfaces)?,
Format::PrettyJson => serde_json::to_string_pretty(&interfaces_result.interfaces)?,
Format::Yaml => serde_yaml::to_string(&interfaces_result.interfaces)?,
Format::Xml => {
quick_xml::se::to_string_with_root("interface", &interfaces_result.interfaces)?
}
Format::Text => format!("{:?}", interfaces_result.interfaces),

#[derive(Debug, Serialize)]
struct WickedConfig {
interface: Vec<Interface>,
netconfig: Option<Netconfig>,
}
let show_output = WickedConfig {
interface: interfaces_result.interfaces,
netconfig: interfaces_result.netconfig,
};

let output = match format {
Format::Json => serde_json::to_string(&show_output)?,
Format::PrettyJson => serde_json::to_string_pretty(&show_output)?,
Format::Yaml => serde_yaml::to_string(&show_output)?,
Format::Xml => quick_xml::se::to_string_with_root("wicked-config", &show_output)?,
Format::Text => format!("{:?}", show_output),
};
println!("{}", output);
Ok(())
Expand All @@ -107,6 +129,8 @@ async fn run_command(cli: Cli) -> anyhow::Result<()> {
continue_migration,
dry_run,
activate_connections,
with_netconfig: !cli.global_opts.without_netconfig,
netconfig_path: cli.global_opts.netconfig_path,
})
.expect("MIGRATION_SETTINGS was set too early");

Expand Down Expand Up @@ -142,6 +166,20 @@ struct MigrationSettings {
continue_migration: bool,
dry_run: bool,
activate_connections: bool,
with_netconfig: bool,
netconfig_path: String,
}

impl Default for MigrationSettings {
fn default() -> Self {
MigrationSettings {
continue_migration: false,
dry_run: false,
activate_connections: true,
with_netconfig: false,
netconfig_path: "".to_string(),
}
}
}

static MIGRATION_SETTINGS: OnceCell<MigrationSettings> = OnceCell::const_new();
Expand Down
55 changes: 53 additions & 2 deletions rust/migrate-wicked/src/migrate.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use crate::bridge::BridgePort;
use crate::{reader::read as wicked_read, MIGRATION_SETTINGS};
use agama_server::network::model::{Connection, GeneralState};
use agama_server::network::{Adapter, NetworkManagerAdapter, NetworkState};
use agama_server::network::model::{Connection, GeneralState, IpConfig, MatchConfig, StateConfig};
use agama_server::network::{model, Adapter, NetworkManagerAdapter, NetworkState};
use cidr::IpInet;
use std::str::FromStr;
use std::{collections::HashMap, error::Error};
use uuid::Uuid;

Expand Down Expand Up @@ -74,6 +76,25 @@ fn update_bridge_ports(
Ok(())
}

fn create_lo_connection() -> Connection {
Connection {
id: "lo".to_string(),
ip_config: IpConfig {
method4: model::Ipv4Method::Manual,
method6: model::Ipv6Method::Manual,
addresses: vec![
IpInet::from_str("127.0.0.1/8").unwrap(),
IpInet::from_str("::1/128").unwrap(),
],
..Default::default()
},
interface: Some("lo".to_string()),
match_config: MatchConfig::default(),
config: model::ConnectionConfig::Loopback,
..Default::default()
}
}

pub async fn migrate(paths: Vec<String>) -> Result<(), Box<dyn Error>> {
let interfaces = wicked_read(paths.clone())?;
let settings = MIGRATION_SETTINGS.get().unwrap();
Expand Down Expand Up @@ -128,6 +149,36 @@ pub async fn migrate(paths: Vec<String>) -> Result<(), Box<dyn Error>> {
return Ok(());
}
let nm = NetworkManagerAdapter::from_system().await?;

if let Some(netconfig) = interfaces.netconfig {
let current_state = nm.read(StateConfig::default()).await?;
let mut loopback = match current_state.get_connection("lo") {
Some(lo) => lo.clone(),
None => create_lo_connection(),
};
loopback.ip_config.nameservers = match netconfig.static_dns_servers() {
Ok(nameservers) => nameservers,
Err(e) => {
let error = anyhow::anyhow!("Error when parsing static DNS servers: {}", e);
if !settings.continue_migration {
return Err(error.into());
} else {
log::warn!("{}", error);
vec![]
}
}
};
if let Some(static_dns_searchlist) = netconfig.static_dns_searchlist {
loopback.ip_config.dns_searchlist = static_dns_searchlist;
}

for con in state.connections.iter_mut() {
con.ip_config.ignore_auto_dns = true;
}

state.add_connection(loopback)?;
}

nm.write(&state).await?;
Ok(())
}
118 changes: 118 additions & 0 deletions rust/migrate-wicked/src/netconfig.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
use serde::{Deserialize, Serialize};
use std::{net::IpAddr, path::Path, str::FromStr};

#[derive(Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct Netconfig {
pub static_dns_servers: Option<Vec<String>>,
pub static_dns_searchlist: Option<Vec<String>>,
}

impl Netconfig {
pub fn static_dns_servers(&self) -> Result<Vec<IpAddr>, std::net::AddrParseError> {
if let Some(static_dns_servers) = &self.static_dns_servers {
static_dns_servers
.iter()
.map(|x| IpAddr::from_str(x))
.collect()
} else {
Ok(vec![])
}
}
}

pub fn read_netconfig(path: impl AsRef<Path>) -> Result<Option<Netconfig>, anyhow::Error> {
if let Err(e) = dotenv::from_filename(path) {
return Err(e.into());
};
handle_netconfig_values()
}

fn handle_netconfig_values() -> Result<Option<Netconfig>, anyhow::Error> {
if let Ok(dns_policy) = dotenv::var("NETCONFIG_DNS_POLICY") {
let dns_policies: Vec<&str> = dns_policy.split(' ').collect();
if dns_policies.len() > 1 {
return Err(anyhow::anyhow!(
"For NETCONFIG_DNS_POLICY only single policies are supported"
));
}
let dns_policy = dns_policies[0];
match dns_policy {
"" => return Ok(None),
"STATIC" => (),
"auto" => (),
_ => {
return Err(anyhow::anyhow!(
"For NETCONFIG_DNS_POLICY only \"STATIC\" and \"auto\" are supported"
))
}
}
}
let mut netconfig = Netconfig::default();
if let Ok(static_dns_servers) = dotenv::var("NETCONFIG_DNS_STATIC_SERVERS") {
if !static_dns_servers.is_empty() {
netconfig.static_dns_servers = Some(
static_dns_servers
.split(' ')
.map(|s| s.to_string())
.collect::<Vec<String>>(),
);
}
}
if let Ok(static_dns_searchlist) = dotenv::var("NETCONFIG_DNS_STATIC_SEARCHLIST") {
if !static_dns_searchlist.is_empty() {
netconfig.static_dns_searchlist = Some(
static_dns_searchlist
.split(' ')
.map(|s| s.to_string())
.collect::<Vec<String>>(),
);
}
}
Ok(Some(netconfig))
}

#[cfg(test)]
mod tests {
use super::*;
use std::env;

#[test]
fn test_handle_netconfig_values() {
env::set_var("NETCONFIG_DNS_POLICY", "STATIC_FALLBACK NetworkManager");
assert!(handle_netconfig_values().is_err());

env::set_var("NETCONFIG_DNS_POLICY", "STATIC_FALLBACK");
assert!(handle_netconfig_values().is_err());

env::set_var("NETCONFIG_DNS_POLICY", "");
env::set_var(
"NETCONFIG_DNS_STATIC_SERVERS",
"192.168.0.10 192.168.1.10 2001:db8::10",
);
env::set_var("NETCONFIG_DNS_STATIC_SEARCHLIST", "suse.com suse.de");
assert!(handle_netconfig_values().unwrap().is_none());

env::set_var("NETCONFIG_DNS_POLICY", "STATIC");
assert_eq!(
handle_netconfig_values().unwrap(),
Some(Netconfig {
static_dns_servers: Some(vec![
"192.168.0.10".to_string(),
"192.168.1.10".to_string(),
"2001:db8::10".to_string()
]),
static_dns_searchlist: Some(vec!["suse.com".to_string(), "suse.de".to_string()])
})
);

env::set_var("NETCONFIG_DNS_STATIC_SERVERS", "");
env::set_var("NETCONFIG_DNS_STATIC_SEARCHLIST", "");
assert_eq!(
handle_netconfig_values().unwrap(),
Some(Netconfig {
static_dns_servers: None,
static_dns_searchlist: None
})
);
}
}
Loading
Loading