-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5355 from danfengliu/add-schedule-backup-timing-e…
…2e-test Add schedule backup timing E2E test
- Loading branch information
Showing
7 changed files
with
223 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Add E2E test for schedule backup |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
package backups | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"math/rand" | ||
"strings" | ||
"time" | ||
|
||
. "github.com/onsi/ginkgo" | ||
. "github.com/onsi/gomega" | ||
|
||
. "github.com/vmware-tanzu/velero/test/e2e" | ||
. "github.com/vmware-tanzu/velero/test/e2e/test" | ||
. "github.com/vmware-tanzu/velero/test/e2e/util/k8s" | ||
. "github.com/vmware-tanzu/velero/test/e2e/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{TestCase: TestCase{NSBaseName: "ns", NSIncluded: &[]string{"ns1"}}}) | ||
|
||
func (n *ScheduleBackup) Init() error { | ||
n.Client = TestClientInstance | ||
n.Period = 3 | ||
n.verifyTimes = 5 // More verify times more confidence | ||
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", | ||
} | ||
return nil | ||
} | ||
|
||
func (n *ScheduleBackup) StartRun() error { | ||
|
||
n.ScheduleName = n.ScheduleName + "schedule-" + UUIDgen.String() | ||
n.RestoreName = n.RestoreName + "restore-ns-mapping-" + UUIDgen.String() | ||
|
||
n.ScheduleArgs = []string{ | ||
"schedule", "create", "--namespace", VeleroCfg.VeleroNamespace, n.ScheduleName, | ||
"--include-namespaces", strings.Join(*n.NSIncluded, ","), | ||
"--schedule=*/" + fmt.Sprintf("%v", n.Period) + " * * * *", | ||
} | ||
|
||
return nil | ||
} | ||
func (n *ScheduleBackup) CreateResources() error { | ||
n.Ctx, _ = context.WithTimeout(context.Background(), 60*time.Minute) | ||
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.NSBaseName | ||
fmt.Printf("Creating configmap %s in namespaces ...%s\n", configmaptName, ns) | ||
_, err := CreateConfigMap(n.Client.ClientGo, ns, configmaptName, 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("ailed 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(VeleroCmdExec(n.Ctx, VeleroCfg.VeleroCLI, n.ScheduleArgs)).To(Succeed()) | ||
break | ||
} | ||
} | ||
}) | ||
return nil | ||
} | ||
func (n *ScheduleBackup) Destroy() error { | ||
By(fmt.Sprintf("Schedule %s is created without any delay\n", n.ScheduleName), func() { | ||
creationTimestamp, err := GetSchedule(context.Background(), 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() < 1).To(Equal(true)) | ||
}) | ||
|
||
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(context.Background(), VeleroCfg.VeleroCLI, "default", n.ScheduleName) | ||
Expect(err).To(Succeed()) | ||
Expect(len(backupsInfo) == 0).To(Equal(true)) | ||
} | ||
} | ||
}) | ||
|
||
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", 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(context.Background(), VeleroCfg.VeleroCLI, "default", n.ScheduleName) | ||
Expect(err).To(Succeed()) | ||
Expect(len(backupsInfo) == i+2).To(Equal(true)) | ||
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) | ||
|
||
By("Delete all namespaces", func() { | ||
Expect(CleanupNamespacesWithPoll(n.Ctx, n.Client, n.NSBaseName)).To(Succeed(), "Could cleanup retrieve namespaces") | ||
}) | ||
|
||
n.RestoreArgs = []string{ | ||
"create", "--namespace", VeleroCfg.VeleroNamespace, "restore", n.RestoreName, | ||
"--from-backup", n.BackupName, | ||
"--wait", | ||
} | ||
|
||
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.NSBaseName) | ||
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters