From 401b85e547fb3325cf49f79142a37c3102e16ce8 Mon Sep 17 00:00:00 2001 From: Masaki Kimura Date: Thu, 20 Feb 2020 21:42:11 +0000 Subject: [PATCH] Add FromFile and FromExistingClassName support for SnapshotClass in external storage e2e test --- test/e2e/storage/external/external.go | 59 ++++++++++++++++++-- test/e2e/storage/testsuites/provisioning.go | 10 ++-- test/e2e/storage/testsuites/snapshottable.go | 23 ++++---- 3 files changed, 73 insertions(+), 19 deletions(-) diff --git a/test/e2e/storage/external/external.go b/test/e2e/storage/external/external.go index 99f977f94dc..afb9e4aaf3e 100644 --- a/test/e2e/storage/external/external.go +++ b/test/e2e/storage/external/external.go @@ -84,7 +84,20 @@ type driverDefinition struct { // snapshotter class with DriverInfo.Name as provisioner. FromName bool - // TODO (?): load from file + // FromFile is used only when FromName is false. It + // loads a snapshot class from the given .yaml or .json + // file. File names are resolved by the + // framework.testfiles package, which typically means + // that they can be absolute or relative to the test + // suite's --repo-root parameter. + // + // This can be used when the snapshot class is meant to have + // additional parameters. + FromFile string + + // FromExistingClassName specifies the name of a pre-installed + // SnapshotClass that will be copied and used for the tests. + FromExistingClassName string } // InlineVolumes defines one or more volumes for use as inline @@ -254,7 +267,7 @@ func (d *driverDefinition) SkipUnsupportedTest(pattern testpatterns.TestPattern) case "": supported = true case testpatterns.DynamicCreatedSnapshot: - if d.SnapshotClass.FromName { + if d.SnapshotClass.FromName || d.SnapshotClass.FromFile != "" || d.SnapshotClass.FromExistingClassName != "" { supported = true } } @@ -304,15 +317,53 @@ func (d *driverDefinition) GetDynamicProvisionStorageClass(config *testsuites.Pe return testsuites.GetStorageClass(sc.Provisioner, sc.Parameters, sc.VolumeBindingMode, f.Namespace.Name, "e2e-sc") } +func loadSnapshotClass(filename string) (*unstructured.Unstructured, error) { + data, err := ioutil.ReadFile(filename) + if err != nil { + return nil, err + } + snapshotClass := &unstructured.Unstructured{} + + if err := runtime.DecodeInto(scheme.Codecs.UniversalDecoder(), data, snapshotClass); err != nil { + return nil, errors.Wrap(err, filename) + } + + return snapshotClass, nil +} + func (d *driverDefinition) GetSnapshotClass(config *testsuites.PerTestConfig) *unstructured.Unstructured { - if !d.SnapshotClass.FromName { + if !d.SnapshotClass.FromName && d.SnapshotClass.FromFile == "" && d.SnapshotClass.FromExistingClassName == "" { e2eskipper.Skipf("Driver %q does not support snapshotting - skipping", d.DriverInfo.Name) } + f := config.Framework snapshotter := d.DriverInfo.Name parameters := map[string]string{} ns := config.Framework.Namespace.Name - suffix := snapshotter + "-vsc" + suffix := "vsc" + + switch { + case d.SnapshotClass.FromName: + // Do nothing (just use empty parameters) + case d.SnapshotClass.FromExistingClassName != "": + snapshotClass, err := f.DynamicClient.Resource(testsuites.SnapshotClassGVR).Get(d.SnapshotClass.FromExistingClassName, metav1.GetOptions{}) + framework.ExpectNoError(err, "getting snapshot class %s", d.SnapshotClass.FromExistingClassName) + + if params, ok := snapshotClass.Object["parameters"].(map[string]interface{}); ok { + for k, v := range params { + parameters[k] = v.(string) + } + } + case d.SnapshotClass.FromFile != "": + snapshotClass, err := loadSnapshotClass(d.SnapshotClass.FromFile) + framework.ExpectNoError(err, "load snapshot class from %s", d.SnapshotClass.FromFile) + + if params, ok := snapshotClass.Object["parameters"].(map[string]interface{}); ok { + for k, v := range params { + parameters[k] = v.(string) + } + } + } return testsuites.GetSnapshotClass(snapshotter, parameters, ns, suffix) } diff --git a/test/e2e/storage/testsuites/provisioning.go b/test/e2e/storage/testsuites/provisioning.go index 3867cd73af1..770edf7f483 100644 --- a/test/e2e/storage/testsuites/provisioning.go +++ b/test/e2e/storage/testsuites/provisioning.go @@ -740,12 +740,12 @@ func prepareSnapshotDataSourceForProvisioning( volume.InjectContent(f, config, nil, "", tests) ginkgo.By("[Initialize dataSource]creating a SnapshotClass") - snapshotClass, err = dynamicClient.Resource(snapshotClassGVR).Create(snapshotClass, metav1.CreateOptions{}) + snapshotClass, err = dynamicClient.Resource(SnapshotClassGVR).Create(snapshotClass, metav1.CreateOptions{}) framework.ExpectNoError(err) ginkgo.By("[Initialize dataSource]creating a snapshot") snapshot := getSnapshot(updatedClaim.Name, updatedClaim.Namespace, snapshotClass.GetName()) - snapshot, err = dynamicClient.Resource(snapshotGVR).Namespace(updatedClaim.Namespace).Create(snapshot, metav1.CreateOptions{}) + snapshot, err = dynamicClient.Resource(SnapshotGVR).Namespace(updatedClaim.Namespace).Create(snapshot, metav1.CreateOptions{}) framework.ExpectNoError(err) WaitForSnapshotReady(dynamicClient, snapshot.GetNamespace(), snapshot.GetName(), framework.Poll, framework.SnapshotCreateTimeout) @@ -753,7 +753,7 @@ func prepareSnapshotDataSourceForProvisioning( ginkgo.By("[Initialize dataSource]checking the snapshot") // Get new copy of the snapshot - snapshot, err = dynamicClient.Resource(snapshotGVR).Namespace(snapshot.GetNamespace()).Get(snapshot.GetName(), metav1.GetOptions{}) + snapshot, err = dynamicClient.Resource(SnapshotGVR).Namespace(snapshot.GetNamespace()).Get(snapshot.GetName(), metav1.GetOptions{}) framework.ExpectNoError(err) group := "snapshot.storage.k8s.io" dataSourceRef := &v1.TypedLocalObjectReference{ @@ -764,7 +764,7 @@ func prepareSnapshotDataSourceForProvisioning( cleanupFunc := func() { framework.Logf("deleting snapshot %q/%q", snapshot.GetNamespace(), snapshot.GetName()) - err = dynamicClient.Resource(snapshotGVR).Namespace(updatedClaim.Namespace).Delete(snapshot.GetName(), nil) + err = dynamicClient.Resource(SnapshotGVR).Namespace(updatedClaim.Namespace).Delete(snapshot.GetName(), nil) if err != nil && !apierrors.IsNotFound(err) { framework.Failf("Error deleting snapshot %q. Error: %v", snapshot.GetName(), err) } @@ -776,7 +776,7 @@ func prepareSnapshotDataSourceForProvisioning( } framework.Logf("deleting SnapshotClass %s", snapshotClass.GetName()) - framework.ExpectNoError(dynamicClient.Resource(snapshotClassGVR).Delete(snapshotClass.GetName(), nil)) + framework.ExpectNoError(dynamicClient.Resource(SnapshotClassGVR).Delete(snapshotClass.GetName(), nil)) } return dataSourceRef, cleanupFunc diff --git a/test/e2e/storage/testsuites/snapshottable.go b/test/e2e/storage/testsuites/snapshottable.go index 56793995281..4bb9f28f177 100644 --- a/test/e2e/storage/testsuites/snapshottable.go +++ b/test/e2e/storage/testsuites/snapshottable.go @@ -42,9 +42,12 @@ const snapshotGroup = "snapshot.storage.k8s.io" const snapshotAPIVersion = "snapshot.storage.k8s.io/v1beta1" var ( - snapshotGVR = schema.GroupVersionResource{Group: snapshotGroup, Version: "v1beta1", Resource: "volumesnapshots"} - snapshotClassGVR = schema.GroupVersionResource{Group: snapshotGroup, Version: "v1beta1", Resource: "volumesnapshotclasses"} - snapshotContentGVR = schema.GroupVersionResource{Group: snapshotGroup, Version: "v1beta1", Resource: "volumesnapshotcontents"} + // SnapshotGVR is GroupVersionResource for volumesnapshots + SnapshotGVR = schema.GroupVersionResource{Group: snapshotGroup, Version: "v1beta1", Resource: "volumesnapshots"} + // SnapshotClassGVR is GroupVersionResource for volumesnapshotclasses + SnapshotClassGVR = schema.GroupVersionResource{Group: snapshotGroup, Version: "v1beta1", Resource: "volumesnapshotclasses"} + // SnapshotContentGVR is GroupVersionResource for volumesnapshotcontents + SnapshotContentGVR = schema.GroupVersionResource{Group: snapshotGroup, Version: "v1beta1", Resource: "volumesnapshotcontents"} ) type snapshottableTestSuite struct { @@ -167,22 +170,22 @@ func (s *snapshottableTestSuite) DefineTests(driver TestDriver, pattern testpatt framework.ExpectNoError(err) ginkgo.By("creating a SnapshotClass") - vsc, err = dc.Resource(snapshotClassGVR).Create(vsc, metav1.CreateOptions{}) + vsc, err = dc.Resource(SnapshotClassGVR).Create(vsc, metav1.CreateOptions{}) framework.ExpectNoError(err) defer func() { framework.Logf("deleting SnapshotClass %s", vsc.GetName()) - framework.ExpectNoError(dc.Resource(snapshotClassGVR).Delete(vsc.GetName(), nil)) + framework.ExpectNoError(dc.Resource(SnapshotClassGVR).Delete(vsc.GetName(), nil)) }() ginkgo.By("creating a snapshot") snapshot := getSnapshot(pvc.Name, pvc.Namespace, vsc.GetName()) - snapshot, err = dc.Resource(snapshotGVR).Namespace(snapshot.GetNamespace()).Create(snapshot, metav1.CreateOptions{}) + snapshot, err = dc.Resource(SnapshotGVR).Namespace(snapshot.GetNamespace()).Create(snapshot, metav1.CreateOptions{}) framework.ExpectNoError(err) defer func() { framework.Logf("deleting snapshot %q/%q", snapshot.GetNamespace(), snapshot.GetName()) // typically this snapshot has already been deleted - err = dc.Resource(snapshotGVR).Namespace(snapshot.GetNamespace()).Delete(snapshot.GetName(), nil) + err = dc.Resource(SnapshotGVR).Namespace(snapshot.GetNamespace()).Delete(snapshot.GetName(), nil) if err != nil && !apierrors.IsNotFound(err) { framework.Failf("Error deleting snapshot %q. Error: %v", pvc.Name, err) } @@ -192,13 +195,13 @@ func (s *snapshottableTestSuite) DefineTests(driver TestDriver, pattern testpatt ginkgo.By("checking the snapshot") // Get new copy of the snapshot - snapshot, err = dc.Resource(snapshotGVR).Namespace(snapshot.GetNamespace()).Get(snapshot.GetName(), metav1.GetOptions{}) + snapshot, err = dc.Resource(SnapshotGVR).Namespace(snapshot.GetNamespace()).Get(snapshot.GetName(), metav1.GetOptions{}) framework.ExpectNoError(err) // Get the bound snapshotContent snapshotStatus := snapshot.Object["status"].(map[string]interface{}) snapshotContentName := snapshotStatus["boundVolumeSnapshotContentName"].(string) - snapshotContent, err := dc.Resource(snapshotContentGVR).Get(snapshotContentName, metav1.GetOptions{}) + snapshotContent, err := dc.Resource(SnapshotContentGVR).Get(snapshotContentName, metav1.GetOptions{}) framework.ExpectNoError(err) snapshotContentSpec := snapshotContent.Object["spec"].(map[string]interface{}) @@ -216,7 +219,7 @@ func (s *snapshottableTestSuite) DefineTests(driver TestDriver, pattern testpatt func WaitForSnapshotReady(c dynamic.Interface, ns string, snapshotName string, Poll, timeout time.Duration) error { framework.Logf("Waiting up to %v for VolumeSnapshot %s to become ready", timeout, snapshotName) for start := time.Now(); time.Since(start) < timeout; time.Sleep(Poll) { - snapshot, err := c.Resource(snapshotGVR).Namespace(ns).Get(snapshotName, metav1.GetOptions{}) + snapshot, err := c.Resource(SnapshotGVR).Namespace(ns).Get(snapshotName, metav1.GetOptions{}) if err != nil { framework.Logf("Failed to get claim %q, retrying in %v. Error: %v", snapshotName, Poll, err) continue