Explain active Domain maintenance contention

This commit is contained in:
ms2k 2026-07-21 22:41:46 +09:00
commit b288e77ed0
2 changed files with 38 additions and 1 deletions

View file

@ -50,7 +50,13 @@ pub fn run_command(command: StateCommand) -> Result<i32, Box<dyn std::error::Err
return Err("reset target is not an exact configured persistent container path".into()); return Err("reset target is not an exact configured persistent container path".into());
} }
let root = configuration.persistent_domain_root().open_authority()?; let root = configuration.persistent_domain_root().open_authority()?;
let lock = try_exclusive_flock(open_private_domain_lock(&root)?)?; let lock = match try_exclusive_flock(open_private_domain_lock(&root)?) {
Ok(lock) => lock,
Err(error) if error.kind() == io::ErrorKind::WouldBlock => {
return Err("Domain state is busy; exit active Lazaret sessions or wait for another maintenance command to finish, then retry".into());
}
Err(error) => return Err(error.into()),
};
let database = match openat2( let database = match openat2(
root.as_fd(), root.as_fd(),
"domain.redb", "domain.redb",

View file

@ -1,5 +1,7 @@
use std::fs; use std::fs;
use lazaret_linux::filesystem::try_exclusive_flock;
#[allow(clippy::disallowed_methods, clippy::disallowed_types)] #[allow(clippy::disallowed_methods, clippy::disallowed_types)]
#[test] #[test]
fn machine_and_human_discovery_are_versioned_and_content_free() { fn machine_and_human_discovery_are_versioned_and_content_free() {
@ -42,6 +44,35 @@ fn reset_refuses_an_arbitrary_container_or_host_path_before_state_access() {
); );
} }
#[allow(clippy::disallowed_methods, clippy::disallowed_types)]
#[test]
fn active_domain_reports_actionable_maintenance_contention() {
let fixture = Fixture::new();
assert!(fixture.command("list").output().unwrap().status.success());
let lock = try_exclusive_flock(
fs::OpenOptions::new()
.read(true)
.write(true)
.open(fixture.domain_root().join("domain.lock"))
.unwrap(),
)
.unwrap();
let active = fixture.command("verify").output().unwrap();
assert!(!active.status.success());
assert!(String::from_utf8_lossy(&active.stderr).contains(
"Domain state is busy; exit active Lazaret sessions or wait for another maintenance command to finish, then retry"
));
drop(lock);
let inactive = fixture.command("verify").output().unwrap();
assert!(
inactive.status.success(),
"{}",
String::from_utf8_lossy(&inactive.stderr)
);
}
#[allow(clippy::disallowed_methods, clippy::disallowed_types)] #[allow(clippy::disallowed_methods, clippy::disallowed_types)]
#[test] #[test]
fn missing_store_succeeds_only_when_the_complete_state_anchor_is_absent() { fn missing_store_succeeds_only_when_the_complete_state_anchor_is_absent() {