Remove an adopted node's guard and openings last on the flip, and keep them if anything failed (hq ADR 0103)
This commit is contained in:
+28
-3
@@ -114,7 +114,9 @@ func (e *Error) Unwrap() error { return e.Err }
|
||||
// Removal happens FIRST, and the order is not arbitrary. A resource that leaves a declaration
|
||||
// while another arrives at the same path is an ordinary rename: removing afterwards would
|
||||
// delete the file that had just been written. Removing first risks losing the old state if the
|
||||
// apply then fails — a recovery concern, where the other is a correctness one.
|
||||
// apply then fails — a recovery concern, where the other is a correctness one. The one exception
|
||||
// is what protects an adopted node, the openings and the guard: that goes last, and only when
|
||||
// everything else applied (novox/hq ADR 0103).
|
||||
func Apply(
|
||||
ctx context.Context,
|
||||
sys system.System,
|
||||
@@ -159,7 +161,7 @@ func ApplyKeeping(
|
||||
return report, known, &Error{Resource: "the firewall found on this machine", Err: err, Done: report}
|
||||
}
|
||||
|
||||
for _, orphan := range known.Orphans(declared, origin) {
|
||||
removeOrphan := func(orphan store.Applied) error {
|
||||
var action, detail string
|
||||
var err error
|
||||
if declaration.Type(orphan.Type) == declaration.TypeOpening {
|
||||
@@ -168,7 +170,7 @@ func ApplyKeeping(
|
||||
action, detail, err = remove(ctx, sys, orphan, run)
|
||||
}
|
||||
if err != nil {
|
||||
return report, known, &Error{Resource: orphan.ID, Err: err, Done: report}
|
||||
return &Error{Resource: orphan.ID, Err: err, Done: report}
|
||||
}
|
||||
known.Forget(orphan.ID)
|
||||
report.Outcomes = append(report.Outcomes, Outcome{
|
||||
@@ -176,6 +178,24 @@ func ApplyKeeping(
|
||||
Action: action, Detail: detail,
|
||||
})
|
||||
log(fmt.Sprintf(" %s %s (%s)", action, orphan.ID, orphan.Target))
|
||||
return nil
|
||||
}
|
||||
|
||||
// **What protects an adopted node goes last** (novox/hq ADR 0103). The openings and the guard
|
||||
// are what keep the mesh reachable through the found firewall and the store unreachable from
|
||||
// outside. When a node is converged they leave the declaration, and removing them first would
|
||||
// leave the store open from the moment the guard stops until the derived filter loads — and
|
||||
// for ever, if the filter then fails. So they are removed only once everything else applied
|
||||
// and the found firewall is retired; if anything failed, they stay, recorded, for the next try.
|
||||
var protecting []store.Applied
|
||||
for _, orphan := range known.Orphans(declared, origin) {
|
||||
if strings.HasPrefix(orphan.ID, declaration.AdoptionPrefix) {
|
||||
protecting = append(protecting, orphan)
|
||||
continue
|
||||
}
|
||||
if err := removeOrphan(orphan); err != nil {
|
||||
return report, known, err
|
||||
}
|
||||
}
|
||||
|
||||
// What moved in this apply, so a service that must reflect a file can be told the file
|
||||
@@ -321,6 +341,11 @@ func ApplyKeeping(
|
||||
if err := retireFirewall(ctx, d, origin, &known, run, log); err != nil {
|
||||
return report, known, &Error{Resource: "the firewall found on this machine", Err: err, Done: report}
|
||||
}
|
||||
for _, orphan := range protecting {
|
||||
if err := removeOrphan(orphan); err != nil {
|
||||
return report, known, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(failures) > 0 {
|
||||
|
||||
Reference in New Issue
Block a user