Merge pull request #88669 from mkimuram/snapfromfile

Add FromFile and FromExistingClassName support for SnapshotClass in external storage e2e test
This commit is contained in:
Kubernetes Prow Robot 2020-03-04 01:10:00 -08:00 committed by GitHub
commit c2593d3fa7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 73 additions and 19 deletions

View File

@ -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)
}

View File

@ -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

View File

@ -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