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>
This commit is contained in:
parent
75cde08ff0
commit
42bc3e8b0a
|
@ -40,6 +40,7 @@ import (
|
||||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||||
|
|
||||||
|
eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1"
|
||||||
"github.com/fluxcd/pkg/apis/meta"
|
"github.com/fluxcd/pkg/apis/meta"
|
||||||
"github.com/fluxcd/pkg/oci"
|
"github.com/fluxcd/pkg/oci"
|
||||||
"github.com/fluxcd/pkg/runtime/conditions"
|
"github.com/fluxcd/pkg/runtime/conditions"
|
||||||
|
@ -82,6 +83,11 @@ type HelmRepositoryOCIReconciler struct {
|
||||||
RegistryClientGenerator RegistryClientGeneratorFunc
|
RegistryClientGenerator RegistryClientGeneratorFunc
|
||||||
|
|
||||||
patchOptions []patch.Option
|
patchOptions []patch.Option
|
||||||
|
|
||||||
|
// unmanagedConditions are the conditions that are not managed by this
|
||||||
|
// reconciler and need to be removed from the object before taking ownership
|
||||||
|
// of the object being reconciled.
|
||||||
|
unmanagedConditions []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegistryClientGeneratorFunc is a function that returns a registry client
|
// RegistryClientGeneratorFunc is a function that returns a registry client
|
||||||
|
@ -95,6 +101,7 @@ func (r *HelmRepositoryOCIReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *HelmRepositoryOCIReconciler) SetupWithManagerAndOptions(mgr ctrl.Manager, opts HelmRepositoryReconcilerOptions) error {
|
func (r *HelmRepositoryOCIReconciler) SetupWithManagerAndOptions(mgr ctrl.Manager, opts HelmRepositoryReconcilerOptions) error {
|
||||||
|
r.unmanagedConditions = conditionsDiff(helmRepositoryReadyCondition.Owned, helmRepositoryOCIOwnedConditions)
|
||||||
r.patchOptions = getPatchOptions(helmRepositoryOCIOwnedConditions, r.ControllerName)
|
r.patchOptions = getPatchOptions(helmRepositoryOCIOwnedConditions, r.ControllerName)
|
||||||
|
|
||||||
recoverPanic := true
|
recoverPanic := true
|
||||||
|
@ -124,6 +131,16 @@ func (r *HelmRepositoryOCIReconciler) Reconcile(ctx context.Context, req ctrl.Re
|
||||||
return ctrl.Result{}, client.IgnoreNotFound(err)
|
return ctrl.Result{}, client.IgnoreNotFound(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the object contains any of the unmanaged conditions, requeue and wait
|
||||||
|
// for those conditions to be removed first before processing the object.
|
||||||
|
// NOTE: This will happen only when a HelmRepository's spec.type is switched
|
||||||
|
// from "default" to "oci".
|
||||||
|
if conditions.HasAny(obj, r.unmanagedConditions) {
|
||||||
|
r.eventLogf(ctx, obj, eventv1.EventTypeTrace, "IncompleteTransition",
|
||||||
|
"object contains conditions managed by other reconciler")
|
||||||
|
return ctrl.Result{RequeueAfter: time.Second}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Record suspended status metric
|
// Record suspended status metric
|
||||||
r.RecordSuspend(ctx, obj, obj.Spec.Suspend)
|
r.RecordSuspend(ctx, obj, obj.Spec.Suspend)
|
||||||
|
|
||||||
|
@ -428,3 +445,18 @@ func makeLoginOption(auth authn.Authenticator, keychain authn.Keychain, registry
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func conditionsDiff(a, b []string) []string {
|
||||||
|
bMap := make(map[string]struct{}, len(b))
|
||||||
|
for _, j := range b {
|
||||||
|
bMap[j] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
r := []string{}
|
||||||
|
for _, i := range a {
|
||||||
|
if _, exists := bMap[i]; !exists {
|
||||||
|
r = append(r, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ package controllers
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
@ -320,3 +321,24 @@ func TestHelmRepositoryOCIReconciler_authStrategy(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConditionsDiff(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
a, b, want []string
|
||||||
|
}{
|
||||||
|
{[]string{"a", "b", "c"}, []string{"b", "d"}, []string{"a", "c"}},
|
||||||
|
{[]string{"a", "b", "c"}, []string{}, []string{"a", "b", "c"}},
|
||||||
|
{[]string{}, []string{"b", "d"}, []string{}},
|
||||||
|
{[]string{}, []string{}, []string{}},
|
||||||
|
{[]string{"a", "b"}, nil, []string{"a", "b"}},
|
||||||
|
{nil, []string{"a", "b"}, []string{}},
|
||||||
|
{nil, nil, []string{}},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tt := range tests {
|
||||||
|
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
||||||
|
g := NewWithT(t)
|
||||||
|
g.Expect(conditionsDiff(tt.a, tt.b)).To(Equal(tt.want))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue