feature: cleanup serviceAccount

This commit is contained in:
kkb0318
2024-07-12 22:36:26 +09:00
parent 907e58e94a
commit 13b8450ba2
12 changed files with 507 additions and 32 deletions
+32 -18
View File
@@ -25,6 +25,7 @@ import (
"github.com/kkb0318/irsa-manager/internal/issuer"
"github.com/kkb0318/irsa-manager/internal/kubernetes"
"github.com/kkb0318/irsa-manager/internal/manifests"
"github.com/kkb0318/irsa-manager/internal/utils"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
@@ -118,8 +119,6 @@ func (r *IRSAReconciler) reconcileDelete(ctx context.Context, obj *irsav1alpha1.
if !obj.Spec.Cleanup {
return nil
}
serviceAccount := obj.Spec.ServiceAccount
kubeHandler := handler.NewKubernetesHandler(kubeClient)
roleManager := awsclient.RoleManager{
RoleName: obj.Spec.IamRole.Name,
Policies: obj.Spec.IamPolicies,
@@ -131,15 +130,8 @@ func (r *IRSAReconciler) reconcileDelete(ctx context.Context, obj *irsav1alpha1.
if err != nil {
return err
}
for _, ns := range serviceAccount.Namespaces {
sa := manifests.NewServiceAccountBuilder().Build(types.NamespacedName{
Name: serviceAccount.Name,
Namespace: ns,
})
kubeHandler.Append(sa)
}
err = kubeHandler.DeleteAll(ctx)
deleted, err := cleanupKubernetesResources(ctx, kubeClient, obj.Spec.ServiceAccount.NamespacedNameList())
*obj = irsav1alpha1.IRSAStatusSetServiceAccount(*obj, deleted)
if err != nil {
return err
}
@@ -196,24 +188,46 @@ func (r *IRSAReconciler) reconcile(ctx context.Context, obj *irsav1alpha1.IRSA,
}
kubeHandler := handler.NewKubernetesHandler(kubeClient)
for _, ns := range serviceAccount.Namespaces {
sa := manifests.NewServiceAccountBuilder().WithIRSAAnnotation(roleManager).Build(types.NamespacedName{
Name: serviceAccount.Name,
Namespace: ns,
})
for _, namespacedName := range serviceAccount.NamespacedNameList() {
sa := manifests.NewServiceAccountBuilder().WithIRSAAnnotation(roleManager).Build(namespacedName)
kubeHandler.Append(sa)
}
err = kubeHandler.ApplyAll(ctx)
applied, err := kubeHandler.ApplyAll(ctx)
*obj = irsav1alpha1.IRSAStatusSetServiceAccount(*obj, applied)
if err != nil {
e = err
reason = irsav1alpha1.IRSAReasonFailedK8sApply
return err
}
deleted, err := cleanupKubernetesResources(
ctx,
kubeClient,
utils.DiffNamespacedNames(obj.Status.ServiceNamespacedNameList(), serviceAccount.NamespacedNameList()),
)
*obj = irsav1alpha1.IRSAStatusSetServiceAccount(*obj, deleted)
if err != nil {
e = err
reason = irsav1alpha1.IRSAReasonFailedK8sCleanUp
return err
}
*obj = irsav1alpha1.IRSAStatusReady(*obj, string(irsav1alpha1.IRSAReasonReady), "successfully setup resources")
return nil
}
func cleanupKubernetesResources(ctx context.Context, client *kubernetes.KubernetesClient, nsNames []types.NamespacedName) ([]types.NamespacedName, error) {
kubeHandler := handler.NewKubernetesHandler(client)
for _, namespacedName := range nsNames {
sa := manifests.NewServiceAccountBuilder().Build(namespacedName)
kubeHandler.Append(sa)
}
deleted, err := kubeHandler.DeleteAll(ctx)
if err != nil {
return deleted, err
}
return deleted, nil
}
// SetupWithManager sets up the controller with the Manager.
func (r *IRSAReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
+99 -5
View File
@@ -17,6 +17,7 @@ limitations under the License.
package controller
import (
"context"
"fmt"
. "github.com/onsi/ginkgo/v2"
@@ -80,10 +81,6 @@ var _ = Describe("IRSA Controller", func() {
NamespacedName: typeNamespacedName,
})
Expect(err).NotTo(HaveOccurred())
_, err = r.Reconcile(ctx, reconcile.Request{
NamespacedName: typeNamespacedName,
})
Expect(err).NotTo(HaveOccurred())
for _, expect := range expected {
checkExist(expect)
}
@@ -101,7 +98,7 @@ var _ = Describe("IRSA Controller", func() {
},
},
{
name: "error",
name: "AWS API Error Case",
obj: &irsav1alpha1.IRSA{
ObjectMeta: metav1.ObjectMeta{
Name: "test-resource2",
@@ -169,6 +166,75 @@ var _ = Describe("IRSA Controller", func() {
}
},
},
{
name: "should update serviceaccount successfully",
obj: &irsav1alpha1.IRSA{
ObjectMeta: metav1.ObjectMeta{
Name: "test-resource3",
Namespace: "default",
},
Spec: irsav1alpha1.IRSASpec{
Cleanup: true,
ServiceAccount: irsav1alpha1.IRSAServiceAccount{
Name: "sa-3",
Namespaces: []string{
"kube-system",
},
},
},
},
irsaSetupObj: newMockIRSASetup(),
f: func(r *IRSAReconciler, obj *irsav1alpha1.IRSA) {
expected := []expectedResource{
{
NamespacedName: types.NamespacedName{Name: "sa-3", Namespace: "kube-system"},
f: newServiceAccount,
},
{
NamespacedName: types.NamespacedName{Name: "sa-3", Namespace: "default"},
f: newServiceAccount,
},
}
By("Reconciling the created resource")
typeNamespacedName := types.NamespacedName{
Name: obj.Name,
Namespace: obj.Namespace,
}
_, err := r.Reconcile(ctx, reconcile.Request{
NamespacedName: typeNamespacedName,
})
Expect(err).NotTo(HaveOccurred())
checkExist(
expectedResource{
NamespacedName: types.NamespacedName{Name: "sa-3", Namespace: "kube-system"},
f: newServiceAccount,
},
)
f := createCallBack(ctx, r, typeNamespacedName, obj)
By("Add Namespace 'default'")
f(obj.Spec.ServiceAccount.Name, []string{"default", "kube-system"})
By("Remove Namespace 'kube-system'")
f(obj.Spec.ServiceAccount.Name, []string{"default"})
checkNoExist(expectedResource{
NamespacedName: types.NamespacedName{Name: "sa-3", Namespace: "kube-system"},
f: newServiceAccount,
})
By("removing the custom resource for the Kind")
Eventually(func() error {
return k8sClient.Delete(ctx, obj)
}, timeout).Should(Succeed())
_, err = r.Reconcile(ctx, reconcile.Request{
NamespacedName: typeNamespacedName,
})
Expect(err).To(Not(HaveOccurred()))
for _, expect := range expected {
checkNoExist(expect)
}
},
},
}
for _, tt := range tests {
It(tt.name, func() {
@@ -231,3 +297,31 @@ func newMockIRSASetup() *irsav1alpha1.IRSASetup {
},
}
}
func createCallBack(ctx context.Context, r *IRSAReconciler, typeNamespacedName types.NamespacedName, obj *irsav1alpha1.IRSA) func(name string, namespaces []string) {
return func(name string, namespaces []string) {
fixNamespacesAndReconcile(ctx, r, typeNamespacedName, obj, name, namespaces)
}
}
func fixNamespacesAndReconcile(ctx context.Context, r *IRSAReconciler, typeNamespacedName types.NamespacedName, obj *irsav1alpha1.IRSA, name string, namespaces []string) {
Expect(k8sClient.Get(ctx, typeNamespacedName, obj)).NotTo(HaveOccurred())
Eventually(func() error {
obj.Spec.ServiceAccount.Namespaces = namespaces
return k8sClient.Update(ctx, obj)
}, timeout).Should(Succeed())
_, err := r.Reconcile(ctx, reconcile.Request{
NamespacedName: typeNamespacedName,
})
Expect(err).NotTo(HaveOccurred())
expected := []expectedResource{}
for _, ns := range namespaces {
expected = append(expected, expectedResource{
NamespacedName: types.NamespacedName{Name: name, Namespace: ns},
f: newServiceAccount,
})
}
for _, e := range expected {
checkExist(e)
}
}
+3 -3
View File
@@ -150,7 +150,7 @@ func (r *IRSASetupReconciler) reconcileDelete(ctx context.Context, obj *irsav1al
for _, r := range webhookSetup.Resources() {
kubeHandler.Append(r)
}
err = kubeHandler.DeleteAll(ctx)
_, err = kubeHandler.DeleteAll(ctx)
if err != nil {
return err
}
@@ -233,7 +233,7 @@ func reconcileSelfhosted(ctx context.Context, obj *irsav1alpha1.IRSASetup, awsCl
return err
}
if forceUpdate {
err = kubeHandlerForOidc.ApplyAll(ctx)
_, err = kubeHandlerForOidc.ApplyAll(ctx)
} else {
err = kubeHandlerForOidc.CreateAll(ctx)
}
@@ -247,7 +247,7 @@ func reconcileSelfhosted(ctx context.Context, obj *irsav1alpha1.IRSASetup, awsCl
for _, r := range webhookSetup.Resources() {
kubeHandlerForWebhook.Append(r)
}
err = kubeHandlerForWebhook.ApplyAll(ctx)
_, err = kubeHandlerForWebhook.ApplyAll(ctx)
if err != nil {
e = err
reason = irsav1alpha1.SelfHostedReasonFailedWebhook