secret deletion

This commit is contained in:
kkb0318
2024-04-11 20:59:17 +09:00
parent 720bc912b9
commit 1b9ccebbc5
13 changed files with 155 additions and 65 deletions
+23 -2
View File
@@ -77,7 +77,10 @@ func (r *IRSASetupReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
} }
if !obj.DeletionTimestamp.IsZero() { if !obj.DeletionTimestamp.IsZero() {
err = r.reconcileDelete(ctx, obj) err = r.reconcileDelete(ctx, obj, kubeClient)
if err == nil {
log.Info("successfully deleted")
}
return ctrl.Result{}, err return ctrl.Result{}, err
} }
@@ -94,7 +97,25 @@ func (r *IRSASetupReconciler) reconcile(ctx context.Context, obj *irsav1alpha1.I
return err return err
} }
func (r *IRSASetupReconciler) reconcileDelete(ctx context.Context, obj *irsav1alpha1.IRSASetup) error { func (r *IRSASetupReconciler) reconcileDelete(ctx context.Context, obj *irsav1alpha1.IRSASetup, kubeClient *kubernetes.KubernetesClient) error {
factory, err := newOIDCIdpFactory(ctx, obj, nil, r.AwsClient)
if err != nil {
return err
}
secret, err := manifests.NewSecretBuilder().Build("name", "default")
if err != nil {
return err
}
kubeHandler := handler.NewKubernetesHandler(kubeClient)
kubeHandler.Append(secret)
err = selfhosted.Delete(ctx, factory)
if err != nil {
return err
}
err = kubeHandler.DeleteAll(ctx)
if err != nil {
return err
}
return nil return nil
} }
@@ -38,13 +38,16 @@ var _ = Describe("IRSASetup Controller", func() {
Context("When reconciling a resource", func() { Context("When reconciling a resource", func() {
const resourceName = "test-resource" const resourceName = "test-resource"
ctx := context.Background()
typeNamespacedName := types.NamespacedName{ typeNamespacedName := types.NamespacedName{
Name: resourceName, Name: resourceName,
Namespace: "default", // TODO(user):Modify as needed Namespace: "default",
}
irsasetup := &irsav1alpha1.IRSASetup{
ObjectMeta: metav1.ObjectMeta{
Name: resourceName,
Namespace: "default",
},
} }
irsasetup := &irsav1alpha1.IRSASetup{}
BeforeEach(func() { BeforeEach(func() {
By("creating the custom resource for the Kind IRSASetup") By("creating the custom resource for the Kind IRSASetup")
@@ -69,17 +72,12 @@ var _ = Describe("IRSASetup Controller", func() {
} }
}) })
AfterEach(func() {
// TODO(user): Cleanup logic after each test, like removing the resource instance.
resource := &irsav1alpha1.IRSASetup{}
err := k8sClient.Get(ctx, typeNamespacedName, resource)
Expect(err).NotTo(HaveOccurred())
By("Cleanup the specific resource instance IRSASetup")
Expect(k8sClient.Delete(ctx, resource)).To(Succeed())
})
It("should successfully reconcile the resource", func() { It("should successfully reconcile the resource", func() {
awsClient := newMockAwsClient() awsClient := newMockAwsClient()
expected := []types.NamespacedName{
{Name: "name", Namespace: "default"},
}
By("Reconciling the created resource") By("Reconciling the created resource")
controllerReconciler := &IRSASetupReconciler{ controllerReconciler := &IRSASetupReconciler{
Client: k8sClient, Client: k8sClient,
@@ -91,8 +89,24 @@ var _ = Describe("IRSASetup Controller", func() {
NamespacedName: typeNamespacedName, NamespacedName: typeNamespacedName,
}) })
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
// TODO(user): Add more specific assertions depending on your controller's reconciliation logic. _, err = controllerReconciler.Reconcile(ctx, reconcile.Request{
// Example: If you expect a certain status condition after reconciliation, verify it here. NamespacedName: typeNamespacedName,
})
Expect(err).NotTo(HaveOccurred())
for _, expect := range expected {
checkExist(expect, newSecret)
}
By("removing the custom resource for the Kind")
Eventually(func() error {
return k8sClient.Delete(ctx, irsasetup)
}, timeout).Should(Succeed())
_, err = controllerReconciler.Reconcile(ctx, reconcile.Request{
NamespacedName: typeNamespacedName,
})
Expect(err).To(Not(HaveOccurred()))
for _, expect := range expected {
checkNoExist(expect, newSecret)
}
}) })
}) })
}) })
+24
View File
@@ -21,12 +21,16 @@ import (
"path/filepath" "path/filepath"
"runtime" "runtime"
"testing" "testing"
"time"
. "github.com/onsi/ginkgo/v2" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest" "k8s.io/client-go/rest"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/envtest" "sigs.k8s.io/controller-runtime/pkg/envtest"
logf "sigs.k8s.io/controller-runtime/pkg/log" logf "sigs.k8s.io/controller-runtime/pkg/log"
@@ -43,6 +47,8 @@ var (
cfg *rest.Config cfg *rest.Config
k8sClient client.Client k8sClient client.Client
testEnv *envtest.Environment testEnv *envtest.Environment
timeout = time.Second * 10
ctx = ctrl.SetupSignalHandler()
) )
func TestControllers(t *testing.T) { func TestControllers(t *testing.T) {
@@ -89,3 +95,21 @@ var _ = AfterSuite(func() {
err := testEnv.Stop() err := testEnv.Stop()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
}) })
func checkExist(expected types.NamespacedName, newFunc func() client.Object) {
Eventually(func() error {
found := newFunc()
return k8sClient.Get(ctx, expected, found)
}, timeout).Should(Succeed())
}
func checkNoExist(expected types.NamespacedName, newFunc func() client.Object) {
Eventually(func() error {
found := newFunc()
return k8sClient.Get(ctx, expected, found)
}, timeout).Should(Not(Succeed()))
}
func newSecret() client.Object {
return &corev1.Secret{}
}
+1 -2
View File
@@ -4,13 +4,12 @@ import (
"context" "context"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
) )
type KubernetesClient interface { type KubernetesClient interface {
Apply(ctx context.Context, obj client.Object) error Apply(ctx context.Context, obj client.Object) error
Delete(ctx context.Context, obj *unstructured.Unstructured, opts DeleteOptions) error Delete(ctx context.Context, obj client.Object, opts DeleteOptions) error
} }
// DeleteOptions contains options for delete requests. // DeleteOptions contains options for delete requests.
+13
View File
@@ -3,6 +3,7 @@ package handler
import ( import (
"context" "context"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
) )
@@ -31,3 +32,15 @@ func (k *KubernetesHandler) ApplyAll(ctx context.Context) error {
} }
return nil return nil
} }
func (k *KubernetesHandler) DeleteAll(ctx context.Context) error {
for _, obj := range k.objs {
err := k.client.Delete(ctx, obj, DeleteOptions{
DeletionPropagation: metav1.DeletePropagationBackground,
})
if err != nil {
return err
}
}
return nil
}
+2 -23
View File
@@ -3,11 +3,7 @@ package kubernetes
import ( import (
"context" "context"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
) )
func NewKubernetesClient(c client.Client, owner Owner) (*KubernetesClient, error) { func NewKubernetesClient(c client.Client, owner Owner) (*KubernetesClient, error) {
@@ -22,19 +18,10 @@ func (h KubernetesClient) Apply(ctx context.Context, obj client.Object) error {
client.ForceOwnership, client.ForceOwnership,
client.FieldOwner(h.owner.Field), client.FieldOwner(h.owner.Field),
} }
gvk, err := apiutil.GVKForObject(obj, h.client.Scheme()) u, err := h.toUnstructured(obj)
if err != nil { if err != nil {
return err return err
} }
u := &unstructured.Unstructured{}
unstructured, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
if err != nil {
return err
}
u.Object = unstructured
u.SetGroupVersionKind(gvk)
u.SetManagedFields(nil)
err = h.client.Patch(ctx, u, client.Apply, opts...) err = h.client.Patch(ctx, u, client.Apply, opts...)
if err != nil { if err != nil {
return err return err
@@ -48,18 +35,10 @@ func (h KubernetesClient) PatchStatus(ctx context.Context, obj client.Object) er
FieldManager: h.owner.Field, FieldManager: h.owner.Field,
}, },
} }
gvk, err := apiutil.GVKForObject(obj, h.client.Scheme()) u, err := h.toUnstructured(obj)
if err != nil { if err != nil {
return err return err
} }
u := &unstructured.Unstructured{}
unstructured, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
if err != nil {
return err
}
u.Object = unstructured
u.SetGroupVersionKind(gvk)
u.SetManagedFields(nil)
return h.client.Status().Patch(ctx, u, client.Apply, opts) return h.client.Status().Patch(ctx, u, client.Apply, opts)
} }
+6 -18
View File
@@ -14,27 +14,15 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
) )
func (h *KubernetesClient) DeleteAll(ctx context.Context, resources []*unstructured.Unstructured, opts handler.DeleteOptions) error {
if !h.cleanup {
return nil
}
for _, r := range resources {
err := h.Delete(ctx, r, opts)
if err != nil {
return err
}
}
return nil
}
// Delete deletes the given object (not found errors are ignored). // Delete deletes the given object (not found errors are ignored).
func (h *KubernetesClient) Delete(ctx context.Context, object *unstructured.Unstructured, opts handler.DeleteOptions) error { func (h *KubernetesClient) Delete(ctx context.Context, obj client.Object, opts handler.DeleteOptions) error {
if !h.cleanup { u, err := h.toUnstructured(obj)
return nil if err != nil {
return err
} }
existingObject := &unstructured.Unstructured{} existingObject := &unstructured.Unstructured{}
existingObject.SetGroupVersionKind(object.GroupVersionKind()) existingObject.SetGroupVersionKind(u.GroupVersionKind())
err := h.client.Get(ctx, client.ObjectKeyFromObject(object), existingObject) err = h.client.Get(ctx, client.ObjectKeyFromObject(u), existingObject)
if err != nil { if err != nil {
if !errors.IsNotFound(err) { if !errors.IsNotFound(err) {
return fmt.Errorf("failed to delete: %w", err) return fmt.Errorf("failed to delete: %w", err)
+26
View File
@@ -0,0 +1,26 @@
package kubernetes
import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
)
func (h KubernetesClient) toUnstructured(obj client.Object) (*unstructured.Unstructured, error) {
gvk, err := apiutil.GVKForObject(obj, h.client.Scheme())
if err != nil {
return nil, err
}
u := &unstructured.Unstructured{}
unstructured, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
if err != nil {
return nil, err
}
u.Object = unstructured
u.SetGroupVersionKind(gvk)
u.SetManagedFields(nil)
return u, nil
}
-5
View File
@@ -1,8 +1,6 @@
package manifests package manifests
import ( import (
"fmt"
"github.com/kkb0318/irsa-manager/internal/selfhosted" "github.com/kkb0318/irsa-manager/internal/selfhosted"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -29,9 +27,6 @@ func (b *SecretBuilder) WithSSHKey(keyPair selfhosted.KeyPair) *SecretBuilder {
} }
func (b *SecretBuilder) Build(name, ns string) (*corev1.Secret, error) { func (b *SecretBuilder) Build(name, ns string) (*corev1.Secret, error) {
if b.data == nil {
return nil, fmt.Errorf("Secret.Data is empty")
}
secret := &corev1.Secret{ secret := &corev1.Secret{
ObjectMeta: v1.ObjectMeta{ ObjectMeta: v1.ObjectMeta{
Name: name, Name: name,
+2
View File
@@ -11,6 +11,7 @@ type OIDCIdP interface {
Create(ctx context.Context) (string, error) Create(ctx context.Context) (string, error)
IsUpdate() (bool, error) IsUpdate() (bool, error)
Update(ctx context.Context) error Update(ctx context.Context) error
Delete(ctx context.Context) error
} }
type OIDCIdPDiscoveryContents interface { type OIDCIdPDiscoveryContents interface {
@@ -22,6 +23,7 @@ type OIDCIdPDiscoveryContents interface {
type OIDCIdPDiscovery interface { type OIDCIdPDiscovery interface {
CreateStorage(ctx context.Context) error CreateStorage(ctx context.Context) error
Upload(ctx context.Context, o OIDCIdPDiscoveryContents) error Upload(ctx context.Context, o OIDCIdPDiscoveryContents) error
DeleteStorage(ctx context.Context) error
} }
type OIDCIdPFactory interface { type OIDCIdPFactory interface {
+5
View File
@@ -32,3 +32,8 @@ func (a *AwsIdP) Update(ctx context.Context) error {
func (a *AwsIdP) IsUpdate() (bool, error) { func (a *AwsIdP) IsUpdate() (bool, error) {
return false, nil return false, nil
} }
func (a *AwsIdP) Delete(ctx context.Context) error {
// TODO:
return nil
}
@@ -59,3 +59,9 @@ func (s *S3IdPDiscovery) Upload(ctx context.Context, o selfhosted.OIDCIdPDiscove
} }
return nil return nil
} }
// DeleteStorage delete an S3 bucket
func (s *S3IdPDiscovery) DeleteStorage(ctx context.Context) error {
// TODO:
return nil
}
+18
View File
@@ -24,3 +24,21 @@ func Execute(ctx context.Context, factory OIDCIdPFactory) error {
} }
return nil return nil
} }
func Delete(ctx context.Context, factory OIDCIdPFactory) error {
issuerMeta := factory.IssuerMeta()
discovery := factory.IdPDiscovery()
idp, err := factory.IdP(issuerMeta)
if err != nil {
return err
}
err = discovery.DeleteStorage(ctx)
if err != nil {
return err
}
err = idp.Delete(ctx)
if err != nil {
return err
}
return nil
}