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 <xun.jiang@broadcom.com>
pull/8430/head
Xun Jiang 2024-11-19 15:07:06 +08:00
parent 9f0026d7dc
commit 226d50d9cb
10 changed files with 576 additions and 484 deletions

View File

@ -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(

View File

@ -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

View File

@ -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
}

View File

@ -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)
}
err := waitutil.PollUntilContextTimeout(
o.Ctx,
30*time.Second,
time.Minute*5,
true,
func(ctx context.Context) (bool, error) {
backupList := new(velerov1api.BackupList)
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
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())
}
}
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))
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),
)
})
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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)

View File

@ -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{}
func GetBackupsForSchedule(
ctx context.Context,
client kbclient.Client,
scheduleName string,
namespace string,
) ([]velerov1api.Backup, error) {
backupList := new(velerov1api.BackupList)
cmd := &common.OsCommandLine{
Cmd: veleroCLI,
Args: args1,
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())
}
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)
return common.GetListByCmdPipes(ctx, cmds)
return backupList.Items, nil
}
func GetAllBackups(ctx context.Context, veleroCLI string) ([]string, error) {