1 //! Helper functions for testing Krill.
2
3 use std::{
4 fs,
5 fs::File,
6 io::Write,
7 path::{Path, PathBuf},
8 str::FromStr,
9 sync::Arc,
10 time::Duration,
11 };
12
13 use bytes::Bytes;
14
15 use hyper::StatusCode;
16 use tokio::time::{sleep, timeout};
17
18 use rpki::{repository::crypto::KeyIdentifier, uri};
19
20 use crate::{
21 cli::{
22 options::{BulkCaCommand, CaCommand, Command, Options, PubServerCommand},
23 report::{ApiResponse, ReportFormat},
24 {Error, KrillClient},
25 },
26 commons::{
27 api::{
28 AddChildRequest, AspaCustomer, AspaDefinition, AspaDefinitionList, AspaProvidersUpdate, CertAuthInfo,
29 CertAuthInit, CertifiedKeyInfo, ChildHandle, Handle, ObjectName, ParentCaContact, ParentCaReq,
30 ParentHandle, ParentStatuses, PublicationServerUris, PublisherDetails, PublisherHandle, PublisherList,
31 RepositoryContact, ResourceClassKeysInfo, ResourceClassName, ResourceSet, RoaDefinition,
32 RoaDefinitionUpdates, RtaList, RtaName, RtaPrepResponse, TypedPrefix, UpdateChildRequest,
33 },
34 bgp::{Announcement, BgpAnalysisReport, BgpAnalysisSuggestion},
35 crypto::SignSupport,
36 remote::rfc8183,
37 remote::rfc8183::{ChildRequest, RepositoryResponse},
38 util::httpclient,
39 },
40 daemon::{
41 ca::{ta_handle, ResourceTaggedAttestation, RtaContentRequest, RtaPrepareRequest},
42 config::Config,
43 http::server,
44 },
45 };
46
47 #[cfg(test)]
48 use crate::commons::crypto::IdCert;
49
50 pub const KRILL_SERVER_URI: &str = "https://localhost:3000/";
51 pub const KRILL_PUBD_SERVER_URI: &str = "https://localhost:3001/";
52
init_logging()53 pub fn init_logging() {
54 // Just creates a test config so we can initialize logging, then forgets about it
55 let d = PathBuf::from(".");
56 let _ = Config::test(&d, false, false, false).init_logging();
57 }
58
info(msg: impl std::fmt::Display)59 pub fn info(msg: impl std::fmt::Display) {
60 info!("{}", msg); // we can change this to using the logger crate later
61 }
62
sleep_seconds(secs: u64)63 pub async fn sleep_seconds(secs: u64) {
64 sleep(Duration::from_secs(secs)).await
65 }
66
sleep_millis(millis: u64)67 pub async fn sleep_millis(millis: u64) {
68 sleep(Duration::from_millis(millis)).await
69 }
70
krill_server_ready() -> bool71 pub async fn krill_server_ready() -> bool {
72 server_ready(KRILL_SERVER_URI).await
73 }
74
krill_pubd_ready() -> bool75 pub async fn krill_pubd_ready() -> bool {
76 server_ready(KRILL_PUBD_SERVER_URI).await
77 }
78
server_ready(uri: &str) -> bool79 pub async fn server_ready(uri: &str) -> bool {
80 let health = format!("{}health", uri);
81
82 for _ in 0..300 {
83 match httpclient::client(&health) {
84 Ok(client) => {
85 let res = timeout(Duration::from_millis(100), client.get(&health).send()).await;
86
87 if let Ok(Ok(res)) = res {
88 if res.status() == StatusCode::OK {
89 return true;
90 } else {
91 eprintln!("Got status: {}", res.status());
92 }
93 }
94 }
95 Err(_) => return false,
96 }
97 sleep_millis(100).await;
98 }
99
100 false
101 }
102
test_config(dir: &Path, enable_testbed: bool, enable_ca_refresh: bool, enable_suspend: bool) -> Config103 pub fn test_config(dir: &Path, enable_testbed: bool, enable_ca_refresh: bool, enable_suspend: bool) -> Config {
104 if enable_testbed {
105 crate::constants::enable_test_mode();
106 crate::constants::enable_test_announcements();
107 }
108 Config::test(dir, enable_testbed, enable_ca_refresh, enable_suspend)
109 }
110
init_config(config: &Config)111 pub fn init_config(config: &Config) {
112 if config.init_logging().is_err() {
113 trace!("Logging already initialized");
114 }
115 config.verify().unwrap();
116 }
117
118 /// Starts krill server for testing using the given configuration. Creates a random base directory in the 'work' folder,
119 /// adjusts the config to use it and returns it. Be sure to clean it up when the test is done.
start_krill_with_custom_config(mut config: Config) -> PathBuf120 pub async fn start_krill_with_custom_config(mut config: Config) -> PathBuf {
121 let dir = tmp_dir();
122 config.set_data_dir(dir.clone());
123 start_krill(config).await;
124 dir
125 }
126
127 /// Starts krill server for testing using the default test configuration, and optionally with testbed mode enabled.
128 /// Creates a random base directory in the 'work' folder, and returns it. Be sure to clean it up when the test is done.
start_krill_with_default_test_config( enable_testbed: bool, enable_ca_refresh: bool, enable_suspend: bool, ) -> PathBuf129 pub async fn start_krill_with_default_test_config(
130 enable_testbed: bool,
131 enable_ca_refresh: bool,
132 enable_suspend: bool,
133 ) -> PathBuf {
134 let dir = tmp_dir();
135 let config = test_config(&dir, enable_testbed, enable_ca_refresh, enable_suspend);
136 start_krill(config).await;
137 dir
138 }
139
start_krill(config: Config)140 async fn start_krill(config: Config) {
141 init_config(&config);
142 tokio::spawn(start_krill_with_error_trap(Arc::new(config)));
143 assert!(krill_server_ready().await);
144 }
145
start_krill_with_error_trap(config: Arc<Config>)146 async fn start_krill_with_error_trap(config: Arc<Config>) {
147 if let Err(err) = server::start_krill_daemon(config).await {
148 error!("Krill failed to start: {}", err);
149 }
150 }
151
152 /// Starts a krill pubd for testing on its own port, and its
153 /// own temp dir for storage.
start_krill_pubd() -> PathBuf154 pub async fn start_krill_pubd() -> PathBuf {
155 let dir = tmp_dir();
156 let mut config = test_config(&dir, false, false, false);
157 init_config(&config);
158 config.port = 3001;
159
160 tokio::spawn(start_krill_with_error_trap(Arc::new(config)));
161 assert!(krill_pubd_ready().await);
162
163 // Initialize the repository using separate URIs
164 let uris = {
165 let rsync_base = uri::Rsync::from_str("rsync://localhost/dedicated-repo/").unwrap();
166 let rrdp_base_uri = uri::Https::from_str("https://localhost:3001/test-rrdp/").unwrap();
167 PublicationServerUris::new(rrdp_base_uri, rsync_base)
168 };
169 let command = PubServerCommand::RepositoryInit(uris);
170 krill_dedicated_pubd_admin(command).await;
171
172 dir
173 }
174
krill_admin(command: Command) -> ApiResponse175 pub async fn krill_admin(command: Command) -> ApiResponse {
176 let krillc_opts = Options::new(https(KRILL_SERVER_URI), "secret", ReportFormat::Json, command);
177 match KrillClient::process(krillc_opts).await {
178 Ok(res) => res, // ok
179 Err(e) => panic!("{}", e),
180 }
181 }
182
krill_embedded_pubd_admin(command: PubServerCommand) -> ApiResponse183 pub async fn krill_embedded_pubd_admin(command: PubServerCommand) -> ApiResponse {
184 krill_admin(Command::PubServer(command)).await
185 }
186
krill_dedicated_pubd_admin(command: PubServerCommand) -> ApiResponse187 pub async fn krill_dedicated_pubd_admin(command: PubServerCommand) -> ApiResponse {
188 let options = Options::new(
189 https(KRILL_PUBD_SERVER_URI),
190 "secret",
191 ReportFormat::Json,
192 Command::PubServer(command),
193 );
194 match KrillClient::process(options).await {
195 Ok(res) => res, // ok
196 Err(e) => panic!("{}", e),
197 }
198 }
199
krill_admin_expect_error(command: Command) -> Error200 pub async fn krill_admin_expect_error(command: Command) -> Error {
201 let krillc_opts = Options::new(https(KRILL_SERVER_URI), "secret", ReportFormat::Json, command);
202 match KrillClient::process(krillc_opts).await {
203 Ok(_res) => panic!("Expected error"),
204 Err(e) => e,
205 }
206 }
207
cas_refresh_all()208 pub async fn cas_refresh_all() {
209 krill_admin(Command::Bulk(BulkCaCommand::Refresh)).await;
210 }
211
cas_refresh_single(ca: &Handle)212 pub async fn cas_refresh_single(ca: &Handle) {
213 krill_admin(Command::CertAuth(CaCommand::Refresh(ca.clone()))).await;
214 }
215
ca_suspend_child(ca: &Handle, child: &ChildHandle)216 pub async fn ca_suspend_child(ca: &Handle, child: &ChildHandle) {
217 krill_admin(Command::CertAuth(CaCommand::ChildUpdate(
218 ca.clone(),
219 child.clone(),
220 UpdateChildRequest::suspend(),
221 )))
222 .await;
223 }
224
ca_unsuspend_child(ca: &Handle, child: &ChildHandle)225 pub async fn ca_unsuspend_child(ca: &Handle, child: &ChildHandle) {
226 krill_admin(Command::CertAuth(CaCommand::ChildUpdate(
227 ca.clone(),
228 child.clone(),
229 UpdateChildRequest::unsuspend(),
230 )))
231 .await;
232 }
233
init_ca(handle: &Handle)234 pub async fn init_ca(handle: &Handle) {
235 krill_admin(Command::CertAuth(CaCommand::Init(CertAuthInit::new(handle.clone())))).await;
236 }
237
delete_ca(ca: &Handle)238 pub async fn delete_ca(ca: &Handle) {
239 krill_admin(Command::CertAuth(CaCommand::Delete(ca.clone()))).await;
240 }
241
ca_repo_update_rfc8181(handle: &Handle, response: RepositoryResponse)242 pub async fn ca_repo_update_rfc8181(handle: &Handle, response: RepositoryResponse) {
243 krill_admin(Command::CertAuth(CaCommand::RepoUpdate(
244 handle.clone(),
245 RepositoryContact::new(response),
246 )))
247 .await;
248 }
249
generate_new_id(handle: &Handle)250 pub async fn generate_new_id(handle: &Handle) {
251 krill_admin(Command::CertAuth(CaCommand::UpdateId(handle.clone()))).await;
252 }
253
parent_contact(handle: &Handle, child: &ChildHandle) -> ParentCaContact254 pub async fn parent_contact(handle: &Handle, child: &ChildHandle) -> ParentCaContact {
255 match krill_admin(Command::CertAuth(CaCommand::ParentResponse(
256 handle.clone(),
257 child.clone(),
258 )))
259 .await
260 {
261 ApiResponse::ParentCaContact(contact) => contact,
262 _ => panic!("Expected RFC8183 parent response"),
263 }
264 }
265
request(handle: &Handle) -> rfc8183::ChildRequest266 pub async fn request(handle: &Handle) -> rfc8183::ChildRequest {
267 match krill_admin(Command::CertAuth(CaCommand::ChildRequest(handle.clone()))).await {
268 ApiResponse::Rfc8183ChildRequest(req) => req,
269 _ => panic!("Expected child request"),
270 }
271 }
272
add_child_to_ta_rfc6492( handle: &Handle, child_request: rfc8183::ChildRequest, resources: ResourceSet, ) -> ParentCaContact273 pub async fn add_child_to_ta_rfc6492(
274 handle: &Handle,
275 child_request: rfc8183::ChildRequest,
276 resources: ResourceSet,
277 ) -> ParentCaContact {
278 let (_, _, id_cert) = child_request.unpack();
279 let req = AddChildRequest::new(handle.clone(), resources, id_cert);
280 let res = krill_admin(Command::CertAuth(CaCommand::ChildAdd(ta_handle(), req))).await;
281
282 match res {
283 ApiResponse::ParentCaContact(info) => info,
284 _ => panic!("Expected ParentCaInfo response"),
285 }
286 }
287
add_child_rfc6492( parent: &ParentHandle, child: &ChildHandle, child_request: rfc8183::ChildRequest, resources: ResourceSet, ) -> ParentCaContact288 pub async fn add_child_rfc6492(
289 parent: &ParentHandle,
290 child: &ChildHandle,
291 child_request: rfc8183::ChildRequest,
292 resources: ResourceSet,
293 ) -> ParentCaContact {
294 let (_, _, id_cert) = child_request.unpack();
295
296 let add_child_request = AddChildRequest::new(child.clone(), resources, id_cert);
297
298 match krill_admin(Command::CertAuth(CaCommand::ChildAdd(
299 parent.clone(),
300 add_child_request,
301 )))
302 .await
303 {
304 ApiResponse::ParentCaContact(info) => info,
305 _ => panic!("Expected ParentCaInfo response"),
306 }
307 }
308
update_child(ca: &Handle, child: &ChildHandle, resources: &ResourceSet)309 pub async fn update_child(ca: &Handle, child: &ChildHandle, resources: &ResourceSet) {
310 let req = UpdateChildRequest::resources(resources.clone());
311 send_child_request(ca, child, req).await
312 }
313
update_child_id(ca: &Handle, child: &ChildHandle, req: ChildRequest)314 pub async fn update_child_id(ca: &Handle, child: &ChildHandle, req: ChildRequest) {
315 let (_, _, id) = req.unpack();
316 let req = UpdateChildRequest::id_cert(id);
317 send_child_request(ca, child, req).await
318 }
319
delete_child(ca: &Handle, child: &ChildHandle)320 pub async fn delete_child(ca: &Handle, child: &ChildHandle) {
321 krill_admin(Command::CertAuth(CaCommand::ChildDelete(ca.clone(), child.clone()))).await;
322 }
323
suspend_inactive_child(ca: &Handle, child: &ChildHandle)324 pub async fn suspend_inactive_child(ca: &Handle, child: &ChildHandle) {
325 let update = UpdateChildRequest::suspend();
326
327 krill_admin(Command::CertAuth(CaCommand::ChildUpdate(
328 ca.clone(),
329 child.clone(),
330 update,
331 )))
332 .await;
333 }
334
unsuspend_child(ca: &Handle, child: &ChildHandle)335 pub async fn unsuspend_child(ca: &Handle, child: &ChildHandle) {
336 let update = UpdateChildRequest::unsuspend();
337
338 krill_admin(Command::CertAuth(CaCommand::ChildUpdate(
339 ca.clone(),
340 child.clone(),
341 update,
342 )))
343 .await;
344 }
345
send_child_request(ca: &Handle, child: &Handle, req: UpdateChildRequest)346 async fn send_child_request(ca: &Handle, child: &Handle, req: UpdateChildRequest) {
347 match krill_admin(Command::CertAuth(CaCommand::ChildUpdate(
348 ca.clone(),
349 child.clone(),
350 req,
351 )))
352 .await
353 {
354 ApiResponse::Empty => {}
355 _ => error!("Expected empty ok response"),
356 }
357 cas_refresh_all().await;
358 }
359
add_parent_to_ca(ca: &Handle, parent: ParentCaReq)360 pub async fn add_parent_to_ca(ca: &Handle, parent: ParentCaReq) {
361 krill_admin(Command::CertAuth(CaCommand::AddParent(ca.clone(), parent))).await;
362 }
363
parent_statuses(ca: &Handle) -> ParentStatuses364 pub async fn parent_statuses(ca: &Handle) -> ParentStatuses {
365 match krill_admin(Command::CertAuth(CaCommand::ParentStatuses(ca.clone()))).await {
366 ApiResponse::ParentStatuses(status) => status,
367 _ => panic!("Expected parent statuses"),
368 }
369 }
370
update_parent_contact(ca: &Handle, parent: &ParentHandle, contact: ParentCaContact)371 pub async fn update_parent_contact(ca: &Handle, parent: &ParentHandle, contact: ParentCaContact) {
372 let parent_req = ParentCaReq::new(parent.clone(), contact);
373 krill_admin(Command::CertAuth(CaCommand::AddParent(ca.clone(), parent_req))).await;
374 }
375
delete_parent(ca: &Handle, parent: &ParentHandle)376 pub async fn delete_parent(ca: &Handle, parent: &ParentHandle) {
377 krill_admin(Command::CertAuth(CaCommand::RemoveParent(ca.clone(), parent.clone()))).await;
378 }
379
ca_route_authorizations_update(handle: &Handle, updates: RoaDefinitionUpdates)380 pub async fn ca_route_authorizations_update(handle: &Handle, updates: RoaDefinitionUpdates) {
381 krill_admin(Command::CertAuth(CaCommand::RouteAuthorizationsUpdate(
382 handle.clone(),
383 updates,
384 )))
385 .await;
386 }
387
ca_route_authorizations_update_expect_error(handle: &Handle, updates: RoaDefinitionUpdates)388 pub async fn ca_route_authorizations_update_expect_error(handle: &Handle, updates: RoaDefinitionUpdates) {
389 krill_admin_expect_error(Command::CertAuth(CaCommand::RouteAuthorizationsUpdate(
390 handle.clone(),
391 updates,
392 )))
393 .await;
394 }
395
ca_route_authorizations_suggestions(handle: &Handle) -> BgpAnalysisSuggestion396 pub async fn ca_route_authorizations_suggestions(handle: &Handle) -> BgpAnalysisSuggestion {
397 match krill_admin(Command::CertAuth(CaCommand::BgpAnalysisSuggest(handle.clone(), None))).await {
398 ApiResponse::BgpAnalysisSuggestions(suggestion) => suggestion,
399 _ => panic!("Expected ROA suggestion"),
400 }
401 }
402
ca_route_authorization_dryrun(handle: &Handle, updates: RoaDefinitionUpdates) -> BgpAnalysisReport403 pub async fn ca_route_authorization_dryrun(handle: &Handle, updates: RoaDefinitionUpdates) -> BgpAnalysisReport {
404 match krill_admin(Command::CertAuth(CaCommand::RouteAuthorizationsDryRunUpdate(
405 handle.clone(),
406 updates,
407 )))
408 .await
409 {
410 ApiResponse::BgpAnalysisFull(report) => report,
411 _ => panic!("Expected BGP analysis report"),
412 }
413 }
414
ca_aspas_add(handle: &Handle, aspa: AspaDefinition)415 pub async fn ca_aspas_add(handle: &Handle, aspa: AspaDefinition) {
416 krill_admin(Command::CertAuth(CaCommand::AspasAddOrReplace(handle.clone(), aspa))).await;
417 }
418
ca_aspas_expect(handle: &Handle, expected_aspas: AspaDefinitionList)419 pub async fn ca_aspas_expect(handle: &Handle, expected_aspas: AspaDefinitionList) {
420 let res = krill_admin(Command::CertAuth(CaCommand::AspasList(handle.clone()))).await;
421
422 if let ApiResponse::AspaDefinitions(found_aspas) = res {
423 if expected_aspas != found_aspas {
424 panic!("Expected ASPAs:\n{}, Got ASPAs:\n{}", expected_aspas, found_aspas)
425 }
426 } else {
427 panic!("Expected AspaDefinitionsList")
428 }
429 }
430
ca_aspas_update(handle: &Handle, customer: AspaCustomer, update: AspaProvidersUpdate)431 pub async fn ca_aspas_update(handle: &Handle, customer: AspaCustomer, update: AspaProvidersUpdate) {
432 krill_admin(Command::CertAuth(CaCommand::AspasUpdate(
433 handle.clone(),
434 customer,
435 update,
436 )))
437 .await;
438 }
439
ca_aspas_remove(handle: &Handle, customer: AspaCustomer)440 pub async fn ca_aspas_remove(handle: &Handle, customer: AspaCustomer) {
441 krill_admin(Command::CertAuth(CaCommand::AspasRemove(handle.clone(), customer))).await;
442 }
443
ca_details(handle: &Handle) -> CertAuthInfo444 pub async fn ca_details(handle: &Handle) -> CertAuthInfo {
445 match krill_admin(Command::CertAuth(CaCommand::Show(handle.clone()))).await {
446 ApiResponse::CertAuthInfo(inf) => inf,
447 _ => panic!("Expected cert auth info"),
448 }
449 }
450
rta_sign_sign( ca: Handle, name: RtaName, resources: ResourceSet, keys: Vec<KeyIdentifier>, content: Bytes, )451 pub async fn rta_sign_sign(
452 ca: Handle,
453 name: RtaName,
454 resources: ResourceSet,
455 keys: Vec<KeyIdentifier>,
456 content: Bytes,
457 ) {
458 let request = RtaContentRequest::new(resources, SignSupport::sign_validity_days(14), keys, content);
459 let command = Command::CertAuth(CaCommand::RtaSign(ca, name, request));
460 krill_admin(command).await;
461 }
462
rta_list(ca: Handle) -> RtaList463 pub async fn rta_list(ca: Handle) -> RtaList {
464 let command = Command::CertAuth(CaCommand::RtaList(ca));
465 match krill_admin(command).await {
466 ApiResponse::RtaList(list) => list,
467 _ => panic!("Expected RTA list"),
468 }
469 }
470
rta_show(ca: Handle, name: RtaName) -> ResourceTaggedAttestation471 pub async fn rta_show(ca: Handle, name: RtaName) -> ResourceTaggedAttestation {
472 let command = Command::CertAuth(CaCommand::RtaShow(ca, name, None));
473 match krill_admin(command).await {
474 ApiResponse::Rta(rta) => rta,
475 _ => panic!("Expected RTA"),
476 }
477 }
478
rta_multi_prep(ca: Handle, name: RtaName, resources: ResourceSet) -> RtaPrepResponse479 pub async fn rta_multi_prep(ca: Handle, name: RtaName, resources: ResourceSet) -> RtaPrepResponse {
480 let request = RtaPrepareRequest::new(resources, SignSupport::sign_validity_days(14));
481 let command = Command::CertAuth(CaCommand::RtaMultiPrep(ca, name, request));
482 match krill_admin(command).await {
483 ApiResponse::RtaMultiPrep(res) => res,
484 _ => panic!("Expected RtaMultiPrep"),
485 }
486 }
487
rta_multi_cosign(ca: Handle, name: RtaName, rta: ResourceTaggedAttestation)488 pub async fn rta_multi_cosign(ca: Handle, name: RtaName, rta: ResourceTaggedAttestation) {
489 let command = Command::CertAuth(CaCommand::RtaMultiCoSign(ca, name, rta));
490 krill_admin(command).await;
491 }
492
ca_key_for_rcn(handle: &Handle, rcn: &ResourceClassName) -> CertifiedKeyInfo493 pub async fn ca_key_for_rcn(handle: &Handle, rcn: &ResourceClassName) -> CertifiedKeyInfo {
494 ca_details(handle)
495 .await
496 .resource_classes()
497 .get(rcn)
498 .unwrap()
499 .current_key()
500 .unwrap()
501 .clone()
502 }
503
ca_new_key_for_rcn(handle: &Handle, rcn: &ResourceClassName) -> CertifiedKeyInfo504 pub async fn ca_new_key_for_rcn(handle: &Handle, rcn: &ResourceClassName) -> CertifiedKeyInfo {
505 ca_details(handle)
506 .await
507 .resource_classes()
508 .get(rcn)
509 .unwrap()
510 .new_key()
511 .unwrap()
512 .clone()
513 }
514
ca_contains_resources(handle: &Handle, resources: &ResourceSet) -> bool515 pub async fn ca_contains_resources(handle: &Handle, resources: &ResourceSet) -> bool {
516 for _ in 0..30_u8 {
517 if ca_current_resources(handle).await.contains(resources) {
518 return true;
519 }
520 cas_refresh_all().await;
521 sleep_seconds(1).await
522 }
523 false
524 }
525
ca_equals_resources(handle: &Handle, resources: &ResourceSet) -> bool526 pub async fn ca_equals_resources(handle: &Handle, resources: &ResourceSet) -> bool {
527 for _ in 0..30_u8 {
528 if &ca_current_resources(handle).await == resources {
529 return true;
530 }
531 cas_refresh_all().await;
532 sleep_seconds(1).await
533 }
534 false
535 }
536
rc_is_removed(handle: &Handle) -> bool537 pub async fn rc_is_removed(handle: &Handle) -> bool {
538 for _ in 0..300 {
539 let ca = ca_details(handle).await;
540 if ca.resource_classes().get(&ResourceClassName::default()).is_none() {
541 return true;
542 }
543 cas_refresh_all().await;
544 sleep_seconds(100).await
545 }
546 false
547 }
548
ca_current_resources(handle: &Handle) -> ResourceSet549 pub async fn ca_current_resources(handle: &Handle) -> ResourceSet {
550 let ca = ca_details(handle).await;
551
552 let mut res = ResourceSet::default();
553
554 for rc in ca.resource_classes().values() {
555 if let Some(resources) = rc.current_resources() {
556 res = res.union(resources)
557 }
558 }
559
560 res
561 }
562
list_publishers() -> PublisherList563 pub async fn list_publishers() -> PublisherList {
564 match krill_embedded_pubd_admin(PubServerCommand::PublisherList).await {
565 ApiResponse::PublisherList(pub_list) => pub_list,
566 _ => panic!("Expected publisher list"),
567 }
568 }
569
publisher_details(publisher: &PublisherHandle) -> PublisherDetails570 pub async fn publisher_details(publisher: &PublisherHandle) -> PublisherDetails {
571 match krill_embedded_pubd_admin(PubServerCommand::ShowPublisher(publisher.clone())).await {
572 ApiResponse::PublisherDetails(pub_details) => pub_details,
573 _ => panic!("Expected publisher details"),
574 }
575 }
576
dedicated_repo_publisher_details(publisher: &PublisherHandle) -> PublisherDetails577 pub async fn dedicated_repo_publisher_details(publisher: &PublisherHandle) -> PublisherDetails {
578 match krill_dedicated_pubd_admin(PubServerCommand::ShowPublisher(publisher.clone())).await {
579 ApiResponse::PublisherDetails(pub_details) => pub_details,
580 _ => panic!("Expected publisher details"),
581 }
582 }
583
publisher_request(handle: &Handle) -> rfc8183::PublisherRequest584 pub async fn publisher_request(handle: &Handle) -> rfc8183::PublisherRequest {
585 match krill_admin(Command::CertAuth(CaCommand::RepoPublisherRequest(handle.clone()))).await {
586 ApiResponse::Rfc8183PublisherRequest(req) => req,
587 _ => panic!("Expected publisher request"),
588 }
589 }
590
591 /// This method sets up a test directory with a random name (a number)
592 /// under 'work', relative to where cargo is running. It then runs the
593 /// test provided in the closure, and finally it cleans up the test
594 /// directory.
595 ///
596 /// Note that if your test fails the directory is not cleaned up.
test_under_tmp<F>(op: F) where F: FnOnce(PathBuf),597 pub fn test_under_tmp<F>(op: F)
598 where
599 F: FnOnce(PathBuf),
600 {
601 let dir = sub_dir(&PathBuf::from("work"));
602 let path = PathBuf::from(&dir);
603
604 op(dir);
605
606 let _result = fs::remove_dir_all(path);
607 }
608
tmp_dir() -> PathBuf609 pub fn tmp_dir() -> PathBuf {
610 sub_dir(&PathBuf::from("work"))
611 }
612
613 /// This method sets up a random subdirectory and returns it. It is
614 /// assumed that the caller will clean this directory themselves.
sub_dir(base_dir: &Path) -> PathBuf615 pub fn sub_dir(base_dir: &Path) -> PathBuf {
616 let mut bytes = [0; 8];
617 openssl::rand::rand_bytes(&mut bytes).unwrap();
618
619 let mut dir = base_dir.to_path_buf();
620 dir.push(hex::encode(bytes));
621
622 let full_path = PathBuf::from(&dir);
623 fs::create_dir_all(&full_path).unwrap();
624
625 full_path
626 }
627
rsync(s: &str) -> uri::Rsync628 pub fn rsync(s: &str) -> uri::Rsync {
629 uri::Rsync::from_str(s).unwrap()
630 }
631
https(s: &str) -> uri::Https632 pub fn https(s: &str) -> uri::Https {
633 uri::Https::from_str(s).unwrap()
634 }
635
handle(s: &str) -> Handle636 pub fn handle(s: &str) -> Handle {
637 Handle::from_str(s).unwrap()
638 }
639
ipv4_resources(v4: &str) -> ResourceSet640 pub fn ipv4_resources(v4: &str) -> ResourceSet {
641 ResourceSet::from_strs("", v4, "").unwrap()
642 }
643
resources(asn: &str, v4: &str, v6: &str) -> ResourceSet644 pub fn resources(asn: &str, v4: &str, v6: &str) -> ResourceSet {
645 ResourceSet::from_strs(asn, v4, v6).unwrap()
646 }
647
rcn(nr: u32) -> ResourceClassName648 pub fn rcn(nr: u32) -> ResourceClassName {
649 ResourceClassName::from(nr)
650 }
651
as_bytes(s: &str) -> Bytes652 pub fn as_bytes(s: &str) -> Bytes {
653 Bytes::copy_from_slice(s.as_bytes())
654 }
655
save_file(base_dir: &Path, file_name: &str, content: &[u8])656 pub fn save_file(base_dir: &Path, file_name: &str, content: &[u8]) {
657 let mut full_name = base_dir.to_path_buf();
658 full_name.push(PathBuf::from(file_name));
659 let mut f = File::create(full_name).unwrap();
660 f.write_all(content).unwrap();
661 }
662
663 // Support testing announcements and ROAs etc
664
announcement(s: &str) -> Announcement665 pub fn announcement(s: &str) -> Announcement {
666 let def = definition(s);
667 Announcement::from(def)
668 }
669
definition(s: &str) -> RoaDefinition670 pub fn definition(s: &str) -> RoaDefinition {
671 RoaDefinition::from_str(s).unwrap()
672 }
673
typed_prefix(s: &str) -> TypedPrefix674 pub fn typed_prefix(s: &str) -> TypedPrefix {
675 TypedPrefix::from_str(s).unwrap()
676 }
677
repo_update(ca: &Handle, contact: RepositoryContact)678 pub async fn repo_update(ca: &Handle, contact: RepositoryContact) {
679 let command = Command::CertAuth(CaCommand::RepoUpdate(ca.clone(), contact));
680 krill_admin(command).await;
681 }
682
embedded_repository_response(publisher: &PublisherHandle) -> rfc8183::RepositoryResponse683 pub async fn embedded_repository_response(publisher: &PublisherHandle) -> rfc8183::RepositoryResponse {
684 let command = PubServerCommand::RepositoryResponse(publisher.clone());
685 match krill_embedded_pubd_admin(command).await {
686 ApiResponse::Rfc8183RepositoryResponse(response) => response,
687 _ => panic!("Expected repository response."),
688 }
689 }
690
embedded_repo_add_publisher(req: rfc8183::PublisherRequest)691 pub async fn embedded_repo_add_publisher(req: rfc8183::PublisherRequest) {
692 let command = PubServerCommand::AddPublisher(req);
693 krill_embedded_pubd_admin(command).await;
694 }
695
dedicated_repository_response(publisher: &PublisherHandle) -> rfc8183::RepositoryResponse696 pub async fn dedicated_repository_response(publisher: &PublisherHandle) -> rfc8183::RepositoryResponse {
697 let command = PubServerCommand::RepositoryResponse(publisher.clone());
698 match krill_dedicated_pubd_admin(command).await {
699 ApiResponse::Rfc8183RepositoryResponse(response) => response,
700 _ => panic!("Expected repository response."),
701 }
702 }
703
dedicated_repo_add_publisher(req: rfc8183::PublisherRequest)704 pub async fn dedicated_repo_add_publisher(req: rfc8183::PublisherRequest) {
705 let command = PubServerCommand::AddPublisher(req);
706 krill_dedicated_pubd_admin(command).await;
707 }
708
set_up_ca_with_repo(ca: &Handle)709 pub async fn set_up_ca_with_repo(ca: &Handle) {
710 init_ca(ca).await;
711
712 // Add the CA as a publisher
713 let publisher_request = publisher_request(ca).await;
714 embedded_repo_add_publisher(publisher_request).await;
715
716 // Get a Repository Response for the CA
717 let response = embedded_repository_response(ca).await;
718
719 // Update the repo for the child
720 let contact = RepositoryContact::new(response);
721 repo_update(ca, contact).await;
722 }
723
expected_mft_and_crl(ca: &Handle, rcn: &ResourceClassName) -> Vec<String>724 pub async fn expected_mft_and_crl(ca: &Handle, rcn: &ResourceClassName) -> Vec<String> {
725 let rc_key = ca_key_for_rcn(ca, rcn).await;
726 let mft_file = rc_key.incoming_cert().mft_name().to_string();
727 let crl_file = rc_key.incoming_cert().crl_name().to_string();
728 vec![mft_file, crl_file]
729 }
730
expected_new_key_mft_and_crl(ca: &Handle, rcn: &ResourceClassName) -> Vec<String>731 pub async fn expected_new_key_mft_and_crl(ca: &Handle, rcn: &ResourceClassName) -> Vec<String> {
732 let rc_key = ca_new_key_for_rcn(ca, rcn).await;
733 let mft_file = rc_key.incoming_cert().mft_name().to_string();
734 let crl_file = rc_key.incoming_cert().crl_name().to_string();
735 vec![mft_file, crl_file]
736 }
737
expected_issued_cer(ca: &Handle, rcn: &ResourceClassName) -> String738 pub async fn expected_issued_cer(ca: &Handle, rcn: &ResourceClassName) -> String {
739 let rc_key = ca_key_for_rcn(ca, rcn).await;
740 ObjectName::from(rc_key.incoming_cert().cert()).to_string()
741 }
742
will_publish_embedded(test_msg: &str, publisher: &PublisherHandle, files: &[String]) -> bool743 pub async fn will_publish_embedded(test_msg: &str, publisher: &PublisherHandle, files: &[String]) -> bool {
744 will_publish(test_msg, publisher, files, PubServer::Embedded).await
745 }
746
will_publish_dedicated(test_msg: &str, publisher: &PublisherHandle, files: &[String]) -> bool747 pub async fn will_publish_dedicated(test_msg: &str, publisher: &PublisherHandle, files: &[String]) -> bool {
748 will_publish(test_msg, publisher, files, PubServer::Dedicated).await
749 }
750
751 enum PubServer {
752 Embedded,
753 Dedicated,
754 }
755
will_publish(test_msg: &str, publisher: &PublisherHandle, files: &[String], server: PubServer) -> bool756 async fn will_publish(test_msg: &str, publisher: &PublisherHandle, files: &[String], server: PubServer) -> bool {
757 let objects: Vec<_> = files.iter().map(|s| s.as_str()).collect();
758 for _ in 0..6000 {
759 let details = {
760 match &server {
761 PubServer::Dedicated => dedicated_repo_publisher_details(publisher).await,
762 PubServer::Embedded => publisher_details(publisher).await,
763 }
764 };
765
766 let current_files = details.current_files();
767
768 if current_files.len() == objects.len() {
769 let current_files: Vec<&uri::Rsync> = current_files.iter().map(|p| p.uri()).collect();
770 let mut all_matched = true;
771 for o in &objects {
772 if !current_files.iter().any(|uri| uri.ends_with(o)) {
773 all_matched = false;
774 }
775 }
776 if all_matched {
777 return true;
778 }
779 }
780
781 sleep_millis(100).await;
782 }
783
784 let details = publisher_details(publisher).await;
785
786 eprintln!(
787 "Did not find match for test: {}, for publisher: {}",
788 test_msg, publisher
789 );
790 eprintln!("Found:");
791 for file in details.current_files() {
792 eprintln!(" {}", file.uri());
793 }
794 eprintln!("Expected:");
795 for file in objects {
796 eprintln!(" {}", file);
797 }
798
799 false
800 }
801
set_up_ca_under_parent_with_resources(ca: &Handle, parent: &ParentHandle, resources: &ResourceSet)802 pub async fn set_up_ca_under_parent_with_resources(ca: &Handle, parent: &ParentHandle, resources: &ResourceSet) {
803 let child_request = request(ca).await;
804 let parent = {
805 let contact = add_child_rfc6492(parent, ca, child_request, resources.clone()).await;
806 ParentCaReq::new(parent.clone(), contact)
807 };
808 add_parent_to_ca(ca, parent).await;
809 assert!(ca_contains_resources(ca, resources).await);
810 }
811
ca_roll_init(handle: &Handle)812 pub async fn ca_roll_init(handle: &Handle) {
813 krill_admin(Command::CertAuth(CaCommand::KeyRollInit(handle.clone()))).await;
814 }
815
ca_roll_activate(handle: &Handle)816 pub async fn ca_roll_activate(handle: &Handle) {
817 krill_admin(Command::CertAuth(CaCommand::KeyRollActivate(handle.clone()))).await;
818 }
819
state_becomes_new_key(handle: &Handle) -> bool820 pub async fn state_becomes_new_key(handle: &Handle) -> bool {
821 for _ in 0..30_u8 {
822 let ca = ca_details(handle).await;
823
824 // wait for ALL RCs to become state new key
825 let rc_map = ca.resource_classes();
826
827 let expected = rc_map.len();
828 let mut found = 0;
829
830 for rc in rc_map.values() {
831 if let ResourceClassKeysInfo::RollNew(_) = rc.keys() {
832 found += 1;
833 }
834 }
835
836 if found == expected {
837 return true;
838 }
839
840 sleep_seconds(1).await
841 }
842 false
843 }
844
state_becomes_active(handle: &Handle) -> bool845 pub async fn state_becomes_active(handle: &Handle) -> bool {
846 for _ in 0..300 {
847 let ca = ca_details(handle).await;
848
849 // wait for ALL RCs to become state active key
850 let rc_map = ca.resource_classes();
851
852 let expected = rc_map.len();
853 let mut found = 0;
854
855 for rc in rc_map.values() {
856 if let ResourceClassKeysInfo::Active(_) = rc.keys() {
857 found += 1;
858 }
859 }
860
861 if found == expected {
862 return true;
863 }
864
865 sleep_millis(100).await
866 }
867 false
868 }
869
870 #[cfg(test)]
test_id_certificate() -> IdCert871 pub fn test_id_certificate() -> IdCert {
872 let data = include_bytes!("../test-resources/oob/id_publisher_ta.cer");
873 IdCert::decode(Bytes::from_static(data)).unwrap()
874 }
875