k8s.io/kubernetes@v1.29.3/pkg/kubelet/volumemanager/cache/actual_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 "fmt" 21 "testing" 22 23 "k8s.io/apimachinery/pkg/api/resource" 24 "k8s.io/apimachinery/pkg/types" 25 utilfeature "k8s.io/apiserver/pkg/util/feature" 26 featuregatetesting "k8s.io/component-base/featuregate/testing" 27 28 "github.com/stretchr/testify/require" 29 v1 "k8s.io/api/core/v1" 30 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 31 "k8s.io/klog/v2/ktesting" 32 "k8s.io/kubernetes/pkg/features" 33 "k8s.io/kubernetes/pkg/volume" 34 volumetesting "k8s.io/kubernetes/pkg/volume/testing" 35 "k8s.io/kubernetes/pkg/volume/util" 36 "k8s.io/kubernetes/pkg/volume/util/operationexecutor" 37 volumetypes "k8s.io/kubernetes/pkg/volume/util/types" 38 ) 39 40 var emptyVolumeName = v1.UniqueVolumeName("") 41 42 // Calls MarkVolumeAsAttached() once to add volume 43 // Verifies newly added volume exists in GetUnmountedVolumes() 44 // Verifies newly added volume doesn't exist in GetGloballyMountedVolumes() 45 func Test_MarkVolumeAsAttached_Positive_NewVolume(t *testing.T) { 46 // Arrange 47 volumePluginMgr, plugin := volumetesting.GetTestKubeletVolumePluginMgr(t) 48 asw := NewActualStateOfWorld("mynode" /* nodeName */, volumePluginMgr) 49 pod := &v1.Pod{ 50 ObjectMeta: metav1.ObjectMeta{ 51 Name: "pod1", 52 UID: "pod1uid", 53 }, 54 Spec: v1.PodSpec{ 55 Volumes: []v1.Volume{ 56 { 57 Name: "volume-name", 58 VolumeSource: v1.VolumeSource{ 59 GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{ 60 PDName: "fake-device1", 61 }, 62 }, 63 }, 64 }, 65 }, 66 } 67 volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]} 68 devicePath := "fake/device/path" 69 generatedVolumeName, err := util.GetUniqueVolumeNameFromSpec(plugin, volumeSpec) 70 if err != nil { 71 t.Fatalf("GetUniqueVolumeNameFromSpec failed. Expected: <no error> Actual: <%v>", err) 72 } 73 74 // Act 75 logger, _ := ktesting.NewTestContext(t) 76 err = asw.MarkVolumeAsAttached(logger, emptyVolumeName, volumeSpec, "" /* nodeName */, devicePath) 77 78 // Assert 79 if err != nil { 80 t.Fatalf("MarkVolumeAsAttached failed. Expected: <no error> Actual: <%v>", err) 81 } 82 83 verifyVolumeExistsAsw(t, generatedVolumeName, true /* shouldExist */, asw) 84 verifyVolumeExistsInUnmountedVolumes(t, generatedVolumeName, asw) 85 verifyVolumeDoesntExistInGloballyMountedVolumes(t, generatedVolumeName, asw) 86 } 87 88 // Calls MarkVolumeAsAttached() once to add volume, specifying a name -- 89 // establishes that the supplied volume name is used to register the volume 90 // rather than the generated one. 91 // Verifies newly added volume exists in GetUnmountedVolumes() 92 // Verifies newly added volume doesn't exist in GetGloballyMountedVolumes() 93 func Test_MarkVolumeAsAttached_SuppliedVolumeName_Positive_NewVolume(t *testing.T) { 94 // Arrange 95 volumePluginMgr, _ := volumetesting.GetTestKubeletVolumePluginMgr(t) 96 asw := NewActualStateOfWorld("mynode" /* nodeName */, volumePluginMgr) 97 pod := &v1.Pod{ 98 ObjectMeta: metav1.ObjectMeta{ 99 Name: "pod1", 100 UID: "pod1uid", 101 }, 102 Spec: v1.PodSpec{ 103 Volumes: []v1.Volume{ 104 { 105 Name: "volume-name", 106 VolumeSource: v1.VolumeSource{ 107 GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{ 108 PDName: "fake-device1", 109 }, 110 }, 111 }, 112 }, 113 }, 114 } 115 volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]} 116 devicePath := "fake/device/path" 117 volumeName := v1.UniqueVolumeName("this-would-never-be-a-volume-name") 118 119 // Act 120 logger, _ := ktesting.NewTestContext(t) 121 err := asw.MarkVolumeAsAttached(logger, volumeName, volumeSpec, "" /* nodeName */, devicePath) 122 123 // Assert 124 if err != nil { 125 t.Fatalf("MarkVolumeAsAttached failed. Expected: <no error> Actual: <%v>", err) 126 } 127 128 verifyVolumeExistsAsw(t, volumeName, true /* shouldExist */, asw) 129 verifyVolumeExistsInUnmountedVolumes(t, volumeName, asw) 130 verifyVolumeDoesntExistInGloballyMountedVolumes(t, volumeName, asw) 131 } 132 133 // Calls MarkVolumeAsAttached() twice to add the same volume 134 // Verifies second call doesn't fail 135 // Verifies newly added volume exists in GetUnmountedVolumes() 136 // Verifies newly added volume doesn't exist in GetGloballyMountedVolumes() 137 func Test_MarkVolumeAsAttached_Positive_ExistingVolume(t *testing.T) { 138 // Arrange 139 volumePluginMgr, plugin := volumetesting.GetTestKubeletVolumePluginMgr(t) 140 devicePath := "fake/device/path" 141 asw := NewActualStateOfWorld("mynode" /* nodeName */, volumePluginMgr) 142 pod := &v1.Pod{ 143 ObjectMeta: metav1.ObjectMeta{ 144 Name: "pod1", 145 UID: "pod1uid", 146 }, 147 Spec: v1.PodSpec{ 148 Volumes: []v1.Volume{ 149 { 150 Name: "volume-name", 151 VolumeSource: v1.VolumeSource{ 152 GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{ 153 PDName: "fake-device1", 154 }, 155 }, 156 }, 157 }, 158 }, 159 } 160 volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]} 161 generatedVolumeName, err := util.GetUniqueVolumeNameFromSpec(plugin, volumeSpec) 162 if err != nil { 163 t.Fatalf("GetUniqueVolumeNameFromSpec failed. Expected: <no error> Actual: <%v>", err) 164 } 165 logger, _ := ktesting.NewTestContext(t) 166 err = asw.MarkVolumeAsAttached(logger, emptyVolumeName, volumeSpec, "" /* nodeName */, devicePath) 167 if err != nil { 168 t.Fatalf("MarkVolumeAsAttached failed. Expected: <no error> Actual: <%v>", err) 169 } 170 171 // Act 172 err = asw.MarkVolumeAsAttached(logger, emptyVolumeName, volumeSpec, "" /* nodeName */, devicePath) 173 174 // Assert 175 if err != nil { 176 t.Fatalf("MarkVolumeAsAttached failed. Expected: <no error> Actual: <%v>", err) 177 } 178 179 verifyVolumeExistsAsw(t, generatedVolumeName, true /* shouldExist */, asw) 180 verifyVolumeExistsInUnmountedVolumes(t, generatedVolumeName, asw) 181 verifyVolumeDoesntExistInGloballyMountedVolumes(t, generatedVolumeName, asw) 182 } 183 184 // Populates data struct with a volume 185 // Calls AddPodToVolume() to add a pod to the volume 186 // Verifies volume/pod combo exist using PodExistsInVolume() 187 func Test_AddPodToVolume_Positive_ExistingVolumeNewNode(t *testing.T) { 188 // Arrange 189 volumePluginMgr, plugin := volumetesting.GetTestKubeletVolumePluginMgr(t) 190 asw := NewActualStateOfWorld("mynode" /* nodeName */, volumePluginMgr) 191 devicePath := "fake/device/path" 192 193 pod := &v1.Pod{ 194 ObjectMeta: metav1.ObjectMeta{ 195 Name: "pod1", 196 UID: "pod1uid", 197 }, 198 Spec: v1.PodSpec{ 199 Volumes: []v1.Volume{ 200 { 201 Name: "volume-name", 202 VolumeSource: v1.VolumeSource{ 203 GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{ 204 PDName: "fake-device1", 205 }, 206 }, 207 }, 208 }, 209 }, 210 } 211 volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]} 212 generatedVolumeName, err := util.GetUniqueVolumeNameFromSpec(plugin, volumeSpec) 213 if err != nil { 214 t.Fatalf("GetUniqueVolumeNameFromSpec failed. Expected: <no error> Actual: <%v>", err) 215 } 216 logger, _ := ktesting.NewTestContext(t) 217 err = asw.MarkVolumeAsAttached(logger, emptyVolumeName, volumeSpec, "" /* nodeName */, devicePath) 218 if err != nil { 219 t.Fatalf("MarkVolumeAsAttached failed. Expected: <no error> Actual: <%v>", err) 220 } 221 podName := util.GetUniquePodName(pod) 222 223 mounter, err := plugin.NewMounter(volumeSpec, pod, volume.VolumeOptions{}) 224 if err != nil { 225 t.Fatalf("NewMounter failed. Expected: <no error> Actual: <%v>", err) 226 } 227 228 mapper, err := plugin.NewBlockVolumeMapper(volumeSpec, pod, volume.VolumeOptions{}) 229 if err != nil { 230 t.Fatalf("NewBlockVolumeMapper failed. Expected: <no error> Actual: <%v>", err) 231 } 232 233 // Act 234 markVolumeOpts := operationexecutor.MarkVolumeOpts{ 235 PodName: podName, 236 PodUID: pod.UID, 237 VolumeName: generatedVolumeName, 238 Mounter: mounter, 239 BlockVolumeMapper: mapper, 240 OuterVolumeSpecName: volumeSpec.Name(), 241 VolumeSpec: volumeSpec, 242 } 243 err = asw.AddPodToVolume(markVolumeOpts) 244 // Assert 245 if err != nil { 246 t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err) 247 } 248 249 verifyVolumeExistsAsw(t, generatedVolumeName, true /* shouldExist */, asw) 250 verifyVolumeDoesntExistInUnmountedVolumes(t, generatedVolumeName, asw) 251 verifyVolumeDoesntExistInGloballyMountedVolumes(t, generatedVolumeName, asw) 252 verifyPodExistsInVolumeAsw(t, podName, generatedVolumeName, "fake/device/path" /* expectedDevicePath */, asw) 253 verifyVolumeExistsWithSpecNameInVolumeAsw(t, podName, volumeSpec.Name(), asw) 254 verifyVolumeMountedElsewhere(t, podName, generatedVolumeName, false /*expectedMountedElsewhere */, asw) 255 } 256 257 // Populates data struct with a volume 258 // Calls AddPodToVolume() twice to add the same pod to the volume 259 // Verifies volume/pod combo exist using PodExistsInVolume() and the second call 260 // did not fail. 261 func Test_AddPodToVolume_Positive_ExistingVolumeExistingNode(t *testing.T) { 262 // Arrange 263 volumePluginMgr, plugin := volumetesting.GetTestKubeletVolumePluginMgr(t) 264 asw := NewActualStateOfWorld("mynode" /* nodeName */, volumePluginMgr) 265 devicePath := "fake/device/path" 266 267 pod := &v1.Pod{ 268 ObjectMeta: metav1.ObjectMeta{ 269 Name: "pod1", 270 UID: "pod1uid", 271 }, 272 Spec: v1.PodSpec{ 273 Volumes: []v1.Volume{ 274 { 275 Name: "volume-name", 276 VolumeSource: v1.VolumeSource{ 277 GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{ 278 PDName: "fake-device1", 279 }, 280 }, 281 }, 282 }, 283 }, 284 } 285 286 volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]} 287 generatedVolumeName, err := util.GetUniqueVolumeNameFromSpec( 288 plugin, volumeSpec) 289 if err != nil { 290 t.Fatalf("GetUniqueVolumeNameFromSpec failed. Expected: <no error> Actual: <%v>", err) 291 } 292 logger, _ := ktesting.NewTestContext(t) 293 err = asw.MarkVolumeAsAttached(logger, emptyVolumeName, volumeSpec, "" /* nodeName */, devicePath) 294 if err != nil { 295 t.Fatalf("MarkVolumeAsAttached failed. Expected: <no error> Actual: <%v>", err) 296 } 297 podName := util.GetUniquePodName(pod) 298 299 mounter, err := plugin.NewMounter(volumeSpec, pod, volume.VolumeOptions{}) 300 if err != nil { 301 t.Fatalf("NewMounter failed. Expected: <no error> Actual: <%v>", err) 302 } 303 304 mapper, err := plugin.NewBlockVolumeMapper(volumeSpec, pod, volume.VolumeOptions{}) 305 if err != nil { 306 t.Fatalf("NewBlockVolumeMapper failed. Expected: <no error> Actual: <%v>", err) 307 } 308 309 markVolumeOpts := operationexecutor.MarkVolumeOpts{ 310 PodName: podName, 311 PodUID: pod.UID, 312 VolumeName: generatedVolumeName, 313 Mounter: mounter, 314 BlockVolumeMapper: mapper, 315 OuterVolumeSpecName: volumeSpec.Name(), 316 VolumeSpec: volumeSpec, 317 } 318 err = asw.AddPodToVolume(markVolumeOpts) 319 if err != nil { 320 t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err) 321 } 322 323 // Act 324 err = asw.AddPodToVolume(markVolumeOpts) 325 // Assert 326 if err != nil { 327 t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err) 328 } 329 330 verifyVolumeExistsAsw(t, generatedVolumeName, true /* shouldExist */, asw) 331 verifyVolumeDoesntExistInUnmountedVolumes(t, generatedVolumeName, asw) 332 verifyVolumeDoesntExistInGloballyMountedVolumes(t, generatedVolumeName, asw) 333 verifyPodExistsInVolumeAsw(t, podName, generatedVolumeName, "fake/device/path" /* expectedDevicePath */, asw) 334 verifyVolumeExistsWithSpecNameInVolumeAsw(t, podName, volumeSpec.Name(), asw) 335 verifyVolumeMountedElsewhere(t, podName, generatedVolumeName, false /*expectedMountedElsewhere */, asw) 336 } 337 338 // Populates data struct with a volume 339 // Calls AddPodToVolume() twice to add the same pod to the volume 340 // Verifies volume/pod combo exist using PodExistsInVolume() and the second call 341 // did not fail. 342 func Test_AddTwoPodsToVolume_Positive(t *testing.T) { 343 // Arrange 344 volumePluginMgr, plugin := volumetesting.GetTestKubeletVolumePluginMgr(t) 345 asw := NewActualStateOfWorld("mynode" /* nodeName */, volumePluginMgr) 346 devicePath := "fake/device/path" 347 348 pod1 := &v1.Pod{ 349 ObjectMeta: metav1.ObjectMeta{ 350 Name: "pod1", 351 UID: "pod1uid", 352 }, 353 Spec: v1.PodSpec{ 354 Volumes: []v1.Volume{ 355 { 356 Name: "volume-name-1", 357 VolumeSource: v1.VolumeSource{ 358 GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{ 359 PDName: "fake-device1", 360 }, 361 }, 362 }, 363 }, 364 }, 365 } 366 367 pod2 := &v1.Pod{ 368 ObjectMeta: metav1.ObjectMeta{ 369 Name: "pod2", 370 UID: "pod2uid", 371 }, 372 Spec: v1.PodSpec{ 373 Volumes: []v1.Volume{ 374 { 375 Name: "volume-name-2", 376 VolumeSource: v1.VolumeSource{ 377 GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{ 378 PDName: "fake-device1", 379 }, 380 }, 381 }, 382 }, 383 }, 384 } 385 volumeSpec1 := &volume.Spec{Volume: &pod1.Spec.Volumes[0]} 386 volumeSpec2 := &volume.Spec{Volume: &pod2.Spec.Volumes[0]} 387 generatedVolumeName1, err := util.GetUniqueVolumeNameFromSpec( 388 plugin, volumeSpec1) 389 require.NoError(t, err) 390 generatedVolumeName2, err := util.GetUniqueVolumeNameFromSpec( 391 plugin, volumeSpec2) 392 require.NoError(t, err) 393 394 if generatedVolumeName1 != generatedVolumeName2 { 395 t.Fatalf( 396 "Unique volume names should be the same. unique volume name 1: <%q> unique volume name 2: <%q>, spec1 %v, spec2 %v", 397 generatedVolumeName1, 398 generatedVolumeName2, volumeSpec1, volumeSpec2) 399 } 400 logger, _ := ktesting.NewTestContext(t) 401 err = asw.MarkVolumeAsAttached(logger, generatedVolumeName1, volumeSpec1, "" /* nodeName */, devicePath) 402 if err != nil { 403 t.Fatalf("MarkVolumeAsAttached failed. Expected: <no error> Actual: <%v>", err) 404 } 405 podName1 := util.GetUniquePodName(pod1) 406 407 mounter1, err := plugin.NewMounter(volumeSpec1, pod1, volume.VolumeOptions{}) 408 if err != nil { 409 t.Fatalf("NewMounter failed. Expected: <no error> Actual: <%v>", err) 410 } 411 412 mapper1, err := plugin.NewBlockVolumeMapper(volumeSpec1, pod1, volume.VolumeOptions{}) 413 if err != nil { 414 t.Fatalf("NewBlockVolumeMapper failed. Expected: <no error> Actual: <%v>", err) 415 } 416 417 markVolumeOpts1 := operationexecutor.MarkVolumeOpts{ 418 PodName: podName1, 419 PodUID: pod1.UID, 420 VolumeName: generatedVolumeName1, 421 Mounter: mounter1, 422 BlockVolumeMapper: mapper1, 423 OuterVolumeSpecName: volumeSpec1.Name(), 424 VolumeSpec: volumeSpec1, 425 } 426 err = asw.AddPodToVolume(markVolumeOpts1) 427 if err != nil { 428 t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err) 429 } 430 431 podName2 := util.GetUniquePodName(pod2) 432 433 mounter2, err := plugin.NewMounter(volumeSpec2, pod2, volume.VolumeOptions{}) 434 if err != nil { 435 t.Fatalf("NewMounter failed. Expected: <no error> Actual: <%v>", err) 436 } 437 438 mapper2, err := plugin.NewBlockVolumeMapper(volumeSpec2, pod2, volume.VolumeOptions{}) 439 if err != nil { 440 t.Fatalf("NewBlockVolumeMapper failed. Expected: <no error> Actual: <%v>", err) 441 } 442 443 markVolumeOpts2 := operationexecutor.MarkVolumeOpts{ 444 PodName: podName2, 445 PodUID: pod2.UID, 446 VolumeName: generatedVolumeName1, 447 Mounter: mounter2, 448 BlockVolumeMapper: mapper2, 449 OuterVolumeSpecName: volumeSpec2.Name(), 450 VolumeSpec: volumeSpec2, 451 } 452 err = asw.AddPodToVolume(markVolumeOpts2) 453 if err != nil { 454 t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err) 455 } 456 457 verifyVolumeExistsAsw(t, generatedVolumeName1, true /* shouldExist */, asw) 458 verifyVolumeDoesntExistInUnmountedVolumes(t, generatedVolumeName1, asw) 459 verifyVolumeDoesntExistInGloballyMountedVolumes(t, generatedVolumeName1, asw) 460 verifyPodExistsInVolumeAsw(t, podName1, generatedVolumeName1, "fake/device/path" /* expectedDevicePath */, asw) 461 verifyVolumeExistsWithSpecNameInVolumeAsw(t, podName1, volumeSpec1.Name(), asw) 462 verifyPodExistsInVolumeAsw(t, podName2, generatedVolumeName2, "fake/device/path" /* expectedDevicePath */, asw) 463 verifyVolumeExistsWithSpecNameInVolumeAsw(t, podName2, volumeSpec2.Name(), asw) 464 verifyVolumeSpecNameInVolumeAsw(t, podName1, []*volume.Spec{volumeSpec1}, asw) 465 verifyVolumeSpecNameInVolumeAsw(t, podName2, []*volume.Spec{volumeSpec2}, asw) 466 verifyVolumeMountedElsewhere(t, podName1, generatedVolumeName1, true /*expectedMountedElsewhere */, asw) 467 verifyVolumeMountedElsewhere(t, podName2, generatedVolumeName2, true /*expectedMountedElsewhere */, asw) 468 } 469 470 // Test if volumes that were recorded to be read from disk during reconstruction 471 // are handled correctly by the ASOW. 472 func TestActualStateOfWorld_FoundDuringReconstruction(t *testing.T) { 473 tests := []struct { 474 name string 475 opCallback func(asw ActualStateOfWorld, volumeOpts operationexecutor.MarkVolumeOpts) error 476 verifyCallback func(asw ActualStateOfWorld, volumeOpts operationexecutor.MarkVolumeOpts) error 477 }{ 478 { 479 name: "marking volume mounted should remove volume from found during reconstruction", 480 opCallback: func(asw ActualStateOfWorld, volumeOpts operationexecutor.MarkVolumeOpts) error { 481 volumeOpts.VolumeMountState = operationexecutor.VolumeMounted 482 return asw.MarkVolumeAsMounted(volumeOpts) 483 }, 484 verifyCallback: func(asw ActualStateOfWorld, volumeOpts operationexecutor.MarkVolumeOpts) error { 485 ok := asw.IsVolumeReconstructed(volumeOpts.VolumeName, volumeOpts.PodName) 486 if ok { 487 return fmt.Errorf("found unexpected volume in reconstructed volume list") 488 } 489 return nil 490 }, 491 }, 492 { 493 name: "removing volume from pod should remove volume from found during reconstruction", 494 opCallback: func(asw ActualStateOfWorld, volumeOpts operationexecutor.MarkVolumeOpts) error { 495 return asw.MarkVolumeAsUnmounted(volumeOpts.PodName, volumeOpts.VolumeName) 496 }, 497 verifyCallback: func(asw ActualStateOfWorld, volumeOpts operationexecutor.MarkVolumeOpts) error { 498 ok := asw.IsVolumeReconstructed(volumeOpts.VolumeName, volumeOpts.PodName) 499 if ok { 500 return fmt.Errorf("found unexpected volume in reconstructed volume list") 501 } 502 return nil 503 }, 504 }, 505 { 506 name: "removing volume entirely from ASOW should remove volume from found during reconstruction", 507 opCallback: func(asw ActualStateOfWorld, volumeOpts operationexecutor.MarkVolumeOpts) error { 508 err := asw.MarkVolumeAsUnmounted(volumeOpts.PodName, volumeOpts.VolumeName) 509 if err != nil { 510 return err 511 } 512 asw.MarkVolumeAsDetached(volumeOpts.VolumeName, "") 513 return nil 514 }, 515 verifyCallback: func(asw ActualStateOfWorld, volumeOpts operationexecutor.MarkVolumeOpts) error { 516 ok := asw.IsVolumeReconstructed(volumeOpts.VolumeName, volumeOpts.PodName) 517 if ok { 518 return fmt.Errorf("found unexpected volume in reconstructed volume list") 519 } 520 aswInstance, _ := asw.(*actualStateOfWorld) 521 _, found := aswInstance.foundDuringReconstruction[volumeOpts.VolumeName] 522 if found { 523 return fmt.Errorf("found unexpected volume in reconstructed map") 524 } 525 return nil 526 }, 527 }, 528 { 529 name: "uncertain attachability is resolved to attachable", 530 opCallback: func(asw ActualStateOfWorld, volumeOpts operationexecutor.MarkVolumeOpts) error { 531 asw.UpdateReconstructedVolumeAttachability(volumeOpts.VolumeName, true) 532 return nil 533 }, 534 verifyCallback: func(asw ActualStateOfWorld, volumeOpts operationexecutor.MarkVolumeOpts) error { 535 verifyVolumeAttachability(t, volumeOpts.VolumeName, asw, volumeAttachabilityTrue) 536 return nil 537 }, 538 }, 539 { 540 name: "uncertain attachability is resolved to non-attachable", 541 opCallback: func(asw ActualStateOfWorld, volumeOpts operationexecutor.MarkVolumeOpts) error { 542 asw.UpdateReconstructedVolumeAttachability(volumeOpts.VolumeName, false) 543 return nil 544 }, 545 verifyCallback: func(asw ActualStateOfWorld, volumeOpts operationexecutor.MarkVolumeOpts) error { 546 verifyVolumeAttachability(t, volumeOpts.VolumeName, asw, volumeAttachabilityFalse) 547 return nil 548 }, 549 }, 550 { 551 name: "certain (false) attachability cannot be changed", 552 opCallback: func(asw ActualStateOfWorld, volumeOpts operationexecutor.MarkVolumeOpts) error { 553 asw.UpdateReconstructedVolumeAttachability(volumeOpts.VolumeName, false) 554 // This function should be NOOP: 555 asw.UpdateReconstructedVolumeAttachability(volumeOpts.VolumeName, true) 556 return nil 557 }, 558 verifyCallback: func(asw ActualStateOfWorld, volumeOpts operationexecutor.MarkVolumeOpts) error { 559 verifyVolumeAttachability(t, volumeOpts.VolumeName, asw, volumeAttachabilityFalse) 560 return nil 561 }, 562 }, 563 { 564 name: "certain (true) attachability cannot be changed", 565 opCallback: func(asw ActualStateOfWorld, volumeOpts operationexecutor.MarkVolumeOpts) error { 566 asw.UpdateReconstructedVolumeAttachability(volumeOpts.VolumeName, true) 567 // This function should be NOOP: 568 asw.UpdateReconstructedVolumeAttachability(volumeOpts.VolumeName, false) 569 return nil 570 }, 571 verifyCallback: func(asw ActualStateOfWorld, volumeOpts operationexecutor.MarkVolumeOpts) error { 572 verifyVolumeAttachability(t, volumeOpts.VolumeName, asw, volumeAttachabilityTrue) 573 return nil 574 }, 575 }, 576 } 577 for _, tc := range tests { 578 t.Run(tc.name, func(t *testing.T) { 579 volumePluginMgr, plugin := volumetesting.GetTestKubeletVolumePluginMgr(t) 580 asw := NewActualStateOfWorld("mynode" /* nodeName */, volumePluginMgr) 581 devicePath := "fake/device/path" 582 583 pod1 := getTestPod("pod1", "pod1uid", "volume-name-1", "fake-device1") 584 volumeSpec1 := &volume.Spec{Volume: &pod1.Spec.Volumes[0]} 585 generatedVolumeName1, err := util.GetUniqueVolumeNameFromSpec( 586 plugin, volumeSpec1) 587 require.NoError(t, err) 588 err = asw.AddAttachUncertainReconstructedVolume(generatedVolumeName1, volumeSpec1, "" /* nodeName */, devicePath) 589 if err != nil { 590 t.Fatalf("MarkVolumeAsAttached failed. Expected: <no error> Actual: <%v>", err) 591 } 592 podName1 := util.GetUniquePodName(pod1) 593 594 mounter1, err := plugin.NewMounter(volumeSpec1, pod1, volume.VolumeOptions{}) 595 if err != nil { 596 t.Fatalf("NewMounter failed. Expected: <no error> Actual: <%v>", err) 597 } 598 599 mapper1, err := plugin.NewBlockVolumeMapper(volumeSpec1, pod1, volume.VolumeOptions{}) 600 if err != nil { 601 t.Fatalf("NewBlockVolumeMapper failed. Expected: <no error> Actual: <%v>", err) 602 } 603 604 markVolumeOpts1 := operationexecutor.MarkVolumeOpts{ 605 PodName: podName1, 606 PodUID: pod1.UID, 607 VolumeName: generatedVolumeName1, 608 Mounter: mounter1, 609 BlockVolumeMapper: mapper1, 610 OuterVolumeSpecName: volumeSpec1.Name(), 611 VolumeSpec: volumeSpec1, 612 VolumeMountState: operationexecutor.VolumeMountUncertain, 613 } 614 _, err = asw.CheckAndMarkVolumeAsUncertainViaReconstruction(markVolumeOpts1) 615 if err != nil { 616 t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err) 617 } 618 // make sure state is as we expect it to be 619 verifyVolumeExistsAsw(t, generatedVolumeName1, true /* shouldExist */, asw) 620 verifyVolumeDoesntExistInUnmountedVolumes(t, generatedVolumeName1, asw) 621 verifyVolumeDoesntExistInGloballyMountedVolumes(t, generatedVolumeName1, asw) 622 verifyVolumeExistsWithSpecNameInVolumeAsw(t, podName1, volumeSpec1.Name(), asw) 623 verifyVolumeSpecNameInVolumeAsw(t, podName1, []*volume.Spec{volumeSpec1}, asw) 624 verifyVolumeFoundInReconstruction(t, podName1, generatedVolumeName1, asw) 625 verifyVolumeAttachability(t, generatedVolumeName1, asw, volumeAttachabilityUncertain) 626 627 if tc.opCallback != nil { 628 err = tc.opCallback(asw, markVolumeOpts1) 629 if err != nil { 630 t.Fatalf("for test %s: %v", tc.name, err) 631 } 632 } 633 err = tc.verifyCallback(asw, markVolumeOpts1) 634 if err != nil { 635 t.Fatalf("for test %s verification failed: %v", tc.name, err) 636 } 637 }) 638 } 639 } 640 641 // Call MarkVolumeAsDetached() on a volume which mounted by pod(s) should be skipped 642 func Test_MarkVolumeAsDetached_Negative_PodInVolume(t *testing.T) { 643 // Arrange 644 volumePluginMgr, plugin := volumetesting.GetTestVolumePluginMgr(t) 645 devicePath := "fake/device/path" 646 asw := NewActualStateOfWorld("mynode", volumePluginMgr) 647 pod := &v1.Pod{ 648 ObjectMeta: metav1.ObjectMeta{ 649 Name: "pod1", 650 UID: "pod1uid", 651 }, 652 Spec: v1.PodSpec{ 653 Volumes: []v1.Volume{ 654 { 655 Name: "volume-name", 656 VolumeSource: v1.VolumeSource{ 657 GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{ 658 PDName: "fake-device1", 659 }, 660 }, 661 }, 662 }, 663 }, 664 } 665 logger, _ := ktesting.NewTestContext(t) 666 volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]} 667 err := asw.MarkVolumeAsAttached(logger, emptyVolumeName, volumeSpec, "" /* nodeName */, devicePath) 668 if err != nil { 669 t.Fatalf("MarkVolumeAsAttached failed. Expected: <no error> Actual: <%v>", err) 670 } 671 672 generatedVolumeName, err := util.GetUniqueVolumeNameFromSpec(plugin, volumeSpec) 673 if err != nil { 674 t.Fatalf("GetUniqueVolumeNameFromSpec failed. Expected: <no error> Actual: <%v>", err) 675 } 676 677 podName := util.GetUniquePodName(pod) 678 mounter, err := plugin.NewMounter(volumeSpec, pod, volume.VolumeOptions{}) 679 if err != nil { 680 t.Fatalf("NewMounter failed. Expected: <no error> Actual: <%v>", err) 681 } 682 683 mapper, err := plugin.NewBlockVolumeMapper(volumeSpec, pod, volume.VolumeOptions{}) 684 if err != nil { 685 t.Fatalf("NewBlockVolumeMapper failed. Expected: <no error> Actual: <%v>", err) 686 } 687 688 markVolumeOpts := operationexecutor.MarkVolumeOpts{ 689 PodName: podName, 690 PodUID: pod.UID, 691 VolumeName: generatedVolumeName, 692 Mounter: mounter, 693 BlockVolumeMapper: mapper, 694 OuterVolumeSpecName: volumeSpec.Name(), 695 VolumeSpec: volumeSpec, 696 } 697 err = asw.AddPodToVolume(markVolumeOpts) 698 if err != nil { 699 t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err) 700 } 701 702 // Act 703 asw.MarkVolumeAsDetached(generatedVolumeName, "" /* nodeName */) 704 705 // Assert 706 verifyPodExistsInVolumeAsw(t, podName, generatedVolumeName, "fake/device/path" /* expectedDevicePath */, asw) 707 } 708 709 func getTestPod(podName, podUID, outerVolumeName, pdName string) *v1.Pod { 710 pod := &v1.Pod{ 711 ObjectMeta: metav1.ObjectMeta{ 712 Name: podName, 713 UID: types.UID(podUID), 714 }, 715 Spec: v1.PodSpec{ 716 Volumes: []v1.Volume{ 717 { 718 Name: outerVolumeName, 719 VolumeSource: v1.VolumeSource{ 720 GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{ 721 PDName: pdName, 722 }, 723 }, 724 }, 725 }, 726 }, 727 } 728 return pod 729 } 730 731 // Calls AddPodToVolume() to add pod to empty data struct 732 // Verifies call fails with "volume does not exist" error. 733 func Test_AddPodToVolume_Negative_VolumeDoesntExist(t *testing.T) { 734 // Arrange 735 volumePluginMgr, _ := volumetesting.GetTestKubeletVolumePluginMgr(t) 736 asw := NewActualStateOfWorld("mynode" /* nodeName */, volumePluginMgr) 737 738 pod := &v1.Pod{ 739 ObjectMeta: metav1.ObjectMeta{ 740 Name: "pod1", 741 UID: "pod1uid", 742 }, 743 Spec: v1.PodSpec{ 744 Volumes: []v1.Volume{ 745 { 746 Name: "volume-name", 747 VolumeSource: v1.VolumeSource{ 748 GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{ 749 PDName: "fake-device1", 750 }, 751 }, 752 }, 753 }, 754 }, 755 } 756 757 volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]} 758 plugin, err := volumePluginMgr.FindPluginBySpec(volumeSpec) 759 if err != nil { 760 t.Fatalf( 761 "volumePluginMgr.FindPluginBySpec failed to find volume plugin for %#v with: %v", 762 volumeSpec, 763 err) 764 } 765 766 generatedVolumeName, err := util.GetUniqueVolumeNameFromSpec( 767 plugin, volumeSpec) 768 require.NoError(t, err) 769 770 blockplugin, err := volumePluginMgr.FindMapperPluginBySpec(volumeSpec) 771 if err != nil { 772 t.Fatalf( 773 "volumePluginMgr.FindMapperPluginBySpec failed to find volume plugin for %#v with: %v", 774 volumeSpec, 775 err) 776 } 777 778 volumeName, err := util.GetUniqueVolumeNameFromSpec( 779 plugin, volumeSpec) 780 require.NoError(t, err) 781 782 podName := util.GetUniquePodName(pod) 783 784 mounter, err := plugin.NewMounter(volumeSpec, pod, volume.VolumeOptions{}) 785 if err != nil { 786 t.Fatalf("NewMounter failed. Expected: <no error> Actual: <%v>", err) 787 } 788 789 mapper, err := blockplugin.NewBlockVolumeMapper(volumeSpec, pod, volume.VolumeOptions{}) 790 if err != nil { 791 t.Fatalf("NewBlockVolumeMapper failed. Expected: <no error> Actual: <%v>", err) 792 } 793 794 // Act 795 markVolumeOpts := operationexecutor.MarkVolumeOpts{ 796 PodName: podName, 797 PodUID: pod.UID, 798 VolumeName: volumeName, 799 Mounter: mounter, 800 BlockVolumeMapper: mapper, 801 OuterVolumeSpecName: volumeSpec.Name(), 802 VolumeSpec: volumeSpec, 803 } 804 err = asw.AddPodToVolume(markVolumeOpts) 805 // Assert 806 if err == nil { 807 t.Fatalf("AddPodToVolume did not fail. Expected: <\"no volume with the name ... exists in the list of attached volumes\"> Actual: <no error>") 808 } 809 810 verifyVolumeExistsAsw(t, volumeName, false /* shouldExist */, asw) 811 verifyVolumeDoesntExistInUnmountedVolumes(t, volumeName, asw) 812 verifyVolumeDoesntExistInGloballyMountedVolumes(t, volumeName, asw) 813 verifyPodDoesntExistInVolumeAsw( 814 t, 815 podName, 816 volumeName, 817 false, /* expectVolumeToExist */ 818 asw) 819 verifyVolumeDoesntExistWithSpecNameInVolumeAsw(t, podName, volumeSpec.Name(), asw) 820 verifyVolumeMountedElsewhere(t, podName, generatedVolumeName, false /*expectedMountedElsewhere */, asw) 821 } 822 823 // Calls MarkVolumeAsAttached() once to add volume 824 // Calls MarkDeviceAsMounted() to mark volume as globally mounted. 825 // Verifies newly added volume exists in GetUnmountedVolumes() 826 // Verifies newly added volume exists in GetGloballyMountedVolumes() 827 func Test_MarkDeviceAsMounted_Positive_NewVolume(t *testing.T) { 828 // Arrange 829 volumePluginMgr, plugin := volumetesting.GetTestKubeletVolumePluginMgr(t) 830 asw := NewActualStateOfWorld("mynode" /* nodeName */, volumePluginMgr) 831 pod := &v1.Pod{ 832 ObjectMeta: metav1.ObjectMeta{ 833 Name: "pod1", 834 UID: "pod1uid", 835 }, 836 Spec: v1.PodSpec{ 837 Volumes: []v1.Volume{ 838 { 839 Name: "volume-name", 840 VolumeSource: v1.VolumeSource{ 841 GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{ 842 PDName: "fake-device1", 843 }, 844 }, 845 }, 846 }, 847 }, 848 } 849 volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]} 850 devicePath := "fake/device/path" 851 deviceMountPath := "fake/device/mount/path" 852 generatedVolumeName, err := util.GetUniqueVolumeNameFromSpec(plugin, volumeSpec) 853 if err != nil { 854 t.Fatalf("GetUniqueVolumeNameFromSpec failed. Expected: <no error> Actual: <%v>", err) 855 } 856 logger, _ := ktesting.NewTestContext(t) 857 err = asw.MarkVolumeAsAttached(logger, emptyVolumeName, volumeSpec, "" /* nodeName */, devicePath) 858 if err != nil { 859 t.Fatalf("MarkVolumeAsAttached failed. Expected: <no error> Actual: <%v>", err) 860 } 861 862 // Act 863 err = asw.MarkDeviceAsMounted(generatedVolumeName, devicePath, deviceMountPath, "") 864 865 // Assert 866 if err != nil { 867 t.Fatalf("MarkDeviceAsMounted failed. Expected: <no error> Actual: <%v>", err) 868 } 869 870 verifyVolumeExistsAsw(t, generatedVolumeName, true /* shouldExist */, asw) 871 verifyVolumeExistsInUnmountedVolumes(t, generatedVolumeName, asw) 872 verifyVolumeExistsInGloballyMountedVolumes(t, generatedVolumeName, asw) 873 } 874 875 // Populates data struct with a volume with a SELinux context. 876 // Calls AddPodToVolume() to add a pod to the volume 877 // Verifies volume/pod combo exist using PodExistsInVolume() 878 func Test_AddPodToVolume_Positive_SELinux(t *testing.T) { 879 // Arrange 880 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)() 881 volumePluginMgr, plugin := volumetesting.GetTestKubeletVolumePluginMgr(t) 882 asw := NewActualStateOfWorld("mynode" /* nodeName */, volumePluginMgr) 883 devicePath := "fake/device/path" 884 885 pod := &v1.Pod{ 886 ObjectMeta: metav1.ObjectMeta{ 887 Name: "pod1", 888 UID: "pod1uid", 889 }, 890 Spec: v1.PodSpec{ 891 Volumes: []v1.Volume{ 892 { 893 Name: "volume-name", 894 VolumeSource: v1.VolumeSource{ 895 GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{ 896 PDName: "fake-device1", 897 }, 898 }, 899 }, 900 }, 901 }, 902 } 903 volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]} 904 generatedVolumeName, err := util.GetUniqueVolumeNameFromSpec(plugin, volumeSpec) 905 if err != nil { 906 t.Fatalf("GetUniqueVolumeNameFromSpec failed. Expected: <no error> Actual: <%v>", err) 907 } 908 logger, _ := ktesting.NewTestContext(t) 909 err = asw.MarkVolumeAsAttached(logger, emptyVolumeName, volumeSpec, "" /* nodeName */, devicePath) 910 if err != nil { 911 t.Fatalf("MarkVolumeAsAttached failed. Expected: <no error> Actual: <%v>", err) 912 } 913 podName := util.GetUniquePodName(pod) 914 915 mounter, err := plugin.NewMounter(volumeSpec, pod, volume.VolumeOptions{}) 916 if err != nil { 917 t.Fatalf("NewMounter failed. Expected: <no error> Actual: <%v>", err) 918 } 919 920 mapper, err := plugin.NewBlockVolumeMapper(volumeSpec, pod, volume.VolumeOptions{}) 921 if err != nil { 922 t.Fatalf("NewBlockVolumeMapper failed. Expected: <no error> Actual: <%v>", err) 923 } 924 925 // Act 926 markVolumeOpts := operationexecutor.MarkVolumeOpts{ 927 PodName: podName, 928 PodUID: pod.UID, 929 VolumeName: generatedVolumeName, 930 Mounter: mounter, 931 BlockVolumeMapper: mapper, 932 OuterVolumeSpecName: volumeSpec.Name(), 933 VolumeSpec: volumeSpec, 934 SELinuxMountContext: "system_u:object_r:container_file_t:s0:c0,c1", 935 VolumeMountState: operationexecutor.VolumeMounted, 936 } 937 err = asw.AddPodToVolume(markVolumeOpts) 938 // Assert 939 if err != nil { 940 t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err) 941 } 942 943 verifyVolumeExistsAswWithSELinux(t, generatedVolumeName, "system_u:object_r:container_file_t:s0:c0,c1", asw) 944 verifyVolumeDoesntExistInUnmountedVolumes(t, generatedVolumeName, asw) 945 verifyVolumeDoesntExistInGloballyMountedVolumes(t, generatedVolumeName, asw) 946 verifyPodExistsInVolumeAswWithSELinux(t, podName, generatedVolumeName, "fake/device/path" /* expectedDevicePath */, "system_u:object_r:container_file_t:s0:c0,c1", asw) 947 verifyPodExistsInVolumeSELinuxMismatch(t, podName, generatedVolumeName, "" /* wrong SELinux label */, asw) 948 verifyVolumeExistsWithSpecNameInVolumeAsw(t, podName, volumeSpec.Name(), asw) 949 verifyVolumeMountedElsewhere(t, podName, generatedVolumeName, false /*expectedMountedElsewhere */, asw) 950 } 951 952 // Calls MarkVolumeAsAttached() once to add volume 953 // Calls MarkDeviceAsMounted() with SELinux to mark volume as globally mounted. 954 // Verifies newly added volume exists in GetUnmountedVolumes() 955 // Verifies newly added volume exists in GetGloballyMountedVolumes() 956 func Test_MarkDeviceAsMounted_Positive_SELinux(t *testing.T) { 957 // Arrange 958 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)() 959 volumePluginMgr, plugin := volumetesting.GetTestKubeletVolumePluginMgr(t) 960 asw := NewActualStateOfWorld("mynode" /* nodeName */, volumePluginMgr) 961 pod := &v1.Pod{ 962 ObjectMeta: metav1.ObjectMeta{ 963 Name: "pod1", 964 UID: "pod1uid", 965 }, 966 Spec: v1.PodSpec{ 967 Volumes: []v1.Volume{ 968 { 969 Name: "volume-name", 970 VolumeSource: v1.VolumeSource{ 971 GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{ 972 PDName: "fake-device1", 973 }, 974 }, 975 }, 976 }, 977 }, 978 } 979 volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]} 980 devicePath := "fake/device/path" 981 deviceMountPath := "fake/device/mount/path" 982 generatedVolumeName, err := util.GetUniqueVolumeNameFromSpec(plugin, volumeSpec) 983 if err != nil { 984 t.Fatalf("GetUniqueVolumeNameFromSpec failed. Expected: <no error> Actual: <%v>", err) 985 } 986 logger, _ := ktesting.NewTestContext(t) 987 err = asw.MarkVolumeAsAttached(logger, emptyVolumeName, volumeSpec, "" /* nodeName */, devicePath) 988 if err != nil { 989 t.Fatalf("MarkVolumeAsAttached failed. Expected: <no error> Actual: <%v>", err) 990 } 991 992 // Act 993 err = asw.MarkDeviceAsMounted(generatedVolumeName, devicePath, deviceMountPath, "system_u:system_r:container_t:s0:c0,c1") 994 995 // Assert 996 if err != nil { 997 t.Fatalf("MarkDeviceAsMounted failed. Expected: <no error> Actual: <%v>", err) 998 } 999 1000 verifyVolumeExistsAsw(t, generatedVolumeName, true /* shouldExist */, asw) 1001 verifyVolumeExistsInUnmountedVolumes(t, generatedVolumeName, asw) 1002 verifyVolumeExistsInGloballyMountedVolumesWithSELinux(t, generatedVolumeName, "system_u:system_r:container_t:s0:c0,c1", asw) 1003 } 1004 1005 func TestUncertainVolumeMounts(t *testing.T) { 1006 // Arrange 1007 volumePluginMgr, plugin := volumetesting.GetTestKubeletVolumePluginMgr(t) 1008 asw := NewActualStateOfWorld("mynode" /* nodeName */, volumePluginMgr) 1009 devicePath := "fake/device/path" 1010 1011 pod1 := &v1.Pod{ 1012 ObjectMeta: metav1.ObjectMeta{ 1013 Name: "pod1", 1014 UID: "pod1uid", 1015 }, 1016 Spec: v1.PodSpec{ 1017 Volumes: []v1.Volume{ 1018 { 1019 Name: "volume-name-1", 1020 VolumeSource: v1.VolumeSource{ 1021 GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{ 1022 PDName: "fake-device1", 1023 }, 1024 }, 1025 }, 1026 }, 1027 }, 1028 } 1029 volumeSpec1 := &volume.Spec{Volume: &pod1.Spec.Volumes[0]} 1030 generatedVolumeName1, err := util.GetUniqueVolumeNameFromSpec( 1031 plugin, volumeSpec1) 1032 require.NoError(t, err) 1033 logger, _ := ktesting.NewTestContext(t) 1034 err = asw.MarkVolumeAsAttached(logger, generatedVolumeName1, volumeSpec1, "" /* nodeName */, devicePath) 1035 if err != nil { 1036 t.Fatalf("MarkVolumeAsAttached failed. Expected: <no error> Actual: <%v>", err) 1037 } 1038 podName1 := util.GetUniquePodName(pod1) 1039 1040 mounter1, err := plugin.NewMounter(volumeSpec1, pod1, volume.VolumeOptions{}) 1041 if err != nil { 1042 t.Fatalf("NewMounter failed. Expected: <no error> Actual: <%v>", err) 1043 } 1044 1045 markVolumeOpts1 := operationexecutor.MarkVolumeOpts{ 1046 PodName: podName1, 1047 PodUID: pod1.UID, 1048 VolumeName: generatedVolumeName1, 1049 Mounter: mounter1, 1050 OuterVolumeSpecName: volumeSpec1.Name(), 1051 VolumeSpec: volumeSpec1, 1052 VolumeMountState: operationexecutor.VolumeMountUncertain, 1053 } 1054 err = asw.AddPodToVolume(markVolumeOpts1) 1055 if err != nil { 1056 t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err) 1057 } 1058 mountedVolumes := asw.GetMountedVolumesForPod(podName1) 1059 volumeFound := false 1060 for _, volume := range mountedVolumes { 1061 if volume.InnerVolumeSpecName == volumeSpec1.Name() { 1062 volumeFound = true 1063 } 1064 } 1065 if volumeFound { 1066 t.Fatalf("expected volume %s to be not found in asw.GetMountedVolumesForPod", volumeSpec1.Name()) 1067 } 1068 1069 possiblyMountedVolumes := asw.GetPossiblyMountedVolumesForPod(podName1) 1070 volumeFound = false 1071 for _, volume := range possiblyMountedVolumes { 1072 if volume.InnerVolumeSpecName == volumeSpec1.Name() { 1073 volumeFound = true 1074 } 1075 } 1076 if !volumeFound { 1077 t.Fatalf("expected volume %s to be found in aws.GetPossiblyMountedVolumesForPod", volumeSpec1.Name()) 1078 } 1079 1080 volExists, _, _ := asw.PodExistsInVolume(podName1, generatedVolumeName1, resource.Quantity{}, "") 1081 if volExists { 1082 t.Fatalf("expected volume %s to not exist in asw", generatedVolumeName1) 1083 } 1084 removed := asw.PodRemovedFromVolume(podName1, generatedVolumeName1) 1085 if removed { 1086 t.Fatalf("expected volume %s not to be removed in asw", generatedVolumeName1) 1087 } 1088 } 1089 1090 func verifyVolumeExistsInGloballyMountedVolumes( 1091 t *testing.T, expectedVolumeName v1.UniqueVolumeName, asw ActualStateOfWorld) { 1092 globallyMountedVolumes := asw.GetGloballyMountedVolumes() 1093 for _, volume := range globallyMountedVolumes { 1094 if volume.VolumeName == expectedVolumeName { 1095 return 1096 } 1097 } 1098 1099 t.Fatalf( 1100 "Could not find volume %v in the list of GloballyMountedVolumes for actual state of world %+v", 1101 expectedVolumeName, 1102 globallyMountedVolumes) 1103 } 1104 1105 func verifyVolumeExistsInGloballyMountedVolumesWithSELinux( 1106 t *testing.T, expectedVolumeName v1.UniqueVolumeName, expectedSELinuxContext string, asw ActualStateOfWorld) { 1107 globallyMountedVolumes := asw.GetGloballyMountedVolumes() 1108 for _, volume := range globallyMountedVolumes { 1109 if volume.VolumeName == expectedVolumeName { 1110 if volume.SELinuxMountContext == expectedSELinuxContext { 1111 return 1112 } 1113 t.Errorf( 1114 "Volume %q has wrong SELinux context. Expected %q, got %q", 1115 expectedVolumeName, 1116 expectedSELinuxContext, 1117 volume.SELinuxMountContext) 1118 } 1119 } 1120 1121 t.Fatalf( 1122 "Could not find volume %v in the list of GloballyMountedVolumes for actual state of world %+v", 1123 expectedVolumeName, 1124 globallyMountedVolumes) 1125 } 1126 1127 func verifyVolumeDoesntExistInGloballyMountedVolumes( 1128 t *testing.T, volumeToCheck v1.UniqueVolumeName, asw ActualStateOfWorld) { 1129 globallyMountedVolumes := asw.GetGloballyMountedVolumes() 1130 for _, volume := range globallyMountedVolumes { 1131 if volume.VolumeName == volumeToCheck { 1132 t.Fatalf( 1133 "Found volume %v in the list of GloballyMountedVolumes. Expected it not to exist.", 1134 volumeToCheck) 1135 } 1136 } 1137 } 1138 1139 func verifyVolumeExistsAsw( 1140 t *testing.T, 1141 expectedVolumeName v1.UniqueVolumeName, 1142 shouldExist bool, 1143 asw ActualStateOfWorld) { 1144 volumeExists := asw.VolumeExists(expectedVolumeName) 1145 if shouldExist != volumeExists { 1146 t.Fatalf( 1147 "VolumeExists(%q) response incorrect. Expected: <%v> Actual: <%v>", 1148 expectedVolumeName, 1149 shouldExist, 1150 volumeExists) 1151 } 1152 } 1153 1154 func verifyVolumeExistsAswWithSELinux( 1155 t *testing.T, 1156 expectedVolumeName v1.UniqueVolumeName, 1157 expectedSELinuxContext string, 1158 asw ActualStateOfWorld) { 1159 volumes := asw.GetMountedVolumes() 1160 for _, vol := range volumes { 1161 if vol.VolumeName == expectedVolumeName { 1162 if vol.SELinuxMountContext == expectedSELinuxContext { 1163 return 1164 } 1165 t.Errorf( 1166 "Volume %q has wrong SELinux context, expected %q, got %q", 1167 expectedVolumeName, 1168 expectedSELinuxContext, 1169 vol.SELinuxMountContext) 1170 } 1171 } 1172 t.Errorf("Volume %q not found in ASW", expectedVolumeName) 1173 } 1174 1175 func verifyVolumeExistsInUnmountedVolumes( 1176 t *testing.T, expectedVolumeName v1.UniqueVolumeName, asw ActualStateOfWorld) { 1177 unmountedVolumes := asw.GetUnmountedVolumes() 1178 for _, volume := range unmountedVolumes { 1179 if volume.VolumeName == expectedVolumeName { 1180 return 1181 } 1182 } 1183 1184 t.Fatalf( 1185 "Could not find volume %v in the list of UnmountedVolumes for actual state of world %+v", 1186 expectedVolumeName, 1187 unmountedVolumes) 1188 } 1189 1190 func verifyVolumeDoesntExistInUnmountedVolumes( 1191 t *testing.T, volumeToCheck v1.UniqueVolumeName, asw ActualStateOfWorld) { 1192 unmountedVolumes := asw.GetUnmountedVolumes() 1193 for _, volume := range unmountedVolumes { 1194 if volume.VolumeName == volumeToCheck { 1195 t.Fatalf( 1196 "Found volume %v in the list of UnmountedVolumes. Expected it not to exist.", 1197 volumeToCheck) 1198 } 1199 } 1200 } 1201 1202 func verifyPodExistsInVolumeAsw( 1203 t *testing.T, 1204 expectedPodName volumetypes.UniquePodName, 1205 expectedVolumeName v1.UniqueVolumeName, 1206 expectedDevicePath string, 1207 asw ActualStateOfWorld) { 1208 verifyPodExistsInVolumeAswWithSELinux(t, expectedPodName, expectedVolumeName, expectedDevicePath, "", asw) 1209 } 1210 1211 func verifyPodExistsInVolumeAswWithSELinux( 1212 t *testing.T, 1213 expectedPodName volumetypes.UniquePodName, 1214 expectedVolumeName v1.UniqueVolumeName, 1215 expectedDevicePath string, 1216 expectedSELinuxLabel string, 1217 asw ActualStateOfWorld) { 1218 podExistsInVolume, devicePath, err := 1219 asw.PodExistsInVolume(expectedPodName, expectedVolumeName, resource.Quantity{}, expectedSELinuxLabel) 1220 if err != nil { 1221 t.Fatalf( 1222 "ASW PodExistsInVolume failed. Expected: <no error> Actual: <%v>", err) 1223 } 1224 1225 if !podExistsInVolume { 1226 t.Fatalf( 1227 "ASW PodExistsInVolume result invalid. Expected: <true> Actual: <%v>", 1228 podExistsInVolume) 1229 } 1230 1231 if devicePath != expectedDevicePath { 1232 t.Fatalf( 1233 "Invalid devicePath. Expected: <%q> Actual: <%q> ", 1234 expectedDevicePath, 1235 devicePath) 1236 } 1237 } 1238 1239 func verifyVolumeMountedElsewhere( 1240 t *testing.T, 1241 expectedPodName volumetypes.UniquePodName, 1242 expectedVolumeName v1.UniqueVolumeName, 1243 expectedMountedElsewhere bool, 1244 asw ActualStateOfWorld) { 1245 mountedElsewhere := asw.IsVolumeMountedElsewhere(expectedVolumeName, expectedPodName) 1246 if mountedElsewhere != expectedMountedElsewhere { 1247 t.Fatalf( 1248 "IsVolumeMountedElsewhere assertion failure. Expected : <%t> Actual: <%t>", 1249 expectedMountedElsewhere, 1250 mountedElsewhere) 1251 } 1252 } 1253 1254 func verifyPodDoesntExistInVolumeAsw( 1255 t *testing.T, 1256 podToCheck volumetypes.UniquePodName, 1257 volumeToCheck v1.UniqueVolumeName, 1258 expectVolumeToExist bool, 1259 asw ActualStateOfWorld) { 1260 podExistsInVolume, devicePath, err := 1261 asw.PodExistsInVolume(podToCheck, volumeToCheck, resource.Quantity{}, "") 1262 if !expectVolumeToExist && err == nil { 1263 t.Fatalf( 1264 "ASW PodExistsInVolume did not return error. Expected: <error indicating volume does not exist> Actual: <%v>", err) 1265 } 1266 1267 if expectVolumeToExist && err != nil { 1268 t.Fatalf( 1269 "ASW PodExistsInVolume failed. Expected: <no error> Actual: <%v>", err) 1270 } 1271 1272 if podExistsInVolume { 1273 t.Fatalf( 1274 "ASW PodExistsInVolume result invalid. Expected: <false> Actual: <%v>", 1275 podExistsInVolume) 1276 } 1277 1278 if devicePath != "" { 1279 t.Fatalf( 1280 "Invalid devicePath. Expected: <\"\"> Actual: <%q> ", 1281 devicePath) 1282 } 1283 } 1284 1285 func verifyPodExistsInVolumeSELinuxMismatch( 1286 t *testing.T, 1287 podToCheck volumetypes.UniquePodName, 1288 volumeToCheck v1.UniqueVolumeName, 1289 unexpectedSELinuxLabel string, 1290 asw ActualStateOfWorld) { 1291 1292 podExistsInVolume, _, err := asw.PodExistsInVolume(podToCheck, volumeToCheck, resource.Quantity{}, unexpectedSELinuxLabel) 1293 if podExistsInVolume { 1294 t.Errorf("expected Pod %s not to exists, but it does", podToCheck) 1295 } 1296 if err == nil { 1297 t.Error("expected PodExistsInVolume to return error, but it returned nil") 1298 } 1299 1300 if !IsSELinuxMountMismatchError(err) { 1301 t.Errorf("expected PodExistsInVolume to return SELinuxMountMismatchError, got %s", err) 1302 } 1303 } 1304 1305 func verifyVolumeExistsWithSpecNameInVolumeAsw( 1306 t *testing.T, 1307 expectedPodName volumetypes.UniquePodName, 1308 expectedVolumeName string, 1309 asw ActualStateOfWorld) { 1310 podExistsInVolume := 1311 asw.VolumeExistsWithSpecName(expectedPodName, expectedVolumeName) 1312 1313 if !podExistsInVolume { 1314 t.Fatalf( 1315 "ASW VolumeExistsWithSpecName result invalid. Expected: <true> Actual: <%v>", 1316 podExistsInVolume) 1317 } 1318 } 1319 1320 func verifyVolumeDoesntExistWithSpecNameInVolumeAsw( 1321 t *testing.T, 1322 podToCheck volumetypes.UniquePodName, 1323 volumeToCheck string, 1324 asw ActualStateOfWorld) { 1325 podExistsInVolume := 1326 asw.VolumeExistsWithSpecName(podToCheck, volumeToCheck) 1327 1328 if podExistsInVolume { 1329 t.Fatalf( 1330 "ASW VolumeExistsWithSpecName result invalid. Expected: <false> Actual: <%v>", 1331 podExistsInVolume) 1332 } 1333 } 1334 1335 func verifyVolumeSpecNameInVolumeAsw( 1336 t *testing.T, 1337 podToCheck volumetypes.UniquePodName, 1338 volumeSpecs []*volume.Spec, 1339 asw ActualStateOfWorld) { 1340 mountedVolumes := 1341 asw.GetMountedVolumesForPod(podToCheck) 1342 1343 for i, volume := range mountedVolumes { 1344 if volume.InnerVolumeSpecName != volumeSpecs[i].Name() { 1345 t.Fatalf("Volume spec name does not match Expected: <%q> Actual: <%q>", volumeSpecs[i].Name(), volume.InnerVolumeSpecName) 1346 } 1347 } 1348 } 1349 1350 func verifyVolumeFoundInReconstruction(t *testing.T, podToCheck volumetypes.UniquePodName, volumeToCheck v1.UniqueVolumeName, asw ActualStateOfWorld) { 1351 isRecontructed := asw.IsVolumeReconstructed(volumeToCheck, podToCheck) 1352 if !isRecontructed { 1353 t.Fatalf("ASW IsVolumeReconstructed result invalid. expected <true> Actual <false>") 1354 } 1355 } 1356 1357 func verifyVolumeAttachability(t *testing.T, volumeToCheck v1.UniqueVolumeName, asw ActualStateOfWorld, expected volumeAttachability) { 1358 attached := asw.GetAttachedVolumes() 1359 attachable := false 1360 1361 for _, volume := range attached { 1362 if volume.VolumeName == volumeToCheck { 1363 attachable = volume.PluginIsAttachable 1364 break 1365 } 1366 } 1367 1368 switch expected { 1369 case volumeAttachabilityTrue: 1370 if !attachable { 1371 t.Errorf("ASW reports %s as not-attachable, when %s was expected", volumeToCheck, expected) 1372 } 1373 // ASW does not have any special difference between False and Uncertain. 1374 // Uncertain only allows to be changed to True / False. 1375 case volumeAttachabilityUncertain, volumeAttachabilityFalse: 1376 if attachable { 1377 t.Errorf("ASW reports %s as attachable, when %s was expected", volumeToCheck, expected) 1378 } 1379 } 1380 }