From 443803aaf589178911c8c950da1c4cd60b43d94b Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Thu, 2 Apr 2026 13:05:26 +0200 Subject: [PATCH] remove zonetrees use from zone status --- crates/api/src/lib.rs | 15 +- crates/cli/src/commands/zone.rs | 638 ++++++++++++++------------------ src/units/http_server.rs | 85 ++--- src/zone/storage.rs | 17 +- 4 files changed, 347 insertions(+), 408 deletions(-) diff --git a/crates/api/src/lib.rs b/crates/api/src/lib.rs index d599693b9..0cfed50b2 100644 --- a/crates/api/src/lib.rs +++ b/crates/api/src/lib.rs @@ -349,7 +349,7 @@ pub struct ZoneStatus { pub name: ZoneName, pub source: ZoneSource, pub policy: String, - pub stage: ZoneStage, + pub progress: Progress, pub keys: Vec, pub key_status: String, pub receipt_report: Option, @@ -365,6 +365,19 @@ pub struct ZoneStatus { pub halted_reason: Option, } +#[derive(Deserialize, Serialize, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum Progress { + WaitingForChanges, + ChangesReceived, + AtUnsignedReview, + WaitingToSign, + Signing, + Signed, + SigningFailed, + AtSignedReview, + Published, +} + #[derive(Clone, Debug, Deserialize, Serialize)] pub struct ZoneLoaderReport { pub started_at: SystemTime, diff --git a/crates/cli/src/commands/zone.rs b/crates/cli/src/commands/zone.rs index 0ed2eda45..7eba5b070 100644 --- a/crates/cli/src/commands/zone.rs +++ b/crates/cli/src/commands/zone.rs @@ -532,11 +532,11 @@ impl Zone { })?; // Determine progress - let progress = determine_progress(&zone, &policy); + let progress = &zone.progress; // Output information per step progressed until the first still // in-progress/aborted step or show all steps if all have completed. - progress.print(&zone, &policy); + print_timeline(progress, &zone, &policy); // If the pipeline is halted, show that. if let Some(reason) = zone.halted_reason { @@ -572,425 +572,345 @@ impl Zone { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] -enum Progress { - WaitingForChanges, - ChangesReceived, - AtUnsignedReview, - WaitingToSign, - Signing, - Signed, - SigningFailed, - AtSignedReview, - Published, -} - -fn determine_progress(zone: &ZoneStatus, policy: &PolicyInfo) -> Progress { - match zone.stage { - ZoneStage::Unsigned => match (&zone.receipt_report, zone.unsigned_review_status) { - (None, _) => Progress::WaitingForChanges, - (Some(_), None) => Progress::ChangesReceived, - (Some(_), Some(TimestampedZoneReviewStatus { status, .. })) => { - match status { - ZoneReviewStatus::Pending | ZoneReviewStatus::Rejected => { - Progress::AtUnsignedReview - } - ZoneReviewStatus::Approved => { - // After reviewing comes signing, and if we're not stuck at - // reviewing then we must be somewhere in signing. - let Some(signing_report) = &zone.signing_report else { - return Progress::WaitingToSign; - }; - match &signing_report.stage_report { - SigningStageReport::Requested(_) => Progress::WaitingToSign, - SigningStageReport::InProgress(_) => Progress::Signing, - SigningStageReport::Finished(s) => match s.succeeded { - true => Progress::Signed, - false => Progress::SigningFailed, - }, - } - } - } - } - }, - ZoneStage::Signed => { - if !policy.signer.review.required { - let Some(signing_report) = &zone.signing_report else { - return Progress::WaitingToSign; - }; - match &signing_report.stage_report { - SigningStageReport::Requested(_) => Progress::WaitingToSign, - SigningStageReport::InProgress(_) => Progress::Signing, - SigningStageReport::Finished(_) => Progress::Signed, - } - } else { - // After reviewing comes publication, and if we're not at the - // published stage then with review enabled we must still be - // at the review stage. - Progress::AtSignedReview - } +pub fn print_timeline(max: &Progress, zone: &ZoneStatus, policy: &PolicyInfo) { + println!( + "Status report for zone '{}' using policy '{}'", + zone.name, policy.name + ); + + let mut p = Progress::WaitingForChanges; + loop { + match p { + Progress::WaitingForChanges => print_waiting_for_changes(max, zone), + Progress::ChangesReceived => print_zone_received(zone), + Progress::AtUnsignedReview => print_pending_unsigned_review(max, zone, policy), + Progress::WaitingToSign => print_waiting_to_sign(max, zone), + Progress::Signing => print_signing(max, zone), + Progress::Signed => print_signed(max, zone, true), + Progress::SigningFailed => print_signed(max, zone, false), + Progress::AtSignedReview => print_pending_signed_review(max, zone, policy), + Progress::Published => print_published(max, zone), } - ZoneStage::Published => Progress::Published, - } -} - -impl std::fmt::Display for Progress { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Progress::WaitingForChanges => f.write_str("Waiting for changes"), - Progress::ChangesReceived => f.write_str("Changes received"), - Progress::AtUnsignedReview => f.write_str("At unsigned review"), - Progress::WaitingToSign => f.write_str("Waiting to sign"), - Progress::Signing => f.write_str("Signing"), - Progress::Signed => f.write_str("Signed"), - Progress::SigningFailed => f.write_str("Signing failed"), - Progress::AtSignedReview => f.write_str("At signed review"), - Progress::Published => f.write_str("Published"), + match next_progress(&p, max) { + ControlFlow::Continue(next_p) => p = next_p, + ControlFlow::Break(()) => break, } } } -impl Progress { - pub fn print(&self, zone: &ZoneStatus, policy: &PolicyInfo) { - println!( - "Status report for zone '{}' using policy '{}'", - zone.name, policy.name - ); - - let mut p = Progress::WaitingForChanges; - loop { - match p { - Progress::WaitingForChanges => self.print_waiting_for_changes(zone), - Progress::ChangesReceived => self.print_zone_received(zone), - Progress::AtUnsignedReview => self.print_pending_unsigned_review(zone, policy), - Progress::WaitingToSign => self.print_waiting_to_sign(zone), - Progress::Signing => self.print_signing(zone), - Progress::Signed => self.print_signed(zone, true), - Progress::SigningFailed => self.print_signed(zone, false), - Progress::AtSignedReview => self.print_pending_signed_review(zone, policy), - Progress::Published => self.print_published(zone), - } - match p.next(*self) { - ControlFlow::Continue(next_p) => p = next_p, - ControlFlow::Break(()) => break, - } - } +fn next_progress(this: &Progress, max: &Progress) -> ControlFlow<(), Progress> { + let next = match this { + Progress::WaitingForChanges => Progress::ChangesReceived, + Progress::ChangesReceived => Progress::AtUnsignedReview, + Progress::AtUnsignedReview => Progress::WaitingToSign, + Progress::WaitingToSign => Progress::Signing, + Progress::Signing => Progress::Signed, + Progress::Signed => Progress::AtSignedReview, + Progress::SigningFailed => return ControlFlow::Break(()), + Progress::AtSignedReview => Progress::Published, + Progress::Published => return ControlFlow::Break(()), + }; + + if next > *max { + return ControlFlow::Break(()); } - fn next(&self, max: Progress) -> ControlFlow<(), Progress> { - let next = match self { - Progress::WaitingForChanges => Progress::ChangesReceived, - Progress::ChangesReceived => Progress::AtUnsignedReview, - Progress::AtUnsignedReview => Progress::WaitingToSign, - Progress::WaitingToSign => Progress::Signing, - Progress::Signing => Progress::Signed, - Progress::Signed => Progress::AtSignedReview, - Progress::SigningFailed => return ControlFlow::Break(()), - Progress::AtSignedReview => Progress::Published, - Progress::Published => return ControlFlow::Break(()), - }; - - if next > max { - return ControlFlow::Break(()); - } + ControlFlow::Continue(next) +} - ControlFlow::Continue(next) - } +fn print_waiting_for_changes(max: &Progress, zone: &ZoneStatus) { + let done = *max > Progress::WaitingForChanges; + let waiting_waited = match done { + true => "Waited", + false => "Waiting", + }; + println!( + "{} {} for a new version of the {} zone", + status_icon(done), + waiting_waited, + zone.name + ); + + // TODO: When complete, show how long we waited. +} - fn print_waiting_for_changes(&self, zone: &ZoneStatus) { - let done = *self > Progress::WaitingForChanges; - let waiting_waited = match done { - true => "Waited", - false => "Waiting", - }; +fn print_zone_received(zone: &ZoneStatus) { + // TODO: we have no indication of whether a zone is currently being + // received or not, we can only say if it was received after the fact. + // Print how receival of the zone went. + let Some(report) = &zone.receipt_report else { + // This shouldn't happen. println!( - "{} {} for a new version of the {} zone", - status_icon(done), - waiting_waited, - zone.name + "{}\u{78} The receipt report for this zone is unavailable.{}", + ansi::RED, + ansi::RESET ); + return; + }; - // TODO: When complete, show how long we waited. - } + let (loading_fetching, loaded_fetched, filesystem_network) = match zone.source { + ZoneSource::None => unreachable!(), + ZoneSource::Zonefile { .. } => ("Loading", "Loaded", "filesystem"), + ZoneSource::Server { .. } => ("Fetching", "Fetched", "network"), + }; + + match report.finished_at { + None => { + println!("{} {loading_fetching} ..", status_icon(false),); - fn print_zone_received(&self, zone: &ZoneStatus) { - // TODO: we have no indication of whether a zone is currently being - // received or not, we can only say if it was received after the fact. - // Print how receival of the zone went. - let Some(report) = &zone.receipt_report else { - // This shouldn't happen. println!( - "{}\u{78} The receipt report for this zone is unavailable.{}", - ansi::RED, - ansi::RESET + " {loaded_fetched} {} and parsed {} in {} seconds", + format_size(report.byte_count, " ", "B"), + format_size(report.record_count, "", " records"), + SystemTime::now() + .duration_since(report.started_at) + .unwrap() + .as_secs() ); - return; - }; - - let (loading_fetching, loaded_fetched, filesystem_network) = match zone.source { - ZoneSource::None => unreachable!(), - ZoneSource::Zonefile { .. } => ("Loading", "Loaded", "filesystem"), - ZoneSource::Server { .. } => ("Fetching", "Fetched", "network"), - }; - - match report.finished_at { - None => { - println!("{} {loading_fetching} ..", status_icon(false),); - - println!( - " {loaded_fetched} {} and parsed {} in {} seconds", - format_size(report.byte_count, " ", "B"), - format_size(report.record_count, "", " records"), - SystemTime::now() - .duration_since(report.started_at) - .unwrap() - .as_secs() - ); - } - Some(finished_at) => { - println!( - "{} Loaded {}", - status_icon(true), - serial_to_string(zone.unsigned_serial), - ); - - println!(" Loaded at {}", to_rfc3339_ago(report.finished_at)); - - println!( - " {loaded_fetched} {} and {} from the {filesystem_network} in {} seconds", - format_size(report.byte_count, " ", "B"), - format_size(report.record_count, "", " records"), - finished_at - .duration_since(report.started_at) - .unwrap() - .as_secs() - ); - } } - } - - fn print_pending_unsigned_review(&self, zone: &ZoneStatus, policy: &PolicyInfo) { - if !policy.loader.review.required { + Some(finished_at) => { println!( - "{} Auto approving signing of {}, no checks enabled in policy.", + "{} Loaded {}", status_icon(true), serial_to_string(zone.unsigned_serial), ); - } else { - let done = *self > Progress::AtUnsignedReview; - let waiting_waited = match done { - true => "Waited", - false => "Waiting", - }; + + println!(" Loaded at {}", to_rfc3339_ago(report.finished_at)); + println!( - "{} {} for approval to sign {}", - status_icon(done), - waiting_waited, - serial_to_string(zone.unsigned_serial), + " {loaded_fetched} {} and {} from the {filesystem_network} in {} seconds", + format_size(report.byte_count, " ", "B"), + format_size(report.record_count, "", " records"), + finished_at + .duration_since(report.started_at) + .unwrap() + .as_secs() ); - if !done { - Self::print_review_hook(done, &policy.loader.review.cmd_hook, zone, true); - } - // TODO: When complete, show how long we waited. } } +} - fn print_waiting_to_sign(&self, zone: &ZoneStatus) { - println!( - "{} Approval received to sign {}, signing requested", - status_icon(*self > Progress::WaitingToSign), - serial_to_string(zone.unsigned_serial) - ); - } - - fn print_signing(&self, zone: &ZoneStatus) { - if *self >= Progress::Signed { - return; - } - +fn print_pending_unsigned_review(max: &Progress, zone: &ZoneStatus, policy: &PolicyInfo) { + if !policy.loader.review.required { println!( - "{} Signing {}", - status_icon(*self > Progress::Signing), - serial_to_string(zone.unsigned_serial) + "{} Auto approving signing of {}, no checks enabled in policy.", + status_icon(true), + serial_to_string(zone.unsigned_serial), ); - Self::print_signing_progress(zone); - } - - fn print_signed(&self, zone: &ZoneStatus, succeeded: bool) { - let (signed_failed, icon) = match succeeded { - true => ("Signed", status_icon(true)), - false => ( - "Signing failed", - format!("{}\u{78}{}", ansi::RED, ansi::RESET), - ), + } else { + let done = *max > Progress::AtUnsignedReview; + let waiting_waited = match done { + true => "Waited", + false => "Waiting", }; println!( - "{icon} {signed_failed} {} as {}", + "{} {} for approval to sign {}", + status_icon(done), + waiting_waited, serial_to_string(zone.unsigned_serial), - serial_to_string(zone.signed_serial) ); + if !done { + print_review_hook(done, &policy.loader.review.cmd_hook, zone, true); + } + // TODO: When complete, show how long we waited. + } +} - Self::print_signing_progress(zone); +fn print_waiting_to_sign(max: &Progress, zone: &ZoneStatus) { + println!( + "{} Approval received to sign {}, signing requested", + status_icon(*max > Progress::WaitingToSign), + serial_to_string(zone.unsigned_serial) + ); +} - if *self == Progress::Signed - && let Some(addr) = zone.signed_review_addr - { - println!(" Signed zone available on {addr}"); - } +fn print_signing(max: &Progress, zone: &ZoneStatus) { + if *max >= Progress::Signed { + return; } - fn print_pending_signed_review(&self, zone: &ZoneStatus, policy: &PolicyInfo) { - if !policy.signer.review.required { - println!( - "{} Auto approving publication of {}, no checks enabled in policy.", - status_icon(true), - serial_to_string(zone.signed_serial) - ); - } else { - let done = *self > Progress::AtSignedReview; - let waiting_waited = match done { - true => "Waited", - false => "Waiting", - }; - println!( - "{} {} for approval to publish {}", - status_icon(*self > Progress::AtSignedReview), - waiting_waited, - serial_to_string(zone.signed_serial), - ); - if !done { - Self::print_review_hook(done, &policy.signer.review.cmd_hook, zone, false); - } - } + println!( + "{} Signing {}", + status_icon(*max > Progress::Signing), + serial_to_string(zone.unsigned_serial) + ); + print_signing_progress(zone); +} + +fn print_signed(max: &Progress, zone: &ZoneStatus, succeeded: bool) { + let (signed_failed, icon) = match succeeded { + true => ("Signed", status_icon(true)), + false => ( + "Signing failed", + format!("{}\u{78}{}", ansi::RED, ansi::RESET), + ), + }; + println!( + "{icon} {signed_failed} {} as {}", + serial_to_string(zone.unsigned_serial), + serial_to_string(zone.signed_serial) + ); + + print_signing_progress(zone); + + if *max == Progress::Signed + && let Some(addr) = zone.signed_review_addr + { + println!(" Signed zone available on {addr}"); } +} - fn print_published(&self, zone: &ZoneStatus) { +fn print_pending_signed_review(max: &Progress, zone: &ZoneStatus, policy: &PolicyInfo) { + if !policy.signer.review.required { println!( - "{} Published {}", + "{} Auto approving publication of {}, no checks enabled in policy.", status_icon(true), - serial_to_string(zone.published_serial), + serial_to_string(zone.signed_serial) + ); + } else { + let done = *max > Progress::AtSignedReview; + let waiting_waited = match done { + true => "Waited", + false => "Waiting", + }; + println!( + "{} {} for approval to publish {}", + status_icon(*max > Progress::AtSignedReview), + waiting_waited, + serial_to_string(zone.signed_serial), ); - if *self == Progress::Published { - println!(" Published zone available on {}", zone.publish_addr); + if !done { + print_review_hook(done, &policy.signer.review.cmd_hook, zone, false); } } +} - fn print_review_hook(done: bool, cmd_hook: &Option, zone: &ZoneStatus, unsigned: bool) { - match cmd_hook { - Some(path) => println!(" Configured to invoke {path}"), - None => { - if !done { - let zone_name = &zone.name; - let (zone_type, zone_serial) = match unsigned { - true => ("unsigned", zone.unsigned_serial), - false => ("signed", zone.signed_serial), - }; - println!("\u{0021} Zone will be held until manually approved"); - if let Some(zone_serial) = zone_serial { - println!( - " Approve with: cascade zone approve --{zone_type} {zone_name} {zone_serial}" - ); - println!( - " Reject with: cascade zone reject --{zone_type} {zone_name} {zone_serial}" - ); - } - } else { - println!(" Zone was held until manually approved"); - } - } - } +fn print_published(max: &Progress, zone: &ZoneStatus) { + println!( + "{} Published {}", + status_icon(true), + serial_to_string(zone.published_serial), + ); + if *max == Progress::Published { + println!(" Published zone available on {}", zone.publish_addr); } +} - fn print_signing_progress(zone: &ZoneStatus) { - if let Some(report) = &zone.signing_report { - match &report.stage_report { - SigningStageReport::Requested(r) => { - println!( - " Signing requested at {}", - to_rfc3339_ago(Some(r.requested_at)) - ); - } - SigningStageReport::InProgress(r) => { +fn print_review_hook(done: bool, cmd_hook: &Option, zone: &ZoneStatus, unsigned: bool) { + match cmd_hook { + Some(path) => println!(" Configured to invoke {path}"), + None => { + if !done { + let zone_name = &zone.name; + let (zone_type, zone_serial) = match unsigned { + true => ("unsigned", zone.unsigned_serial), + false => ("signed", zone.signed_serial), + }; + println!("\u{0021} Zone will be held until manually approved"); + if let Some(zone_serial) = zone_serial { println!( - " Signing requested at {}", - to_rfc3339_ago(Some(r.requested_at)) + " Approve with: cascade zone approve --{zone_type} {zone_name} {zone_serial}" ); println!( - " Signing started at {}", - to_rfc3339_ago(Some(r.started_at)) + " Reject with: cascade zone reject --{zone_type} {zone_name} {zone_serial}" ); - if let (Some(unsigned_rr_count), Some(walk_time), Some(sort_time)) = - (r.unsigned_rr_count, r.walk_time, r.sort_time) - { - println!( - " Collected {} in {}, sorted in {}", - format_size(unsigned_rr_count, "", " records"), - format_duration(walk_time), - format_duration(sort_time) - ); - } - if let (Some(denial_rr_count), Some(denial_time)) = - (r.denial_rr_count, r.denial_time) - { - println!( - " Generated {} in {}", - format_size(denial_rr_count, "", " NSEC(3) records"), - format_duration(denial_time) - ); - } - if let (Some(rrsig_count), Some(rrsig_time)) = (r.rrsig_count, r.rrsig_time) { - println!( - " Generated {} in {} ({} sig/s)", - format_size(rrsig_count, "", " signatures"), - format_duration(rrsig_time), - rrsig_count / (rrsig_time.as_secs() as usize) - ); - } - if let Some(threads_used) = r.threads_used { - println!(" Using {threads_used} threads to generate signatures"); - } } - SigningStageReport::Finished(r) => { - println!( - " Signing requested at {}", - to_rfc3339_ago(Some(r.requested_at)) - ); - println!( - " Signing started at {}", - to_rfc3339_ago(Some(r.started_at)) - ); - println!( - " Signing finished at {}", - to_rfc3339_ago(Some(r.finished_at)) - ); + } else { + println!(" Zone was held until manually approved"); + } + } + } +} + +fn print_signing_progress(zone: &ZoneStatus) { + if let Some(report) = &zone.signing_report { + match &report.stage_report { + SigningStageReport::Requested(r) => { + println!( + " Signing requested at {}", + to_rfc3339_ago(Some(r.requested_at)) + ); + } + SigningStageReport::InProgress(r) => { + println!( + " Signing requested at {}", + to_rfc3339_ago(Some(r.requested_at)) + ); + println!( + " Signing started at {}", + to_rfc3339_ago(Some(r.started_at)) + ); + if let (Some(unsigned_rr_count), Some(walk_time), Some(sort_time)) = + (r.unsigned_rr_count, r.walk_time, r.sort_time) + { println!( " Collected {} in {}, sorted in {}", - format_size(r.unsigned_rr_count, "", " records"), - format_duration(r.walk_time), - format_duration(r.sort_time) + format_size(unsigned_rr_count, "", " records"), + format_duration(walk_time), + format_duration(sort_time) ); + } + if let (Some(denial_rr_count), Some(denial_time)) = + (r.denial_rr_count, r.denial_time) + { println!( " Generated {} in {}", - format_size(r.denial_rr_count, "", " NSEC(3) records"), - format_duration(r.denial_time) + format_size(denial_rr_count, "", " NSEC(3) records"), + format_duration(denial_time) ); + } + if let (Some(rrsig_count), Some(rrsig_time)) = (r.rrsig_count, r.rrsig_time) { println!( " Generated {} in {} ({} sig/s)", - format_size(r.rrsig_count, "", " signatures"), - format_duration(r.rrsig_time), - r.rrsig_count - .checked_div(r.rrsig_time.as_secs() as usize) - .unwrap_or(r.rrsig_count), - ); - println!( - " Took {} in total, using {} threads", - format_duration(r.total_time), - r.threads_used + format_size(rrsig_count, "", " signatures"), + format_duration(rrsig_time), + rrsig_count / (rrsig_time.as_secs() as usize) ); } + if let Some(threads_used) = r.threads_used { + println!(" Using {threads_used} threads to generate signatures"); + } + } + SigningStageReport::Finished(r) => { + println!( + " Signing requested at {}", + to_rfc3339_ago(Some(r.requested_at)) + ); + println!( + " Signing started at {}", + to_rfc3339_ago(Some(r.started_at)) + ); + println!( + " Signing finished at {}", + to_rfc3339_ago(Some(r.finished_at)) + ); + println!( + " Collected {} in {}, sorted in {}", + format_size(r.unsigned_rr_count, "", " records"), + format_duration(r.walk_time), + format_duration(r.sort_time) + ); + println!( + " Generated {} in {}", + format_size(r.denial_rr_count, "", " NSEC(3) records"), + format_duration(r.denial_time) + ); + println!( + " Generated {} in {} ({} sig/s)", + format_size(r.rrsig_count, "", " signatures"), + format_duration(r.rrsig_time), + r.rrsig_count + .checked_div(r.rrsig_time.as_secs() as usize) + .unwrap_or(r.rrsig_count), + ); + println!( + " Took {} in total, using {} threads", + format_duration(r.total_time), + r.threads_used + ); } - println!(" Current action: {}", report.current_action); } + println!(" Current action: {}", report.current_action); } } diff --git a/src/units/http_server.rs b/src/units/http_server.rs index 0e82b0dab..dbf89f638 100644 --- a/src/units/http_server.rs +++ b/src/units/http_server.rs @@ -18,7 +18,6 @@ use domain::base::Name; use domain::base::Rtype; use domain::base::Serial; use domain::base::Ttl; -use domain::base::iana::Class; use domain::dnssec::sign::keys::keyset::KeyType; use domain::rdata::Soa; use domain::zonetree::ReadableZone; @@ -52,6 +51,7 @@ use crate::units::zone_signer::KeySetState; use crate::zone::HistoricalEvent; use crate::zone::HistoricalEventType; use crate::zone::ZoneHandle; +use crate::zone::machine::ZoneStateMachine; pub const HTTP_UNIT_NAME: &str = "HS"; @@ -351,6 +351,10 @@ impl HttpServer { let signed_review_status; let zone; let halted_reason; + let progress; + let unsigned_serial; + let signed_serial; + let published_serial; { let locked_state = state.center.state.lock().unwrap(); let keys_dir = &state.center.config.keys_dir; @@ -427,24 +431,38 @@ impl HttpServer { when: item.when, } }); - } - // TODO: We need to show multiple versions here - let unsigned_zones = state.center.unsigned_zones.load(); - let signed_zones = state.center.signed_zones.load(); - let published_zones = state.center.published_zones.load(); - let unsigned_zone = unsigned_zones.get_zone(&name, Class::IN); - let signed_zone = signed_zones.get_zone(&name, Class::IN); - let published_zone = published_zones.get_zone(&name, Class::IN); - - // Determine the highest stage the zone has progressed to. - let stage = if published_zone.is_some() { - ZoneStage::Published - } else if signed_zone.is_some() { - ZoneStage::Signed - } else { - ZoneStage::Unsigned - }; + unsigned_serial = zone_state + .storage + .loaded_soa() + .map(|r| Serial::from(u32::from(r.rdata.serial))); + signed_serial = zone_state + .storage + .signed_soa() + .map(|r| Serial::from(u32::from(r.rdata.serial))); + published_serial = zone_state + .storage + .published_soa() + .map(|r| Serial::from(u32::from(r.rdata.serial))); + + progress = match zone_state.machine { + ZoneStateMachine::Waiting(..) => { + if published_serial.is_some() { + Progress::Published + } else { + Progress::WaitingForChanges + } + } + ZoneStateMachine::Loading(..) => Progress::ChangesReceived, + ZoneStateMachine::LoadedReview(..) => Progress::AtUnsignedReview, + ZoneStateMachine::HaltLoaded(..) => Progress::AtUnsignedReview, + ZoneStateMachine::Signing(..) => Progress::Signing, + ZoneStateMachine::SigningFailed(..) => Progress::SigningFailed, + ZoneStateMachine::SignedReview(..) => Progress::AtSignedReview, + ZoneStateMachine::HaltSigned(..) => Progress::AtSignedReview, + ZoneStateMachine::Poisoned => unreachable!(), + }; + } // Query key status let key_status = { @@ -517,7 +535,7 @@ impl HttpServer { } // Query signing status - let signing_report = if stage >= ZoneStage::Signed { + let signing_report = if progress >= Progress::Signed { let center = &state.center; center.signer.on_signing_report(&zone) } else { @@ -546,38 +564,11 @@ impl HttpServer { }) }; - // Query zone serials - let mut unsigned_serial = None; - if let Some(zone) = unsigned_zone - && let Ok(Some((soa, _ttl))) = read_soa(&*zone.read(), name.clone()).await - { - unsigned_serial = Some(soa.serial()); - } - let mut signed_serial = None; - if let Some(zone) = signed_zone - && let Ok(Some((soa, _ttl))) = read_soa(&*zone.read(), name.clone()).await - { - signed_serial = Some(soa.serial()); - } - let mut published_serial = None; - if let Some(zone) = published_zone - && let Ok(Some((soa, _ttl))) = read_soa(&*zone.read(), name.clone()).await - { - published_serial = Some(soa.serial()); - } - - // If the timing were unlucky we may have a published serial but not - // signed serial as the signed zone may have just been removed. Use - // the published serial as the signed serial in this case. - if signed_serial.is_none() && published_serial.is_some() { - signed_serial = published_serial; - } - Ok(ZoneStatus { name, source, policy, - stage, + progress, keys, key_status, receipt_report, diff --git a/src/zone/storage.rs b/src/zone/storage.rs index 428227dee..939b2c76a 100644 --- a/src/zone/storage.rs +++ b/src/zone/storage.rs @@ -28,7 +28,7 @@ use std::{fmt, sync::Arc}; use cascade_zonedata::{ LoadedZoneBuilder, LoadedZoneBuilt, LoadedZonePersister, LoadedZoneReader, LoadedZoneReviewer, SignedZoneBuilder, SignedZoneBuilt, SignedZonePersister, SignedZoneReader, SignedZoneReviewer, - ZoneCleaner, ZoneDataStorage, ZoneViewer, + SoaRecord, ZoneCleaner, ZoneDataStorage, ZoneViewer, }; use domain::zonetree; use tracing::{info, trace, trace_span, warn}; @@ -805,6 +805,21 @@ impl StorageState { background_tasks: Default::default(), } } + + pub fn loaded_soa(&self) -> Option<&SoaRecord> { + let loaded = self.loaded_reviewer.read_loaded()?; + Some(loaded.soa()) + } + + pub fn signed_soa(&self) -> Option<&SoaRecord> { + let signed = self.signed_reviewer.read()?; + Some(signed.soa()) + } + + pub fn published_soa(&self) -> Option<&SoaRecord> { + let published = self.viewer.read()?; + Some(published.soa()) + } } impl Default for StorageState {