Skip to content

Commit 386018b

Browse files
Merge pull request #1276 from wking/Upgradeable-blocks-major-too
OTA-1787: pkg: Update Upgradeable condition to explicitly mention major version updates
2 parents 79e4015 + 07c1bb8 commit 386018b

6 files changed

Lines changed: 53 additions & 33 deletions

File tree

install/0000_90_cluster-version-operator_02_servicemonitor.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ spec:
8787
rules:
8888
- alert: ClusterNotUpgradeable
8989
annotations:
90-
summary: One or more cluster operators have been blocking minor version cluster upgrades for at least an hour.
90+
summary: One or more cluster operators have been blocking minor or major version cluster updates for at least an hour.
9191
description: In most cases, you will still be able to apply patch releases. Reason {{ "{{ with $cluster_operator_conditions := \"cluster_operator_conditions\" | query}}{{range $value := .}}{{if and (eq (label \"name\" $value) \"version\") (eq (label \"condition\" $value) \"Upgradeable\") (eq (label \"endpoint\" $value) \"metrics\") (eq (value $value) 0.0) (ne (len (label \"reason\" $value)) 0) }}{{label \"reason\" $value}}.{{end}}{{end}}{{end}}"}} For more information refer to 'oc adm upgrade'{{ "{{ with $console_url := \"console_url\" | query }}{{ if ne (len (label \"url\" (first $console_url ) ) ) 0}} or {{ label \"url\" (first $console_url ) }}/settings/cluster/{{ end }}{{ end }}" }}.
9292
expr: |
9393
max by (namespace, name, condition, endpoint) (cluster_operator_conditions{name="version", condition="Upgradeable", endpoint="metrics"} == 0)

pkg/cvo/cvo_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2929,7 +2929,7 @@ func TestOperator_upgradeableSync(t *testing.T) {
29292929
Type: configv1.OperatorUpgradeable,
29302930
Status: configv1.ConditionFalse,
29312931
Reason: "RandomReason",
2932-
Message: "Cluster operator default-operator-1 should not be upgraded between minor versions: some random reason why upgrades are not safe.",
2932+
Message: "Cluster operator default-operator-1 should not be upgraded between minor or major versions: some random reason why upgrades are not safe.",
29332933
}},
29342934
},
29352935
},
@@ -2990,7 +2990,7 @@ func TestOperator_upgradeableSync(t *testing.T) {
29902990
Type: configv1.OperatorUpgradeable,
29912991
Status: configv1.ConditionFalse,
29922992
Reason: "RandomReason",
2993-
Message: "Cluster operator default-operator-1 should not be upgraded between minor versions: some random reason why upgrades are not safe.",
2993+
Message: "Cluster operator default-operator-1 should not be upgraded between minor or major versions: some random reason why upgrades are not safe.",
29942994
}},
29952995
},
29962996
},
@@ -3054,7 +3054,7 @@ func TestOperator_upgradeableSync(t *testing.T) {
30543054
Type: configv1.OperatorUpgradeable,
30553055
Status: configv1.ConditionFalse,
30563056
Reason: "RandomReason",
3057-
Message: "Cluster operator default-operator-1 should not be upgraded between minor versions: some random reason why upgrades are not safe.",
3057+
Message: "Cluster operator default-operator-1 should not be upgraded between minor or major versions: some random reason why upgrades are not safe.",
30583058
}},
30593059
},
30603060
},
@@ -3120,7 +3120,7 @@ func TestOperator_upgradeableSync(t *testing.T) {
31203120
Type: configv1.OperatorUpgradeable,
31213121
Status: configv1.ConditionFalse,
31223122
Reason: "ClusterOperatorsNotUpgradeable",
3123-
Message: "Multiple cluster operators should not be upgraded between minor versions:\n* Cluster operator default-operator-1 should not be upgraded between minor versions: RandomReason: some random reason why upgrades are not safe.\n* Cluster operator default-operator-2 should not be upgraded between minor versions: RandomReason2: some random reason 2 why upgrades are not safe.",
3123+
Message: "Multiple cluster operators should not be upgraded between minor or major versions:\n* Cluster operator default-operator-1 should not be upgraded between minor or major versions: RandomReason: some random reason why upgrades are not safe.\n* Cluster operator default-operator-2 should not be upgraded between minor or major versions: RandomReason2: some random reason 2 why upgrades are not safe.",
31243124
}},
31253125
},
31263126
},
@@ -3189,12 +3189,12 @@ func TestOperator_upgradeableSync(t *testing.T) {
31893189
Type: configv1.OperatorUpgradeable,
31903190
Status: configv1.ConditionFalse,
31913191
Reason: "MultipleReasons",
3192-
Message: "Cluster should not be upgraded between minor versions for multiple reasons: ClusterVersionOverridesSet,ClusterOperatorsNotUpgradeable\n* Disabling ownership via cluster version overrides prevents upgrades. Please remove overrides before continuing.\n* Multiple cluster operators should not be upgraded between minor versions:\n* Cluster operator default-operator-1 should not be upgraded between minor versions: RandomReason: some random reason why upgrades are not safe.\n* Cluster operator default-operator-2 should not be upgraded between minor versions: RandomReason2: some random reason 2 why upgrades are not safe.",
3192+
Message: "Cluster should not be upgraded between minor or major versions for multiple reasons: ClusterVersionOverridesSet,ClusterOperatorsNotUpgradeable\n* Disabling ownership via cluster version overrides prevents upgrades. Please remove overrides before continuing.\n* Multiple cluster operators should not be upgraded between minor or major versions:\n* Cluster operator default-operator-1 should not be upgraded between minor or major versions: RandomReason: some random reason why upgrades are not safe.\n* Cluster operator default-operator-2 should not be upgraded between minor or major versions: RandomReason2: some random reason 2 why upgrades are not safe.",
31933193
}, {
31943194
Type: "UpgradeableClusterOperators",
31953195
Status: configv1.ConditionFalse,
31963196
Reason: "ClusterOperatorsNotUpgradeable",
3197-
Message: "Multiple cluster operators should not be upgraded between minor versions:\n* Cluster operator default-operator-1 should not be upgraded between minor versions: RandomReason: some random reason why upgrades are not safe.\n* Cluster operator default-operator-2 should not be upgraded between minor versions: RandomReason2: some random reason 2 why upgrades are not safe.",
3197+
Message: "Multiple cluster operators should not be upgraded between minor or major versions:\n* Cluster operator default-operator-1 should not be upgraded between minor or major versions: RandomReason: some random reason why upgrades are not safe.\n* Cluster operator default-operator-2 should not be upgraded between minor or major versions: RandomReason2: some random reason 2 why upgrades are not safe.",
31983198
}, {
31993199
Type: "UpgradeableClusterVersionOverrides",
32003200
Status: configv1.ConditionFalse,

pkg/cvo/upgradeable.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ func (optr *Operator) setUpgradeableConditions() {
104104
Type: configv1.OperatorUpgradeable,
105105
Status: configv1.ConditionFalse,
106106
Reason: "MultipleReasons",
107-
Message: fmt.Sprintf("Cluster should not be upgraded between minor versions for multiple reasons: %s\n* %s", strings.Join(reasons, ","), strings.Join(msgs, "\n* ")),
107+
Message: fmt.Sprintf("Cluster should not be upgraded between minor or major versions for multiple reasons: %s\n* %s", strings.Join(reasons, ","), strings.Join(msgs, "\n* ")),
108108
LastTransitionTime: now,
109109
})
110110
} else {
@@ -176,7 +176,7 @@ func (optr *Operator) getUpgradeable() *upgradeable {
176176
}
177177

178178
type upgradeableCheck interface {
179-
// Check returns a not-nil condition that should be addressed before a minor level upgrade when the check fails.
179+
// Check returns a not-nil condition that should be addressed before a minor or major version upgrade when the check fails.
180180
Check() *configv1.ClusterOperatorStatusCondition
181181
}
182182

@@ -217,14 +217,14 @@ func (check *clusterOperatorsUpgradeable) Check() *configv1.ClusterOperatorStatu
217217
reason := ""
218218
if len(notup) == 1 {
219219
reason = notup[0].condition.Reason
220-
msg = fmt.Sprintf("Cluster operator %s should not be upgraded between minor versions: %s", notup[0].name, notup[0].condition.Message)
220+
msg = fmt.Sprintf("Cluster operator %s should not be upgraded between minor or major versions: %s", notup[0].name, notup[0].condition.Message)
221221
} else {
222222
reason = "ClusterOperatorsNotUpgradeable"
223223
var msgs []string
224224
for _, cond := range notup {
225-
msgs = append(msgs, fmt.Sprintf("Cluster operator %s should not be upgraded between minor versions: %s: %s", cond.name, cond.condition.Reason, cond.condition.Message))
225+
msgs = append(msgs, fmt.Sprintf("Cluster operator %s should not be upgraded between minor or major versions: %s: %s", cond.name, cond.condition.Reason, cond.condition.Message))
226226
}
227-
msg = fmt.Sprintf("Multiple cluster operators should not be upgraded between minor versions:\n* %s", strings.Join(msgs, "\n* "))
227+
msg = fmt.Sprintf("Multiple cluster operators should not be upgraded between minor or major versions:\n* %s", strings.Join(msgs, "\n* "))
228228
}
229229
cond.Reason = reason
230230
cond.Message = msg
@@ -302,7 +302,7 @@ func (check *clusterManifestDeleteInProgressUpgradeable) Check() *configv1.Clust
302302
resources := strings.Join(deletes, ",")
303303
klog.V(2).Infof("Resource deletions in progress; resources=%s", resources)
304304
cond.Reason = "ResourceDeletesInProgress"
305-
cond.Message = fmt.Sprintf("Cluster minor level upgrades are not allowed while resource deletions are in progress; resources=%s", resources)
305+
cond.Message = fmt.Sprintf("Cluster minor or major version upgrades are not allowed while resource deletions are in progress; resources=%s", resources)
306306
return cond
307307
}
308308
return nil

pkg/internal/constants.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,18 +56,18 @@ const (
5656
ImplicitlyEnabledCapabilities configv1.ClusterStatusConditionType = "ImplicitlyEnabledCapabilities"
5757

5858
// UpgradeableAdminAckRequired is False if there is API removed from the Kubernetes API server which requires admin
59-
// consideration, and thus update to the next minor version is blocked.
59+
// consideration, and thus update to the next minor or major version is blocked.
6060
UpgradeableAdminAckRequired configv1.ClusterStatusConditionType = "UpgradeableAdminAckRequired"
61-
// UpgradeableDeletesInProgress is False if deleting resources is in progress, and thus update to the next minor
61+
// UpgradeableDeletesInProgress is False if deleting resources is in progress, and thus update to the next minor or major
6262
// version is blocked.
6363
UpgradeableDeletesInProgress configv1.ClusterStatusConditionType = "UpgradeableDeletesInProgress"
64-
// UpgradeableClusterOperators is False if something is wrong with Cluster Operators, and thus update to the next minor
64+
// UpgradeableClusterOperators is False if something is wrong with Cluster Operators, and thus update to the next minor or major
6565
// version is blocked.
6666
UpgradeableClusterOperators configv1.ClusterStatusConditionType = "UpgradeableClusterOperators"
67-
// UpgradeableClusterVersionOverrides is False if there are overrides in the Cluster Version, and thus update to the next minor
67+
// UpgradeableClusterVersionOverrides is False if there are overrides in the Cluster Version, and thus update to the next minor or major
6868
// version is blocked.
6969
UpgradeableClusterVersionOverrides configv1.ClusterStatusConditionType = "UpgradeableClusterVersionOverrides"
7070

71-
// UpgradeableUpgradeInProgress is True if an update is in progress
71+
// UpgradeableUpgradeInProgress is True if an update is in progress.
7272
UpgradeableUpgradeInProgress configv1.ClusterStatusConditionType = "UpgradeableUpgradeInProgress"
7373
)

pkg/payload/precondition/clusterversion/upgradeable.go

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package clusterversion
33
import (
44
"context"
55
"fmt"
6+
"strings"
67
"time"
78

89
"github.com/blang/semver/v4"
@@ -97,7 +98,8 @@ func (pf *Upgradeable) Run(ctx context.Context, releaseContext precondition.Rele
9798
klog.V(4).Infof("The current version is %s parsed from %s and the target version is %s parsed from %s", currentVersion.String(), cv.Status.Desired.Version, targetVersion.String(), releaseContext.DesiredVersion)
9899
patchOnly := targetVersion.Major == currentVersion.Major && targetVersion.Minor == currentVersion.Minor
99100
if targetVersion.LTE(currentVersion) || patchOnly {
100-
// When Upgradeable==False, a patch level update with the same minor level is allowed unless overrides are set
101+
// When Upgradeable==False, a patch level update with the same minor version is allowed unless overrides are set.
102+
// However, minor or major version updates are blocked when Upgradeable==False.
101103
// This Upgradeable precondition is only concerned about moving forward, i.e., do not care about downgrade which is taken care of by the Rollback precondition
102104
if condition := ClusterVersionOverridesCondition(cv); condition != nil {
103105
klog.V(2).Infof("Retarget from %s to %s is blocked by %s: %s", currentVersion.String(), targetVersion.String(), condition.Reason, condition.Message)
@@ -107,11 +109,11 @@ func (pf *Upgradeable) Run(ctx context.Context, releaseContext precondition.Rele
107109
Name: pf.Name(),
108110
}
109111
} else {
110-
if completedVersion := minorUpdateFrom(cv.Status, currentVersion); completedVersion != "" && patchOnly {
112+
if completedVersion, majorOrMinor := majorOrMinorUpdateFrom(cv.Status, currentVersion); completedVersion != "" && patchOnly {
111113
// This is to generate an accepted risk for the accepting case 4.y.z -> 4.y+1.z' -> 4.y+1.z''
112114
return &precondition.Error{
113-
Reason: "MinorVersionClusterUpdateInProgress",
114-
Message: fmt.Sprintf("Retarget to %s while a minor level update from %s to %s is in progress", targetVersion, completedVersion, currentVersion),
115+
Reason: fmt.Sprintf("%sVersionClusterUpdateInProgress", majorOrMinor),
116+
Message: fmt.Sprintf("Retarget to %s while a %s version update from %s to %s is in progress", targetVersion, strings.ToLower(majorOrMinor), completedVersion, currentVersion),
115117
Name: pf.Name(),
116118
NonBlockingWarning: true,
117119
}
@@ -129,24 +131,29 @@ func (pf *Upgradeable) Run(ctx context.Context, releaseContext precondition.Rele
129131
}
130132
}
131133

132-
// minorUpdateFrom returns the version that was installed completed if a minor level upgrade is in progress
133-
// and the empty string otherwise
134-
func minorUpdateFrom(status configv1.ClusterVersionStatus, currentVersion semver.Version) string {
134+
// majorOrMinorUpdateFrom returns the version that was installed
135+
// completed if a minor or major version upgrade is in progress and the
136+
// empty string otherwise. It also returns "Major", "Minor", or "" to name
137+
// the transition.
138+
func majorOrMinorUpdateFrom(status configv1.ClusterVersionStatus, currentVersion semver.Version) (string, string) {
135139
completedVersion := GetCurrentVersion(status.History)
136140
if completedVersion == "" {
137-
return ""
141+
return "", ""
138142
}
139143
v, err := semver.Parse(completedVersion)
140144
if err != nil {
141-
return ""
145+
return "", ""
142146
}
143147
if cond := resourcemerge.FindOperatorStatusCondition(status.Conditions, configv1.OperatorProgressing); cond != nil &&
144-
cond.Status == configv1.ConditionTrue &&
145-
v.Major == currentVersion.Major &&
146-
v.Minor < currentVersion.Minor {
147-
return completedVersion
148+
cond.Status == configv1.ConditionTrue {
149+
if v.Major < currentVersion.Major {
150+
return completedVersion, "Major"
151+
}
152+
if v.Major == currentVersion.Major && v.Minor < currentVersion.Minor {
153+
return completedVersion, "Minor"
154+
}
148155
}
149-
return ""
156+
return "", ""
150157
}
151158

152159
// Name returns the name of the precondition.

pkg/payload/precondition/clusterversion/upgradeable_test.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,10 +136,23 @@ func TestUpgradeableRun(t *testing.T) {
136136
expected: &precondition.Error{
137137
NonBlockingWarning: true,
138138
Name: "ClusterVersionUpgradeable",
139-
Message: "Retarget to 4.2.3 while a minor level update from 4.1.1 to 4.2.1 is in progress",
139+
Message: "Retarget to 4.2.3 while a minor version update from 4.1.1 to 4.2.1 is in progress",
140140
Reason: "MinorVersionClusterUpdateInProgress",
141141
},
142142
},
143+
{
144+
name: "move-x-then-z, with false condition",
145+
upgradeable: ptr(configv1.ConditionFalse),
146+
completedVersion: "4.1.1",
147+
currVersion: "5.0.1",
148+
desiredVersion: "5.0.3",
149+
expected: &precondition.Error{
150+
NonBlockingWarning: true,
151+
Name: "ClusterVersionUpgradeable",
152+
Message: "Retarget to 5.0.3 while a major version update from 4.1.1 to 5.0.1 is in progress",
153+
Reason: "MajorVersionClusterUpdateInProgress",
154+
},
155+
},
143156
{
144157
name: "move-z-then-z, with false condition",
145158
upgradeable: ptr(configv1.ConditionFalse),

0 commit comments

Comments
 (0)