Cluster¶
Cluster wide operations¶
A cluster can only ever run a single cluster wide operation at a time. Currently, two such operations exist:
update, triggered withPOST /1.0/provisioning/clusters/{name}/:update, which performs a rolling update of OS and applications.reboot, triggered withPOST /1.0/provisioning/clusters/{name}/:reboot, which performs a rolling reboot of all servers.
Whichever operation is currently ongoing is canceled with
POST /1.0/provisioning/clusters/{name}/:cancel-operation.
Both operations share the same state machine, which is described in the following sections.
Rolling Update¶
The rolling update process is tracked by a combination of the server state and the cluster update in progress state and follows the following flow diagram:
flowchart TD
TriggerUpdate[trigger update]@{ shape: circle }
StatusUpdate[server status event]@{ shape: circle }
UpdateMonitor[update monitor interval]@{ shape: circle }
Abort[abort]
Abort@{ shape: circle }
UpdateOngoing{update ongoing?}
RefreshServersTriggerUpdate[refresh all servers]
ClusterReady{is cluster ready?}
TriggerAppUpdate[trigger app update]
AppUpdateRequired{app update required?}
SetClusterUpdateInProgressStatus[set 'cluster update in progress status']
TargetStateFromDB[target state from DB]
OSUpdateDone{OS update done?}
CleanupDB[cleanup update state from DB]
End@{ shape: stop }
NextAction[calculate next action]
NextActionAllowed{next action allowed?}
TriggerNextAction[trigger next action, update DB state]
RefreshServersFromEvent[refresh all servers]
UpdateOngoingFromEvent{update ongoing?}
ForEachCluster[for each cluster do]
TriggerUpdate --> UpdateOngoing
UpdateOngoing -->|Yes| End
UpdateOngoing -->|No| RefreshServersTriggerUpdate
RefreshServersTriggerUpdate --> ClusterReady
ClusterReady -->|No| End
ClusterReady -->|Yes| AppUpdateRequired
AppUpdateRequired -->|No| SetClusterUpdateInProgressStatus
AppUpdateRequired -->|Yes| TriggerAppUpdate
TriggerAppUpdate --> AppUpdateRequired
SetClusterUpdateInProgressStatus --> TargetStateFromDB
OSUpdateDone -->|Yes| CleanupDB
CleanupDB --> End
OSUpdateDone -->|No| NextAction
NextAction --> NextActionAllowed
NextActionAllowed -->|No| End
NextActionAllowed -->|Yes| TriggerNextAction
TriggerNextAction --> End
StatusUpdate -----> TargetStateFromDB
TargetStateFromDB --> UpdateOngoingFromEvent
UpdateOngoingFromEvent -->|No| End
UpdateOngoingFromEvent -->|Yes| RefreshServersFromEvent
RefreshServersFromEvent --> OSUpdateDone
UpdateMonitor ----> ForEachCluster
ForEachCluster --> TargetStateFromDB
Abort -----------> CleanupDB
On-demand Rolling Reboot¶
A rolling reboot reboots every server of a cluster, one at a time, independently of whether an update is pending. It is meant for reboots, which Operations Center can not derive from the state reported by IncusOS, e.g. after a firmware update.
It is triggered with POST /1.0/provisioning/clusters/{name}/:reboot and, being
a cluster wide operation like the rolling update, is canceled with
POST /1.0/provisioning/clusters/{name}/:cancel-operation.
Reusing the rolling restart¶
The rolling reboot does not have a control loop of its own. It sets the cluster
update in progress status to rolling reboot and is then driven by
executeRollingRestartNextStep, the same one-server-at-a-time loop, that performs
the restart phase of a rolling update. It therefore enters the state machine at
evacuation pending and skips the two leading update steps, which is why a
rolling reboot has 7 steps per server instead of the 9 steps of a rolling update
with reboot.
Synthesizing the need for a reboot¶
The loop is driven entirely by api.Server.UpdateState, which derives the state
of a server from Status, StatusDetail and VersionData. With no pending
update, VersionData.NeedsReboot is false for every server, so all servers report
up to date and the cycle would end immediately.
ClusterUpdateInProgressStatus.PendingReboot therefore holds the list of servers,
which still have to be rebooted. It is populated with all servers of the cluster
when the reboot is launched, and serverUpdateStateForRollingUpdate reports
NeedsReboot = true for every server on that list. Pending updates are reported
as absent for the whole run, so a newly published update can not interrupt the
cycle, exactly as during a rolling restart.
A server is removed from PendingReboot as soon as its reboot has been triggered.
Preconditions and side effects¶
On top of the checks a rolling update performs, a rolling reboot additionally
requires that no server is busy (StatusDetail is empty). This is checked at
launch time, so the user gets to see the reason.
Servers, which have been evacuated manually before the reboot was launched, are rebooted as well, but are left in the evacuated state afterwards, the same as during a rolling update.
Rebooting a server applies an IncusOS update, that has already been staged on it. This is unavoidable, since the staged image is what the server boots.