Show repo state and published objects through API and CLI. (#104)

This commit is contained in:
Tim Bruijnzeels
2019-11-04 14:28:56 +01:00
parent c6f38065a7
commit 714f0fcb6e
10 changed files with 278 additions and 57 deletions
+10 -2
View File
@@ -14,6 +14,7 @@ use crate::commons::remote::rfc8183;
use crate::commons::remote::rfc8183::RepositoryResponse;
use crate::commons::util::httpclient;
use crate::constants::KRILL_CLI_API_ENV;
use commons::api::CaRepoDetails;
/// Command line tool for Krill admin tasks
pub struct KrillClient {
@@ -89,8 +90,8 @@ impl KrillClient {
Ok(ApiResponse::Rfc8183ChildRequest(req))
}
CaCommand::PublisherRequest(handle) => {
let uri = format!("api/v1/cas/{}/publisher_request", handle);
CaCommand::RepoPublisherRequest(handle) => {
let uri = format!("api/v1/cas/{}/repo/publisher_request", handle);
let req: PublisherRequest = self.get_json(&uri)?;
let (handle, id_cert) = req.unpack();
let req = rfc8183::PublisherRequest::new(None, handle, id_cert);
@@ -98,6 +99,13 @@ impl KrillClient {
Ok(ApiResponse::Rfc8183PublisherRequest(req))
}
CaCommand::RepoDetails(handle) => {
let uri = format!("api/v1/cas/{}/repo/", handle);
let details: CaRepoDetails = self.get_json(&uri)?;
Ok(ApiResponse::RepoDetails(details))
}
CaCommand::AddParent(handle, parent) => {
let uri = format!("api/v1/cas/{}/parents", handle);
self.post_json(&uri, parent)?;
+24 -2
View File
@@ -475,10 +475,20 @@ impl Options {
app.subcommand(sub)
}
fn make_case_repo_show_sc<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
let mut sub = SubCommand::with_name("show").about("Show current repo config and state.");
sub = Self::add_general_args(sub);
sub = Self::add_my_ca_arg(sub);
app.subcommand(sub)
}
fn make_cas_repo_sc<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
let mut sub = SubCommand::with_name("repo").about("Manage the repository for your CA.");
sub = Self::make_case_repo_request_sc(sub);
sub = Self::make_case_repo_show_sc(sub);
app.subcommand(sub)
}
@@ -871,7 +881,16 @@ impl Options {
let general_args = GeneralArgs::from_matches(matches)?;
let my_ca = Self::parse_my_ca(matches)?;
let command = Command::CertAuth(CaCommand::PublisherRequest(my_ca));
let command = Command::CertAuth(CaCommand::RepoPublisherRequest(my_ca));
Ok(Options::make(general_args, command))
}
fn parse_matches_cas_repo_details(matches: &ArgMatches) -> Result<Options, Error> {
let general_args = GeneralArgs::from_matches(matches)?;
let my_ca = Self::parse_my_ca(matches)?;
let command = Command::CertAuth(CaCommand::RepoDetails(my_ca));
Ok(Options::make(general_args, command))
}
@@ -879,6 +898,8 @@ impl Options {
fn parse_matches_cas_repo(matches: &ArgMatches) -> Result<Options, Error> {
if let Some(m) = matches.subcommand_matches("request") {
Self::parse_matches_cas_repo_request(m)
} else if let Some(m) = matches.subcommand_matches("show") {
Self::parse_matches_cas_repo_details(m)
} else {
Err(Error::UnrecognisedSubCommand)
}
@@ -1013,7 +1034,8 @@ pub enum CaCommand {
ChildRequest(Handle),
// Get the RFC8183 publisher request
PublisherRequest(Handle),
RepoPublisherRequest(Handle),
RepoDetails(Handle),
// Add a parent to this CA
AddParent(Handle, ParentCaReq),
+53 -2
View File
@@ -1,8 +1,8 @@
use std::str::{from_utf8_unchecked, FromStr};
use crate::commons::api::{
CertAuthHistory, CertAuthInfo, CertAuthList, CurrentObjects, ParentCaContact, PublisherDetails,
PublisherList, RouteAuthorization,
CaRepoDetails, CertAuthHistory, CertAuthInfo, CertAuthList, CurrentObjects, CurrentRepoState,
ParentCaContact, PubServerContact, PublisherDetails, PublisherList, RouteAuthorization,
};
use crate::commons::remote::api::ClientInfo;
use crate::commons::remote::rfc8183;
@@ -30,6 +30,8 @@ pub enum ApiResponse {
Rfc8183ChildRequest(rfc8183::ChildRequest),
Rfc8183PublisherRequest(rfc8183::PublisherRequest),
RepoDetails(CaRepoDetails),
Empty, // Typically a successful post just gets an empty 200 response
GenericBody(String), // For when the server echos Json to a successful post
}
@@ -58,6 +60,7 @@ impl ApiResponse {
ApiResponse::Rfc8183ChildRequest(req) => Ok(Some(req.report(fmt)?)),
ApiResponse::Rfc8183PublisherRequest(req) => Ok(Some(req.report(fmt)?)),
ApiResponse::Rfc8183RepositoryResponse(res) => Ok(Some(res.report(fmt)?)),
ApiResponse::RepoDetails(details) => Ok(Some(details.report(fmt)?)),
ApiResponse::GenericBody(body) => Ok(Some(body.clone())),
ApiResponse::Empty => Ok(None),
}
@@ -353,3 +356,51 @@ impl Report for Vec<RouteAuthorization> {
}
}
}
impl Report for CaRepoDetails {
fn report(&self, format: ReportFormat) -> Result<String, ReportError> {
match format {
ReportFormat::Json => Ok(serde_json::to_string_pretty(self).unwrap()),
ReportFormat::Default | ReportFormat::Text => {
let mut res = String::new();
res.push_str("Repository Details:\n");
match self.contact() {
PubServerContact::Embedded(repo_info) => {
res.push_str(" type: embedded\n");
res.push_str(&format!(" base_uri: {}\n", repo_info.base_uri()));
res.push_str(&format!(" rpki_notify: {}\n", repo_info.rpki_notify()));
}
PubServerContact::Rfc8181(response) => {
res.push_str(" type: remote\n");
res.push_str(&format!(" service uri: {}\n", response.service_uri()));
let repo_info = response.repo_info();
res.push_str(&format!(" base_uri: {}\n", repo_info.base_uri()));
res.push_str(&format!(" rpki_notify: {}\n", repo_info.rpki_notify()));
}
}
res.push_str("\n");
res.push_str("Currently published:\n");
match self.state() {
CurrentRepoState::Error(e) => {
res.push_str(&format!(" Error contacting repo! => {}", e));
}
CurrentRepoState::List(list) => {
let elements = list.elements();
if elements.is_empty() {
res.push_str(" <nothing>\n");
} else {
for el in elements.iter() {
res.push_str(&format!(" {} {}\n", el.hash(), el.uri()));
}
}
}
}
Ok(res)
}
_ => Err(ReportError::UnsupportedFormat),
}
}
}