Skip to content

Commit fb9f7b5

Browse files
author
Tyler Slaton
committed
fix(openshift): update openshiftRelease to be protected by a mutex
Signed-off-by: Tyler Slaton <[email protected]>
1 parent 3a9b0b9 commit fb9f7b5

File tree

3 files changed

+44
-35
lines changed

3 files changed

+44
-35
lines changed

pkg/controller/operators/openshift/clusteroperator_controller_test.go

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package openshift
33
import (
44
"fmt"
55
"os"
6-
"sync"
76

87
semver "github.com/blang/semver/v4"
98
. "github.com/onsi/ginkgo/v2"
@@ -60,7 +59,7 @@ var _ = Describe("ClusterOperator controller", func() {
6059
})
6160

6261
AfterEach(func() {
63-
openshiftReleaseOnce = sync.Once{}
62+
resetCurrentReleaseTo(clusterVersion)
6463
})
6564

6665
It("should ensure the ClusterOperator always exists", func() {
@@ -124,7 +123,7 @@ var _ = Describe("ClusterOperator controller", func() {
124123
By("setting upgradeable=false when there's an error determining compatibility")
125124

126125
By("changing the openshift environment variable to be invalid and restarting the ClusterOperator")
127-
resetOpenshiftReleaseOnceTo("")
126+
resetCurrentReleaseTo("")
128127
Eventually(func() error {
129128
return k8sClient.Delete(ctx, co)
130129
}).Should(Succeed())
@@ -141,7 +140,7 @@ var _ = Describe("ClusterOperator controller", func() {
141140
}))
142141

143142
By("setting an appropriate variable for the cluster version and restarting the ClusterOperator")
144-
resetOpenshiftReleaseOnceTo(clusterVersion)
143+
resetCurrentReleaseTo(clusterVersion)
145144
Eventually(func() error {
146145
return k8sClient.Delete(ctx, co)
147146
}).Should(Succeed())
@@ -304,15 +303,13 @@ var _ = Describe("ClusterOperator controller", func() {
304303
})
305304
})
306305

307-
// resetOpenshiftReleaseOnce creates a new sync.Once for the openshift release and then sets the openshift
306+
// resetCurrentRelease thread safely updates the currentRelease.version and then sets the openshift release
308307
// env var to the desired version. WARNING: This function should only be used for testing purposes as it
309308
// goes around the desired logic of only setting the version of the cluster for this operator once.
310-
var resetMutex sync.Mutex
309+
func resetCurrentReleaseTo(version string) {
310+
currentRelease.mu.Lock()
311+
defer currentRelease.mu.Unlock()
311312

312-
func resetOpenshiftReleaseOnceTo(version string) {
313-
resetMutex.Lock()
314-
defer resetMutex.Unlock()
315-
316-
openshiftReleaseOnce = *new(sync.Once)
313+
currentRelease.version = nil
317314
os.Setenv(releaseEnvVar, version)
318315
}

pkg/controller/operators/openshift/helpers.go

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ func transientErrors(err error) error {
121121
}
122122

123123
func incompatibleOperators(ctx context.Context, cli client.Client) (skews, error) {
124-
current, err := getCurrentRelease(ctx)
124+
current, err := getCurrentRelease()
125125
if err != nil {
126126
return nil, err
127127
}
@@ -170,39 +170,51 @@ func incompatibleOperators(ctx context.Context, cli client.Client) (skews, error
170170
return incompatible, nil
171171
}
172172

173+
type openshiftRelease struct {
174+
version *semver.Version
175+
mu sync.Mutex
176+
}
177+
173178
var (
174-
openshiftReleaseOnce = sync.Once{}
175-
openshiftRelease *semver.Version
179+
currentRelease = &openshiftRelease{}
176180
)
177181

178182
const (
179183
releaseEnvVar = "OPENSHIFT_RELEASE" // OpenShift's env variable for defining the current release
180184
)
181185

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-
}
186+
func getCurrentRelease() (*semver.Version, error) {
187+
currentRelease.mu.Lock()
188+
defer currentRelease.mu.Unlock()
189+
190+
if currentRelease.version != nil {
191+
/*
192+
If the version is already set, we don't want to set it again as the currentRelease
193+
is designed to be a singleton. If a new version is set, we are making an assumption
194+
that this controller will be restarted and thus pull in the new version from the
195+
environment into memory.
196+
197+
Note: sync.Once is not used here as it was difficult to reliably test without hitting
198+
race conditions.
199+
*/
200+
return currentRelease.version, nil
201+
}
197202

198-
openshiftRelease = &release
199-
})
203+
// Get the raw version from the OPENSHIFT_RELEASE environment variable
204+
raw, ok := os.LookupEnv(releaseEnvVar)
205+
if !ok || raw == "" {
206+
// No env var set, try again later
207+
return nil, fmt.Errorf("desired release version missing from OPENSHIFT_RELEASE env variable")
208+
}
200209

201-
if doError != nil {
202-
return nil, doError
210+
release, err := semver.ParseTolerant(raw)
211+
if err != nil {
212+
return nil, fmt.Errorf("cluster version has invalid desired release version: %w", err)
203213
}
204214

205-
return openshiftRelease, nil
215+
currentRelease.version = &release
216+
217+
return currentRelease.version, nil
206218
}
207219

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

pkg/controller/operators/openshift/helpers_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ func TestIncompatibleOperators(t *testing.T) {
440440
t.Run(tt.description, func(t *testing.T) {
441441
objs := []client.Object{}
442442

443-
resetOpenshiftReleaseOnceTo(tt.version)
443+
resetCurrentReleaseTo(tt.version)
444444

445445
for _, s := range tt.in {
446446
csv := &operatorsv1alpha1.ClusterServiceVersion{}

0 commit comments

Comments
 (0)