diff --git a/src/bin/krillpubc.rs b/src/bin/krillpubc.rs deleted file mode 100644 index 1098a5b8..00000000 --- a/src/bin/krillpubc.rs +++ /dev/null @@ -1,41 +0,0 @@ -extern crate krill; - -use krill::cli::options::KrillPubcOptions; -use krill::cli::report::ReportFormat; -use krill::cli::{Error, KrillPubdClient}; -use krill::commons::util::httpclient; - -#[tokio::main] -async fn main() { - match KrillPubcOptions::from_args() { - Ok(options) => { - let format = options.format; - match KrillPubdClient::report(options).await { - Ok(()) => {} //, - Err(e) => { - if format != ReportFormat::None { - match &e { - Error::HttpClientError(httpclient::Error::ErrorWithJson(_code, res)) => { - if format == ReportFormat::Json { - eprintln!("{}", e); - } else if let Some(delta_error) = res.delta_error() { - eprintln!("Delta rejected:\n\n{}", delta_error); - } else { - eprintln!("Error: {}", res.msg()); - } - } - _ => { - eprintln!("{}", e); - } - } - } - ::std::process::exit(1); - } - } - } - Err(e) => { - eprintln!("{}", e); - ::std::process::exit(1); - } - } -} diff --git a/src/cli/client.rs b/src/cli/client.rs index b235ec52..41e7584a 100644 --- a/src/cli/client.rs +++ b/src/cli/client.rs @@ -18,7 +18,7 @@ use crate::commons::util::{file, httpclient}; use crate::constants::KRILL_CLI_API_ENV; use crate::daemon::config::Config; use crate::{ - cli::options::{BulkCaCommand, CaCommand, Command, KrillInitDetails, KrillPubcOptions, Options, PublishersCommand}, + cli::options::{BulkCaCommand, CaCommand, Command, KrillInitDetails, Options, PubServerCommand}, commons::error::KrillIoError, }; @@ -122,6 +122,7 @@ impl KrillClient { Command::Info => client.info().await, Command::Bulk(cmd) => client.bulk(cmd).await, Command::CertAuth(cmd) => client.certauth(cmd).await, + Command::PubServer(cmd) => client.publishers(cmd).await, Command::Init(details) => client.init_config(details), #[cfg(feature = "multi-user")] Command::User(cmd) => client.user(cmd), @@ -397,6 +398,56 @@ impl KrillClient { } } + /// Processes the options, and returns a response ready for formatting. + /// Note that this function is public to help integration testing the API + /// and client. + pub async fn publishers(&self, command: PubServerCommand) -> Result { + match command { + PubServerCommand::PublisherList => { + let list: PublisherList = get_json(&self.server, &self.token, "api/v1/pubd/publishers").await?; + Ok(ApiResponse::PublisherList(list)) + } + PubServerCommand::StalePublishers(seconds) => { + let uri = format!("api/v1/pubd/stale/{}", seconds); + let stales = get_json(&self.server, &self.token, &uri).await?; + Ok(ApiResponse::PublisherList(stales)) + } + PubServerCommand::RepositoryStats => { + let stats = get_json(&self.server, &self.token, "stats/repo").await?; + Ok(ApiResponse::RepoStats(stats)) + } + PubServerCommand::RepositoryInit(uris) => { + let uri = "api/v1/pubd/init"; + post_json(&self.server, &self.token, uri, uris).await?; + Ok(ApiResponse::Empty) + } + PubServerCommand::RepositoryClear => { + let uri = "api/v1/pubd/init"; + delete(&self.server, &self.token, uri).await?; + Ok(ApiResponse::Empty) + } + PubServerCommand::AddPublisher(req) => { + let res = post_json_with_response(&self.server, &self.token, "api/v1/pubd/publishers", req).await?; + Ok(ApiResponse::Rfc8183RepositoryResponse(res)) + } + PubServerCommand::RemovePublisher(handle) => { + let uri = format!("api/v1/pubd/publishers/{}", handle); + delete(&self.server, &self.token, &uri).await?; + Ok(ApiResponse::Empty) + } + PubServerCommand::ShowPublisher(handle) => { + let uri = format!("api/v1/pubd/publishers/{}", handle); + let details: PublisherDetails = get_json(&self.server, &self.token, &uri).await?; + Ok(ApiResponse::PublisherDetails(details)) + } + PubServerCommand::RepositoryResponse(handle) => { + let uri = format!("api/v1/pubd/publishers/{}/response.json", handle); + let res = get_json(&self.server, &self.token, &uri).await?; + Ok(ApiResponse::Rfc8183RepositoryResponse(res)) + } + } + } + fn init_config(&self, details: KrillInitDetails) -> Result { let defaults = include_str!("../../defaults/krill.conf"); let multi_add_on = include_str!("../../defaults/krill-multi-user.conf"); @@ -504,82 +555,6 @@ impl KrillClient { } } -//------------ KrillPubdClient ----------------------------------------------- - -pub struct KrillPubdClient; - -impl KrillPubdClient { - /// Delegates the options to be processed, and reports the response - /// back to the user. Note that error reporting is handled by CLI. - pub async fn report(options: KrillPubcOptions) -> Result<(), Error> { - let format = options.format; - let res = Self::process(options).await?; - - if let Some(string) = res.report(format)? { - println!("{}", string) - } - Ok(()) - } - - /// Processes the options, and returns a response ready for formatting. - /// Note that this function is public to help integration testing the API - /// and client. - pub async fn process(options: KrillPubcOptions) -> Result { - let (server, token, _format, api, command) = options.unpack(); - - if api { - // passing the api option in the env, so that the call - // to the back-end will just print and exit. - env::set_var(KRILL_CLI_API_ENV, "1") - } - - match command { - PublishersCommand::PublisherList => { - let list: PublisherList = get_json(&server, &token, "api/v1/pubd/publishers").await?; - Ok(ApiResponse::PublisherList(list)) - } - PublishersCommand::StalePublishers(seconds) => { - let uri = format!("api/v1/pubd/stale/{}", seconds); - let stales = get_json(&server, &token, &uri).await?; - Ok(ApiResponse::PublisherList(stales)) - } - PublishersCommand::RepositoryStats => { - let stats = get_json(&server, &token, "stats/repo").await?; - Ok(ApiResponse::RepoStats(stats)) - } - PublishersCommand::RepositoryInit(uris) => { - let uri = "api/v1/pubd/init"; - post_json(&server, &token, uri, uris).await?; - Ok(ApiResponse::Empty) - } - PublishersCommand::RepositoryClear => { - let uri = "api/v1/pubd/init"; - delete(&server, &token, uri).await?; - Ok(ApiResponse::Empty) - } - PublishersCommand::AddPublisher(req) => { - let res = post_json_with_response(&server, &token, "api/v1/pubd/publishers", req).await?; - Ok(ApiResponse::Rfc8183RepositoryResponse(res)) - } - PublishersCommand::RemovePublisher(handle) => { - let uri = format!("api/v1/pubd/publishers/{}", handle); - delete(&server, &token, &uri).await?; - Ok(ApiResponse::Empty) - } - PublishersCommand::ShowPublisher(handle) => { - let uri = format!("api/v1/pubd/publishers/{}", handle); - let details: PublisherDetails = get_json(&server, &token, &uri).await?; - Ok(ApiResponse::PublisherDetails(details)) - } - PublishersCommand::RepositoryResponse(handle) => { - let uri = format!("api/v1/pubd/publishers/{}/response.json", handle); - let res = get_json(&server, &token, &uri).await?; - Ok(ApiResponse::Rfc8183RepositoryResponse(res)) - } - } - } -} - //------------ Error --------------------------------------------------------- #[derive(Debug)] diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 7d3df5ee..0d7917ba 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -4,4 +4,3 @@ pub mod report; mod client; pub use self::client::Error; pub use self::client::KrillClient; -pub use self::client::KrillPubdClient; diff --git a/src/cli/options.rs b/src/cli/options.rs index 696ccf75..3d823697 100644 --- a/src/cli/options.rs +++ b/src/cli/options.rs @@ -957,6 +957,159 @@ impl Options { app.subcommand(info) } + fn make_publishers_list_sc<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { + let mut sub = SubCommand::with_name("list").about("List all publishers"); + sub = Options::add_general_args(sub); + app.subcommand(sub) + } + + fn make_publishers_stale_sc<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { + let mut sub = SubCommand::with_name("stale").about("List all publishers which have not published in a while"); + sub = Options::add_general_args(sub); + sub = sub.arg( + Arg::with_name("seconds") + .value_name("seconds") + .long("seconds") + .help("The number of seconds since last publication") + .required(true), + ); + app.subcommand(sub) + } + + fn add_publisher_arg<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { + app.arg( + Arg::with_name("publisher") + .value_name("handle") + .short("p") + .long("publisher") + .help("The handle (name) of the publisher") + .required(true), + ) + } + + fn add_rsync_base_arg<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { + app.arg( + Arg::with_name("rsync") + .long("rsync") + .value_name("uri") + .help("Specify the base rsync URI for the repository, must end with '/'") + .required(true), + ) + } + + fn add_rrdp_base_uri_arg<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { + app.arg( + Arg::with_name("rrdp") + .long("rrdp") + .value_name("uri") + .help( + "Specify the base https URI for the RRDP (excluding notification.xml), \ + must \ + end with '/'", + ) + .required(true), + ) + } + + fn make_publishers_add_sc<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { + let mut sub = SubCommand::with_name("add").about("Add a publisher"); + sub = Options::add_general_args(sub); + + sub = sub + .arg( + Arg::with_name("request") + .value_name("file") + .long("request") + .short("r") + .help("The location of the RFC8183 Publisher Request XML file") + .required(true), + ) + .arg( + Arg::with_name("publisher") + .value_name("handle") + .short("p") + .long("publisher") + .help("Override the publisher handle in the XML") + .required(false), + ); + + app.subcommand(sub) + } + + fn make_publishers_remove_sc<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { + let mut sub = SubCommand::with_name("remove").about("Remove a publisher"); + sub = Options::add_general_args(sub); + sub = Self::add_publisher_arg(sub); + app.subcommand(sub) + } + + fn make_publishers_show_sc<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { + let mut sub = SubCommand::with_name("show").about("Show details for a publisher"); + sub = Options::add_general_args(sub); + sub = Self::add_publisher_arg(sub); + app.subcommand(sub) + } + + fn make_publishers_response_sc<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { + let mut sub = SubCommand::with_name("response").about("Show RFC8183 Repository Response XML"); + sub = Options::add_general_args(sub); + sub = Self::add_publisher_arg(sub); + app.subcommand(sub) + } + + fn make_publication_server_stats_sc<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { + let mut sub = SubCommand::with_name("stats").about("Show publication server stats"); + sub = Options::add_general_args(sub); + app.subcommand(sub) + } + + fn make_publication_server_init_sc<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { + let mut sub = SubCommand::with_name("init").about("Initialize publication server"); + sub = Options::add_general_args(sub); + + sub = Self::add_rsync_base_arg(sub); + sub = Self::add_rrdp_base_uri_arg(sub); + + app.subcommand(sub) + } + + fn make_publication_server_clear_sc<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { + let mut sub = SubCommand::with_name("clear").about("Clear the publication server so it can re-initialized"); + sub = Options::add_general_args(sub); + app.subcommand(sub) + } + + fn make_publication_server_sc<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { + let mut sub = SubCommand::with_name("server").about("Manage the Publication Server (init/stats)"); + sub = Self::make_publication_server_stats_sc(sub); + sub = Self::make_publication_server_init_sc(sub); + sub = Self::make_publication_server_clear_sc(sub); + app.subcommand(sub) + } + + fn make_publishers_sc<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { + let mut sub = SubCommand::with_name("publishers").about("Manage the publishers in your Publication Server"); + + sub = Self::make_publishers_list_sc(sub); + sub = Self::make_publishers_stale_sc(sub); + sub = Self::make_publishers_add_sc(sub); + sub = Self::make_publishers_remove_sc(sub); + sub = Self::make_publishers_show_sc(sub); + sub = Self::make_publishers_response_sc(sub); + + app.subcommand(sub) + } + + fn make_pubserver_sc<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { + let mut sub = SubCommand::with_name("pubserver") + .about("Manage your Publication Server (only needed if you run your own)"); + + sub = Self::make_publishers_sc(sub); + sub = Self::make_publication_server_sc(sub); + + app.subcommand(sub) + } + fn make_matches<'a>() -> ArgMatches<'a> { let mut app = App::new(KRILL_CLIENT_APP).version(KRILL_VERSION); @@ -972,6 +1125,7 @@ impl Options { app = Self::make_cas_routes_sc(app); app = Self::make_cas_repo_sc(app); app = Self::make_cas_issues_sc(app); + app = Self::make_pubserver_sc(app); #[cfg(feature = "rta")] { @@ -1712,6 +1866,141 @@ impl Options { Ok(Options::make(general_args, command)) } + fn parse_publisher_arg(matches: &ArgMatches) -> Result { + let publisher_str = matches.value_of("publisher").unwrap(); + PublisherHandle::from_str(publisher_str).map_err(|_| Error::InvalidHandle) + } + + fn parse_matches_publishers_list(matches: &ArgMatches) -> Result { + let general_args = GeneralArgs::from_matches(matches)?; + let command = Command::PubServer(PubServerCommand::PublisherList); + Ok(Options::make(general_args, command)) + } + + fn parse_matches_publishers_stale(matches: &ArgMatches) -> Result { + let general_args = GeneralArgs::from_matches(matches)?; + let seconds = i64::from_str(matches.value_of("seconds").unwrap()).map_err(|_| Error::InvalidSeconds)?; + let command = Command::PubServer(PubServerCommand::StalePublishers(seconds)); + Ok(Options::make(general_args, command)) + } + + fn parse_matches_publishers_add(matches: &ArgMatches) -> Result { + let general_args = GeneralArgs::from_matches(matches)?; + + let path = matches.value_of("request").unwrap(); + let path = PathBuf::from(path); + let bytes = file::read(&path)?; + let mut req = rfc8183::PublisherRequest::validate(bytes.as_ref())?; + + if let Some(publisher_str) = matches.value_of("publisher") { + let publisher = PublisherHandle::from_str(publisher_str).map_err(|_| Error::InvalidHandle)?; + let (tag, _, cert) = req.unpack(); + req = rfc8183::PublisherRequest::new(tag, publisher, cert); + } + + let command = Command::PubServer(PubServerCommand::AddPublisher(req)); + Ok(Options::make(general_args, command)) + } + + fn parse_matches_publishers_remove(matches: &ArgMatches) -> Result { + let general_args = GeneralArgs::from_matches(matches)?; + let publisher = Self::parse_publisher_arg(matches)?; + let command = Command::PubServer(PubServerCommand::RemovePublisher(publisher)); + Ok(Options::make(general_args, command)) + } + + fn parse_matches_publishers_show(matches: &ArgMatches) -> Result { + let general_args = GeneralArgs::from_matches(matches)?; + let publisher = Self::parse_publisher_arg(matches)?; + let command = Command::PubServer(PubServerCommand::ShowPublisher(publisher)); + Ok(Options::make(general_args, command)) + } + + fn parse_matches_publishers_repo_response(matches: &ArgMatches) -> Result { + let general_args = GeneralArgs::from_matches(matches)?; + let publisher = Self::parse_publisher_arg(matches)?; + let command = Command::PubServer(PubServerCommand::RepositoryResponse(publisher)); + Ok(Options::make(general_args, command)) + } + + fn parse_matches_publication_server_stats(matches: &ArgMatches) -> Result { + let general_args = GeneralArgs::from_matches(matches)?; + let command = Command::PubServer(PubServerCommand::RepositoryStats); + Ok(Options::make(general_args, command)) + } + + fn parse_matches_publication_server_init(matches: &ArgMatches) -> Result { + let general_args = GeneralArgs::from_matches(matches)?; + + let rsync_str = matches.value_of("rsync").unwrap(); + let rrdp_str = matches.value_of("rrdp").unwrap(); + + if !rsync_str.ends_with('/') { + return Err(Error::general("rsync base URI must end with '/'")); + } + + if !rrdp_str.ends_with('/') { + return Err(Error::general("RRDP base URI must end with '/'")); + } + + let rsync = uri::Rsync::from_str(rsync_str) + .map_err(|e| Error::GeneralArgumentError(format!("Invalid rsync URI: {}", e)))?; + + let rrdp = uri::Https::from_str(rrdp_str) + .map_err(|e| Error::GeneralArgumentError(format!("Invalid RRDP URI: {}", e)))?; + + let uris = PublicationServerUris::new(rrdp, rsync); + + let command = Command::PubServer(PubServerCommand::RepositoryInit(uris)); + Ok(Options::make(general_args, command)) + } + + fn parse_matches_publication_server_clear(matches: &ArgMatches) -> Result { + let general_args = GeneralArgs::from_matches(matches)?; + let command = Command::PubServer(PubServerCommand::RepositoryClear); + Ok(Options::make(general_args, command)) + } + + fn parse_matches_publication_server(matches: &ArgMatches) -> Result { + if let Some(m) = matches.subcommand_matches("stats") { + Self::parse_matches_publication_server_stats(m) + } else if let Some(m) = matches.subcommand_matches("init") { + Self::parse_matches_publication_server_init(m) + } else if let Some(m) = matches.subcommand_matches("clear") { + Self::parse_matches_publication_server_clear(m) + } else { + Err(Error::UnrecognizedSubCommand) + } + } + + fn parse_matches_publishers(matches: &ArgMatches) -> Result { + if let Some(m) = matches.subcommand_matches("list") { + Self::parse_matches_publishers_list(m) + } else if let Some(m) = matches.subcommand_matches("stale") { + Self::parse_matches_publishers_stale(m) + } else if let Some(m) = matches.subcommand_matches("add") { + Self::parse_matches_publishers_add(m) + } else if let Some(m) = matches.subcommand_matches("remove") { + Self::parse_matches_publishers_remove(m) + } else if let Some(m) = matches.subcommand_matches("show") { + Self::parse_matches_publishers_show(m) + } else if let Some(m) = matches.subcommand_matches("response") { + Self::parse_matches_publishers_repo_response(m) + } else { + Err(Error::UnrecognizedSubCommand) + } + } + + fn parse_matches_pubserver(matches: &ArgMatches) -> Result { + if let Some(m) = matches.subcommand_matches("publishers") { + Self::parse_matches_publishers(m) + } else if let Some(m) = matches.subcommand_matches("server") { + Self::parse_matches_publication_server(m) + } else { + Err(Error::UnrecognizedSubCommand) + } + } + fn parse_matches(matches: ArgMatches) -> Result { if let Some(m) = matches.subcommand_matches("config") { Self::parse_matches_config(m) @@ -1745,6 +2034,8 @@ impl Options { Self::parse_matches_health(m) } else if let Some(m) = matches.subcommand_matches("info") { Self::parse_matches_info(m) + } else if let Some(m) = matches.subcommand_matches("pubserver") { + Self::parse_matches_pubserver(m) } else { Err(Error::UnrecognizedSubCommand) } @@ -1756,318 +2047,6 @@ impl Options { } } -/// This type holds all the necessary data to connect to a Krill daemon, and -/// authenticate, and perform a specific action. -pub struct KrillPubcOptions { - server: uri::Https, - token: Token, - pub format: ReportFormat, - api: bool, - command: PublishersCommand, -} - -impl KrillPubcOptions { - fn make(general: GeneralArgs, command: PublishersCommand) -> Self { - KrillPubcOptions { - server: general.server, - token: general.token, - format: general.format, - api: general.api, - command, - } - } - - pub fn new(server: uri::Https, token: Token, format: ReportFormat, api: bool, command: PublishersCommand) -> Self { - KrillPubcOptions { - server, - token, - format, - api, - command, - } - } - - pub fn unpack(self) -> (uri::Https, Token, ReportFormat, bool, PublishersCommand) { - (self.server, self.token, self.format, self.api, self.command) - } - - pub fn from_args() -> Result { - let matches = Self::make_matches(); - Self::parse_matches(matches) - } - - fn make_publishers_list_sc<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { - let mut sub = SubCommand::with_name("list").about("List all publishers"); - sub = Options::add_general_args(sub); - app.subcommand(sub) - } - - fn make_publishers_stale_sc<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { - let mut sub = SubCommand::with_name("stale").about("List all publishers which have not published in a while"); - sub = Options::add_general_args(sub); - sub = sub.arg( - Arg::with_name("seconds") - .value_name("seconds") - .long("seconds") - .help("The number of seconds since last publication") - .required(true), - ); - app.subcommand(sub) - } - - fn add_publisher_arg<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { - app.arg( - Arg::with_name("publisher") - .value_name("handle") - .short("p") - .long("publisher") - .help("The handle (name) of the publisher") - .required(true), - ) - } - - fn add_rsync_base_arg<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { - app.arg( - Arg::with_name("rsync") - .long("rsync") - .value_name("uri") - .help("Specify the base rsync URI for the repository, must end with '/'") - .required(true), - ) - } - - fn add_rrdp_base_uri_arg<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { - app.arg( - Arg::with_name("rrdp") - .long("rrdp") - .value_name("uri") - .help( - "Specify the base https URI for the RRDP (excluding notification.xml), \ - must \ - end with '/'", - ) - .required(true), - ) - } - - fn make_publishers_add_sc<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { - let mut sub = SubCommand::with_name("add").about("Add a publisher"); - sub = Options::add_general_args(sub); - - sub = sub - .arg( - Arg::with_name("request") - .value_name("file") - .long("request") - .short("r") - .help("The location of the RFC8183 Publisher Request XML file") - .required(true), - ) - .arg( - Arg::with_name("publisher") - .value_name("handle") - .short("p") - .long("publisher") - .help("Override the publisher handle in the XML") - .required(false), - ); - - app.subcommand(sub) - } - - fn make_publishers_remove_sc<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { - let mut sub = SubCommand::with_name("remove").about("Remove a publisher"); - sub = Options::add_general_args(sub); - sub = Self::add_publisher_arg(sub); - app.subcommand(sub) - } - - fn make_publishers_show_sc<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { - let mut sub = SubCommand::with_name("show").about("Show details for a publisher"); - sub = Options::add_general_args(sub); - sub = Self::add_publisher_arg(sub); - app.subcommand(sub) - } - - fn make_publishers_response_sc<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { - let mut sub = SubCommand::with_name("response").about("Show RFC8183 Repository Response XML"); - sub = Options::add_general_args(sub); - sub = Self::add_publisher_arg(sub); - app.subcommand(sub) - } - - fn make_publication_server_stats_sc<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { - let mut sub = SubCommand::with_name("stats").about("Show publication server stats"); - sub = Options::add_general_args(sub); - app.subcommand(sub) - } - - fn make_publication_server_init_sc<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { - let mut sub = SubCommand::with_name("init").about("Initialize publication server"); - sub = Options::add_general_args(sub); - - sub = Self::add_rsync_base_arg(sub); - sub = Self::add_rrdp_base_uri_arg(sub); - - app.subcommand(sub) - } - - fn make_publication_server_clear_sc<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { - let mut sub = SubCommand::with_name("clear").about("Clear the publication server so it can re-initialized"); - sub = Options::add_general_args(sub); - app.subcommand(sub) - } - - fn make_publication_server_sc<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { - let mut sub = SubCommand::with_name("server").about("Manage the Publication Server (init/stats)"); - sub = Self::make_publication_server_stats_sc(sub); - sub = Self::make_publication_server_init_sc(sub); - sub = Self::make_publication_server_clear_sc(sub); - app.subcommand(sub) - } - - fn make_matches<'a>() -> ArgMatches<'a> { - let mut app = App::new(KRILL_PUBC_CLIENT_APP).version(KRILL_VERSION); - - app = Self::make_publishers_list_sc(app); - app = Self::make_publishers_stale_sc(app); - app = Self::make_publishers_add_sc(app); - app = Self::make_publishers_remove_sc(app); - app = Self::make_publishers_show_sc(app); - app = Self::make_publishers_response_sc(app); - app = Self::make_publication_server_sc(app); - - app.get_matches() - } - - fn parse_publisher_arg(matches: &ArgMatches) -> Result { - let publisher_str = matches.value_of("publisher").unwrap(); - PublisherHandle::from_str(publisher_str).map_err(|_| Error::InvalidHandle) - } - - fn parse_matches_publishers_list(matches: &ArgMatches) -> Result { - let general_args = GeneralArgs::from_matches(matches)?; - let command = PublishersCommand::PublisherList; - Ok(KrillPubcOptions::make(general_args, command)) - } - - fn parse_matches_publishers_stale(matches: &ArgMatches) -> Result { - let general_args = GeneralArgs::from_matches(matches)?; - let seconds = i64::from_str(matches.value_of("seconds").unwrap()).map_err(|_| Error::InvalidSeconds)?; - let command = PublishersCommand::StalePublishers(seconds); - Ok(KrillPubcOptions::make(general_args, command)) - } - - fn parse_matches_publishers_add(matches: &ArgMatches) -> Result { - let general_args = GeneralArgs::from_matches(matches)?; - - let path = matches.value_of("request").unwrap(); - let path = PathBuf::from(path); - let bytes = file::read(&path)?; - let mut req = rfc8183::PublisherRequest::validate(bytes.as_ref())?; - - if let Some(publisher_str) = matches.value_of("publisher") { - let publisher = PublisherHandle::from_str(publisher_str).map_err(|_| Error::InvalidHandle)?; - let (tag, _, cert) = req.unpack(); - req = rfc8183::PublisherRequest::new(tag, publisher, cert); - } - - let command = PublishersCommand::AddPublisher(req); - Ok(KrillPubcOptions::make(general_args, command)) - } - - fn parse_matches_publishers_remove(matches: &ArgMatches) -> Result { - let general_args = GeneralArgs::from_matches(matches)?; - let publisher = Self::parse_publisher_arg(matches)?; - let command = PublishersCommand::RemovePublisher(publisher); - Ok(KrillPubcOptions::make(general_args, command)) - } - - fn parse_matches_publishers_show(matches: &ArgMatches) -> Result { - let general_args = GeneralArgs::from_matches(matches)?; - let publisher = Self::parse_publisher_arg(matches)?; - let command = PublishersCommand::ShowPublisher(publisher); - Ok(KrillPubcOptions::make(general_args, command)) - } - - fn parse_matches_publishers_repo_response(matches: &ArgMatches) -> Result { - let general_args = GeneralArgs::from_matches(matches)?; - let publisher = Self::parse_publisher_arg(matches)?; - let command = PublishersCommand::RepositoryResponse(publisher); - Ok(KrillPubcOptions::make(general_args, command)) - } - - fn parse_matches_publication_server_stats(matches: &ArgMatches) -> Result { - let general_args = GeneralArgs::from_matches(matches)?; - let command = PublishersCommand::RepositoryStats; - Ok(KrillPubcOptions::make(general_args, command)) - } - - fn parse_matches_publication_server_init(matches: &ArgMatches) -> Result { - let general_args = GeneralArgs::from_matches(matches)?; - - let rsync_str = matches.value_of("rsync").unwrap(); - let rrdp_str = matches.value_of("rrdp").unwrap(); - - if !rsync_str.ends_with('/') { - return Err(Error::general("rsync base URI must end with '/'")); - } - - if !rrdp_str.ends_with('/') { - return Err(Error::general("RRDP base URI must end with '/'")); - } - - let rsync = uri::Rsync::from_str(rsync_str) - .map_err(|e| Error::GeneralArgumentError(format!("Invalid rsync URI: {}", e)))?; - - let rrdp = uri::Https::from_str(rrdp_str) - .map_err(|e| Error::GeneralArgumentError(format!("Invalid RRDP URI: {}", e)))?; - - let uris = PublicationServerUris::new(rrdp, rsync); - - let command = PublishersCommand::RepositoryInit(uris); - Ok(KrillPubcOptions::make(general_args, command)) - } - - fn parse_matches_publication_server_clear(matches: &ArgMatches) -> Result { - let general_args = GeneralArgs::from_matches(matches)?; - let command = PublishersCommand::RepositoryClear; - Ok(KrillPubcOptions::make(general_args, command)) - } - - fn parse_matches_publication_server(matches: &ArgMatches) -> Result { - if let Some(m) = matches.subcommand_matches("stats") { - Self::parse_matches_publication_server_stats(m) - } else if let Some(m) = matches.subcommand_matches("init") { - Self::parse_matches_publication_server_init(m) - } else if let Some(m) = matches.subcommand_matches("clear") { - Self::parse_matches_publication_server_clear(m) - } else { - Err(Error::UnrecognizedSubCommand) - } - } - - fn parse_matches(matches: ArgMatches) -> Result { - if let Some(m) = matches.subcommand_matches("list") { - Self::parse_matches_publishers_list(m) - } else if let Some(m) = matches.subcommand_matches("stale") { - Self::parse_matches_publishers_stale(m) - } else if let Some(m) = matches.subcommand_matches("add") { - Self::parse_matches_publishers_add(m) - } else if let Some(m) = matches.subcommand_matches("remove") { - Self::parse_matches_publishers_remove(m) - } else if let Some(m) = matches.subcommand_matches("show") { - Self::parse_matches_publishers_show(m) - } else if let Some(m) = matches.subcommand_matches("response") { - Self::parse_matches_publishers_repo_response(m) - } else if let Some(m) = matches.subcommand_matches("server") { - Self::parse_matches_publication_server(m) - } else { - Err(Error::UnrecognizedSubCommand) - } - } -} - #[derive(Clone, Debug, Eq, PartialEq)] #[allow(clippy::large_enum_variant)] pub enum Command { @@ -2076,6 +2055,7 @@ pub enum Command { Info, Bulk(BulkCaCommand), CertAuth(CaCommand), + PubServer(PubServerCommand), Init(KrillInitDetails), #[cfg(feature = "multi-user")] User(KrillUserDetails), @@ -2263,7 +2243,7 @@ impl Default for KrillUserDetails { #[derive(Clone, Debug, Eq, PartialEq)] #[allow(clippy::large_enum_variant)] -pub enum PublishersCommand { +pub enum PubServerCommand { AddPublisher(rfc8183::PublisherRequest), ShowPublisher(PublisherHandle), RemovePublisher(PublisherHandle), diff --git a/src/test.rs b/src/test.rs index a17fb606..f2009718 100644 --- a/src/test.rs +++ b/src/test.rs @@ -17,11 +17,11 @@ use rpki::crypto::KeyIdentifier; use rpki::uri; use crate::cli::report::{ApiResponse, ReportFormat}; -use crate::cli::{Error, KrillClient, KrillPubdClient}; +use crate::cli::{Error, KrillClient}; use crate::commons::api::{ AddChildRequest, CertAuthInfo, CertAuthInit, CertifiedKeyInfo, ChildHandle, Handle, ParentCaContact, ParentCaReq, ParentHandle, ParentStatuses, PublicationServerUris, PublisherDetails, PublisherHandle, PublisherList, - ResourceClassName, ResourceSet, RoaDefinition, RoaDefinitionUpdates, RtaList, RtaName, RtaPrepResponse, Token, + ResourceClassName, ResourceSet, RoaDefinition, RoaDefinitionUpdates, RtaList, RtaName, RtaPrepResponse, TypedPrefix, UpdateChildRequest, }; use crate::commons::bgp::{Announcement, BgpAnalysisReport, BgpAnalysisSuggestion}; @@ -32,7 +32,7 @@ use crate::commons::util::httpclient; use crate::daemon::ca::{ta_handle, ResourceTaggedAttestation, RtaContentRequest, RtaPrepareRequest}; use crate::daemon::http::server; use crate::{ - cli::options::{BulkCaCommand, CaCommand, Command, KrillPubcOptions, Options, PublishersCommand}, + cli::options::{BulkCaCommand, CaCommand, Command, Options, PubServerCommand}, commons::api::RepositoryContact, }; @@ -149,7 +149,7 @@ pub async fn start_krill_pubd() -> PathBuf { let rrdp_base_uri = uri::Https::from_str("https://localhost:3001/test-rrdp/").unwrap(); PublicationServerUris::new(rrdp_base_uri, rsync_base) }; - let command = PublishersCommand::RepositoryInit(uris); + let command = PubServerCommand::RepositoryInit(uris); krill_dedicated_pubd_admin(command).await; dir @@ -163,29 +163,18 @@ pub async fn krill_admin(command: Command) -> ApiResponse { } } -pub async fn krill_embedded_pubd_admin(command: PublishersCommand) -> ApiResponse { - let options = KrillPubcOptions::new( - https(KRILL_SERVER_URI), - Token::from("secret"), - ReportFormat::Json, - false, - command, - ); - match KrillPubdClient::process(options).await { - Ok(res) => res, // ok - Err(e) => panic!("{}", e), - } +pub async fn krill_embedded_pubd_admin(command: PubServerCommand) -> ApiResponse { + krill_admin(Command::PubServer(command)).await } -pub async fn krill_dedicated_pubd_admin(command: PublishersCommand) -> ApiResponse { - let options = KrillPubcOptions::new( +pub async fn krill_dedicated_pubd_admin(command: PubServerCommand) -> ApiResponse { + let options = Options::new( https(KRILL_PUBD_SERVER_URI), - Token::from("secret"), + "secret", ReportFormat::Json, - false, - command, + Command::PubServer(command), ); - match KrillPubdClient::process(options).await { + match KrillClient::process(options).await { Ok(res) => res, // ok Err(e) => panic!("{}", e), } @@ -489,21 +478,21 @@ pub async fn ca_current_resources(handle: &Handle) -> ResourceSet { } pub async fn list_publishers() -> PublisherList { - match krill_embedded_pubd_admin(PublishersCommand::PublisherList).await { + match krill_embedded_pubd_admin(PubServerCommand::PublisherList).await { ApiResponse::PublisherList(pub_list) => pub_list, _ => panic!("Expected publisher list"), } } pub async fn publisher_details(publisher: &PublisherHandle) -> PublisherDetails { - match krill_embedded_pubd_admin(PublishersCommand::ShowPublisher(publisher.clone())).await { + match krill_embedded_pubd_admin(PubServerCommand::ShowPublisher(publisher.clone())).await { ApiResponse::PublisherDetails(pub_details) => pub_details, _ => panic!("Expected publisher details"), } } pub async fn dedicated_repo_publisher_details(publisher: &PublisherHandle) -> PublisherDetails { - match krill_dedicated_pubd_admin(PublishersCommand::ShowPublisher(publisher.clone())).await { + match krill_dedicated_pubd_admin(PubServerCommand::ShowPublisher(publisher.clone())).await { ApiResponse::PublisherDetails(pub_details) => pub_details, _ => panic!("Expected publisher details"), } diff --git a/tests/functional.rs b/tests/functional.rs index 8fdcbb08..aac683e6 100644 --- a/tests/functional.rs +++ b/tests/functional.rs @@ -19,7 +19,7 @@ use krill::commons::remote::rfc8183; use krill::daemon::ca::ta_handle; use krill::test::*; use krill::{ - cli::options::{BulkCaCommand, CaCommand, Command, PublishersCommand}, + cli::options::{BulkCaCommand, CaCommand, Command, PubServerCommand}, commons::api::RepositoryContact, }; @@ -37,7 +37,7 @@ async fn repo_update(ca: &Handle, contact: RepositoryContact) { } async fn embedded_repository_response(publisher: &PublisherHandle) -> rfc8183::RepositoryResponse { - let command = PublishersCommand::RepositoryResponse(publisher.clone()); + let command = PubServerCommand::RepositoryResponse(publisher.clone()); match krill_embedded_pubd_admin(command).await { ApiResponse::Rfc8183RepositoryResponse(response) => response, _ => panic!("Expected repository response."), @@ -45,7 +45,7 @@ async fn embedded_repository_response(publisher: &PublisherHandle) -> rfc8183::R } async fn embedded_repo_add_publisher(req: rfc8183::PublisherRequest) { - let command = PublishersCommand::AddPublisher(req); + let command = PubServerCommand::AddPublisher(req); krill_embedded_pubd_admin(command).await; } diff --git a/tests/migrate_repository.rs b/tests/migrate_repository.rs index 420c63b5..2e0008c8 100644 --- a/tests/migrate_repository.rs +++ b/tests/migrate_repository.rs @@ -16,7 +16,7 @@ use krill::commons::remote::rfc8183; use krill::daemon::ca::ta_handle; use krill::test::*; use krill::{ - cli::options::{CaCommand, Command, PublishersCommand}, + cli::options::{CaCommand, Command, PubServerCommand}, commons::api::RepositoryContact, }; use krill::{cli::report::ApiResponse, commons::api::RoaDefinition}; @@ -35,7 +35,7 @@ async fn repo_update(ca: &Handle, contact: RepositoryContact) { } async fn embedded_repository_response(publisher: &PublisherHandle) -> rfc8183::RepositoryResponse { - let command = PublishersCommand::RepositoryResponse(publisher.clone()); + let command = PubServerCommand::RepositoryResponse(publisher.clone()); match krill_embedded_pubd_admin(command).await { ApiResponse::Rfc8183RepositoryResponse(response) => response, _ => panic!("Expected repository response."), @@ -43,7 +43,7 @@ async fn embedded_repository_response(publisher: &PublisherHandle) -> rfc8183::R } async fn dedicated_repository_response(publisher: &PublisherHandle) -> rfc8183::RepositoryResponse { - let command = PublishersCommand::RepositoryResponse(publisher.clone()); + let command = PubServerCommand::RepositoryResponse(publisher.clone()); match krill_dedicated_pubd_admin(command).await { ApiResponse::Rfc8183RepositoryResponse(response) => response, _ => panic!("Expected repository response."), @@ -51,12 +51,12 @@ async fn dedicated_repository_response(publisher: &PublisherHandle) -> rfc8183:: } async fn embedded_repo_add_publisher(req: rfc8183::PublisherRequest) { - let command = PublishersCommand::AddPublisher(req); + let command = PubServerCommand::AddPublisher(req); krill_embedded_pubd_admin(command).await; } async fn dedicated_repo_add_publisher(req: rfc8183::PublisherRequest) { - let command = PublishersCommand::AddPublisher(req); + let command = PubServerCommand::AddPublisher(req); krill_dedicated_pubd_admin(command).await; }