1
16
17 package storage
18
19 import (
20 "context"
21 "fmt"
22 "time"
23
24 storagev1 "k8s.io/api/storage/v1"
25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26 "k8s.io/apimachinery/pkg/labels"
27 types "k8s.io/apimachinery/pkg/types"
28 "k8s.io/client-go/util/retry"
29 "k8s.io/kubernetes/test/e2e/framework"
30 "k8s.io/kubernetes/test/e2e/storage/utils"
31 admissionapi "k8s.io/pod-security-admission/api"
32
33 "github.com/onsi/ginkgo/v2"
34 "github.com/onsi/gomega"
35 )
36
37 var _ = utils.SIGDescribe("StorageClasses", func() {
38
39 f := framework.NewDefaultFramework("csi-storageclass")
40 f.NamespacePodSecurityLevel = admissionapi.LevelBaseline
41
42 ginkgo.Describe("CSI Conformance", func() {
43
44
53 framework.ConformanceIt("should run through the lifecycle of a StorageClass", func(ctx context.Context) {
54
55 scClient := f.ClientSet.StorageV1().StorageClasses()
56 var initialSC, replacementSC *storagev1.StorageClass
57
58 initialSC = &storagev1.StorageClass{
59 TypeMeta: metav1.TypeMeta{
60 Kind: "StorageClass",
61 },
62 ObjectMeta: metav1.ObjectMeta{
63 GenerateName: "e2e-",
64 },
65 Provisioner: "e2e-fake-provisioner",
66 }
67
68 ginkgo.By("Creating a StorageClass")
69 createdStorageClass, err := scClient.Create(ctx, initialSC, metav1.CreateOptions{})
70 framework.ExpectNoError(err, "failed to create the requested StorageClass")
71
72 ginkgo.By(fmt.Sprintf("Get StorageClass %q", createdStorageClass.Name))
73 retrievedStorageClass, err := scClient.Get(ctx, createdStorageClass.Name, metav1.GetOptions{})
74 framework.ExpectNoError(err, "failed to get StorageClass %q", createdStorageClass.Name)
75
76 ginkgo.By(fmt.Sprintf("Patching the StorageClass %q", retrievedStorageClass.Name))
77 payload := "{\"metadata\":{\"labels\":{\"" + retrievedStorageClass.Name + "\":\"patched\"}}}"
78 patchedStorageClass, err := scClient.Patch(ctx, retrievedStorageClass.Name, types.StrategicMergePatchType, []byte(payload), metav1.PatchOptions{})
79 framework.ExpectNoError(err, "failed to patch StorageClass %q", retrievedStorageClass.Name)
80 gomega.Expect(patchedStorageClass.Labels).To(gomega.HaveKeyWithValue(patchedStorageClass.Name, "patched"), "checking that patched label has been applied")
81
82 ginkgo.By(fmt.Sprintf("Delete StorageClass %q", patchedStorageClass.Name))
83 err = scClient.Delete(ctx, patchedStorageClass.Name, metav1.DeleteOptions{})
84 framework.ExpectNoError(err, "failed to delete StorageClass %q", patchedStorageClass.Name)
85
86 ginkgo.By(fmt.Sprintf("Confirm deletion of StorageClass %q", patchedStorageClass.Name))
87
88 scSelector := labels.Set{patchedStorageClass.Name: "patched"}.AsSelector().String()
89 type state struct {
90 StorageClasses []storagev1.StorageClass
91 }
92
93 err = framework.Gomega().Eventually(ctx, framework.HandleRetry(func(ctx context.Context) (*state, error) {
94 scList, err := scClient.List(ctx, metav1.ListOptions{LabelSelector: scSelector})
95 if err != nil {
96 return nil, fmt.Errorf("failed to list StorageClass: %w", err)
97 }
98 return &state{
99 StorageClasses: scList.Items,
100 }, nil
101 })).WithTimeout(30 * time.Second).Should(framework.MakeMatcher(func(s *state) (func() string, error) {
102 if len(s.StorageClasses) == 0 {
103 return nil, nil
104 }
105 return func() string {
106 return fmt.Sprintf("expected StorageClass to be deleted, found %q", s.StorageClasses[0].Name)
107 }, nil
108 }))
109 framework.ExpectNoError(err, "timeout while waiting to confirm StorageClass %q deletion", patchedStorageClass.Name)
110
111 ginkgo.By("Create a replacement StorageClass")
112
113 replacementSC = &storagev1.StorageClass{
114 TypeMeta: metav1.TypeMeta{
115 Kind: "StorageClass",
116 },
117 ObjectMeta: metav1.ObjectMeta{
118 GenerateName: "e2e-v2-",
119 },
120 Provisioner: "e2e-fake-provisioner",
121 }
122
123 replacementStorageClass, err := scClient.Create(ctx, replacementSC, metav1.CreateOptions{})
124 framework.ExpectNoError(err, "failed to create replacement StorageClass")
125
126 ginkgo.By(fmt.Sprintf("Updating StorageClass %q", replacementStorageClass.Name))
127 var updatedStorageClass *storagev1.StorageClass
128
129 err = retry.RetryOnConflict(retry.DefaultRetry, func() error {
130 sc, err := scClient.Get(ctx, replacementStorageClass.Name, metav1.GetOptions{})
131 framework.ExpectNoError(err, "unable to get Storage %q", replacementStorageClass.Name)
132 sc.Labels = map[string]string{replacementStorageClass.Name: "updated"}
133 updatedStorageClass, err = scClient.Update(ctx, sc, metav1.UpdateOptions{})
134
135 return err
136 })
137 framework.ExpectNoError(err, "failed to update StorageClass %q", replacementStorageClass.Name)
138 gomega.Expect(updatedStorageClass.Labels).To(gomega.HaveKeyWithValue(replacementStorageClass.Name, "updated"), "checking that updated label has been applied")
139
140 scSelector = labels.Set{replacementStorageClass.Name: "updated"}.AsSelector().String()
141 ginkgo.By(fmt.Sprintf("Listing all StorageClass with the labelSelector: %q", scSelector))
142 scList, err := scClient.List(ctx, metav1.ListOptions{LabelSelector: scSelector})
143 framework.ExpectNoError(err, "failed to list StorageClasses with the labelSelector: %q", scSelector)
144 gomega.Expect(scList.Items).To(gomega.HaveLen(1))
145
146 ginkgo.By(fmt.Sprintf("Deleting StorageClass %q via DeleteCollection", updatedStorageClass.Name))
147 err = scClient.DeleteCollection(ctx, metav1.DeleteOptions{}, metav1.ListOptions{LabelSelector: scSelector})
148 framework.ExpectNoError(err, "failed to delete StorageClass %q", updatedStorageClass.Name)
149
150 ginkgo.By(fmt.Sprintf("Confirm deletion of StorageClass %q", updatedStorageClass.Name))
151
152 err = framework.Gomega().Eventually(ctx, framework.HandleRetry(func(ctx context.Context) (*state, error) {
153 scList, err := scClient.List(ctx, metav1.ListOptions{LabelSelector: scSelector})
154 if err != nil {
155 return nil, fmt.Errorf("failed to list StorageClass: %w", err)
156 }
157 return &state{
158 StorageClasses: scList.Items,
159 }, nil
160 })).WithTimeout(30 * time.Second).Should(framework.MakeMatcher(func(s *state) (func() string, error) {
161 if len(s.StorageClasses) == 0 {
162 return nil, nil
163 }
164 return func() string {
165 return fmt.Sprintf("expected StorageClass to be deleted, found %q", s.StorageClasses[0].Name)
166 }, nil
167 }))
168 framework.ExpectNoError(err, "timeout while waiting to confirm StorageClass %q deletion", updatedStorageClass.Name)
169 })
170 })
171 })
172
View as plain text