Do not isolate a candidate against a stopped incumbent
prove_isolation compared the candidate's live process identity against the incumbent's identity as recorded at admission. When the incumbent has stopped, systemd has already released its DynamicUser UID and is free to hand that same UID to the candidate -- so identical values mean ordinary UID reuse, not a namespace collision, and fencing refused forever with "candidate and incumbent are not distinct by UID, PID namespace, and mount namespace". Isolation is a property of two processes running at once. When the admitted incumbent is permanently stopped there is nothing to be isolated from, so the comparison is skipped. is_permanently_stopped already exists on WorkloadPort for exactly this distinction. Found by deploying: odin's incumbent died mid-deployment, and every subsequent attempt to replace it was refused by this check. cargo test --locked -> test result: ok. 102 passed; 0 failed; 1 ignored Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
b7caaefb61
commit
8448f8355a
1 changed files with 11 additions and 2 deletions
|
|
@ -3551,8 +3551,17 @@ impl Engine {
|
|||
let now = now_millis()?;
|
||||
let snapshot = ControlSnapshot::read(&self.options.state_store)?;
|
||||
let incumbent = self.exact_incumbent(&snapshot, ¤t.value)?;
|
||||
let isolation =
|
||||
prove_isolation(workload, incumbent.map(|value| &value.value.workload))?;
|
||||
// Isolation is a property of two processes running at once. A
|
||||
// stopped incumbent has already released its DynamicUser UID, and
|
||||
// systemd is free to hand that same UID to the candidate -- so
|
||||
// comparing the candidate against the incumbent's *recorded*
|
||||
// identity turns ordinary UID reuse into a permanent refusal to
|
||||
// fence. There is nothing left to be isolated from.
|
||||
let incumbent_workload = match incumbent {
|
||||
Some(value) if self.workload.is_permanently_stopped(&value.value.workload)? => None,
|
||||
other => other.map(|value| &value.value.workload),
|
||||
};
|
||||
let isolation = prove_isolation(workload, incumbent_workload)?;
|
||||
return self.persist_same_phase(current, |next| {
|
||||
next.isolation = Some(isolation);
|
||||
next.updated_at_unix_millis = now;
|
||||
|
|
|
|||
Loading…
Reference in a new issue