From 6cf84d4a0180a54a54f38c0ae0b977c20679573e Mon Sep 17 00:00:00 2001 From: Jorik Cronenberg Date: Tue, 5 Mar 2024 17:04:52 +0100 Subject: [PATCH 1/8] Add static dns migration from netconfig --- rust/migrate-wicked/Cargo.lock | 7 + rust/migrate-wicked/Cargo.toml | 1 + rust/migrate-wicked/src/bond.rs | 6 +- rust/migrate-wicked/src/interface.rs | 6 +- rust/migrate-wicked/src/main.rs | 47 ++- rust/migrate-wicked/src/migrate.rs | 24 +- rust/migrate-wicked/src/netconfig.rs | 69 ++++ rust/migrate-wicked/src/reader.rs | 17 + rust/migrate-wicked/src/vlan.rs | 6 +- .../tests/static_dns/netconfig/config | 302 ++++++++++++++++++ .../system-connections/lo.nmconnection | 26 ++ .../tests/static_dns/wicked_xml/basic.xml | 14 + rust/migrate-wicked/tests/test.sh | 27 +- 13 files changed, 516 insertions(+), 36 deletions(-) create mode 100644 rust/migrate-wicked/src/netconfig.rs create mode 100644 rust/migrate-wicked/tests/static_dns/netconfig/config create mode 100644 rust/migrate-wicked/tests/static_dns/system-connections/lo.nmconnection create mode 100644 rust/migrate-wicked/tests/static_dns/wicked_xml/basic.xml diff --git a/rust/migrate-wicked/Cargo.lock b/rust/migrate-wicked/Cargo.lock index 7b8b6edf3d..5a3dc20f01 100644 --- a/rust/migrate-wicked/Cargo.lock +++ b/rust/migrate-wicked/Cargo.lock @@ -1019,6 +1019,12 @@ dependencies = [ "const-random", ] +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + [[package]] name = "either" version = "1.12.0" @@ -2012,6 +2018,7 @@ dependencies = [ "anyhow", "cidr", "clap", + "dotenv", "log", "macaddr", "quick-xml", diff --git a/rust/migrate-wicked/Cargo.toml b/rust/migrate-wicked/Cargo.toml index 3c7f75fcd6..3eb00e4236 100644 --- a/rust/migrate-wicked/Cargo.toml +++ b/rust/migrate-wicked/Cargo.toml @@ -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" diff --git a/rust/migrate-wicked/src/bond.rs b/rust/migrate-wicked/src/bond.rs index 871a46c477..4a530b5b0d 100644 --- a/rust/migrate-wicked/src/bond.rs +++ b/rust/migrate-wicked/src/bond.rs @@ -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] diff --git a/rust/migrate-wicked/src/interface.rs b/rust/migrate-wicked/src/interface.rs index 8d4275801a..8211c5f844 100644 --- a/rust/migrate-wicked/src/interface.rs +++ b/rust/migrate-wicked/src/interface.rs @@ -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] diff --git a/rust/migrate-wicked/src/main.rs b/rust/migrate-wicked/src/main.rs index 4c2b19bb4e..8a8974f72d 100644 --- a/rust/migrate-wicked/src/main.rs +++ b/rust/migrate-wicked/src/main.rs @@ -3,6 +3,7 @@ mod bridge; mod infiniband; mod interface; mod migrate; +mod netconfig; mod reader; mod tuntap; mod vlan; @@ -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 { @@ -30,6 +35,9 @@ 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::().unwrap()),)] pub log_level: LevelFilter, + + #[arg(long, global = true, default_value_t = String::from("/etc/sysconfig/network/config"), env = "MIGRATE_WICKED_NETCONFIG_PATH")] + pub netconfig_path: String, } #[derive(Subcommand)] @@ -80,18 +88,28 @@ async fn run_command(cli: Cli) -> anyhow::Result<()> { continue_migration: true, dry_run: false, activate_connections: true, + 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, + netconfig: Option, + } + 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(()) @@ -107,6 +125,7 @@ async fn run_command(cli: Cli) -> anyhow::Result<()> { continue_migration, dry_run, activate_connections, + netconfig_path: cli.global_opts.netconfig_path, }) .expect("MIGRATION_SETTINGS was set too early"); @@ -142,6 +161,18 @@ struct MigrationSettings { continue_migration: bool, dry_run: bool, activate_connections: bool, + netconfig_path: String, +} + +impl Default for MigrationSettings { + fn default() -> Self { + MigrationSettings { + continue_migration: false, + dry_run: false, + activate_connections: true, + netconfig_path: "".to_string(), + } + } } static MIGRATION_SETTINGS: OnceCell = OnceCell::const_new(); diff --git a/rust/migrate-wicked/src/migrate.rs b/rust/migrate-wicked/src/migrate.rs index d7f2126110..5b8c11e84a 100644 --- a/rust/migrate-wicked/src/migrate.rs +++ b/rust/migrate-wicked/src/migrate.rs @@ -1,6 +1,6 @@ use crate::bridge::BridgePort; use crate::{reader::read as wicked_read, MIGRATION_SETTINGS}; -use agama_server::network::model::{Connection, GeneralState}; +use agama_server::network::model::{Connection, GeneralState, StateConfig}; use agama_server::network::{Adapter, NetworkManagerAdapter, NetworkState}; use std::{collections::HashMap, error::Error}; use uuid::Uuid; @@ -128,6 +128,28 @@ pub async fn migrate(paths: Vec) -> Result<(), Box> { 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 = current_state.get_connection("lo").unwrap().clone(); + 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; + } + state.add_connection(loopback)?; + } + nm.write(&state).await?; Ok(()) } diff --git a/rust/migrate-wicked/src/netconfig.rs b/rust/migrate-wicked/src/netconfig.rs new file mode 100644 index 0000000000..f8cbebf803 --- /dev/null +++ b/rust/migrate-wicked/src/netconfig.rs @@ -0,0 +1,69 @@ +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>, + pub static_dns_searchlist: Option>, +} + +impl Netconfig { + pub fn static_dns_servers(&self) -> Result, 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) -> Result, anyhow::Error> { + if let Err(e) = dotenv::from_filename(path) { + return Err(e.into()); + }; + if let Ok(dns_policy) = dotenv::var("NETCONFIG_DNS_POLICY") { + let dns_policies: Vec<&str> = dns_policy.split(' ').collect(); + if dns_policies.len() > 1 { + println!("{:?}", dns_policies); + 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::>(), + ); + } + } + 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::>(), + ); + } + } + Ok(Some(netconfig)) +} diff --git a/rust/migrate-wicked/src/reader.rs b/rust/migrate-wicked/src/reader.rs index c3a9b8d39b..3347b5e75c 100644 --- a/rust/migrate-wicked/src/reader.rs +++ b/rust/migrate-wicked/src/reader.rs @@ -1,4 +1,6 @@ use crate::interface::Interface; +use crate::netconfig::{read_netconfig, Netconfig}; +use crate::MIGRATION_SETTINGS; use regex::Regex; use std::fs::{self, read_dir}; @@ -6,6 +8,7 @@ use std::path::{Path, PathBuf}; pub struct InterfacesResult { pub interfaces: Vec, + pub netconfig: Option, pub warning: Option, } @@ -28,6 +31,7 @@ pub fn read_xml_file(path: PathBuf) -> Result { })?; let mut result = InterfacesResult { interfaces, + netconfig: None, warning: None, }; if !unhandled_fields.is_empty() { @@ -73,10 +77,23 @@ fn recurse_files(path: impl AsRef) -> std::io::Result> { } pub fn read(paths: Vec) -> Result { + let settings = MIGRATION_SETTINGS.get().unwrap(); let mut result = InterfacesResult { interfaces: vec![], + netconfig: None, warning: None, }; + + match read_netconfig(settings.netconfig_path.clone()) { + Ok(netconfig) => result.netconfig = netconfig, + Err(e) => { + if !settings.continue_migration { + return Err(e); + }; + log::warn!("Failed to read netconfig: {}", e); + } + }; + for path in paths { let path: PathBuf = path.into(); if path.is_dir() { diff --git a/rust/migrate-wicked/src/vlan.rs b/rust/migrate-wicked/src/vlan.rs index d3056e9aa2..93b806e4c6 100644 --- a/rust/migrate-wicked/src/vlan.rs +++ b/rust/migrate-wicked/src/vlan.rs @@ -51,11 +51,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] diff --git a/rust/migrate-wicked/tests/static_dns/netconfig/config b/rust/migrate-wicked/tests/static_dns/netconfig/config new file mode 100644 index 0000000000..d360ae6b8f --- /dev/null +++ b/rust/migrate-wicked/tests/static_dns/netconfig/config @@ -0,0 +1,302 @@ +## Path: Network/General +## Description: Global network configuration +# +# Note: +# Most of the options can and should be overridden by per-interface +# settings in the ifcfg-* files. +# +# Note: The ISC dhclient started by the NetworkManager is not using any +# of these options -- NetworkManager is not using any sysconfig settings. +# + +## Type: yesno +## Default: yes +# If ifup should check if an IPv4 address is already in use, set this to yes. +# +# Make sure that packet sockets (CONFIG_PACKET) are supported in the kernel, +# since this feature uses arp, which depends on that. +# Also be aware that this takes one second per interface; consider that when +# setting up a lot of interfaces. +CHECK_DUPLICATE_IP="yes" + +## Type: list(auto,yes,no) +## Default: auto +# If ifup should send a gratuitous ARP to inform the receivers about its +# IPv4 addresses. Default is to send gratuitous ARP, when duplicate IPv4 +# address check is enabled and the check were successful. +# +# Make sure that packet sockets (CONFIG_PACKET) are supported in the kernel, +# since this feature uses arp, which depends on that. +SEND_GRATUITOUS_ARP="auto" + +## Type: yesno +## Default: no +# Switch on/off debug messages for all network configuration stuff. If set to no +# most scripts can enable it locally with "-o debug". +DEBUG="no" + +## Type: integer +## Default: 30 +# +# Some interfaces need some time to come up or come asynchronously via hotplug. +# WAIT_FOR_INTERFACES is a global wait for all mandatory interfaces in +# seconds. If empty no wait occurs. +# +WAIT_FOR_INTERFACES="30" + +## Type: yesno +## Default: yes +# +# With this variable you can determine if the SuSEfirewall when enabled +# should get started when network interfaces are started. +FIREWALL="yes" + +## Type: int +## Default: 30 +# +# When using NetworkManager you may define a timeout to wait for NetworkManager +# to connect in NetworkManager-wait-online.service. Other network services +# may require the system to have a valid network setup in order to succeed. +# +# This variable has no effect if NetworkManager is disabled. +# +NM_ONLINE_TIMEOUT="30" + +## Type: string +## Default: "dns-resolver dns-bind ntp-runtime nis" +# +# This variable defines the start order of netconfig modules installed +# in the /etc/netconfig.d and /usr/libexec/netconfig/netconfig.d/ directories. +# +# To disable the execution of a module, don't remove it from the list +# but prepend it with a minus sign, "-ntp-runtime". +# +NETCONFIG_MODULES_ORDER="dns-resolver dns-bind dns-dnsmasq nis ntp-runtime" + +## Type: yesno +## Default: no +# +# Enable netconfig verbose reporting. +# +NETCONFIG_VERBOSE="no" + +## Type: yesno +## Default: no +# +# This variable enables netconfig to always force a replace of modified +# files and automatically enables the -f | --force-replace parameter. +# +# The purpose is to use it as workaround, when some other tool trashes +# the files, e.g. /etc/resolv.conf and you observe messages like this +# in your logs on in "netconfig update" output: +# ATTENTION: You have modified /etc/resolv.conf. Leaving it untouched. +# +# Please do not forget to also report a bug as we have a system policy +# to use netconfig. +# +NETCONFIG_FORCE_REPLACE="no" + +## Type: string +## Default: "auto" +# +# Defines the DNS merge policy as documented in netconfig(8) manual page. +# Set to "" to disable DNS configuration. +# +NETCONFIG_DNS_POLICY="STATIC" + +## Type: string(resolver,bind,dnsmasq,) +## Default: "resolver" +# +# Defines the name of the DNS forwarder that has to be configured. +# Currently implemented are "bind", "dnsmasq" and "resolver", that +# causes to write the name server IP addresses to /etc/resolv.conf +# only (no forwarder). Empty string defaults to "resolver". +# +NETCONFIG_DNS_FORWARDER="resolver" + +## Type: yesno +## Default: yes +# +# When enabled (default) in forwarder mode ("bind", "dnsmasq"), +# netconfig writes an explicit localhost nameserver address to the +# /etc/resolv.conf, followed by the policy resolved name server list +# as fallback for the moments, when the local forwarder is stopped. +# +NETCONFIG_DNS_FORWARDER_FALLBACK="yes" + +## Type: string +## Default: "" +# +# List of DNS domain names used for host-name lookup. +# It is written as search list into the /etc/resolv.conf file. +# +NETCONFIG_DNS_STATIC_SEARCHLIST="suse.de suse.com" + +## Type: string +## Default: "" +# +# List of DNS nameserver IP addresses to use for host-name lookup. +# When the NETCONFIG_DNS_FORWARDER variable is set to "resolver", +# the name servers are written directly to /etc/resolv.conf. +# Otherwise, the nameserver are written into a forwarder specific +# configuration file and the /etc/resolv.conf does not contain any +# nameservers causing the glibc to use the name server on the local +# machine (the forwarder). See also netconfig(8) manual page. +# +NETCONFIG_DNS_STATIC_SERVERS="192.168.0.10 192.168.1.10 2001:db8::10" + +## Type: string +## Default: "auto" +# +# Allows to specify a custom DNS service ranking list, that is which +# services provide preferred (e.g. vpn services), and which services +# fallback settings (e.g. avahi). +# Preferred service names have to be prepended with a "+", fallback +# service names with a "-" character. The special default value +# "auto" enables the current build-in service ranking list -- see the +# netconfig(8) manual page -- "none" or "" disables the ranking. +# +NETCONFIG_DNS_RANKING="auto" + +## Type: string +## Default: "" +# +# Allows to specify options to use when writing the /etc/resolv.conf, +# for example: +# "debug attempts:1 timeout:10" +# See resolv.conf(5) manual page for details. +# +NETCONFIG_DNS_RESOLVER_OPTIONS="" + +## Type: string +## Default: "" +# +# Allows to specify a sortlist to use when writing the /etc/resolv.conf, +# for example: +# 130.155.160.0/255.255.240.0 130.155.0.0" +# See resolv.conf(5) manual page for details. +# +NETCONFIG_DNS_RESOLVER_SORTLIST="" + +## Type: string +## Default: "auto" +# +# Defines the NTP merge policy as documented in netconfig(8) manual page. +# Set to "" to disable NTP configuration. +# +NETCONFIG_NTP_POLICY="auto" + +## Type: string +## Default: "" +# +# List of NTP servers. +# +NETCONFIG_NTP_STATIC_SERVERS="" + +## Type: string +## Default: "auto" +# +# Defines the NIS merge policy as documented in netconfig(8) manual page. +# Set to "" to disable NIS configuration. +# +NETCONFIG_NIS_POLICY="auto" + +## Type: string(yes,no,) +## Default: "yes" +# +# Defines whether to set the default NIS domain. When enabled and no domain +# is provided dynamically or in static settings, /etc/defaultdomain is used. +# Valid values are: +# - "no" or "" netconfig does not set the domainname +# - "yes" netconfig sets the domainname according to the +# NIS policy using settings provided by the first +# interface and service that provided it. +# - "" as yes, but only using settings from interface. +# +NETCONFIG_NIS_SETDOMAINNAME="yes" + +## Type: string +## Default: "" +# +# Defines a default NIS domain. +# +# Further domain can be specified by adding a "_" suffix to +# the NETCONFIG_NIS_STATIC_DOMAIN and NETCONFIG_NIS_STATIC_SERVERS +# variables, e.g.: NETCONFIG_NIS_STATIC_DOMAIN_1="second". +# +NETCONFIG_NIS_STATIC_DOMAIN="" + +## Type: string +## Default: "" +# +# Defines a list of NIS servers for the default NIS domain or the +# domain specified with same "_" suffix. +# +NETCONFIG_NIS_STATIC_SERVERS="" + +## Type: string +## Default: '' +# +# Set this variable global variable to the ISO / IEC 3166 alpha2 +# country code specifying the wireless regulatory domain to set. +# When not empty, ifup-wireless will be set in the wpa_supplicant +# config or via 'iw reg set' command. +# +# Note: This option requires a wpa driver supporting it, like +# the 'nl80211' driver used by default since openSUSE 11.3. +# When you notice problems with your hardware, please file a +# bug report and set e.g. WIRELESS_WPA_DRIVER='wext' (the old +# default driver) in the ifcfg file. +# See also "/usr/sbin/wpa_supplicant --help" for the list of +# available wpa drivers. +# +WIRELESS_REGULATORY_DOMAIN='' +## Type: integer +## Default: "" +# +# How log to wait for IPv6 autoconfig in ifup when requested with +# the auto6 or +auto6 tag in BOOTPROTO variable. +# When unset, a wicked built-in default defer time (10sec) is used. +# +AUTO6_WAIT_AT_BOOT="" + +## Type: list(all,dns,none,"") +## Default: "" +# +# Whether to update system (DNS) settings from IPv6 RA when requested +# with the auto6 or +auto6 tag in BOOTPROTO variable. +# Defaults to update if autoconf sysctl (address autoconf) is enabled. +# +AUTO6_UPDATE="" + +## Type: list(auto,yes,no) +## Default: "auto" +# +# Permits to specify/modify a global ifcfg default. Use with care! +# +# This settings breaks rules for many things, which require carrier +# before they can start, e.g. L2 link protocols, link authentication, +# ipv4 duplicate address detection, ipv6 duplicate detection will +# happen "post-mortem" and maybe even cause to disable ipv6 at all. +# See also "man ifcfg" for further information. +# +LINK_REQUIRED="auto" + +## Type: string +## Default: "" +# +# Allows to specify a comma separated list of debug facilities used +# by wicked. Negated facility names can be prepended by a "-", e.g.: +# "all,-events,-socket,-objectmodel,xpath,xml,dbus" +# +# When set, wicked debug level is automatically enabled. +# For a complete list of facility names, see: "wicked --debug help". +# +WICKED_DEBUG="" + +## Type: list("",error,warning,notice,info,debug,debug1,debug2,debug3) +## Default: "" +# +# Allows to specify wicked debug level. Default level is "notice". +# +WICKED_LOG_LEVEL="" diff --git a/rust/migrate-wicked/tests/static_dns/system-connections/lo.nmconnection b/rust/migrate-wicked/tests/static_dns/system-connections/lo.nmconnection new file mode 100644 index 0000000000..79208ebc0b --- /dev/null +++ b/rust/migrate-wicked/tests/static_dns/system-connections/lo.nmconnection @@ -0,0 +1,26 @@ +[connection] +id=lo +uuid=8711628a-f044-4516-a5b4-bb19f4f9f8fd +type=loopback +interface-name=lo + +[ethernet] + +[loopback] + +[match] + +[ipv4] +address1=127.0.0.1/8 +dns=192.168.0.10;192.168.1.10; +dns-search=suse.de;suse.com; +method=manual + +[ipv6] +addr-gen-mode=default +address1=::1/128 +dns=2001:db8::10; +dns-search=suse.de;suse.com; +method=manual + +[proxy] diff --git a/rust/migrate-wicked/tests/static_dns/wicked_xml/basic.xml b/rust/migrate-wicked/tests/static_dns/wicked_xml/basic.xml new file mode 100644 index 0000000000..1ba98f25f4 --- /dev/null +++ b/rust/migrate-wicked/tests/static_dns/wicked_xml/basic.xml @@ -0,0 +1,14 @@ + + eth0 + + boot + + + + + false + + + false + + diff --git a/rust/migrate-wicked/tests/test.sh b/rust/migrate-wicked/tests/test.sh index 2b2eed7f79..597eca71ef 100755 --- a/rust/migrate-wicked/tests/test.sh +++ b/rust/migrate-wicked/tests/test.sh @@ -19,12 +19,9 @@ if [[ $(ls -A /etc/NetworkManager/system-connections/) ]]; then exit 1 fi -nm_connections="$(nmcli connection | tail -n +2 | awk '{print $1}')"; nm_cleanup() { - for i in $(nmcli connection | tail -n +2 | awk '{print $1}'); do - if ! printf '%s\0' "${nm_connections[@]}" | grep -qwz $i; then - nmcli connection delete "$i" - fi + for con in $(ls /etc/NetworkManager/system-connections/ | sed 's/\.nmconnection//'); do + nmcli con delete $con done } @@ -36,23 +33,28 @@ fi for test_dir in ${TEST_DIRS}; do echo -e "${BOLD}Testing ${test_dir}${NC}" + migrate_args="" + show_args="" + if [[ $test_dir == *"failure" ]]; then expect_fail=true else expect_fail=false + migrate_args+=" -c" + fi + + if [ -d $test_dir/netconfig ]; then + migrate_args+=" --netconfig-path $test_dir/netconfig/config" + show_args+=" --netconfig-path $test_dir/netconfig/config" fi - $MIGRATE_WICKED_BIN show $test_dir/wicked_xml + $MIGRATE_WICKED_BIN show $show_args $test_dir/wicked_xml if [ $? -ne 0 ] && [ "$expect_fail" = false ]; then error_msg ${test_dir} "show failed" FAILED_TESTS+=("${test_dir}::show") fi - if [ "$expect_fail" = true ]; then - $MIGRATE_WICKED_BIN migrate $test_dir/wicked_xml - else - $MIGRATE_WICKED_BIN migrate -c $test_dir/wicked_xml - fi + $MIGRATE_WICKED_BIN migrate $migrate_args $test_dir/wicked_xml if [ $? -ne 0 ] && [ "$expect_fail" = false ]; then error_msg ${test_dir} "migration failed" FAILED_TESTS+=("${test_dir}::migrate") @@ -60,8 +62,9 @@ for test_dir in ${TEST_DIRS}; do elif [ $? -ne 0 ] && [ "$expect_fail" = true ]; then echo -e "${GREEN}Migration for $test_dir failed as expected${NC}" fi + for cmp_file in $(ls -1 $test_dir/system-connections/); do - diff --unified=0 --color=always -I uuid $test_dir/system-connections/$cmp_file /etc/NetworkManager/system-connections/${cmp_file} + diff --unified=0 --color=always -I uuid -I timestamp $test_dir/system-connections/$cmp_file /etc/NetworkManager/system-connections/${cmp_file} if [ $? -ne 0 ]; then error_msg ${test_dir} "$cmp_file didn't match" FAILED_TESTS+=("${test_dir}::compare_config::${cmp_file}") From 7e21f090b81e93bdf8b93098845a6b9c79a6a01e Mon Sep 17 00:00:00 2001 From: Jorik Cronenberg Date: Tue, 12 Mar 2024 15:17:47 +0100 Subject: [PATCH 2/8] Fix NM access to loopback in integration CI --- .github/workflows/migrate-wicked-integration-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/migrate-wicked-integration-tests.yml b/.github/workflows/migrate-wicked-integration-tests.yml index 55a61fcd6d..23e5f99bea 100644 --- a/.github/workflows/migrate-wicked-integration-tests.yml +++ b/.github/workflows/migrate-wicked-integration-tests.yml @@ -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" From 4ced5c7acae3926cf32cc4b4bdfab99dd248864b Mon Sep 17 00:00:00 2001 From: Jorik Cronenberg Date: Tue, 12 Mar 2024 15:33:10 +0100 Subject: [PATCH 3/8] Create fallback loopback connection if not available --- rust/migrate-wicked/src/migrate.rs | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/rust/migrate-wicked/src/migrate.rs b/rust/migrate-wicked/src/migrate.rs index 5b8c11e84a..503d90d9ba 100644 --- a/rust/migrate-wicked/src/migrate.rs +++ b/rust/migrate-wicked/src/migrate.rs @@ -1,7 +1,9 @@ use crate::bridge::BridgePort; use crate::{reader::read as wicked_read, MIGRATION_SETTINGS}; -use agama_server::network::model::{Connection, GeneralState, StateConfig}; -use agama_server::network::{Adapter, NetworkManagerAdapter, NetworkState}; +use agama_server::network::model::{MatchConfig, IpConfig, Connection, GeneralState, StateConfig}; +use agama_server::network::{Adapter, NetworkManagerAdapter, NetworkState, model}; +use cidr::IpInet; +use std::str::FromStr; use std::{collections::HashMap, error::Error}; use uuid::Uuid; @@ -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) -> Result<(), Box> { let interfaces = wicked_read(paths.clone())?; let settings = MIGRATION_SETTINGS.get().unwrap(); @@ -131,7 +152,10 @@ pub async fn migrate(paths: Vec) -> Result<(), Box> { if let Some(netconfig) = interfaces.netconfig { let current_state = nm.read(StateConfig::default()).await?; - let mut loopback = current_state.get_connection("lo").unwrap().clone(); + 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) => { From 47fdba12cde7c814590517222a1f3a0ffdad1a60 Mon Sep 17 00:00:00 2001 From: Jorik Cronenberg Date: Thu, 14 Mar 2024 11:37:09 +0100 Subject: [PATCH 4/8] Set ignore-auto-dns for all non lo connections --- rust/migrate-wicked/src/migrate.rs | 5 +++++ .../system-connections/eth9.nmconnection | 20 +++++++++++++++++++ .../tests/static_dns/wicked_xml/basic.xml | 4 ++-- 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 rust/migrate-wicked/tests/static_dns/system-connections/eth9.nmconnection diff --git a/rust/migrate-wicked/src/migrate.rs b/rust/migrate-wicked/src/migrate.rs index 503d90d9ba..e530a8a883 100644 --- a/rust/migrate-wicked/src/migrate.rs +++ b/rust/migrate-wicked/src/migrate.rs @@ -171,6 +171,11 @@ pub async fn migrate(paths: Vec) -> Result<(), Box> { 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)?; } diff --git a/rust/migrate-wicked/tests/static_dns/system-connections/eth9.nmconnection b/rust/migrate-wicked/tests/static_dns/system-connections/eth9.nmconnection new file mode 100644 index 0000000000..7fcde336e2 --- /dev/null +++ b/rust/migrate-wicked/tests/static_dns/system-connections/eth9.nmconnection @@ -0,0 +1,20 @@ +[connection] +id=eth9 +uuid=5e734b30-8000-4889-894e-61c7a185b835 +type=ethernet +interface-name=eth9 + +[ethernet] + +[match] + +[ipv4] +ignore-auto-dns=true +method=disabled + +[ipv6] +addr-gen-mode=default +ignore-auto-dns=true +method=disabled + +[proxy] diff --git a/rust/migrate-wicked/tests/static_dns/wicked_xml/basic.xml b/rust/migrate-wicked/tests/static_dns/wicked_xml/basic.xml index 1ba98f25f4..634faaf761 100644 --- a/rust/migrate-wicked/tests/static_dns/wicked_xml/basic.xml +++ b/rust/migrate-wicked/tests/static_dns/wicked_xml/basic.xml @@ -1,5 +1,5 @@ - - eth0 + + eth9 boot From e7d513570032f689329ec5bc315d479f8ff0f81a Mon Sep 17 00:00:00 2001 From: Jorik Cronenberg Date: Thu, 14 Mar 2024 12:02:58 +0100 Subject: [PATCH 5/8] Add netconfig unit tests --- rust/migrate-wicked/src/infiniband.rs | 1 + rust/migrate-wicked/src/migrate.rs | 4 +-- rust/migrate-wicked/src/netconfig.rs | 51 ++++++++++++++++++++++++++- rust/migrate-wicked/src/wireless.rs | 1 + 4 files changed, 54 insertions(+), 3 deletions(-) diff --git a/rust/migrate-wicked/src/infiniband.rs b/rust/migrate-wicked/src/infiniband.rs index 4e8739b472..c5e88039d0 100644 --- a/rust/migrate-wicked/src/infiniband.rs +++ b/rust/migrate-wicked/src/infiniband.rs @@ -74,6 +74,7 @@ mod tests { continue_migration: false, dry_run: false, activate_connections: true, + netconfig_path: "".to_string(), }); } diff --git a/rust/migrate-wicked/src/migrate.rs b/rust/migrate-wicked/src/migrate.rs index e530a8a883..e0d1fa9e29 100644 --- a/rust/migrate-wicked/src/migrate.rs +++ b/rust/migrate-wicked/src/migrate.rs @@ -1,7 +1,7 @@ use crate::bridge::BridgePort; use crate::{reader::read as wicked_read, MIGRATION_SETTINGS}; -use agama_server::network::model::{MatchConfig, IpConfig, Connection, GeneralState, StateConfig}; -use agama_server::network::{Adapter, NetworkManagerAdapter, NetworkState, model}; +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}; diff --git a/rust/migrate-wicked/src/netconfig.rs b/rust/migrate-wicked/src/netconfig.rs index f8cbebf803..cb7c31c84b 100644 --- a/rust/migrate-wicked/src/netconfig.rs +++ b/rust/migrate-wicked/src/netconfig.rs @@ -24,10 +24,13 @@ pub fn read_netconfig(path: impl AsRef) -> Result, anyho if let Err(e) = dotenv::from_filename(path) { return Err(e.into()); }; + handle_netconfig_values() +} + +fn handle_netconfig_values() -> Result, 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 { - println!("{:?}", dns_policies); return Err(anyhow::anyhow!( "For NETCONFIG_DNS_POLICY only single policies are supported" )); @@ -67,3 +70,49 @@ pub fn read_netconfig(path: impl AsRef) -> Result, anyho } 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 + }) + ); + } +} diff --git a/rust/migrate-wicked/src/wireless.rs b/rust/migrate-wicked/src/wireless.rs index 64b07917ed..8e08224ee2 100644 --- a/rust/migrate-wicked/src/wireless.rs +++ b/rust/migrate-wicked/src/wireless.rs @@ -185,6 +185,7 @@ mod tests { continue_migration: false, dry_run: false, activate_connections: true, + netconfig_path: "".to_string(), }); } From 9e7e14097b21b7bc8c89af4dbbec55ae2a9c4724 Mon Sep 17 00:00:00 2001 From: Jorik Cronenberg Date: Tue, 11 Jun 2024 17:34:02 +0200 Subject: [PATCH 6/8] Add without-netconfig argument --- rust/migrate-wicked/src/infiniband.rs | 1 + rust/migrate-wicked/src/main.rs | 7 +++++++ rust/migrate-wicked/src/reader.rs | 20 +++++++++++--------- rust/migrate-wicked/src/wireless.rs | 1 + rust/migrate-wicked/tests/test.sh | 3 +++ 5 files changed, 23 insertions(+), 9 deletions(-) diff --git a/rust/migrate-wicked/src/infiniband.rs b/rust/migrate-wicked/src/infiniband.rs index c5e88039d0..fb03631140 100644 --- a/rust/migrate-wicked/src/infiniband.rs +++ b/rust/migrate-wicked/src/infiniband.rs @@ -74,6 +74,7 @@ mod tests { continue_migration: false, dry_run: false, activate_connections: true, + without_netconfig: true, netconfig_path: "".to_string(), }); } diff --git a/rust/migrate-wicked/src/main.rs b/rust/migrate-wicked/src/main.rs index 8a8974f72d..07b876916a 100644 --- a/rust/migrate-wicked/src/main.rs +++ b/rust/migrate-wicked/src/main.rs @@ -36,6 +36,9 @@ 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::().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, } @@ -88,6 +91,7 @@ async fn run_command(cli: Cli) -> anyhow::Result<()> { continue_migration: true, dry_run: false, activate_connections: true, + without_netconfig: cli.global_opts.without_netconfig, netconfig_path: cli.global_opts.netconfig_path, }) .expect("MIGRATION_SETTINGS was set too early"); @@ -125,6 +129,7 @@ async fn run_command(cli: Cli) -> anyhow::Result<()> { continue_migration, dry_run, activate_connections, + without_netconfig: cli.global_opts.without_netconfig, netconfig_path: cli.global_opts.netconfig_path, }) .expect("MIGRATION_SETTINGS was set too early"); @@ -161,6 +166,7 @@ struct MigrationSettings { continue_migration: bool, dry_run: bool, activate_connections: bool, + without_netconfig: bool, netconfig_path: String, } @@ -170,6 +176,7 @@ impl Default for MigrationSettings { continue_migration: false, dry_run: false, activate_connections: true, + without_netconfig: false, netconfig_path: "".to_string(), } } diff --git a/rust/migrate-wicked/src/reader.rs b/rust/migrate-wicked/src/reader.rs index 3347b5e75c..8ad0e71c77 100644 --- a/rust/migrate-wicked/src/reader.rs +++ b/rust/migrate-wicked/src/reader.rs @@ -84,15 +84,17 @@ pub fn read(paths: Vec) -> Result { warning: None, }; - match read_netconfig(settings.netconfig_path.clone()) { - Ok(netconfig) => result.netconfig = netconfig, - Err(e) => { - if !settings.continue_migration { - return Err(e); - }; - log::warn!("Failed to read netconfig: {}", e); - } - }; + if !settings.without_netconfig { + match read_netconfig(settings.netconfig_path.clone()) { + Ok(netconfig) => result.netconfig = netconfig, + Err(e) => { + if !settings.continue_migration { + return Err(e); + }; + log::warn!("Failed to read netconfig: {}", e); + } + }; + } for path in paths { let path: PathBuf = path.into(); diff --git a/rust/migrate-wicked/src/wireless.rs b/rust/migrate-wicked/src/wireless.rs index 8e08224ee2..0703647bca 100644 --- a/rust/migrate-wicked/src/wireless.rs +++ b/rust/migrate-wicked/src/wireless.rs @@ -185,6 +185,7 @@ mod tests { continue_migration: false, dry_run: false, activate_connections: true, + without_netconfig: true, netconfig_path: "".to_string(), }); } diff --git a/rust/migrate-wicked/tests/test.sh b/rust/migrate-wicked/tests/test.sh index 597eca71ef..14af6ccfc8 100755 --- a/rust/migrate-wicked/tests/test.sh +++ b/rust/migrate-wicked/tests/test.sh @@ -46,6 +46,9 @@ for test_dir in ${TEST_DIRS}; do if [ -d $test_dir/netconfig ]; then migrate_args+=" --netconfig-path $test_dir/netconfig/config" show_args+=" --netconfig-path $test_dir/netconfig/config" + else + migrate_args+=" --without-netconfig" + show_args+=" --without-netconfig" fi $MIGRATE_WICKED_BIN show $show_args $test_dir/wicked_xml From 410ab9f45d65345f2f06e2c546b765da500110bf Mon Sep 17 00:00:00 2001 From: Jorik Cronenberg Date: Mon, 12 Aug 2024 16:41:51 +0200 Subject: [PATCH 7/8] Use default migration settings for infiniband unit tests --- rust/migrate-wicked/src/infiniband.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/rust/migrate-wicked/src/infiniband.rs b/rust/migrate-wicked/src/infiniband.rs index fb03631140..965986f154 100644 --- a/rust/migrate-wicked/src/infiniband.rs +++ b/rust/migrate-wicked/src/infiniband.rs @@ -70,13 +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, - without_netconfig: true, - netconfig_path: "".to_string(), - }); + let _ = MIGRATION_SETTINGS.set(crate::MigrationSettings::default()); } #[test] From 0810a16d3a8024b572a17489d6a250e4f8a760d9 Mon Sep 17 00:00:00 2001 From: Clemens Famulla-Conrad Date: Thu, 29 Aug 2024 21:25:19 +0200 Subject: [PATCH 8/8] Use with_netconfig=true as default --- rust/migrate-wicked/src/main.rs | 8 ++++---- rust/migrate-wicked/src/reader.rs | 2 +- rust/migrate-wicked/src/wireless.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/rust/migrate-wicked/src/main.rs b/rust/migrate-wicked/src/main.rs index 07b876916a..88efdd3543 100644 --- a/rust/migrate-wicked/src/main.rs +++ b/rust/migrate-wicked/src/main.rs @@ -91,7 +91,7 @@ async fn run_command(cli: Cli) -> anyhow::Result<()> { continue_migration: true, dry_run: false, activate_connections: true, - without_netconfig: cli.global_opts.without_netconfig, + with_netconfig: !cli.global_opts.without_netconfig, netconfig_path: cli.global_opts.netconfig_path, }) .expect("MIGRATION_SETTINGS was set too early"); @@ -129,7 +129,7 @@ async fn run_command(cli: Cli) -> anyhow::Result<()> { continue_migration, dry_run, activate_connections, - without_netconfig: cli.global_opts.without_netconfig, + with_netconfig: !cli.global_opts.without_netconfig, netconfig_path: cli.global_opts.netconfig_path, }) .expect("MIGRATION_SETTINGS was set too early"); @@ -166,7 +166,7 @@ struct MigrationSettings { continue_migration: bool, dry_run: bool, activate_connections: bool, - without_netconfig: bool, + with_netconfig: bool, netconfig_path: String, } @@ -176,7 +176,7 @@ impl Default for MigrationSettings { continue_migration: false, dry_run: false, activate_connections: true, - without_netconfig: false, + with_netconfig: false, netconfig_path: "".to_string(), } } diff --git a/rust/migrate-wicked/src/reader.rs b/rust/migrate-wicked/src/reader.rs index 8ad0e71c77..dcc75c9253 100644 --- a/rust/migrate-wicked/src/reader.rs +++ b/rust/migrate-wicked/src/reader.rs @@ -84,7 +84,7 @@ pub fn read(paths: Vec) -> Result { warning: None, }; - if !settings.without_netconfig { + if settings.with_netconfig { match read_netconfig(settings.netconfig_path.clone()) { Ok(netconfig) => result.netconfig = netconfig, Err(e) => { diff --git a/rust/migrate-wicked/src/wireless.rs b/rust/migrate-wicked/src/wireless.rs index 0703647bca..9dbcc1f3f7 100644 --- a/rust/migrate-wicked/src/wireless.rs +++ b/rust/migrate-wicked/src/wireless.rs @@ -185,7 +185,7 @@ mod tests { continue_migration: false, dry_run: false, activate_connections: true, - without_netconfig: true, + with_netconfig: false, netconfig_path: "".to_string(), }); }