k8s.io/kubernetes@v1.29.3/pkg/kubelet/volumemanager/cache/desired_state_of_world_test.go (about) 1 /* 2 Copyright 2016 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 cache 18 19 import ( 20 "testing" 21 22 v1 "k8s.io/api/core/v1" 23 "k8s.io/apimachinery/pkg/api/resource" 24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 utilfeature "k8s.io/apiserver/pkg/util/feature" 26 featuregatetesting "k8s.io/component-base/featuregate/testing" 27 "k8s.io/kubernetes/pkg/features" 28 "k8s.io/kubernetes/pkg/volume" 29 volumetesting "k8s.io/kubernetes/pkg/volume/testing" 30 "k8s.io/kubernetes/pkg/volume/util" 31 volumetypes "k8s.io/kubernetes/pkg/volume/util/types" 32 ) 33 34 // Calls AddPodToVolume() to add new pod to new volume 35 // Verifies newly added pod/volume exists via 36 // PodExistsInVolume() VolumeExists() and GetVolumesToMount() 37 func Test_AddPodToVolume_Positive_NewPodNewVolume(t *testing.T) { 38 // Arrange 39 volumePluginMgr, _ := volumetesting.GetTestKubeletVolumePluginMgr(t) 40 seLinuxTranslator := util.NewFakeSELinuxLabelTranslator() 41 dsw := NewDesiredStateOfWorld(volumePluginMgr, seLinuxTranslator) 42 pod := &v1.Pod{ 43 ObjectMeta: metav1.ObjectMeta{ 44 Name: "pod3", 45 UID: "pod3uid", 46 }, 47 Spec: v1.PodSpec{ 48 Volumes: []v1.Volume{ 49 { 50 Name: "volume-name", 51 VolumeSource: v1.VolumeSource{ 52 GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{ 53 PDName: "fake-device1", 54 }, 55 }, 56 }, 57 }, 58 }, 59 } 60 61 volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]} 62 podName := util.GetUniquePodName(pod) 63 64 // Act 65 generatedVolumeName, err := dsw.AddPodToVolume( 66 podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */, nil /* seLinuxContainerContexts */) 67 68 // Assert 69 if err != nil { 70 t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err) 71 } 72 73 verifyVolumeExistsDsw(t, generatedVolumeName, "" /* SELinuxContext */, dsw) 74 verifyVolumeExistsInVolumesToMount( 75 t, generatedVolumeName, false /* expectReportedInUse */, dsw) 76 verifyPodExistsInVolumeDsw(t, podName, generatedVolumeName, "" /* SELinuxContext */, dsw) 77 verifyVolumeExistsWithSpecNameInVolumeDsw(t, podName, volumeSpec.Name(), dsw) 78 } 79 80 // Calls AddPodToVolume() twice to add the same pod to the same volume 81 // Verifies newly added pod/volume exists via 82 // PodExistsInVolume() VolumeExists() and GetVolumesToMount() and no errors. 83 func Test_AddPodToVolume_Positive_ExistingPodExistingVolume(t *testing.T) { 84 // Arrange 85 volumePluginMgr, _ := volumetesting.GetTestKubeletVolumePluginMgr(t) 86 seLinuxTranslator := util.NewFakeSELinuxLabelTranslator() 87 dsw := NewDesiredStateOfWorld(volumePluginMgr, seLinuxTranslator) 88 pod := &v1.Pod{ 89 ObjectMeta: metav1.ObjectMeta{ 90 Name: "pod3", 91 UID: "pod3uid", 92 }, 93 Spec: v1.PodSpec{ 94 Volumes: []v1.Volume{ 95 { 96 Name: "volume-name", 97 VolumeSource: v1.VolumeSource{ 98 GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{ 99 PDName: "fake-device1", 100 }, 101 }, 102 }, 103 }, 104 }, 105 } 106 107 volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]} 108 podName := util.GetUniquePodName(pod) 109 110 // Act 111 generatedVolumeName, err := dsw.AddPodToVolume( 112 podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */, nil /* seLinuxContainerContexts */) 113 114 // Assert 115 if err != nil { 116 t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err) 117 } 118 119 verifyVolumeExistsDsw(t, generatedVolumeName, "" /* SELinuxContext */, dsw) 120 verifyVolumeExistsInVolumesToMount( 121 t, generatedVolumeName, false /* expectReportedInUse */, dsw) 122 verifyPodExistsInVolumeDsw(t, podName, generatedVolumeName, "" /* SELinuxContext */, dsw) 123 verifyVolumeExistsWithSpecNameInVolumeDsw(t, podName, volumeSpec.Name(), dsw) 124 } 125 126 // Call AddPodToVolume() on different pods for different kinds of volumes 127 // Verities generated names are same for different pods if volume is device mountable or attachable 128 // Verities generated names are different for different pods if volume is not device mountble and attachable 129 func Test_AddPodToVolume_Positive_NamesForDifferentPodsAndDifferentVolumes(t *testing.T) { 130 // Arrange 131 fakeVolumeHost := volumetesting.NewFakeVolumeHost(t, 132 "", /* rootDir */ 133 nil, /* kubeClient */ 134 nil, /* plugins */ 135 ) 136 plugins := []volume.VolumePlugin{ 137 &volumetesting.FakeBasicVolumePlugin{ 138 Plugin: volumetesting.FakeVolumePlugin{ 139 PluginName: "basic", 140 }, 141 }, 142 &volumetesting.FakeDeviceMountableVolumePlugin{ 143 FakeBasicVolumePlugin: volumetesting.FakeBasicVolumePlugin{ 144 Plugin: volumetesting.FakeVolumePlugin{ 145 PluginName: "device-mountable", 146 }, 147 }, 148 }, 149 &volumetesting.FakeAttachableVolumePlugin{ 150 FakeDeviceMountableVolumePlugin: volumetesting.FakeDeviceMountableVolumePlugin{ 151 FakeBasicVolumePlugin: volumetesting.FakeBasicVolumePlugin{ 152 Plugin: volumetesting.FakeVolumePlugin{ 153 PluginName: "attachable", 154 }, 155 }, 156 }, 157 }, 158 } 159 volumePluginMgr := volume.VolumePluginMgr{} 160 volumePluginMgr.InitPlugins(plugins, nil /* prober */, fakeVolumeHost) 161 seLinuxTranslator := util.NewFakeSELinuxLabelTranslator() 162 dsw := NewDesiredStateOfWorld(&volumePluginMgr, seLinuxTranslator) 163 164 testcases := map[string]struct { 165 pod1 *v1.Pod 166 pod2 *v1.Pod 167 same bool 168 }{ 169 "basic": { 170 &v1.Pod{ 171 ObjectMeta: metav1.ObjectMeta{ 172 Name: "pod1", 173 UID: "pod1uid", 174 }, 175 Spec: v1.PodSpec{ 176 Volumes: []v1.Volume{ 177 { 178 Name: "basic", 179 VolumeSource: v1.VolumeSource{}, 180 }, 181 }, 182 }, 183 }, 184 &v1.Pod{ 185 ObjectMeta: metav1.ObjectMeta{ 186 Name: "pod2", 187 UID: "pod2uid", 188 }, 189 Spec: v1.PodSpec{ 190 Volumes: []v1.Volume{ 191 { 192 Name: "basic", 193 VolumeSource: v1.VolumeSource{}, 194 }, 195 }, 196 }, 197 }, 198 false, 199 }, 200 "device-mountable": { 201 &v1.Pod{ 202 ObjectMeta: metav1.ObjectMeta{ 203 Name: "pod1", 204 UID: "pod1uid", 205 }, 206 Spec: v1.PodSpec{ 207 Volumes: []v1.Volume{ 208 { 209 Name: "device-mountable", 210 VolumeSource: v1.VolumeSource{}, 211 }, 212 }, 213 }, 214 }, 215 &v1.Pod{ 216 ObjectMeta: metav1.ObjectMeta{ 217 Name: "pod2", 218 UID: "pod2uid", 219 }, 220 Spec: v1.PodSpec{ 221 Volumes: []v1.Volume{ 222 { 223 Name: "device-mountable", 224 VolumeSource: v1.VolumeSource{}, 225 }, 226 }, 227 }, 228 }, 229 true, 230 }, 231 "attachable": { 232 &v1.Pod{ 233 ObjectMeta: metav1.ObjectMeta{ 234 Name: "pod1", 235 UID: "pod1uid", 236 }, 237 Spec: v1.PodSpec{ 238 Volumes: []v1.Volume{ 239 { 240 Name: "attachable", 241 VolumeSource: v1.VolumeSource{}, 242 }, 243 }, 244 }, 245 }, 246 &v1.Pod{ 247 ObjectMeta: metav1.ObjectMeta{ 248 Name: "pod2", 249 UID: "pod2uid", 250 }, 251 Spec: v1.PodSpec{ 252 Volumes: []v1.Volume{ 253 { 254 Name: "attachable", 255 VolumeSource: v1.VolumeSource{}, 256 }, 257 }, 258 }, 259 }, 260 true, 261 }, 262 } 263 264 // Act & Assert 265 for name, v := range testcases { 266 volumeSpec1 := &volume.Spec{Volume: &v.pod1.Spec.Volumes[0]} 267 volumeSpec2 := &volume.Spec{Volume: &v.pod2.Spec.Volumes[0]} 268 generatedVolumeName1, err1 := dsw.AddPodToVolume(util.GetUniquePodName(v.pod1), v.pod1, volumeSpec1, volumeSpec1.Name(), "", nil) 269 generatedVolumeName2, err2 := dsw.AddPodToVolume(util.GetUniquePodName(v.pod2), v.pod2, volumeSpec2, volumeSpec2.Name(), "", nil) 270 if err1 != nil { 271 t.Fatalf("test %q: AddPodToVolume failed. Expected: <no error> Actual: <%v>", name, err1) 272 } 273 if err2 != nil { 274 t.Fatalf("test %q: AddPodToVolume failed. Expected: <no error> Actual: <%v>", name, err2) 275 } 276 if v.same { 277 if generatedVolumeName1 != generatedVolumeName2 { 278 t.Fatalf("test %q: AddPodToVolume should generate same names, but got %q != %q", name, generatedVolumeName1, generatedVolumeName2) 279 } 280 } else { 281 if generatedVolumeName1 == generatedVolumeName2 { 282 t.Fatalf("test %q: AddPodToVolume should generate different names, but got %q == %q", name, generatedVolumeName1, generatedVolumeName2) 283 } 284 } 285 } 286 287 } 288 289 // Populates data struct with a new volume/pod 290 // Calls DeletePodFromVolume() to removes the pod 291 // Verifies newly added pod/volume are deleted 292 func Test_DeletePodFromVolume_Positive_PodExistsVolumeExists(t *testing.T) { 293 // Arrange 294 volumePluginMgr, _ := volumetesting.GetTestKubeletVolumePluginMgr(t) 295 seLinuxTranslator := util.NewFakeSELinuxLabelTranslator() 296 dsw := NewDesiredStateOfWorld(volumePluginMgr, seLinuxTranslator) 297 pod := &v1.Pod{ 298 ObjectMeta: metav1.ObjectMeta{ 299 Name: "pod3", 300 UID: "pod3uid", 301 }, 302 Spec: v1.PodSpec{ 303 Volumes: []v1.Volume{ 304 { 305 Name: "volume-name", 306 VolumeSource: v1.VolumeSource{ 307 GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{ 308 PDName: "fake-device1", 309 }, 310 }, 311 }, 312 }, 313 }, 314 } 315 316 volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]} 317 podName := util.GetUniquePodName(pod) 318 generatedVolumeName, err := dsw.AddPodToVolume( 319 podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */, nil /* seLinuxContainerContexts */) 320 if err != nil { 321 t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err) 322 } 323 verifyVolumeExistsDsw(t, generatedVolumeName, "" /* SELinuxContext */, dsw) 324 verifyVolumeExistsInVolumesToMount( 325 t, generatedVolumeName, false /* expectReportedInUse */, dsw) 326 verifyPodExistsInVolumeDsw(t, podName, generatedVolumeName, "" /* SELinuxContext */, dsw) 327 328 // Act 329 dsw.DeletePodFromVolume(podName, generatedVolumeName) 330 331 // Assert 332 verifyVolumeDoesntExist(t, generatedVolumeName, "" /* SELinuxContext */, dsw) 333 verifyVolumeDoesntExistInVolumesToMount(t, generatedVolumeName, dsw) 334 verifyPodDoesntExistInVolumeDsw(t, podName, generatedVolumeName, "" /* SELinuxContext */, dsw) 335 verifyVolumeDoesntExistWithSpecNameInVolumeDsw(t, podName, volumeSpec.Name(), dsw) 336 } 337 338 // Calls AddPodToVolume() to add three new volumes to data struct 339 // Verifies newly added pod/volume exists via PodExistsInVolume() 340 // VolumeExists() and GetVolumesToMount() 341 // Marks only second volume as reported in use. 342 // Verifies only that volume is marked reported in use 343 // Marks only first volume as reported in use. 344 // Verifies only that volume is marked reported in use 345 func Test_MarkVolumesReportedInUse_Positive_NewPodNewVolume(t *testing.T) { 346 // Arrange 347 volumePluginMgr, _ := volumetesting.GetTestKubeletVolumePluginMgr(t) 348 seLinuxTranslator := util.NewFakeSELinuxLabelTranslator() 349 dsw := NewDesiredStateOfWorld(volumePluginMgr, seLinuxTranslator) 350 351 pod1 := &v1.Pod{ 352 ObjectMeta: metav1.ObjectMeta{ 353 Name: "pod1", 354 UID: "pod1uid", 355 }, 356 Spec: v1.PodSpec{ 357 Volumes: []v1.Volume{ 358 { 359 Name: "volume1-name", 360 VolumeSource: v1.VolumeSource{ 361 GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{ 362 PDName: "fake-device1", 363 }, 364 }, 365 }, 366 }, 367 }, 368 } 369 370 volume1Spec := &volume.Spec{Volume: &pod1.Spec.Volumes[0]} 371 pod1Name := util.GetUniquePodName(pod1) 372 373 pod2 := &v1.Pod{ 374 ObjectMeta: metav1.ObjectMeta{ 375 Name: "pod2", 376 UID: "pod2uid", 377 }, 378 Spec: v1.PodSpec{ 379 Volumes: []v1.Volume{ 380 { 381 Name: "volume2-name", 382 VolumeSource: v1.VolumeSource{ 383 GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{ 384 PDName: "fake-device2", 385 }, 386 }, 387 }, 388 }, 389 }, 390 } 391 392 volume2Spec := &volume.Spec{Volume: &pod2.Spec.Volumes[0]} 393 pod2Name := util.GetUniquePodName(pod2) 394 395 pod3 := &v1.Pod{ 396 ObjectMeta: metav1.ObjectMeta{ 397 Name: "pod3", 398 UID: "pod3uid", 399 }, 400 Spec: v1.PodSpec{ 401 Volumes: []v1.Volume{ 402 { 403 Name: "volume3-name", 404 VolumeSource: v1.VolumeSource{ 405 GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{ 406 PDName: "fake-device3", 407 }, 408 }, 409 }, 410 }, 411 }, 412 } 413 414 volume3Spec := &volume.Spec{Volume: &pod3.Spec.Volumes[0]} 415 pod3Name := util.GetUniquePodName(pod3) 416 417 generatedVolume1Name, err := dsw.AddPodToVolume( 418 pod1Name, pod1, volume1Spec, volume1Spec.Name(), "" /* volumeGidValue */, nil /* seLinuxContainerContexts */) 419 if err != nil { 420 t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err) 421 } 422 423 generatedVolume2Name, err := dsw.AddPodToVolume( 424 pod2Name, pod2, volume2Spec, volume2Spec.Name(), "" /* volumeGidValue */, nil /* seLinuxContainerContexts */) 425 if err != nil { 426 t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err) 427 } 428 429 generatedVolume3Name, err := dsw.AddPodToVolume( 430 pod3Name, pod3, volume3Spec, volume3Spec.Name(), "" /* volumeGidValue */, nil /* seLinuxContainerContexts */) 431 if err != nil { 432 t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err) 433 } 434 435 // Act 436 volumesReportedInUse := []v1.UniqueVolumeName{generatedVolume2Name} 437 dsw.MarkVolumesReportedInUse(volumesReportedInUse) 438 439 // Assert 440 verifyVolumeExistsDsw(t, generatedVolume1Name, "" /* SELinuxContext */, dsw) 441 verifyVolumeExistsInVolumesToMount( 442 t, generatedVolume1Name, false /* expectReportedInUse */, dsw) 443 verifyPodExistsInVolumeDsw(t, pod1Name, generatedVolume1Name, "" /* SELinuxContext */, dsw) 444 verifyVolumeExistsDsw(t, generatedVolume2Name, "" /* SELinuxContext */, dsw) 445 verifyVolumeExistsInVolumesToMount( 446 t, generatedVolume2Name, true /* expectReportedInUse */, dsw) 447 verifyPodExistsInVolumeDsw(t, pod2Name, generatedVolume2Name, "" /* SELinuxContext */, dsw) 448 verifyVolumeExistsDsw(t, generatedVolume3Name, "" /* SELinuxContext */, dsw) 449 verifyVolumeExistsInVolumesToMount( 450 t, generatedVolume3Name, false /* expectReportedInUse */, dsw) 451 verifyPodExistsInVolumeDsw(t, pod3Name, generatedVolume3Name, "" /* SELinuxContext */, dsw) 452 453 // Act 454 volumesReportedInUse = []v1.UniqueVolumeName{generatedVolume3Name} 455 dsw.MarkVolumesReportedInUse(volumesReportedInUse) 456 457 // Assert 458 verifyVolumeExistsDsw(t, generatedVolume1Name, "" /* SELinuxContext */, dsw) 459 verifyVolumeExistsInVolumesToMount( 460 t, generatedVolume1Name, false /* expectReportedInUse */, dsw) 461 verifyPodExistsInVolumeDsw(t, pod1Name, generatedVolume1Name, "" /* SELinuxContext */, dsw) 462 verifyVolumeExistsDsw(t, generatedVolume2Name, "" /* SELinuxContext */, dsw) 463 verifyVolumeExistsInVolumesToMount( 464 t, generatedVolume2Name, false /* expectReportedInUse */, dsw) 465 verifyPodExistsInVolumeDsw(t, pod2Name, generatedVolume2Name, "" /* SELinuxContext */, dsw) 466 verifyVolumeExistsDsw(t, generatedVolume3Name, "" /* SELinuxContext */, dsw) 467 verifyVolumeExistsInVolumesToMount( 468 t, generatedVolume3Name, true /* expectReportedInUse */, dsw) 469 verifyPodExistsInVolumeDsw(t, pod3Name, generatedVolume3Name, "" /* SELinuxContext */, dsw) 470 } 471 472 func Test_AddPodToVolume_WithEmptyDirSizeLimit(t *testing.T) { 473 volumePluginMgr, _ := volumetesting.GetTestKubeletVolumePluginMgr(t) 474 seLinuxTranslator := util.NewFakeSELinuxLabelTranslator() 475 dsw := NewDesiredStateOfWorld(volumePluginMgr, seLinuxTranslator) 476 quantity1Gi := resource.MustParse("1Gi") 477 quantity2Gi := resource.MustParse("2Gi") 478 quantity3Gi := resource.MustParse("3Gi") 479 480 pod1 := &v1.Pod{ 481 ObjectMeta: metav1.ObjectMeta{ 482 Name: "pod1", 483 UID: "pod1uid", 484 }, 485 Spec: v1.PodSpec{ 486 Containers: []v1.Container{ 487 { 488 Resources: v1.ResourceRequirements{ 489 Limits: v1.ResourceList{ 490 v1.ResourceEphemeralStorage: quantity1Gi, 491 }, 492 }, 493 }, 494 { 495 Resources: v1.ResourceRequirements{ 496 Limits: v1.ResourceList{ 497 v1.ResourceEphemeralStorage: quantity1Gi, 498 }, 499 }, 500 }, 501 }, 502 Volumes: []v1.Volume{ 503 { 504 Name: "emptyDir1", 505 VolumeSource: v1.VolumeSource{ 506 EmptyDir: &v1.EmptyDirVolumeSource{ 507 SizeLimit: &quantity1Gi, 508 }, 509 }, 510 }, 511 { 512 Name: "emptyDir2", 513 VolumeSource: v1.VolumeSource{ 514 EmptyDir: &v1.EmptyDirVolumeSource{ 515 SizeLimit: &quantity2Gi, 516 }, 517 }, 518 }, 519 { 520 Name: "emptyDir3", 521 VolumeSource: v1.VolumeSource{ 522 EmptyDir: &v1.EmptyDirVolumeSource{ 523 SizeLimit: &quantity3Gi, 524 }, 525 }, 526 }, 527 { 528 Name: "emptyDir4", 529 VolumeSource: v1.VolumeSource{ 530 EmptyDir: &v1.EmptyDirVolumeSource{}, 531 }, 532 }, 533 }, 534 }, 535 } 536 pod1Name := util.GetUniquePodName(pod1) 537 pod1DesiredSizeLimitMap := map[string]*resource.Quantity{ 538 "emptyDir1": &quantity1Gi, 539 "emptyDir2": &quantity2Gi, 540 "emptyDir3": &quantity2Gi, 541 "emptyDir4": &quantity2Gi, 542 } 543 pod2 := &v1.Pod{ 544 ObjectMeta: metav1.ObjectMeta{ 545 Name: "pod2", 546 UID: "pod2uid", 547 }, 548 Spec: v1.PodSpec{ 549 Volumes: []v1.Volume{ 550 { 551 Name: "emptyDir5", 552 VolumeSource: v1.VolumeSource{ 553 EmptyDir: &v1.EmptyDirVolumeSource{ 554 SizeLimit: &quantity1Gi, 555 }, 556 }, 557 }, 558 { 559 Name: "emptyDir6", 560 VolumeSource: v1.VolumeSource{ 561 EmptyDir: &v1.EmptyDirVolumeSource{ 562 SizeLimit: &quantity2Gi, 563 }, 564 }, 565 }, 566 { 567 Name: "emptyDir7", 568 VolumeSource: v1.VolumeSource{ 569 EmptyDir: &v1.EmptyDirVolumeSource{ 570 SizeLimit: &quantity3Gi, 571 }, 572 }, 573 }, 574 { 575 Name: "emptyDir8", 576 VolumeSource: v1.VolumeSource{ 577 EmptyDir: &v1.EmptyDirVolumeSource{}, 578 }, 579 }, 580 }, 581 }, 582 } 583 pod2Name := util.GetUniquePodName(pod2) 584 pod2DesiredSizeLimitMap := map[string]*resource.Quantity{ 585 "emptyDir5": &quantity1Gi, 586 "emptyDir6": &quantity2Gi, 587 "emptyDir7": &quantity3Gi, 588 "emptyDir8": resource.NewQuantity(0, resource.BinarySI), 589 } 590 for i := range pod1.Spec.Volumes { 591 volumeSpec := &volume.Spec{Volume: &pod1.Spec.Volumes[i]} 592 _, err := dsw.AddPodToVolume(pod1Name, pod1, volumeSpec, volumeSpec.Name(), "", nil /* seLinuxContainerContexts */) 593 if err != nil { 594 t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err) 595 } 596 } 597 for i := range pod2.Spec.Volumes { 598 volumeSpec := &volume.Spec{Volume: &pod2.Spec.Volumes[i]} 599 _, err := dsw.AddPodToVolume(pod2Name, pod2, volumeSpec, volumeSpec.Name(), "", nil /* seLinuxContainerContexts */) 600 if err != nil { 601 t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err) 602 } 603 } 604 verifyDesiredSizeLimitInVolumeDsw(t, pod1Name, pod1DesiredSizeLimitMap, dsw) 605 verifyDesiredSizeLimitInVolumeDsw(t, pod2Name, pod2DesiredSizeLimitMap, dsw) 606 } 607 608 // Calls AddPodToVolume() with a volume that support SELinux, but is ReadWriteMany. 609 // Verifies newly added pod/volume exists via PodExistsInVolume() without SELinux context 610 // VolumeExists() and GetVolumesToMount() and no errors. 611 func Test_AddPodToVolume_Positive_SELinuxNoRWOP(t *testing.T) { 612 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)() 613 // Arrange 614 plugins := []volume.VolumePlugin{ 615 &volumetesting.FakeDeviceMountableVolumePlugin{ 616 FakeBasicVolumePlugin: volumetesting.FakeBasicVolumePlugin{ 617 Plugin: volumetesting.FakeVolumePlugin{ 618 PluginName: "basic", 619 SupportsSELinux: true, 620 }, 621 }, 622 }, 623 } 624 volumePluginMgr := volume.VolumePluginMgr{} 625 fakeVolumeHost := volumetesting.NewFakeVolumeHost(t, 626 "", /* rootDir */ 627 nil, /* kubeClient */ 628 nil, /* plugins */ 629 ) 630 volumePluginMgr.InitPlugins(plugins, nil /* prober */, fakeVolumeHost) 631 seLinuxTranslator := util.NewFakeSELinuxLabelTranslator() 632 dsw := NewDesiredStateOfWorld(&volumePluginMgr, seLinuxTranslator) 633 seLinux := v1.SELinuxOptions{ 634 User: "system_u", 635 Role: "object_r", 636 Type: "container_t", 637 Level: "s0:c1,c2", 638 } 639 pod := &v1.Pod{ 640 ObjectMeta: metav1.ObjectMeta{ 641 Name: "pod1", 642 UID: "pod1uid", 643 }, 644 Spec: v1.PodSpec{ 645 SecurityContext: &v1.PodSecurityContext{ 646 SELinuxOptions: &seLinux, 647 }, 648 Volumes: []v1.Volume{ 649 { 650 Name: "volume-name", 651 VolumeSource: v1.VolumeSource{ 652 PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ 653 ClaimName: "myClaim", 654 }, 655 }, 656 }, 657 }, 658 }, 659 } 660 661 volumeSpec := &volume.Spec{ 662 PersistentVolume: &v1.PersistentVolume{ 663 ObjectMeta: metav1.ObjectMeta{ 664 Name: "basicPV", 665 }, 666 Spec: v1.PersistentVolumeSpec{ 667 AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteMany}, 668 }, 669 }, 670 } 671 podName := util.GetUniquePodName(pod) 672 seLinuxContainerContexts := []*v1.SELinuxOptions{&seLinux} 673 674 // Act 675 generatedVolumeName, err := dsw.AddPodToVolume( 676 podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */, seLinuxContainerContexts) 677 678 // Assert 679 if err != nil { 680 t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err) 681 } 682 683 verifyVolumeExistsDsw(t, generatedVolumeName, "" /* SELinux */, dsw) 684 verifyVolumeExistsInVolumesToMount( 685 t, generatedVolumeName, false /* expectReportedInUse */, dsw) 686 verifyPodExistsInVolumeDsw(t, podName, generatedVolumeName, "" /* SELinux */, dsw) 687 verifyVolumeExistsWithSpecNameInVolumeDsw(t, podName, volumeSpec.Name(), dsw) 688 } 689 690 // Calls AddPodToVolume() with a volume that does not support SELinux. 691 // Verifies newly added pod/volume exists via PodExistsInVolume() without SELinux context 692 // VolumeExists() and GetVolumesToMount() and no errors. 693 func Test_AddPodToVolume_Positive_NoSELinuxPlugin(t *testing.T) { 694 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)() 695 // Arrange 696 plugins := []volume.VolumePlugin{ 697 &volumetesting.FakeDeviceMountableVolumePlugin{ 698 FakeBasicVolumePlugin: volumetesting.FakeBasicVolumePlugin{ 699 Plugin: volumetesting.FakeVolumePlugin{ 700 PluginName: "basic", 701 SupportsSELinux: false, 702 }, 703 }, 704 }, 705 } 706 volumePluginMgr := volume.VolumePluginMgr{} 707 fakeVolumeHost := volumetesting.NewFakeVolumeHost(t, 708 "", /* rootDir */ 709 nil, /* kubeClient */ 710 nil, /* plugins */ 711 ) 712 volumePluginMgr.InitPlugins(plugins, nil /* prober */, fakeVolumeHost) 713 seLinuxTranslator := util.NewFakeSELinuxLabelTranslator() 714 dsw := NewDesiredStateOfWorld(&volumePluginMgr, seLinuxTranslator) 715 seLinux := v1.SELinuxOptions{ 716 User: "system_u", 717 Role: "object_r", 718 Type: "container_t", 719 Level: "s0:c1,c2", 720 } 721 pod := &v1.Pod{ 722 ObjectMeta: metav1.ObjectMeta{ 723 Name: "pod1", 724 UID: "pod1uid", 725 }, 726 Spec: v1.PodSpec{ 727 SecurityContext: &v1.PodSecurityContext{ 728 SELinuxOptions: &seLinux, 729 }, 730 Volumes: []v1.Volume{ 731 { 732 Name: "volume-name", 733 VolumeSource: v1.VolumeSource{ 734 PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ 735 ClaimName: "myClaim", 736 }, 737 }, 738 }, 739 }, 740 }, 741 } 742 743 volumeSpec := &volume.Spec{ 744 PersistentVolume: &v1.PersistentVolume{ 745 ObjectMeta: metav1.ObjectMeta{ 746 Name: "basicPV", 747 }, 748 Spec: v1.PersistentVolumeSpec{ 749 AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOncePod}, 750 }, 751 }, 752 } 753 podName := util.GetUniquePodName(pod) 754 seLinuxContainerContexts := []*v1.SELinuxOptions{&seLinux} 755 756 // Act 757 generatedVolumeName, err := dsw.AddPodToVolume( 758 podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */, seLinuxContainerContexts) 759 760 // Assert 761 if err != nil { 762 t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err) 763 } 764 765 verifyVolumeExistsDsw(t, generatedVolumeName, "" /* SELinux */, dsw) 766 verifyVolumeExistsInVolumesToMount( 767 t, generatedVolumeName, false /* expectReportedInUse */, dsw) 768 verifyPodExistsInVolumeDsw(t, podName, generatedVolumeName, "" /* SELinux */, dsw) 769 verifyVolumeExistsWithSpecNameInVolumeDsw(t, podName, volumeSpec.Name(), dsw) 770 } 771 772 // Calls AddPodToVolume() twice to add two pods with the same SELinuxContext 773 // to the same ReadWriteOncePod PV. 774 // Verifies newly added pod/volume exists via PodExistsInVolume() 775 // VolumeExists() and GetVolumesToMount() and no errors. 776 func Test_AddPodToVolume_Positive_ExistingPodSameSELinuxRWOP(t *testing.T) { 777 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)() 778 // Arrange 779 plugins := []volume.VolumePlugin{ 780 &volumetesting.FakeDeviceMountableVolumePlugin{ 781 FakeBasicVolumePlugin: volumetesting.FakeBasicVolumePlugin{ 782 Plugin: volumetesting.FakeVolumePlugin{ 783 PluginName: "basic", 784 SupportsSELinux: true, 785 }, 786 }, 787 }, 788 } 789 volumePluginMgr := volume.VolumePluginMgr{} 790 fakeVolumeHost := volumetesting.NewFakeVolumeHost(t, 791 "", /* rootDir */ 792 nil, /* kubeClient */ 793 nil, /* plugins */ 794 ) 795 volumePluginMgr.InitPlugins(plugins, nil /* prober */, fakeVolumeHost) 796 seLinuxTranslator := util.NewFakeSELinuxLabelTranslator() 797 dsw := NewDesiredStateOfWorld(&volumePluginMgr, seLinuxTranslator) 798 seLinux := v1.SELinuxOptions{ 799 User: "system_u", 800 Role: "object_r", 801 Type: "container_t", 802 Level: "s0:c1,c2", 803 } 804 pod := &v1.Pod{ 805 ObjectMeta: metav1.ObjectMeta{ 806 Name: "pod1", 807 UID: "pod1uid", 808 }, 809 Spec: v1.PodSpec{ 810 SecurityContext: &v1.PodSecurityContext{ 811 SELinuxOptions: &seLinux, 812 }, 813 Volumes: []v1.Volume{ 814 { 815 Name: "volume-name", 816 VolumeSource: v1.VolumeSource{ 817 PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ 818 ClaimName: "myClaim", 819 }, 820 }, 821 }, 822 }, 823 }, 824 } 825 826 volumeSpec := &volume.Spec{ 827 PersistentVolume: &v1.PersistentVolume{ 828 ObjectMeta: metav1.ObjectMeta{ 829 Name: "basicPV", 830 }, 831 Spec: v1.PersistentVolumeSpec{ 832 AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOncePod}, 833 }, 834 }, 835 } 836 podName := util.GetUniquePodName(pod) 837 seLinuxContainerContexts := []*v1.SELinuxOptions{&seLinux} 838 839 // Act 840 generatedVolumeName, err := dsw.AddPodToVolume( 841 podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */, seLinuxContainerContexts) 842 843 // Assert 844 if err != nil { 845 t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err) 846 } 847 848 verifyVolumeExistsDsw(t, generatedVolumeName, "system_u:object_r:container_file_t:s0:c1,c2", dsw) 849 verifyVolumeExistsInVolumesToMount( 850 t, generatedVolumeName, false /* expectReportedInUse */, dsw) 851 verifyPodExistsInVolumeDsw(t, podName, generatedVolumeName, "system_u:object_r:container_file_t:s0:c1,c2", dsw) 852 verifyVolumeExistsWithSpecNameInVolumeDsw(t, podName, volumeSpec.Name(), dsw) 853 854 // Arrange: prepare a different pod with the same context 855 pod2 := pod.DeepCopy() 856 pod2.Name = "pod2" 857 pod2.UID = "pod2uid" 858 pod2Name := util.GetUniquePodName(pod) 859 860 // Act 861 generatedVolumeName2, err := dsw.AddPodToVolume( 862 pod2Name, pod2, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */, seLinuxContainerContexts) 863 // Assert 864 if err != nil { 865 t.Fatalf("Second AddPodToVolume failed. Expected: <no error> Actual: <%v>", err) 866 } 867 if generatedVolumeName2 != generatedVolumeName { 868 t.Errorf("Expected second generatedVolumeName %s, got %s", generatedVolumeName, generatedVolumeName2) 869 } 870 871 verifyPodExistsInVolumeDsw(t, pod2Name, generatedVolumeName, "system_u:object_r:container_file_t:s0:c1,c2", dsw) 872 } 873 874 // Calls AddPodToVolume() twice to add two pods with different SELinuxContext 875 // to the same ReadWriteOncePod PV. 876 // Verifies newly added pod/volume exists via PodExistsInVolume() 877 // VolumeExists() and GetVolumesToMount() and no errors. 878 func Test_AddPodToVolume_Negative_ExistingPodDifferentSELinuxRWOP(t *testing.T) { 879 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)() 880 // Arrange 881 plugins := []volume.VolumePlugin{ 882 &volumetesting.FakeDeviceMountableVolumePlugin{ 883 FakeBasicVolumePlugin: volumetesting.FakeBasicVolumePlugin{ 884 Plugin: volumetesting.FakeVolumePlugin{ 885 PluginName: "basic", 886 SupportsSELinux: true, 887 }, 888 }, 889 }, 890 } 891 volumePluginMgr := volume.VolumePluginMgr{} 892 fakeVolumeHost := volumetesting.NewFakeVolumeHost(t, 893 "", /* rootDir */ 894 nil, /* kubeClient */ 895 nil, /* plugins */ 896 ) 897 volumePluginMgr.InitPlugins(plugins, nil /* prober */, fakeVolumeHost) 898 seLinuxTranslator := util.NewFakeSELinuxLabelTranslator() 899 dsw := NewDesiredStateOfWorld(&volumePluginMgr, seLinuxTranslator) 900 seLinux1 := v1.SELinuxOptions{ 901 User: "system_u", 902 Role: "object_r", 903 Type: "container_t", 904 Level: "s0:c1,c2", 905 } 906 pod := &v1.Pod{ 907 ObjectMeta: metav1.ObjectMeta{ 908 Name: "pod1", 909 UID: "pod1uid", 910 }, 911 Spec: v1.PodSpec{ 912 SecurityContext: &v1.PodSecurityContext{ 913 SELinuxOptions: &seLinux1, 914 }, 915 Volumes: []v1.Volume{ 916 { 917 Name: "volume-name", 918 VolumeSource: v1.VolumeSource{ 919 PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ 920 ClaimName: "myClaim", 921 }, 922 }, 923 }, 924 }, 925 }, 926 } 927 928 volumeSpec := &volume.Spec{ 929 PersistentVolume: &v1.PersistentVolume{ 930 ObjectMeta: metav1.ObjectMeta{ 931 Name: "basicPV", 932 }, 933 Spec: v1.PersistentVolumeSpec{ 934 AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOncePod}, 935 }, 936 }, 937 } 938 podName := util.GetUniquePodName(pod) 939 seLinuxContainerContexts := []*v1.SELinuxOptions{&seLinux1} 940 941 // Act 942 generatedVolumeName, err := dsw.AddPodToVolume( 943 podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */, seLinuxContainerContexts) 944 945 // Assert 946 if err != nil { 947 t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err) 948 } 949 950 verifyVolumeExistsDsw(t, generatedVolumeName, "system_u:object_r:container_file_t:s0:c1,c2", dsw) 951 verifyVolumeExistsInVolumesToMount( 952 t, generatedVolumeName, false /* expectReportedInUse */, dsw) 953 verifyPodExistsInVolumeDsw(t, podName, generatedVolumeName, "system_u:object_r:container_file_t:s0:c1,c2", dsw) 954 verifyVolumeExistsWithSpecNameInVolumeDsw(t, podName, volumeSpec.Name(), dsw) 955 956 // Arrange: prepare a different pod with the same context 957 seLinux2 := v1.SELinuxOptions{ 958 User: "system_u", 959 Role: "object_r", 960 Type: "container_t", 961 Level: "s0:c3,c4", 962 } 963 seLinuxContainerContexts2 := []*v1.SELinuxOptions{&seLinux2} 964 pod2 := pod.DeepCopy() 965 pod2.Name = "pod2" 966 pod2.UID = "pod2uid" 967 pod2.Spec.SecurityContext.SELinuxOptions = &seLinux2 968 pod2Name := util.GetUniquePodName(pod2) 969 970 // Act 971 _, err = dsw.AddPodToVolume( 972 pod2Name, pod2, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */, seLinuxContainerContexts2) 973 // Assert 974 if err == nil { 975 t.Fatalf("Second AddPodToVolume succeeded, expected a failure") 976 } 977 // Verify the original SELinux context is still in DSW 978 verifyPodExistsInVolumeDsw(t, podName, generatedVolumeName, "system_u:object_r:container_file_t:s0:c1,c2", dsw) 979 } 980 981 func verifyVolumeExistsDsw( 982 t *testing.T, expectedVolumeName v1.UniqueVolumeName, expectedSELinuxContext string, dsw DesiredStateOfWorld) { 983 volumeExists := dsw.VolumeExists(expectedVolumeName, expectedSELinuxContext) 984 if !volumeExists { 985 t.Fatalf( 986 "VolumeExists(%q) failed. Expected: <true> Actual: <%v>", 987 expectedVolumeName, 988 volumeExists) 989 } 990 } 991 992 func verifyVolumeDoesntExist( 993 t *testing.T, expectedVolumeName v1.UniqueVolumeName, expectedSELinuxContext string, dsw DesiredStateOfWorld) { 994 volumeExists := dsw.VolumeExists(expectedVolumeName, expectedSELinuxContext) 995 if volumeExists { 996 t.Fatalf( 997 "VolumeExists(%q) returned incorrect value. Expected: <false> Actual: <%v>", 998 expectedVolumeName, 999 volumeExists) 1000 } 1001 } 1002 1003 func verifyVolumeExistsInVolumesToMount( 1004 t *testing.T, 1005 expectedVolumeName v1.UniqueVolumeName, 1006 expectReportedInUse bool, 1007 dsw DesiredStateOfWorld) { 1008 volumesToMount := dsw.GetVolumesToMount() 1009 for _, volume := range volumesToMount { 1010 if volume.VolumeName == expectedVolumeName { 1011 if volume.ReportedInUse != expectReportedInUse { 1012 t.Fatalf( 1013 "Found volume %v in the list of VolumesToMount, but ReportedInUse incorrect. Expected: <%v> Actual: <%v>", 1014 expectedVolumeName, 1015 expectReportedInUse, 1016 volume.ReportedInUse) 1017 } 1018 1019 return 1020 } 1021 } 1022 1023 t.Fatalf( 1024 "Could not find volume %v in the list of desired state of world volumes to mount %+v", 1025 expectedVolumeName, 1026 volumesToMount) 1027 } 1028 1029 func verifyVolumeDoesntExistInVolumesToMount( 1030 t *testing.T, volumeToCheck v1.UniqueVolumeName, dsw DesiredStateOfWorld) { 1031 volumesToMount := dsw.GetVolumesToMount() 1032 for _, volume := range volumesToMount { 1033 if volume.VolumeName == volumeToCheck { 1034 t.Fatalf( 1035 "Found volume %v in the list of desired state of world volumes to mount. Expected it not to exist.", 1036 volumeToCheck) 1037 } 1038 } 1039 } 1040 1041 func verifyPodExistsInVolumeDsw( 1042 t *testing.T, 1043 expectedPodName volumetypes.UniquePodName, 1044 expectedVolumeName v1.UniqueVolumeName, 1045 expectedSeLinuxContext string, 1046 dsw DesiredStateOfWorld) { 1047 if podExistsInVolume := dsw.PodExistsInVolume( 1048 expectedPodName, expectedVolumeName, expectedSeLinuxContext); !podExistsInVolume { 1049 t.Fatalf( 1050 "DSW PodExistsInVolume returned incorrect value. Expected: <true> Actual: <%v>", 1051 podExistsInVolume) 1052 } 1053 } 1054 1055 func verifyPodDoesntExistInVolumeDsw( 1056 t *testing.T, 1057 expectedPodName volumetypes.UniquePodName, 1058 expectedVolumeName v1.UniqueVolumeName, 1059 expectedSeLinuxContext string, 1060 dsw DesiredStateOfWorld) { 1061 if podExistsInVolume := dsw.PodExistsInVolume( 1062 expectedPodName, expectedVolumeName, expectedSeLinuxContext); podExistsInVolume { 1063 t.Fatalf( 1064 "DSW PodExistsInVolume returned incorrect value. Expected: <true> Actual: <%v>", 1065 podExistsInVolume) 1066 } 1067 } 1068 1069 func verifyVolumeExistsWithSpecNameInVolumeDsw( 1070 t *testing.T, 1071 expectedPodName volumetypes.UniquePodName, 1072 expectedVolumeSpecName string, 1073 dsw DesiredStateOfWorld) { 1074 if podExistsInVolume := dsw.VolumeExistsWithSpecName( 1075 expectedPodName, expectedVolumeSpecName); !podExistsInVolume { 1076 t.Fatalf( 1077 "DSW VolumeExistsWithSpecNam returned incorrect value. Expected: <true> Actual: <%v>", 1078 podExistsInVolume) 1079 } 1080 } 1081 1082 func verifyVolumeDoesntExistWithSpecNameInVolumeDsw( 1083 t *testing.T, 1084 expectedPodName volumetypes.UniquePodName, 1085 expectedVolumeSpecName string, 1086 dsw DesiredStateOfWorld) { 1087 if podExistsInVolume := dsw.VolumeExistsWithSpecName( 1088 expectedPodName, expectedVolumeSpecName); podExistsInVolume { 1089 t.Fatalf( 1090 "DSW VolumeExistsWithSpecNam returned incorrect value. Expected: <true> Actual: <%v>", 1091 podExistsInVolume) 1092 } 1093 } 1094 1095 func verifyDesiredSizeLimitInVolumeDsw( 1096 t *testing.T, 1097 expectedPodName volumetypes.UniquePodName, 1098 expectedDesiredSizeMap map[string]*resource.Quantity, 1099 dsw DesiredStateOfWorld) { 1100 volumesToMount := dsw.GetVolumesToMount() 1101 for volumeName, expectedDesiredSize := range expectedDesiredSizeMap { 1102 if podExistsInVolume := dsw.VolumeExistsWithSpecName( 1103 expectedPodName, volumeName); !podExistsInVolume { 1104 t.Fatalf( 1105 "DSW VolumeExistsWithSpecName returned incorrect value. Expected: <true> Actual: <%v>", 1106 podExistsInVolume) 1107 } 1108 for _, v := range volumesToMount { 1109 if v.VolumeSpec.Name() == volumeName && v.PodName == expectedPodName { 1110 if v.DesiredSizeLimit == nil || v.DesiredSizeLimit.Value() != expectedDesiredSize.Value() { 1111 t.Fatalf( 1112 "Found volume %v in the list of VolumesToMount, but DesiredSizeLimit incorrect. Expected: <%v> Actual: <%v>", 1113 volumeName, 1114 expectedDesiredSize, 1115 v.DesiredSizeLimit) 1116 1117 } 1118 } 1119 } 1120 } 1121 }