Skip to content

Commit 893cdb4

Browse files
committed
Refactor BootstrapConfig/InfraMachine managedFields for in-place
1 parent f0d3d3e commit 893cdb4

File tree

12 files changed

+1108
-371
lines changed

12 files changed

+1108
-371
lines changed

controlplane/kubeadm/controllers/alias.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
// KubeadmControlPlaneReconciler reconciles a KubeadmControlPlane object.
3434
type KubeadmControlPlaneReconciler struct {
3535
Client client.Client
36+
APIReader client.Reader
3637
SecretCachingClient client.Client
3738
RuntimeClient runtimeclient.Client
3839
ClusterCache clustercache.ClusterCache
@@ -51,6 +52,7 @@ type KubeadmControlPlaneReconciler struct {
5152
func (r *KubeadmControlPlaneReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error {
5253
return (&kubeadmcontrolplanecontrollers.KubeadmControlPlaneReconciler{
5354
Client: r.Client,
55+
APIReader: r.APIReader,
5456
SecretCachingClient: r.SecretCachingClient,
5557
RuntimeClient: r.RuntimeClient,
5658
ClusterCache: r.ClusterCache,

controlplane/kubeadm/internal/controllers/controller.go

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ import (
4848
"sigs.k8s.io/cluster-api/controlplane/kubeadm/internal"
4949
runtimeclient "sigs.k8s.io/cluster-api/exp/runtime/client"
5050
"sigs.k8s.io/cluster-api/feature"
51-
"sigs.k8s.io/cluster-api/internal/contract"
5251
"sigs.k8s.io/cluster-api/internal/util/ssa"
5352
"sigs.k8s.io/cluster-api/util"
5453
"sigs.k8s.io/cluster-api/util/cache"
@@ -66,6 +65,7 @@ import (
6665

6766
const (
6867
kcpManagerName = "capi-kubeadmcontrolplane"
68+
kcpMetadataManagerName = "capi-kubeadmcontrolplane-metadata"
6969
kubeadmControlPlaneKind = "KubeadmControlPlane"
7070
)
7171

@@ -80,6 +80,7 @@ const (
8080
// KubeadmControlPlaneReconciler reconciles a KubeadmControlPlane object.
8181
type KubeadmControlPlaneReconciler struct {
8282
Client client.Client
83+
APIReader client.Reader
8384
SecretCachingClient client.Client
8485
RuntimeClient runtimeclient.Client
8586
controller controller.Controller
@@ -106,6 +107,9 @@ type KubeadmControlPlaneReconciler struct {
106107
overridePreflightChecksFunc func(ctx context.Context, controlPlane *internal.ControlPlane, excludeFor ...*clusterv1.Machine) ctrl.Result
107108
overrideCanUpdateMachineFunc func(ctx context.Context, machine *clusterv1.Machine, machineUpToDateResult internal.UpToDateResult) (bool, error)
108109
overrideCanExtensionsUpdateMachine func(ctx context.Context, machine *clusterv1.Machine, machineUpToDateResult internal.UpToDateResult, extensionHandlers []string) (bool, []string, error)
110+
// Note: This field is only used for unit tests that use fake client because the fake client does not properly set resourceVersion
111+
// on BootstrapConfig/InfraMachine after ssa.Patch and then ssa.RemoveManagedFieldsForLabelsAndAnnotations would fail.
112+
disableRemoveManagedFieldsForLabelsAndAnnotations bool
109113
}
110114

111115
func (r *KubeadmControlPlaneReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error {
@@ -857,23 +861,15 @@ func (r *KubeadmControlPlaneReconciler) syncMachines(ctx context.Context, contro
857861
}
858862
patchHelpers[machineName] = patchHelper
859863

860-
labelsAndAnnotationsManagedFieldPaths := []contract.Path{
861-
{"f:metadata", "f:annotations"},
862-
{"f:metadata", "f:labels"},
863-
}
864864
infraMachine, infraMachineFound := controlPlane.InfraResources[machineName]
865865
// Only update the InfraMachine if it is already found, otherwise just skip it.
866866
// This could happen e.g. if the cache is not up-to-date yet.
867867
if infraMachineFound {
868-
// Cleanup managed fields of all InfrastructureMachines to drop ownership of labels and annotations
869-
// from "manager". We do this so that InfrastructureMachines that are created using the Create method
870-
// can also work with SSA. Otherwise, labels and annotations would be co-owned by our "old" "manager"
871-
// and "capi-kubeadmcontrolplane" and then we would not be able to e.g. drop labels and annotations.
872-
if err := ssa.DropManagedFields(ctx, r.Client, infraMachine, kcpManagerName, labelsAndAnnotationsManagedFieldPaths); err != nil {
868+
if err := ssa.MigrateManagedFields(ctx, r.Client, infraMachine, kcpManagerName, kcpMetadataManagerName); err != nil {
873869
return errors.Wrapf(err, "failed to clean up managedFields of InfrastructureMachine %s", klog.KObj(infraMachine))
874870
}
875871
// Update in-place mutating fields on InfrastructureMachine.
876-
if err := r.updateExternalObject(ctx, infraMachine, infraMachine.GroupVersionKind(), controlPlane.KCP, controlPlane.Cluster); err != nil {
872+
if err := r.updateLabelsAndAnnotations(ctx, infraMachine, infraMachine.GroupVersionKind(), controlPlane.KCP, controlPlane.Cluster); err != nil {
877873
return errors.Wrapf(err, "failed to update InfrastructureMachine %s", klog.KObj(infraMachine))
878874
}
879875
}
@@ -882,15 +878,11 @@ func (r *KubeadmControlPlaneReconciler) syncMachines(ctx context.Context, contro
882878
// Only update the KubeadmConfig if it is already found, otherwise just skip it.
883879
// This could happen e.g. if the cache is not up-to-date yet.
884880
if kubeadmConfigFound {
885-
// Cleanup managed fields of all KubeadmConfigs to drop ownership of labels and annotations
886-
// from "manager". We do this so that KubeadmConfigs that are created using the Create method
887-
// can also work with SSA. Otherwise, labels and annotations would be co-owned by our "old" "manager"
888-
// and "capi-kubeadmcontrolplane" and then we would not be able to e.g. drop labels and annotations.
889-
if err := ssa.DropManagedFields(ctx, r.Client, kubeadmConfig, kcpManagerName, labelsAndAnnotationsManagedFieldPaths); err != nil {
881+
if err := ssa.MigrateManagedFields(ctx, r.Client, kubeadmConfig, kcpManagerName, kcpMetadataManagerName); err != nil {
890882
return errors.Wrapf(err, "failed to clean up managedFields of KubeadmConfig %s", klog.KObj(kubeadmConfig))
891883
}
892884
// Update in-place mutating fields on BootstrapConfig.
893-
if err := r.updateExternalObject(ctx, kubeadmConfig, bootstrapv1.GroupVersion.WithKind("KubeadmConfig"), controlPlane.KCP, controlPlane.Cluster); err != nil {
885+
if err := r.updateLabelsAndAnnotations(ctx, kubeadmConfig, bootstrapv1.GroupVersion.WithKind("KubeadmConfig"), controlPlane.KCP, controlPlane.Cluster); err != nil {
894886
return errors.Wrapf(err, "failed to update KubeadmConfig %s", klog.KObj(kubeadmConfig))
895887
}
896888
}

controlplane/kubeadm/internal/controllers/controller_test.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,10 @@ import (
3333
"github.com/pkg/errors"
3434
appsv1 "k8s.io/api/apps/v1"
3535
corev1 "k8s.io/api/core/v1"
36+
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
3637
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3738
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
39+
"k8s.io/apimachinery/pkg/runtime"
3840
"k8s.io/apimachinery/pkg/types"
3941
"k8s.io/apimachinery/pkg/util/intstr"
4042
"k8s.io/client-go/tools/clientcmd"
@@ -3923,9 +3925,17 @@ func TestObjectsPendingDelete(t *testing.T) {
39233925
// test utils.
39243926

39253927
func newFakeClient(initObjs ...client.Object) client.WithWatch {
3928+
// Use a new scheme to avoid side effects if multiple tests are sharing the same global scheme.
3929+
scheme := runtime.NewScheme()
3930+
_ = appsv1.AddToScheme(scheme)
3931+
_ = corev1.AddToScheme(scheme)
3932+
_ = apiextensionsv1.AddToScheme(scheme)
3933+
_ = clusterv1.AddToScheme(scheme)
3934+
_ = bootstrapv1.AddToScheme(scheme)
3935+
_ = controlplanev1.AddToScheme(scheme)
39263936
return &fakeClient{
39273937
startTime: time.Now(),
3928-
WithWatch: fake.NewClientBuilder().WithObjects(initObjs...).WithStatusSubresource(&controlplanev1.KubeadmControlPlane{}).Build(),
3938+
WithWatch: fake.NewClientBuilder().WithScheme(scheme).WithObjects(initObjs...).WithStatusSubresource(&controlplanev1.KubeadmControlPlane{}).Build(),
39293939
}
39303940
}
39313941

controlplane/kubeadm/internal/controllers/helpers.go

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -234,10 +234,18 @@ func (r *KubeadmControlPlaneReconciler) createInfraMachine(ctx context.Context,
234234
return nil, clusterv1.ContractVersionedObjectReference{}, errors.Wrapf(err, "failed to create InfraMachine")
235235
}
236236

237-
if err := r.Client.Create(ctx, infraMachine); err != nil {
237+
if err := ssa.Patch(ctx, r.Client, kcpManagerName, infraMachine); err != nil {
238238
return nil, clusterv1.ContractVersionedObjectReference{}, errors.Wrapf(err, "failed to create InfraMachine")
239239
}
240240

241+
// Note: This field is only used for unit tests that use fake client because the fake client does not properly set resourceVersion
242+
// on BootstrapConfig/InfraMachine after ssa.Patch and then ssa.RemoveManagedFieldsForLabelsAndAnnotations would fail.
243+
if !r.disableRemoveManagedFieldsForLabelsAndAnnotations {
244+
if err := ssa.RemoveManagedFieldsForLabelsAndAnnotations(ctx, r.Client, r.APIReader, infraMachine, kcpManagerName); err != nil {
245+
return nil, clusterv1.ContractVersionedObjectReference{}, errors.Wrapf(err, "failed to create InfraMachine")
246+
}
247+
}
248+
241249
return infraMachine, clusterv1.ContractVersionedObjectReference{
242250
APIGroup: infraMachine.GroupVersionKind().Group,
243251
Kind: infraMachine.GetKind(),
@@ -251,19 +259,27 @@ func (r *KubeadmControlPlaneReconciler) createKubeadmConfig(ctx context.Context,
251259
return nil, clusterv1.ContractVersionedObjectReference{}, errors.Wrapf(err, "failed to create KubeadmConfig")
252260
}
253261

254-
if err := r.Client.Create(ctx, kubeadmConfig); err != nil {
262+
if err := ssa.Patch(ctx, r.Client, kcpManagerName, kubeadmConfig); err != nil {
255263
return nil, clusterv1.ContractVersionedObjectReference{}, errors.Wrapf(err, "failed to create KubeadmConfig")
256264
}
257265

266+
// Note: This field is only used for unit tests that use fake client because the fake client does not properly set resourceVersion
267+
// on BootstrapConfig/InfraMachine after ssa.Patch and then ssa.RemoveManagedFieldsForLabelsAndAnnotations would fail.
268+
if !r.disableRemoveManagedFieldsForLabelsAndAnnotations {
269+
if err := ssa.RemoveManagedFieldsForLabelsAndAnnotations(ctx, r.Client, r.APIReader, kubeadmConfig, kcpManagerName); err != nil {
270+
return nil, clusterv1.ContractVersionedObjectReference{}, errors.Wrapf(err, "failed to create KubeadmConfig")
271+
}
272+
}
273+
258274
return kubeadmConfig, clusterv1.ContractVersionedObjectReference{
259275
APIGroup: bootstrapv1.GroupVersion.Group,
260276
Kind: "KubeadmConfig",
261277
Name: kubeadmConfig.GetName(),
262278
}, nil
263279
}
264280

265-
// updateExternalObject updates the external object with the labels and annotations from KCP.
266-
func (r *KubeadmControlPlaneReconciler) updateExternalObject(ctx context.Context, obj client.Object, objGVK schema.GroupVersionKind, kcp *controlplanev1.KubeadmControlPlane, cluster *clusterv1.Cluster) error {
281+
// updateLabelsAndAnnotations updates the external object with the labels and annotations from KCP.
282+
func (r *KubeadmControlPlaneReconciler) updateLabelsAndAnnotations(ctx context.Context, obj client.Object, objGVK schema.GroupVersionKind, kcp *controlplanev1.KubeadmControlPlane, cluster *clusterv1.Cluster) error {
267283
updatedObject := &unstructured.Unstructured{}
268284
updatedObject.SetGroupVersionKind(objGVK)
269285
updatedObject.SetNamespace(obj.GetNamespace())
@@ -277,7 +293,7 @@ func (r *KubeadmControlPlaneReconciler) updateExternalObject(ctx context.Context
277293
// Update annotations
278294
updatedObject.SetAnnotations(desiredstate.ControlPlaneMachineAnnotations(kcp))
279295

280-
return ssa.Patch(ctx, r.Client, kcpManagerName, updatedObject, ssa.WithCachingProxy{Cache: r.ssaCache, Original: obj})
296+
return ssa.Patch(ctx, r.Client, kcpMetadataManagerName, updatedObject, ssa.WithCachingProxy{Cache: r.ssaCache, Original: obj})
281297
}
282298

283299
func (r *KubeadmControlPlaneReconciler) createMachine(ctx context.Context, kcp *controlplanev1.KubeadmControlPlane, machine *clusterv1.Machine) error {

0 commit comments

Comments
 (0)