controller v0.178.0 — R-88 Part 2: only a positive 'never' fires the valve
MinAgent: 0.105.0. scheduledRunAllowed fired on any nil age; it now requires a licence from valveLicensed, which grants it for AgeStateAbsent and for a LEGACY agent, and refuses it for AgeStateUnknown. An unreadable storage no longer masquerades as a first-ever backup and no longer quiesces apps outside the window. A missing wire field means legacy, not unknown — deliberately. Treating it as unknown would stop the valve firing on un-upgraded boxes and starve genuinely new ones. Degrade logged once; unrecognised future values also map to legacy. Caught in passing: TieredBackend is satisfied by a RUNTIME assertion, so the signature change compiled and vetted clean while quiesceBackend silently stopped satisfying it — which would have degraded every box to the single-tier path with no error. Added a compile-time witness. Also corrects the notifier comment that claimed operator-only came from a missing customerMessages entry; enforcement is hub-side operatorOnlyEvents (hub 0.79.0).
This commit is contained in:
@@ -174,6 +174,14 @@ type DueResponse struct {
|
||||
Due bool `json:"due"`
|
||||
Reason string `json:"reason"`
|
||||
AgeSecs *int64 `json:"age_seconds"`
|
||||
// AgeState (R-88 Part 2, agent >= v0.105.0) says WHY AgeSecs is nil: "absent" (a positive
|
||||
// determination that no backup has ever landed) or "unknown" (the agent could not tell —
|
||||
// unreadable storage, unparseable timestamp). "known" accompanies a real age.
|
||||
//
|
||||
// EMPTY MEANS LEGACY — an agent older than v0.105.0 simply omits the field. It does NOT mean
|
||||
// "unknown", and the distinction is load-bearing: see quiesce.ageStateFromWire. Never
|
||||
// discriminate on Reason instead; those strings are operator copy and will drift.
|
||||
AgeState string `json:"age_state"`
|
||||
}
|
||||
|
||||
// BackupResponse mirrors the agent's POST /backup payload.
|
||||
|
||||
@@ -29,6 +29,12 @@ const FeatureNetstorageVerify Feature = "netstorage_verify"
|
||||
// (GET/POST /guest/memory) shipped together, so GET /guest/memory IS the capability signal.
|
||||
const FeatureGuestMemoryResize Feature = "guest_memory_resize"
|
||||
|
||||
// FeatureBackupAgeState is R-88 Part 2 (agent v0.105.0): GET /backup/due carries `age_state`,
|
||||
// distinguishing "never backed up" (absent) from "could not tell" (unknown). There is no route
|
||||
// probe for it — the signal is a FIELD on an existing route, so the version floor is the gate and
|
||||
// an empty field means legacy.
|
||||
const FeatureBackupAgeState Feature = "backup_age_state"
|
||||
|
||||
// SupportState is a probe verdict. The zero value is SupportUnknown (fail-open: unknown never
|
||||
// refuses — the existing agent-error paths speak honestly when the agent is down).
|
||||
type SupportState int
|
||||
@@ -99,6 +105,8 @@ var errNoMemoryProbe = errors.New("agentapi: prober does not support the guest-m
|
||||
var featureMinAgent = map[Feature]string{
|
||||
FeatureNetstorageVerify: "0.81.0",
|
||||
FeatureGuestMemoryResize: "0.90.0",
|
||||
// R-88 Part 2: /backup/due carries age_state, distinguishing "never backed up" from "cannot tell".
|
||||
FeatureBackupAgeState: "0.105.0",
|
||||
}
|
||||
|
||||
// AgentVersionReporter is optionally implemented by a SupportProber (*Client is one): it reports
|
||||
|
||||
Reference in New Issue
Block a user