diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 6cf937638a..5a72b8489f 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -13,7 +13,6 @@ name = "agama-cli" version = "1.0.0" dependencies = [ "agama-lib", - "agama-migrate-wicked", "agama-settings", "anyhow", "async-std", @@ -99,11 +98,17 @@ version = "0.1.0" dependencies = [ "agama-dbus-server", "agama-lib", + "anyhow", "async-std", "cidr", + "clap", + "log", "quick-xml", "regex", "serde", + "serde_json", + "serde_yaml", + "simplelog", ] [[package]] diff --git a/rust/agama-cli/Cargo.toml b/rust/agama-cli/Cargo.toml index 81628eb7e7..c7701ae7f4 100644 --- a/rust/agama-cli/Cargo.toml +++ b/rust/agama-cli/Cargo.toml @@ -9,7 +9,6 @@ edition = "2021" clap = { version = "4.1.4", features = ["derive", "wrap_help"] } agama-lib = { path="../agama-lib" } agama-settings = { path="../agama-settings" } -agama-migrate-wicked = { path="../agama-migrate-wicked" } serde = { version = "1.0.152" } serde_json = "1.0.91" serde_yaml = "0.9.17" diff --git a/rust/agama-cli/src/commands.rs b/rust/agama-cli/src/commands.rs index a095d59a09..99d51ece9f 100644 --- a/rust/agama-cli/src/commands.rs +++ b/rust/agama-cli/src/commands.rs @@ -2,7 +2,6 @@ use crate::config::ConfigCommands; use crate::logs::LogsCommands; use crate::profile::ProfileCommands; use crate::questions::QuestionsCommands; -use crate::wicked::WickedCommands; use clap::Subcommand; #[derive(Subcommand, Debug)] @@ -36,7 +35,4 @@ pub enum Commands { /// Collects logs #[command(subcommand)] Logs(LogsCommands), - /// Migrate wicked config - #[command(subcommand)] - Wicked(WickedCommands), } diff --git a/rust/agama-cli/src/main.rs b/rust/agama-cli/src/main.rs index c8d1cad8e7..b555884b6c 100644 --- a/rust/agama-cli/src/main.rs +++ b/rust/agama-cli/src/main.rs @@ -8,7 +8,6 @@ mod printers; mod profile; mod progress; mod questions; -mod wicked; use crate::error::CliError; use agama_lib::error::ServiceError; @@ -27,7 +26,6 @@ use std::{ thread::sleep, time::Duration, }; -use wicked::run as run_wicked_cmd; #[derive(Parser)] #[command(name = "agama", version, about, long_about = None)] @@ -136,7 +134,6 @@ async fn run_command(cli: Cli) -> anyhow::Result<()> { } Commands::Questions(subcommand) => block_on(run_questions_cmd(subcommand)), Commands::Logs(subcommand) => block_on(run_logs_cmd(subcommand)), - Commands::Wicked(subcommand) => block_on(run_wicked_cmd(subcommand, cli.format)), _ => unimplemented!(), } } diff --git a/rust/agama-migrate-wicked/Cargo.toml b/rust/agama-migrate-wicked/Cargo.toml index 41fc281afd..3d54e1dcea 100644 --- a/rust/agama-migrate-wicked/Cargo.toml +++ b/rust/agama-migrate-wicked/Cargo.toml @@ -7,9 +7,19 @@ edition = "2021" [dependencies] serde = { version = "1.0.152", features = ["derive"] } +serde_json = "1.0.91" +serde_yaml = "0.9.17" quick-xml = { version = "0.28.2", features = ["serialize"] } agama-lib = { path="../agama-lib" } regex = "1.9.5" agama-dbus-server = { path="../agama-dbus-server" } async-std = "1.12.0" cidr = { version = "0.2.2", features = ["serde"] } +clap = { version = "4.1.4", features = ["derive", "wrap_help"] } +anyhow = "1.0.71" +log = "0.4" +simplelog = "0.12.1" + +[[bin]] +name = "migrate-wicked" +path = "src/main.rs" diff --git a/rust/agama-migrate-wicked/README.md b/rust/agama-migrate-wicked/README.md new file mode 100644 index 0000000000..193fc08218 --- /dev/null +++ b/rust/agama-migrate-wicked/README.md @@ -0,0 +1,11 @@ +# Migrate wicked +This project creates a `migrate-wicked` binary which is able to parse wicked xml configs and send them to a NetworkManager dbus service. +## Architecture +`migrate-wicked` uses agama as a library to communicate the parsed network state to NetworkManager +but the binary is completely independent of any agama services and can be run standalone +## Obtaining wicked xml config +A wicked config xml can be generated by running `wicked show-config > wicked.xml` which can then be passed to `migrate-wicked` +## Testing +Running the migration on a live system isn't currently recommended. To test it's recommended to use a container +(instructions how to set one up can be found [here](https://github.com/openSUSE/agama/blob/master/rust/agama-cli/doc/backend-for-testing.md)) +Example configurations can be found under `tests` diff --git a/rust/agama-migrate-wicked/src/lib.rs b/rust/agama-migrate-wicked/src/lib.rs deleted file mode 100644 index a184bc4c4e..0000000000 --- a/rust/agama-migrate-wicked/src/lib.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod interface; -pub mod migrate; -pub mod reader; diff --git a/rust/agama-migrate-wicked/src/main.rs b/rust/agama-migrate-wicked/src/main.rs new file mode 100644 index 0000000000..81eb00abf3 --- /dev/null +++ b/rust/agama-migrate-wicked/src/main.rs @@ -0,0 +1,106 @@ +mod interface; +mod migrate; +mod reader; + +use clap::builder::TypedValueParser; +use clap::{Args, Parser, Subcommand}; +use log::*; +use migrate::migrate; +use reader::read as wicked_read; +use std::process::{ExitCode, Termination}; + +#[derive(Parser)] +#[command(name = "migrate-wicked", version, about, long_about = None)] +struct Cli { + #[clap(flatten)] + global_opts: GlobalOpts, + + #[command(subcommand)] + pub command: Commands, +} + +#[derive(Debug, Args)] +struct GlobalOpts { + #[arg(long, global = true, default_value_t = LevelFilter::Error, value_parser = clap::builder::PossibleValuesParser::new(["TRACE", "DEBUG", "INFO", "WARN", "ERROR"]).map(|s| s.parse::().unwrap()),)] + pub log_level: LevelFilter, +} + +#[derive(Subcommand)] +pub enum Commands { + /// Shows the current xml wicked configuration + Show { + /// Format output + #[arg(value_enum, short, long, default_value_t = Format::Json)] + format: Format, + + /// Path to file or directory where the wicked xml config is located + path: String, + }, + /// Migrate wicked state at path + Migrate { + /// Path to file or directory where the wicked xml config is located + path: String, + }, +} + +/// Supported output formats +#[derive(clap::ValueEnum, Clone)] +pub enum Format { + Json, + PrettyJson, + Yaml, + Text, +} + +async fn run_command(cli: Cli) -> anyhow::Result<()> { + match cli.command { + Commands::Show { path, format } => { + let interfaces = wicked_read(path.into()).await?; + let output: String = match format { + Format::Json => serde_json::to_string(&interfaces)?, + Format::PrettyJson => serde_json::to_string_pretty(&interfaces)?, + Format::Yaml => serde_yaml::to_string(&interfaces)?, + Format::Text => format!("{:?}", interfaces), + }; + println!("{}", output); + Ok(()) + } + Commands::Migrate { path } => { + migrate(path).await.unwrap(); + Ok(()) + } + } +} + +/// Represents the result of execution. +pub enum CliResult { + /// Successful execution. + Ok = 0, + /// Something went wrong. + Error = 1, +} + +impl Termination for CliResult { + fn report(self) -> ExitCode { + ExitCode::from(self as u8) + } +} + +#[async_std::main] +async fn main() -> CliResult { + let cli = Cli::parse(); + + simplelog::TermLogger::init( + cli.global_opts.log_level, + simplelog::Config::default(), + simplelog::TerminalMode::Stderr, + simplelog::ColorChoice::Auto, + ) + .unwrap(); + + if let Err(error) = run_command(cli).await { + eprintln!("{:?}", error); + return CliResult::Error; + } + CliResult::Ok +}