@@ -18,172 +18,152 @@ package storage
18
18
19
19
import (
20
20
"context"
21
- "fmt"
22
21
"time"
23
22
23
+ "k8s.io/klog/v2"
24
+
24
25
"github.com/onsi/ginkgo/v2"
25
26
"github.com/onsi/gomega"
26
-
27
27
v1 "k8s.io/api/core/v1"
28
28
storagev1 "k8s.io/api/storage/v1"
29
29
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30
- "k8s.io/apimachinery/pkg/util/wait"
31
30
clientset "k8s.io/client-go/kubernetes"
32
31
storageutil "k8s.io/kubernetes/pkg/apis/storage/util"
33
32
"k8s.io/kubernetes/test/e2e/framework"
34
33
e2epv "k8s.io/kubernetes/test/e2e/framework/pv"
35
- "k8s.io/kubernetes/test/e2e/storage/testsuites"
36
34
"k8s.io/kubernetes/test/e2e/storage/utils"
37
35
admissionapi "k8s.io/pod-security-admission/api"
38
36
)
39
37
40
- var _ = utils .SIGDescribe ("Persistent Volume Claim and StorageClass" , func () {
41
- f := framework .NewDefaultFramework ("pvc- retroactive-storageclass" )
38
+ var _ = utils .SIGDescribe ("Retroactive StorageClass Assignment " , func () {
39
+ f := framework .NewDefaultFramework ("retroactive-storageclass" )
42
40
f .NamespacePodSecurityLevel = admissionapi .LevelBaseline
43
41
44
42
var (
45
43
client clientset.Interface
46
44
namespace string
47
- prefixPVC string
48
- prefixSC string
49
- t testsuites.StorageClassTest
50
- pvc * v1.PersistentVolumeClaim
51
- err error
52
45
)
53
46
54
47
ginkgo .BeforeEach (func () {
55
48
client = f .ClientSet
56
49
namespace = f .Namespace .Name
57
- prefixPVC = "retro-pvc-"
58
- prefixSC = "retro"
59
- t = testsuites.StorageClassTest {
60
- Timeouts : f .Timeouts ,
61
- ClaimSize : "1Gi" ,
62
- }
63
50
})
64
51
65
- f .Describe ("Retroactive StorageClass assignment" , framework .WithSerial (), framework .WithDisruptive (), func () {
66
- ginkgo .It ("should assign default SC to PVCs that have no SC set" , func (ctx context.Context ) {
67
-
68
- // Temporarily set all default storage classes as non-default
69
- restoreClasses := temporarilyUnsetDefaultClasses (ctx , client )
70
- defer restoreClasses ()
71
-
72
- // Create PVC with nil SC
73
- pvcObj := e2epv .MakePersistentVolumeClaim (e2epv.PersistentVolumeClaimConfig {
74
- NamePrefix : prefixPVC ,
75
- ClaimSize : t .ClaimSize ,
76
- VolumeMode : & t .VolumeMode ,
77
- }, namespace )
78
- pvc , err = client .CoreV1 ().PersistentVolumeClaims (pvcObj .Namespace ).Create (ctx , pvcObj , metav1.CreateOptions {})
79
- framework .ExpectNoError (err , "Error creating PVC" )
80
- defer func (pvc * v1.PersistentVolumeClaim ) {
81
- // Remove test PVC
82
- err := client .CoreV1 ().PersistentVolumeClaims (pvc .Namespace ).Delete (ctx , pvc .Name , metav1.DeleteOptions {})
83
- framework .ExpectNoError (err , "Error cleaning up PVC" )
84
- }(pvc )
85
-
86
- // Create custom default SC
87
- storageClass := testsuites .SetupStorageClass (ctx , client , makeStorageClass (prefixSC ))
88
-
89
- // Wait for PVC to get updated with the new default SC
90
- pvc , err = waitForPVCStorageClass (ctx , client , namespace , pvc .Name , storageClass .Name , f .Timeouts .ClaimBound )
91
- framework .ExpectNoError (err , "Error updating PVC with the correct storage class" )
92
-
93
- // Create PV with specific class
94
- pv := e2epv .MakePersistentVolume (e2epv.PersistentVolumeConfig {
95
- NamePrefix : "pv-" ,
96
- StorageClassName : storageClass .Name ,
97
- VolumeMode : pvc .Spec .VolumeMode ,
98
- PVSource : v1.PersistentVolumeSource {
99
- HostPath : & v1.HostPathVolumeSource {
100
- Path : "/tmp/test" ,
101
- },
102
- },
103
- })
104
- _ , err = e2epv .CreatePV (ctx , client , f .Timeouts , pv )
105
- framework .ExpectNoError (err , "Error creating pv %v" , err )
106
- ginkgo .DeferCleanup (e2epv .DeletePersistentVolume , client , pv .Name )
107
-
108
- // Verify the PVC is bound and has the new default SC
109
- claimNames := []string {pvc .Name }
110
- err = e2epv .WaitForPersistentVolumeClaimsPhase (ctx , v1 .ClaimBound , client , namespace , claimNames , 2 * time .Second /* Poll */ , t .Timeouts .ClaimProvisionShort , false )
111
- framework .ExpectNoError (err )
112
- updatedPVC , err := client .CoreV1 ().PersistentVolumeClaims (namespace ).Get (ctx , pvc .Name , metav1.GetOptions {})
113
- framework .ExpectNoError (err )
114
- gomega .Expect (* updatedPVC .Spec .StorageClassName ).To (gomega .Equal (storageClass .Name ), "Expected PVC %v to have StorageClass %v, but it has StorageClass %v instead" , updatedPVC .Name , prefixSC , updatedPVC .Spec .StorageClassName )
115
- framework .Logf ("Success - PersistentVolumeClaim %s got updated retroactively with StorageClass %v" , updatedPVC .Name , storageClass .Name )
52
+ f .It ("should assign default StorageClass to PVCs retroactively" , f .WithDisruptive (), f .WithSerial (), func (ctx context.Context ) {
53
+ defaultSCs , err := getDefaultStorageClasses (ctx , client )
54
+ framework .ExpectNoError (err , "Failed to get default StorageClasses" )
55
+
56
+ ginkgo .DeferCleanup (func (cleanupContext context.Context ) {
57
+ // Restore existing default StorageClasses at the end of the test
58
+ for _ , sc := range defaultSCs {
59
+ setStorageClassDefault (cleanupContext , client , sc .Name , "true" )
60
+ }
61
+ })
62
+
63
+ // Unset all default StorageClasses
64
+ for _ , sc := range defaultSCs {
65
+ klog .InfoS ("Unsetting default StorageClass" , "StorageClass" , sc .Name )
66
+ setStorageClassDefault (ctx , client , sc .Name , "false" )
67
+ }
68
+
69
+ // Ensure no default StorageClasses exist
70
+ if len (defaultSCs ) > 0 {
71
+ ensureNoDefaultStorageClasses (ctx , client )
72
+ }
73
+
74
+ // Create a PVC with nil StorageClass
75
+ pvc := createPVC (ctx , client , namespace )
76
+ ginkgo .DeferCleanup (func (cleanupContext context.Context ) {
77
+ err := client .CoreV1 ().PersistentVolumeClaims (namespace ).Delete (ctx , pvc .Name , * metav1 .NewDeleteOptions (0 ))
78
+ framework .ExpectNoError (err , "Error deleting PVC" )
116
79
})
80
+
81
+ // Create a default StorageClass
82
+ sc := createDefaultStorageClass (ctx , client )
83
+ ginkgo .DeferCleanup (func (cleanupContext context.Context ) {
84
+ deleteStorageClass (cleanupContext , client , sc .Name )
85
+ })
86
+
87
+ // Verify that the PVC is assigned the default StorageClass
88
+ gomega .Eventually (ctx , framework .GetObject (client .CoreV1 ().PersistentVolumeClaims (pvc .Namespace ).Get , pvc .Name , metav1.GetOptions {})).
89
+ WithPolling (framework .Poll ).
90
+ WithTimeout (2 * time .Minute ).
91
+ Should (gomega .HaveField ("Spec.StorageClassName" , gomega .Equal (& sc .Name )),
92
+ "failed to wait for PVC to have the storageclass %s" , sc .Name )
117
93
})
118
94
})
119
95
120
- func makeStorageClass (prefixSC string ) * storagev1.StorageClass {
121
- return & storagev1.StorageClass {
122
- TypeMeta : metav1.TypeMeta {
123
- Kind : "StorageClass" ,
124
- },
125
- ObjectMeta : metav1.ObjectMeta {
126
- GenerateName : prefixSC ,
127
- Annotations : map [string ]string {
128
- storageutil .IsDefaultStorageClassAnnotation : "true" ,
129
- },
130
- },
131
- Provisioner : "fake-1" ,
96
+ func getDefaultStorageClasses (ctx context.Context , client clientset.Interface ) ([]storagev1.StorageClass , error ) {
97
+ scList , err := client .StorageV1 ().StorageClasses ().List (ctx , metav1.ListOptions {})
98
+ if err != nil {
99
+ return nil , err
132
100
}
133
- }
134
-
135
- func temporarilyUnsetDefaultClasses (ctx context.Context , client clientset.Interface ) func () {
136
- classes , err := client .StorageV1 ().StorageClasses ().List (ctx , metav1.ListOptions {})
137
- framework .ExpectNoError (err )
138
-
139
- changedClasses := make (map [string ]bool )
140
101
141
- for _ , sc := range classes .Items {
102
+ var defaultSCs []storagev1.StorageClass
103
+ for _ , sc := range scList .Items {
142
104
if sc .Annotations [storageutil .IsDefaultStorageClassAnnotation ] == "true" {
143
- changedClasses [sc .GetName ()] = true
144
- sc .Annotations [storageutil .IsDefaultStorageClassAnnotation ] = "false"
145
- _ , err := client .StorageV1 ().StorageClasses ().Update (ctx , & sc , metav1.UpdateOptions {})
146
- framework .ExpectNoError (err )
105
+ defaultSCs = append (defaultSCs , sc )
147
106
}
148
107
}
108
+ return defaultSCs , nil
109
+ }
149
110
150
- return func () {
151
- classes , err = client .StorageV1 ().StorageClasses ().List (ctx , metav1.ListOptions {})
152
- framework .ExpectNoError (err )
153
- for _ , sc := range classes .Items {
154
- if _ , found := changedClasses [sc .GetName ()]; found {
155
- sc .Annotations [storageutil .IsDefaultStorageClassAnnotation ] = "true"
156
- _ , err := client .StorageV1 ().StorageClasses ().Update (ctx , & sc , metav1.UpdateOptions {})
157
- framework .ExpectNoError (err )
158
- }
159
- }
111
+ func setStorageClassDefault (ctx context.Context , client clientset.Interface , scName string , isDefault string ) {
112
+ sc , err := client .StorageV1 ().StorageClasses ().Get (ctx , scName , metav1.GetOptions {})
113
+ framework .ExpectNoError (err , "Error getting StorageClass" )
114
+
115
+ if sc .Annotations == nil {
116
+ sc .Annotations = make (map [string ]string )
160
117
}
118
+ sc .Annotations [storageutil .IsDefaultStorageClassAnnotation ] = isDefault
161
119
120
+ _ , err = client .StorageV1 ().StorageClasses ().Update (ctx , sc , metav1.UpdateOptions {})
121
+ framework .ExpectNoError (err , "Error updating StorageClass" )
162
122
}
163
123
164
- func waitForPVCStorageClass (ctx context.Context , c clientset.Interface , namespace , pvcName , scName string , timeout time.Duration ) (* v1.PersistentVolumeClaim , error ) {
165
- var watchedPVC * v1.PersistentVolumeClaim
166
-
167
- err := wait .PollUntilContextTimeout (ctx , 1 * time .Second , timeout , false , func (ctx context.Context ) (bool , error ) {
168
- var err error
169
- watchedPVC , err = c .CoreV1 ().PersistentVolumeClaims (namespace ).Get (ctx , pvcName , metav1.GetOptions {})
124
+ func ensureNoDefaultStorageClasses (ctx context.Context , client clientset.Interface ) {
125
+ gomega .Eventually (ctx , func () (int , error ) {
126
+ defaultSCs , err := getDefaultStorageClasses (ctx , client )
170
127
if err != nil {
171
- return true , err
128
+ return 0 , err
172
129
}
130
+ return len (defaultSCs ), nil
131
+ }).WithPolling (framework .Poll ).WithTimeout (2 * time .Minute ).
132
+ Should (gomega .BeZero (), "Expected no default StorageClasses" )
133
+ }
173
134
174
- if watchedPVC .Spec .StorageClassName == nil {
175
- return false , nil // Poll until PVC has correct SC
176
- }
177
- if watchedPVC .Spec .StorageClassName != nil && * watchedPVC .Spec .StorageClassName != scName {
178
- framework .Logf ("PersistentVolumeClaim %s has unexpected StorageClass %v, expected StorageClass is: %v" , watchedPVC .Name , * watchedPVC .Spec .StorageClassName , scName )
179
- return false , nil // Log unexpected SC and continue poll (something might be changing default SC)
180
- }
181
- return true , nil // Correct SC name found on PVC
182
- })
135
+ func createPVC (ctx context.Context , client clientset.Interface , namespace string ) * v1.PersistentVolumeClaim {
136
+ ginkgo .By ("Creating a PVC" )
183
137
184
- if err != nil {
185
- return watchedPVC , fmt .Errorf ("error waiting for claim %s to have StorageClass set to %s: %w" , pvcName , scName , err )
138
+ c := e2epv.PersistentVolumeClaimConfig {
139
+ Name : "test-pvc" ,
140
+ }
141
+
142
+ pvcObj := e2epv .MakePersistentVolumeClaim (c , namespace )
143
+ pvc , err := client .CoreV1 ().PersistentVolumeClaims (pvcObj .Namespace ).Create (ctx , pvcObj , metav1.CreateOptions {})
144
+ framework .ExpectNoError (err , "Error creating PVC" )
145
+
146
+ return pvc
147
+ }
148
+
149
+ func createDefaultStorageClass (ctx context.Context , client clientset.Interface ) * storagev1.StorageClass {
150
+ ginkgo .By ("Creating a default StorageClass" )
151
+
152
+ c := & storagev1.StorageClass {
153
+ TypeMeta : metav1.TypeMeta {
154
+ Kind : "StorageClass" ,
155
+ },
156
+ ObjectMeta : metav1.ObjectMeta {
157
+ Name : "test-default-sc" ,
158
+ Annotations : map [string ]string {
159
+ storageutil .IsDefaultStorageClassAnnotation : "true" ,
160
+ },
161
+ },
162
+ Provisioner : "fake-1" ,
186
163
}
187
164
188
- return watchedPVC , nil
165
+ sc , err := client .StorageV1 ().StorageClasses ().Create (ctx , c , metav1.CreateOptions {})
166
+ framework .ExpectNoError (err , "Error creating StorageClass" )
167
+
168
+ return sc
189
169
}
0 commit comments