From c0a367898c0f5edf2b24edbabb27f831e6ea7753 Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Tue, 14 Jul 2026 15:10:16 +0200 Subject: [PATCH 1/3] persist whether the zone is in maintenance mode --- src/zone/state/mod.rs | 2 ++ src/zone/state/v1.rs | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/src/zone/state/mod.rs b/src/zone/state/mod.rs index ac9be488..ef879655 100644 --- a/src/zone/state/mod.rs +++ b/src/zone/state/mod.rs @@ -85,6 +85,7 @@ impl Spec { match self { Self::V1(v1::Spec { policy, + maintenance_mode, instances, source, min_expiration, @@ -138,6 +139,7 @@ impl Spec { loader, history, persistence, + maintenance_mode, ..Default::default() }) } diff --git a/src/zone/state/v1.rs b/src/zone/state/v1.rs index 75c7e237..46c0c10b 100644 --- a/src/zone/state/v1.rs +++ b/src/zone/state/v1.rs @@ -47,6 +47,12 @@ pub struct Spec { /// version of the policy that is not yet in use. pub policy: Option, + /// Whether the zone is in maintenance mode + /// + /// Maintenance mode means that Cascade won't start loading and signing + /// operations automatically. + pub maintenance_mode: bool, + /// Instances of the zone. pub instances: InstancesSpec, @@ -122,6 +128,7 @@ impl Spec { pub fn build(zone: &ZoneState) -> Self { Self { policy: zone.policy.as_ref().map(|p| PolicySpec::build(p)), + maintenance_mode: zone.maintenance_mode, instances: InstancesSpec::build(&zone.instances), source: ZoneLoadSourceSpec::build(&zone.loader.source), min_expiration: zone.min_expiration, From dad161f140f798c22270b1c1ecb30a4ce41b32a1 Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Tue, 14 Jul 2026 15:10:16 +0200 Subject: [PATCH 2/3] update the checks in `start_pending` functions to take maintenance mode into account --- src/loader/zone.rs | 5 +++-- src/signer/zone.rs | 5 +++-- src/zone/machine.rs | 20 +++++--------------- src/zone/mod.rs | 8 ++++++++ src/zone/storage.rs | 2 +- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/loader/zone.rs b/src/loader/zone.rs index 02f878ac..0a61f64e 100644 --- a/src/loader/zone.rs +++ b/src/loader/zone.rs @@ -112,8 +112,9 @@ impl LoaderZoneHandle<'_> { /// Start a pending enqueued refresh. /// /// This should be called when the zone data storage is in the passive - /// state. If a load has been enqueued, it will be initiated (making the - /// data storage busy), and `true` will be returned. + /// state and the zone is not in maintenance mode. If a load has been + /// enqueued, it will be initiated (making the data storage busy), and + /// `true` will be returned. /// /// ## Panics /// diff --git a/src/signer/zone.rs b/src/signer/zone.rs index 203217b2..1f76a0d8 100644 --- a/src/signer/zone.rs +++ b/src/signer/zone.rs @@ -261,8 +261,9 @@ impl SignerZoneHandle<'_> { /// Start a pending enqueued re-sign. /// /// This should be called when the zone state machine is in the waiting - /// state. If a re-sign has been enqueued, it will be initiated (making the - /// data storage busy), and `true` will be returned. + /// state and the zone is not in maintenance mode. If a re-sign has been + /// enqueued, it will be initiated (making the data storage busy), and + /// `true` will be returned. /// /// This method cannot initiate enqueued new-signing operations (see /// [`Self::enqueue_new_sign()`]); when a new-signing operation is enqueued, diff --git a/src/zone/machine.rs b/src/zone/machine.rs index eba6a825..15bf690d 100644 --- a/src/zone/machine.rs +++ b/src/zone/machine.rs @@ -104,14 +104,10 @@ impl ZoneStateMachine { /// # Initiating operations impl<'a> ZoneHandle<'a> { pub(crate) fn try_start_load(&mut self) -> Option { - // If we're in maintenance mode, then we don't start this operation. - // TODO: distinguish between a manual load and an automatic one. - if self.state.maintenance_mode { - return None; - } - - let ZoneStateMachine::Waiting(_) = &self.state.machine else { - info!("Could not start load since an operation is in progress on the zone."); + if !self.state.ready_for_operation() { + info!( + "Could not start load since an operation is in progress on the zone or the zone is in maintenance mode." + ); return None; }; @@ -138,13 +134,7 @@ impl<'a> ZoneHandle<'a> { } pub(crate) fn try_start_resign(&mut self) -> Option { - // If we're in maintenance mode, then we don't start this operation. - // TODO: distinguish between a manual resign and an automatic one. - if self.state.maintenance_mode { - return None; - } - - let ZoneStateMachine::Waiting(_) = &self.state.machine else { + if !self.state.ready_for_operation() { info!("Could not start load since an operation is in progress on the zone."); return None; }; diff --git a/src/zone/mod.rs b/src/zone/mod.rs index 6bfc2937..93dca2fd 100644 --- a/src/zone/mod.rs +++ b/src/zone/mod.rs @@ -424,6 +424,14 @@ impl ZoneState { .rev() .find(|item| item.event.is_of_type(typ) && (serial.is_none() || item.serial == serial)) } + + /// Whether the zone state is ready to start a new loading or signing operation + /// + /// This checks the maintenance mode and the zone state machine. + pub fn ready_for_operation(&self) -> bool { + // TODO: distinguish between a manual load/sign and an automatic one. + !self.maintenance_mode && matches!(&self.machine, ZoneStateMachine::Waiting(_)) + } } impl Default for ZoneState { diff --git a/src/zone/storage.rs b/src/zone/storage.rs index 9763fd6e..ca66bd95 100644 --- a/src/zone/storage.rs +++ b/src/zone/storage.rs @@ -798,7 +798,7 @@ impl StorageZoneHandle<'_> { // loading a new instance. // Ensure a new operation can be started. - let ZoneStateMachine::Waiting(_) = &self.state.machine else { + if !self.state.ready_for_operation() { trace!("Ignoring `on_passive()` because the pipeline is busy"); return; }; From 300ffc0403522b7ff8515cd04b69c0927191a9dc Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Wed, 15 Jul 2026 14:55:37 +0200 Subject: [PATCH 3/3] Remove unused import --- src/zone/storage.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zone/storage.rs b/src/zone/storage.rs index ca66bd95..d2f45bb0 100644 --- a/src/zone/storage.rs +++ b/src/zone/storage.rs @@ -38,7 +38,7 @@ use crate::{ persistence::zone::IxfrZoneDiffs, server::{LoadedReviewServer, PublicationServer, SignedReviewServer}, util::BackgroundTasks, - zone::{Zone, ZoneHandle, ZoneState, machine::ZoneStateMachine}, + zone::{Zone, ZoneHandle, ZoneState}, }; //----------- StorageZoneHandle ------------------------------------------------