Skip to content

Commit 8c6e1b4

Browse files
committed
patch: Call patchHelper only if necessary when reconciling external refs
Signed-off-by: Stefan Büringer [email protected]
1 parent 199edc1 commit 8c6e1b4

File tree

8 files changed

+133
-47
lines changed

8 files changed

+133
-47
lines changed

.golangci.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ linters:
2727
- errchkjson
2828
- gci
2929
- ginkgolinter
30-
- goconst
3130
- gocritic
3231
- godot
3332
- gofmt

controlplane/kubeadm/internal/controllers/helpers.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -147,17 +147,23 @@ func (r *KubeadmControlPlaneReconciler) reconcileExternalReference(ctx context.C
147147

148148
// Note: We intentionally do not handle checking for the paused label on an external template reference
149149

150+
desiredOwnerRef := metav1.OwnerReference{
151+
APIVersion: clusterv1.GroupVersion.String(),
152+
Kind: "Cluster",
153+
Name: cluster.Name,
154+
UID: cluster.UID,
155+
}
156+
157+
if util.HasExactOwnerRef(obj.GetOwnerReferences(), desiredOwnerRef) {
158+
return nil
159+
}
160+
150161
patchHelper, err := patch.NewHelper(obj, r.Client)
151162
if err != nil {
152163
return err
153164
}
154165

155-
obj.SetOwnerReferences(util.EnsureOwnerRef(obj.GetOwnerReferences(), metav1.OwnerReference{
156-
APIVersion: clusterv1.GroupVersion.String(),
157-
Kind: "Cluster",
158-
Name: cluster.Name,
159-
UID: cluster.UID,
160-
}))
166+
obj.SetOwnerReferences(util.EnsureOwnerRef(obj.GetOwnerReferences(), desiredOwnerRef))
161167

162168
return patchHelper.Patch(ctx, obj)
163169
}

internal/controllers/cluster/cluster_controller_phases.go

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,11 @@ import (
2424
"github.com/pkg/errors"
2525
corev1 "k8s.io/api/core/v1"
2626
apierrors "k8s.io/apimachinery/pkg/api/errors"
27+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2729
"k8s.io/utils/ptr"
2830
ctrl "sigs.k8s.io/controller-runtime"
31+
"sigs.k8s.io/controller-runtime/pkg/client"
2932
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
3033
"sigs.k8s.io/controller-runtime/pkg/handler"
3134

@@ -103,27 +106,7 @@ func (r *Reconciler) reconcileExternal(ctx context.Context, cluster *clusterv1.C
103106
return external.ReconcileOutput{Paused: true}, nil
104107
}
105108

106-
// Initialize the patch helper.
107-
patchHelper, err := patch.NewHelper(obj, r.Client)
108-
if err != nil {
109-
return external.ReconcileOutput{}, err
110-
}
111-
112-
// Set external object ControllerReference to the Cluster.
113-
if err := controllerutil.SetControllerReference(cluster, obj, r.Client.Scheme()); err != nil {
114-
return external.ReconcileOutput{}, err
115-
}
116-
117-
// Set the Cluster label.
118-
labels := obj.GetLabels()
119-
if labels == nil {
120-
labels = make(map[string]string)
121-
}
122-
labels[clusterv1.ClusterNameLabel] = cluster.Name
123-
obj.SetLabels(labels)
124-
125-
// Always attempt to Patch the external object.
126-
if err := patchHelper.Patch(ctx, obj); err != nil {
109+
if err := ensureOwnerRefAndLabel(ctx, r.Client, obj, cluster); err != nil {
127110
return external.ReconcileOutput{}, err
128111
}
129112

@@ -146,6 +129,38 @@ func (r *Reconciler) reconcileExternal(ctx context.Context, cluster *clusterv1.C
146129
return external.ReconcileOutput{Result: obj}, nil
147130
}
148131

132+
func ensureOwnerRefAndLabel(ctx context.Context, c client.Client, obj *unstructured.Unstructured, cluster *clusterv1.Cluster) error {
133+
desiredOwnerRef := metav1.OwnerReference{
134+
APIVersion: clusterv1.GroupVersion.String(),
135+
Kind: "Cluster",
136+
Name: cluster.Name,
137+
Controller: ptr.To(true),
138+
}
139+
140+
if util.HasExactOwnerRef(obj.GetOwnerReferences(), desiredOwnerRef) &&
141+
obj.GetLabels()[clusterv1.ClusterNameLabel] == cluster.Name {
142+
return nil
143+
}
144+
145+
patchHelper, err := patch.NewHelper(obj, c)
146+
if err != nil {
147+
return err
148+
}
149+
150+
if err := controllerutil.SetControllerReference(cluster, obj, c.Scheme()); err != nil {
151+
return err
152+
}
153+
154+
labels := obj.GetLabels()
155+
if labels == nil {
156+
labels = make(map[string]string)
157+
}
158+
labels[clusterv1.ClusterNameLabel] = cluster.Name
159+
obj.SetLabels(labels)
160+
161+
return patchHelper.Patch(ctx, obj)
162+
}
163+
149164
// reconcileInfrastructure reconciles the Spec.InfrastructureRef object on a Cluster.
150165
func (r *Reconciler) reconcileInfrastructure(ctx context.Context, cluster *clusterv1.Cluster) (ctrl.Result, error) {
151166
log := ctrl.LoggerFrom(ctx)

internal/controllers/clusterclass/clusterclass_controller.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import (
4848
tlog "sigs.k8s.io/cluster-api/internal/log"
4949
internalruntimeclient "sigs.k8s.io/cluster-api/internal/runtime/client"
5050
"sigs.k8s.io/cluster-api/internal/topology/variables"
51+
"sigs.k8s.io/cluster-api/util"
5152
"sigs.k8s.io/cluster-api/util/annotations"
5253
"sigs.k8s.io/cluster-api/util/cache"
5354
"sigs.k8s.io/cluster-api/util/conditions"
@@ -396,18 +397,25 @@ func (r *Reconciler) reconcileExternal(ctx context.Context, clusterClass *cluste
396397
return nil
397398
}
398399

399-
// Initialize the patch helper.
400+
desiredOwnerRef := metav1.OwnerReference{
401+
APIVersion: clusterv1.GroupVersion.String(),
402+
Kind: "ClusterClass",
403+
Name: clusterClass.Name,
404+
}
405+
406+
if util.HasExactOwnerRef(obj.GetOwnerReferences(), desiredOwnerRef) {
407+
return nil
408+
}
409+
400410
patchHelper, err := patch.NewHelper(obj, r.Client)
401411
if err != nil {
402412
return err
403413
}
404414

405-
// Set external object ControllerReference to the ClusterClass.
406415
if err := controllerutil.SetOwnerReference(clusterClass, obj, r.Client.Scheme()); err != nil {
407416
return errors.Wrapf(err, "failed to set ClusterClass owner reference for %s", tlog.KObj{Obj: obj})
408417
}
409418

410-
// Patch the external object.
411419
return patchHelper.Patch(ctx, obj)
412420
}
413421

internal/controllers/machine/machine_controller_phases.go

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,24 @@ func (r *Reconciler) ensureExternalOwnershipAndWatch(ctx context.Context, cluste
145145
return external.ReconcileOutput{Paused: true}, nil
146146
}
147147

148-
// Initialize the patch helper.
148+
desiredOwnerRef := metav1.OwnerReference{
149+
APIVersion: clusterv1.GroupVersion.String(),
150+
Kind: "Machine",
151+
Name: m.Name,
152+
Controller: ptr.To(true),
153+
}
154+
155+
hasOnCreateOwnerRefs, err := hasOnCreateOwnerRefs(cluster, m, obj)
156+
if err != nil {
157+
return external.ReconcileOutput{}, err
158+
}
159+
160+
if !hasOnCreateOwnerRefs &&
161+
util.HasExactOwnerRef(obj.GetOwnerReferences(), desiredOwnerRef) &&
162+
obj.GetLabels()[clusterv1.ClusterNameLabel] == m.Spec.ClusterName {
163+
return external.ReconcileOutput{Result: obj}, nil
164+
}
165+
149166
patchHelper, err := patch.NewHelper(obj, r.Client)
150167
if err != nil {
151168
return external.ReconcileOutput{}, err
@@ -163,15 +180,13 @@ func (r *Reconciler) ensureExternalOwnershipAndWatch(ctx context.Context, cluste
163180
return external.ReconcileOutput{}, err
164181
}
165182

166-
// Set the Cluster label.
167183
labels := obj.GetLabels()
168184
if labels == nil {
169185
labels = make(map[string]string)
170186
}
171187
labels[clusterv1.ClusterNameLabel] = m.Spec.ClusterName
172188
obj.SetLabels(labels)
173189

174-
// Always attempt to Patch the external object.
175190
if err := patchHelper.Patch(ctx, obj); err != nil {
176191
return external.ReconcileOutput{}, err
177192
}
@@ -388,7 +403,7 @@ func removeOnCreateOwnerRefs(cluster *clusterv1.Cluster, m *clusterv1.Machine, o
388403
for _, owner := range obj.GetOwnerReferences() {
389404
ownerGV, err := schema.ParseGroupVersion(owner.APIVersion)
390405
if err != nil {
391-
return errors.Wrapf(err, "Could not remove ownerReference %v from object %s/%s", owner.String(), obj.GetKind(), obj.GetName())
406+
return errors.Wrapf(err, "could not remove ownerReference %v from object %s/%s", owner.String(), obj.GetKind(), obj.GetName())
392407
}
393408
if (ownerGV.Group == clusterv1.GroupVersion.Group && owner.Kind == "MachineSet") ||
394409
(cpGVK != nil && ownerGV.Group == cpGVK.GroupVersion().Group && owner.Kind == cpGVK.Kind) {
@@ -399,6 +414,22 @@ func removeOnCreateOwnerRefs(cluster *clusterv1.Cluster, m *clusterv1.Machine, o
399414
return nil
400415
}
401416

417+
// hasOnCreateOwnerRefs will check if any MachineSet or control plane owner references from passed objects are set.
418+
func hasOnCreateOwnerRefs(cluster *clusterv1.Cluster, m *clusterv1.Machine, obj *unstructured.Unstructured) (bool, error) {
419+
cpGVK := getControlPlaneGVKForMachine(cluster, m)
420+
for _, owner := range obj.GetOwnerReferences() {
421+
ownerGV, err := schema.ParseGroupVersion(owner.APIVersion)
422+
if err != nil {
423+
return false, errors.Wrapf(err, "could not remove ownerReference %v from object %s/%s", owner.String(), obj.GetKind(), obj.GetName())
424+
}
425+
if (ownerGV.Group == clusterv1.GroupVersion.Group && owner.Kind == "MachineSet") ||
426+
(cpGVK != nil && ownerGV.Group == cpGVK.GroupVersion().Group && owner.Kind == cpGVK.Kind) {
427+
return true, nil
428+
}
429+
}
430+
return false, nil
431+
}
432+
402433
// getControlPlaneGVKForMachine returns the Kind of the control plane in the Cluster associated with the Machine.
403434
// This function checks that the Machine is managed by a control plane, and then retrieves the Kind from the Cluster's
404435
// .spec.controlPlaneRef.

internal/controllers/machinedeployment/machinedeployment_controller.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -424,17 +424,23 @@ func reconcileExternalTemplateReference(ctx context.Context, c client.Client, cl
424424
return err
425425
}
426426

427+
desiredOwnerRef := metav1.OwnerReference{
428+
APIVersion: clusterv1.GroupVersion.String(),
429+
Kind: "Cluster",
430+
Name: cluster.Name,
431+
UID: cluster.UID,
432+
}
433+
434+
if util.HasExactOwnerRef(obj.GetOwnerReferences(), desiredOwnerRef) {
435+
return nil
436+
}
437+
427438
patchHelper, err := patch.NewHelper(obj, c)
428439
if err != nil {
429440
return err
430441
}
431442

432-
obj.SetOwnerReferences(util.EnsureOwnerRef(obj.GetOwnerReferences(), metav1.OwnerReference{
433-
APIVersion: clusterv1.GroupVersion.String(),
434-
Kind: "Cluster",
435-
Name: cluster.Name,
436-
UID: cluster.UID,
437-
}))
443+
obj.SetOwnerReferences(util.EnsureOwnerRef(obj.GetOwnerReferences(), desiredOwnerRef))
438444

439445
return patchHelper.Patch(ctx, obj)
440446
}

internal/controllers/machineset/machineset_controller.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1171,17 +1171,23 @@ func (r *Reconciler) reconcileExternalTemplateReference(ctx context.Context, clu
11711171
return err
11721172
}
11731173

1174+
desiredOwnerRef := metav1.OwnerReference{
1175+
APIVersion: clusterv1.GroupVersion.String(),
1176+
Kind: "Cluster",
1177+
Name: cluster.Name,
1178+
UID: cluster.UID,
1179+
}
1180+
1181+
if util.HasExactOwnerRef(obj.GetOwnerReferences(), desiredOwnerRef) {
1182+
return nil
1183+
}
1184+
11741185
patchHelper, err := patch.NewHelper(obj, r.Client)
11751186
if err != nil {
11761187
return err
11771188
}
11781189

1179-
obj.SetOwnerReferences(util.EnsureOwnerRef(obj.GetOwnerReferences(), metav1.OwnerReference{
1180-
APIVersion: clusterv1.GroupVersion.String(),
1181-
Kind: "Cluster",
1182-
Name: cluster.Name,
1183-
UID: cluster.UID,
1184-
}))
1190+
obj.SetOwnerReferences(util.EnsureOwnerRef(obj.GetOwnerReferences(), desiredOwnerRef))
11851191

11861192
return patchHelper.Patch(ctx, obj)
11871193
}

util/util.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import (
3939
"k8s.io/apimachinery/pkg/runtime/schema"
4040
"k8s.io/apimachinery/pkg/types"
4141
k8sversion "k8s.io/apimachinery/pkg/version"
42+
"k8s.io/utils/ptr"
4243
ctrl "sigs.k8s.io/controller-runtime"
4344
"sigs.k8s.io/controller-runtime/pkg/client"
4445
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
@@ -334,6 +335,20 @@ func RemoveOwnerRef(ownerReferences []metav1.OwnerReference, inputRef metav1.Own
334335
return ownerReferences
335336
}
336337

338+
// HasExactOwnerRef returns true if the exact OwnerReference is already in the slice.
339+
// It matches based on APIVersion, Kind, Name and Controller.
340+
func HasExactOwnerRef(ownerReferences []metav1.OwnerReference, ref metav1.OwnerReference) bool {
341+
for _, r := range ownerReferences {
342+
if r.APIVersion == ref.APIVersion &&
343+
r.Kind == ref.Kind &&
344+
r.Name == ref.Name &&
345+
ptr.Deref(r.Controller, false) == ptr.Deref(ref.Controller, false) {
346+
return true
347+
}
348+
}
349+
return false
350+
}
351+
337352
// indexOwnerRef returns the index of the owner reference in the slice if found, or -1.
338353
func indexOwnerRef(ownerReferences []metav1.OwnerReference, ref metav1.OwnerReference) int {
339354
for index, r := range ownerReferences {

0 commit comments

Comments
 (0)