1
16
17 package csidriver
18
19 import (
20 "testing"
21
22 "github.com/stretchr/testify/require"
23 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
24 "k8s.io/apimachinery/pkg/util/validation/field"
25 genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
26 utilfeature "k8s.io/apiserver/pkg/util/feature"
27 featuregatetesting "k8s.io/component-base/featuregate/testing"
28 "k8s.io/kubernetes/pkg/apis/storage"
29 "k8s.io/kubernetes/pkg/features"
30 )
31
32 func getValidCSIDriver(name string) *storage.CSIDriver {
33 enabled := true
34 return &storage.CSIDriver{
35 ObjectMeta: metav1.ObjectMeta{
36 Name: name,
37 },
38 Spec: storage.CSIDriverSpec{
39 AttachRequired: &enabled,
40 PodInfoOnMount: &enabled,
41 StorageCapacity: &enabled,
42 RequiresRepublish: &enabled,
43 SELinuxMount: &enabled,
44 },
45 }
46 }
47
48 func TestCSIDriverStrategy(t *testing.T) {
49 ctx := genericapirequest.WithRequestInfo(genericapirequest.NewContext(), &genericapirequest.RequestInfo{
50 APIGroup: "storage.k8s.io",
51 APIVersion: "v1",
52 Resource: "csidrivers",
53 })
54 if Strategy.NamespaceScoped() {
55 t.Errorf("CSIDriver must not be namespace scoped")
56 }
57 if Strategy.AllowCreateOnUpdate() {
58 t.Errorf("CSIDriver should not allow create on update")
59 }
60
61 csiDriver := getValidCSIDriver("valid-csidriver")
62
63 Strategy.PrepareForCreate(ctx, csiDriver)
64
65 errs := Strategy.Validate(ctx, csiDriver)
66 if len(errs) != 0 {
67 t.Errorf("unexpected error validating %v", errs)
68 }
69
70
71 newCSIDriver := csiDriver.DeepCopy()
72 attachNotRequired := false
73 newCSIDriver.Spec.AttachRequired = &attachNotRequired
74
75 Strategy.PrepareForUpdate(ctx, newCSIDriver, csiDriver)
76
77 errs = Strategy.ValidateUpdate(ctx, newCSIDriver, csiDriver)
78 if len(errs) == 0 {
79 t.Errorf("Expected a validation error")
80 }
81 }
82
83 func TestCSIDriverPrepareForUpdate(t *testing.T) {
84 ctx := genericapirequest.WithRequestInfo(genericapirequest.NewContext(), &genericapirequest.RequestInfo{
85 APIGroup: "storage.k8s.io",
86 APIVersion: "v1",
87 Resource: "csidrivers",
88 })
89
90 attachRequired := true
91 driverWithNothing := &storage.CSIDriver{
92 ObjectMeta: metav1.ObjectMeta{
93 Name: "foo",
94 },
95 }
96 driverWithPersistent := &storage.CSIDriver{
97 ObjectMeta: metav1.ObjectMeta{
98 Name: "foo",
99 },
100 Spec: storage.CSIDriverSpec{
101 AttachRequired: &attachRequired,
102 VolumeLifecycleModes: []storage.VolumeLifecycleMode{
103 storage.VolumeLifecyclePersistent,
104 },
105 },
106 }
107 enabled := true
108 disabled := false
109 gcp := "gcp"
110 noneFsGroupPolicy := storage.NoneFSGroupPolicy
111 readWriteOnceWithFSTypeFSGroupPolicy := storage.ReadWriteOnceWithFSTypeFSGroupPolicy
112 fileFSGroupPolicy := storage.FileFSGroupPolicy
113 driverWithPodInfoOnMountEnabled := &storage.CSIDriver{
114 ObjectMeta: metav1.ObjectMeta{
115 Name: "foo",
116 },
117 Spec: storage.CSIDriverSpec{
118 PodInfoOnMount: &enabled,
119 },
120 }
121 driverWithPodInfoOnMountDisabled := &storage.CSIDriver{
122 ObjectMeta: metav1.ObjectMeta{
123 Name: "foo",
124 },
125 Spec: storage.CSIDriverSpec{
126 PodInfoOnMount: &disabled,
127 },
128 }
129 driverWithNoneFSGroupPolicy := &storage.CSIDriver{
130 ObjectMeta: metav1.ObjectMeta{
131 Name: "foo",
132 },
133 Spec: storage.CSIDriverSpec{
134 FSGroupPolicy: &noneFsGroupPolicy,
135 },
136 }
137 driverWithReadWriteOnceWithFSTypeFSGroupPolicy := &storage.CSIDriver{
138 ObjectMeta: metav1.ObjectMeta{
139 Name: "foo",
140 },
141 Spec: storage.CSIDriverSpec{
142 FSGroupPolicy: &readWriteOnceWithFSTypeFSGroupPolicy,
143 },
144 }
145 driverWithFileFSGroupPolicy := &storage.CSIDriver{
146 ObjectMeta: metav1.ObjectMeta{
147 Name: "foo",
148 },
149 Spec: storage.CSIDriverSpec{
150 FSGroupPolicy: &fileFSGroupPolicy,
151 },
152 }
153 driverWithCapacityEnabled := &storage.CSIDriver{
154 ObjectMeta: metav1.ObjectMeta{
155 Name: "foo",
156 },
157 Spec: storage.CSIDriverSpec{
158 StorageCapacity: &enabled,
159 },
160 }
161 driverWithCapacityDisabled := &storage.CSIDriver{
162 ObjectMeta: metav1.ObjectMeta{
163 Name: "foo",
164 },
165 Spec: storage.CSIDriverSpec{
166 StorageCapacity: &disabled,
167 },
168 }
169 driverWithServiceAccountTokenGCP := &storage.CSIDriver{
170 ObjectMeta: metav1.ObjectMeta{
171 Name: "foo",
172 },
173 Spec: storage.CSIDriverSpec{
174 TokenRequests: []storage.TokenRequest{{Audience: gcp}},
175 RequiresRepublish: &enabled,
176 },
177 }
178 driverWithSELinuxMountEnabled := &storage.CSIDriver{
179 ObjectMeta: metav1.ObjectMeta{
180 Name: "foo",
181 },
182 Spec: storage.CSIDriverSpec{
183 SELinuxMount: &enabled,
184 },
185 }
186 driverWithSELinuxMountDisabled := &storage.CSIDriver{
187 ObjectMeta: metav1.ObjectMeta{
188 Name: "foo",
189 },
190 Spec: storage.CSIDriverSpec{
191 SELinuxMount: &disabled,
192 },
193 }
194
195 resultPersistent := []storage.VolumeLifecycleMode{storage.VolumeLifecyclePersistent}
196
197 tests := []struct {
198 name string
199 old, update *storage.CSIDriver
200 seLinuxMountReadWriteOncePodEnabled bool
201 wantCapacity *bool
202 wantModes []storage.VolumeLifecycleMode
203 wantTokenRequests []storage.TokenRequest
204 wantRequiresRepublish *bool
205 wantGeneration int64
206 wantSELinuxMount *bool
207 }{
208 {
209 name: "podInfoOnMount feature enabled, before: none, update: enabled",
210 old: driverWithNothing,
211 update: driverWithPodInfoOnMountEnabled,
212 wantGeneration: 1,
213 },
214 {
215 name: "podInfoOnMount feature enabled, before: enabled, update: disabled",
216 old: driverWithPodInfoOnMountEnabled,
217 update: driverWithPodInfoOnMountDisabled,
218 wantGeneration: 1,
219 },
220 {
221 name: "fSGroupPolicy feature enabled, before: nil, update: none",
222 old: driverWithNothing,
223 update: driverWithNoneFSGroupPolicy,
224 wantGeneration: 1,
225 },
226 {
227 name: "fSGroupPolicy feature enabled, before: nil, update: readWriteOnceWithFSType",
228 old: driverWithNothing,
229 update: driverWithReadWriteOnceWithFSTypeFSGroupPolicy,
230 wantGeneration: 1,
231 },
232 {
233 name: "fSGroupPolicy feature enabled, before: nil, update: file",
234 old: driverWithNothing,
235 update: driverWithFileFSGroupPolicy,
236 wantGeneration: 1,
237 },
238 {
239 name: "fSGroupPolicy feature enabled, before: none, update: readWriteOnceWithFSType",
240 old: driverWithNoneFSGroupPolicy,
241 update: driverWithReadWriteOnceWithFSTypeFSGroupPolicy,
242 wantGeneration: 1,
243 },
244 {
245 name: "fSGroupPolicy feature enabled, before: none, update: file",
246 old: driverWithNoneFSGroupPolicy,
247 update: driverWithFileFSGroupPolicy,
248 wantGeneration: 1,
249 },
250 {
251 name: "fSGroupPolicy feature enabled, before: readWriteOnceWithFSType, update: none",
252 old: driverWithReadWriteOnceWithFSTypeFSGroupPolicy,
253 update: driverWithNoneFSGroupPolicy,
254 wantGeneration: 1,
255 },
256 {
257 name: "fSGroupPolicy feature enabled, before: readWriteOnceWithFSType, update: file",
258 old: driverWithReadWriteOnceWithFSTypeFSGroupPolicy,
259 update: driverWithFileFSGroupPolicy,
260 wantGeneration: 1,
261 },
262 {
263 name: "fSGroupPolicy feature enabled, before: file, update: none",
264 old: driverWithFileFSGroupPolicy,
265 update: driverWithNoneFSGroupPolicy,
266 wantGeneration: 1,
267 },
268 {
269 name: "fSGroupPolicy feature enabled, before: file, update: readWriteOnceWithFSType",
270 old: driverWithFileFSGroupPolicy,
271 update: driverWithReadWriteOnceWithFSTypeFSGroupPolicy,
272 wantGeneration: 1,
273 },
274 {
275 name: "capacity feature enabled, before: none, update: enabled",
276 old: driverWithNothing,
277 update: driverWithCapacityEnabled,
278 wantCapacity: &enabled,
279 wantGeneration: 1,
280 },
281 {
282 name: "capacity feature enabled, before: enabled, update: disabled",
283 old: driverWithCapacityEnabled,
284 update: driverWithCapacityDisabled,
285 wantCapacity: &disabled,
286 wantGeneration: 1,
287 },
288 {
289 name: "inline feature enabled, before: none, update: persistent",
290 old: driverWithNothing,
291 update: driverWithPersistent,
292 wantModes: resultPersistent,
293 wantGeneration: 1,
294 },
295 {
296 name: "service account token feature enabled, before: none, update: audience=gcp",
297 old: driverWithNothing,
298 update: driverWithServiceAccountTokenGCP,
299 wantTokenRequests: []storage.TokenRequest{{Audience: gcp}},
300 wantRequiresRepublish: &enabled,
301 wantGeneration: 1,
302 },
303 {
304 name: "SELinux mount support feature enabled, before: nil, update: on",
305 seLinuxMountReadWriteOncePodEnabled: true,
306 old: driverWithNothing,
307 update: driverWithSELinuxMountEnabled,
308 wantSELinuxMount: &enabled,
309 wantGeneration: 1,
310 },
311 {
312 name: "SELinux mount support feature enabled, before: off, update: on",
313 seLinuxMountReadWriteOncePodEnabled: true,
314 old: driverWithSELinuxMountDisabled,
315 update: driverWithSELinuxMountEnabled,
316 wantSELinuxMount: &enabled,
317 wantGeneration: 1,
318 },
319 {
320 name: "SELinux mount support feature enabled, before: on, update: off",
321 seLinuxMountReadWriteOncePodEnabled: true,
322 old: driverWithSELinuxMountEnabled,
323 update: driverWithSELinuxMountDisabled,
324 wantSELinuxMount: &disabled,
325 wantGeneration: 1,
326 },
327 {
328 name: "SELinux mount support feature disabled, before: nil, update: on",
329 seLinuxMountReadWriteOncePodEnabled: false,
330 old: driverWithNothing,
331 update: driverWithSELinuxMountEnabled,
332 wantSELinuxMount: nil,
333 wantGeneration: 0,
334 },
335 {
336 name: "SELinux mount support feature disabled, before: off, update: on",
337 seLinuxMountReadWriteOncePodEnabled: false,
338 old: driverWithSELinuxMountDisabled,
339 update: driverWithSELinuxMountEnabled,
340 wantSELinuxMount: &enabled,
341 wantGeneration: 1,
342 },
343 {
344 name: "SELinux mount support feature enabled, before: on, update: off",
345 seLinuxMountReadWriteOncePodEnabled: false,
346 old: driverWithSELinuxMountEnabled,
347 update: driverWithSELinuxMountDisabled,
348 wantSELinuxMount: &disabled,
349 wantGeneration: 1,
350 },
351 }
352
353 for _, test := range tests {
354 t.Run(test.name, func(t *testing.T) {
355 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, test.seLinuxMountReadWriteOncePodEnabled)()
356
357 csiDriver := test.update.DeepCopy()
358 Strategy.PrepareForUpdate(ctx, csiDriver, test.old)
359 require.Equal(t, test.wantGeneration, csiDriver.GetGeneration())
360 require.Equal(t, test.wantCapacity, csiDriver.Spec.StorageCapacity)
361 require.Equal(t, test.wantModes, csiDriver.Spec.VolumeLifecycleModes)
362 require.Equal(t, test.wantTokenRequests, csiDriver.Spec.TokenRequests)
363 require.Equal(t, test.wantRequiresRepublish, csiDriver.Spec.RequiresRepublish)
364 require.Equal(t, test.wantSELinuxMount, csiDriver.Spec.SELinuxMount)
365 })
366 }
367 }
368
369 func TestCSIDriverValidation(t *testing.T) {
370 enabled := true
371 disabled := true
372 gcp := "gcp"
373
374 tests := []struct {
375 name string
376 csiDriver *storage.CSIDriver
377 expectError bool
378 }{
379 {
380 "valid csidriver",
381 getValidCSIDriver("foo"),
382 false,
383 },
384 {
385 "true for all flags",
386 &storage.CSIDriver{
387 ObjectMeta: metav1.ObjectMeta{
388 Name: "foo",
389 },
390 Spec: storage.CSIDriverSpec{
391 AttachRequired: &enabled,
392 PodInfoOnMount: &enabled,
393 StorageCapacity: &enabled,
394 RequiresRepublish: &enabled,
395 SELinuxMount: &enabled,
396 },
397 },
398 false,
399 },
400 {
401 "false for all flags",
402 &storage.CSIDriver{
403 ObjectMeta: metav1.ObjectMeta{
404 Name: "foo",
405 },
406 Spec: storage.CSIDriverSpec{
407 AttachRequired: &disabled,
408 PodInfoOnMount: &disabled,
409 StorageCapacity: &disabled,
410 RequiresRepublish: &disabled,
411 SELinuxMount: &disabled,
412 },
413 },
414 false,
415 },
416 {
417 "invalid driver name",
418 &storage.CSIDriver{
419 ObjectMeta: metav1.ObjectMeta{
420 Name: "*foo#",
421 },
422 Spec: storage.CSIDriverSpec{
423 AttachRequired: &enabled,
424 PodInfoOnMount: &enabled,
425 StorageCapacity: &enabled,
426 RequiresRepublish: &enabled,
427 SELinuxMount: &enabled,
428 },
429 },
430 true,
431 },
432 {
433 "invalid volume mode",
434 &storage.CSIDriver{
435 ObjectMeta: metav1.ObjectMeta{
436 Name: "foo",
437 },
438 Spec: storage.CSIDriverSpec{
439 AttachRequired: &enabled,
440 PodInfoOnMount: &enabled,
441 StorageCapacity: &enabled,
442 VolumeLifecycleModes: []storage.VolumeLifecycleMode{
443 storage.VolumeLifecycleMode("no-such-mode"),
444 },
445 RequiresRepublish: &enabled,
446 SELinuxMount: &enabled,
447 },
448 },
449 true,
450 },
451 {
452 "persistent volume mode",
453 &storage.CSIDriver{
454 ObjectMeta: metav1.ObjectMeta{
455 Name: "foo",
456 },
457 Spec: storage.CSIDriverSpec{
458 AttachRequired: &enabled,
459 PodInfoOnMount: &enabled,
460 StorageCapacity: &enabled,
461 VolumeLifecycleModes: []storage.VolumeLifecycleMode{
462 storage.VolumeLifecyclePersistent,
463 },
464 RequiresRepublish: &enabled,
465 SELinuxMount: &enabled,
466 },
467 },
468 false,
469 },
470 {
471 "ephemeral volume mode",
472 &storage.CSIDriver{
473 ObjectMeta: metav1.ObjectMeta{
474 Name: "foo",
475 },
476 Spec: storage.CSIDriverSpec{
477 AttachRequired: &enabled,
478 PodInfoOnMount: &enabled,
479 StorageCapacity: &enabled,
480 VolumeLifecycleModes: []storage.VolumeLifecycleMode{
481 storage.VolumeLifecycleEphemeral,
482 },
483 RequiresRepublish: &enabled,
484 SELinuxMount: &enabled,
485 },
486 },
487 false,
488 },
489 {
490 "both volume modes",
491 &storage.CSIDriver{
492 ObjectMeta: metav1.ObjectMeta{
493 Name: "foo",
494 },
495 Spec: storage.CSIDriverSpec{
496 AttachRequired: &enabled,
497 PodInfoOnMount: &enabled,
498 StorageCapacity: &enabled,
499 VolumeLifecycleModes: []storage.VolumeLifecycleMode{
500 storage.VolumeLifecyclePersistent,
501 storage.VolumeLifecycleEphemeral,
502 },
503 RequiresRepublish: &enabled,
504 SELinuxMount: &enabled,
505 },
506 },
507 false,
508 },
509 {
510 "service account token with gcp as audience",
511 &storage.CSIDriver{
512 ObjectMeta: metav1.ObjectMeta{
513 Name: "foo",
514 },
515 Spec: storage.CSIDriverSpec{
516 AttachRequired: &enabled,
517 PodInfoOnMount: &enabled,
518 StorageCapacity: &enabled,
519 TokenRequests: []storage.TokenRequest{{Audience: gcp}},
520 RequiresRepublish: &enabled,
521 SELinuxMount: &enabled,
522 },
523 },
524 false,
525 },
526 {
527 "invalid SELinuxMount",
528 &storage.CSIDriver{
529 ObjectMeta: metav1.ObjectMeta{
530 Name: "foo",
531 },
532 Spec: storage.CSIDriverSpec{
533 AttachRequired: &enabled,
534 PodInfoOnMount: &enabled,
535 StorageCapacity: &enabled,
536 SELinuxMount: nil,
537 },
538 },
539 true,
540 },
541 }
542
543 for _, test := range tests {
544 t.Run(test.name, func(t *testing.T) {
545
546 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)()
547
548 testValidation := func(csiDriver *storage.CSIDriver, apiVersion string) field.ErrorList {
549 ctx := genericapirequest.WithRequestInfo(genericapirequest.NewContext(), &genericapirequest.RequestInfo{
550 APIGroup: "storage.k8s.io",
551 APIVersion: "v1",
552 Resource: "csidrivers",
553 })
554 return Strategy.Validate(ctx, csiDriver)
555 }
556
557 err := testValidation(test.csiDriver, "v1")
558 if len(err) > 0 && !test.expectError {
559 t.Errorf("Validation of v1 object failed: %+v", err)
560 }
561 if len(err) == 0 && test.expectError {
562 t.Errorf("Validation of v1 object unexpectedly succeeded")
563 }
564 })
565 }
566 }
567
View as plain text