k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/registry/storage/csidriver/strategy_test.go (about) 1 /* 2 Copyright 2019 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 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 // Update of spec is disallowed 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 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 // assume this feature is on for this test, detailed enabled/disabled tests in TestCSIDriverValidationSELinuxMountEnabledDisabled 546 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 }