Upgrade Runs
Upgrade Runs represent the execution of an Upgrade Plan. Each Upgrade Run references an Upgrade Plan and tracks the progress of upgrading resources according to the plan's rollout groups.
Upgrade Runs are cluster-scoped resources. They can be created by SKE when an Upgrade Plan's execution policy triggers, but they can also be created manually.
An Upgrade Run looks like this:
apiVersion: platform.syntasso.io/v1alpha1
kind: UpgradeRun
metadata:
name: redis-v1-to-v2-run-001
spec:
upgradePlanRef:
# Name of the UpgradePlan this run executes. Immutable after creation.
name: redis-v1-to-v2
# Set to true to pause execution. Defaults to false.
suspend: false
Upgrade Plan Reference
The upgradePlanRef field references the Upgrade Plan that this run executes. This field is immutable: once set, it
cannot be changed.
spec:
upgradePlanRef:
name: redis-v1-to-v2
When the referenced Upgrade Plan exists, the Upgrade Run will resolve the plan and begin execution.
If the plan does not exist, the Upgrade Run will set a PlanResolved condition with status False and reason PlanNotFound.
A run that starts before its plan exists can still resolve later if the plan appears.
Suspending an Upgrade Run
You can pause an in-progress Upgrade Run by setting suspend to true:
spec:
suspend: true
Setting suspend back to false resumes execution. This allows you to temporarily halt an upgrade without deleting the
run.
Suspending a run does not pause the health timeout of resources that are already waiting to pass their health checks.
Previewing an upgrade before it runs
You can review exactly which resources an Upgrade Run will touch before any of them are upgraded by creating the run suspended:
apiVersion: platform.syntasso.io/v1alpha1
kind: UpgradeRun
metadata:
name: redis-v1-to-v2-preview
spec:
upgradePlanRef:
name: redis-v1-to-v2
suspend: true
A run created with suspend: true still takes its snapshot of eligible resources and writes the
snapshot ConfigMap, but it does not patch any Resource Bindings. This gives you a stable, per-rollout-group list of what
the run set out to change, without changing anything.
Once you are happy with the snapshot, set suspend back to false to let the run proceed. If you decide not to go
ahead, delete the run; the snapshot ConfigMap is cleaned up with it.
Superseded runs
When an Upgrade Plan is on a schedule and the next trigger fires while a run is still Pending or InProgress, SKE does
not start a second run alongside the first. It supersedes the active run instead:
- The active run is patched with
spec.suspend: true, so it stops starting new resource upgrades. - Its
status.supersededByis set to the name of the new run. - The new run starts in its place.
This keeps a single run rolling out at a time for a given plan, even when a schedule fires during a long-running upgrade.
How an UpgradeRun executes
When an UpgradeRun starts, it:
- Takes a snapshot of all Resource Bindings for the Promise that are on an eligible
fromversion. The snapshot records each resource's version at the moment the run begins. This baseline is used throughout the run to detect drift. - Waits for the target PromiseRevision to exist before the snapshot is finalised. If the target Promise Revision is not yet available, the run requeues until it appears.
- Processes rollout groups in plan order. For each group, it patches the
spec.versionon each matching Resource Binding to the target version and waits for Kratix to apply the upgrade. In a group withsuccessCriteria: healthCheck, it also waits for each resource to pass its health checks at the target version. Only once every resource in the current group is accounted for does the run move to the next group.
Resource Outcomes
When a run processes a rollout group, each snapshotted resource is evaluated against its current live state. Because the run re-checks bindings on every reconcile cycle, resources can change between when the snapshot was taken and when their group is reached.
In every group, a resource's outcome first depends on its Resource Configure workflow (the Pipelines column). In a
group with successCriteria: healthCheck, a resource whose workflow has run at the
target version is then evaluated on its health checks (the Health checks column).
| Outcome | Pipelines | Health checks |
|---|---|---|
| Succeeded | The binding's lastAppliedVersion equals the target version. This includes resources that were already applied at the target version by the time their group was reached. | The binding's HealthChecksSucceeded condition is True at the target version. |
| Skipped | The binding no longer exists (resource was deleted), or the resource was upgraded to a different version externally. | Not applicable. |
| Failed | Kratix reported an upgrade failure on the binding (UpgradeSucceeded=False) during the current run. The failure is part of the current run when the condition's lastTransitionTime is at or after the Upgrade Run's creationTimestamp. | The binding's HealthChecksSucceeded condition is False with reason Unhealthy at the target version. A resource that has not passed its health checks within the group's healthTimeout also fails. |
| Pending | The binding has been patched to the target version but Kratix has not yet applied it. | The binding has reached the target version and is waiting to pass its health checks. It is counted in the group's awaitingHealth. |
If the binding is already at the target spec.version and the only upgrade failure was recorded before this Upgrade Run
was created, the run treats that failure as the result of an earlier run. The resource stays Pending and Kratix tries to reconcile the resource again.
Skipped resources count towards group completion and do not block the run from advancing to the next group. Upgrade failures recorded before the Upgrade Run was created do not fail the current run. When a resource fails, subsequent groups are not processed, and how the current group ends depends on the kind of failure:
- Resource Configure workflow failure (
UpgradeSucceeded=False): the rest of the group finishes, then the run fails with reasonResourceUpgradeFailed. - Health check failure or health timeout (
healthCheckgroups only): the group and the run fail in the same reconcile, with reasonHealthCheckFailedorHealthTimeoutExceeded. No further resource is started. Resources already in flight are left where they are, and there is no rollback.
Identifying a failed resource
The RunSucceeded condition and the rollout group status tell you how many resources failed and in which group, but not which specific resource. When a resource fails to upgrade, the run records a Kubernetes Event against the Upgrade Run naming the offending resource. Inspect the run's events to find it:
$ kubectl describe upgraderun redis-v1-to-v2-run-001
Name: redis-v1-to-v2-run-001
Namespace:
Labels: <none>
API Version: platform.syntasso.io/v1alpha1
Kind: UpgradeRun
Metadata:
Creation Timestamp: 2026-07-01T15:54:32Z
Finalizers:
platform.syntasso.io/upgraderun
Generation: 1
Owner References:
API Version: platform.syntasso.io/v1alpha1
Block Owner Deletion: true
Controller: true
Kind: UpgradePlan
Name: redis-v1-to-v2
UID: 98b582ba-e1e7-40bb-af7d-86ce0f31e18a
Resource Version: 10042
UID: c89f8ed6-7387-48c4-aad2-9db38b72444d
Spec:
Upgrade Plan Ref:
Name: redis-v1-to-v2
Status:
Completed Resources: 2
Conditions:
Last Transition Time: 2026-07-01T15:54:32Z
Message: UpgradePlan "redis-v1-to-v2" found
Reason: PlanFound
Status: True
Type: PlanResolved
Last Transition Time: 2026-07-01T15:54:33Z
Message: PromiseRevision for promise "redis" version "v2.0.0" is ready
Reason: PromiseRevisionReady
Status: True
Type: TargetRevisionReady
Last Transition Time: 2026-07-01T16:00:46Z
Message: 1 resource(s) failed to upgrade in rollout group "dev"
Reason: ResourceUpgradeFailed
Status: False
Type: RunSucceeded
Finished At: 2026-07-01T16:00:46Z
Resource List Refs:
Name: redis-v1-to-v2-run-001-resource-snapshot
Rollout Groups:
Failed: 1
Name: dev
Skipped: 0
Succeeded: 2
Total: 3
Failed: 0
Name: staging
Skipped: 0
Succeeded: 0
Total: 2
State: Failed
Total Resources: 5
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal GroupInProgress 9m21s (x2 over 9m21s) UpgradeRunController Group "dev": 0/3 resources upgraded to v2.0.0
Warning ResourceUpgradeFailed 3m28s UpgradeRunController Resource default/dev-r2 failed to upgrade to v2.0.0: upgrade gate denied
Normal GroupInProgress 3m28s (x2 over 3m28s) UpgradeRunController Group "dev": 1/3 resources upgraded to v2.0.0
Warning ResourceUpgradeFailed 3m28s UpgradeRunController Resource default/dev-r2 failed to upgrade to v2.0.0: upgrade gate denied
Normal GroupInProgress 3m23s (x2 over 3m23s) UpgradeRunController Group "dev": 1/3 resources upgraded to v2.0.0
Warning ResourceUpgradeFailed 3m7s UpgradeRunController Resource default/dev-r2 failed to upgrade to v2.0.0: upgrade gate denied
Warning UpgradeRunFailed 3m7s UpgradeRunController 2/5 resources upgraded to v2.0.0
The Events section at the end of the output identifies the resource that caused the group to fail.
In a group with successCriteria: healthCheck, a resource that fails its health
checks or exceeds its health timeout is reported with one of these Warning events instead:
| Reason | Message |
|---|---|
HealthCheckFailed | Resource <namespace>/<name> failed its health checks at <version>: <condition message> |
HealthTimeoutExceeded | Resource <namespace>/<name> did not pass its health checks at <version> within <duration> |
Drift Detection
The snapshot records each resource's version at run start. If, by the time the run processes a resource, its version has been changed externally, the resource is Skipped rather than overwritten:
- A resource upgraded to a version other than the target (e.g.
v3.0.0when the target isv2.0.0) is skipped. - A resource with
lastAppliedVersionalready at the target version is not patched. In a group that does not setsuccessCriteria: healthCheck, it is counted as Succeeded immediately. In ahealthCheckgroup, it is evaluated on its health checks at the target version, like any other resource that has reached the target version. - A resource with
spec.versionalready at the target version, but withlastAppliedVersionstill behind, remains Pending. If its only upgrade failure was recorded before the current run was created, the run adds the manual reconciliation label to the Resource Binding so Kratix retries the Resource Configure workflow.
PromiseRevision Gate
The run checks that the target Promise Revision exists at two points, with different behaviour each time:
Before the snapshot is taken: if the target PromiseRevision does not yet exist, the run requeues and waits. No failure is recorded. This handles the case where the revision is still being created when the run starts.
Once the snapshot exists and the rollout is underway: if the PromiseRevision is deleted, the run transitions immediately to Failed with reason PromiseRevisionNotFound. Resources that have not yet been patched remain on their current version.
Status
The Upgrade Run status tracks the progress of the upgrade across all rollout groups.
status:
# Overall execution state: (empty), Pending, InProgress, Completed, Failed, or Cancelled.
state: InProgress
# Total number of resources across all rollout groups.
totalResources: 10
# Resources successfully upgraded so far (sum of each group's succeeded; excludes skipped and failed).
completedResources: 3
# References to ConfigMaps containing the snapshot of resources to be upgraded.
resourceListRefs:
- name: redis-v1-to-v2-run-001-resource-snapshot
rolloutGroups:
- name: dev
# Total resources in this group.
total: 5
# Resources successfully upgraded.
succeeded: 3
# Resources that failed to upgrade.
failed: 1
# Resources that were skipped.
skipped: 1
- name: staging
total: 5
succeeded: 0
failed: 0
skipped: 0
conditions:
- type: PlanResolved
status: "True"
reason: PlanFound
- type: RunSucceeded
status: "False"
reason: ResourceUpgradeFailed
message: "1 resource(s) failed to upgrade in rollout group \"dev\""
State
The state field reflects the overall execution state of the run:
| State | Meaning |
|---|---|
| (empty) | Waiting for the referenced Upgrade Plan or the target PromiseRevision to be available |
Pending | Run is active but rollout has not started. Counts as active on the parent plan (phase: Running). The controller typically leaves this empty until the snapshot is created, then sets InProgress. |
InProgress | Snapshot created, rollout underway |
Completed | All rollout groups finished successfully |
Failed | A resource reported an upgrade failure, a resource in a healthCheck group failed its health checks or exceeded its health timeout, or the target PromiseRevision was deleted mid-run |
Cancelled | The run was deleted while still in progress |
Once a run reaches Completed, Failed, or Cancelled it is terminal. It will not be reconciled further. The controller sets finishedAt at that point.
When a run becomes terminal, the controller records a summary on the parent Upgrade Plan in status.lastRun.
Resource Snapshot
When an Upgrade Run begins, it records a snapshot of every resource it will upgrade, grouped by rollout group, in a
ConfigMap in the kratix-platform-system namespace. Because the snapshot is written at the start of the run and does not
change as the upgrade proceeds, it gives you an auditable record of exactly which resources a run is upgrading. You can
use it to review the scope of an upgrade before it proceeds (see
Previewing an upgrade before it runs) and to confirm afterwards what was in
scope. The Managing Promise Upgrades guide walks through this workflow.
The resourceListRefs field on the run's status lists the ConfigMaps that hold the snapshot. In practice this is a
single ConfigMap. Read it from the kratix-platform-system namespace:
kubectl -n kratix-platform-system get configmap <snapshot-name> -o yaml
Each entry records the resource's namespace and name, the version captured at snapshot time (lastAppliedVersion), and
its spec.version (specVersion). These versions also form the baseline used for drift detection.
{
"groups": [
{
"name": "dev",
"resources": [
{
"namespace": "team-a",
"name": "r1",
"lastAppliedVersion": "v1",
"specVersion": "v1"
}
]
}
]
}
Rollout Group Status
Each entry in groups summarises the upgrade progress of a single rollout group:
| Field | Description |
|---|---|
name | Name of the rollout group |
total | Total number of resources in this group |
succeeded | Number of resources successfully upgraded |
failed | Number of resources that failed to upgrade |
skipped | Number of resources that were skipped |
awaitingHealth | Number of resources that have reached the target version and are waiting to pass their health checks (successCriteria: healthCheck groups only) |
Conditions
The Upgrade Run reports its state via standard Kubernetes conditions:
| Condition | Status | Reason | Description |
|---|---|---|---|
PlanResolved | True | absent | The referenced Upgrade Plan exists |
PlanResolved | False | PlanNotFound | The referenced Upgrade Plan does not exist |
RunSucceeded | True | RunCompleted | All rollout groups completed successfully |
RunSucceeded | False | ResourceUpgradeFailed | A resource's Resource Configure workflow failed |
RunSucceeded | False | HealthCheckFailed | A resource in a healthCheck group failed its health checks |
RunSucceeded | False | HealthTimeoutExceeded | A resource in a healthCheck group did not pass its health checks within healthTimeout |
RunSucceeded | False | PromiseRevisionNotFound | The target revision was deleted mid-run |
RunSucceeded | False | RunCancelled | The run was deleted while in progress |
Manually Creating an Upgrade Run
Upgrade Runs are typically created automatically by the system when an Upgrade Plan's execution policy triggers (via
repeatSchedule or executeAt). You can also create one manually to trigger an immediate upgrade:
kubectl apply -f - <<EOF
apiVersion: platform.syntasso.io/v1alpha1
kind: UpgradeRun
metadata:
name: redis-v1-to-v2-manual-run
spec:
upgradePlanRef:
name: redis-v1-to-v2
EOF
Deleting an Upgrade Run
When an Upgrade Run that is still in progress is deleted, the controller marks it Cancelled, records the outcome on the parent Upgrade Plan's status.lastRun, and then removes the associated resource snapshot ConfigMap.
When a terminal run is deleted, the snapshot ConfigMap is cleaned up automatically. The plan's lastRun summary is not removed.
