Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/loader/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ async fn refresh(
unreachable!("source-specific loading succeeded and must have filled 'builder'")
});

handle.finish_load(built);
handle.finish_load(built, soa.rdata.serial);
}

Err(err) => {
Expand Down
144 changes: 132 additions & 12 deletions src/server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@

use std::{fmt, sync::Arc};

use cascade_api::{ZoneReviewDecision, ZoneReviewResult};
use cascade_zonedata::{LoadedZoneReviewer, SignedZoneReviewer, ZoneViewer};
use domain::base::Serial;
use tracing::{debug, error, info};

use crate::{
center::Center,
daemon::SocketProvider,
manager::Terminated,
units::zone_server::{Source, ZoneServer},
util::AbortOnDrop,
zone::Zone,
zone::{UpcomingInstance, Zone, ZoneHandle, machine::ZoneStateMachine},
};

mod request;
Expand Down Expand Up @@ -62,15 +62,75 @@ impl LoadedReviewServer {
ZoneServer::new(Source::Unsigned).on_seek_approval_for_zone(center, zone, zone_serial)
}

/// Process a review of a served instance.
/// Process a review of the upcoming loaded instance.
#[tracing::instrument(
level = "trace",
skip_all,
fields(zone = %zone.name, r#type = "loaded", zone_serial, ?decision)
)]
pub fn process_review(
center: &Arc<Center>,
zone: &Arc<Zone>,
zone_serial: Serial,
decision: ZoneReviewDecision,
) -> ZoneReviewResult {
// TODO: Inline.
ZoneServer::new(Source::Unsigned).on_zone_review(center, zone, zone_serial, decision)
decision: cascade_api::ZoneReviewDecision,
) -> cascade_api::ZoneReviewResult {
let mut state = zone.state.lock().unwrap();
let mut handle = ZoneHandle {
zone,
state: &mut state,
center,
};

// Ensure the zone is in loader review.
let ZoneStateMachine::LoadedReview(machine) = &mut handle.state.machine else {
debug!("The zone is not in loaded-review state");

return Err(cascade_api::ZoneReviewError::NotUnderReview);
};
if machine.decided {
debug!("The instance has already been reviewed");

return Err(cascade_api::ZoneReviewError::NotUnderReview);
}

// Look up the upcoming instance.
let Some(UpcomingInstance {
loaded: Some(loaded),
signed: None,
}) = &handle.state.instances.upcoming
else {
unreachable!("'UpcomingInstance' is inconsistent with 'LoadedReview'")
};

// Ensure the serial number is correct.
if Serial(loaded.serial.into()) != zone_serial {
debug!(
"The upcoming loaded instance has serial '{}', not '{zone_serial}'",
loaded.serial
);

return Err(cascade_api::ZoneReviewError::NotUnderReview);
}

// Remember that a review has been received.
machine.decided = true;

match decision {
cascade_api::ZoneReviewDecision::Approve => {
info!("Approving the upcoming loaded instance");

handle.approve_loaded();
}

cascade_api::ZoneReviewDecision::Reject => {
error!("Rejecting the upcoming loaded instance");

// TODO: Whether to soft or hard reject should be part of the policy
handle.hard_reject_loaded();
}
}

Ok(cascade_api::ZoneReviewOutput {})
}

/// Register a new zone.
Expand Down Expand Up @@ -151,15 +211,75 @@ impl SignedReviewServer {
ZoneServer::new(Source::Signed).on_seek_approval_for_zone(center, zone, zone_serial)
}

/// Process a review of a served instance.
/// Process a review of the upcoming signed instance.
#[tracing::instrument(
level = "trace",
skip_all,
fields(zone = %zone.name, r#type = "signed", zone_serial, ?decision)
)]
pub fn process_review(
center: &Arc<Center>,
zone: &Arc<Zone>,
zone_serial: Serial,
decision: ZoneReviewDecision,
) -> ZoneReviewResult {
// TODO: Inline.
ZoneServer::new(Source::Signed).on_zone_review(center, zone, zone_serial, decision)
decision: cascade_api::ZoneReviewDecision,
) -> cascade_api::ZoneReviewResult {
let mut state = zone.state.lock().unwrap();
let mut handle = ZoneHandle {
zone,
state: &mut state,
center,
};

// Ensure the zone is in signer review.
let ZoneStateMachine::SignedReview(machine) = &mut handle.state.machine else {
debug!("The zone is not in signed-review state");

return Err(cascade_api::ZoneReviewError::NotUnderReview);
};
if machine.decided {
debug!("The instance has already been reviewed");

return Err(cascade_api::ZoneReviewError::NotUnderReview);
}

// Look up the upcoming instance.
let Some(UpcomingInstance {
loaded: _,
signed: Some(signed),
}) = &handle.state.instances.upcoming
else {
unreachable!("'UpcomingInstance' is inconsistent with 'LoadedReview'")
};

// Ensure the serial number is correct.
if Serial(signed.serial.into()) != zone_serial {
debug!(
"The upcoming signed instance has serial '{}', not '{zone_serial}'",
signed.serial
);

return Err(cascade_api::ZoneReviewError::NotUnderReview);
}

// Remember that a review has been received.
machine.decided = true;

match decision {
cascade_api::ZoneReviewDecision::Approve => {
info!("Approving the upcoming signed instance");

handle.approve_signed();
}

cascade_api::ZoneReviewDecision::Reject => {
error!("Rejecting the upcoming signed instance");

// TODO: Whether to soft or hard reject should be part of the policy
handle.hard_reject_signed();
}
}

Ok(cascade_api::ZoneReviewOutput {})
}

/// Register a new zone.
Expand Down
12 changes: 10 additions & 2 deletions src/signer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use std::{
};

use cascade_zonedata::SignedZoneBuilder;
use tracing::error;
use tracing::{debug, error};

use crate::units::zone_signer::SignerError;
use crate::{
Expand Down Expand Up @@ -85,8 +85,16 @@ async fn sign(

match result {
Ok(()) => {
let soa = builder.next_signed().unwrap().soa().clone();

debug!(
zone = %zone.name,
serial = ?soa.rdata.serial,
"Generated a new signed instance of the zone"
);

let built = builder.finish().unwrap_or_else(|_| unreachable!());
handle.finish_signing(built);
handle.finish_signing(built, soa.rdata.serial);
status.status.finish(true);
status.current_action = "Finished".to_string();
}
Expand Down
32 changes: 15 additions & 17 deletions src/units/http_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -438,21 +438,18 @@ impl HttpServer {
}
});

unsigned_serial = zone_state
.storage
.loaded_review_soa
.as_ref()
.map(|r| Serial::from(u32::from(r.rdata.serial)));
signed_serial = zone_state
.storage
.signed_review_soa
.as_ref()
.map(|r| Serial::from(u32::from(r.rdata.serial)));
let upcoming = zone_state.instances.upcoming.as_ref();
unsigned_serial = upcoming
.and_then(|i| i.loaded.as_ref())
.map(|i| Serial(u32::from(i.serial)));
signed_serial = upcoming
.and_then(|i| i.signed.as_ref())
.map(|i| Serial(u32::from(i.serial)));
published_serial = zone_state
.storage
.published_soa
.instances
.current
.as_ref()
.map(|r| Serial::from(u32::from(r.rdata.serial)));
.map(|i| Serial(u32::from(i.signed.serial)));

progress = match zone_state.machine {
ZoneStateMachine::Waiting(..) => Progress::Waiting,
Expand All @@ -467,11 +464,12 @@ impl HttpServer {
};

last_published = zone_state
.last_published
.instances
.current
.as_ref()
.map(|p| LastPublishedZone {
loaded_serial: p.loaded_serial,
signed_serial: p.signed_serial,
.map(|i| LastPublishedZone {
loaded_serial: Serial(i.loaded.serial.into()),
signed_serial: Serial(i.signed.serial.into()),
});

let mut found_error = None;
Expand Down
Loading
Loading