github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/controllers/dataprotection/gc_controller_test.go (about)

     1  /*
     2  Copyright (C) 2022-2023 ApeCloud Co., Ltd
     3  
     4  This file is part of KubeBlocks project
     5  
     6  This program is free software: you can redistribute it and/or modify
     7  it under the terms of the GNU Affero General Public License as published by
     8  the Free Software Foundation, either version 3 of the License, or
     9  (at your option) any later version.
    10  
    11  This program is distributed in the hope that it will be useful
    12  but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  GNU Affero General Public License for more details.
    15  
    16  You should have received a copy of the GNU Affero General Public License
    17  along with this program.  If not, see <http://www.gnu.org/licenses/>.
    18  */
    19  
    20  package dataprotection
    21  
    22  import (
    23  	"time"
    24  
    25  	. "github.com/onsi/ginkgo/v2"
    26  	. "github.com/onsi/gomega"
    27  
    28  	batchv1 "k8s.io/api/batch/v1"
    29  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    30  	"sigs.k8s.io/controller-runtime/pkg/client"
    31  
    32  	dpv1alpha1 "github.com/1aal/kubeblocks/apis/dataprotection/v1alpha1"
    33  	dpbackup "github.com/1aal/kubeblocks/pkg/dataprotection/backup"
    34  	dptypes "github.com/1aal/kubeblocks/pkg/dataprotection/types"
    35  	"github.com/1aal/kubeblocks/pkg/generics"
    36  	testapps "github.com/1aal/kubeblocks/pkg/testutil/apps"
    37  	testdp "github.com/1aal/kubeblocks/pkg/testutil/dataprotection"
    38  )
    39  
    40  var _ = Describe("Data Protection Garbage Collection Controller", func() {
    41  	cleanEnv := func() {
    42  		// must wait till resources deleted and no longer existed before the testcases start,
    43  		// otherwise if later it needs to create some new resource objects with the same name,
    44  		// in race conditions, it will find the existence of old objects, resulting failure to
    45  		// create the new objects.
    46  		By("clean resources")
    47  		// delete rest mocked objects
    48  		inNS := client.InNamespace(testCtx.DefaultNamespace)
    49  		ml := client.HasLabels{testCtx.TestObjLabelKey}
    50  
    51  		// namespaced
    52  		testapps.ClearResources(&testCtx, generics.ClusterSignature, inNS, ml)
    53  		testapps.ClearResources(&testCtx, generics.PodSignature, inNS, ml)
    54  		testapps.ClearResources(&testCtx, generics.SecretSignature, inNS, ml)
    55  		testapps.ClearResourcesWithRemoveFinalizerOption(&testCtx, generics.BackupPolicySignature, true, inNS)
    56  		testapps.ClearResourcesWithRemoveFinalizerOption(&testCtx, generics.BackupSignature, true, inNS)
    57  
    58  		// wait all backup to be deleted, otherwise the controller maybe create
    59  		// job to delete the backup between the ClearResources function delete
    60  		// the job and get the job list, resulting the ClearResources panic.
    61  		Eventually(testapps.List(&testCtx, generics.BackupSignature, inNS)).Should(HaveLen(0))
    62  
    63  		testapps.ClearResourcesWithRemoveFinalizerOption(&testCtx, generics.JobSignature, true, inNS)
    64  		testapps.ClearResourcesWithRemoveFinalizerOption(&testCtx, generics.PersistentVolumeClaimSignature, true, inNS)
    65  		testapps.ClearResources(&testCtx, generics.SecretSignature, inNS, ml)
    66  		// non-namespaced
    67  		testapps.ClearResourcesWithRemoveFinalizerOption(&testCtx, generics.ActionSetSignature, true, ml)
    68  		testapps.ClearResources(&testCtx, generics.StorageClassSignature, ml)
    69  		testapps.ClearResourcesWithRemoveFinalizerOption(&testCtx, generics.PersistentVolumeSignature, true, ml)
    70  		testapps.ClearResourcesWithRemoveFinalizerOption(&testCtx, generics.BackupRepoSignature, true, ml)
    71  		testapps.ClearResources(&testCtx, generics.StorageProviderSignature, ml)
    72  	}
    73  
    74  	BeforeEach(func() {
    75  		cleanEnv()
    76  		_ = testdp.NewFakeCluster(&testCtx)
    77  	})
    78  
    79  	AfterEach(cleanEnv)
    80  
    81  	Context("garbage collection", func() {
    82  		var (
    83  			backupNamePrefix = "schedule-test-backup-"
    84  			backupPolicy     *dpv1alpha1.BackupPolicy
    85  		)
    86  
    87  		getJobKey := func(backup *dpv1alpha1.Backup) client.ObjectKey {
    88  			return client.ObjectKey{
    89  				Name:      dpbackup.GenerateBackupJobName(backup, dpbackup.BackupDataJobNamePrefix),
    90  				Namespace: backup.Namespace,
    91  			}
    92  		}
    93  
    94  		BeforeEach(func() {
    95  			By("creating an actionSet")
    96  			actionSet := testdp.NewFakeActionSet(&testCtx)
    97  
    98  			By("creating storage provider")
    99  			_ = testdp.NewFakeStorageProvider(&testCtx, nil)
   100  
   101  			By("creating backup repo")
   102  			_, _ = testdp.NewFakeBackupRepo(&testCtx, nil)
   103  
   104  			By("By creating a backupPolicy from actionSet " + actionSet.Name)
   105  			backupPolicy = testdp.NewFakeBackupPolicy(&testCtx, nil)
   106  		})
   107  
   108  		It("delete expired backups", func() {
   109  			now := metav1.Now()
   110  			backupStatus := dpv1alpha1.BackupStatus{
   111  				Phase:               dpv1alpha1.BackupPhaseCompleted,
   112  				Expiration:          &now,
   113  				StartTimestamp:      &now,
   114  				CompletionTimestamp: &now,
   115  			}
   116  
   117  			autoBackupLabel := map[string]string{
   118  				dptypes.AutoBackupLabelKey:     "true",
   119  				dptypes.BackupScheduleLabelKey: testdp.BackupPolicyName,
   120  				dptypes.BackupMethodLabelKey:   testdp.BackupMethodName,
   121  			}
   122  
   123  			createBackup := func(name string) *dpv1alpha1.Backup {
   124  				return testdp.NewBackupFactory(testCtx.DefaultNamespace, name).
   125  					WithRandomName().AddLabelsInMap(autoBackupLabel).
   126  					SetBackupPolicyName(testdp.BackupPolicyName).
   127  					SetBackupMethod(testdp.BackupMethodName).
   128  					Create(&testCtx).GetObject()
   129  			}
   130  
   131  			checkBackupCompleted := func(key client.ObjectKey) {
   132  				Eventually(testapps.CheckObj(&testCtx, key,
   133  					func(g Gomega, fetched *dpv1alpha1.Backup) {
   134  						g.Expect(fetched.Status.Phase).To(Equal(dpv1alpha1.BackupPhaseCompleted))
   135  					})).Should(Succeed())
   136  			}
   137  
   138  			setBackupUnexpired := func(backup *dpv1alpha1.Backup) {
   139  				backup.Status.Expiration = &metav1.Time{Time: fakeClock.Now().Add(time.Hour * 24)}
   140  				backup.Status.StartTimestamp = &metav1.Time{Time: fakeClock.Now().Add(time.Hour)}
   141  				testdp.PatchBackupStatus(&testCtx, client.ObjectKeyFromObject(backup), backup.Status)
   142  			}
   143  
   144  			By("create an expired backup")
   145  			backupExpired := createBackup(backupNamePrefix + "expired")
   146  
   147  			By("create an unexpired backup")
   148  			backup1 := createBackup(backupNamePrefix + "unexpired")
   149  
   150  			By("waiting expired backup completed")
   151  			expiredKey := client.ObjectKeyFromObject(backupExpired)
   152  			testdp.PatchK8sJobStatus(&testCtx, getJobKey(backupExpired), batchv1.JobComplete)
   153  			checkBackupCompleted(expiredKey)
   154  
   155  			By("mock backup status to expire")
   156  			backupStatus.Expiration = &metav1.Time{Time: fakeClock.Now().Add(-time.Hour * 24)}
   157  			backupStatus.StartTimestamp = backupStatus.Expiration
   158  			testdp.PatchBackupStatus(&testCtx, client.ObjectKeyFromObject(backupExpired), backupStatus)
   159  
   160  			By("waiting backup completed")
   161  			backup1Key := client.ObjectKeyFromObject(backup1)
   162  			testdp.PatchK8sJobStatus(&testCtx, getJobKey(backup1), batchv1.JobComplete)
   163  			checkBackupCompleted(backup1Key)
   164  
   165  			By("mock backup not to expire")
   166  			setBackupUnexpired(backup1)
   167  
   168  			By("retain the unexpired backup")
   169  			Eventually(testapps.List(&testCtx, generics.BackupSignature,
   170  				client.MatchingLabels(autoBackupLabel),
   171  				client.InNamespace(backupPolicy.Namespace))).Should(HaveLen(1))
   172  			Eventually(testapps.CheckObjExists(&testCtx, backup1Key, &dpv1alpha1.Backup{}, true)).Should(Succeed())
   173  			Eventually(testapps.CheckObjExists(&testCtx, expiredKey, &dpv1alpha1.Backup{}, false)).Should(Succeed())
   174  		})
   175  	})
   176  })