Skip to content

Commit 760c10d

Browse files
authored
fix(openshift): drop z from next calculated y-stream (#2324)
When determining operator compatibility, drop z and build versions in the calculation of the next Y-stream (minor) release of OpenShift. e.g. If the current version is v4.9.5+build, the next Y-stream is calculated as v4.10.0. If a pre-release is included, drop it as well but don't increment the minor version. e.g. If the current version is v4.10.0-rc, the next Y-stream is calculated as v4.10.0. Before this change, the next Y-stream was the result of simply iterating the cluster's minor version. When the cluster was at a patch version greater than that specified by an operator, upgrades would be erroneously blocked. e.g. If the current version was v4.9.5, the next version would be calculated as v4.10.5, which would block upgrades on operators with max versions set to v4.10 -- or more explicitly [v4.10.0, v4.10.5) (')' is read "exclusive"). Signed-off-by: Nick Hale <[email protected]>
1 parent c76e1cd commit 760c10d

File tree

2 files changed

+104
-7
lines changed

2 files changed

+104
-7
lines changed

pkg/controller/operators/openshift/helpers.go

+23-5
Original file line numberDiff line numberDiff line change
@@ -125,16 +125,20 @@ func transientErrors(err error) error {
125125
}
126126

127127
func incompatibleOperators(ctx context.Context, cli client.Client) (skews, error) {
128-
next, err := desiredRelease(ctx, cli)
128+
desired, err := desiredRelease(ctx, cli)
129129
if err != nil {
130130
return nil, err
131131
}
132132

133-
if next == nil {
133+
if desired == nil {
134134
// Note: This shouldn't happen
135-
return nil, fmt.Errorf("Failed to determine next OpenShift Y-stream release")
135+
return nil, fmt.Errorf("Failed to determine current OpenShift Y-stream release")
136+
}
137+
138+
next, err := nextY(*desired)
139+
if err != nil {
140+
return nil, err
136141
}
137-
next.Minor++
138142

139143
csvList := &operatorsv1alpha1.ClusterServiceVersionList{}
140144
if err := cli.List(ctx, csvList); err != nil {
@@ -158,7 +162,7 @@ func incompatibleOperators(ctx context.Context, cli client.Client) (skews, error
158162
continue
159163
}
160164

161-
if max == nil || max.GTE(*next) {
165+
if max == nil || max.GTE(next) {
162166
continue
163167
}
164168
s.maxOpenShiftVersion = max.String()
@@ -189,6 +193,20 @@ func desiredRelease(ctx context.Context, cli client.Client) (*semver.Version, er
189193
return &desired, nil
190194
}
191195

196+
func nextY(v semver.Version) (semver.Version, error) {
197+
v.Build = nil // Builds are irrelevant
198+
199+
if len(v.Pre) > 0 {
200+
// Dropping pre-releases is equivalent to incrementing Y
201+
v.Pre = nil
202+
v.Patch = 0
203+
204+
return v, nil
205+
}
206+
207+
return v, v.IncrementMinor() // Sets Y=Y+1 and Z=0
208+
}
209+
192210
const (
193211
MaxOpenShiftVersionProperty = "olm.maxOpenShiftVersion"
194212
)

pkg/controller/operators/openshift/helpers_test.go

+81-2
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,11 @@ func TestIncompatibleOperators(t *testing.T) {
251251
{
252252
name: "chestnut",
253253
namespace: "default",
254+
maxOpenShiftVersion: "1.2.0-pre+build",
255+
},
256+
{
257+
name: "drupe",
258+
namespace: "default",
254259
maxOpenShiftVersion: "2.0.0",
255260
},
256261
},
@@ -290,6 +295,11 @@ func TestIncompatibleOperators(t *testing.T) {
290295
{
291296
name: "drupe",
292297
namespace: "default",
298+
maxOpenShiftVersion: "1.1.0-pre+build",
299+
},
300+
{
301+
name: "european-hazelnut",
302+
namespace: "default",
293303
maxOpenShiftVersion: "0.1.0",
294304
},
295305
},
@@ -314,6 +324,11 @@ func TestIncompatibleOperators(t *testing.T) {
314324
{
315325
name: "drupe",
316326
namespace: "default",
327+
maxOpenShiftVersion: "1.1.0-pre+build",
328+
},
329+
{
330+
name: "european-hazelnut",
331+
namespace: "default",
317332
maxOpenShiftVersion: "0.1.0",
318333
},
319334
},
@@ -413,14 +428,14 @@ func TestIncompatibleOperators(t *testing.T) {
413428
},
414429
},
415430
{
416-
description: "Compatible/EmptyVersion",
431+
description: "EmptyVersion",
417432
cv: configv1.ClusterVersion{
418433
ObjectMeta: metav1.ObjectMeta{
419434
Name: "version",
420435
},
421436
Status: configv1.ClusterVersionStatus{
422437
Desired: configv1.Update{
423-
Version: "",
438+
Version: "", // This should result in an transient error
424439
},
425440
},
426441
},
@@ -441,6 +456,70 @@ func TestIncompatibleOperators(t *testing.T) {
441456
incompatible: nil,
442457
},
443458
},
459+
{
460+
description: "ClusterZ",
461+
cv: configv1.ClusterVersion{
462+
ObjectMeta: metav1.ObjectMeta{
463+
Name: "version",
464+
},
465+
Status: configv1.ClusterVersionStatus{
466+
Desired: configv1.Update{
467+
Version: "1.0.1", // Next Y-stream is 1.1.0, NOT 1.1.1
468+
},
469+
},
470+
},
471+
in: skews{
472+
{
473+
name: "almond",
474+
namespace: "default",
475+
maxOpenShiftVersion: "1.1.2",
476+
},
477+
{
478+
name: "beech",
479+
namespace: "default",
480+
maxOpenShiftVersion: "1.1",
481+
},
482+
},
483+
expect: expect{
484+
err: false,
485+
incompatible: nil,
486+
},
487+
},
488+
{
489+
description: "ClusterPre",
490+
cv: configv1.ClusterVersion{
491+
ObjectMeta: metav1.ObjectMeta{
492+
Name: "version",
493+
},
494+
Status: configv1.ClusterVersionStatus{
495+
Desired: configv1.Update{
496+
Version: "1.1.0-pre", // Next Y-stream is 1.1.0, NOT 1.2.0
497+
},
498+
},
499+
},
500+
in: skews{
501+
{
502+
name: "almond",
503+
namespace: "default",
504+
maxOpenShiftVersion: "1.1.0",
505+
},
506+
{
507+
name: "beech",
508+
namespace: "default",
509+
maxOpenShiftVersion: "1.1.0-pre",
510+
},
511+
},
512+
expect: expect{
513+
err: false,
514+
incompatible: skews{
515+
{
516+
name: "beech",
517+
namespace: "default",
518+
maxOpenShiftVersion: "1.1.0-pre",
519+
},
520+
},
521+
},
522+
},
444523
} {
445524
t.Run(tt.description, func(t *testing.T) {
446525
objs := []client.Object{tt.cv.DeepCopy()}

0 commit comments

Comments
 (0)