Maintenance Flow
The Maintenance controller computes the lifecycle phase of each maintenance window and triggers automatic phase transitions using strategic requeue timing.
Overview
flowchart TD
Maint["Maintenance CR\n(scheduledStart, scheduledEnd)"] --> Chain["Maintenance Controller\n(Chain of Responsibility)"]
Chain --> Status["Maintenance CR Status\n(phase: upcoming/in_progress/completed)"]
Chain --> Store["MaintenanceStore\n(in-memory ReadStore)"]
Chain -->|"enqueue affected\nComponent CRs"| CompCtrl["Component Controller"]
Store --> API["Connect gRPC API / MCP"]
API --> UI["Web UI\n(Status page)"]
Trigger
Watch-based: triggers on create/update/delete of Maintenance CRs. No fixed polling interval — the controller uses strategic RequeueAfter to wake up exactly when the phase transitions.
Chain of Responsibility
flowchart TD
Start([Reconcile]) --> H1
H1["① ComputePhase\nValidate schedule (end > start)\nCompute phase from current time\n→ upcoming / in_progress / completed"] --> H2
H2["② UpdateStatus\nPatch status.phase + Ready condition\nRe-fetch for fresh resourceVersion\nAdd sreportal.io/portal label\nProject to MaintenanceWriter\nSet RequeueAfter for next transition"] --> Done([Done])
Step 1 — ComputePhase
Uses the domain function maintenance.ComputePhase(now, scheduledStart, scheduledEnd):
Now < scheduledStart → upcoming
scheduledStart ≤ Now ≤ scheduledEnd → in_progress
Now > scheduledEnd → completedValidation: if scheduledEnd ≤ scheduledStart, the handler returns ErrInvalidSchedule and the chain stops.
Step 2 — UpdateStatus
- Patches
status.phaseandReady=Truecondition viastatusutil.SetConditionAndPatch() - Re-fetches the CR for a fresh
resourceVersion - Adds
sreportal.io/portallabel - Projects
MaintenanceViewto theMaintenanceWriter - Computes and sets
RequeueAfterfor the next phase transition
Strategic RequeueAfter
Instead of polling at a fixed interval, the controller computes the exact duration until the next phase change using the domain function maintenance.ComputeRequeue():
flowchart LR
subgraph Upcoming
direction LR
A["Created"] -->|"RequeueAfter =\nscheduledStart - Now"| B["scheduledStart"]
end
subgraph InProgress
direction LR
B -->|"RequeueAfter =\nscheduledEnd - Now"| C["scheduledEnd"]
end
subgraph Completed
direction LR
C -->|"No requeue\n(final state)"| D["Done"]
end
| Current Phase | RequeueAfter | Purpose |
|---|---|---|
upcoming | scheduledStart - Now | Transition to in_progress |
in_progress | scheduledEnd - Now | Transition to completed |
completed | 0 (no requeue) | Terminal state |
This ensures zero-delay transitions with no wasted reconciliations.
Impact on Components
When a Maintenance CR changes, the Component controller is also triggered:
- The
ComponentReconcilerwatches Maintenance CRs viahandler.EnqueueRequestsFromMapFunc - Each component listed in
maintenance.spec.components[]is re-enqueued - The Component controller reads from the
MaintenanceReaderto check if the component is under active maintenance - If yes,
computedStatusis overridden tomaintenance.spec.affectedStatus
Domain Types
Maintenance CR (spec.scheduledStart, scheduledEnd)
│
▼ ComputePhase(now, start, end) → MaintenancePhase
MaintenancePhase (status.phase in etcd)
│
▼
MaintenanceView (ReadStore, in-memory)
│
▼
proto MaintenanceResource (on the wire)