Skip to content

Commit ceefe5a

Browse files
authored
Merge pull request #552 from fluxcd/impersonation-finalize
Ensure object are finalized under impersonation
2 parents cd6fff0 + 65aaa1d commit ceefe5a

3 files changed

Lines changed: 60 additions & 7 deletions

File tree

controllers/kustomization_controller.go

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -922,13 +922,12 @@ func (r *KustomizationReconciler) finalize(ctx context.Context, kustomization ku
922922
objects, _ := ListObjectsInInventory(kustomization.Status.Inventory)
923923

924924
impersonation := NewKustomizeImpersonation(kustomization, r.Client, r.StatusPoller, r.DefaultServiceAccount)
925-
kubeClient, _, err := impersonation.GetClient(ctx)
926-
if err != nil {
927-
// when impersonation fails, log the stale objects and continue with the finalization
928-
msg := fmt.Sprintf("unable to prune objects: \n%s", ssa.FmtUnstructuredList(objects))
929-
log.Error(fmt.Errorf("failed to build kube client: %w", err), msg)
930-
r.event(ctx, kustomization, kustomization.Status.LastAppliedRevision, events.EventSeverityError, msg, nil)
931-
} else {
925+
if impersonation.CanFinalize(ctx) {
926+
kubeClient, _, err := impersonation.GetClient(ctx)
927+
if err != nil {
928+
return ctrl.Result{}, err
929+
}
930+
932931
resourceManager := ssa.NewResourceManager(kubeClient, nil, ssa.Owner{
933932
Field: r.ControllerName,
934933
Group: kustomizev1.GroupVersion.Group,
@@ -953,6 +952,11 @@ func (r *KustomizationReconciler) finalize(ctx context.Context, kustomization ku
953952
if changeSet != nil && len(changeSet.Entries) > 0 {
954953
r.event(ctx, kustomization, kustomization.Status.LastAppliedRevision, events.EventSeverityInfo, changeSet.String(), nil)
955954
}
955+
} else {
956+
// when the account to impersonate is gone, log the stale objects and continue with the finalization
957+
msg := fmt.Sprintf("unable to prune objects: \n%s", ssa.FmtUnstructuredList(objects))
958+
log.Error(fmt.Errorf("skiping pruning, failed to find account to impersonate"), msg)
959+
r.event(ctx, kustomization, kustomization.Status.LastAppliedRevision, events.EventSeverityError, msg, nil)
956960
}
957961
}
958962

controllers/kustomization_impersonation.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ package controllers
1919
import (
2020
"context"
2121
"fmt"
22+
2223
corev1 "k8s.io/api/core/v1"
24+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2325
"k8s.io/apimachinery/pkg/types"
2426
"k8s.io/client-go/rest"
2527
"k8s.io/client-go/tools/clientcmd"
@@ -69,6 +71,33 @@ func (ki *KustomizeImpersonation) GetClient(ctx context.Context) (client.Client,
6971
}
7072
}
7173

74+
// CanFinalize asserts if the given Kustomization can be finalized using impersonation.
75+
func (ki *KustomizeImpersonation) CanFinalize(ctx context.Context) bool {
76+
name := ki.defaultServiceAccount
77+
if sa := ki.kustomization.Spec.ServiceAccountName; sa != "" {
78+
name = sa
79+
}
80+
if name == "" {
81+
return true
82+
}
83+
84+
sa := &corev1.ServiceAccount{
85+
TypeMeta: metav1.TypeMeta{
86+
Kind: "ServiceAccount",
87+
APIVersion: "v1",
88+
},
89+
ObjectMeta: metav1.ObjectMeta{
90+
Name: name,
91+
Namespace: ki.kustomization.Namespace,
92+
},
93+
}
94+
if err := ki.Client.Get(ctx, client.ObjectKeyFromObject(sa), sa); err != nil {
95+
return false
96+
}
97+
98+
return true
99+
}
100+
72101
func (ki *KustomizeImpersonation) setImpersonationConfig(restConfig *rest.Config) {
73102
name := ki.defaultServiceAccount
74103
if sa := ki.kustomization.Spec.ServiceAccountName; sa != "" {

controllers/kustomization_impersonation_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
. "github.com/onsi/gomega"
3030
corev1 "k8s.io/api/core/v1"
3131
rbacv1 "k8s.io/api/rbac/v1"
32+
apierrors "k8s.io/apimachinery/pkg/api/errors"
3233
apimeta "k8s.io/apimachinery/pkg/api/meta"
3334
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3435
"k8s.io/apimachinery/pkg/types"
@@ -101,6 +102,7 @@ data:
101102
Kind: sourcev1.GitRepositoryKind,
102103
},
103104
TargetNamespace: id,
105+
Prune: true,
104106
},
105107
}
106108

@@ -187,4 +189,22 @@ data:
187189

188190
g.Expect(readyCondition.Reason).To(Equal(meta.ReconciliationSucceededReason))
189191
})
192+
193+
t.Run("can finalize impersonating service account", func(t *testing.T) {
194+
saK := &kustomizev1.Kustomization{}
195+
err = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), saK)
196+
g.Expect(err).NotTo(HaveOccurred())
197+
198+
err = k8sClient.Delete(context.Background(), saK)
199+
g.Expect(err).NotTo(HaveOccurred())
200+
201+
g.Eventually(func() bool {
202+
err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
203+
return apierrors.IsNotFound(err)
204+
}, timeout, time.Second).Should(BeTrue())
205+
206+
resultConfig := &corev1.ConfigMap{}
207+
err := k8sClient.Get(context.Background(), types.NamespacedName{Name: id, Namespace: id}, resultConfig)
208+
g.Expect(apierrors.IsNotFound(err)).To(BeTrue())
209+
})
190210
}

0 commit comments

Comments
 (0)