fix(patching): final review fixes
- no dispatch in the last 15 minutes of a window; no-result timeout from dispatch time - per-server output moves to patch_run_outputs (16MB document limit) - reboot proven by a changed boot time; RebootTimeout 45m, ResultGrace 20m - window update and delete are server-scoped against the policies using them - scheduler puts the claim back on an error after it, so the next tick retries - cancelled runs with failures alert; MCP apply_updates audits per server - apply-updates 503 body documented; openapi regenerated - web: cleared numeric fields no longer save as 0; Run now asks for confirmation
This commit is contained in:
@@ -96,18 +96,18 @@ func process(ctx context.Context, deps Deps, p models.PatchPolicy, now time.Time
|
||||
|
||||
n, err := deps.CountTargets(p)
|
||||
if err != nil {
|
||||
recordSkip(ctx, deps, p, "error: "+err.Error(), due, now)
|
||||
retryLater(ctx, deps, p, err, due, next, now)
|
||||
return
|
||||
}
|
||||
active, err := hasActiveRun(ctx, p)
|
||||
if err != nil {
|
||||
recordSkip(ctx, deps, p, "error: "+err.Error(), due, now)
|
||||
retryLater(ctx, deps, p, err, due, next, now)
|
||||
return
|
||||
}
|
||||
switch d := Decide(due, end, now, active, n); d {
|
||||
case Fire:
|
||||
if err := deps.StartPolicyRun(p, end); err != nil {
|
||||
recordSkip(ctx, deps, p, "error: "+err.Error(), due, now)
|
||||
retryLater(ctx, deps, p, err, due, next, now)
|
||||
return
|
||||
}
|
||||
_, _ = db.Col("patch_policies").UpdateOne(ctx, bson.M{"policy_id": p.PolicyID},
|
||||
@@ -130,6 +130,19 @@ func hasActiveRun(ctx context.Context, p models.PatchPolicy) (bool, error) {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// retryLater handles an error after the claim. The claim is put back, guarded
|
||||
// on the value just written so a concurrent edit to the policy is not undone,
|
||||
// and the next tick retries the same occurrence. Decide's missed rule bounds
|
||||
// the retries: once the occurrence is too late it is skipped as missed.
|
||||
func retryLater(ctx context.Context, deps Deps, p models.PatchPolicy, cause error, due, next, now time.Time) {
|
||||
if _, err := db.Col("patch_policies").UpdateOne(ctx,
|
||||
bson.M{"policy_id": p.PolicyID, "next_run_at": next},
|
||||
bson.M{"$set": bson.M{"next_run_at": due}}); err != nil {
|
||||
log.Printf("patchsched: policy %s: put back claim: %v", p.PolicyID, err)
|
||||
}
|
||||
recordSkip(ctx, deps, p, "error: "+cause.Error(), due, now)
|
||||
}
|
||||
|
||||
func recordSkip(ctx context.Context, deps Deps, p models.PatchPolicy, reason string, due, at time.Time) {
|
||||
_, _ = db.Col("patch_policies").UpdateOne(ctx, bson.M{"policy_id": p.PolicyID},
|
||||
bson.M{"$set": bson.M{"last_skipped": models.Skip{Reason: reason, Due: due, At: at}}})
|
||||
|
||||
Reference in New Issue
Block a user