Skip to content

Commit 206f751

Browse files
committed
helmrepo-oci: check before rec on type switching
When a HelmRepository with "default" spec.type is switched to "oci", the existing HelmRepository is processed by HelmRepositoryReconciler by running reconcileDelete() which removes all the previous status information and allows the HelmRepositoryOCIReconciler to process the object and add its own status data. But at times, when HelmRepositoryOCIReconciler starts processing a HelmRepository with stale status data from the client cache, it contains the stale conditions that are owned only by HelmRepositoryReconciler and isn't managed by HelmRepositoryOCIReconciler. This results in situations where Ready is marked as True with the latest generation of the object and the unmanaged stale conditions remain in the previous generation, resulting in unexpected status conditions. In the observed flaky tests, `TestHelmRepositoryReconciler_ReconcileTypeUpdatePredicateFilter` would fail because of stale ArtifactInStorage condition with previous generation value. This change adds a check in the HelmRepositoryOCIReconciler to start processing the object only once the stale unmanaged conditions have been removed. Signed-off-by: Sunny <darkowlzz@protonmail.com>
1 parent 9110e6f commit 206f751

File tree

2 files changed

+51
-0
lines changed

2 files changed

+51
-0
lines changed

controllers/helmrepository_controller_oci.go

+29
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,11 @@ type HelmRepositoryOCIReconciler struct {
8282
RegistryClientGenerator RegistryClientGeneratorFunc
8383

8484
patchOptions []patch.Option
85+
86+
// unmanagedConditions are the conditions that are not managed by this
87+
// reconciler and need to be removed from the object before taking ownership
88+
// of the object being reconciled.
89+
unmanagedConditions []string
8590
}
8691

8792
// RegistryClientGeneratorFunc is a function that returns a registry client
@@ -95,6 +100,7 @@ func (r *HelmRepositoryOCIReconciler) SetupWithManager(mgr ctrl.Manager) error {
95100
}
96101

97102
func (r *HelmRepositoryOCIReconciler) SetupWithManagerAndOptions(mgr ctrl.Manager, opts HelmRepositoryReconcilerOptions) error {
103+
r.unmanagedConditions = conditionsDiff(helmRepositoryReadyCondition.Owned, helmRepositoryOCIOwnedConditions)
98104
r.patchOptions = getPatchOptions(helmRepositoryOCIOwnedConditions, r.ControllerName)
99105

100106
recoverPanic := true
@@ -124,6 +130,14 @@ func (r *HelmRepositoryOCIReconciler) Reconcile(ctx context.Context, req ctrl.Re
124130
return ctrl.Result{}, client.IgnoreNotFound(err)
125131
}
126132

133+
// If the object contains any of the unmanaged conditions, requeue and wait
134+
// for those conditions to be removed first before processing the object.
135+
// NOTE: This will happen only when a HelmRepository's spec.type is switched
136+
// from "default" to "oci".
137+
if conditions.HasAny(obj, r.unmanagedConditions) {
138+
return ctrl.Result{RequeueAfter: time.Second}, nil
139+
}
140+
127141
// Record suspended status metric
128142
r.RecordSuspend(ctx, obj, obj.Spec.Suspend)
129143

@@ -428,3 +442,18 @@ func makeLoginOption(auth authn.Authenticator, keychain authn.Keychain, registry
428442

429443
return nil, nil
430444
}
445+
446+
func conditionsDiff(a, b []string) []string {
447+
bMap := make(map[string]struct{}, len(b))
448+
for _, j := range b {
449+
bMap[j] = struct{}{}
450+
}
451+
452+
r := []string{}
453+
for _, i := range a {
454+
if _, exists := bMap[i]; !exists {
455+
r = append(r, i)
456+
}
457+
}
458+
return r
459+
}

controllers/helmrepository_controller_oci_test.go

+22
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package controllers
1919
import (
2020
"encoding/base64"
2121
"fmt"
22+
"strconv"
2223
"testing"
2324

2425
. "github.com/onsi/gomega"
@@ -320,3 +321,24 @@ func TestHelmRepositoryOCIReconciler_authStrategy(t *testing.T) {
320321
})
321322
}
322323
}
324+
325+
func TestConditionsDiff(t *testing.T) {
326+
tests := []struct {
327+
a, b, want []string
328+
}{
329+
{[]string{"a", "b", "c"}, []string{"b", "d"}, []string{"a", "c"}},
330+
{[]string{"a", "b", "c"}, []string{}, []string{"a", "b", "c"}},
331+
{[]string{}, []string{"b", "d"}, []string{}},
332+
{[]string{}, []string{}, []string{}},
333+
{[]string{"a", "b"}, nil, []string{"a", "b"}},
334+
{nil, []string{"a", "b"}, []string{}},
335+
{nil, nil, []string{}},
336+
}
337+
338+
for i, tt := range tests {
339+
t.Run(strconv.Itoa(i), func(t *testing.T) {
340+
g := NewWithT(t)
341+
g.Expect(conditionsDiff(tt.a, tt.b)).To(Equal(tt.want))
342+
})
343+
}
344+
}

0 commit comments

Comments
 (0)