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
parent
9f0026d7dc
commit
226d50d9cb
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue