Enforce exact recovery ownership before cold start

This commit is contained in:
ms2k 2026-07-17 06:48:49 +09:00
commit 2bc5982a62

View file

@ -7,7 +7,10 @@ use lazaret_core::configuration::ResolvedDomainConfiguration;
use lazaret_core::identity::{BundleDigest, ContainerId, MountIdentity};
use lazaret_core::network::{CanonicalDerivedNetworkPolicy, ReachabilityExpectation};
use lazaret_core::records::Session;
use lazaret_core::records::{Generation, GenerationIdentity, PreparedArtifact};
use lazaret_core::records::{
Generation, GenerationIdentity, Participant, ParticipantOwnership, ParticipantRole,
ParticipantState, PreparedArtifact,
};
use lazaret_linux::process::current_process_identity;
use lazaret_runtime_supervisor::network::NetworkProbeRequest;
use lazaret_runtime_supervisor::sandbox::SandboxBundle;
@ -20,7 +23,7 @@ use crate::control::{
ControlError, NonInteractiveSessionExecutor, PublishedControlFace, SessionRegistry,
StagedControlFace, TrustAnchor,
};
use crate::domain_store::HostCoordinatorDomainStore;
use crate::domain_store::{DomainStoreMutation, HostCoordinatorDomainStore};
use crate::lifecycle::{
HostCoordinatorLifecycle, LifecycleAction, LifecycleAdapter, SessionAdmissionIdentity,
SessionLifecycleAdapter,
@ -240,6 +243,10 @@ impl<'a> ProductionLifecycleAdapter<'a> {
self.plan.generation_identity.generation_id,
self.plan.container_id,
&self.plan.runtime_root,
self.plan
.runtime_staging
.runsc_root_identity()
.map_err(failure)?,
self.plan.bundle_digest,
current_process_identity().map_err(failure)?,
)
@ -347,36 +354,105 @@ impl<'a> ProductionLifecycleAdapter<'a> {
.trust_anchor
.take()
.ok_or_else(|| ProductionLifecycleError("Trust Anchor is absent".into()))?;
self.staged_control = Some(
StagedControlFace::stage_with_executor(
path_from_host(
self.plan
.configuration
.runtime_domain_root()
.canonical_label()
.as_bytes(),
),
self.plan.invoking_uid,
anchor,
Arc::clone(&self.registry),
Arc::clone(&self.plan.non_interactive_executor),
)
.map_err(failure)?,
);
let generation_id = self.plan.generation_identity.generation_id;
self.plan
.store
.apply(&[DomainStoreMutation::PutParticipant(
Participant::bare_intent(generation_id, ParticipantRole::Publication),
)])
.map_err(failure)?;
let staged = StagedControlFace::stage_with_executor(
path_from_host(
self.plan
.configuration
.runtime_domain_root()
.canonical_label()
.as_bytes(),
),
self.plan.invoking_uid,
anchor,
Arc::clone(&self.registry),
Arc::clone(&self.plan.non_interactive_executor),
)
.map_err(failure)?;
let ownership = staged.recovery_ownership().map_err(failure)?;
self.plan
.store
.apply(&[DomainStoreMutation::PutParticipant(
Participant::snapshot(
generation_id,
ParticipantRole::Publication,
ParticipantState::Intent,
Some(ParticipantOwnership::Publication(ownership)),
)
.map_err(failure)?,
)])
.map_err(failure)?;
self.staged_control = Some(staged);
Ok(())
}
fn expose_publication(&mut self) -> Result<(), ProductionLifecycleError> {
self.published_control = Some(Arc::new(
self.staged_control
.take()
.ok_or_else(|| ProductionLifecycleError("staged control face is absent".into()))?
.expose()
let published = self
.staged_control
.take()
.ok_or_else(|| ProductionLifecycleError("staged control face is absent".into()))?
.expose()
.map_err(failure)?;
let ownership = published.recovery_ownership().map_err(failure)?;
self.plan
.store
.apply(&[DomainStoreMutation::PutParticipant(
Participant::snapshot(
self.plan.generation_identity.generation_id,
ParticipantRole::Publication,
ParticipantState::Committed,
Some(ParticipantOwnership::Publication(ownership)),
)
.map_err(failure)?,
));
)])
.map_err(failure)?;
self.published_control = Some(Arc::new(published));
Ok(())
}
fn clean_publication_after_withdrawal(&self) -> Result<(), ProductionLifecycleError> {
let generation_id = self.plan.generation_identity.generation_id;
let current = self
.plan
.store
.snapshot()
.map_err(failure)?
.participants
.into_iter()
.find(|participant| {
participant.generation_id() == generation_id
&& participant.role() == ParticipantRole::Publication
})
.ok_or_else(|| ProductionLifecycleError("Publication participant is absent".into()))?;
let release = Participant::snapshot(
generation_id,
ParticipantRole::Publication,
ParticipantState::ReleaseIntent,
current.ownership().cloned(),
)
.map_err(failure)?;
let clean = Participant::snapshot(
generation_id,
ParticipantRole::Publication,
ParticipantState::Clean,
Some(ParticipantOwnership::empty(ParticipantRole::Publication)),
)
.map_err(failure)?;
self.plan
.store
.apply(&[
DomainStoreMutation::PutParticipant(release),
DomainStoreMutation::CleanParticipantAfterAbsence(clean),
])
.map_err(failure)
}
fn stop_sandbox(&mut self) -> Result<(), ProductionLifecycleError> {
let store = Arc::clone(&self.plan.store);
let sandbox = SandboxCoordinator::new(&store);
@ -517,6 +593,7 @@ impl LifecycleAdapter for ProductionLifecycleAdapter<'_> {
LifecycleAction::BeginTeardown => {
if let Some(control) = self.published_control.as_ref() {
control.withdraw().map_err(failure)?;
self.clean_publication_after_withdrawal()?;
}
self.published_control.take();
Ok(())