1
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
36 SnapshotGroup = "snapshot.storage.k8s.io"
37
38 SnapshotAPIVersion = "snapshot.storage.k8s.io/v1"
39 )
40
41 var (
42
43 SnapshotGVR = schema.GroupVersionResource{Group: SnapshotGroup, Version: "v1", Resource: "volumesnapshots"}
44
45 SnapshotClassGVR = schema.GroupVersionResource{Group: SnapshotGroup, Version: "v1", Resource: "volumesnapshotclasses"}
46
47 SnapshotContentGVR = schema.GroupVersionResource{Group: SnapshotGroup, Version: "v1", Resource: "volumesnapshotcontents"}
48 )
49
50
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
82
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
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
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
128
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
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