diff --git a/test/e2e/basic/nodeport.go b/test/e2e/basic/nodeport.go index a475b5702..556054c35 100644 --- a/test/e2e/basic/nodeport.go +++ b/test/e2e/basic/nodeport.go @@ -44,7 +44,7 @@ func (n *NodePort) Init() error { FailedMSG: "Failed to restore with nodeport preservation", Text: fmt.Sprintf("Nodeport can be preserved or omit during restore"), } - n.BackupName = "backup-label-selector-" + UUIDgen.String() + n.BackupName = "backup-nodeport-" + UUIDgen.String() n.RestoreName = "restore-" + UUIDgen.String() n.serviceName = "nginx-service-" + UUIDgen.String() n.labels = map[string]string{"app": "nginx"} diff --git a/test/e2e/basic/storage-class-changing.go b/test/e2e/basic/storage-class-changing.go new file mode 100644 index 000000000..1617a14c9 --- /dev/null +++ b/test/e2e/basic/storage-class-changing.go @@ -0,0 +1,142 @@ +package basic + +import ( + "context" + "fmt" + "time" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" + + . "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 StorageClasssChanging struct { + TestCase + labels map[string]string + data map[string]string + configmaptName string + namespace string + srcStorageClass string + desStorageClass string + volume string + podName string + mappedNS string +} + +const SCCBaseName string = "scc-" + +var StorageClasssChangingTest func() = TestFunc(&StorageClasssChanging{ + namespace: SCCBaseName + "1", TestCase: TestCase{NSBaseName: SCCBaseName}}) + +func (s *StorageClasssChanging) Init() error { + s.VeleroCfg = VeleroCfg + s.Client = *s.VeleroCfg.ClientToInstallVelero + s.NSBaseName = SCCBaseName + s.namespace = s.NSBaseName + UUIDgen.String() + s.mappedNS = s.namespace + "-mapped" + s.NamespacesTotal = 1 + s.TestMsg = &TestMSG{ + Desc: "Changing PV/PVC Storage Classes", + FailedMSG: "Failed to changing PV/PVC Storage Classes", + Text: "Change the storage class of persistent volumes and persistent" + + " volume claims during restores", + } + s.BackupName = "backup-sc-" + UUIDgen.String() + s.RestoreName = "restore-" + UUIDgen.String() + s.srcStorageClass = "default" + s.desStorageClass = "e2e-storage-class" + s.labels = map[string]string{"velero.io/change-storage-class": "RestoreItemAction", + "velero.io/plugin-config": ""} + s.data = map[string]string{s.srcStorageClass: s.desStorageClass} + s.configmaptName = "change-storage-class-config" + s.volume = "volume-1" + s.podName = "pod-1" + return nil +} + +func (s *StorageClasssChanging) StartRun() error { + s.BackupName = s.BackupName + "backup-" + UUIDgen.String() + s.RestoreName = s.RestoreName + "restore-" + UUIDgen.String() + s.BackupArgs = []string{ + "create", "--namespace", VeleroCfg.VeleroNamespace, "backup", s.BackupName, + "--include-namespaces", s.namespace, + "--snapshot-volumes=false", "--wait", + } + s.RestoreArgs = []string{ + "create", "--namespace", VeleroCfg.VeleroNamespace, "restore", s.RestoreName, + "--from-backup", s.BackupName, "--namespace-mappings", fmt.Sprintf("%s:%s", s.namespace, s.mappedNS), "--wait", + } + return nil +} +func (s *StorageClasssChanging) CreateResources() error { + s.Ctx, _ = context.WithTimeout(context.Background(), 60*time.Minute) + By(fmt.Sprintf("Create a storage class %s", s.desStorageClass), func() { + Expect(InstallStorageClass(context.Background(), fmt.Sprintf("testdata/storage-class/%s.yaml", + s.VeleroCfg.CloudProvider))).To(Succeed()) + }) + By(fmt.Sprintf("Create namespace %s", s.namespace), func() { + Expect(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 := CreatePodWithPVC(s.Client, s.namespace, s.podName, s.srcStorageClass, []string{s.volume}) + Expect(err).To(Succeed()) + }) + By(fmt.Sprintf("Create ConfigMap %s in namespace %s", s.configmaptName, s.VeleroCfg.VeleroNamespace), func() { + _, err := CreateConfigMap(s.Client.ClientGo, s.VeleroCfg.VeleroNamespace, s.configmaptName, s.labels, s.data) + Expect(err).To(Succeed(), fmt.Sprintf("failed to create configmap in the namespace %q", s.VeleroCfg.VeleroNamespace)) + }) + return nil +} + +func (s *StorageClasssChanging) Destroy() error { + By(fmt.Sprintf("Expect storage class of PV %s to be %s ", s.volume, s.srcStorageClass), func() { + pvName, err := GetPVByPodName(s.Client, s.namespace, s.volume) + Expect(err).To(Succeed(), fmt.Sprintf("Failed to get PV name by pod name %s", s.podName)) + pv, err := GetPersistentVolume(s.Ctx, s.Client, s.namespace, pvName) + Expect(err).To(Succeed(), fmt.Sprintf("Failed to get PV by pod name %s", s.podName)) + fmt.Println(pv) + Expect(pv.Spec.StorageClassName).To(Equal(s.srcStorageClass), + fmt.Sprintf("PV storage %s is not as expected %s", pv.Spec.StorageClassName, s.srcStorageClass)) + }) + + By(fmt.Sprintf("Start to destroy namespace %s......", s.NSBaseName), func() { + Expect(CleanupNamespacesWithPoll(s.Ctx, s.Client, s.NSBaseName)).To(Succeed(), + fmt.Sprintf("Failed to delete namespace %s", s.NSBaseName)) + }) + return nil +} + +func (s *StorageClasssChanging) Restore() error { + By(fmt.Sprintf("Start to restore %s .....", s.RestoreName), func() { + Expect(VeleroRestoreExec(s.Ctx, s.VeleroCfg.VeleroCLI, + s.VeleroCfg.VeleroNamespace, s.RestoreName, + s.RestoreArgs, velerov1api.RestorePhaseCompleted)).To( + Succeed(), + func() string { + RunDebug(context.Background(), s.VeleroCfg.VeleroCLI, + s.VeleroCfg.VeleroNamespace, "", s.RestoreName) + return "Fail to restore workload" + }) + }) + return nil +} +func (s *StorageClasssChanging) Verify() error { + By(fmt.Sprintf("Expect storage class of PV %s to be %s ", s.volume, s.desStorageClass), func() { + pvName, err := GetPVByPodName(s.Client, s.mappedNS, s.volume) + Expect(err).To(Succeed(), fmt.Sprintf("Failed to get PV name by pod name %s", s.podName)) + pv, err := GetPersistentVolume(s.Ctx, s.Client, s.mappedNS, pvName) + Expect(err).To(Succeed(), fmt.Sprintf("Failed to get PV by pod name %s", s.podName)) + fmt.Println(pv) + Expect(pv.Spec.StorageClassName).To(Equal(s.desStorageClass), + fmt.Sprintf("PV storage %s is not as expected %s", pv.Spec.StorageClassName, s.desStorageClass)) + }) + return nil +} diff --git a/test/e2e/e2e_suite_test.go b/test/e2e/e2e_suite_test.go index 28dd4f20e..1f4e6e53d 100644 --- a/test/e2e/e2e_suite_test.go +++ b/test/e2e/e2e_suite_test.go @@ -135,6 +135,7 @@ var _ = Describe("[pv-backup][Opt-In] Backup resources should follow the specifi var _ = Describe("[pv-backup][Opt-Out] Backup resources should follow the specific order in schedule", OptOutPVBackupTest) var _ = Describe("[Basic][Nodeport] Service nodeport reservation during restore is configurable", NodePortTest) +var _ = Describe("[Basic][StorageClass] Storage class of persistent volumes and persistent volume claims can be changed during restores", StorageClasssChangingTest) func GetKubeconfigContext() error { var err error diff --git a/test/e2e/pv-backup/pv-backup-filter.go b/test/e2e/pv-backup/pv-backup-filter.go index 0e8d14622..6f8cd29d9 100644 --- a/test/e2e/pv-backup/pv-backup-filter.go +++ b/test/e2e/pv-backup/pv-backup-filter.go @@ -48,7 +48,7 @@ func (p *PVBackupFiltering) Init() error { } func (p *PVBackupFiltering) StartRun() error { - err := installStorageClass(context.Background(), fmt.Sprintf("testdata/storage-class/%s.yaml", VeleroCfg.CloudProvider)) + err := InstallStorageClass(context.Background(), fmt.Sprintf("testdata/storage-class/%s.yaml", VeleroCfg.CloudProvider)) if err != nil { return err } @@ -205,9 +205,3 @@ func fileNotExist(ctx context.Context, namespace, podName, volume string) error FILE_NAME, volume, podName, namespace)) } } - -func installStorageClass(ctx context.Context, yaml string) error { - fmt.Printf("Install storage class with %s.\n", yaml) - err := KubectlApplyByFile(ctx, yaml) - return err -} diff --git a/test/e2e/resource-filtering/base.go b/test/e2e/resource-filtering/base.go index f951113b2..9be9d6973 100644 --- a/test/e2e/resource-filtering/base.go +++ b/test/e2e/resource-filtering/base.go @@ -108,7 +108,7 @@ func (f *FilteringCase) CreateResources() error { //Create Configmap configmaptName := f.NSBaseName fmt.Printf("Creating configmap %s in namespaces ...%s\n", configmaptName, namespace) - _, err = CreateConfigMap(f.Client.ClientGo, namespace, configmaptName, f.labels) + _, err = CreateConfigMap(f.Client.ClientGo, namespace, configmaptName, f.labels, nil) if err != nil { return errors.Wrap(err, fmt.Sprintf("failed to create configmap in the namespace %q", namespace)) } diff --git a/test/e2e/resource-filtering/exclude_label.go b/test/e2e/resource-filtering/exclude_label.go index 8ff0c1755..f04308ea1 100644 --- a/test/e2e/resource-filtering/exclude_label.go +++ b/test/e2e/resource-filtering/exclude_label.go @@ -127,7 +127,7 @@ func (e *ExcludeFromBackup) CreateResources() error { //Create Configmap: to be included configmaptName := e.NSBaseName fmt.Printf("Creating configmap %s in namespaces ...%s\n", configmaptName, namespace) - _, err = CreateConfigMap(e.Client.ClientGo, namespace, configmaptName, label1) + _, err = CreateConfigMap(e.Client.ClientGo, namespace, configmaptName, label1, nil) if err != nil { return errors.Wrap(err, fmt.Sprintf("failed to create configmap in the namespace %q", namespace)) } diff --git a/test/e2e/schedule/ordered_resources.go b/test/e2e/schedule/ordered_resources.go index 5dde07115..166913c41 100644 --- a/test/e2e/schedule/ordered_resources.go +++ b/test/e2e/schedule/ordered_resources.go @@ -182,7 +182,7 @@ func (o *OrderedResources) CreateResources() error { //Create Configmap configmapName := fmt.Sprintf("configmap-%s", o.NSBaseName) fmt.Printf("Creating configmap %s in %s namespaces ...\n", configmapName, o.Namespace) - _, err = CreateConfigMap(o.Client.ClientGo, o.Namespace, configmapName, label) + _, 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)) } diff --git a/test/e2e/schedule/schedule.go b/test/e2e/schedule/schedule.go index 8445f6256..1643490ea 100644 --- a/test/e2e/schedule/schedule.go +++ b/test/e2e/schedule/schedule.go @@ -61,7 +61,7 @@ func (n *ScheduleBackup) CreateResources() error { }) configmaptName := n.NSBaseName fmt.Printf("Creating configmap %s in namespaces ...%s\n", configmaptName, ns) - _, err := CreateConfigMap(n.Client.ClientGo, ns, configmaptName, nil) + _, 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("ailed to ensure secret completion in namespace: %q", ns)) diff --git a/test/e2e/util/k8s/configmap.go b/test/e2e/util/k8s/configmap.go index 91fcf97cd..0f311fa1d 100644 --- a/test/e2e/util/k8s/configmap.go +++ b/test/e2e/util/k8s/configmap.go @@ -31,11 +31,11 @@ import ( clientset "k8s.io/client-go/kubernetes" ) -func CreateConfigMap(c clientset.Interface, ns, name string, data map[string]string) (*v1.ConfigMap, error) { +func CreateConfigMap(c clientset.Interface, ns, name string, labels, data map[string]string) (*v1.ConfigMap, error) { cm := &v1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Name: name, - Labels: data, + Labels: labels, }, Data: data, } diff --git a/test/e2e/util/k8s/sc.go b/test/e2e/util/k8s/sc.go new file mode 100644 index 000000000..bcc5cbfed --- /dev/null +++ b/test/e2e/util/k8s/sc.go @@ -0,0 +1,12 @@ +package k8s + +import ( + "context" + "fmt" +) + +func InstallStorageClass(ctx context.Context, yaml string) error { + fmt.Printf("Install storage class with %s.\n", yaml) + err := KubectlApplyByFile(ctx, yaml) + return err +} diff --git a/test/e2e/util/velero/install.go b/test/e2e/util/velero/install.go index d8f03671a..25caaa761 100644 --- a/test/e2e/util/velero/install.go +++ b/test/e2e/util/velero/install.go @@ -129,7 +129,7 @@ func configvSpherePlugin(cli TestClient) error { "cluster_flavor": "VANILLA", "vsphere_secret_name": vsphereSecret, "vsphere_secret_namespace": VeleroCfg.VeleroNamespace, - }) + }, nil) if err != nil { return errors.WithMessagef(err, "Failed to create velero-vsphere-plugin-config configmap in %s namespace", VeleroCfg.VeleroNamespace) }