Compose foreground sandbox process lifetimes
This commit is contained in:
parent
3171c41399
commit
fd78804fc7
1 changed files with 2313 additions and 7 deletions
179
crates/lazaret-host-coordinator/src/runtime/tests.rs
Normal file
179
crates/lazaret-host-coordinator/src/runtime/tests.rs
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
use std::fs::{File, OpenOptions};
|
||||
use std::path::Path;
|
||||
|
||||
use lazaret_core::identity::{
|
||||
BootId, ConfigurationFingerprint, CoordinatorId, DomainId, HostPidLocator, NetworkSidecarId,
|
||||
PidfsDeviceId, PidfsInodeId, PidfsProcessAuthorityV1, ProcessStartTimeTicks, SandboxId,
|
||||
};
|
||||
use lazaret_core::records::{Domain, DurableDecision, Generation};
|
||||
use lazaret_linux::filesystem::try_exclusive_flock;
|
||||
use tempfile::TempDir;
|
||||
|
||||
use super::*;
|
||||
|
||||
fn bytes(value: u8) -> [u8; 32] {
|
||||
[value; 32]
|
||||
}
|
||||
|
||||
fn process(value: u32) -> PidfsProcessIdentityV1 {
|
||||
PidfsProcessIdentityV1::new(
|
||||
PidfsProcessAuthorityV1 {
|
||||
boot_id: BootId::new([1; 16]),
|
||||
pidfs_st_dev: PidfsDeviceId::new(u64::from(value)),
|
||||
pidfs_st_ino: PidfsInodeId::new(u64::from(value) + 100),
|
||||
},
|
||||
HostPidLocator::new(value),
|
||||
ProcessStartTimeTicks::new(u64::from(value) + 200),
|
||||
)
|
||||
}
|
||||
|
||||
fn domain() -> Domain {
|
||||
Domain {
|
||||
domain_id: DomainId::new(bytes(1)),
|
||||
profile_name: "trusted".into(),
|
||||
canonical_workspace: HostPath::new(b"/workspace/project".to_vec()),
|
||||
}
|
||||
}
|
||||
|
||||
fn generation() -> Generation {
|
||||
Generation {
|
||||
domain_id: domain().domain_id,
|
||||
generation_id: GenerationId::new(7),
|
||||
configuration_fingerprint: ConfigurationFingerprint::new(bytes(2)),
|
||||
coordinator_id: CoordinatorId::new(bytes(3)),
|
||||
network_sidecar_id: NetworkSidecarId::new(bytes(4)),
|
||||
sandbox_id: SandboxId::new(bytes(5)),
|
||||
durable_decision: DurableDecision::None,
|
||||
}
|
||||
}
|
||||
|
||||
fn lock_file(path: &Path) -> File {
|
||||
OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create(true)
|
||||
.truncate(false)
|
||||
.open(path)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn store(directory: &TempDir) -> HostCoordinatorDomainStore {
|
||||
let lock = try_exclusive_flock(lock_file(&directory.path().join("domain.lock"))).unwrap();
|
||||
let store =
|
||||
HostCoordinatorDomainStore::open(lock, &directory.path().join("domain.redb"), &domain())
|
||||
.unwrap();
|
||||
store
|
||||
.apply(&[DomainStoreMutation::PutGeneration(generation())])
|
||||
.unwrap();
|
||||
store
|
||||
}
|
||||
|
||||
fn staged(
|
||||
slot: HostProcessOwnershipSlot,
|
||||
identity: PidfsProcessIdentityV1,
|
||||
) -> StagedProcessOwnership {
|
||||
StagedProcessOwnership::v1(
|
||||
domain().domain_id,
|
||||
generation().generation_id,
|
||||
generation().coordinator_id,
|
||||
slot,
|
||||
identity,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sandbox_staging_readiness_and_release_preserve_exact_ownership() {
|
||||
let directory = tempfile::tempdir().unwrap();
|
||||
let store = store(&directory);
|
||||
let coordinator = SandboxCoordinator::new(&store);
|
||||
coordinator
|
||||
.begin_intent(
|
||||
generation().generation_id,
|
||||
ContainerId::new(bytes(6)),
|
||||
directory.path(),
|
||||
BundleDigest::new(bytes(7)),
|
||||
process(100),
|
||||
)
|
||||
.unwrap();
|
||||
let rs = staged(
|
||||
HostProcessOwnershipSlot::SandboxRuntimeSupervisor,
|
||||
process(101),
|
||||
);
|
||||
coordinator.stage_runtime_supervisor(rs).unwrap();
|
||||
assert!(
|
||||
coordinator
|
||||
.acknowledge_runtime_supervisor(rs)
|
||||
.unwrap()
|
||||
.acknowledges(&rs)
|
||||
);
|
||||
let runsc = staged(HostProcessOwnershipSlot::SandboxAttachedRunsc, process(102));
|
||||
assert!(
|
||||
coordinator
|
||||
.stage_attached_runsc(runsc)
|
||||
.unwrap()
|
||||
.acknowledges(&runsc)
|
||||
);
|
||||
let intent = coordinator.participant(generation().generation_id).unwrap();
|
||||
let Some(ParticipantOwnership::Sandbox(ownership)) = intent.ownership() else {
|
||||
panic!("Sandbox ownership missing");
|
||||
};
|
||||
assert_eq!(intent.state(), ParticipantState::Intent);
|
||||
assert_eq!(
|
||||
ownership.runtime_supervisor,
|
||||
PersistedHostProcessOwnership::committed(process(101))
|
||||
);
|
||||
assert_eq!(
|
||||
ownership.attached_runsc,
|
||||
PersistedHostProcessOwnership::staged(process(102))
|
||||
);
|
||||
coordinator.commit_ready(runsc).unwrap();
|
||||
assert_eq!(
|
||||
coordinator
|
||||
.participant(generation().generation_id)
|
||||
.unwrap()
|
||||
.state(),
|
||||
ParticipantState::Committed
|
||||
);
|
||||
coordinator
|
||||
.begin_release(generation().generation_id)
|
||||
.unwrap();
|
||||
coordinator
|
||||
.complete_clean_after_absence(generation().generation_id)
|
||||
.unwrap();
|
||||
let clean = coordinator.participant(generation().generation_id).unwrap();
|
||||
assert_eq!(clean.state(), ParticipantState::Clean);
|
||||
assert!(clean.ownership().unwrap().is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mismatched_and_skipped_acquisition_boundaries_refuse_without_state_change() {
|
||||
let directory = tempfile::tempdir().unwrap();
|
||||
let store = store(&directory);
|
||||
let coordinator = SandboxCoordinator::new(&store);
|
||||
coordinator
|
||||
.begin_intent(
|
||||
generation().generation_id,
|
||||
ContainerId::new(bytes(6)),
|
||||
directory.path(),
|
||||
BundleDigest::new(bytes(7)),
|
||||
process(100),
|
||||
)
|
||||
.unwrap();
|
||||
let runsc = staged(HostProcessOwnershipSlot::SandboxAttachedRunsc, process(102));
|
||||
assert!(coordinator.stage_attached_runsc(runsc).is_err());
|
||||
assert!(coordinator.commit_ready(runsc).is_err());
|
||||
let wrong_domain = StagedProcessOwnership::v1(
|
||||
DomainId::new(bytes(9)),
|
||||
generation().generation_id,
|
||||
generation().coordinator_id,
|
||||
HostProcessOwnershipSlot::SandboxRuntimeSupervisor,
|
||||
process(101),
|
||||
);
|
||||
assert!(coordinator.stage_runtime_supervisor(wrong_domain).is_err());
|
||||
let participant = coordinator.participant(generation().generation_id).unwrap();
|
||||
let Some(ParticipantOwnership::Sandbox(ownership)) = participant.ownership() else {
|
||||
panic!("Sandbox ownership missing");
|
||||
};
|
||||
assert!(ownership.runtime_supervisor.is_unassigned());
|
||||
assert!(ownership.attached_runsc.is_unassigned());
|
||||
}
|
||||
Loading…
Reference in a new issue