diff --git a/internal/controller/reconcile-capapplication.go b/internal/controller/reconcile-capapplication.go index a881f51..aa98ceb 100644 --- a/internal/controller/reconcile-capapplication.go +++ b/internal/controller/reconcile-capapplication.go @@ -252,9 +252,8 @@ func (c *Controller) updateCAPApplicationStatus(ctx context.Context, ca *v1alpha return err } -// TODO: remove this entirely from CA soon func (c *Controller) validateSecrets(ctx context.Context, ca *v1alpha1.CAPApplication, attempts int) (bool, error) { - err := c.checkSecretsExist(ca.Spec.BTP.Services, ca.Namespace) + err := c.checkAndPreserveSecrets(ca.Spec.BTP.Services, ca.Namespace) if err == nil { return false, nil @@ -357,6 +356,10 @@ func (c *Controller) handleCAPApplicationDeletion(ctx context.Context, ca *v1alp return nil, err } + if err = c.cleanupPreservedSecrets(ca.Spec.BTP.Services, ca.Namespace); err != nil && !k8sErrors.IsNotFound(err) { + return nil, err + } + // delete CAPApplication if removeFinalizer(&ca.Finalizers, FinalizerCAPApplication) { return nil, c.updateCAPApplication(ctx, ca) diff --git a/internal/controller/reconcile-capapplication_test.go b/internal/controller/reconcile-capapplication_test.go index 482b85d..6435fc5 100644 --- a/internal/controller/reconcile-capapplication_test.go +++ b/internal/controller/reconcile-capapplication_test.go @@ -436,6 +436,7 @@ func TestDeletion_Case7(t *testing.T) { initialResources: []string{ "testdata/capapplication/ca-19.initial.yaml", "testdata/capapplication/istio-ingress-with-cert.yaml", + "testdata/common/credential-secrets.yaml", }, expectedResources: "testdata/capapplication/ca-19.expected.yaml", }, diff --git a/internal/controller/reconcile.go b/internal/controller/reconcile.go index 582fa2f..909f6e3 100644 --- a/internal/controller/reconcile.go +++ b/internal/controller/reconcile.go @@ -16,6 +16,7 @@ import ( batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" + k8sErrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" @@ -269,6 +270,47 @@ func (c *Controller) checkSecretsExist(serviceInfos []v1alpha1.ServiceInfo, name return err } +func (c *Controller) checkAndPreserveSecrets(serviceInfos []v1alpha1.ServiceInfo, namespace string) error { + var err error + var secret *corev1.Secret + secretLister := c.kubeInformerFactory.Core().V1().Secrets().Lister() + + for _, service := range serviceInfos { + secretName := service.Secret + if secret, err = secretLister.Secrets(namespace).Get(secretName); err != nil { + break + } + // Add finalizer to preserve Secret from being deleted accidentally + if addFinalizer(&secret.Finalizers, FinalizerCAPApplication) { + if _, err = c.kubeClient.CoreV1().Secrets(namespace).Update(context.TODO(), secret, metav1.UpdateOptions{}); err != nil { + break + } + } + } + return err +} + +func (c *Controller) cleanupPreservedSecrets(serviceInfos []v1alpha1.ServiceInfo, namespace string) error { + var err error + var secret *corev1.Secret + secretLister := c.kubeInformerFactory.Core().V1().Secrets().Lister() + + for _, service := range serviceInfos { + secretName := service.Secret + // Check if a secret exists + if secret, err = secretLister.Secrets(namespace).Get(secretName); err != nil && !k8sErrors.IsNotFound(err) { + break + } + // Remove finalizer from preserved Secret (if one exists) to allow it to be cleaned up if needed + if secret != nil && removeFinalizer(&secret.Finalizers, FinalizerCAPApplication) { + if _, err = c.kubeClient.CoreV1().Secrets(namespace).Update(context.TODO(), secret, metav1.UpdateOptions{}); err != nil { + break + } + } + } + return err +} + // This method is called to handle NotFound error at the beginning of reconciliation to skip requeue on errors due to deletion of resource func handleOperatorResourceErrors(err error) error { // Handle NotFound errors (object was most likely deleted) diff --git a/internal/controller/testdata/capapplication/ca-19.expected.yaml b/internal/controller/testdata/capapplication/ca-19.expected.yaml index 5c263ac..b0304d7 100644 --- a/internal/controller/testdata/capapplication/ca-19.expected.yaml +++ b/internal/controller/testdata/capapplication/ca-19.expected.yaml @@ -44,3 +44,13 @@ status: - type: Ready reason: DeletionTriggered status: "False" +--- +apiVersion: v1 +kind: Secret +metadata: + name: cap-cap-01-uaa-bind-cf + namespace: default + finalizers: [] # CA removes finalizer from presevered secret +type: Opaque +data: + credentials: ewogICJ1YWFkb21haW4iOiAiYXV0aC5zZXJ2aWNlLmxvY2FsIiwKICAieHNhcHBuYW1lIjogInRlc3QtY2FwLTAxIWIxNCIsCiAgInVybCI6ICJodHRwczovL2FwcC1kb21haW4uYXV0aC5zZXJ2aWNlLmxvY2FsIiwKICAiY3JlZGVudGlhbC10eXBlIjogImluc3RhbmNlLXNlY3JldCIKfQo= \ No newline at end of file diff --git a/internal/controller/testdata/capapplication/ca-29.expected.yaml b/internal/controller/testdata/capapplication/ca-29.expected.yaml index de70616..e467c22 100644 --- a/internal/controller/testdata/capapplication/ca-29.expected.yaml +++ b/internal/controller/testdata/capapplication/ca-29.expected.yaml @@ -53,3 +53,14 @@ status: reason: AllTenantsReady observedGeneration: 0 status: "True" +--- +apiVersion: v1 +kind: Secret +metadata: + name: cap-cap-01-uaa-bind-cf + namespace: default + finalizers: + - sme.sap.com/capapplication # CA presevered secret exists +type: Opaque +data: + credentials: ewogICJ1YWFkb21haW4iOiAiYXV0aC5zZXJ2aWNlLmxvY2FsIiwKICAieHNhcHBuYW1lIjogInRlc3QtY2FwLTAxIWIxNCIsCiAgInVybCI6ICJodHRwczovL2FwcC1kb21haW4uYXV0aC5zZXJ2aWNlLmxvY2FsIiwKICAiY3JlZGVudGlhbC10eXBlIjogImluc3RhbmNlLXNlY3JldCIKfQo= \ No newline at end of file diff --git a/internal/controller/testdata/common/credential-secrets.yaml b/internal/controller/testdata/common/credential-secrets.yaml index f258f50..7309e8f 100644 --- a/internal/controller/testdata/common/credential-secrets.yaml +++ b/internal/controller/testdata/common/credential-secrets.yaml @@ -3,6 +3,8 @@ kind: Secret metadata: name: cap-cap-01-uaa-bind-cf namespace: default + finalizers: + - sme.sap.com/capapplication type: Opaque data: credentials: ewogICJ1YWFkb21haW4iOiAiYXV0aC5zZXJ2aWNlLmxvY2FsIiwKICAieHNhcHBuYW1lIjogInRlc3QtY2FwLTAxIWIxNCIsCiAgInVybCI6ICJodHRwczovL2FwcC1kb21haW4uYXV0aC5zZXJ2aWNlLmxvY2FsIiwKICAiY3JlZGVudGlhbC10eXBlIjogImluc3RhbmNlLXNlY3JldCIKfQo=