From 38541078fab303dc642242ad935bd88fbe6ea70a Mon Sep 17 00:00:00 2001 From: Stefan Prodan Date: Sat, 8 Jan 2022 13:36:21 +0200 Subject: [PATCH 1/2] Revoke kubectl managed fields ownership Signed-off-by: Stefan Prodan --- .github/workflows/e2e.yaml | 23 ++++++++++-- config/testdata/managed-fields/podinfo.yaml | 23 ++++++++++++ controllers/kustomization_controller.go | 40 +++++++++++++++++++-- 3 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 config/testdata/managed-fields/podinfo.yaml diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index 2a8efd03..1ed96aa5 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -22,8 +22,6 @@ jobs: - name: Setup Docker Buildx id: buildx uses: docker/setup-buildx-action@v1 - with: - buildkitd-flags: "--debug" - name: Restore Go cache uses: actions/cache@v1 with: @@ -97,6 +95,27 @@ jobs: make dev-deploy IMG=test/kustomize-controller:latest kubectl -n kustomize-system rollout status deploy/source-controller --timeout=1m kubectl -n kustomize-system rollout status deploy/kustomize-controller --timeout=1m + - name: Run tests for removing kubectl managed fields + run: | + kubectl create ns managed-fields + kustomize build github.com/stefanprodan/podinfo//kustomize?ref=6.0.0 > /tmp/podinfo.yaml + kubectl -n managed-fields apply -f /tmp/podinfo.yaml + kubectl -n managed-fields apply -f ./config/testdata/managed-fields + kubectl -n managed-fields wait kustomization/podinfo --for=condition=ready --timeout=4m + OUTDATA=$(kubectl -n managed-fields get deploy podinfo --show-managed-fields -oyaml) + if echo "$OUTDATA" | grep -q "kubectl";then + echo "kubectl client-side manager not removed" + exit 1 + fi + kubectl -n managed-fields apply --server-side --force-conflicts -f /tmp/podinfo.yaml + kubectl -n managed-fields annotate --overwrite kustomization/podinfo reconcile.fluxcd.io/requestedAt="$(date +%s)" + kubectl -n managed-fields wait kustomization/podinfo --for=condition=ready --timeout=4m + OUTDATA=$(kubectl -n managed-fields get deploy podinfo --show-managed-fields -oyaml) + if echo "$OUTDATA" | grep -q "kubectl";then + echo "kubectl server-side manager not removed" + exit 1 + fi + kubectl delete ns managed-fields - name: Run overlays tests run: | kubectl -n kustomize-system apply -k ./config/testdata/overlays diff --git a/config/testdata/managed-fields/podinfo.yaml b/config/testdata/managed-fields/podinfo.yaml new file mode 100644 index 00000000..1f065fc0 --- /dev/null +++ b/config/testdata/managed-fields/podinfo.yaml @@ -0,0 +1,23 @@ +apiVersion: kustomize.toolkit.fluxcd.io/v1beta2 +kind: Kustomization +metadata: + name: podinfo +spec: + interval: 15m + path: "./kustomize/" + prune: true + sourceRef: + kind: GitRepository + name: podinfo + timeout: 1m + targetNamespace: managed-fields +--- +apiVersion: source.toolkit.fluxcd.io/v1beta1 +kind: GitRepository +metadata: + name: podinfo +spec: + interval: 5m + url: https://github.com/stefanprodan/podinfo + ref: + semver: "6.0.0" diff --git a/controllers/kustomization_controller.go b/controllers/kustomization_controller.go index 1bd6eea6..32cdb9ae 100644 --- a/controllers/kustomization_controller.go +++ b/controllers/kustomization_controller.go @@ -32,6 +32,7 @@ import ( securejoin "github.com/cyphar/filepath-securejoin" "github.com/hashicorp/go-retryablehttp" + corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" apimeta "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -709,6 +710,41 @@ func (r *KustomizationReconciler) apply(ctx context.Context, manager *ssa.Resour applyOpts.Exclusions = map[string]string{ fmt.Sprintf("%s/reconcile", kustomizev1.GroupVersion.Group): kustomizev1.DisabledValue, } + applyOpts.Cleanup = ssa.ApplyCleanupOptions{ + Annotations: []string{ + // remove the kubectl annotation + corev1.LastAppliedConfigAnnotation, + // remove deprecated fluxcd.io annotations + "kustomize.toolkit.fluxcd.io/checksum", + "fluxcd.io/sync-checksum", + }, + Labels: []string{ + // remove deprecated fluxcd.io labels + "fluxcd.io/sync-gc-mark", + }, + FieldManagers: []ssa.FieldManager{ + { + // to undo changes made with 'kubectl apply --server-side --force-conflicts' + Name: "kubectl", + OperationType: metav1.ManagedFieldsOperationApply, + }, + { + // to undo changes made with 'kubectl apply' + Name: "kubectl", + OperationType: metav1.ManagedFieldsOperationUpdate, + }, + { + // to undo changes made with 'kubectl apply' + Name: "before-first-apply", + OperationType: metav1.ManagedFieldsOperationUpdate, + }, + { + // to undo changes made by the controller before SSA + Name: r.ControllerName, + OperationType: metav1.ManagedFieldsOperationUpdate, + }, + }, + } // contains only CRDs and Namespaces var stageOne []*unstructured.Unstructured @@ -924,7 +960,7 @@ func (r *KustomizationReconciler) finalize(ctx context.Context, kustomization ku // Remove our finalizer from the list and update it controllerutil.RemoveFinalizer(&kustomization, kustomizev1.KustomizationFinalizer) - if err := r.Update(ctx, &kustomization); err != nil { + if err := r.Update(ctx, &kustomization, client.FieldOwner(r.ControllerName)); err != nil { return ctrl.Result{}, err } @@ -1022,5 +1058,5 @@ func (r *KustomizationReconciler) patchStatus(ctx context.Context, req ctrl.Requ patch := client.MergeFrom(kustomization.DeepCopy()) kustomization.Status = newStatus - return r.Status().Patch(ctx, &kustomization, patch) + return r.Status().Patch(ctx, &kustomization, patch, client.FieldOwner(r.ControllerName)) } From f353ba44a7f97a6a98801b9b2a0d7a142a941945 Mon Sep 17 00:00:00 2001 From: Stefan Prodan Date: Mon, 24 Jan 2022 16:00:59 +0200 Subject: [PATCH 2/2] Introduce a dedicated manager for status updates to avoid conflicts Signed-off-by: Stefan Prodan --- controllers/kustomization_controller.go | 10 +++++----- go.mod | 2 +- go.sum | 2 ++ 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/controllers/kustomization_controller.go b/controllers/kustomization_controller.go index 32cdb9ae..dc6f5198 100644 --- a/controllers/kustomization_controller.go +++ b/controllers/kustomization_controller.go @@ -86,6 +86,7 @@ type KustomizationReconciler struct { MetricsRecorder *metrics.Recorder StatusPoller *polling.StatusPoller ControllerName string + statusManager string NoCrossNamespaceRefs bool DefaultServiceAccount string } @@ -116,6 +117,7 @@ func (r *KustomizationReconciler) SetupWithManager(mgr ctrl.Manager, opts Kustom } r.requeueDependency = opts.DependencyRequeueInterval + r.statusManager = fmt.Sprintf("gotk-%s", r.ControllerName) // Configure the retryable http client used for fetching artifacts. // By default it retries 10 times within a 3.5 minutes window. @@ -160,7 +162,7 @@ func (r *KustomizationReconciler) Reconcile(ctx context.Context, req ctrl.Reques if !controllerutil.ContainsFinalizer(&kustomization, kustomizev1.KustomizationFinalizer) { patch := client.MergeFrom(kustomization.DeepCopy()) controllerutil.AddFinalizer(&kustomization, kustomizev1.KustomizationFinalizer) - if err := r.Patch(ctx, &kustomization, patch); err != nil { + if err := r.Patch(ctx, &kustomization, patch, client.FieldOwner(r.statusManager)); err != nil { log.Error(err, "unable to register finalizer") return ctrl.Result{}, err } @@ -584,7 +586,6 @@ func (r *KustomizationReconciler) getSource(ctx context.Context, kustomization k if kustomization.Spec.SourceRef.Namespace != "" { sourceNamespace = kustomization.Spec.SourceRef.Namespace } - namespacedName := types.NamespacedName{ Namespace: sourceNamespace, Name: kustomization.Spec.SourceRef.Name, @@ -960,7 +961,7 @@ func (r *KustomizationReconciler) finalize(ctx context.Context, kustomization ku // Remove our finalizer from the list and update it controllerutil.RemoveFinalizer(&kustomization, kustomizev1.KustomizationFinalizer) - if err := r.Update(ctx, &kustomization, client.FieldOwner(r.ControllerName)); err != nil { + if err := r.Update(ctx, &kustomization, client.FieldOwner(r.statusManager)); err != nil { return ctrl.Result{}, err } @@ -1057,6 +1058,5 @@ func (r *KustomizationReconciler) patchStatus(ctx context.Context, req ctrl.Requ patch := client.MergeFrom(kustomization.DeepCopy()) kustomization.Status = newStatus - - return r.Status().Patch(ctx, &kustomization, patch, client.FieldOwner(r.ControllerName)) + return r.Status().Patch(ctx, &kustomization, patch, client.FieldOwner(r.statusManager)) } diff --git a/go.mod b/go.mod index b1e29069..7f574f4d 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/fluxcd/pkg/apis/kustomize v0.3.1 github.com/fluxcd/pkg/apis/meta v0.10.2 github.com/fluxcd/pkg/runtime v0.12.4 - github.com/fluxcd/pkg/ssa v0.11.1 + github.com/fluxcd/pkg/ssa v0.12.0 github.com/fluxcd/pkg/testserver v0.2.0 github.com/fluxcd/pkg/untar v0.1.0 github.com/fluxcd/source-controller/api v0.20.1 diff --git a/go.sum b/go.sum index bdb7e281..23ee5fc1 100644 --- a/go.sum +++ b/go.sum @@ -257,6 +257,8 @@ github.com/fluxcd/pkg/runtime v0.12.4 h1:gA27RG/+adN2/7Qe03PB46Iwmye/MusPCpuS4zQ github.com/fluxcd/pkg/runtime v0.12.4/go.mod h1:gspNvhAqodZgSmK1ZhMtvARBf/NGAlxmaZaIOHkJYsc= github.com/fluxcd/pkg/ssa v0.11.1 h1:iZMMe6Pdgt/sv3pZPJ5y4oRDa+8IXHbpPYgpjEmaq/8= github.com/fluxcd/pkg/ssa v0.11.1/go.mod h1:S+qig7BTOxop0c134y8Yv8/iQST4Kt7S2xXiFkP4VMA= +github.com/fluxcd/pkg/ssa v0.12.0 h1:7nF4UigU9Zk/9P/nbzUP3ah8IRC+BpB64O9iu5VnvEo= +github.com/fluxcd/pkg/ssa v0.12.0/go.mod h1:S+qig7BTOxop0c134y8Yv8/iQST4Kt7S2xXiFkP4VMA= github.com/fluxcd/pkg/testserver v0.2.0 h1:Mj0TapmKaywI6Fi5wvt1LAZpakUHmtzWQpJNKQ0Krt4= github.com/fluxcd/pkg/testserver v0.2.0/go.mod h1:bgjjydkXsZTeFzjz9Cr4heGANr41uTB1Aj1Q5qzuYVk= github.com/fluxcd/pkg/untar v0.1.0 h1:k97V/xV5hFrAkIkVPuv5AVhyxh1ZzzAKba/lbDfGo6o=