Skip to content

Commit 42bc3e8

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 75cde08 commit 42bc3e8

File tree

2 files changed

+54
-0
lines changed

2 files changed

+54
-0
lines changed

controllers/helmrepository_controller_oci.go

+32
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import (
4040
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
4141
"sigs.k8s.io/controller-runtime/pkg/predicate"
4242

43+
eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1"
4344
"github.com/fluxcd/pkg/apis/meta"
4445
"github.com/fluxcd/pkg/oci"
4546
"github.com/fluxcd/pkg/runtime/conditions"
@@ -82,6 +83,11 @@ type HelmRepositoryOCIReconciler struct {
8283
RegistryClientGenerator RegistryClientGeneratorFunc
8384

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

8793
// RegistryClientGeneratorFunc is a function that returns a registry client
@@ -95,6 +101,7 @@ func (r *HelmRepositoryOCIReconciler) SetupWithManager(mgr ctrl.Manager) error {
95101
}
96102

97103
func (r *HelmRepositoryOCIReconciler) SetupWithManagerAndOptions(mgr ctrl.Manager, opts HelmRepositoryReconcilerOptions) error {
104+
r.unmanagedConditions = conditionsDiff(helmRepositoryReadyCondition.Owned, helmRepositoryOCIOwnedConditions)
98105
r.patchOptions = getPatchOptions(helmRepositoryOCIOwnedConditions, r.ControllerName)
99106

100107
recoverPanic := true
@@ -124,6 +131,16 @@ func (r *HelmRepositoryOCIReconciler) Reconcile(ctx context.Context, req ctrl.Re
124131
return ctrl.Result{}, client.IgnoreNotFound(err)
125132
}
126133

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

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

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

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)