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" "github.com/vmware-tanzu/velero/test/util/common" 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() { labels := make(map[string]string) if s.VeleroCfg.WorkerOS == common.WorkerOSWindows { labels = map[string]string{ "pod-security.kubernetes.io/enforce": "privileged", "pod-security.kubernetes.io/enforce-version": "latest", } } Expect( k8sutil.CreateNamespaceWithLabel( s.Ctx, s.Client, s.namespace, labels, ), ).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, s.VeleroCfg.ImageRegistryProxy, s.VeleroCfg.WorkerOS, ) 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 }