Skip to content

Commit b436942

Browse files
Tyler Slatonnjhale
Tyler Slaton
andcommitted
fix(openshift): use env var instead of clusterversion status
Get the current OpenShift release version from the OPENSHIFT_RELEASE environment variable since the behavior of the original source -- the ClusterVersion desired release status field -- has changed. Signed-off-by: Tyler Slaton <[email protected]> Co-authored-by: Nick Hale <[email protected]>
1 parent 6c4e779 commit b436942

File tree

4 files changed

+66
-126
lines changed

4 files changed

+66
-126
lines changed

Diff for: pkg/controller/operators/openshift/clusteroperator_controller_test.go

+19-35
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package openshift
22

33
import (
44
"fmt"
5+
"os"
6+
"sync"
57

68
semver "github.com/blang/semver/v4"
79
. "github.com/onsi/ginkgo/v2"
@@ -19,7 +21,6 @@ import (
1921
var _ = Describe("ClusterOperator controller", func() {
2022
var (
2123
clusterOperatorName types.NamespacedName
22-
cv *configv1.ClusterVersion
2324
csv *operatorsv1alpha1.ClusterServiceVersion
2425
)
2526

@@ -55,33 +56,11 @@ var _ = Describe("ClusterOperator controller", func() {
5556
})
5657

5758
BeforeEach(func() {
58-
// "version" singleton is available in OpenShift by default
59-
cv = &configv1.ClusterVersion{}
60-
cv.SetName("version")
61-
62-
Eventually(func() error {
63-
return k8sClient.Create(ctx, cv)
64-
}).Should(Succeed())
65-
66-
cv.Status = configv1.ClusterVersionStatus{
67-
Desired: configv1.Release{
68-
Version: clusterVersion,
69-
},
70-
}
71-
72-
Eventually(func() error {
73-
return k8sClient.Status().Update(ctx, cv)
74-
}).Should(Succeed())
59+
os.Setenv(releaseEnvVar, clusterVersion)
7560
})
7661

7762
AfterEach(func() {
78-
Eventually(func() error {
79-
err := k8sClient.Delete(ctx, cv)
80-
if err != nil && apierrors.IsNotFound(err) {
81-
err = nil
82-
}
83-
return err
84-
}).Should(Succeed())
63+
openshiftReleaseOnce = sync.Once{}
8564
})
8665

8766
It("should ensure the ClusterOperator always exists", func() {
@@ -143,10 +122,11 @@ var _ = Describe("ClusterOperator controller", func() {
143122
}))
144123

145124
By("setting upgradeable=false when there's an error determining compatibility")
146-
cv.Status = configv1.ClusterVersionStatus{}
147125

126+
By("changing the openshift environment variable to be invalid and restarting the ClusterOperator")
127+
resetOpenshiftReleaseOnceTo("")
148128
Eventually(func() error {
149-
return k8sClient.Status().Update(ctx, cv)
129+
return k8sClient.Delete(ctx, co)
150130
}).Should(Succeed())
151131

152132
Eventually(func() ([]configv1.ClusterOperatorStatusCondition, error) {
@@ -156,18 +136,14 @@ var _ = Describe("ClusterOperator controller", func() {
156136
Type: configv1.OperatorUpgradeable,
157137
Status: configv1.ConditionFalse,
158138
Reason: ErrorCheckingOperatorCompatibility,
159-
Message: "Encountered errors while checking compatibility with the next minor version of OpenShift: desired release version missing from ClusterVersion",
139+
Message: "Encountered errors while checking compatibility with the next minor version of OpenShift: desired release version missing from OPENSHIFT_RELEASE env variable",
160140
LastTransitionTime: fixedNow(),
161141
}))
162142

163-
cv.Status = configv1.ClusterVersionStatus{
164-
Desired: configv1.Release{
165-
Version: clusterVersion,
166-
},
167-
}
168-
143+
By("setting an appropriate variable for the cluster version and restarting the ClusterOperator")
144+
resetOpenshiftReleaseOnceTo(clusterVersion)
169145
Eventually(func() error {
170-
return k8sClient.Status().Update(ctx, cv)
146+
return k8sClient.Delete(ctx, co)
171147
}).Should(Succeed())
172148

173149
By("setting upgradeable=false when incompatible operators exist")
@@ -327,3 +303,11 @@ var _ = Describe("ClusterOperator controller", func() {
327303
}))
328304
})
329305
})
306+
307+
// resetOpenshiftReleaseOnce creates a new sync.Once for the openshift release and then sets the openshift
308+
// env var to the desired version. WARNING: This function should only be used for testing purposes as it
309+
// goes around the desired logic of only setting the version of the cluster for this operator once.
310+
func resetOpenshiftReleaseOnceTo(version string) {
311+
openshiftReleaseOnce = *new(sync.Once)
312+
os.Setenv(releaseEnvVar, version)
313+
}

Diff for: pkg/controller/operators/openshift/helpers.go

+34-17
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import (
44
"context"
55
"errors"
66
"fmt"
7+
"os"
78
"strings"
9+
"sync"
810

911
semver "github.com/blang/semver/v4"
1012
configv1 "github.com/openshift/api/config/v1"
@@ -119,17 +121,17 @@ func transientErrors(err error) error {
119121
}
120122

121123
func incompatibleOperators(ctx context.Context, cli client.Client) (skews, error) {
122-
desired, err := desiredRelease(ctx, cli)
124+
current, err := getCurrentRelease(ctx)
123125
if err != nil {
124126
return nil, err
125127
}
126128

127-
if desired == nil {
129+
if current == nil {
128130
// Note: This shouldn't happen
129131
return nil, fmt.Errorf("failed to determine current OpenShift Y-stream release")
130132
}
131133

132-
next, err := nextY(*desired)
134+
next, err := nextY(*current)
133135
if err != nil {
134136
return nil, err
135137
}
@@ -168,24 +170,39 @@ func incompatibleOperators(ctx context.Context, cli client.Client) (skews, error
168170
return incompatible, nil
169171
}
170172

171-
func desiredRelease(ctx context.Context, cli client.Client) (*semver.Version, error) {
172-
cv := configv1.ClusterVersion{}
173-
if err := cli.Get(ctx, client.ObjectKey{Name: "version"}, &cv); err != nil { // "version" is the name of OpenShift's ClusterVersion singleton
174-
return nil, &transientError{fmt.Errorf("failed to get ClusterVersion: %w", err)}
175-
}
173+
var (
174+
openshiftReleaseOnce = sync.Once{}
175+
openshiftRelease *semver.Version
176+
)
176177

177-
v := cv.Status.Desired.Version
178-
if v == "" {
179-
// The release version hasn't been set yet
180-
return nil, fmt.Errorf("desired release version missing from ClusterVersion")
181-
}
178+
const (
179+
releaseEnvVar = "OPENSHIFT_RELEASE" // OpenShift's env variable for defining the current release
180+
)
182181

183-
desired, err := semver.ParseTolerant(v)
184-
if err != nil {
185-
return nil, fmt.Errorf("cluster version has invalid desired release version: %w", err)
182+
func getCurrentRelease(ctx context.Context) (*semver.Version, error) {
183+
var doError error
184+
openshiftReleaseOnce.Do(func() {
185+
// Get the raw version from the OPENSHIFT_RELEASE environment variable
186+
raw, ok := os.LookupEnv(releaseEnvVar)
187+
if !ok || raw == "" {
188+
doError = fmt.Errorf("desired release version missing from OPENSHIFT_RELEASE env variable")
189+
return
190+
}
191+
192+
release, err := semver.ParseTolerant(raw)
193+
if err != nil {
194+
doError = fmt.Errorf("cluster version has invalid desired release version: %w", err)
195+
return
196+
}
197+
198+
openshiftRelease = &release
199+
})
200+
201+
if doError != nil {
202+
return nil, doError
186203
}
187204

188-
return &desired, nil
205+
return openshiftRelease, nil
189206
}
190207

191208
func nextY(v semver.Version) (semver.Version, error) {

Diff for: pkg/controller/operators/openshift/helpers_test.go

+12-73
Original file line numberDiff line numberDiff line change
@@ -221,22 +221,13 @@ func TestIncompatibleOperators(t *testing.T) {
221221
}
222222
for _, tt := range []struct {
223223
description string
224-
cv configv1.ClusterVersion
224+
version string
225225
in skews
226226
expect expect
227227
}{
228228
{
229229
description: "Compatible",
230-
cv: configv1.ClusterVersion{
231-
ObjectMeta: metav1.ObjectMeta{
232-
Name: "version",
233-
},
234-
Status: configv1.ClusterVersionStatus{
235-
Desired: configv1.Release{
236-
Version: "1.0.0",
237-
},
238-
},
239-
},
230+
version: "1.0.0",
240231
in: skews{
241232
{
242233
name: "almond",
@@ -261,16 +252,7 @@ func TestIncompatibleOperators(t *testing.T) {
261252
},
262253
{
263254
description: "Incompatible",
264-
cv: configv1.ClusterVersion{
265-
ObjectMeta: metav1.ObjectMeta{
266-
Name: "version",
267-
},
268-
Status: configv1.ClusterVersionStatus{
269-
Desired: configv1.Release{
270-
Version: "1.0.0",
271-
},
272-
},
273-
},
255+
version: "1.0.0",
274256
in: skews{
275257
{
276258
name: "almond",
@@ -331,16 +313,7 @@ func TestIncompatibleOperators(t *testing.T) {
331313
},
332314
{
333315
description: "Mixed",
334-
cv: configv1.ClusterVersion{
335-
ObjectMeta: metav1.ObjectMeta{
336-
Name: "version",
337-
},
338-
Status: configv1.ClusterVersionStatus{
339-
Desired: configv1.Release{
340-
Version: "1.0.0",
341-
},
342-
},
343-
},
316+
version: "1.0.0",
344317
in: skews{
345318
{
346319
name: "almond",
@@ -376,16 +349,7 @@ func TestIncompatibleOperators(t *testing.T) {
376349
},
377350
{
378351
description: "Mixed/BadVersion",
379-
cv: configv1.ClusterVersion{
380-
ObjectMeta: metav1.ObjectMeta{
381-
Name: "version",
382-
},
383-
Status: configv1.ClusterVersionStatus{
384-
Desired: configv1.Release{
385-
Version: "1.0.0",
386-
},
387-
},
388-
},
352+
version: "1.0.0",
389353
in: skews{
390354
{
391355
name: "almond",
@@ -424,16 +388,7 @@ func TestIncompatibleOperators(t *testing.T) {
424388
},
425389
{
426390
description: "EmptyVersion",
427-
cv: configv1.ClusterVersion{
428-
ObjectMeta: metav1.ObjectMeta{
429-
Name: "version",
430-
},
431-
Status: configv1.ClusterVersionStatus{
432-
Desired: configv1.Release{
433-
Version: "", // This should result in an transient error
434-
},
435-
},
436-
},
391+
version: "", // This should result in an transient error
437392
in: skews{
438393
{
439394
name: "almond",
@@ -453,16 +408,7 @@ func TestIncompatibleOperators(t *testing.T) {
453408
},
454409
{
455410
description: "ClusterZ",
456-
cv: configv1.ClusterVersion{
457-
ObjectMeta: metav1.ObjectMeta{
458-
Name: "version",
459-
},
460-
Status: configv1.ClusterVersionStatus{
461-
Desired: configv1.Release{
462-
Version: "1.0.1", // Next Y-stream is 1.1.0, NOT 1.1.1
463-
},
464-
},
465-
},
411+
version: "1.0.1", // Next Y-stream is 1.1.0, NOT 1.1.1
466412
in: skews{
467413
{
468414
name: "beech",
@@ -477,16 +423,7 @@ func TestIncompatibleOperators(t *testing.T) {
477423
},
478424
{
479425
description: "ClusterPre",
480-
cv: configv1.ClusterVersion{
481-
ObjectMeta: metav1.ObjectMeta{
482-
Name: "version",
483-
},
484-
Status: configv1.ClusterVersionStatus{
485-
Desired: configv1.Release{
486-
Version: "1.1.0-pre", // Next Y-stream is 1.1.0, NOT 1.2.0
487-
},
488-
},
489-
},
426+
version: "1.1.0-pre", // Next Y-stream is 1.1.0, NOT 1.2.0
490427
in: skews{
491428
{
492429
name: "almond",
@@ -501,7 +438,9 @@ func TestIncompatibleOperators(t *testing.T) {
501438
},
502439
} {
503440
t.Run(tt.description, func(t *testing.T) {
504-
objs := []client.Object{tt.cv.DeepCopy()}
441+
objs := []client.Object{}
442+
443+
resetOpenshiftReleaseOnceTo(tt.version)
505444

506445
for _, s := range tt.in {
507446
csv := &operatorsv1alpha1.ClusterServiceVersion{}
@@ -525,7 +464,7 @@ func TestIncompatibleOperators(t *testing.T) {
525464
scheme := runtime.NewScheme()
526465
require.NoError(t, AddToScheme(scheme))
527466

528-
fcli := fake.NewClientBuilder().WithScheme(scheme).WithObjects(objs...).Build()
467+
fcli := fake.NewClientBuilder().WithObjects(objs...).WithScheme(scheme).Build()
529468
incompatible, err := incompatibleOperators(context.Background(), fcli)
530469
if tt.expect.err {
531470
require.Error(t, err)

Diff for: pkg/controller/operators/openshift/options.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ func WithOLMOperator() ReconcilerOption {
175175
})
176176
config.TweakBuilder = func(bldr *builder.Builder) *builder.Builder {
177177
return bldr.Watches(&source.Kind{Type: &operatorsv1alpha1.ClusterServiceVersion{}}, enqueue, builder.WithPredicates(originalCSV)).
178-
Watches(&source.Kind{Type: &configv1.ClusterVersion{}}, enqueue, builder.WithPredicates(watchName(&name)))
178+
Watches(&source.Kind{Type: &configv1.ClusterVersion{}}, enqueue, builder.WithPredicates(watchName(&name))) // Note: is this still needed?
179179
}
180180
}
181181
}

0 commit comments

Comments
 (0)