k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/volume/util/operationexecutor/operation_executor_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 operationexecutor 18 19 import ( 20 "fmt" 21 "strconv" 22 "testing" 23 "time" 24 25 "k8s.io/klog/v2" 26 27 v1 "k8s.io/api/core/v1" 28 "k8s.io/apimachinery/pkg/api/resource" 29 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 30 "k8s.io/apimachinery/pkg/types" 31 "k8s.io/apimachinery/pkg/util/uuid" 32 csitrans "k8s.io/csi-translation-lib" 33 "k8s.io/klog/v2/ktesting" 34 "k8s.io/kubernetes/pkg/volume" 35 "k8s.io/kubernetes/pkg/volume/util/hostutil" 36 volumetypes "k8s.io/kubernetes/pkg/volume/util/types" 37 ) 38 39 const ( 40 numVolumesToMount = 2 41 numAttachableVolumesToUnmount = 2 42 numNonAttachableVolumesToUnmount = 2 43 numDevicesToUnmount = 2 44 numVolumesToAttach = 2 45 numVolumesToDetach = 2 46 numVolumesToVerifyAttached = 2 47 numVolumesToVerifyControllerAttached = 2 48 numVolumesToMap = 2 49 numAttachableVolumesToUnmap = 2 50 numNonAttachableVolumesToUnmap = 2 51 numDevicesToUnmap = 2 52 ) 53 54 var _ OperationGenerator = &fakeOperationGenerator{} 55 56 func TestOperationExecutor_MountVolume_ConcurrentMountForNonAttachableAndNonDevicemountablePlugins(t *testing.T) { 57 // Arrange 58 ch, quit, oe := setup() 59 volumesToMount := make([]VolumeToMount, numVolumesToMount) 60 secretName := "secret-volume" 61 volumeName := v1.UniqueVolumeName(secretName) 62 63 // Act 64 for i := range volumesToMount { 65 podName := "pod-" + strconv.Itoa(i+1) 66 pod := getTestPodWithSecret(podName, secretName) 67 volumesToMount[i] = VolumeToMount{ 68 Pod: pod, 69 VolumeName: volumeName, 70 PluginIsAttachable: false, // this field determines whether the plugin is attachable 71 PluginIsDeviceMountable: false, // this field determines whether the plugin is devicemountable 72 ReportedInUse: true, 73 } 74 oe.MountVolume(0 /* waitForAttachTimeOut */, volumesToMount[i], nil /* actualStateOfWorldMounterUpdater */, false /* isRemount */) 75 } 76 77 // Assert 78 if !isOperationRunConcurrently(ch, quit, numVolumesToMount) { 79 t.Fatalf("Unable to start mount operations in Concurrent for non-attachable volumes") 80 } 81 } 82 83 func TestOperationExecutor_MountVolume_ConcurrentMountForAttachablePlugins(t *testing.T) { 84 t.Parallel() 85 86 // Arrange 87 ch, quit, oe := setup() 88 volumesToMount := make([]VolumeToMount, numVolumesToAttach) 89 pdName := "pd-volume" 90 volumeName := v1.UniqueVolumeName(pdName) 91 // Act 92 for i := range volumesToMount { 93 podName := "pod-" + strconv.Itoa(i+1) 94 pod := getTestPodWithGCEPD(podName, pdName) 95 volumesToMount[i] = VolumeToMount{ 96 Pod: pod, 97 VolumeName: volumeName, 98 PluginIsAttachable: true, // this field determines whether the plugin is attachable 99 ReportedInUse: true, 100 } 101 oe.MountVolume(0 /* waitForAttachTimeout */, volumesToMount[i], nil /* actualStateOfWorldMounterUpdater */, false /* isRemount */) 102 } 103 104 // Assert 105 if !isOperationRunSerially(ch, quit) { 106 t.Fatalf("Mount operations should not start concurrently for attachable volumes") 107 } 108 } 109 110 func TestOperationExecutor_MountVolume_ConcurrentMountForDeviceMountablePlugins(t *testing.T) { 111 t.Parallel() 112 113 // Arrange 114 ch, quit, oe := setup() 115 volumesToMount := make([]VolumeToMount, numVolumesToAttach) 116 pdName := "pd-volume" 117 volumeName := v1.UniqueVolumeName(pdName) 118 // Act 119 for i := range volumesToMount { 120 podName := "pod-" + strconv.Itoa(i+1) 121 pod := getTestPodWithGCEPD(podName, pdName) 122 volumesToMount[i] = VolumeToMount{ 123 Pod: pod, 124 VolumeName: volumeName, 125 PluginIsDeviceMountable: true, // this field determines whether the plugin is devicemountable 126 ReportedInUse: true, 127 } 128 oe.MountVolume(0 /* waitForAttachTimeout */, volumesToMount[i], nil /* actualStateOfWorldMounterUpdater */, false /* isRemount */) 129 } 130 131 // Assert 132 if !isOperationRunSerially(ch, quit) { 133 t.Fatalf("Mount operations should not start concurrently for devicemountable volumes") 134 } 135 } 136 137 func TestOperationExecutor_UnmountVolume_ConcurrentUnmountForAllPlugins(t *testing.T) { 138 // Arrange 139 ch, quit, oe := setup() 140 volumesToUnmount := make([]MountedVolume, numAttachableVolumesToUnmount+numNonAttachableVolumesToUnmount) 141 pdName := "pd-volume" 142 secretName := "secret-volume" 143 144 // Act 145 for i := 0; i < numNonAttachableVolumesToUnmount+numAttachableVolumesToUnmount; i++ { 146 podName := "pod-" + strconv.Itoa(i+1) 147 if i < numNonAttachableVolumesToUnmount { 148 pod := getTestPodWithSecret(podName, secretName) 149 volumesToUnmount[i] = MountedVolume{ 150 PodName: volumetypes.UniquePodName(podName), 151 VolumeName: v1.UniqueVolumeName(secretName), 152 PodUID: pod.UID, 153 } 154 } else { 155 pod := getTestPodWithGCEPD(podName, pdName) 156 volumesToUnmount[i] = MountedVolume{ 157 PodName: volumetypes.UniquePodName(podName), 158 VolumeName: v1.UniqueVolumeName(pdName), 159 PodUID: pod.UID, 160 } 161 } 162 oe.UnmountVolume(volumesToUnmount[i], nil /* actualStateOfWorldMounterUpdater */, "" /*podsDir*/) 163 } 164 165 // Assert 166 if !isOperationRunConcurrently(ch, quit, numNonAttachableVolumesToUnmount+numAttachableVolumesToUnmount) { 167 t.Fatalf("Unable to start unmount operations concurrently for volume plugins") 168 } 169 } 170 171 func TestOperationExecutor_UnmountDeviceConcurrently(t *testing.T) { 172 t.Parallel() 173 174 // Arrange 175 ch, quit, oe := setup() 176 attachedVolumes := make([]AttachedVolume, numDevicesToUnmount) 177 pdName := "pd-volume" 178 179 // Act 180 for i := range attachedVolumes { 181 attachedVolumes[i] = AttachedVolume{ 182 VolumeName: v1.UniqueVolumeName(pdName), 183 NodeName: "node-name", 184 } 185 oe.UnmountDevice(attachedVolumes[i], nil /* actualStateOfWorldMounterUpdater */, nil /* mount.Interface */) 186 } 187 188 // Assert 189 if !isOperationRunSerially(ch, quit) { 190 t.Fatalf("Unmount device operations should not start concurrently") 191 } 192 } 193 194 func TestOperationExecutor_AttachSingleNodeVolumeConcurrentlyToSameNode(t *testing.T) { 195 t.Parallel() 196 197 // Arrange 198 ch, quit, oe := setup() 199 volumesToAttach := make([]VolumeToAttach, numVolumesToAttach) 200 pdName := "pd-volume" 201 202 // Act 203 for i := range volumesToAttach { 204 volumesToAttach[i] = VolumeToAttach{ 205 VolumeName: v1.UniqueVolumeName(pdName), 206 NodeName: "node", 207 VolumeSpec: &volume.Spec{ 208 PersistentVolume: &v1.PersistentVolume{ 209 Spec: v1.PersistentVolumeSpec{ 210 AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}, 211 }, 212 }, 213 }, 214 } 215 logger, _ := ktesting.NewTestContext(t) 216 oe.AttachVolume(logger, volumesToAttach[i], nil /* actualStateOfWorldAttacherUpdater */) 217 } 218 219 // Assert 220 if !isOperationRunSerially(ch, quit) { 221 t.Fatalf("Attach volume operations should not start concurrently") 222 } 223 } 224 225 func TestOperationExecutor_AttachMultiNodeVolumeConcurrentlyToSameNode(t *testing.T) { 226 t.Parallel() 227 228 // Arrange 229 ch, quit, oe := setup() 230 volumesToAttach := make([]VolumeToAttach, numVolumesToAttach) 231 pdName := "pd-volume" 232 233 // Act 234 for i := range volumesToAttach { 235 volumesToAttach[i] = VolumeToAttach{ 236 VolumeName: v1.UniqueVolumeName(pdName), 237 NodeName: "node", 238 VolumeSpec: &volume.Spec{ 239 PersistentVolume: &v1.PersistentVolume{ 240 Spec: v1.PersistentVolumeSpec{ 241 AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadOnlyMany}, 242 }, 243 }, 244 }, 245 } 246 logger, _ := ktesting.NewTestContext(t) 247 oe.AttachVolume(logger, volumesToAttach[i], nil /* actualStateOfWorldAttacherUpdater */) 248 } 249 250 // Assert 251 if !isOperationRunSerially(ch, quit) { 252 t.Fatalf("Attach volume operations should not start concurrently") 253 } 254 } 255 256 func TestOperationExecutor_AttachSingleNodeVolumeConcurrentlyToDifferentNodes(t *testing.T) { 257 t.Parallel() 258 259 // Arrange 260 ch, quit, oe := setup() 261 volumesToAttach := make([]VolumeToAttach, numVolumesToAttach) 262 pdName := "pd-volume" 263 264 // Act 265 for i := range volumesToAttach { 266 volumesToAttach[i] = VolumeToAttach{ 267 VolumeName: v1.UniqueVolumeName(pdName), 268 NodeName: types.NodeName(fmt.Sprintf("node%d", i)), 269 VolumeSpec: &volume.Spec{ 270 PersistentVolume: &v1.PersistentVolume{ 271 Spec: v1.PersistentVolumeSpec{ 272 AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}, 273 }, 274 }, 275 }, 276 } 277 logger, _ := ktesting.NewTestContext(t) 278 oe.AttachVolume(logger, volumesToAttach[i], nil /* actualStateOfWorldAttacherUpdater */) 279 } 280 281 // Assert 282 if !isOperationRunSerially(ch, quit) { 283 t.Fatalf("Attach volume operations should not start concurrently") 284 } 285 } 286 287 func TestOperationExecutor_AttachMultiNodeVolumeConcurrentlyToDifferentNodes(t *testing.T) { 288 // Arrange 289 ch, quit, oe := setup() 290 volumesToAttach := make([]VolumeToAttach, numVolumesToAttach) 291 pdName := "pd-volume" 292 293 // Act 294 for i := range volumesToAttach { 295 volumesToAttach[i] = VolumeToAttach{ 296 VolumeName: v1.UniqueVolumeName(pdName), 297 NodeName: types.NodeName(fmt.Sprintf("node%d", i)), 298 VolumeSpec: &volume.Spec{ 299 PersistentVolume: &v1.PersistentVolume{ 300 Spec: v1.PersistentVolumeSpec{ 301 AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadOnlyMany}, 302 }, 303 }, 304 }, 305 } 306 logger, _ := ktesting.NewTestContext(t) 307 oe.AttachVolume(logger, volumesToAttach[i], nil /* actualStateOfWorldAttacherUpdater */) 308 } 309 310 // Assert 311 if !isOperationRunConcurrently(ch, quit, numVolumesToAttach) { 312 t.Fatalf("Attach volume operations should not execute serially") 313 } 314 } 315 316 func TestOperationExecutor_DetachSingleNodeVolumeConcurrentlyFromSameNode(t *testing.T) { 317 t.Parallel() 318 319 // Arrange 320 ch, quit, oe := setup() 321 attachedVolumes := make([]AttachedVolume, numVolumesToDetach) 322 pdName := "pd-volume" 323 324 // Act 325 for i := range attachedVolumes { 326 attachedVolumes[i] = AttachedVolume{ 327 VolumeName: v1.UniqueVolumeName(pdName), 328 NodeName: "node", 329 VolumeSpec: &volume.Spec{ 330 PersistentVolume: &v1.PersistentVolume{ 331 Spec: v1.PersistentVolumeSpec{ 332 AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}, 333 }, 334 }, 335 }, 336 } 337 logger, _ := ktesting.NewTestContext(t) 338 oe.DetachVolume(logger, attachedVolumes[i], true /* verifySafeToDetach */, nil /* actualStateOfWorldAttacherUpdater */) 339 } 340 341 // Assert 342 if !isOperationRunSerially(ch, quit) { 343 t.Fatalf("DetachVolume operations should not run concurrently") 344 } 345 } 346 347 func TestOperationExecutor_DetachMultiNodeVolumeConcurrentlyFromSameNode(t *testing.T) { 348 t.Parallel() 349 350 // Arrange 351 ch, quit, oe := setup() 352 attachedVolumes := make([]AttachedVolume, numVolumesToDetach) 353 pdName := "pd-volume" 354 355 // Act 356 for i := range attachedVolumes { 357 attachedVolumes[i] = AttachedVolume{ 358 VolumeName: v1.UniqueVolumeName(pdName), 359 NodeName: "node", 360 VolumeSpec: &volume.Spec{ 361 PersistentVolume: &v1.PersistentVolume{ 362 Spec: v1.PersistentVolumeSpec{ 363 AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadOnlyMany}, 364 }, 365 }, 366 }, 367 } 368 logger, _ := ktesting.NewTestContext(t) 369 oe.DetachVolume(logger, attachedVolumes[i], true /* verifySafeToDetach */, nil /* actualStateOfWorldAttacherUpdater */) 370 } 371 372 // Assert 373 if !isOperationRunSerially(ch, quit) { 374 t.Fatalf("DetachVolume operations should not run concurrently") 375 } 376 } 377 378 func TestOperationExecutor_DetachMultiNodeVolumeConcurrentlyFromDifferentNodes(t *testing.T) { 379 // Arrange 380 ch, quit, oe := setup() 381 attachedVolumes := make([]AttachedVolume, numVolumesToDetach) 382 pdName := "pd-volume" 383 384 // Act 385 for i := range attachedVolumes { 386 attachedVolumes[i] = AttachedVolume{ 387 VolumeName: v1.UniqueVolumeName(pdName), 388 NodeName: types.NodeName(fmt.Sprintf("node%d", i)), 389 VolumeSpec: &volume.Spec{ 390 PersistentVolume: &v1.PersistentVolume{ 391 Spec: v1.PersistentVolumeSpec{ 392 AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadOnlyMany}, 393 }, 394 }, 395 }, 396 } 397 logger, _ := ktesting.NewTestContext(t) 398 oe.DetachVolume(logger, attachedVolumes[i], true /* verifySafeToDetach */, nil /* actualStateOfWorldAttacherUpdater */) 399 } 400 401 // Assert 402 if !isOperationRunConcurrently(ch, quit, numVolumesToDetach) { 403 t.Fatalf("Attach volume operations should not execute serially") 404 } 405 } 406 407 func TestOperationExecutor_VerifyVolumesAreAttachedConcurrentlyOnSameNode(t *testing.T) { 408 // Arrange 409 ch, quit, oe := setup() 410 411 // Act 412 for i := 0; i < numVolumesToVerifyAttached; i++ { 413 oe.VerifyVolumesAreAttachedPerNode(nil /* attachedVolumes */, "node-name", nil /* actualStateOfWorldAttacherUpdater */) 414 } 415 416 // Assert 417 if !isOperationRunConcurrently(ch, quit, numVolumesToVerifyAttached) { 418 t.Fatalf("VerifyVolumesAreAttached operation is not being run concurrently") 419 } 420 } 421 422 func TestOperationExecutor_VerifyVolumesAreAttachedConcurrentlyOnDifferentNodes(t *testing.T) { 423 // Arrange 424 ch, quit, oe := setup() 425 426 // Act 427 for i := 0; i < numVolumesToVerifyAttached; i++ { 428 oe.VerifyVolumesAreAttachedPerNode( 429 nil, /* attachedVolumes */ 430 types.NodeName(fmt.Sprintf("node-name-%d", i)), 431 nil /* actualStateOfWorldAttacherUpdater */) 432 } 433 434 // Assert 435 if !isOperationRunConcurrently(ch, quit, numVolumesToVerifyAttached) { 436 t.Fatalf("VerifyVolumesAreAttached operation is not being run concurrently") 437 } 438 } 439 440 func TestOperationExecutor_VerifyControllerAttachedVolumeConcurrently(t *testing.T) { 441 t.Parallel() 442 443 // Arrange 444 ch, quit, oe := setup() 445 volumesToMount := make([]VolumeToMount, numVolumesToVerifyControllerAttached) 446 pdName := "pd-volume" 447 448 // Act 449 for i := range volumesToMount { 450 volumesToMount[i] = VolumeToMount{ 451 VolumeName: v1.UniqueVolumeName(pdName), 452 } 453 logger, _ := ktesting.NewTestContext(t) 454 oe.VerifyControllerAttachedVolume(logger, volumesToMount[i], types.NodeName("node-name"), nil /* actualStateOfWorldMounterUpdater */) 455 } 456 457 // Assert 458 if !isOperationRunSerially(ch, quit) { 459 t.Fatalf("VerifyControllerAttachedVolume should not run concurrently") 460 } 461 } 462 463 func TestOperationExecutor_MountVolume_ConcurrentMountForNonAttachablePlugins_VolumeMode_Block(t *testing.T) { 464 // Arrange 465 ch, quit, oe := setup() 466 volumesToMount := make([]VolumeToMount, numVolumesToMap) 467 secretName := "secret-volume" 468 volumeName := v1.UniqueVolumeName(secretName) 469 volumeMode := v1.PersistentVolumeBlock 470 tmpSpec := &volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{VolumeMode: &volumeMode}}} 471 472 // Act 473 for i := range volumesToMount { 474 podName := "pod-" + strconv.Itoa(i+1) 475 pod := getTestPodWithSecret(podName, secretName) 476 volumesToMount[i] = VolumeToMount{ 477 Pod: pod, 478 VolumeName: volumeName, 479 PluginIsAttachable: false, // this field determines whether the plugin is attachable 480 ReportedInUse: true, 481 VolumeSpec: tmpSpec, 482 } 483 oe.MountVolume(0 /* waitForAttachTimeOut */, volumesToMount[i], nil /* actualStateOfWorldMounterUpdater */, false) 484 } 485 486 // Assert 487 if !isOperationRunConcurrently(ch, quit, numVolumesToMap) { 488 t.Fatalf("Unable to start map operations in Concurrent for non-attachable volumes") 489 } 490 } 491 492 func TestOperationExecutor_MountVolume_ConcurrentMountForAttachablePlugins_VolumeMode_Block(t *testing.T) { 493 t.Parallel() 494 495 // Arrange 496 ch, quit, oe := setup() 497 volumesToMount := make([]VolumeToMount, numVolumesToAttach) 498 pdName := "pd-volume" 499 volumeName := v1.UniqueVolumeName(pdName) 500 volumeMode := v1.PersistentVolumeBlock 501 tmpSpec := &volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{VolumeMode: &volumeMode}}} 502 503 // Act 504 for i := range volumesToMount { 505 podName := "pod-" + strconv.Itoa(i+1) 506 pod := getTestPodWithGCEPD(podName, pdName) 507 volumesToMount[i] = VolumeToMount{ 508 Pod: pod, 509 VolumeName: volumeName, 510 PluginIsAttachable: true, // this field determines whether the plugin is attachable 511 ReportedInUse: true, 512 VolumeSpec: tmpSpec, 513 } 514 oe.MountVolume(0 /* waitForAttachTimeout */, volumesToMount[i], nil /* actualStateOfWorldMounterUpdater */, false) 515 } 516 517 // Assert 518 if !isOperationRunSerially(ch, quit) { 519 t.Fatalf("Map operations should not start concurrently for attachable volumes") 520 } 521 } 522 523 func TestOperationExecutor_UnmountVolume_ConcurrentUnmountForAllPlugins_VolumeMode_Block(t *testing.T) { 524 // Arrange 525 ch, quit, oe := setup() 526 volumesToUnmount := make([]MountedVolume, numAttachableVolumesToUnmap+numNonAttachableVolumesToUnmap) 527 pdName := "pd-volume" 528 secretName := "secret-volume" 529 volumeMode := v1.PersistentVolumeBlock 530 tmpSpec := &volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{VolumeMode: &volumeMode}}} 531 532 // Act 533 for i := 0; i < numNonAttachableVolumesToUnmap+numAttachableVolumesToUnmap; i++ { 534 podName := "pod-" + strconv.Itoa(i+1) 535 if i < numNonAttachableVolumesToUnmap { 536 pod := getTestPodWithSecret(podName, secretName) 537 volumesToUnmount[i] = MountedVolume{ 538 PodName: volumetypes.UniquePodName(podName), 539 VolumeName: v1.UniqueVolumeName(secretName), 540 PodUID: pod.UID, 541 VolumeSpec: tmpSpec, 542 } 543 } else { 544 pod := getTestPodWithGCEPD(podName, pdName) 545 volumesToUnmount[i] = MountedVolume{ 546 PodName: volumetypes.UniquePodName(podName), 547 VolumeName: v1.UniqueVolumeName(pdName), 548 PodUID: pod.UID, 549 VolumeSpec: tmpSpec, 550 } 551 } 552 oe.UnmountVolume(volumesToUnmount[i], nil /* actualStateOfWorldMounterUpdater */, "" /* podsDir */) 553 } 554 555 // Assert 556 if !isOperationRunConcurrently(ch, quit, numNonAttachableVolumesToUnmap+numAttachableVolumesToUnmap) { 557 t.Fatalf("Unable to start unmap operations concurrently for volume plugins") 558 } 559 } 560 561 func TestOperationExecutor_UnmountDeviceConcurrently_VolumeMode_Block(t *testing.T) { 562 t.Parallel() 563 564 // Arrange 565 ch, quit, oe := setup() 566 attachedVolumes := make([]AttachedVolume, numDevicesToUnmap) 567 pdName := "pd-volume" 568 volumeMode := v1.PersistentVolumeBlock 569 tmpSpec := &volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{VolumeMode: &volumeMode}}} 570 571 // Act 572 for i := range attachedVolumes { 573 attachedVolumes[i] = AttachedVolume{ 574 VolumeName: v1.UniqueVolumeName(pdName), 575 NodeName: "node-name", 576 VolumeSpec: tmpSpec, 577 } 578 oe.UnmountDevice(attachedVolumes[i], nil /* actualStateOfWorldMounterUpdater */, nil /* mount.Interface */) 579 } 580 581 // Assert 582 if !isOperationRunSerially(ch, quit) { 583 t.Fatalf("Unmap device operations should not start concurrently") 584 } 585 } 586 587 type fakeOperationGenerator struct { 588 ch chan interface{} 589 quit chan interface{} 590 } 591 592 func newFakeOperationGenerator(ch chan interface{}, quit chan interface{}) OperationGenerator { 593 return &fakeOperationGenerator{ 594 ch: ch, 595 quit: quit, 596 } 597 } 598 599 func (fopg *fakeOperationGenerator) GenerateMountVolumeFunc(waitForAttachTimeout time.Duration, volumeToMount VolumeToMount, actualStateOfWorldMounterUpdater ActualStateOfWorldMounterUpdater, isRemount bool) volumetypes.GeneratedOperations { 600 opFunc := func() volumetypes.OperationContext { 601 startOperationAndBlock(fopg.ch, fopg.quit) 602 return volumetypes.NewOperationContext(nil, nil, false) 603 } 604 return volumetypes.GeneratedOperations{ 605 OperationFunc: opFunc, 606 } 607 } 608 func (fopg *fakeOperationGenerator) GenerateUnmountVolumeFunc(volumeToUnmount MountedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater, podsDir string) (volumetypes.GeneratedOperations, error) { 609 opFunc := func() volumetypes.OperationContext { 610 startOperationAndBlock(fopg.ch, fopg.quit) 611 return volumetypes.NewOperationContext(nil, nil, false) 612 } 613 return volumetypes.GeneratedOperations{ 614 OperationFunc: opFunc, 615 }, nil 616 } 617 func (fopg *fakeOperationGenerator) GenerateAttachVolumeFunc(logger klog.Logger, volumeToAttach VolumeToAttach, actualStateOfWorld ActualStateOfWorldAttacherUpdater) volumetypes.GeneratedOperations { 618 opFunc := func() volumetypes.OperationContext { 619 startOperationAndBlock(fopg.ch, fopg.quit) 620 return volumetypes.NewOperationContext(nil, nil, false) 621 } 622 return volumetypes.GeneratedOperations{ 623 OperationFunc: opFunc, 624 } 625 } 626 func (fopg *fakeOperationGenerator) GenerateDetachVolumeFunc(logger klog.Logger, volumeToDetach AttachedVolume, verifySafeToDetach bool, actualStateOfWorld ActualStateOfWorldAttacherUpdater) (volumetypes.GeneratedOperations, error) { 627 opFunc := func() volumetypes.OperationContext { 628 startOperationAndBlock(fopg.ch, fopg.quit) 629 return volumetypes.NewOperationContext(nil, nil, false) 630 } 631 return volumetypes.GeneratedOperations{ 632 OperationFunc: opFunc, 633 }, nil 634 } 635 func (fopg *fakeOperationGenerator) GenerateVolumesAreAttachedFunc(attachedVolumes []AttachedVolume, nodeName types.NodeName, actualStateOfWorld ActualStateOfWorldAttacherUpdater) (volumetypes.GeneratedOperations, error) { 636 opFunc := func() volumetypes.OperationContext { 637 startOperationAndBlock(fopg.ch, fopg.quit) 638 return volumetypes.NewOperationContext(nil, nil, false) 639 } 640 return volumetypes.GeneratedOperations{ 641 OperationFunc: opFunc, 642 }, nil 643 } 644 func (fopg *fakeOperationGenerator) GenerateUnmountDeviceFunc(deviceToDetach AttachedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater, hostutil hostutil.HostUtils) (volumetypes.GeneratedOperations, error) { 645 opFunc := func() volumetypes.OperationContext { 646 startOperationAndBlock(fopg.ch, fopg.quit) 647 return volumetypes.NewOperationContext(nil, nil, false) 648 } 649 return volumetypes.GeneratedOperations{ 650 OperationFunc: opFunc, 651 }, nil 652 } 653 func (fopg *fakeOperationGenerator) GenerateVerifyControllerAttachedVolumeFunc(logger klog.Logger, volumeToMount VolumeToMount, nodeName types.NodeName, actualStateOfWorld ActualStateOfWorldAttacherUpdater) (volumetypes.GeneratedOperations, error) { 654 opFunc := func() volumetypes.OperationContext { 655 startOperationAndBlock(fopg.ch, fopg.quit) 656 return volumetypes.NewOperationContext(nil, nil, false) 657 } 658 return volumetypes.GeneratedOperations{ 659 OperationFunc: opFunc, 660 }, nil 661 } 662 663 func (fopg *fakeOperationGenerator) GenerateExpandVolumeFunc(pvc *v1.PersistentVolumeClaim, pv *v1.PersistentVolume) (volumetypes.GeneratedOperations, error) { 664 opFunc := func() volumetypes.OperationContext { 665 startOperationAndBlock(fopg.ch, fopg.quit) 666 return volumetypes.NewOperationContext(nil, nil, false) 667 } 668 return volumetypes.GeneratedOperations{ 669 OperationFunc: opFunc, 670 }, nil 671 } 672 673 func (fopg *fakeOperationGenerator) GenerateExpandAndRecoverVolumeFunc(pvc *v1.PersistentVolumeClaim, pv *v1.PersistentVolume, resizerName string) (volumetypes.GeneratedOperations, error) { 674 opFunc := func() volumetypes.OperationContext { 675 startOperationAndBlock(fopg.ch, fopg.quit) 676 return volumetypes.NewOperationContext(nil, nil, false) 677 } 678 return volumetypes.GeneratedOperations{ 679 OperationFunc: opFunc, 680 }, nil 681 } 682 683 func (fopg *fakeOperationGenerator) GenerateExpandInUseVolumeFunc(volumeToMount VolumeToMount, actualStateOfWorld ActualStateOfWorldMounterUpdater, currentSize resource.Quantity) (volumetypes.GeneratedOperations, error) { 684 opFunc := func() volumetypes.OperationContext { 685 startOperationAndBlock(fopg.ch, fopg.quit) 686 return volumetypes.NewOperationContext(nil, nil, false) 687 } 688 return volumetypes.GeneratedOperations{ 689 OperationFunc: opFunc, 690 }, nil 691 } 692 693 func (fopg *fakeOperationGenerator) GenerateMapVolumeFunc(waitForAttachTimeout time.Duration, volumeToMount VolumeToMount, actualStateOfWorldMounterUpdater ActualStateOfWorldMounterUpdater) (volumetypes.GeneratedOperations, error) { 694 opFunc := func() volumetypes.OperationContext { 695 startOperationAndBlock(fopg.ch, fopg.quit) 696 return volumetypes.NewOperationContext(nil, nil, false) 697 } 698 return volumetypes.GeneratedOperations{ 699 OperationFunc: opFunc, 700 }, nil 701 } 702 703 func (fopg *fakeOperationGenerator) GenerateUnmapVolumeFunc(volumeToUnmount MountedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater) (volumetypes.GeneratedOperations, error) { 704 opFunc := func() volumetypes.OperationContext { 705 startOperationAndBlock(fopg.ch, fopg.quit) 706 return volumetypes.NewOperationContext(nil, nil, false) 707 } 708 return volumetypes.GeneratedOperations{ 709 OperationFunc: opFunc, 710 }, nil 711 } 712 713 func (fopg *fakeOperationGenerator) GenerateUnmapDeviceFunc(deviceToDetach AttachedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater, hostutil hostutil.HostUtils) (volumetypes.GeneratedOperations, error) { 714 opFunc := func() volumetypes.OperationContext { 715 startOperationAndBlock(fopg.ch, fopg.quit) 716 return volumetypes.NewOperationContext(nil, nil, false) 717 } 718 return volumetypes.GeneratedOperations{ 719 OperationFunc: opFunc, 720 }, nil 721 } 722 723 func (fopg *fakeOperationGenerator) GetVolumePluginMgr() *volume.VolumePluginMgr { 724 return nil 725 } 726 727 func (fopg *fakeOperationGenerator) GetCSITranslator() InTreeToCSITranslator { 728 return csitrans.New() 729 } 730 731 func getTestPodWithSecret(podName, secretName string) *v1.Pod { 732 return &v1.Pod{ 733 ObjectMeta: metav1.ObjectMeta{ 734 Name: podName, 735 UID: types.UID(podName), 736 }, 737 Spec: v1.PodSpec{ 738 Volumes: []v1.Volume{ 739 { 740 Name: secretName, 741 VolumeSource: v1.VolumeSource{ 742 Secret: &v1.SecretVolumeSource{ 743 SecretName: secretName, 744 }, 745 }, 746 }, 747 }, 748 Containers: []v1.Container{ 749 { 750 Name: "secret-volume-test", 751 Image: "registry.k8s.io/mounttest:0.8", 752 Args: []string{ 753 "--file_content=/etc/secret-volume/data-1", 754 "--file_mode=/etc/secret-volume/data-1"}, 755 VolumeMounts: []v1.VolumeMount{ 756 { 757 Name: secretName, 758 MountPath: "/data", 759 }, 760 }, 761 }, 762 }, 763 RestartPolicy: v1.RestartPolicyNever, 764 }, 765 } 766 } 767 768 func getTestPodWithGCEPD(podName, pdName string) *v1.Pod { 769 return &v1.Pod{ 770 ObjectMeta: metav1.ObjectMeta{ 771 Name: podName, 772 UID: types.UID(podName + string(uuid.NewUUID())), 773 }, 774 Spec: v1.PodSpec{ 775 Volumes: []v1.Volume{ 776 { 777 Name: pdName, 778 VolumeSource: v1.VolumeSource{ 779 GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{ 780 PDName: pdName, 781 FSType: "ext4", 782 ReadOnly: false, 783 }, 784 }, 785 }, 786 }, 787 Containers: []v1.Container{ 788 { 789 Name: "pd-volume-test", 790 Image: "registry.k8s.io/mounttest:0.8", 791 Args: []string{ 792 "--file_content=/etc/pd-volume/data-1", 793 }, 794 VolumeMounts: []v1.VolumeMount{ 795 { 796 Name: pdName, 797 MountPath: "/data", 798 }, 799 }, 800 }, 801 }, 802 RestartPolicy: v1.RestartPolicyNever, 803 }, 804 } 805 } 806 807 func isOperationRunSerially(ch <-chan interface{}, quit chan<- interface{}) bool { 808 defer close(quit) 809 numOperationsStarted := 0 810 loop: 811 for { 812 select { 813 case <-ch: 814 numOperationsStarted++ 815 if numOperationsStarted > 1 { 816 return false 817 } 818 case <-time.After(5 * time.Second): 819 break loop 820 } 821 } 822 return true 823 } 824 825 func isOperationRunConcurrently(ch <-chan interface{}, quit chan<- interface{}, numOperationsToRun int) bool { 826 defer close(quit) 827 numOperationsStarted := 0 828 loop: 829 for { 830 select { 831 case <-ch: 832 numOperationsStarted++ 833 if numOperationsStarted == numOperationsToRun { 834 return true 835 } 836 case <-time.After(5 * time.Second): 837 break loop 838 } 839 } 840 return false 841 } 842 843 func setup() (chan interface{}, chan interface{}, OperationExecutor) { 844 ch, quit := make(chan interface{}), make(chan interface{}) 845 return ch, quit, NewOperationExecutor(newFakeOperationGenerator(ch, quit)) 846 } 847 848 // This function starts by writing to ch and blocks on the quit channel 849 // until it is closed by the currently running test 850 func startOperationAndBlock(ch chan<- interface{}, quit <-chan interface{}) { 851 ch <- nil 852 <-quit 853 }