From 226d50d9cb9da5542eaf2b2db3602d5def15c51a Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Tue, 19 Nov 2024 15:07:06 +0800 Subject: [PATCH] Modify the schedule cases. * Modify the OrderResource case's verification code. * Simplify the Periodical case. * Simplify the InProgess case. * Prettify the code. * Replace math/rand with crypto/rand * Replace PollUnitl with PollUntilContextTimeout Signed-off-by: Xun Jiang --- test/e2e/e2e_suite_test.go | 10 +- test/e2e/resource-filtering/exclude_label.go | 2 +- test/e2e/schedule/in_progress.go | 196 ++++++++++++++++ test/e2e/schedule/ordered_resources.go | 206 ++++++++++------- test/e2e/schedule/periodical.go | 210 +++++++++++++++++ test/e2e/schedule/schedule-backup-creation.go | 138 ----------- test/e2e/schedule/schedule.go | 214 ------------------ test/util/k8s/configmap.go | 8 +- test/util/velero/install.go | 2 +- test/util/velero/velero_utils.go | 80 +++---- 10 files changed, 579 insertions(+), 487 deletions(-) create mode 100644 test/e2e/schedule/in_progress.go create mode 100644 test/e2e/schedule/periodical.go delete mode 100644 test/e2e/schedule/schedule-backup-creation.go delete mode 100644 test/e2e/schedule/schedule.go diff --git a/test/e2e/e2e_suite_test.go b/test/e2e/e2e_suite_test.go index 790019ba29..8e9e9bc0b4 100644 --- a/test/e2e/e2e_suite_test.go +++ b/test/e2e/e2e_suite_test.go @@ -543,18 +543,18 @@ var _ = Describe( var _ = Describe( "Backup will be created periodically by schedule defined by a Cron expression", - Label("Schedule", "BR", "Pause", "LongTime"), - ScheduleBackupTest, + Label("Schedule", "Periodical", "Pause", "LongTime"), + SchedulePeriodicalTest, ) var _ = Describe( "Backup resources should follow the specific order in schedule", - Label("Schedule", "OrderedResources", "LongTime"), + Label("Schedule", "OrderedResources"), ScheduleOrderedResources, ) var _ = Describe( "Schedule controller wouldn't create a new backup when it still has pending or InProgress backup", - Label("Schedule", "BackupCreation", "SKIP_KIND", "LongTime"), - ScheduleBackupCreationTest, + Label("Schedule", "InProgress", "SKIP_KIND", "LongTime"), + ScheduleInProgressTest, ) var _ = Describe( diff --git a/test/e2e/resource-filtering/exclude_label.go b/test/e2e/resource-filtering/exclude_label.go index 0dd1753694..b90d63dd87 100644 --- a/test/e2e/resource-filtering/exclude_label.go +++ b/test/e2e/resource-filtering/exclude_label.go @@ -144,7 +144,7 @@ func (e *ExcludeFromBackup) Verify() error { Expect(apierrors.IsNotFound(err)).To(BeTrue()) //Check configmap: should be included - _, err = GetConfigmap(e.Client.ClientGo, namespace, e.CaseBaseName) + _, err = GetConfigMap(e.Client.ClientGo, namespace, e.CaseBaseName) Expect(err).ShouldNot(HaveOccurred(), fmt.Sprintf("failed to list configmap in namespace: %q", namespace)) }) return nil diff --git a/test/e2e/schedule/in_progress.go b/test/e2e/schedule/in_progress.go new file mode 100644 index 0000000000..3a148a8c1f --- /dev/null +++ b/test/e2e/schedule/in_progress.go @@ -0,0 +1,196 @@ +package schedule + +import ( + "context" + "fmt" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/util/wait" + kbclient "sigs.k8s.io/controller-runtime/pkg/client" + + velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" + "github.com/vmware-tanzu/velero/test" + framework "github.com/vmware-tanzu/velero/test/e2e/test" + k8sutil "github.com/vmware-tanzu/velero/test/util/k8s" + veleroutil "github.com/vmware-tanzu/velero/test/util/velero" +) + +var ScheduleInProgressTest func() = framework.TestFunc(&InProgressCase{}) + +type InProgressCase struct { + framework.TestCase + namespace string + ScheduleName string + ScheduleArgs []string + volume string + podName string + pvcName string + podAnn map[string]string + podSleepDuration time.Duration +} + +func (s *InProgressCase) Init() error { + Expect(s.TestCase.Init()).To(Succeed()) + + s.CaseBaseName = "schedule-backup-creation-test" + s.UUIDgen + s.ScheduleName = "schedule-" + s.CaseBaseName + s.namespace = s.CaseBaseName + podSleepDurationStr := "60s" + s.podSleepDuration, _ = time.ParseDuration(podSleepDurationStr) + + s.TestMsg = &framework.TestMSG{ + Desc: "Schedule controller wouldn't create a new backup when it still has pending or InProgress backup", + FailedMSG: "Failed to verify schedule back creation behavior", + Text: "Schedule controller wouldn't create a new backup when it still has pending or InProgress backup", + } + + s.podAnn = map[string]string{ + "pre.hook.backup.velero.io/container": s.podName, + "pre.hook.backup.velero.io/command": "[\"sleep\", \"" + podSleepDurationStr + "\"]", + "pre.hook.backup.velero.io/timeout": "120s", + } + s.volume = "volume-1" + s.podName = "pod-1" + s.pvcName = "pvc-1" + s.ScheduleArgs = []string{ + "--include-namespaces", s.namespace, + "--schedule=@every 1m", + } + return nil +} + +func (s *InProgressCase) CreateResources() error { + By(fmt.Sprintf("Create namespace %s", s.namespace), func() { + Expect( + k8sutil.CreateNamespace( + s.Ctx, + s.Client, + s.namespace, + ), + ).To(Succeed(), + fmt.Sprintf("Failed to create namespace %s", s.namespace)) + }) + + By(fmt.Sprintf("Create pod %s in namespace %s", s.podName, s.namespace), func() { + _, err := k8sutil.CreatePod( + s.Client, + s.namespace, + s.podName, + test.StorageClassName, + s.pvcName, + []string{s.volume}, + nil, + s.podAnn, + ) + Expect(err).To(Succeed()) + + err = k8sutil.WaitForPods( + s.Ctx, + s.Client, + s.namespace, + []string{s.podName}, + ) + Expect(err).To(Succeed()) + }) + return nil +} + +func (s *InProgressCase) Backup() error { + By(fmt.Sprintf("Creating schedule %s\n", s.ScheduleName), func() { + Expect( + veleroutil.VeleroScheduleCreate( + s.Ctx, + s.VeleroCfg.VeleroCLI, + s.VeleroCfg.VeleroNamespace, + s.ScheduleName, + s.ScheduleArgs, + ), + ).To( + Succeed(), + func() string { + veleroutil.RunDebug( + context.Background(), + s.VeleroCfg.VeleroCLI, + s.VeleroCfg.VeleroNamespace, + "", + "", + ) + + return "Fail to create schedule" + }) + }) + + By("Get backup every half minute.", func() { + err := wait.PollUntilContextTimeout( + s.Ctx, + 30*time.Second, + 5*time.Minute, + true, + func(ctx context.Context) (bool, error) { + backupList := new(velerov1api.BackupList) + + if err := s.Client.Kubebuilder.List( + s.Ctx, + backupList, + &kbclient.ListOptions{ + Namespace: s.VeleroCfg.VeleroNamespace, + LabelSelector: labels.SelectorFromSet(map[string]string{ + velerov1api.ScheduleNameLabel: s.ScheduleName, + }), + }, + ); err != nil { + return false, fmt.Errorf("failed to list backup in %s namespace for schedule %s: %s", + s.VeleroCfg.VeleroNamespace, s.ScheduleName, err.Error()) + } + + if len(backupList.Items) == 0 { + fmt.Println("No backup is found yet. Continue query on the next turn.") + return false, nil + } + + inProgressBackupCount := 0 + for _, backup := range backupList.Items { + if backup.Status.Phase == velerov1api.BackupPhaseInProgress { + inProgressBackupCount++ + } + } + + // There should be at most one in-progress backup per schedule. + Expect(inProgressBackupCount).Should(BeNumerically("<=", 1)) + + // Already ensured at most one in-progress backup when schedule triggered 2 backups. + // Succeed. + if len(backupList.Items) >= 2 { + return true, nil + } + + fmt.Println("Wait until the schedule triggers two backups.") + return false, nil + }, + ) + + Expect(err).To(Succeed()) + }) + return nil +} + +func (s *InProgressCase) Clean() error { + if CurrentSpecReport().Failed() && s.VeleroCfg.FailFast { + fmt.Println("Test case failed and fail fast is enabled. Skip resource clean up.") + } else { + Expect( + veleroutil.VeleroScheduleDelete( + s.Ctx, + s.VeleroCfg.VeleroCLI, + s.VeleroCfg.VeleroNamespace, + s.ScheduleName, + ), + ).To(Succeed()) + Expect(s.TestCase.Clean()).To(Succeed()) + } + + return nil +} diff --git a/test/e2e/schedule/ordered_resources.go b/test/e2e/schedule/ordered_resources.go index 6df2ab17d1..238a014c75 100644 --- a/test/e2e/schedule/ordered_resources.go +++ b/test/e2e/schedule/ordered_resources.go @@ -18,6 +18,7 @@ limitations under the License. //the ordered resources test related to https://github.com/vmware-tanzu/velero/issues/4561 import ( + "context" "fmt" "strings" "time" @@ -25,129 +26,189 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" + "k8s.io/apimachinery/pkg/labels" waitutil "k8s.io/apimachinery/pkg/util/wait" kbclient "sigs.k8s.io/controller-runtime/pkg/client" velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" - . "github.com/vmware-tanzu/velero/test/e2e/test" - . "github.com/vmware-tanzu/velero/test/util/k8s" - . "github.com/vmware-tanzu/velero/test/util/velero" + framework "github.com/vmware-tanzu/velero/test/e2e/test" + k8sutil "github.com/vmware-tanzu/velero/test/util/k8s" + veleroutil "github.com/vmware-tanzu/velero/test/util/velero" ) -var ScheduleOrderedResources func() = TestFunc(&OrderedResources{}) +var ScheduleOrderedResources func() = framework.TestFunc(&OrderedResources{}) type OrderedResources struct { - Namespace string - ScheduleName string - OrderMap map[string]string - ScheduleArgs []string - TestCase + Namespace string + ScheduleName string + OrderResource map[string]string + ScheduleArgs []string + framework.TestCase } func (o *OrderedResources) Init() error { - o.TestCase.Init() + Expect(o.TestCase.Init()).To(Succeed()) + o.CaseBaseName = "ordered-resources-" + o.UUIDgen o.ScheduleName = "schedule-" + o.CaseBaseName o.Namespace = o.CaseBaseName + "-" + o.UUIDgen - o.OrderMap = map[string]string{ + + o.OrderResource = map[string]string{ "deployments": fmt.Sprintf("deploy-%s", o.CaseBaseName), "secrets": fmt.Sprintf("secret-%s", o.CaseBaseName), "configmaps": fmt.Sprintf("configmap-%s", o.CaseBaseName), } - o.TestMsg = &TestMSG{ + + orderResourceArray := make([]string, 0) + for k, v := range o.OrderResource { + orderResourceArray = append( + orderResourceArray, + fmt.Sprintf("%s=%s", k, v), + ) + } + orderResourceStr := strings.Join(orderResourceArray, ";") + + o.TestMsg = &framework.TestMSG{ Desc: "Create a schedule to backup resources in a specific order should be successful", FailedMSG: "Failed to verify schedule backup resources in a specific order", Text: "Create a schedule to backup resources in a specific order should be successful", } - o.ScheduleArgs = []string{"--schedule", "@every 1m", - "--include-namespaces", o.Namespace, "--default-volumes-to-fs-backup", "--ordered-resources"} - var orderStr string - for kind, resource := range o.OrderMap { - orderStr += fmt.Sprintf("%s=%s;", kind, resource) + + o.ScheduleArgs = []string{ + "--schedule", + "@every 1m", + "--include-namespaces", + o.Namespace, + "--default-volumes-to-fs-backup", + "--ordered-resources", + orderResourceStr, } - o.ScheduleArgs = append(o.ScheduleArgs, strings.TrimRight(orderStr, ";")) return nil } + func (o *OrderedResources) CreateResources() error { label := map[string]string{ "orderedresources": "true", } fmt.Printf("Creating resources in %s namespace ...\n", o.Namespace) - if err := CreateNamespace(o.Ctx, o.Client, o.Namespace); err != nil { + if err := k8sutil.CreateNamespace(o.Ctx, o.Client, o.Namespace); err != nil { return errors.Wrapf(err, "failed to create namespace %s", o.Namespace) } + //Create deployment deploymentName := fmt.Sprintf("deploy-%s", o.CaseBaseName) fmt.Printf("Creating deployment %s in %s namespaces ...\n", deploymentName, o.Namespace) - deployment := NewDeployment(deploymentName, o.Namespace, 1, label, nil).Result() - deployment, err := CreateDeployment(o.Client.ClientGo, o.Namespace, deployment) + deployment := k8sutil.NewDeployment(deploymentName, o.Namespace, 1, label, nil).Result() + _, err := k8sutil.CreateDeployment(o.Client.ClientGo, o.Namespace, deployment) if err != nil { return errors.Wrap(err, fmt.Sprintf("failed to create namespace %q with err %v", o.Namespace, err)) } - err = WaitForReadyDeployment(o.Client.ClientGo, o.Namespace, deployment.Name) + err = k8sutil.WaitForReadyDeployment(o.Client.ClientGo, o.Namespace, deployment.Name) if err != nil { return errors.Wrap(err, fmt.Sprintf("failed to ensure job completion in namespace: %q", o.Namespace)) } + //Create Secret secretName := fmt.Sprintf("secret-%s", o.CaseBaseName) fmt.Printf("Creating secret %s in %s namespaces ...\n", secretName, o.Namespace) - _, err = CreateSecret(o.Client.ClientGo, o.Namespace, secretName, label) + _, err = k8sutil.CreateSecret(o.Client.ClientGo, o.Namespace, secretName, label) if err != nil { return errors.Wrap(err, fmt.Sprintf("failed to create secret in the namespace %q", o.Namespace)) } - err = WaitForSecretsComplete(o.Client.ClientGo, o.Namespace, secretName) - if err != nil { - return errors.Wrap(err, fmt.Sprintf("failed to ensure secret completion in namespace: %q", o.Namespace)) - } - //Create Configmap - configmapName := fmt.Sprintf("configmap-%s", o.CaseBaseName) - fmt.Printf("Creating configmap %s in %s namespaces ...\n", configmapName, o.Namespace) - _, err = CreateConfigMap(o.Client.ClientGo, o.Namespace, configmapName, label, nil) - if err != nil { - return errors.Wrap(err, fmt.Sprintf("failed to create configmap in the namespace %q", o.Namespace)) - } - err = WaitForConfigMapComplete(o.Client.ClientGo, o.Namespace, configmapName) - if err != nil { - return errors.Wrap(err, fmt.Sprintf("failed to ensure secret completion in namespace: %q", o.Namespace)) + + //Create ConfigMap + cmName := fmt.Sprintf("configmap-%s", o.CaseBaseName) + fmt.Printf("Creating ConfigMap %s in %s namespaces ...\n", cmName, o.Namespace) + if _, err := k8sutil.CreateConfigMap( + o.Client.ClientGo, + o.Namespace, + cmName, + label, + nil, + ); err != nil { + return errors.Wrap( + err, + fmt.Sprintf("failed to create ConfigMap in the namespace %q", o.Namespace), + ) } + return nil } func (o *OrderedResources) Backup() error { By(fmt.Sprintf("Create schedule the workload in %s namespace", o.Namespace), func() { - err := VeleroScheduleCreate(o.Ctx, o.VeleroCfg.VeleroCLI, o.VeleroCfg.VeleroNamespace, o.ScheduleName, o.ScheduleArgs) + err := veleroutil.VeleroScheduleCreate( + o.Ctx, + o.VeleroCfg.VeleroCLI, + o.VeleroCfg.VeleroNamespace, + o.ScheduleName, + o.ScheduleArgs, + ) Expect(err).To(Succeed(), fmt.Sprintf("Failed to create schedule %s with err %v", o.ScheduleName, err)) }) - return nil -} -func (o *OrderedResources) Destroy() error { - return nil -} - -func (o *OrderedResources) Verify() error { - By(fmt.Sprintf("Checking resource order in %s schedule cr", o.ScheduleName), func() { - err := CheckScheduleWithResourceOrder(o.Ctx, o.VeleroCfg.VeleroCLI, o.VeleroCfg.VeleroNamespace, o.ScheduleName, o.OrderMap) - Expect(err).To(Succeed(), fmt.Sprintf("Failed to check schedule %s with err %v", o.ScheduleName, err)) + By(fmt.Sprintf("Checking resource order in %s schedule CR", o.ScheduleName), func() { + err := veleroutil.CheckScheduleWithResourceOrder( + o.Ctx, + o.VeleroCfg.VeleroCLI, + o.VeleroCfg.VeleroNamespace, + o.ScheduleName, + o.OrderResource, + ) + Expect(err).To( + Succeed(), + fmt.Sprintf("Failed to check schedule %s with err %v", o.ScheduleName, err), + ) }) By("Checking resource order in backup cr", func() { - backupList := new(velerov1api.BackupList) - err := waitutil.PollImmediate(10*time.Second, time.Minute*5, func() (bool, error) { - if err := o.Client.Kubebuilder.List(o.Ctx, backupList, &kbclient.ListOptions{Namespace: o.VeleroCfg.VeleroNamespace}); err != nil { - return false, fmt.Errorf("failed to list backup object in %s namespace with err %v", o.VeleroCfg.VeleroNamespace, err) - } - - for _, backup := range backupList.Items { - if err := CheckBackupWithResourceOrder(o.Ctx, o.VeleroCfg.VeleroCLI, o.VeleroCfg.VeleroNamespace, backup.Name, o.OrderMap); err == nil { - return true, nil + err := waitutil.PollUntilContextTimeout( + o.Ctx, + 30*time.Second, + time.Minute*5, + true, + func(ctx context.Context) (bool, error) { + backupList := new(velerov1api.BackupList) + + if err := o.Client.Kubebuilder.List( + o.Ctx, + backupList, + &kbclient.ListOptions{ + Namespace: o.VeleroCfg.VeleroNamespace, + LabelSelector: labels.SelectorFromSet(map[string]string{ + velerov1api.ScheduleNameLabel: o.ScheduleName, + }), + }, + ); err != nil { + return false, fmt.Errorf("failed to list backup in %s namespace for schedule %s: %s", + o.VeleroCfg.VeleroNamespace, o.ScheduleName, err.Error()) + } + + for _, backup := range backupList.Items { + if err := veleroutil.CheckBackupWithResourceOrder( + o.Ctx, + o.VeleroCfg.VeleroCLI, + o.VeleroCfg.VeleroNamespace, + backup.Name, + o.OrderResource, + ); err == nil { + // After schedule successfully triggers a backup, + // the workload namespace is deleted. + // It's possible the following backup may fail. + // As a result, as long as there is one backup in Completed state, + // the case assumes test pass. + return true, nil + } } - } - fmt.Printf("still finding backup created by schedule %s ...\n", o.ScheduleName) - return false, nil - }) - Expect(err).To(Succeed(), fmt.Sprintf("Failed to check schedule %s created backup with err %v", o.ScheduleName, err)) + fmt.Printf("still finding backup created by schedule %s ...\n", o.ScheduleName) + return false, nil + }) + Expect(err).To( + Succeed(), + fmt.Sprintf("Failed to check schedule %s created backup with err %v", + o.ScheduleName, err), + ) }) return nil } @@ -156,22 +217,15 @@ func (o *OrderedResources) Clean() error { if CurrentSpecReport().Failed() && o.VeleroCfg.FailFast { fmt.Println("Test case failed and fail fast is enabled. Skip resource clean up.") } else { - Expect(VeleroScheduleDelete(o.Ctx, o.VeleroCfg.VeleroCLI, o.VeleroCfg.VeleroNamespace, o.ScheduleName)).To(Succeed()) + Expect(veleroutil.VeleroScheduleDelete( + o.Ctx, + o.VeleroCfg.VeleroCLI, + o.VeleroCfg.VeleroNamespace, + o.ScheduleName, + )).To(Succeed()) + Expect(o.TestCase.Clean()).To(Succeed()) } return nil } - -func (o *OrderedResources) DeleteAllBackups() error { - backupList := new(velerov1api.BackupList) - if err := o.Client.Kubebuilder.List(o.Ctx, backupList, &kbclient.ListOptions{Namespace: o.VeleroCfg.VeleroNamespace}); err != nil { - return fmt.Errorf("failed to list backup object in %s namespace with err %v", o.VeleroCfg.VeleroNamespace, err) - } - for _, backup := range backupList.Items { - if err := VeleroBackupDelete(o.Ctx, o.VeleroCfg.VeleroCLI, o.VeleroCfg.VeleroNamespace, backup.Name); err != nil { - return err - } - } - return nil -} diff --git a/test/e2e/schedule/periodical.go b/test/e2e/schedule/periodical.go new file mode 100644 index 0000000000..330356e998 --- /dev/null +++ b/test/e2e/schedule/periodical.go @@ -0,0 +1,210 @@ +package schedule + +import ( + "context" + "fmt" + "strings" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "k8s.io/apimachinery/pkg/util/wait" + + velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" + framework "github.com/vmware-tanzu/velero/test/e2e/test" + k8sutil "github.com/vmware-tanzu/velero/test/util/k8s" + veleroutil "github.com/vmware-tanzu/velero/test/util/velero" +) + +type PeriodicalCase struct { + framework.TestCase + ScheduleName string + ScheduleArgs []string + Period int // The minimum unit is minute. +} + +var SchedulePeriodicalTest func() = framework.TestFunc(&PeriodicalCase{}) + +func (n *PeriodicalCase) Init() error { + Expect(n.TestCase.Init()).To(Succeed()) + + n.CaseBaseName = "schedule-backup-" + n.UUIDgen + n.NSIncluded = &[]string{n.CaseBaseName} + n.ScheduleName = "schedule-" + n.CaseBaseName + n.RestoreName = "restore-" + n.CaseBaseName + n.TestMsg = &framework.TestMSG{ + Desc: "Set up a scheduled backup defined by a Cron expression", + FailedMSG: "Failed to schedule a backup", + Text: "Should backup periodically according to the schedule", + } + n.ScheduleArgs = []string{ + "--include-namespaces", strings.Join(*n.NSIncluded, ","), + "--schedule=@every 1m", + } + + return nil +} + +func (n *PeriodicalCase) CreateResources() error { + for _, ns := range *n.NSIncluded { + By(fmt.Sprintf("Creating namespaces %s ......\n", ns), func() { + Expect( + k8sutil.CreateNamespace( + n.Ctx, + n.Client, + ns, + ), + ).To( + Succeed(), + fmt.Sprintf("Failed to create namespace %s", ns), + ) + }) + + cmName := n.CaseBaseName + fmt.Printf("Creating ConfigMap %s in namespaces ...%s\n", cmName, ns) + _, err := k8sutil.CreateConfigMap( + n.Client.ClientGo, + ns, + cmName, + nil, + nil, + ) + Expect(err).To(Succeed(), fmt.Sprintf("failed to create ConfigMap in the namespace %q", ns)) + } + return nil +} + +func (n *PeriodicalCase) Backup() error { + By(fmt.Sprintf("Creating schedule %s ......\n", n.ScheduleName), func() { + Expect( + veleroutil.VeleroScheduleCreate( + n.Ctx, + n.VeleroCfg.VeleroCLI, + n.VeleroCfg.VeleroNamespace, + n.ScheduleName, + n.ScheduleArgs, + ), + ).To(Succeed()) + }) + + By(fmt.Sprintf("No immediate backup is created by schedule %s\n", n.ScheduleName), func() { + backups, err := veleroutil.GetBackupsForSchedule( + n.Ctx, + n.Client.Kubebuilder, + n.ScheduleName, + n.VeleroCfg.Namespace, + ) + Expect(err).To(Succeed()) + Expect(backups).To(BeEmpty()) + }) + + By("Wait until schedule triggers backup.", func() { + err := wait.PollUntilContextTimeout( + n.Ctx, + 30*time.Second, + 5*time.Minute, + true, + func(ctx context.Context) (bool, error) { + backups, err := veleroutil.GetBackupsForSchedule( + n.Ctx, + n.Client.Kubebuilder, + n.ScheduleName, + n.VeleroCfg.Namespace, + ) + if err != nil { + fmt.Println("Fail to get backups for schedule.") + return false, err + } + + // The triggered backup completed. + if len(backups) == 1 && + backups[0].Status.Phase == velerov1api.BackupPhaseCompleted { + n.BackupName = backups[0].Name + return true, nil + } + + return false, nil + }, + ) + + Expect(err).To(Succeed()) + }) + + n.RestoreArgs = []string{ + "create", "--namespace", n.VeleroCfg.VeleroNamespace, "restore", n.RestoreName, + "--from-backup", n.BackupName, + "--wait", + } + + By(fmt.Sprintf("Pause schedule %s ......\n", n.ScheduleName), func() { + Expect( + veleroutil.VeleroSchedulePause( + n.Ctx, + n.VeleroCfg.VeleroCLI, + n.VeleroCfg.VeleroNamespace, + n.ScheduleName, + ), + ).To(Succeed()) + }) + + By(("Sleep 2 minutes"), func() { + time.Sleep(2 * time.Minute) + }) + + backups, err := veleroutil.GetBackupsForSchedule( + n.Ctx, + n.Client.Kubebuilder, + n.ScheduleName, + n.VeleroCfg.Namespace, + ) + Expect(err).To(Succeed(), fmt.Sprintf("Fail to get backups from schedule %s", n.ScheduleName)) + + backupCountPostPause := len(backups) + fmt.Printf("After pause, backups count is %d\n", backupCountPostPause) + + By(fmt.Sprintf("Verify no new backups from %s ......\n", n.ScheduleName), func() { + Expect(backupCountPostPause).To(Equal(1)) + }) + + By(fmt.Sprintf("Unpause schedule %s ......\n", n.ScheduleName), func() { + Expect( + veleroutil.VeleroScheduleUnpause( + n.Ctx, + n.VeleroCfg.VeleroCLI, + n.VeleroCfg.VeleroNamespace, + n.ScheduleName, + ), + ).To(Succeed()) + }) + + return nil +} + +func (n *PeriodicalCase) Verify() error { + By("Namespaces were restored", func() { + for _, ns := range *n.NSIncluded { + _, err := k8sutil.GetConfigMap(n.Client.ClientGo, ns, n.CaseBaseName) + Expect(err).ShouldNot(HaveOccurred(), fmt.Sprintf("failed to list CM in namespace: %s\n", ns)) + } + }) + return nil +} + +func (n *PeriodicalCase) Clean() error { + if CurrentSpecReport().Failed() && n.VeleroCfg.FailFast { + fmt.Println("Test case failed and fail fast is enabled. Skip resource clean up.") + } else { + Expect( + veleroutil.VeleroScheduleDelete( + n.Ctx, + n.VeleroCfg.VeleroCLI, + n.VeleroCfg.VeleroNamespace, + n.ScheduleName, + ), + ).To(Succeed()) + + Expect(n.TestCase.Clean()).To(Succeed()) + } + + return nil +} diff --git a/test/e2e/schedule/schedule-backup-creation.go b/test/e2e/schedule/schedule-backup-creation.go deleted file mode 100644 index df30b1752f..0000000000 --- a/test/e2e/schedule/schedule-backup-creation.go +++ /dev/null @@ -1,138 +0,0 @@ -package schedule - -import ( - "context" - "fmt" - "math/rand" - "strings" - "time" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "github.com/vmware-tanzu/velero/test" - framework "github.com/vmware-tanzu/velero/test/e2e/test" - k8sutil "github.com/vmware-tanzu/velero/test/util/k8s" - veleroutil "github.com/vmware-tanzu/velero/test/util/velero" -) - -type ScheduleBackupCreation struct { - framework.TestCase - namespace string - ScheduleName string - ScheduleArgs []string - Period int //Limitation: The unit is minitue only and 60 is divisible by it - randBackupName string - verifyTimes int - volume string - podName string - pvcName string - podAnn map[string]string - podSleepDuration time.Duration -} - -var ScheduleBackupCreationTest func() = framework.TestFunc(&ScheduleBackupCreation{}) - -func (s *ScheduleBackupCreation) Init() error { - s.TestCase.Init() - s.CaseBaseName = "schedule-backup-creation-test" + s.UUIDgen - s.ScheduleName = "schedule-" + s.CaseBaseName - s.namespace = s.GetTestCase().CaseBaseName - s.Period = 3 // Unit is minute - s.verifyTimes = 5 // More larger verify times more confidence we have - podSleepDurationStr := "300s" - s.podSleepDuration, _ = time.ParseDuration(podSleepDurationStr) - s.TestMsg = &framework.TestMSG{ - Desc: "Schedule controller wouldn't create a new backup when it still has pending or InProgress backup", - FailedMSG: "Failed to verify schedule back creation behavior", - Text: "Schedule controller wouldn't create a new backup when it still has pending or InProgress backup", - } - s.podAnn = map[string]string{ - "pre.hook.backup.velero.io/container": s.podName, - "pre.hook.backup.velero.io/command": "[\"sleep\", \"" + podSleepDurationStr + "\"]", - "pre.hook.backup.velero.io/timeout": "600s", - } - s.volume = "volume-1" - s.podName = "pod-1" - s.pvcName = "pvc-1" - s.ScheduleArgs = []string{ - "--include-namespaces", s.namespace, - "--schedule=*/" + fmt.Sprintf("%v", s.Period) + " * * * *", - } - Expect(s.Period).To(BeNumerically("<", 30)) - return nil -} - -func (s *ScheduleBackupCreation) CreateResources() error { - By(fmt.Sprintf("Create namespace %s", s.namespace), func() { - Expect(k8sutil.CreateNamespace(s.Ctx, s.Client, s.namespace)).To(Succeed(), - fmt.Sprintf("Failed to create namespace %s", s.namespace)) - }) - - By(fmt.Sprintf("Create pod %s in namespace %s", s.podName, s.namespace), func() { - _, err := k8sutil.CreatePod(s.Client, s.namespace, s.podName, test.StorageClassName, s.pvcName, []string{s.volume}, nil, s.podAnn) - Expect(err).To(Succeed()) - err = k8sutil.WaitForPods(s.Ctx, s.Client, s.namespace, []string{s.podName}) - Expect(err).To(Succeed()) - }) - return nil -} - -func (s *ScheduleBackupCreation) Backup() error { - // Wait until the beginning of the given period to create schedule, it will give us - // a predictable period to wait for the first scheduled backup, and verify no immediate - // scheduled backup was created between schedule creation and first scheduled backup. - By(fmt.Sprintf("Creating schedule %s ......\n", s.ScheduleName), func() { - for i := 0; i < s.Period*60/30; i++ { - time.Sleep(30 * time.Second) - now := time.Now().Minute() - triggerNow := now % s.Period - if triggerNow == 0 { - Expect(veleroutil.VeleroScheduleCreate(s.Ctx, s.VeleroCfg.VeleroCLI, s.VeleroCfg.VeleroNamespace, s.ScheduleName, s.ScheduleArgs)).To(Succeed(), func() string { - veleroutil.RunDebug(context.Background(), s.VeleroCfg.VeleroCLI, s.VeleroCfg.VeleroNamespace, "", "") - return "Fail to create schedule" - }) - break - } - } - }) - - By("Delay one more minute to make sure the new backup was created in the given period", func() { - time.Sleep(1 * time.Minute) - }) - - By(fmt.Sprintf("Get backups every %d minute, and backups count should increase 1 more step in the same pace\n", s.Period), func() { - for i := 1; i <= s.verifyTimes; i++ { - fmt.Printf("Start to sleep %d minute #%d time...\n", s.podSleepDuration, i) - mi, _ := time.ParseDuration("60s") - time.Sleep(s.podSleepDuration + mi) - bMap := make(map[string]string) - backupsInfo, err := veleroutil.GetScheduledBackupsCreationTime(s.Ctx, s.VeleroCfg.VeleroCLI, "default", s.ScheduleName) - Expect(err).To(Succeed()) - Expect(backupsInfo).To(HaveLen(i)) - for index, bi := range backupsInfo { - bList := strings.Split(bi, ",") - fmt.Printf("Backup %d: %v\n", index, bList) - bMap[bList[0]] = bList[1] - _, err := time.Parse("2006-01-02 15:04:05 -0700 MST", bList[1]) - Expect(err).To(Succeed()) - } - if i == s.verifyTimes-1 { - backupInfo := backupsInfo[rand.Intn(len(backupsInfo))] - s.randBackupName = strings.Split(backupInfo, ",")[0] - } - } - }) - return nil -} - -func (s *ScheduleBackupCreation) Clean() error { - if CurrentSpecReport().Failed() && s.VeleroCfg.FailFast { - fmt.Println("Test case failed and fail fast is enabled. Skip resource clean up.") - } else { - Expect(veleroutil.VeleroScheduleDelete(s.Ctx, s.VeleroCfg.VeleroCLI, s.VeleroCfg.VeleroNamespace, s.ScheduleName)).To(Succeed()) - Expect(s.TestCase.Clean()).To(Succeed()) - } - - return nil -} diff --git a/test/e2e/schedule/schedule.go b/test/e2e/schedule/schedule.go deleted file mode 100644 index f1a4bfe213..0000000000 --- a/test/e2e/schedule/schedule.go +++ /dev/null @@ -1,214 +0,0 @@ -package schedule - -import ( - "context" - "fmt" - "math/rand" - "strings" - "time" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - . "github.com/vmware-tanzu/velero/test/e2e/test" - . "github.com/vmware-tanzu/velero/test/util/k8s" - . "github.com/vmware-tanzu/velero/test/util/velero" -) - -type ScheduleBackup struct { - TestCase - ScheduleName string - ScheduleArgs []string - Period int //Limitation: The unit is minitue only and 60 is divisible by it - randBackupName string - verifyTimes int -} - -var ScheduleBackupTest func() = TestFunc(&ScheduleBackup{}) - -func (n *ScheduleBackup) Init() error { - n.TestCase.Init() - n.CaseBaseName = "schedule-backup-" + n.UUIDgen - n.NSIncluded = &[]string{n.CaseBaseName} - n.ScheduleName = "schedule-" + n.CaseBaseName - n.RestoreName = "restore-" + n.CaseBaseName - n.Period = 3 // Unit is minute - n.verifyTimes = 5 // More larger verify times more confidence we have - n.TestMsg = &TestMSG{ - Desc: "Set up a scheduled backup defined by a Cron expression", - FailedMSG: "Failed to schedule a backup", - Text: "should backup periodly according to the schedule", - } - n.ScheduleArgs = []string{ - "--include-namespaces", strings.Join(*n.NSIncluded, ","), - "--schedule=*/" + fmt.Sprintf("%v", n.Period) + " * * * *", - } - - Expect(n.Period).To(BeNumerically("<", 30)) - return nil -} -func (n *ScheduleBackup) CreateResources() error { - for _, ns := range *n.NSIncluded { - By(fmt.Sprintf("Creating namespaces %s ......\n", ns), func() { - Expect(CreateNamespace(n.Ctx, n.Client, ns)).To(Succeed(), fmt.Sprintf("Failed to create namespace %s", ns)) - }) - configmaptName := n.CaseBaseName - fmt.Printf("Creating configmap %s in namespaces ...%s\n", configmaptName, ns) - _, err := CreateConfigMap(n.Client.ClientGo, ns, configmaptName, nil, nil) - Expect(err).To(Succeed(), fmt.Sprintf("failed to create configmap in the namespace %q", ns)) - Expect(WaitForConfigMapComplete(n.Client.ClientGo, ns, configmaptName)).To(Succeed(), - fmt.Sprintf("failed to ensure secret completion in namespace: %q", ns)) - } - return nil -} - -func (n *ScheduleBackup) Backup() error { - // Wait until the beginning of the given period to create schedule, it will give us - // a predictable period to wait for the first scheduled backup, and verify no immediate - // scheduled backup was created between schedule creation and first scheduled backup. - By(fmt.Sprintf("Creating schedule %s ......\n", n.ScheduleName), func() { - for i := 0; i < n.Period*60/30; i++ { - time.Sleep(30 * time.Second) - now := time.Now().Minute() - triggerNow := now % n.Period - if triggerNow == 0 { - Expect(VeleroScheduleCreate(n.Ctx, n.VeleroCfg.VeleroCLI, n.VeleroCfg.VeleroNamespace, n.ScheduleName, n.ScheduleArgs)).To(Succeed(), func() string { - RunDebug(context.Background(), n.VeleroCfg.VeleroCLI, n.VeleroCfg.VeleroNamespace, "", "") - return "Fail to create schedule" - }) - break - } - } - }) - - By(fmt.Sprintf("Schedule %s is created without any delay\n", n.ScheduleName), func() { - creationTimestamp, err := GetSchedule(n.Ctx, n.VeleroCfg.VeleroNamespace, n.ScheduleName) - Expect(err).To(Succeed()) - - creationTime, err := time.Parse(time.RFC3339, strings.Replace(creationTimestamp, "'", "", -1)) - Expect(err).To(Succeed()) - fmt.Printf("Schedule %s created at %s\n", n.ScheduleName, creationTime) - now := time.Now() - diff := creationTime.Sub(now) - Expect(diff.Minutes()).To(BeNumerically("<", 1)) - }) - - By(fmt.Sprintf("No immediate backup is created by schedule %s\n", n.ScheduleName), func() { - for i := 0; i < n.Period; i++ { - time.Sleep(1 * time.Minute) - now := time.Now() - fmt.Printf("Get backup for #%d time at %v\n", i, now) - //Ignore the last minute in the period avoiding met the 1st backup by schedule - if i != n.Period-1 { - backupsInfo, err := GetScheduledBackupsCreationTime(n.Ctx, n.VeleroCfg.VeleroCLI, "default", n.ScheduleName) - Expect(err).To(Succeed()) - Expect(backupsInfo).To(BeEmpty()) - } - } - }) - - By("Delay one more minute to make sure the new backup was created in the given period", func() { - time.Sleep(time.Minute) - }) - - By(fmt.Sprintf("Get backups every %d minute, and backups count should increase 1 more step in the same pace\n", n.Period), func() { - for i := 0; i < n.verifyTimes; i++ { - fmt.Printf("Start to sleep %d minute #%d time...\n", n.Period, i+1) - time.Sleep(time.Duration(n.Period) * time.Minute) - bMap := make(map[string]string) - backupsInfo, err := GetScheduledBackupsCreationTime(n.Ctx, n.VeleroCfg.VeleroCLI, "default", n.ScheduleName) - Expect(err).To(Succeed()) - Expect(backupsInfo).To(HaveLen(i + 2)) - for index, bi := range backupsInfo { - bList := strings.Split(bi, ",") - fmt.Printf("Backup %d: %v\n", index, bList) - bMap[bList[0]] = bList[1] - _, err := time.Parse("2006-01-02 15:04:05 -0700 MST", bList[1]) - Expect(err).To(Succeed()) - } - if i == n.verifyTimes-1 { - backupInfo := backupsInfo[rand.Intn(len(backupsInfo))] - n.randBackupName = strings.Split(backupInfo, ",")[0] - } - } - }) - - n.BackupName = strings.Replace(n.randBackupName, " ", "", -1) - - n.RestoreArgs = []string{ - "create", "--namespace", n.VeleroCfg.VeleroNamespace, "restore", n.RestoreName, - "--from-backup", n.BackupName, - "--wait", - } - - backupsInfo, err := GetScheduledBackupsCreationTime(n.Ctx, n.VeleroCfg.VeleroCLI, "default", n.ScheduleName) - Expect(err).To(Succeed(), fmt.Sprintf("Fail to get backups from schedule %s", n.ScheduleName)) - fmt.Println(backupsInfo) - backupCount := len(backupsInfo) - - By(fmt.Sprintf("Pause schedule %s ......\n", n.ScheduleName), func() { - Expect(VeleroSchedulePause(n.Ctx, n.VeleroCfg.VeleroCLI, n.VeleroCfg.VeleroNamespace, n.ScheduleName)).To(Succeed(), func() string { - RunDebug(context.Background(), n.VeleroCfg.VeleroCLI, n.VeleroCfg.VeleroNamespace, "", "") - return "Fail to pause schedule" - }) - }) - - periodCount := 3 - sleepDuration := time.Duration(n.Period*periodCount) * time.Minute - By(fmt.Sprintf("Sleep for %s ......\n", sleepDuration), func() { - time.Sleep(sleepDuration) - }) - - backupsInfo, err = GetScheduledBackupsCreationTime(n.Ctx, n.VeleroCfg.VeleroCLI, "default", n.ScheduleName) - Expect(err).To(Succeed(), fmt.Sprintf("Fail to get backups from schedule %s", n.ScheduleName)) - - backupCountPostPause := len(backupsInfo) - fmt.Printf("After pause, backkups count is %d\n", backupCountPostPause) - - By(fmt.Sprintf("Verify no new backups from %s ......\n", n.ScheduleName), func() { - Expect(backupCountPostPause).To(Equal(backupCount)) - }) - - By(fmt.Sprintf("Unpause schedule %s ......\n", n.ScheduleName), func() { - Expect(VeleroScheduleUnpause(n.Ctx, n.VeleroCfg.VeleroCLI, n.VeleroCfg.VeleroNamespace, n.ScheduleName)).To(Succeed(), func() string { - RunDebug(context.Background(), n.VeleroCfg.VeleroCLI, n.VeleroCfg.VeleroNamespace, "", "") - return "Fail to unpause schedule" - }) - }) - - By(fmt.Sprintf("Sleep for %s ......\n", sleepDuration), func() { - time.Sleep(sleepDuration) - }) - - backupsInfo, err = GetScheduledBackupsCreationTime(n.Ctx, n.VeleroCfg.VeleroCLI, "default", n.ScheduleName) - Expect(err).To(Succeed(), fmt.Sprintf("Fail to get backups from schedule %s", n.ScheduleName)) - fmt.Println(backupsInfo) - backupCountPostUnpause := len(backupsInfo) - fmt.Printf("After unpause, backkups count is %d\n", backupCountPostUnpause) - By(fmt.Sprintf("Verify no new backups by schedule %s ......\n", n.ScheduleName), func() { - Expect(backupCountPostUnpause - backupCount).To(BeNumerically(">=", periodCount-1)) - }) - return nil -} - -func (n *ScheduleBackup) Verify() error { - By("Namespaces were restored", func() { - for _, ns := range *n.NSIncluded { - configmap, err := GetConfigmap(n.Client.ClientGo, ns, n.CaseBaseName) - fmt.Printf("Restored configmap is %v\n", configmap) - Expect(err).ShouldNot(HaveOccurred(), fmt.Sprintf("failed to list configmap in namespace: %q\n", ns)) - } - }) - return nil -} - -func (n *ScheduleBackup) Clean() error { - if CurrentSpecReport().Failed() && n.VeleroCfg.FailFast { - fmt.Println("Test case failed and fail fast is enabled. Skip resource clean up.") - } else { - Expect(VeleroScheduleDelete(n.Ctx, n.VeleroCfg.VeleroCLI, n.VeleroCfg.VeleroNamespace, n.ScheduleName)).To(Succeed()) - Expect(n.TestCase.Clean()).To(Succeed()) - } - - return nil -} diff --git a/test/util/k8s/configmap.go b/test/util/k8s/configmap.go index 5a49932bae..41f1844329 100644 --- a/test/util/k8s/configmap.go +++ b/test/util/k8s/configmap.go @@ -57,9 +57,9 @@ func CreateConfigMapFromYAMLData(c clientset.Interface, yamlData, cmName, namesp } // WaitForConfigMapComplete uses c to wait for completions to complete for the Job jobName in namespace ns. -func WaitForConfigMapComplete(c clientset.Interface, ns, configmapName string) error { +func WaitForConfigMapComplete(c clientset.Interface, ns, cmName string) error { return wait.Poll(PollInterval, PollTimeout, func() (bool, error) { - _, err := c.CoreV1().ConfigMaps(ns).Get(context.TODO(), configmapName, metav1.GetOptions{}) + _, err := c.CoreV1().ConfigMaps(ns).Get(context.TODO(), cmName, metav1.GetOptions{}) if err != nil { return false, err } @@ -67,13 +67,13 @@ func WaitForConfigMapComplete(c clientset.Interface, ns, configmapName string) e }) } -func GetConfigmap(c clientset.Interface, ns, secretName string) (*v1.ConfigMap, error) { +func GetConfigMap(c clientset.Interface, ns, secretName string) (*v1.ConfigMap, error) { return c.CoreV1().ConfigMaps(ns).Get(context.TODO(), secretName, metav1.GetOptions{}) } func DeleteConfigMap(c clientset.Interface, ns, name string) error { if err := c.CoreV1().ConfigMaps(ns).Delete(context.TODO(), name, metav1.DeleteOptions{}); err != nil { - return errors.Wrap(err, fmt.Sprintf("failed to delete configmap in namespace %q", ns)) + return errors.Wrap(err, fmt.Sprintf("failed to delete ConfigMap in namespace %q", ns)) } return nil } diff --git a/test/util/velero/install.go b/test/util/velero/install.go index 7d6a6d1c49..cc81813bc9 100644 --- a/test/util/velero/install.go +++ b/test/util/velero/install.go @@ -250,7 +250,7 @@ func cleanVSpherePluginConfig(c clientset.Interface, ns, secretName, configMapNa } //clear configmap - _, err = k8s.GetConfigmap(c, ns, configMapName) + _, err = k8s.GetConfigMap(c, ns, configMapName) if err == nil { if err := k8s.WaitForConfigmapDelete(c, ns, configMapName); err != nil { return errors.WithMessagef(err, "Failed to clear up vsphere plugin configmap in %s namespace", ns) diff --git a/test/util/velero/velero_utils.go b/test/util/velero/velero_utils.go index 639fefb015..1605398529 100644 --- a/test/util/velero/velero_utils.go +++ b/test/util/velero/velero_utils.go @@ -37,6 +37,7 @@ import ( "github.com/pkg/errors" "golang.org/x/exp/slices" "golang.org/x/mod/semver" + "k8s.io/apimachinery/pkg/labels" ver "k8s.io/apimachinery/pkg/util/version" "k8s.io/apimachinery/pkg/util/wait" kbclient "sigs.k8s.io/controller-runtime/pkg/client" @@ -334,7 +335,7 @@ func checkRestorePhase(ctx context.Context, veleroCLI string, veleroNamespace st func checkSchedulePhase(ctx context.Context, veleroCLI, veleroNamespace, scheduleName string) error { return wait.PollImmediate(time.Second*5, time.Minute*2, func() (bool, error) { - checkCMD := exec.CommandContext(ctx, veleroCLI, "--namespace", veleroNamespace, "schedule", "get", scheduleName, "-ojson") + checkCMD := exec.CommandContext(ctx, veleroCLI, "--namespace", veleroNamespace, "schedule", "get", scheduleName, "-o", "json") jsonBuf, err := common.CMDExecWithOutput(checkCMD) if err != nil { return false, err @@ -354,7 +355,7 @@ func checkSchedulePhase(ctx context.Context, veleroCLI, veleroNamespace, schedul } func checkSchedulePause(ctx context.Context, veleroCLI, veleroNamespace, scheduleName string, pause bool) error { - checkCMD := exec.CommandContext(ctx, veleroCLI, "--namespace", veleroNamespace, "schedule", "get", scheduleName, "-ojson") + checkCMD := exec.CommandContext(ctx, veleroCLI, "--namespace", veleroNamespace, "schedule", "get", scheduleName, "-o", "json") jsonBuf, err := common.CMDExecWithOutput(checkCMD) if err != nil { return err @@ -372,7 +373,7 @@ func checkSchedulePause(ctx context.Context, veleroCLI, veleroNamespace, schedul return nil } func CheckScheduleWithResourceOrder(ctx context.Context, veleroCLI, veleroNamespace, scheduleName string, order map[string]string) error { - checkCMD := exec.CommandContext(ctx, veleroCLI, "--namespace", veleroNamespace, "schedule", "get", scheduleName, "-ojson") + checkCMD := exec.CommandContext(ctx, veleroCLI, "--namespace", veleroNamespace, "schedule", "get", scheduleName, "-o", "json") jsonBuf, err := common.CMDExecWithOutput(checkCMD) if err != nil { return err @@ -393,8 +394,8 @@ func CheckScheduleWithResourceOrder(ctx context.Context, veleroCLI, veleroNamesp } } -func CheckBackupWithResourceOrder(ctx context.Context, veleroCLI, veleroNamespace, backupName string, order map[string]string) error { - checkCMD := exec.CommandContext(ctx, veleroCLI, "--namespace", veleroNamespace, "get", "backup", backupName, "-ojson") +func CheckBackupWithResourceOrder(ctx context.Context, veleroCLI, veleroNamespace, backupName string, orderResources map[string]string) error { + checkCMD := exec.CommandContext(ctx, veleroCLI, "--namespace", veleroNamespace, "get", "backup", backupName, "-o", "json") jsonBuf, err := common.CMDExecWithOutput(checkCMD) if err != nil { return err @@ -407,10 +408,10 @@ func CheckBackupWithResourceOrder(ctx context.Context, veleroCLI, veleroNamespac if backup.Status.Phase != velerov1api.BackupPhaseCompleted { return errors.Errorf("Unexpected restore phase got %s, expecting %s", backup.Status.Phase, velerov1api.BackupPhaseCompleted) } - if reflect.DeepEqual(backup.Spec.OrderedResources, order) { + if reflect.DeepEqual(backup.Spec.OrderedResources, orderResources) { return nil } else { - return fmt.Errorf("resource order %v set in backup command is not equal with order %v stored in backup cr", order, backup.Spec.OrderedResources) + return fmt.Errorf("resource order %v set in backup command is not equal with order %v stored in backup cr", orderResources, backup.Spec.OrderedResources) } } @@ -452,7 +453,7 @@ func VeleroBackupNamespace(ctx context.Context, veleroCLI, veleroNamespace strin args = append(args, "--snapshot-volumes=false") } // if "--snapshot-volumes" is not provide, snapshot should be taken as default behavior. } else { // DefaultVolumesToFsBackup is false - // Althrough DefaultVolumesToFsBackup is false, but probably DefaultVolumesToFsBackup + // Although DefaultVolumesToFsBackup is false, but probably DefaultVolumesToFsBackup // was set to true in installation CLI in snapshot volume test, so set DefaultVolumesToFsBackup // to false specifically to make sure volume snapshot was taken if backupCfg.UseVolumeSnapshots { @@ -462,7 +463,7 @@ func VeleroBackupNamespace(ctx context.Context, veleroCLI, veleroNamespace strin args = append(args, "--default-volumes-to-fs-backup=false") } } - // Also Althrough DefaultVolumesToFsBackup is false, but probably DefaultVolumesToFsBackup + // Although DefaultVolumesToFsBackup is false, but probably DefaultVolumesToFsBackup // was set to true in installation CLI in FS volume backup test, so do nothing here, no DefaultVolumesToFsBackup // appear in backup CLI } @@ -1181,46 +1182,29 @@ func GetLatestSuccessBackupsFromBSL(ctx context.Context, veleroCLI, bslName stri return backups[0], nil } -func GetScheduledBackupsCreationTime(ctx context.Context, veleroCLI, bslName, scheduleName string) ([]string, error) { - var creationTimes []string - backups, err := GetBackupsCreationTime(ctx, veleroCLI, bslName) - if err != nil { - return nil, err - } - for _, b := range backups { - if strings.Contains(b, scheduleName) { - creationTimes = append(creationTimes, b) - } - } - return creationTimes, nil -} -func GetBackupsCreationTime(ctx context.Context, veleroCLI, bslName string) ([]string, error) { - args1 := []string{"get", "backups"} - createdTime := "$1,\",\" $5,$6,$7,$8" - if strings.TrimSpace(bslName) != "" { - args1 = append(args1, "-l", "velero.io/storage-location="+bslName) - } - cmds := []*common.OsCommandLine{} - - cmd := &common.OsCommandLine{ - Cmd: veleroCLI, - Args: args1, - } - cmds = append(cmds, cmd) - - cmd = &common.OsCommandLine{ - Cmd: "awk", - Args: []string{"{print " + createdTime + "}"}, - } - cmds = append(cmds, cmd) - - cmd = &common.OsCommandLine{ - Cmd: "tail", - Args: []string{"-n", "+2"}, - } - cmds = append(cmds, cmd) +func GetBackupsForSchedule( + ctx context.Context, + client kbclient.Client, + scheduleName string, + namespace string, +) ([]velerov1api.Backup, error) { + backupList := new(velerov1api.BackupList) - return common.GetListByCmdPipes(ctx, cmds) + if err := client.List( + ctx, + backupList, + &kbclient.ListOptions{ + Namespace: namespace, + LabelSelector: labels.SelectorFromSet(map[string]string{ + velerov1api.ScheduleNameLabel: scheduleName, + }), + }, + ); err != nil { + return nil, fmt.Errorf("failed to list backup in %s namespace for schedule %s: %s", + namespace, scheduleName, err.Error()) + } + + return backupList.Items, nil } func GetAllBackups(ctx context.Context, veleroCLI string) ([]string, error) {