Ensure object are finalized under impersonation
If the service account used for impersonation has been deleted, skip pruning, log the error and continue with finalization to allow tenants removals from clusters. Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
This commit is contained in:
parent
cd6fff0220
commit
65aaa1d69a
|
@ -922,13 +922,12 @@ func (r *KustomizationReconciler) finalize(ctx context.Context, kustomization ku
|
|||
objects, _ := ListObjectsInInventory(kustomization.Status.Inventory)
|
||||
|
||||
impersonation := NewKustomizeImpersonation(kustomization, r.Client, r.StatusPoller, r.DefaultServiceAccount)
|
||||
if impersonation.CanFinalize(ctx) {
|
||||
kubeClient, _, err := impersonation.GetClient(ctx)
|
||||
if err != nil {
|
||||
// when impersonation fails, log the stale objects and continue with the finalization
|
||||
msg := fmt.Sprintf("unable to prune objects: \n%s", ssa.FmtUnstructuredList(objects))
|
||||
log.Error(fmt.Errorf("failed to build kube client: %w", err), msg)
|
||||
r.event(ctx, kustomization, kustomization.Status.LastAppliedRevision, events.EventSeverityError, msg, nil)
|
||||
} else {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
resourceManager := ssa.NewResourceManager(kubeClient, nil, ssa.Owner{
|
||||
Field: r.ControllerName,
|
||||
Group: kustomizev1.GroupVersion.Group,
|
||||
|
@ -953,6 +952,11 @@ func (r *KustomizationReconciler) finalize(ctx context.Context, kustomization ku
|
|||
if changeSet != nil && len(changeSet.Entries) > 0 {
|
||||
r.event(ctx, kustomization, kustomization.Status.LastAppliedRevision, events.EventSeverityInfo, changeSet.String(), nil)
|
||||
}
|
||||
} else {
|
||||
// when the account to impersonate is gone, log the stale objects and continue with the finalization
|
||||
msg := fmt.Sprintf("unable to prune objects: \n%s", ssa.FmtUnstructuredList(objects))
|
||||
log.Error(fmt.Errorf("skiping pruning, failed to find account to impersonate"), msg)
|
||||
r.event(ctx, kustomization, kustomization.Status.LastAppliedRevision, events.EventSeverityError, msg, nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,9 @@ package controllers
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
|
@ -69,6 +71,33 @@ func (ki *KustomizeImpersonation) GetClient(ctx context.Context) (client.Client,
|
|||
}
|
||||
}
|
||||
|
||||
// CanFinalize asserts if the given Kustomization can be finalized using impersonation.
|
||||
func (ki *KustomizeImpersonation) CanFinalize(ctx context.Context) bool {
|
||||
name := ki.defaultServiceAccount
|
||||
if sa := ki.kustomization.Spec.ServiceAccountName; sa != "" {
|
||||
name = sa
|
||||
}
|
||||
if name == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
sa := &corev1.ServiceAccount{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "ServiceAccount",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: ki.kustomization.Namespace,
|
||||
},
|
||||
}
|
||||
if err := ki.Client.Get(ctx, client.ObjectKeyFromObject(sa), sa); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (ki *KustomizeImpersonation) setImpersonationConfig(restConfig *rest.Config) {
|
||||
name := ki.defaultServiceAccount
|
||||
if sa := ki.kustomization.Spec.ServiceAccountName; sa != "" {
|
||||
|
|
|
@ -29,6 +29,7 @@ import (
|
|||
. "github.com/onsi/gomega"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
|
@ -101,6 +102,7 @@ data:
|
|||
Kind: sourcev1.GitRepositoryKind,
|
||||
},
|
||||
TargetNamespace: id,
|
||||
Prune: true,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -187,4 +189,22 @@ data:
|
|||
|
||||
g.Expect(readyCondition.Reason).To(Equal(meta.ReconciliationSucceededReason))
|
||||
})
|
||||
|
||||
t.Run("can finalize impersonating service account", func(t *testing.T) {
|
||||
saK := &kustomizev1.Kustomization{}
|
||||
err = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), saK)
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
err = k8sClient.Delete(context.Background(), saK)
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
g.Eventually(func() bool {
|
||||
err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
|
||||
return apierrors.IsNotFound(err)
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
|
||||
resultConfig := &corev1.ConfigMap{}
|
||||
err := k8sClient.Get(context.Background(), types.NamespacedName{Name: id, Namespace: id}, resultConfig)
|
||||
g.Expect(apierrors.IsNotFound(err)).To(BeTrue())
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue