206 lines
7.0 KiB
Go
206 lines
7.0 KiB
Go
/*
|
|
Copyright 2017 Heptio Inc.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package backup
|
|
|
|
import (
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/util/clock"
|
|
|
|
"github.com/heptio/ark/pkg/apis/ark/v1"
|
|
. "github.com/heptio/ark/pkg/util/test"
|
|
)
|
|
|
|
func TestVolumeSnapshotAction(t *testing.T) {
|
|
iops := 1000
|
|
|
|
tests := []struct {
|
|
name string
|
|
snapshotEnabled bool
|
|
pv string
|
|
ttl time.Duration
|
|
expectError bool
|
|
expectedVolumeID string
|
|
existingVolumeBackups map[string]*v1.VolumeBackupInfo
|
|
volumeInfo map[string]v1.VolumeBackupInfo
|
|
}{
|
|
{
|
|
name: "snapshot disabled",
|
|
pv: `{"apiVersion": "v1", "kind": "PersistentVolume", "metadata": {"name": "mypv"}}`,
|
|
snapshotEnabled: false,
|
|
},
|
|
{
|
|
name: "can't find volume id - missing spec",
|
|
snapshotEnabled: true,
|
|
pv: `{"apiVersion": "v1", "kind": "PersistentVolume", "metadata": {"name": "mypv"}}`,
|
|
expectError: true,
|
|
},
|
|
{
|
|
name: "can't find volume id - spec but no volume source defined",
|
|
snapshotEnabled: true,
|
|
pv: `{"apiVersion": "v1", "kind": "PersistentVolume", "metadata": {"name": "mypv"}, "spec": {}}`,
|
|
expectError: true,
|
|
},
|
|
{
|
|
name: "can't find volume id - aws but no volume id",
|
|
snapshotEnabled: true,
|
|
pv: `{"apiVersion": "v1", "kind": "PersistentVolume", "metadata": {"name": "mypv"}, "spec": {"awsElasticBlockStore": {}}}`,
|
|
expectError: true,
|
|
},
|
|
{
|
|
name: "can't find volume id - gce but no volume id",
|
|
snapshotEnabled: true,
|
|
pv: `{"apiVersion": "v1", "kind": "PersistentVolume", "metadata": {"name": "mypv"}, "spec": {"gcePersistentDisk": {}}}`,
|
|
expectError: true,
|
|
},
|
|
{
|
|
name: "aws - simple volume id",
|
|
snapshotEnabled: true,
|
|
pv: `{"apiVersion": "v1", "kind": "PersistentVolume", "metadata": {"name": "mypv"}, "spec": {"awsElasticBlockStore": {"volumeID": "vol-abc123"}}}`,
|
|
expectError: false,
|
|
expectedVolumeID: "vol-abc123",
|
|
ttl: 5 * time.Minute,
|
|
volumeInfo: map[string]v1.VolumeBackupInfo{
|
|
"vol-abc123": v1.VolumeBackupInfo{Type: "gp", SnapshotID: "snap-1"},
|
|
},
|
|
},
|
|
{
|
|
name: "aws - simple volume id with provisioned IOPS",
|
|
snapshotEnabled: true,
|
|
pv: `{"apiVersion": "v1", "kind": "PersistentVolume", "metadata": {"name": "mypv"}, "spec": {"awsElasticBlockStore": {"volumeID": "vol-abc123"}}}`,
|
|
expectError: false,
|
|
expectedVolumeID: "vol-abc123",
|
|
ttl: 5 * time.Minute,
|
|
volumeInfo: map[string]v1.VolumeBackupInfo{
|
|
"vol-abc123": v1.VolumeBackupInfo{Type: "io1", Iops: &iops, SnapshotID: "snap-1"},
|
|
},
|
|
},
|
|
{
|
|
name: "aws - dynamically provisioned volume id",
|
|
snapshotEnabled: true,
|
|
pv: `{"apiVersion": "v1", "kind": "PersistentVolume", "metadata": {"name": "mypv"}, "spec": {"awsElasticBlockStore": {"volumeID": "aws://us-west-2a/vol-abc123"}}}`,
|
|
expectError: false,
|
|
expectedVolumeID: "vol-abc123",
|
|
ttl: 5 * time.Minute,
|
|
volumeInfo: map[string]v1.VolumeBackupInfo{
|
|
"vol-abc123": v1.VolumeBackupInfo{Type: "gp", SnapshotID: "snap-1"},
|
|
},
|
|
},
|
|
{
|
|
name: "gce",
|
|
snapshotEnabled: true,
|
|
pv: `{"apiVersion": "v1", "kind": "PersistentVolume", "metadata": {"name": "mypv"}, "spec": {"gcePersistentDisk": {"pdName": "pd-abc123"}}}`,
|
|
expectError: false,
|
|
expectedVolumeID: "pd-abc123",
|
|
ttl: 5 * time.Minute,
|
|
volumeInfo: map[string]v1.VolumeBackupInfo{
|
|
"pd-abc123": v1.VolumeBackupInfo{Type: "gp", SnapshotID: "snap-1"},
|
|
},
|
|
},
|
|
{
|
|
name: "preexisting volume backup info in backup status",
|
|
snapshotEnabled: true,
|
|
pv: `{"apiVersion": "v1", "kind": "PersistentVolume", "metadata": {"name": "mypv"}, "spec": {"gcePersistentDisk": {"pdName": "pd-abc123"}}}`,
|
|
expectError: false,
|
|
expectedVolumeID: "pd-abc123",
|
|
ttl: 5 * time.Minute,
|
|
existingVolumeBackups: map[string]*v1.VolumeBackupInfo{
|
|
"anotherpv": &v1.VolumeBackupInfo{SnapshotID: "anothersnap"},
|
|
},
|
|
volumeInfo: map[string]v1.VolumeBackupInfo{
|
|
"pd-abc123": v1.VolumeBackupInfo{Type: "gp", SnapshotID: "snap-1"},
|
|
},
|
|
},
|
|
{
|
|
name: "create snapshot error",
|
|
snapshotEnabled: true,
|
|
pv: `{"apiVersion": "v1", "kind": "PersistentVolume", "metadata": {"name": "mypv"}, "spec": {"gcePersistentDisk": {"pdName": "pd-abc123"}}}`,
|
|
expectError: true,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
backup := &v1.Backup{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Namespace: v1.DefaultNamespace,
|
|
Name: "mybackup",
|
|
},
|
|
Spec: v1.BackupSpec{
|
|
SnapshotVolumes: test.snapshotEnabled,
|
|
TTL: metav1.Duration{Duration: test.ttl},
|
|
},
|
|
Status: v1.BackupStatus{
|
|
VolumeBackups: test.existingVolumeBackups,
|
|
},
|
|
}
|
|
|
|
snapshotService := &FakeSnapshotService{SnapshottableVolumes: test.volumeInfo}
|
|
action := NewVolumeSnapshotAction(snapshotService).(*volumeSnapshotAction)
|
|
fakeClock := clock.NewFakeClock(time.Now())
|
|
action.clock = fakeClock
|
|
|
|
pv, err := getAsMap(test.pv)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
err = action.Execute(pv, backup)
|
|
gotErr := err != nil
|
|
|
|
if e, a := test.expectError, gotErr; e != a {
|
|
t.Errorf("error: expected %v, got %v", e, a)
|
|
}
|
|
if test.expectError {
|
|
return
|
|
}
|
|
|
|
if !test.snapshotEnabled {
|
|
// don't need to check anything else if snapshots are disabled
|
|
return
|
|
}
|
|
|
|
expectedVolumeBackups := test.existingVolumeBackups
|
|
if expectedVolumeBackups == nil {
|
|
expectedVolumeBackups = make(map[string]*v1.VolumeBackupInfo)
|
|
}
|
|
|
|
// we should have one snapshot taken exactly
|
|
require.Equal(t, 1, snapshotService.SnapshotsTaken.Len())
|
|
|
|
// the snapshotID should be the one in the entry in snapshotService.SnapshottableVolumes
|
|
// for the volume we ran the test for
|
|
snapshotID, _ := snapshotService.SnapshotsTaken.PopAny()
|
|
|
|
expectedVolumeBackups["mypv"] = &v1.VolumeBackupInfo{
|
|
SnapshotID: snapshotID,
|
|
Type: test.volumeInfo[test.expectedVolumeID].Type,
|
|
Iops: test.volumeInfo[test.expectedVolumeID].Iops,
|
|
}
|
|
|
|
if e, a := expectedVolumeBackups, backup.Status.VolumeBackups; !reflect.DeepEqual(e, a) {
|
|
t.Errorf("backup.status.VolumeBackups: expected %v, got %v", e, a)
|
|
}
|
|
})
|
|
}
|
|
}
|