...

Source file src/k8s.io/kubernetes/test/e2e/storage/utils/snapshot.go

Documentation: k8s.io/kubernetes/test/e2e/storage/utils

     1  /*
     2  Copyright 2020 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package utils
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"time"
    23  
    24  	"github.com/onsi/ginkgo/v2"
    25  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    28  	"k8s.io/apimachinery/pkg/runtime/schema"
    29  	"k8s.io/apiserver/pkg/storage/names"
    30  	"k8s.io/client-go/dynamic"
    31  	"k8s.io/kubernetes/test/e2e/framework"
    32  )
    33  
    34  const (
    35  	// SnapshotGroup is the snapshot CRD api group
    36  	SnapshotGroup = "snapshot.storage.k8s.io"
    37  	// SnapshotAPIVersion is the snapshot CRD api version
    38  	SnapshotAPIVersion = "snapshot.storage.k8s.io/v1"
    39  )
    40  
    41  var (
    42  	// SnapshotGVR is GroupVersionResource for volumesnapshots
    43  	SnapshotGVR = schema.GroupVersionResource{Group: SnapshotGroup, Version: "v1", Resource: "volumesnapshots"}
    44  	// SnapshotClassGVR is GroupVersionResource for volumesnapshotclasses
    45  	SnapshotClassGVR = schema.GroupVersionResource{Group: SnapshotGroup, Version: "v1", Resource: "volumesnapshotclasses"}
    46  	// SnapshotContentGVR is GroupVersionResource for volumesnapshotcontents
    47  	SnapshotContentGVR = schema.GroupVersionResource{Group: SnapshotGroup, Version: "v1", Resource: "volumesnapshotcontents"}
    48  )
    49  
    50  // WaitForSnapshotReady waits for a VolumeSnapshot to be ready to use or until timeout occurs, whichever comes first.
    51  func WaitForSnapshotReady(ctx context.Context, c dynamic.Interface, ns string, snapshotName string, poll, timeout time.Duration) error {
    52  	framework.Logf("Waiting up to %v for VolumeSnapshot %s to become ready", timeout, snapshotName)
    53  
    54  	if successful := WaitUntil(poll, timeout, func() bool {
    55  		snapshot, err := c.Resource(SnapshotGVR).Namespace(ns).Get(ctx, snapshotName, metav1.GetOptions{})
    56  		if err != nil {
    57  			framework.Logf("Failed to get snapshot %q, retrying in %v. Error: %v", snapshotName, poll, err)
    58  			return false
    59  		}
    60  
    61  		status := snapshot.Object["status"]
    62  		if status == nil {
    63  			framework.Logf("VolumeSnapshot %s found but is not ready.", snapshotName)
    64  			return false
    65  		}
    66  		value := status.(map[string]interface{})
    67  		if value["readyToUse"] == true {
    68  			framework.Logf("VolumeSnapshot %s found and is ready", snapshotName)
    69  			return true
    70  		}
    71  
    72  		framework.Logf("VolumeSnapshot %s found but is not ready.", snapshotName)
    73  		return false
    74  	}); successful {
    75  		return nil
    76  	}
    77  
    78  	return fmt.Errorf("VolumeSnapshot %s is not ready within %v", snapshotName, timeout)
    79  }
    80  
    81  // GetSnapshotContentFromSnapshot returns the VolumeSnapshotContent object Bound to a
    82  // given VolumeSnapshot
    83  func GetSnapshotContentFromSnapshot(ctx context.Context, dc dynamic.Interface, snapshot *unstructured.Unstructured, timeout time.Duration) *unstructured.Unstructured {
    84  	defer ginkgo.GinkgoRecover()
    85  	err := WaitForSnapshotReady(ctx, dc, snapshot.GetNamespace(), snapshot.GetName(), framework.Poll, timeout)
    86  	framework.ExpectNoError(err)
    87  
    88  	vs, err := dc.Resource(SnapshotGVR).Namespace(snapshot.GetNamespace()).Get(ctx, snapshot.GetName(), metav1.GetOptions{})
    89  
    90  	snapshotStatus := vs.Object["status"].(map[string]interface{})
    91  	snapshotContentName := snapshotStatus["boundVolumeSnapshotContentName"].(string)
    92  	framework.Logf("received snapshotStatus %v", snapshotStatus)
    93  	framework.Logf("snapshotContentName %s", snapshotContentName)
    94  	framework.ExpectNoError(err)
    95  
    96  	vscontent, err := dc.Resource(SnapshotContentGVR).Get(ctx, snapshotContentName, metav1.GetOptions{})
    97  	framework.ExpectNoError(err)
    98  
    99  	return vscontent
   100  
   101  }
   102  
   103  // DeleteSnapshotWithoutWaiting deletes a VolumeSnapshot and return directly without waiting
   104  func DeleteSnapshotWithoutWaiting(ctx context.Context, dc dynamic.Interface, ns string, snapshotName string) error {
   105  	ginkgo.By("deleting the snapshot")
   106  	err := dc.Resource(SnapshotGVR).Namespace(ns).Delete(ctx, snapshotName, metav1.DeleteOptions{})
   107  	if err != nil && !apierrors.IsNotFound(err) {
   108  		return err
   109  	}
   110  	return nil
   111  }
   112  
   113  // DeleteAndWaitSnapshot deletes a VolumeSnapshot and waits for it to be deleted or until timeout occurs, whichever comes first
   114  func DeleteAndWaitSnapshot(ctx context.Context, dc dynamic.Interface, ns string, snapshotName string, poll, timeout time.Duration) error {
   115  	var err error
   116  	err = DeleteSnapshotWithoutWaiting(ctx, dc, ns, snapshotName)
   117  	if err != nil {
   118  		return err
   119  	}
   120  
   121  	ginkgo.By("checking the Snapshot has been deleted")
   122  	err = WaitForNamespacedGVRDeletion(ctx, dc, SnapshotGVR, ns, snapshotName, poll, timeout)
   123  
   124  	return err
   125  }
   126  
   127  // GenerateSnapshotClassSpec constructs a new SnapshotClass instance spec
   128  // with a unique name that is based on namespace + suffix.
   129  func GenerateSnapshotClassSpec(
   130  	snapshotter string,
   131  	parameters map[string]string,
   132  	ns string,
   133  ) *unstructured.Unstructured {
   134  	snapshotClass := &unstructured.Unstructured{
   135  		Object: map[string]interface{}{
   136  			"kind":       "VolumeSnapshotClass",
   137  			"apiVersion": SnapshotAPIVersion,
   138  			"metadata": map[string]interface{}{
   139  				// Name must be unique, so let's base it on namespace name and use GenerateName
   140  				"name": names.SimpleNameGenerator.GenerateName(ns),
   141  			},
   142  			"driver":         snapshotter,
   143  			"parameters":     parameters,
   144  			"deletionPolicy": "Delete",
   145  		},
   146  	}
   147  
   148  	return snapshotClass
   149  }
   150  

View as plain text