mirror of
https://github.com/NLnetLabs/krill.git
synced 2026-09-18 07:27:42 +02:00
Add IdCert to Publishers so we can verify RFC8183 messages there. (#107)
This commit is contained in:
@@ -8,17 +8,6 @@
|
||||
#
|
||||
# use_ta = false
|
||||
|
||||
# Specify whether https is to be used instead of plain http. Allowed values are
|
||||
# "yes" and "test". Defaults to "test".
|
||||
#
|
||||
# "yes" : The server will look for a 'cert.pem' and 'key.pem' file, under the
|
||||
# 'ssl' sub-folder of the 'data_dir' specified below. This option is
|
||||
# untested. We recommend that you use 'tesst" and a proxy server for now!
|
||||
#
|
||||
# "test" : The server will generate a key pair and a long-lived self-signed
|
||||
# certificate if no 'cert.pem' or 'key.pem' file can be found.
|
||||
#use_ssl = "test"
|
||||
|
||||
# Specify the directory where the publication server will store its data.
|
||||
# Note that clustering through a shared data directory is not supported.
|
||||
# But, we plan to look into a proper clustering solution later.
|
||||
|
||||
+2
-2
@@ -183,7 +183,7 @@ impl KrillClient {
|
||||
Ok(ApiResponse::PublisherList(list))
|
||||
}
|
||||
PublishersCommand::Add(add) => {
|
||||
let pbl = PublisherRequest::new(add.handle, add.base_uri);
|
||||
let pbl = PublisherRequest::new(add.handle, add.id_cert, add.base_uri);
|
||||
self.add_publisher(pbl)
|
||||
}
|
||||
PublishersCommand::Deactivate(handle) => {
|
||||
@@ -191,7 +191,7 @@ impl KrillClient {
|
||||
self.delete(&uri)?;
|
||||
Ok(ApiResponse::Empty)
|
||||
}
|
||||
PublishersCommand::Details(handle) => {
|
||||
PublishersCommand::Show(handle) => {
|
||||
let uri = format!("api/v1/publishers/{}", handle);
|
||||
let details: PublisherDetails = self.get_json(&uri)?;
|
||||
Ok(ApiResponse::PublisherDetails(details))
|
||||
|
||||
+46
-1
@@ -484,6 +484,47 @@ impl Options {
|
||||
app.subcommand(sub)
|
||||
}
|
||||
|
||||
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 = Self::add_general_args(sub);
|
||||
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 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 = Self::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 = Self::add_general_args(sub);
|
||||
sub = Self::add_publisher_arg(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 publishers in Krill.");
|
||||
|
||||
sub = Self::make_publishers_list_sc(sub);
|
||||
sub = Self::make_publishers_add_sc(sub);
|
||||
sub = Self::make_publishers_show_sc(sub);
|
||||
|
||||
app.subcommand(sub)
|
||||
}
|
||||
|
||||
fn make_health_sc<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
|
||||
app.subcommand(
|
||||
SubCommand::with_name("health").about("Perform an authenticated health check"),
|
||||
@@ -502,6 +543,8 @@ impl Options {
|
||||
app = Self::make_cas_keyroll_sc(app);
|
||||
app = Self::make_cas_routes_sc(app);
|
||||
|
||||
app = Self::make_publishers_sc(app);
|
||||
|
||||
app = Self::make_health_sc(app);
|
||||
|
||||
app.get_matches()
|
||||
@@ -900,9 +943,10 @@ pub enum CaCommand {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum PublishersCommand {
|
||||
Add(AddPublisher),
|
||||
Details(Handle),
|
||||
Show(Handle),
|
||||
Deactivate(Handle),
|
||||
List,
|
||||
}
|
||||
@@ -910,6 +954,7 @@ pub enum PublishersCommand {
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct AddPublisher {
|
||||
pub handle: Handle,
|
||||
pub id_cert: Option<IdCert>,
|
||||
pub base_uri: uri::Rsync,
|
||||
}
|
||||
|
||||
|
||||
+5
-3
@@ -259,9 +259,11 @@ impl Report for PublisherDetails {
|
||||
ReportFormat::Text => {
|
||||
let mut res = String::new();
|
||||
|
||||
res.push_str("handle: ");
|
||||
res.push_str(self.handle());
|
||||
res.push_str("\n");
|
||||
res.push_str(&format!("handle: {}\n", self.handle()));
|
||||
|
||||
if let Some(id_cert) = self.id_cert() {
|
||||
res.push_str(&format!("id: {}", id_cert.ski_hex()))
|
||||
}
|
||||
|
||||
res.push_str("base uri: ");
|
||||
res.push_str(self.base_uri().to_string().as_str());
|
||||
|
||||
+22
-23
@@ -159,12 +159,17 @@ impl fmt::Display for Token {
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
pub struct PublisherRequest {
|
||||
handle: Handle,
|
||||
id_cert: Option<IdCert>,
|
||||
base_uri: uri::Rsync,
|
||||
}
|
||||
|
||||
impl PublisherRequest {
|
||||
pub fn new(handle: Handle, base_uri: uri::Rsync) -> Self {
|
||||
PublisherRequest { handle, base_uri }
|
||||
pub fn new(handle: Handle, id_cert: Option<IdCert>, base_uri: uri::Rsync) -> Self {
|
||||
PublisherRequest {
|
||||
handle,
|
||||
id_cert,
|
||||
base_uri,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,8 +183,8 @@ impl PublisherRequest {
|
||||
}
|
||||
|
||||
/// Return all the values (handle, base_uri).
|
||||
pub fn unwrap(self) -> (Handle, uri::Rsync) {
|
||||
(self.handle, self.base_uri)
|
||||
pub fn unwrap(self) -> (Handle, Option<IdCert>, uri::Rsync) {
|
||||
(self.handle, self.id_cert, self.base_uri)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,57 +245,49 @@ impl PublisherList {
|
||||
|
||||
/// This type defines the publisher details for:
|
||||
/// /api/v1/publishers/{handle}
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
pub struct PublisherDetails {
|
||||
handle: String,
|
||||
handle: Handle,
|
||||
deactivated: bool,
|
||||
id_cert: Option<IdCert>,
|
||||
base_uri: uri::Rsync,
|
||||
current_files: Vec<PublishElement>,
|
||||
}
|
||||
|
||||
impl PublisherDetails {
|
||||
pub fn new(
|
||||
handle: &str,
|
||||
handle: &Handle,
|
||||
deactivated: bool,
|
||||
id_cert: Option<&IdCert>,
|
||||
base_uri: &uri::Rsync,
|
||||
current_files: Vec<PublishElement>,
|
||||
) -> Self {
|
||||
PublisherDetails {
|
||||
handle: handle.to_string(),
|
||||
handle: handle.clone(),
|
||||
deactivated,
|
||||
id_cert: id_cert.cloned(),
|
||||
base_uri: base_uri.clone(),
|
||||
current_files,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle(&self) -> &str {
|
||||
pub fn handle(&self) -> &Handle {
|
||||
&self.handle
|
||||
}
|
||||
|
||||
pub fn deactivated(&self) -> bool {
|
||||
self.deactivated
|
||||
}
|
||||
|
||||
pub fn id_cert(&self) -> Option<&IdCert> {
|
||||
self.id_cert.as_ref()
|
||||
}
|
||||
pub fn base_uri(&self) -> &uri::Rsync {
|
||||
&self.base_uri
|
||||
}
|
||||
|
||||
pub fn current_files(&self) -> &Vec<PublishElement> {
|
||||
&self.current_files
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for PublisherDetails {
|
||||
fn eq(&self, other: &PublisherDetails) -> bool {
|
||||
match (serde_json::to_string(self), serde_json::to_string(other)) {
|
||||
(Ok(ser_self), Ok(ser_other)) => ser_self == ser_other,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for PublisherDetails {}
|
||||
|
||||
//------------ PublisherClientRequest ----------------------------------------
|
||||
|
||||
/// This type defines request for a new Publisher client, i.e. the proxy that
|
||||
@@ -445,8 +442,10 @@ impl CertAuthInit {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum CertAuthPubMode {
|
||||
Embedded,
|
||||
Rfc8181(IdCert),
|
||||
}
|
||||
|
||||
//------------ AddChildRequest -----------------------------------------------
|
||||
|
||||
@@ -32,7 +32,6 @@ pub struct ProxyServer {
|
||||
signer: OpenSslSigner,
|
||||
clients_store: Arc<DiskAggregateStore<ClientManager>>,
|
||||
responder_store: Arc<DiskAggregateStore<Responder>>,
|
||||
krill_uri: uri::Https,
|
||||
}
|
||||
|
||||
/// # Server Life Cycle
|
||||
@@ -41,7 +40,7 @@ impl ProxyServer {
|
||||
/// Initialises the Proxy Server. This will re-use the existing clients and
|
||||
/// responder (i.e. server certificate and all), if they exist for this work_dir.
|
||||
/// If they do not exist, they will be initialised as well.
|
||||
pub fn init(work_dir: &PathBuf, krill_uri: &uri::Https) -> Result<Self, Error> {
|
||||
pub fn init(work_dir: &PathBuf) -> Result<Self, Error> {
|
||||
let mut signer = OpenSslSigner::build(work_dir)?;
|
||||
let clients_store = Arc::new(DiskAggregateStore::<ClientManager>::new(work_dir, "proxy")?);
|
||||
let responder_store = Arc::new(DiskAggregateStore::<Responder>::new(work_dir, "proxy")?);
|
||||
@@ -62,7 +61,6 @@ impl ProxyServer {
|
||||
signer,
|
||||
clients_store,
|
||||
responder_store,
|
||||
krill_uri: krill_uri.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -475,8 +473,7 @@ mod tests {
|
||||
#[test]
|
||||
fn should_init() {
|
||||
test::test_under_tmp(|d| {
|
||||
let krill_uri = test::https("https://localhost:3000/");
|
||||
let server = ProxyServer::init(&d, &krill_uri).unwrap();
|
||||
let server = ProxyServer::init(&d).unwrap();
|
||||
|
||||
let add_alice = clients::tests::add_client(&d, "alice");
|
||||
|
||||
|
||||
@@ -42,13 +42,13 @@ impl<S: Signer> CaServer<S> {
|
||||
pub fn build(
|
||||
work_dir: &PathBuf,
|
||||
events_queue: Arc<EventQueueListener>,
|
||||
signer: S,
|
||||
signer: Arc<RwLock<S>>,
|
||||
) -> ServerResult<Self, S> {
|
||||
let mut ca_store = DiskAggregateStore::<CertAuth<S>>::new(work_dir, CA_NS)?;
|
||||
ca_store.add_listener(events_queue);
|
||||
|
||||
Ok(CaServer {
|
||||
signer: Arc::new(RwLock::new(signer)),
|
||||
signer,
|
||||
ca_store: Arc::new(ca_store),
|
||||
})
|
||||
}
|
||||
@@ -936,6 +936,7 @@ mod tests {
|
||||
fn add_ta() {
|
||||
test::test_under_tmp(|d| {
|
||||
let signer = OpenSslSigner::build(&d).unwrap();
|
||||
let signer = Arc::new(RwLock::new(signer));
|
||||
|
||||
let event_queue = Arc::new(EventQueueListener::in_mem());
|
||||
|
||||
|
||||
+22
-10
@@ -1,6 +1,6 @@
|
||||
//! An RPKI publication protocol server.
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::{io, thread};
|
||||
|
||||
use bcder::Captured;
|
||||
@@ -91,16 +91,24 @@ impl KrillServer {
|
||||
let mut repo_dir = work_dir.clone();
|
||||
repo_dir.push("repo");
|
||||
|
||||
let signer = OpenSslSigner::build(work_dir)?;
|
||||
let signer = Arc::new(RwLock::new(signer));
|
||||
|
||||
let authorizer = Authorizer::new(token);
|
||||
|
||||
let pubserver = Arc::new(
|
||||
PubServer::build(base_uri.clone(), rrdp_base_uri.clone(), repo_dir, work_dir)
|
||||
.map_err(Error::PubServer)?,
|
||||
PubServer::build(
|
||||
base_uri.clone(),
|
||||
rrdp_base_uri.clone(),
|
||||
repo_dir,
|
||||
work_dir,
|
||||
signer.clone(),
|
||||
)
|
||||
.map_err(Error::PubServer)?,
|
||||
);
|
||||
|
||||
let proxy_server = ProxyServer::init(work_dir, &service_uri)?;
|
||||
let proxy_server = ProxyServer::init(work_dir)?;
|
||||
|
||||
let signer = OpenSslSigner::build(work_dir)?;
|
||||
let event_queue = Arc::new(EventQueueListener::in_mem());
|
||||
let caserver = Arc::new(ca::CaServer::build(work_dir, event_queue.clone(), signer)?);
|
||||
|
||||
@@ -117,7 +125,8 @@ impl KrillServer {
|
||||
let ta_aia = uri::Rsync::from_string(ta_aia).unwrap();
|
||||
|
||||
// Add publisher
|
||||
let req = PublisherRequest::new(ta_handle.clone(), repo_info.base_uri().clone());
|
||||
let req =
|
||||
PublisherRequest::new(ta_handle.clone(), None, repo_info.base_uri().clone());
|
||||
|
||||
pubserver.create_publisher(req).map_err(Error::PubServer)?;
|
||||
|
||||
@@ -378,16 +387,19 @@ impl KrillServer {
|
||||
pub fn ca_init(&mut self, init: CertAuthInit) -> EmptyRes {
|
||||
let (handle, pub_mode) = init.unwrap();
|
||||
|
||||
let repo_info = match pub_mode {
|
||||
CertAuthPubMode::Embedded => self.pubserver.repo_info_for(&handle)?,
|
||||
};
|
||||
let repo_info = self.pubserver.repo_info_for(&handle)?;
|
||||
let base_uri = repo_info.ca_repository("");
|
||||
|
||||
// Create CA
|
||||
self.caserver.init_ca(&handle, repo_info)?;
|
||||
|
||||
let id_cert = match pub_mode {
|
||||
CertAuthPubMode::Embedded => None,
|
||||
CertAuthPubMode::Rfc8181(id_cert) => Some(id_cert),
|
||||
};
|
||||
|
||||
// Add publisher
|
||||
let req = PublisherRequest::new(handle.clone(), base_uri);
|
||||
let req = PublisherRequest::new(handle.clone(), id_cert, base_uri);
|
||||
self.add_publisher(req)?;
|
||||
|
||||
Ok(())
|
||||
|
||||
+1
-3
@@ -360,9 +360,7 @@ pub fn ca_current_objects(handle: &Handle) -> Vec<Publish> {
|
||||
}
|
||||
|
||||
pub fn publisher_details(handle: &Handle) -> PublisherDetails {
|
||||
match krill_admin(Command::Publishers(PublishersCommand::Details(
|
||||
handle.clone(),
|
||||
))) {
|
||||
match krill_admin(Command::Publishers(PublishersCommand::Show(handle.clone()))) {
|
||||
ApiResponse::PublisherDetails(pub_details) => pub_details,
|
||||
_ => panic!("Expected publisher details"),
|
||||
}
|
||||
|
||||
+10
-3
@@ -5,6 +5,7 @@ use rpki::uri;
|
||||
use crate::commons::api::rrdp::{CurrentObjects, DeltaElements, VerificationError};
|
||||
use crate::commons::api::{Handle, ListReply, PublishDelta, PublisherDetails, PublisherRequest};
|
||||
use crate::commons::eventsourcing::{Aggregate, CommandDetails, SentCommand, StoredEvent};
|
||||
use commons::remote::id::IdCert;
|
||||
|
||||
//------------ PublisherInit -------------------------------------------------
|
||||
|
||||
@@ -12,13 +13,14 @@ pub type PublisherInit = StoredEvent<InitPublisherDetails>;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
pub struct InitPublisherDetails {
|
||||
id_cert: Option<IdCert>,
|
||||
base_uri: uri::Rsync,
|
||||
}
|
||||
|
||||
impl InitPublisherDetails {
|
||||
pub fn for_request(req: PublisherRequest) -> PublisherInit {
|
||||
let (handle, base_uri) = req.unwrap(); // (self
|
||||
let details = InitPublisherDetails { base_uri };
|
||||
let (handle, id_cert, base_uri) = req.unwrap(); // (self
|
||||
let details = InitPublisherDetails { id_cert, base_uri };
|
||||
StoredEvent::new(&handle, 0, details)
|
||||
}
|
||||
}
|
||||
@@ -107,6 +109,9 @@ pub struct Publisher {
|
||||
version: u64,
|
||||
deactivated: bool,
|
||||
|
||||
/// Used by remote RFC8181 publishers
|
||||
id_cert: Option<IdCert>,
|
||||
|
||||
/// Publication jail for this publisher
|
||||
base_uri: uri::Rsync,
|
||||
|
||||
@@ -130,8 +135,9 @@ impl Publisher {
|
||||
|
||||
pub fn as_api_details(&self) -> PublisherDetails {
|
||||
PublisherDetails::new(
|
||||
self.handle.as_str(),
|
||||
&self.handle,
|
||||
self.deactivated,
|
||||
self.id_cert.as_ref(),
|
||||
&self.base_uri,
|
||||
self.current_objects
|
||||
.elements()
|
||||
@@ -151,6 +157,7 @@ impl Publisher {
|
||||
handle,
|
||||
version: 1,
|
||||
deactivated: false,
|
||||
id_cert: init.id_cert,
|
||||
base_uri: init.base_uri,
|
||||
current_objects: CurrentObjects::default(),
|
||||
}
|
||||
|
||||
+22
-5
@@ -1,6 +1,6 @@
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
|
||||
use chrono::Duration;
|
||||
|
||||
@@ -18,18 +18,28 @@ use crate::pubd::publishers::{
|
||||
use crate::pubd::repo::{
|
||||
self, RrdpCommandDetails, RrdpInitDetails, RrdpServer, RrdpServerError, RsyncdStore,
|
||||
};
|
||||
use commons::util::softsigner::OpenSslSigner;
|
||||
|
||||
//------------ PubServer -----------------------------------------------------
|
||||
|
||||
/// This server manages all publishers. I.e. finds them, adds them, dispatches
|
||||
/// commands to them, stores them.. also publishes the combined snapshots and
|
||||
/// deltas, and manages the files on disk for rsync.
|
||||
/// The Publication Server.
|
||||
///
|
||||
/// This component is responsible for:
|
||||
/// * managing allowed publishers
|
||||
/// * verifying requests from remote RFC8183 publishers
|
||||
/// * verifying requests from local (embedded) publishers
|
||||
/// * updating the RRDP server with any deltas
|
||||
/// * updating the contents on disk for Rsync
|
||||
/// * responding to publishers
|
||||
/// * wrapping responses in RFC8183 for remote publishers
|
||||
///
|
||||
pub struct PubServer {
|
||||
rrdp_store: Arc<DiskAggregateStore<RrdpServer>>,
|
||||
rsyncd_store: RsyncdStore,
|
||||
store: Arc<DiskAggregateStore<Publisher>>,
|
||||
base_rsync_uri: uri::Rsync, // jail for the publishers,
|
||||
command_lock: Mutex<()>, // Only one command at the time.
|
||||
signer: Arc<RwLock<OpenSslSigner>>,
|
||||
}
|
||||
|
||||
impl PubServer {
|
||||
@@ -38,6 +48,7 @@ impl PubServer {
|
||||
base_http_uri: uri::Https, // for the RRDP files
|
||||
repo_dir: PathBuf, // for the RRDP and rsync files
|
||||
work_dir: &PathBuf, // for the aggregate stores
|
||||
signer: Arc<RwLock<OpenSslSigner>>,
|
||||
) -> Result<Self, Error> {
|
||||
let rrdp_store = Arc::new(DiskAggregateStore::<RrdpServer>::new(
|
||||
work_dir,
|
||||
@@ -64,6 +75,7 @@ impl PubServer {
|
||||
store,
|
||||
base_rsync_uri,
|
||||
command_lock,
|
||||
signer,
|
||||
};
|
||||
|
||||
Ok(pubserver)
|
||||
@@ -331,11 +343,15 @@ mod tests {
|
||||
fn make_publisher_req(handle: &str, uri: &str) -> PublisherRequest {
|
||||
let base_uri = test::rsync(uri);
|
||||
let handle = Handle::from_str_unsafe(handle);
|
||||
let id_cert = None; // embedded
|
||||
|
||||
PublisherRequest::new(handle, base_uri)
|
||||
PublisherRequest::new(handle, id_cert, base_uri)
|
||||
}
|
||||
|
||||
fn make_server(work_dir: &PathBuf) -> PubServer {
|
||||
let signer = OpenSslSigner::build(work_dir).unwrap();
|
||||
let signer = Arc::new(RwLock::new(signer));
|
||||
|
||||
let mut base_dir = work_dir.clone();
|
||||
base_dir.push("repo");
|
||||
|
||||
@@ -344,6 +360,7 @@ mod tests {
|
||||
server_base_http_uri(),
|
||||
base_dir,
|
||||
work_dir,
|
||||
signer,
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ use krill::daemon::test::{krill_admin, test_with_krill_server};
|
||||
fn add_publisher(handle: &Handle, base_uri: &str) {
|
||||
let command = Command::Publishers(PublishersCommand::Add(AddPublisher {
|
||||
handle: handle.clone(),
|
||||
id_cert: None, // embedded for test
|
||||
base_uri: test::rsync(base_uri),
|
||||
}));
|
||||
krill_admin(command);
|
||||
@@ -27,7 +28,7 @@ fn list_publishers() -> ApiResponse {
|
||||
}
|
||||
|
||||
fn details_publisher(handle: &Handle) -> ApiResponse {
|
||||
let command = Command::Publishers(PublishersCommand::Details(handle.clone()));
|
||||
let command = Command::Publishers(PublishersCommand::Show(handle.clone()));
|
||||
|
||||
krill_admin(command)
|
||||
}
|
||||
@@ -56,7 +57,7 @@ fn admin_publishers() {
|
||||
let details_res = details_publisher(&handle);
|
||||
match details_res {
|
||||
ApiResponse::PublisherDetails(details) => {
|
||||
assert_eq!("alice", details.handle());
|
||||
assert_eq!(&handle, details.handle());
|
||||
assert_eq!(false, details.deactivated());
|
||||
}
|
||||
_ => panic!("Expected details"),
|
||||
@@ -69,7 +70,7 @@ fn admin_publishers() {
|
||||
let details_res = details_publisher(&handle);
|
||||
match details_res {
|
||||
ApiResponse::PublisherDetails(details) => {
|
||||
assert_eq!("alice", details.handle());
|
||||
assert_eq!(&handle, details.handle());
|
||||
assert_eq!(true, details.deactivated());
|
||||
}
|
||||
_ => panic!("Expected details"),
|
||||
|
||||
Reference in New Issue
Block a user