use std::io; use std::process::ExitCode; use lazaret_core::identity::{ ConfigurationFingerprint, CoordinatorId, DomainId, GenerationId, NetworkSidecarId, SandboxId, }; use lazaret_core::records::{ DurableDecision, Generation, Participant, ParticipantOwnership, ParticipantRole, ParticipantState, PersistedHostProcessOwnership, StateAnchorOwnership, }; use lazaret_host_coordinator::recovery::{prove_runtime_owners_absent, runtime_recovery_ownership}; use lazaret_linux::process::{TargetCommand, child_broker, dispatch_private_process_role}; use rustix::process::Signal; fn main() -> ExitCode { let arguments = std::env::args_os().skip(1).collect::>(); if let Some(result) = dispatch_private_process_role(&arguments) { return exit(result); } exit(run()) } fn exit(result: io::Result<()>) -> ExitCode { match result { Ok(()) => ExitCode::SUCCESS, Err(error) => { eprintln!("recovery process test failed: {error}"); ExitCode::FAILURE } } } fn run() -> io::Result<()> { verify_exact_action(None)?; verify_exact_action(Some(Signal::STOP)) } fn verify_exact_action(signal: Option) -> io::Result<()> { let captured = child_broker().run_transient_captured(&TargetCommand::new("/bin/sleep").argument("60"))?; if let Some(signal) = signal { captured.process().send_signal(signal)?; } let process = captured.into_process(); let generation = generation(); let participants = [ Participant::bare_intent(generation.generation_id, ParticipantRole::PreparedLower), Participant::snapshot( generation.generation_id, ParticipantRole::StateAnchor, ParticipantState::Intent, Some(ParticipantOwnership::StateAnchor(StateAnchorOwnership { lower_artifact_id: None, upper_path: None, work_path: None, merged_path: None, daemon: PersistedHostProcessOwnership::staged(process.identity()), user_namespace: None, mount_namespace: None, mount: None, })), ) .map_err(|_| io::Error::other("State Anchor participant is invalid"))?, ]; let ownership = runtime_recovery_ownership(&participants, &generation).map_err(io::Error::other)?; prove_runtime_owners_absent(&ownership)?; child_broker().reap(process) } fn generation() -> Generation { Generation { domain_id: DomainId::new([1; 32]), generation_id: GenerationId::new(1), configuration_fingerprint: ConfigurationFingerprint::new([2; 32]), coordinator_id: CoordinatorId::new([3; 32]), network_sidecar_id: NetworkSidecarId::new([4; 32]), sandbox_id: SandboxId::new([5; 32]), durable_decision: DurableDecision::Preparing, } }