Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.

Commit d8800a1

Browse files
committed
backup: add e2e slow test for periodic backup
1 parent 8737c73 commit d8800a1

3 files changed

Lines changed: 123 additions & 0 deletions

File tree

test/e2e/e2eslow/backup_restore_test.go

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,20 @@
1515
package e2eslow
1616

1717
import (
18+
"context"
1819
"errors"
1920
"fmt"
2021
"math/rand"
2122
"os"
2223
"path"
24+
"sort"
25+
"strings"
2326
"testing"
2427
"time"
2528

2629
api "github.com/coreos/etcd-operator/pkg/apis/etcd/v1beta2"
30+
"github.com/coreos/etcd-operator/pkg/backup/writer"
31+
"github.com/coreos/etcd-operator/pkg/util/awsutil/s3factory"
2732
"github.com/coreos/etcd-operator/pkg/util/etcdutil"
2833
"github.com/coreos/etcd-operator/pkg/util/k8sutil"
2934
"github.com/coreos/etcd-operator/pkg/util/retryutil"
@@ -78,6 +83,7 @@ func TestBackupAndRestore(t *testing.T) {
7883
s3Path := path.Join(os.Getenv("TEST_S3_BUCKET"), "jenkins", suffix, time.Now().Format(time.RFC3339), "etcd.backup")
7984

8085
testEtcdBackupOperatorForS3Backup(t, clusterName, operatorClientTLSSecret, s3Path)
86+
testEtcdBackupOperatorForPeriodicS3Backup(t, clusterName, operatorClientTLSSecret, s3Path)
8187
testEtcdRestoreOperatorForS3Source(t, clusterName, s3Path)
8288
}
8389

@@ -166,6 +172,97 @@ func testEtcdBackupOperatorForS3Backup(t *testing.T, clusterName, operatorClient
166172
t.Logf("backup for cluster (%s) has been saved", clusterName)
167173
}
168174

175+
// testEtcdBackupOperatorForPeriodicS3Backup test if etcd backup operator can periodically backup and upload to s3.
176+
// This e2e test would check basic function of periodic backup and MaxBackup functionality
177+
func testEtcdBackupOperatorForPeriodicS3Backup(t *testing.T, clusterName, operatorClientTLSSecret, s3Path string) {
178+
f := framework.Global
179+
180+
endpoints, err := getEndpoints(f.KubeClient, true, f.Namespace, clusterName)
181+
if err != nil {
182+
t.Fatalf("failed to get endpoints: %v", err)
183+
}
184+
backupCR := e2eutil.NewS3Backup(endpoints, clusterName, s3Path, os.Getenv("TEST_AWS_SECRET"), operatorClientTLSSecret)
185+
// enable periodic backup
186+
backupCR.Spec.BackupPolicy = &api.BackupPolicy{BackupIntervalInSecond: 5, MaxBackups: 2}
187+
backupS3Source := backupCR.Spec.BackupSource.S3
188+
189+
// initialize s3 client
190+
s3cli, err := s3factory.NewClientFromSecret(
191+
f.KubeClient, f.Namespace, backupS3Source.Endpoint, backupS3Source.AWSSecret)
192+
if err != nil {
193+
t.Fatalf("failed to initialize s3client: %v", err)
194+
}
195+
wr := writer.NewS3Writer(s3cli.S3)
196+
197+
// check if there is existing backup file
198+
allBackups, err := wr.List(context.Background(), backupS3Source.Path)
199+
if err != nil {
200+
t.Fatalf("failed to list backup files: %v", err)
201+
}
202+
if len(allBackups) > 0 {
203+
t.Logf("existing backup file is detected: %s", strings.Join(allBackups, ","))
204+
// try to delete all existing backup files
205+
if err := e2eutil.DeleteBackupFiles(wr, allBackups); err != nil {
206+
t.Fatalf("failed to delete existing backup: %v", err)
207+
}
208+
// make sure no exisiting backups
209+
// will wait for 10 sec until deleting operation completed
210+
if err := e2eutil.WaitUntilNoBackupFiles(wr, backupS3Source.Path, 10); err != nil {
211+
t.Fatalf("failed to make sure no old backup: %v", err)
212+
}
213+
}
214+
215+
// create etcdbackup resource
216+
eb, err := f.CRClient.EtcdV1beta2().EtcdBackups(f.Namespace).Create(backupCR)
217+
if err != nil {
218+
t.Fatalf("failed to create etcd back cr: %v", err)
219+
}
220+
defer func() {
221+
if err := f.CRClient.EtcdV1beta2().EtcdBackups(f.Namespace).Delete(eb.Name, nil); err != nil {
222+
t.Fatalf("failed to delete etcd backup cr: %v", err)
223+
}
224+
// cleanup backup files
225+
allBackups, err = wr.List(context.Background(), backupS3Source.Path)
226+
if err != nil {
227+
t.Fatalf("failed to list backup files: %v", err)
228+
}
229+
if err := e2eutil.DeleteBackupFiles(wr, allBackups); err != nil {
230+
t.Fatalf("failed to cleanup backup files: %v", err)
231+
}
232+
}()
233+
234+
var firstBackup string
235+
var periodicBackup, maxBackup bool
236+
// Check if periodic backup is correctly performed
237+
// Check if maxBackup is correctly performed
238+
err = retryutil.Retry(time.Second, 20, func() (bool, error) {
239+
allBackups, err = wr.List(context.Background(), backupS3Source.Path)
240+
sort.Sort(sort.StringSlice(allBackups))
241+
if err != nil {
242+
return false, fmt.Errorf("failed to list backup files: %v", err)
243+
}
244+
if len(allBackups) > 0 {
245+
if firstBackup == "" {
246+
firstBackup = allBackups[0]
247+
}
248+
// Check if firt seen backup file is deleted or not
249+
if firstBackup != allBackups[0] {
250+
maxBackup = true
251+
}
252+
if len(allBackups) > 1 {
253+
periodicBackup = true
254+
}
255+
}
256+
if periodicBackup && maxBackup {
257+
return true, nil
258+
}
259+
return false, nil
260+
})
261+
if err != nil {
262+
t.Fatalf("failed to verify periodic bakcup: %v", err)
263+
}
264+
}
265+
169266
// testEtcdRestoreOperatorForS3Source tests if the restore-operator can restore an etcd cluster from an S3 restore source
170267
func testEtcdRestoreOperatorForS3Source(t *testing.T, clusterName, s3Path string) {
171268
f := framework.Global

test/e2e/e2eutil/util.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@ package e2eutil
1616

1717
import (
1818
"bytes"
19+
"context"
1920
"fmt"
2021
"testing"
2122
"time"
2223

24+
"github.com/coreos/etcd-operator/pkg/backup/writer"
2325
"github.com/coreos/etcd-operator/pkg/util/k8sutil"
2426

2527
"k8s.io/api/core/v1"
@@ -62,3 +64,12 @@ func printContainerStatus(buf *bytes.Buffer, ss []v1.ContainerStatus) {
6264
}
6365
}
6466
}
67+
68+
func DeleteBackupFiles(wr writer.Writer, files []string) error {
69+
for _, v := range files {
70+
if err := wr.Delete(context.Background(), v); err != nil {
71+
return err
72+
}
73+
}
74+
return nil
75+
}

test/e2e/e2eutil/wait_util.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@ package e2eutil
1616

1717
import (
1818
"bytes"
19+
"context"
1920
"fmt"
2021
"strings"
2122
"testing"
2223
"time"
2324

2425
api "github.com/coreos/etcd-operator/pkg/apis/etcd/v1beta2"
26+
"github.com/coreos/etcd-operator/pkg/backup/writer"
2527
"github.com/coreos/etcd-operator/pkg/generated/clientset/versioned"
2628
"github.com/coreos/etcd-operator/pkg/util"
2729
"github.com/coreos/etcd-operator/pkg/util/k8sutil"
@@ -275,3 +277,16 @@ func WaitUntilOperatorReady(kubecli kubernetes.Interface, namespace, name string
275277
}
276278
return nil
277279
}
280+
281+
func WaitUntilNoBackupFiles(wr writer.Writer, path string, timeout int) error {
282+
return retryutil.Retry(time.Second, timeout, func() (bool, error) {
283+
allBackups, err := wr.List(context.Background(), path)
284+
if err != nil {
285+
return false, fmt.Errorf("failed to list backup files: %v", err)
286+
}
287+
if len(allBackups) > 0 {
288+
return false, fmt.Errorf("%d existing backup files are detected", len(allBackups))
289+
}
290+
return true, nil
291+
})
292+
}

0 commit comments

Comments
 (0)