k8s.io/kubernetes@v1.29.3/pkg/volume/testing/testing.go (about) 1 /* 2 Copyright 2014 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 testing 18 19 import ( 20 "fmt" 21 "os" 22 "path/filepath" 23 goruntime "runtime" 24 "strings" 25 "sync" 26 "testing" 27 "time" 28 29 "k8s.io/klog/v2" 30 31 "k8s.io/apimachinery/pkg/util/sets" 32 "k8s.io/utils/exec" 33 testingexec "k8s.io/utils/exec/testing" 34 utilstrings "k8s.io/utils/strings" 35 36 v1 "k8s.io/api/core/v1" 37 "k8s.io/apimachinery/pkg/api/resource" 38 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 39 "k8s.io/apimachinery/pkg/types" 40 "k8s.io/apimachinery/pkg/util/uuid" 41 utiltesting "k8s.io/client-go/util/testing" 42 "k8s.io/kubernetes/pkg/volume" 43 "k8s.io/kubernetes/pkg/volume/util" 44 "k8s.io/kubernetes/pkg/volume/util/recyclerclient" 45 volumetypes "k8s.io/kubernetes/pkg/volume/util/types" 46 "k8s.io/kubernetes/pkg/volume/util/volumepathhandler" 47 ) 48 49 const ( 50 // A hook specified in storage class to indicate it's provisioning 51 // is expected to fail. 52 ExpectProvisionFailureKey = "expect-provision-failure" 53 // The node is marked as uncertain. The attach operation will fail and return timeout error 54 // for the first attach call. The following call will return successfully. 55 UncertainAttachNode = "uncertain-attach-node" 56 // The detach operation will keep failing on the node. 57 FailDetachNode = "fail-detach-node" 58 // The node is marked as timeout. The attach operation will always fail and return timeout error 59 // but the operation is actually succeeded. 60 TimeoutAttachNode = "timeout-attach-node" 61 // The node is marked as multi-attach which means it is allowed to attach the volume to multiple nodes. 62 MultiAttachNode = "multi-attach-node" 63 // TimeoutOnSetupVolumeName will cause Setup call to timeout but volume will finish mounting. 64 TimeoutOnSetupVolumeName = "timeout-setup-volume" 65 // FailOnSetupVolumeName will cause setup call to fail 66 FailOnSetupVolumeName = "fail-setup-volume" 67 //TimeoutAndFailOnSetupVolumeName will first timeout and then fail the setup 68 TimeoutAndFailOnSetupVolumeName = "timeout-and-fail-setup-volume" 69 // SuccessAndTimeoutSetupVolumeName will cause first mount operation to succeed but subsequent attempts to timeout 70 SuccessAndTimeoutSetupVolumeName = "success-and-timeout-setup-volume-name" 71 // SuccessAndFailOnSetupVolumeName will cause first mount operation to succeed but subsequent attempts to fail 72 SuccessAndFailOnSetupVolumeName = "success-and-failed-setup-device-name" 73 74 // TimeoutOnMountDeviceVolumeName will cause MountDevice call to timeout but Setup will finish. 75 TimeoutOnMountDeviceVolumeName = "timeout-mount-device-volume" 76 // TimeoutAndFailOnMountDeviceVolumeName will cause first MountDevice call to timeout but second call will fail 77 TimeoutAndFailOnMountDeviceVolumeName = "timeout-and-fail-mount-device-name" 78 // FailMountDeviceVolumeName will cause MountDevice operation on volume to fail 79 FailMountDeviceVolumeName = "fail-mount-device-volume-name" 80 // SuccessAndTimeoutDeviceName will cause first mount operation to succeed but subsequent attempts to timeout 81 SuccessAndTimeoutDeviceName = "success-and-timeout-device-name" 82 // SuccessAndFailOnMountDeviceName will cause first mount operation to succeed but subsequent attempts to fail 83 SuccessAndFailOnMountDeviceName = "success-and-failed-mount-device-name" 84 85 // FailWithInUseVolumeName will cause NodeExpandVolume to result in FailedPrecondition error 86 FailWithInUseVolumeName = "fail-expansion-in-use" 87 FailWithUnSupportedVolumeName = "fail-expansion-unsupported" 88 89 FailVolumeExpansion = "fail-expansion-test" 90 91 AlwaysFailNodeExpansion = "always-fail-node-expansion" 92 93 deviceNotMounted = "deviceNotMounted" 94 deviceMountUncertain = "deviceMountUncertain" 95 deviceMounted = "deviceMounted" 96 97 volumeNotMounted = "volumeNotMounted" 98 volumeMountUncertain = "volumeMountUncertain" 99 volumeMounted = "volumeMounted" 100 101 FailNewMounter = "fail-new-mounter" 102 ) 103 104 // CommandScript is used to pre-configure a command that will be executed and 105 // optionally set it's output (stdout and stderr combined) and return code. 106 type CommandScript struct { 107 // Cmd is the command to execute, e.g. "ls" 108 Cmd string 109 // Args is a slice of arguments to pass to the command, e.g. "-a" 110 Args []string 111 // Output is the combined stdout and stderr of the command to return 112 Output string 113 // ReturnCode is the exit code for the command. Setting this to non-zero will 114 // cause the command to return an error with this exit code set. 115 ReturnCode int 116 } 117 118 // ScriptCommands configures fe, the FakeExec, to have a pre-configured list of 119 // commands to expect. Calling more commands using fe than those scripted will 120 // result in a panic. By default, the fe does not enforce command argument checking 121 // or order -- if you have given an Output to the command, the first command scripted 122 // will return its output on the first command call, even if the command called is 123 // different than the one scripted. This is mostly useful to make sure that the 124 // right number of commands were called. If you want to check the exact commands 125 // and arguments were called, set fe.ExectOrder to true. 126 func ScriptCommands(fe *testingexec.FakeExec, scripts []CommandScript) { 127 fe.DisableScripts = false 128 for _, script := range scripts { 129 fakeCmd := &testingexec.FakeCmd{} 130 cmdAction := makeFakeCmd(fakeCmd, script.Cmd, script.Args...) 131 outputAction := makeFakeOutput(script.Output, script.ReturnCode) 132 fakeCmd.CombinedOutputScript = append(fakeCmd.CombinedOutputScript, outputAction) 133 fe.CommandScript = append(fe.CommandScript, cmdAction) 134 } 135 } 136 137 func makeFakeCmd(fakeCmd *testingexec.FakeCmd, cmd string, args ...string) testingexec.FakeCommandAction { 138 fc := fakeCmd 139 c := cmd 140 a := args 141 return func(cmd string, args ...string) exec.Cmd { 142 command := testingexec.InitFakeCmd(fc, c, a...) 143 return command 144 } 145 } 146 147 func makeFakeOutput(output string, rc int) testingexec.FakeAction { 148 o := output 149 var e error 150 if rc != 0 { 151 e = testingexec.FakeExitError{Status: rc} 152 } 153 return func() ([]byte, []byte, error) { 154 return []byte(o), nil, e 155 } 156 } 157 158 func ProbeVolumePlugins(config volume.VolumeConfig) []volume.VolumePlugin { 159 if _, ok := config.OtherAttributes["fake-property"]; ok { 160 return []volume.VolumePlugin{ 161 &FakeVolumePlugin{ 162 PluginName: "fake-plugin", 163 Host: nil, 164 // SomeFakeProperty: config.OtherAttributes["fake-property"] -- string, may require parsing by plugin 165 }, 166 } 167 } 168 return []volume.VolumePlugin{&FakeVolumePlugin{PluginName: "fake-plugin"}} 169 } 170 171 // FakeVolumePlugin is useful for testing. It tries to be a fully compliant 172 // plugin, but all it does is make empty directories. 173 // Use as: 174 // 175 // volume.RegisterPlugin(&FakePlugin{"fake-name"}) 176 type FakeVolumePlugin struct { 177 sync.RWMutex 178 PluginName string 179 Host volume.VolumeHost 180 Config volume.VolumeConfig 181 LastProvisionerOptions volume.VolumeOptions 182 NewAttacherCallCount int 183 NewDetacherCallCount int 184 NodeExpandCallCount int 185 VolumeLimits map[string]int64 186 VolumeLimitsError error 187 LimitKey string 188 ProvisionDelaySeconds int 189 SupportsRemount bool 190 SupportsSELinux bool 191 DisableNodeExpansion bool 192 CanSupportFn func(*volume.Spec) bool 193 194 // default to false which means it is attachable by default 195 NonAttachable bool 196 197 // Add callbacks as needed 198 WaitForAttachHook func(spec *volume.Spec, devicePath string, pod *v1.Pod, spectimeout time.Duration) (string, error) 199 UnmountDeviceHook func(globalMountPath string) error 200 201 Mounters []*FakeVolume 202 Unmounters []*FakeVolume 203 Attachers []*FakeVolume 204 Detachers []*FakeVolume 205 BlockVolumeMappers []*FakeVolume 206 BlockVolumeUnmappers []*FakeVolume 207 } 208 209 var _ volume.VolumePlugin = &FakeVolumePlugin{} 210 var _ volume.BlockVolumePlugin = &FakeVolumePlugin{} 211 var _ volume.RecyclableVolumePlugin = &FakeVolumePlugin{} 212 var _ volume.DeletableVolumePlugin = &FakeVolumePlugin{} 213 var _ volume.ProvisionableVolumePlugin = &FakeVolumePlugin{} 214 var _ volume.AttachableVolumePlugin = &FakeVolumePlugin{} 215 var _ volume.VolumePluginWithAttachLimits = &FakeVolumePlugin{} 216 var _ volume.DeviceMountableVolumePlugin = &FakeVolumePlugin{} 217 var _ volume.NodeExpandableVolumePlugin = &FakeVolumePlugin{} 218 219 func (plugin *FakeVolumePlugin) getFakeVolume(list *[]*FakeVolume) *FakeVolume { 220 if list != nil { 221 volumeList := *list 222 if len(volumeList) > 0 { 223 volume := volumeList[0] 224 volume.Lock() 225 defer volume.Unlock() 226 volume.WaitForAttachHook = plugin.WaitForAttachHook 227 volume.UnmountDeviceHook = plugin.UnmountDeviceHook 228 return volume 229 } 230 } 231 volume := &FakeVolume{ 232 WaitForAttachHook: plugin.WaitForAttachHook, 233 UnmountDeviceHook: plugin.UnmountDeviceHook, 234 } 235 volume.VolumesAttached = make(map[string]sets.String) 236 volume.DeviceMountState = make(map[string]string) 237 volume.VolumeMountState = make(map[string]string) 238 if list != nil { 239 *list = append(*list, volume) 240 } 241 return volume 242 } 243 244 func (plugin *FakeVolumePlugin) Init(host volume.VolumeHost) error { 245 plugin.Lock() 246 defer plugin.Unlock() 247 plugin.Host = host 248 return nil 249 } 250 251 func (plugin *FakeVolumePlugin) GetPluginName() string { 252 plugin.RLock() 253 defer plugin.RUnlock() 254 return plugin.PluginName 255 } 256 257 func (plugin *FakeVolumePlugin) GetVolumeName(spec *volume.Spec) (string, error) { 258 var volumeName string 259 if spec.Volume != nil && spec.Volume.GCEPersistentDisk != nil { 260 volumeName = spec.Volume.GCEPersistentDisk.PDName 261 } else if spec.Volume != nil && spec.Volume.RBD != nil { 262 volumeName = spec.Volume.RBD.RBDImage 263 } else if spec.PersistentVolume != nil && 264 spec.PersistentVolume.Spec.GCEPersistentDisk != nil { 265 volumeName = spec.PersistentVolume.Spec.GCEPersistentDisk.PDName 266 } else if spec.PersistentVolume != nil && 267 spec.PersistentVolume.Spec.RBD != nil { 268 volumeName = spec.PersistentVolume.Spec.RBD.RBDImage 269 } else if spec.Volume != nil && spec.Volume.CSI != nil { 270 volumeName = spec.Volume.CSI.Driver 271 } 272 if volumeName == "" { 273 volumeName = spec.Name() 274 } 275 return volumeName, nil 276 } 277 278 func (plugin *FakeVolumePlugin) CanSupport(spec *volume.Spec) bool { 279 if plugin.CanSupportFn != nil { 280 return plugin.CanSupportFn(spec) 281 } 282 283 return true 284 } 285 286 func (plugin *FakeVolumePlugin) RequiresRemount(spec *volume.Spec) bool { 287 return plugin.SupportsRemount 288 } 289 290 func (plugin *FakeVolumePlugin) SupportsMountOption() bool { 291 return true 292 } 293 294 func (plugin *FakeVolumePlugin) SupportsBulkVolumeVerification() bool { 295 return false 296 } 297 298 func (plugin *FakeVolumePlugin) SupportsSELinuxContextMount(spec *volume.Spec) (bool, error) { 299 return plugin.SupportsSELinux, nil 300 } 301 302 func (plugin *FakeVolumePlugin) NewMounter(spec *volume.Spec, pod *v1.Pod, opts volume.VolumeOptions) (volume.Mounter, error) { 303 plugin.Lock() 304 defer plugin.Unlock() 305 if spec.Name() == FailNewMounter { 306 return nil, fmt.Errorf("AlwaysFailNewMounter") 307 } 308 fakeVolume := plugin.getFakeVolume(&plugin.Mounters) 309 fakeVolume.Lock() 310 defer fakeVolume.Unlock() 311 fakeVolume.PodUID = pod.UID 312 fakeVolume.VolName = spec.Name() 313 fakeVolume.Plugin = plugin 314 fakeVolume.MetricsNil = volume.MetricsNil{} 315 return fakeVolume, nil 316 } 317 318 func (plugin *FakeVolumePlugin) GetMounters() (Mounters []*FakeVolume) { 319 plugin.RLock() 320 defer plugin.RUnlock() 321 return plugin.Mounters 322 } 323 324 func (plugin *FakeVolumePlugin) NewUnmounter(volName string, podUID types.UID) (volume.Unmounter, error) { 325 plugin.Lock() 326 defer plugin.Unlock() 327 fakeVolume := plugin.getFakeVolume(&plugin.Unmounters) 328 fakeVolume.Lock() 329 defer fakeVolume.Unlock() 330 fakeVolume.PodUID = podUID 331 fakeVolume.VolName = volName 332 fakeVolume.Plugin = plugin 333 fakeVolume.MetricsNil = volume.MetricsNil{} 334 return fakeVolume, nil 335 } 336 337 func (plugin *FakeVolumePlugin) GetUnmounters() (Unmounters []*FakeVolume) { 338 plugin.RLock() 339 defer plugin.RUnlock() 340 return plugin.Unmounters 341 } 342 343 // Block volume support 344 func (plugin *FakeVolumePlugin) NewBlockVolumeMapper(spec *volume.Spec, pod *v1.Pod, opts volume.VolumeOptions) (volume.BlockVolumeMapper, error) { 345 plugin.Lock() 346 defer plugin.Unlock() 347 volume := plugin.getFakeVolume(&plugin.BlockVolumeMappers) 348 volume.Lock() 349 defer volume.Unlock() 350 if pod != nil { 351 volume.PodUID = pod.UID 352 } 353 volume.VolName = spec.Name() 354 volume.Plugin = plugin 355 return volume, nil 356 } 357 358 // Block volume support 359 func (plugin *FakeVolumePlugin) GetBlockVolumeMapper() (BlockVolumeMappers []*FakeVolume) { 360 plugin.RLock() 361 defer plugin.RUnlock() 362 return plugin.BlockVolumeMappers 363 } 364 365 // Block volume support 366 func (plugin *FakeVolumePlugin) NewBlockVolumeUnmapper(volName string, podUID types.UID) (volume.BlockVolumeUnmapper, error) { 367 plugin.Lock() 368 defer plugin.Unlock() 369 volume := plugin.getFakeVolume(&plugin.BlockVolumeUnmappers) 370 volume.Lock() 371 defer volume.Unlock() 372 volume.PodUID = podUID 373 volume.VolName = volName 374 volume.Plugin = plugin 375 return volume, nil 376 } 377 378 // Block volume support 379 func (plugin *FakeVolumePlugin) GetBlockVolumeUnmapper() (BlockVolumeUnmappers []*FakeVolume) { 380 plugin.RLock() 381 defer plugin.RUnlock() 382 return plugin.BlockVolumeUnmappers 383 } 384 385 func (plugin *FakeVolumePlugin) NewAttacher() (volume.Attacher, error) { 386 plugin.Lock() 387 defer plugin.Unlock() 388 plugin.NewAttacherCallCount = plugin.NewAttacherCallCount + 1 389 return plugin.getFakeVolume(&plugin.Attachers), nil 390 } 391 392 func (plugin *FakeVolumePlugin) NewDeviceMounter() (volume.DeviceMounter, error) { 393 return plugin.NewAttacher() 394 } 395 396 func (plugin *FakeVolumePlugin) GetAttachers() (Attachers []*FakeVolume) { 397 plugin.RLock() 398 defer plugin.RUnlock() 399 return plugin.Attachers 400 } 401 402 func (plugin *FakeVolumePlugin) GetNewAttacherCallCount() int { 403 plugin.RLock() 404 defer plugin.RUnlock() 405 return plugin.NewAttacherCallCount 406 } 407 408 func (plugin *FakeVolumePlugin) NewDetacher() (volume.Detacher, error) { 409 plugin.Lock() 410 defer plugin.Unlock() 411 plugin.NewDetacherCallCount = plugin.NewDetacherCallCount + 1 412 detacher := plugin.getFakeVolume(&plugin.Detachers) 413 attacherList := plugin.Attachers 414 if len(attacherList) > 0 { 415 detacherList := plugin.Detachers 416 if len(detacherList) > 0 { 417 detacherList[0].VolumesAttached = attacherList[0].VolumesAttached 418 } 419 420 } 421 return detacher, nil 422 } 423 424 func (plugin *FakeVolumePlugin) NewDeviceUnmounter() (volume.DeviceUnmounter, error) { 425 return plugin.NewDetacher() 426 } 427 428 func (plugin *FakeVolumePlugin) GetDetachers() (Detachers []*FakeVolume) { 429 plugin.RLock() 430 defer plugin.RUnlock() 431 return plugin.Detachers 432 } 433 434 func (plugin *FakeVolumePlugin) GetNewDetacherCallCount() int { 435 plugin.RLock() 436 defer plugin.RUnlock() 437 return plugin.NewDetacherCallCount 438 } 439 440 func (plugin *FakeVolumePlugin) CanAttach(spec *volume.Spec) (bool, error) { 441 return !plugin.NonAttachable, nil 442 } 443 444 func (plugin *FakeVolumePlugin) CanDeviceMount(spec *volume.Spec) (bool, error) { 445 return true, nil 446 } 447 448 func (plugin *FakeVolumePlugin) Recycle(pvName string, spec *volume.Spec, eventRecorder recyclerclient.RecycleEventRecorder) error { 449 return nil 450 } 451 452 func (plugin *FakeVolumePlugin) NewDeleter(logger klog.Logger, spec *volume.Spec) (volume.Deleter, error) { 453 return &FakeDeleter{"/attributesTransferredFromSpec", volume.MetricsNil{}}, nil 454 } 455 456 func (plugin *FakeVolumePlugin) NewProvisioner(logger klog.Logger, options volume.VolumeOptions) (volume.Provisioner, error) { 457 plugin.Lock() 458 defer plugin.Unlock() 459 plugin.LastProvisionerOptions = options 460 return &FakeProvisioner{options, plugin.Host, plugin.ProvisionDelaySeconds}, nil 461 } 462 463 func (plugin *FakeVolumePlugin) GetAccessModes() []v1.PersistentVolumeAccessMode { 464 return []v1.PersistentVolumeAccessMode{} 465 } 466 467 func (plugin *FakeVolumePlugin) ConstructVolumeSpec(volumeName, mountPath string) (volume.ReconstructedVolume, error) { 468 return volume.ReconstructedVolume{ 469 Spec: &volume.Spec{ 470 Volume: &v1.Volume{ 471 Name: volumeName, 472 }, 473 }, 474 }, nil 475 } 476 477 // Block volume support 478 func (plugin *FakeVolumePlugin) ConstructBlockVolumeSpec(podUID types.UID, volumeName, mountPath string) (*volume.Spec, error) { 479 return &volume.Spec{ 480 Volume: &v1.Volume{ 481 Name: volumeName, 482 }, 483 }, nil 484 } 485 486 func (plugin *FakeVolumePlugin) GetDeviceMountRefs(deviceMountPath string) ([]string, error) { 487 return []string{}, nil 488 } 489 490 // Expandable volume support 491 func (plugin *FakeVolumePlugin) ExpandVolumeDevice(spec *volume.Spec, newSize resource.Quantity, oldSize resource.Quantity) (resource.Quantity, error) { 492 return resource.Quantity{}, nil 493 } 494 495 func (plugin *FakeVolumePlugin) RequiresFSResize() bool { 496 return !plugin.DisableNodeExpansion 497 } 498 499 func (plugin *FakeVolumePlugin) NodeExpand(resizeOptions volume.NodeResizeOptions) (bool, error) { 500 plugin.NodeExpandCallCount++ 501 if resizeOptions.VolumeSpec.Name() == FailWithInUseVolumeName { 502 return false, volumetypes.NewFailedPreconditionError("volume-in-use") 503 } 504 if resizeOptions.VolumeSpec.Name() == FailWithUnSupportedVolumeName { 505 return false, volumetypes.NewOperationNotSupportedError("volume-unsupported") 506 } 507 508 if resizeOptions.VolumeSpec.Name() == AlwaysFailNodeExpansion { 509 return false, fmt.Errorf("test failure: NodeExpand") 510 } 511 512 if resizeOptions.VolumeSpec.Name() == FailVolumeExpansion { 513 return false, fmt.Errorf("fail volume expansion for volume: %s", FailVolumeExpansion) 514 } 515 return true, nil 516 } 517 518 func (plugin *FakeVolumePlugin) GetVolumeLimits() (map[string]int64, error) { 519 return plugin.VolumeLimits, plugin.VolumeLimitsError 520 } 521 522 func (plugin *FakeVolumePlugin) VolumeLimitKey(spec *volume.Spec) string { 523 return plugin.LimitKey 524 } 525 526 // FakeBasicVolumePlugin implements a basic volume plugin. It wrappers on 527 // FakeVolumePlugin but implements VolumePlugin interface only. 528 // It is useful to test logic involving plugin interfaces. 529 type FakeBasicVolumePlugin struct { 530 Plugin FakeVolumePlugin 531 } 532 533 func (f *FakeBasicVolumePlugin) GetPluginName() string { 534 return f.Plugin.GetPluginName() 535 } 536 537 func (f *FakeBasicVolumePlugin) GetVolumeName(spec *volume.Spec) (string, error) { 538 return f.Plugin.GetVolumeName(spec) 539 } 540 541 // CanSupport tests whether the plugin supports a given volume specification by 542 // testing volume spec name begins with plugin name or not. 543 // This is useful to choose plugin by volume in testing. 544 func (f *FakeBasicVolumePlugin) CanSupport(spec *volume.Spec) bool { 545 return strings.HasPrefix(spec.Name(), f.GetPluginName()) 546 } 547 548 func (f *FakeBasicVolumePlugin) ConstructVolumeSpec(ame, mountPath string) (volume.ReconstructedVolume, error) { 549 return f.Plugin.ConstructVolumeSpec(ame, mountPath) 550 } 551 552 func (f *FakeBasicVolumePlugin) Init(ost volume.VolumeHost) error { 553 return f.Plugin.Init(ost) 554 } 555 556 func (f *FakeBasicVolumePlugin) NewMounter(spec *volume.Spec, pod *v1.Pod, opts volume.VolumeOptions) (volume.Mounter, error) { 557 return f.Plugin.NewMounter(spec, pod, opts) 558 } 559 560 func (f *FakeBasicVolumePlugin) NewUnmounter(volName string, podUID types.UID) (volume.Unmounter, error) { 561 return f.Plugin.NewUnmounter(volName, podUID) 562 } 563 564 func (f *FakeBasicVolumePlugin) RequiresRemount(spec *volume.Spec) bool { 565 return f.Plugin.RequiresRemount(spec) 566 } 567 568 func (f *FakeBasicVolumePlugin) SupportsBulkVolumeVerification() bool { 569 return f.Plugin.SupportsBulkVolumeVerification() 570 } 571 572 func (f *FakeBasicVolumePlugin) SupportsSELinuxContextMount(spec *volume.Spec) (bool, error) { 573 return f.Plugin.SupportsSELinuxContextMount(spec) 574 } 575 576 func (f *FakeBasicVolumePlugin) SupportsMountOption() bool { 577 return f.Plugin.SupportsMountOption() 578 } 579 580 var _ volume.VolumePlugin = &FakeBasicVolumePlugin{} 581 582 // FakeDeviceMountableVolumePlugin implements an device mountable plugin based on FakeBasicVolumePlugin. 583 type FakeDeviceMountableVolumePlugin struct { 584 FakeBasicVolumePlugin 585 } 586 587 func (f *FakeDeviceMountableVolumePlugin) CanDeviceMount(spec *volume.Spec) (bool, error) { 588 return true, nil 589 } 590 591 func (f *FakeDeviceMountableVolumePlugin) NewDeviceMounter() (volume.DeviceMounter, error) { 592 return f.Plugin.NewDeviceMounter() 593 } 594 595 func (f *FakeDeviceMountableVolumePlugin) NewDeviceUnmounter() (volume.DeviceUnmounter, error) { 596 return f.Plugin.NewDeviceUnmounter() 597 } 598 599 func (f *FakeDeviceMountableVolumePlugin) GetDeviceMountRefs(deviceMountPath string) ([]string, error) { 600 return f.Plugin.GetDeviceMountRefs(deviceMountPath) 601 } 602 603 var _ volume.VolumePlugin = &FakeDeviceMountableVolumePlugin{} 604 var _ volume.DeviceMountableVolumePlugin = &FakeDeviceMountableVolumePlugin{} 605 606 // FakeAttachableVolumePlugin implements an attachable plugin based on FakeDeviceMountableVolumePlugin. 607 type FakeAttachableVolumePlugin struct { 608 FakeDeviceMountableVolumePlugin 609 } 610 611 func (f *FakeAttachableVolumePlugin) NewAttacher() (volume.Attacher, error) { 612 return f.Plugin.NewAttacher() 613 } 614 615 func (f *FakeAttachableVolumePlugin) NewDetacher() (volume.Detacher, error) { 616 return f.Plugin.NewDetacher() 617 } 618 619 func (f *FakeAttachableVolumePlugin) CanAttach(spec *volume.Spec) (bool, error) { 620 return true, nil 621 } 622 623 var _ volume.VolumePlugin = &FakeAttachableVolumePlugin{} 624 var _ volume.AttachableVolumePlugin = &FakeAttachableVolumePlugin{} 625 626 type FakeFileVolumePlugin struct { 627 } 628 629 func (plugin *FakeFileVolumePlugin) Init(host volume.VolumeHost) error { 630 return nil 631 } 632 633 func (plugin *FakeFileVolumePlugin) GetPluginName() string { 634 return "fake-file-plugin" 635 } 636 637 func (plugin *FakeFileVolumePlugin) GetVolumeName(spec *volume.Spec) (string, error) { 638 return "", nil 639 } 640 641 func (plugin *FakeFileVolumePlugin) CanSupport(spec *volume.Spec) bool { 642 return true 643 } 644 645 func (plugin *FakeFileVolumePlugin) RequiresRemount(spec *volume.Spec) bool { 646 return false 647 } 648 649 func (plugin *FakeFileVolumePlugin) SupportsMountOption() bool { 650 return false 651 } 652 653 func (plugin *FakeFileVolumePlugin) SupportsBulkVolumeVerification() bool { 654 return false 655 } 656 657 func (plugin *FakeFileVolumePlugin) SupportsSELinuxContextMount(spec *volume.Spec) (bool, error) { 658 return false, nil 659 } 660 661 func (plugin *FakeFileVolumePlugin) NewMounter(spec *volume.Spec, podRef *v1.Pod, opts volume.VolumeOptions) (volume.Mounter, error) { 662 return nil, nil 663 } 664 665 func (plugin *FakeFileVolumePlugin) NewUnmounter(name string, podUID types.UID) (volume.Unmounter, error) { 666 return nil, nil 667 } 668 669 func (plugin *FakeFileVolumePlugin) ConstructVolumeSpec(volumeName, mountPath string) (volume.ReconstructedVolume, error) { 670 return volume.ReconstructedVolume{}, nil 671 } 672 673 func NewFakeFileVolumePlugin() []volume.VolumePlugin { 674 return []volume.VolumePlugin{&FakeFileVolumePlugin{}} 675 } 676 677 type FakeVolume struct { 678 sync.RWMutex 679 PodUID types.UID 680 VolName string 681 Plugin *FakeVolumePlugin 682 volume.MetricsNil 683 VolumesAttached map[string]sets.String 684 DeviceMountState map[string]string 685 VolumeMountState map[string]string 686 687 // Add callbacks as needed 688 WaitForAttachHook func(spec *volume.Spec, devicePath string, pod *v1.Pod, spectimeout time.Duration) (string, error) 689 UnmountDeviceHook func(globalMountPath string) error 690 691 SetUpCallCount int 692 TearDownCallCount int 693 AttachCallCount int 694 DetachCallCount int 695 WaitForAttachCallCount int 696 MountDeviceCallCount int 697 UnmountDeviceCallCount int 698 GetDeviceMountPathCallCount int 699 SetUpDeviceCallCount int 700 TearDownDeviceCallCount int 701 MapPodDeviceCallCount int 702 UnmapPodDeviceCallCount int 703 GlobalMapPathCallCount int 704 PodDeviceMapPathCallCount int 705 } 706 707 func getUniqueVolumeName(spec *volume.Spec) (string, error) { 708 var volumeName string 709 if spec.Volume != nil && spec.Volume.GCEPersistentDisk != nil { 710 volumeName = spec.Volume.GCEPersistentDisk.PDName 711 } else if spec.Volume != nil && spec.Volume.RBD != nil { 712 volumeName = spec.Volume.RBD.RBDImage 713 } else if spec.PersistentVolume != nil && 714 spec.PersistentVolume.Spec.GCEPersistentDisk != nil { 715 volumeName = spec.PersistentVolume.Spec.GCEPersistentDisk.PDName 716 } else if spec.PersistentVolume != nil && 717 spec.PersistentVolume.Spec.RBD != nil { 718 volumeName = spec.PersistentVolume.Spec.RBD.RBDImage 719 } 720 if volumeName == "" { 721 volumeName = spec.Name() 722 } 723 return volumeName, nil 724 } 725 726 func (_ *FakeVolume) GetAttributes() volume.Attributes { 727 return volume.Attributes{ 728 ReadOnly: false, 729 Managed: true, 730 SELinuxRelabel: true, 731 } 732 } 733 734 func (fv *FakeVolume) SetUp(mounterArgs volume.MounterArgs) error { 735 fv.Lock() 736 defer fv.Unlock() 737 err := fv.setupInternal(mounterArgs) 738 fv.SetUpCallCount++ 739 return err 740 } 741 742 func (fv *FakeVolume) setupInternal(mounterArgs volume.MounterArgs) error { 743 if fv.VolName == TimeoutOnSetupVolumeName { 744 fv.VolumeMountState[fv.VolName] = volumeMountUncertain 745 return volumetypes.NewUncertainProgressError("time out on setup") 746 } 747 748 if fv.VolName == FailOnSetupVolumeName { 749 fv.VolumeMountState[fv.VolName] = volumeNotMounted 750 return fmt.Errorf("mounting volume failed") 751 } 752 753 if fv.VolName == TimeoutAndFailOnSetupVolumeName { 754 _, ok := fv.VolumeMountState[fv.VolName] 755 if !ok { 756 fv.VolumeMountState[fv.VolName] = volumeMountUncertain 757 return volumetypes.NewUncertainProgressError("time out on setup") 758 } 759 fv.VolumeMountState[fv.VolName] = volumeNotMounted 760 return fmt.Errorf("mounting volume failed") 761 762 } 763 764 if fv.VolName == SuccessAndFailOnSetupVolumeName { 765 _, ok := fv.VolumeMountState[fv.VolName] 766 if ok { 767 fv.VolumeMountState[fv.VolName] = volumeNotMounted 768 return fmt.Errorf("mounting volume failed") 769 } 770 } 771 772 if fv.VolName == SuccessAndTimeoutSetupVolumeName { 773 _, ok := fv.VolumeMountState[fv.VolName] 774 if ok { 775 fv.VolumeMountState[fv.VolName] = volumeMountUncertain 776 return volumetypes.NewUncertainProgressError("time out on setup") 777 } 778 } 779 780 fv.VolumeMountState[fv.VolName] = volumeNotMounted 781 return fv.SetUpAt(fv.getPath(), mounterArgs) 782 } 783 784 func (fv *FakeVolume) GetSetUpCallCount() int { 785 fv.RLock() 786 defer fv.RUnlock() 787 return fv.SetUpCallCount 788 } 789 790 func (fv *FakeVolume) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { 791 return os.MkdirAll(dir, 0750) 792 } 793 794 func (fv *FakeVolume) GetPath() string { 795 fv.RLock() 796 defer fv.RUnlock() 797 return fv.getPath() 798 } 799 800 func (fv *FakeVolume) getPath() string { 801 return filepath.Join(fv.Plugin.Host.GetPodVolumeDir(fv.PodUID, utilstrings.EscapeQualifiedName(fv.Plugin.PluginName), fv.VolName)) 802 } 803 804 func (fv *FakeVolume) TearDown() error { 805 fv.Lock() 806 defer fv.Unlock() 807 fv.TearDownCallCount++ 808 return fv.TearDownAt(fv.getPath()) 809 } 810 811 func (fv *FakeVolume) GetTearDownCallCount() int { 812 fv.RLock() 813 defer fv.RUnlock() 814 return fv.TearDownCallCount 815 } 816 817 func (fv *FakeVolume) TearDownAt(dir string) error { 818 return os.RemoveAll(dir) 819 } 820 821 // Block volume support 822 func (fv *FakeVolume) SetUpDevice() (string, error) { 823 fv.Lock() 824 defer fv.Unlock() 825 if fv.VolName == TimeoutOnMountDeviceVolumeName { 826 fv.DeviceMountState[fv.VolName] = deviceMountUncertain 827 return "", volumetypes.NewUncertainProgressError("mount failed") 828 } 829 if fv.VolName == FailMountDeviceVolumeName { 830 fv.DeviceMountState[fv.VolName] = deviceNotMounted 831 return "", fmt.Errorf("error mapping disk: %s", fv.VolName) 832 } 833 834 if fv.VolName == TimeoutAndFailOnMountDeviceVolumeName { 835 _, ok := fv.DeviceMountState[fv.VolName] 836 if !ok { 837 fv.DeviceMountState[fv.VolName] = deviceMountUncertain 838 return "", volumetypes.NewUncertainProgressError("timed out mounting error") 839 } 840 fv.DeviceMountState[fv.VolName] = deviceNotMounted 841 return "", fmt.Errorf("error mapping disk: %s", fv.VolName) 842 } 843 844 if fv.VolName == SuccessAndTimeoutDeviceName { 845 _, ok := fv.DeviceMountState[fv.VolName] 846 if ok { 847 fv.DeviceMountState[fv.VolName] = deviceMountUncertain 848 return "", volumetypes.NewUncertainProgressError("error mounting state") 849 } 850 } 851 if fv.VolName == SuccessAndFailOnMountDeviceName { 852 _, ok := fv.DeviceMountState[fv.VolName] 853 if ok { 854 return "", fmt.Errorf("error mapping disk: %s", fv.VolName) 855 } 856 } 857 858 fv.DeviceMountState[fv.VolName] = deviceMounted 859 fv.SetUpDeviceCallCount++ 860 861 return "", nil 862 } 863 864 func (fv *FakeVolume) GetStagingPath() string { 865 return filepath.Join(fv.Plugin.Host.GetVolumeDevicePluginDir(utilstrings.EscapeQualifiedName(fv.Plugin.PluginName)), "staging", fv.VolName) 866 } 867 868 // Block volume support 869 func (fv *FakeVolume) GetSetUpDeviceCallCount() int { 870 fv.RLock() 871 defer fv.RUnlock() 872 return fv.SetUpDeviceCallCount 873 } 874 875 // Block volume support 876 func (fv *FakeVolume) GetGlobalMapPath(spec *volume.Spec) (string, error) { 877 fv.Lock() 878 defer fv.Unlock() 879 fv.GlobalMapPathCallCount++ 880 return fv.getGlobalMapPath() 881 } 882 883 // Block volume support 884 func (fv *FakeVolume) getGlobalMapPath() (string, error) { 885 return filepath.Join(fv.Plugin.Host.GetVolumeDevicePluginDir(utilstrings.EscapeQualifiedName(fv.Plugin.PluginName)), "pluginDependentPath"), nil 886 } 887 888 // Block volume support 889 func (fv *FakeVolume) GetGlobalMapPathCallCount() int { 890 fv.RLock() 891 defer fv.RUnlock() 892 return fv.GlobalMapPathCallCount 893 } 894 895 // Block volume support 896 func (fv *FakeVolume) GetPodDeviceMapPath() (string, string) { 897 fv.RLock() 898 defer fv.RUnlock() 899 fv.PodDeviceMapPathCallCount++ 900 return fv.getPodDeviceMapPath() 901 } 902 903 // Block volume support 904 func (fv *FakeVolume) getPodDeviceMapPath() (string, string) { 905 return filepath.Join(fv.Plugin.Host.GetPodVolumeDeviceDir(fv.PodUID, utilstrings.EscapeQualifiedName(fv.Plugin.PluginName))), fv.VolName 906 } 907 908 // Block volume support 909 func (fv *FakeVolume) GetPodDeviceMapPathCallCount() int { 910 fv.RLock() 911 defer fv.RUnlock() 912 return fv.PodDeviceMapPathCallCount 913 } 914 915 // Block volume support 916 func (fv *FakeVolume) TearDownDevice(mapPath string, devicePath string) error { 917 fv.Lock() 918 defer fv.Unlock() 919 fv.TearDownDeviceCallCount++ 920 return nil 921 } 922 923 // Block volume support 924 func (fv *FakeVolume) GetTearDownDeviceCallCount() int { 925 fv.RLock() 926 defer fv.RUnlock() 927 return fv.TearDownDeviceCallCount 928 } 929 930 // Block volume support 931 func (fv *FakeVolume) UnmapPodDevice() error { 932 fv.Lock() 933 defer fv.Unlock() 934 fv.UnmapPodDeviceCallCount++ 935 return nil 936 } 937 938 // Block volume support 939 func (fv *FakeVolume) GetUnmapPodDeviceCallCount() int { 940 fv.RLock() 941 defer fv.RUnlock() 942 return fv.UnmapPodDeviceCallCount 943 } 944 945 // Block volume support 946 func (fv *FakeVolume) MapPodDevice() (string, error) { 947 fv.Lock() 948 defer fv.Unlock() 949 950 if fv.VolName == TimeoutOnSetupVolumeName { 951 fv.VolumeMountState[fv.VolName] = volumeMountUncertain 952 return "", volumetypes.NewUncertainProgressError("time out on setup") 953 } 954 955 if fv.VolName == FailOnSetupVolumeName { 956 fv.VolumeMountState[fv.VolName] = volumeNotMounted 957 return "", fmt.Errorf("mounting volume failed") 958 } 959 960 if fv.VolName == TimeoutAndFailOnSetupVolumeName { 961 _, ok := fv.VolumeMountState[fv.VolName] 962 if !ok { 963 fv.VolumeMountState[fv.VolName] = volumeMountUncertain 964 return "", volumetypes.NewUncertainProgressError("time out on setup") 965 } 966 fv.VolumeMountState[fv.VolName] = volumeNotMounted 967 return "", fmt.Errorf("mounting volume failed") 968 969 } 970 971 if fv.VolName == SuccessAndFailOnSetupVolumeName { 972 _, ok := fv.VolumeMountState[fv.VolName] 973 if ok { 974 fv.VolumeMountState[fv.VolName] = volumeNotMounted 975 return "", fmt.Errorf("mounting volume failed") 976 } 977 } 978 979 if fv.VolName == SuccessAndTimeoutSetupVolumeName { 980 _, ok := fv.VolumeMountState[fv.VolName] 981 if ok { 982 fv.VolumeMountState[fv.VolName] = volumeMountUncertain 983 return "", volumetypes.NewUncertainProgressError("time out on setup") 984 } 985 } 986 987 fv.VolumeMountState[fv.VolName] = volumeMounted 988 fv.MapPodDeviceCallCount++ 989 return "", nil 990 } 991 992 // Block volume support 993 func (fv *FakeVolume) GetMapPodDeviceCallCount() int { 994 fv.RLock() 995 defer fv.RUnlock() 996 return fv.MapPodDeviceCallCount 997 } 998 999 func (fv *FakeVolume) Attach(spec *volume.Spec, nodeName types.NodeName) (string, error) { 1000 fv.Lock() 1001 defer fv.Unlock() 1002 fv.AttachCallCount++ 1003 1004 volumeName, err := getUniqueVolumeName(spec) 1005 if err != nil { 1006 return "", err 1007 } 1008 volumeNodes, exist := fv.VolumesAttached[volumeName] 1009 if exist { 1010 if nodeName == UncertainAttachNode { 1011 return "/dev/vdb-test", nil 1012 } 1013 // even if volume was previously attached to time out, we need to keep returning error 1014 // so as reconciler can not confirm this volume as attached. 1015 if nodeName == TimeoutAttachNode { 1016 return "", fmt.Errorf("timed out to attach volume %q to node %q", volumeName, nodeName) 1017 } 1018 if volumeNodes.Has(string(nodeName)) || volumeNodes.Has(MultiAttachNode) || nodeName == MultiAttachNode { 1019 volumeNodes.Insert(string(nodeName)) 1020 return "/dev/vdb-test", nil 1021 } 1022 return "", fmt.Errorf("volume %q trying to attach to node %q is already attached to node %q", volumeName, nodeName, volumeNodes) 1023 } 1024 1025 fv.VolumesAttached[volumeName] = sets.NewString(string(nodeName)) 1026 if nodeName == UncertainAttachNode || nodeName == TimeoutAttachNode { 1027 return "", fmt.Errorf("timed out to attach volume %q to node %q", volumeName, nodeName) 1028 } 1029 return "/dev/vdb-test", nil 1030 } 1031 1032 func (fv *FakeVolume) GetAttachCallCount() int { 1033 fv.RLock() 1034 defer fv.RUnlock() 1035 return fv.AttachCallCount 1036 } 1037 1038 func (fv *FakeVolume) WaitForAttach(spec *volume.Spec, devicePath string, pod *v1.Pod, spectimeout time.Duration) (string, error) { 1039 fv.Lock() 1040 defer fv.Unlock() 1041 fv.WaitForAttachCallCount++ 1042 if fv.WaitForAttachHook != nil { 1043 return fv.WaitForAttachHook(spec, devicePath, pod, spectimeout) 1044 } 1045 return "/dev/sdb", nil 1046 } 1047 1048 func (fv *FakeVolume) GetWaitForAttachCallCount() int { 1049 fv.RLock() 1050 defer fv.RUnlock() 1051 return fv.WaitForAttachCallCount 1052 } 1053 1054 func (fv *FakeVolume) GetDeviceMountPath(spec *volume.Spec) (string, error) { 1055 fv.Lock() 1056 defer fv.Unlock() 1057 fv.GetDeviceMountPathCallCount++ 1058 return "", nil 1059 } 1060 1061 func (fv *FakeVolume) mountDeviceInternal(spec *volume.Spec, devicePath string, deviceMountPath string) error { 1062 fv.Lock() 1063 defer fv.Unlock() 1064 if spec.Name() == TimeoutOnMountDeviceVolumeName { 1065 fv.DeviceMountState[spec.Name()] = deviceMountUncertain 1066 return volumetypes.NewUncertainProgressError("mount failed") 1067 } 1068 1069 if spec.Name() == FailMountDeviceVolumeName { 1070 fv.DeviceMountState[spec.Name()] = deviceNotMounted 1071 return fmt.Errorf("error mounting disk: %s", devicePath) 1072 } 1073 1074 if spec.Name() == TimeoutAndFailOnMountDeviceVolumeName { 1075 _, ok := fv.DeviceMountState[spec.Name()] 1076 if !ok { 1077 fv.DeviceMountState[spec.Name()] = deviceMountUncertain 1078 return volumetypes.NewUncertainProgressError("timed out mounting error") 1079 } 1080 fv.DeviceMountState[spec.Name()] = deviceNotMounted 1081 return fmt.Errorf("error mounting disk: %s", devicePath) 1082 } 1083 1084 if spec.Name() == SuccessAndTimeoutDeviceName { 1085 _, ok := fv.DeviceMountState[spec.Name()] 1086 if ok { 1087 fv.DeviceMountState[spec.Name()] = deviceMountUncertain 1088 return volumetypes.NewUncertainProgressError("error mounting state") 1089 } 1090 } 1091 1092 if spec.Name() == SuccessAndFailOnMountDeviceName { 1093 _, ok := fv.DeviceMountState[spec.Name()] 1094 if ok { 1095 return fmt.Errorf("error mounting disk: %s", devicePath) 1096 } 1097 } 1098 fv.DeviceMountState[spec.Name()] = deviceMounted 1099 fv.MountDeviceCallCount++ 1100 return nil 1101 } 1102 1103 func (fv *FakeVolume) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string, _ volume.DeviceMounterArgs) error { 1104 return fv.mountDeviceInternal(spec, devicePath, deviceMountPath) 1105 } 1106 1107 func (fv *FakeVolume) GetMountDeviceCallCount() int { 1108 fv.RLock() 1109 defer fv.RUnlock() 1110 return fv.MountDeviceCallCount 1111 } 1112 1113 func (fv *FakeVolume) GetUnmountDeviceCallCount() int { 1114 fv.RLock() 1115 defer fv.RUnlock() 1116 return fv.UnmountDeviceCallCount 1117 } 1118 1119 func (fv *FakeVolume) Detach(volumeName string, nodeName types.NodeName) error { 1120 fv.Lock() 1121 defer fv.Unlock() 1122 1123 node := string(nodeName) 1124 volumeNodes, exist := fv.VolumesAttached[volumeName] 1125 if !exist || !volumeNodes.Has(node) { 1126 return fmt.Errorf("trying to detach volume %q that is not attached to the node %q", volumeName, node) 1127 } 1128 1129 fv.DetachCallCount++ 1130 if nodeName == FailDetachNode { 1131 return fmt.Errorf("fail to detach volume %q to node %q", volumeName, nodeName) 1132 } 1133 1134 volumeNodes.Delete(node) 1135 if volumeNodes.Len() == 0 { 1136 delete(fv.VolumesAttached, volumeName) 1137 } 1138 1139 return nil 1140 } 1141 1142 func (fv *FakeVolume) VolumesAreAttached(spec []*volume.Spec, nodeName types.NodeName) (map[*volume.Spec]bool, error) { 1143 fv.Lock() 1144 defer fv.Unlock() 1145 return nil, nil 1146 } 1147 1148 func (fv *FakeVolume) GetDetachCallCount() int { 1149 fv.RLock() 1150 defer fv.RUnlock() 1151 return fv.DetachCallCount 1152 } 1153 1154 func (fv *FakeVolume) UnmountDevice(globalMountPath string) error { 1155 fv.Lock() 1156 defer fv.Unlock() 1157 fv.UnmountDeviceCallCount++ 1158 if fv.UnmountDeviceHook != nil { 1159 return fv.UnmountDeviceHook(globalMountPath) 1160 } 1161 return nil 1162 } 1163 1164 type FakeDeleter struct { 1165 path string 1166 volume.MetricsNil 1167 } 1168 1169 func (fd *FakeDeleter) Delete() error { 1170 // nil is success, else error 1171 return nil 1172 } 1173 1174 func (fd *FakeDeleter) GetPath() string { 1175 return fd.path 1176 } 1177 1178 type FakeProvisioner struct { 1179 Options volume.VolumeOptions 1180 Host volume.VolumeHost 1181 ProvisionDelaySeconds int 1182 } 1183 1184 func (fc *FakeProvisioner) Provision(selectedNode *v1.Node, allowedTopologies []v1.TopologySelectorTerm) (*v1.PersistentVolume, error) { 1185 // Add provision failure hook 1186 if fc.Options.Parameters != nil { 1187 if _, ok := fc.Options.Parameters[ExpectProvisionFailureKey]; ok { 1188 return nil, fmt.Errorf("expected error") 1189 } 1190 } 1191 fullpath := fmt.Sprintf("/%s/hostpath_pv/%s", os.TempDir(), uuid.NewUUID()) 1192 1193 pv := &v1.PersistentVolume{ 1194 ObjectMeta: metav1.ObjectMeta{ 1195 Name: fc.Options.PVName, 1196 Annotations: map[string]string{ 1197 util.VolumeDynamicallyCreatedByKey: "fakeplugin-provisioner", 1198 }, 1199 }, 1200 Spec: v1.PersistentVolumeSpec{ 1201 PersistentVolumeReclaimPolicy: fc.Options.PersistentVolumeReclaimPolicy, 1202 AccessModes: fc.Options.PVC.Spec.AccessModes, 1203 Capacity: v1.ResourceList{ 1204 v1.ResourceName(v1.ResourceStorage): fc.Options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)], 1205 }, 1206 PersistentVolumeSource: v1.PersistentVolumeSource{ 1207 HostPath: &v1.HostPathVolumeSource{ 1208 Path: fullpath, 1209 }, 1210 }, 1211 }, 1212 } 1213 1214 if fc.ProvisionDelaySeconds > 0 { 1215 time.Sleep(time.Duration(fc.ProvisionDelaySeconds) * time.Second) 1216 } 1217 1218 return pv, nil 1219 } 1220 1221 var _ volumepathhandler.BlockVolumePathHandler = &FakeVolumePathHandler{} 1222 1223 // NewDeviceHandler Create a new IoHandler implementation 1224 func NewBlockVolumePathHandler() volumepathhandler.BlockVolumePathHandler { 1225 return &FakeVolumePathHandler{} 1226 } 1227 1228 type FakeVolumePathHandler struct { 1229 sync.RWMutex 1230 } 1231 1232 func (fv *FakeVolumePathHandler) MapDevice(devicePath string, mapDir string, linkName string, bindMount bool) error { 1233 // nil is success, else error 1234 return nil 1235 } 1236 1237 func (fv *FakeVolumePathHandler) UnmapDevice(mapDir string, linkName string, bindMount bool) error { 1238 // nil is success, else error 1239 return nil 1240 } 1241 1242 func (fv *FakeVolumePathHandler) RemoveMapPath(mapPath string) error { 1243 // nil is success, else error 1244 return nil 1245 } 1246 1247 func (fv *FakeVolumePathHandler) IsSymlinkExist(mapPath string) (bool, error) { 1248 // nil is success, else error 1249 return true, nil 1250 } 1251 1252 func (fv *FakeVolumePathHandler) IsDeviceBindMountExist(mapPath string) (bool, error) { 1253 // nil is success, else error 1254 return true, nil 1255 } 1256 1257 func (fv *FakeVolumePathHandler) GetDeviceBindMountRefs(devPath string, mapPath string) ([]string, error) { 1258 // nil is success, else error 1259 return []string{}, nil 1260 } 1261 1262 func (fv *FakeVolumePathHandler) FindGlobalMapPathUUIDFromPod(pluginDir, mapPath string, podUID types.UID) (string, error) { 1263 // nil is success, else error 1264 return "", nil 1265 } 1266 1267 func (fv *FakeVolumePathHandler) AttachFileDevice(path string) (string, error) { 1268 // nil is success, else error 1269 return "", nil 1270 } 1271 1272 func (fv *FakeVolumePathHandler) DetachFileDevice(path string) error { 1273 // nil is success, else error 1274 return nil 1275 } 1276 1277 func (fv *FakeVolumePathHandler) GetLoopDevice(path string) (string, error) { 1278 // nil is success, else error 1279 return "/dev/loop1", nil 1280 } 1281 1282 // FindEmptyDirectoryUsageOnTmpfs finds the expected usage of an empty directory existing on 1283 // a tmpfs filesystem on this system. 1284 func FindEmptyDirectoryUsageOnTmpfs() (*resource.Quantity, error) { 1285 // The command below does not exist on Windows. Additionally, empty folders have size 0 on Windows. 1286 if goruntime.GOOS == "windows" { 1287 used, err := resource.ParseQuantity("0") 1288 return &used, err 1289 } 1290 tmpDir, err := utiltesting.MkTmpdir("metrics_du_test") 1291 if err != nil { 1292 return nil, err 1293 } 1294 defer os.RemoveAll(tmpDir) 1295 out, err := exec.New().Command("nice", "-n", "19", "du", "-x", "-s", "-B", "1", tmpDir).CombinedOutput() 1296 if err != nil { 1297 return nil, fmt.Errorf("failed command 'du' on %s with error %v", tmpDir, err) 1298 } 1299 used, err := resource.ParseQuantity(strings.Fields(string(out))[0]) 1300 if err != nil { 1301 return nil, fmt.Errorf("failed to parse 'du' output %s due to error %v", out, err) 1302 } 1303 used.Format = resource.BinarySI 1304 return &used, nil 1305 } 1306 1307 // VerifyAttachCallCount ensures that at least one of the Attachers for this 1308 // plugin has the expectedAttachCallCount number of calls. Otherwise it returns 1309 // an error. 1310 func VerifyAttachCallCount( 1311 expectedAttachCallCount int, 1312 fakeVolumePlugin *FakeVolumePlugin) error { 1313 for _, attacher := range fakeVolumePlugin.GetAttachers() { 1314 actualCallCount := attacher.GetAttachCallCount() 1315 if actualCallCount >= expectedAttachCallCount { 1316 return nil 1317 } 1318 } 1319 1320 return fmt.Errorf( 1321 "No attachers have expected AttachCallCount. Expected: <%v>.", 1322 expectedAttachCallCount) 1323 } 1324 1325 // VerifyZeroAttachCalls ensures that all of the Attachers for this plugin have 1326 // a zero AttachCallCount. Otherwise it returns an error. 1327 func VerifyZeroAttachCalls(fakeVolumePlugin *FakeVolumePlugin) error { 1328 for _, attacher := range fakeVolumePlugin.GetAttachers() { 1329 actualCallCount := attacher.GetAttachCallCount() 1330 if actualCallCount != 0 { 1331 return fmt.Errorf( 1332 "At least one attacher has non-zero AttachCallCount: <%v>.", 1333 actualCallCount) 1334 } 1335 } 1336 1337 return nil 1338 } 1339 1340 // VerifyWaitForAttachCallCount ensures that at least one of the Mounters for 1341 // this plugin has the expectedWaitForAttachCallCount number of calls. Otherwise 1342 // it returns an error. 1343 func VerifyWaitForAttachCallCount( 1344 expectedWaitForAttachCallCount int, 1345 fakeVolumePlugin *FakeVolumePlugin) error { 1346 for _, attacher := range fakeVolumePlugin.GetAttachers() { 1347 actualCallCount := attacher.GetWaitForAttachCallCount() 1348 if actualCallCount >= expectedWaitForAttachCallCount { 1349 return nil 1350 } 1351 } 1352 1353 return fmt.Errorf( 1354 "No Attachers have expected WaitForAttachCallCount. Expected: <%v>.", 1355 expectedWaitForAttachCallCount) 1356 } 1357 1358 // VerifyZeroWaitForAttachCallCount ensures that all Attachers for this plugin 1359 // have a zero WaitForAttachCallCount. Otherwise it returns an error. 1360 func VerifyZeroWaitForAttachCallCount(fakeVolumePlugin *FakeVolumePlugin) error { 1361 for _, attacher := range fakeVolumePlugin.GetAttachers() { 1362 actualCallCount := attacher.GetWaitForAttachCallCount() 1363 if actualCallCount != 0 { 1364 return fmt.Errorf( 1365 "At least one attacher has non-zero WaitForAttachCallCount: <%v>.", 1366 actualCallCount) 1367 } 1368 } 1369 1370 return nil 1371 } 1372 1373 // VerifyMountDeviceCallCount ensures that at least one of the Mounters for 1374 // this plugin has the expectedMountDeviceCallCount number of calls. Otherwise 1375 // it returns an error. 1376 func VerifyMountDeviceCallCount( 1377 expectedMountDeviceCallCount int, 1378 fakeVolumePlugin *FakeVolumePlugin) error { 1379 for _, attacher := range fakeVolumePlugin.GetAttachers() { 1380 actualCallCount := attacher.GetMountDeviceCallCount() 1381 if actualCallCount >= expectedMountDeviceCallCount { 1382 return nil 1383 } 1384 } 1385 1386 return fmt.Errorf( 1387 "No Attachers have expected MountDeviceCallCount. Expected: <%v>.", 1388 expectedMountDeviceCallCount) 1389 } 1390 1391 func VerifyUnmountDeviceCallCount(expectedCallCount int, fakeVolumePlugin *FakeVolumePlugin) error { 1392 detachers := fakeVolumePlugin.GetDetachers() 1393 if len(detachers) == 0 && (expectedCallCount == 0) { 1394 return nil 1395 } 1396 actualCallCount := 0 1397 for _, detacher := range detachers { 1398 actualCallCount = detacher.GetUnmountDeviceCallCount() 1399 if expectedCallCount == 0 && actualCallCount == expectedCallCount { 1400 return nil 1401 } 1402 1403 if (expectedCallCount > 0) && (actualCallCount >= expectedCallCount) { 1404 return nil 1405 } 1406 } 1407 1408 return fmt.Errorf( 1409 "Expected DeviceUnmount Call %d, got %d", 1410 expectedCallCount, actualCallCount) 1411 } 1412 1413 // VerifyZeroMountDeviceCallCount ensures that all Attachers for this plugin 1414 // have a zero MountDeviceCallCount. Otherwise it returns an error. 1415 func VerifyZeroMountDeviceCallCount(fakeVolumePlugin *FakeVolumePlugin) error { 1416 for _, attacher := range fakeVolumePlugin.GetAttachers() { 1417 actualCallCount := attacher.GetMountDeviceCallCount() 1418 if actualCallCount != 0 { 1419 return fmt.Errorf( 1420 "At least one attacher has non-zero MountDeviceCallCount: <%v>.", 1421 actualCallCount) 1422 } 1423 } 1424 1425 return nil 1426 } 1427 1428 // VerifySetUpCallCount ensures that at least one of the Mounters for this 1429 // plugin has the expectedSetUpCallCount number of calls. Otherwise it returns 1430 // an error. 1431 func VerifySetUpCallCount( 1432 expectedSetUpCallCount int, 1433 fakeVolumePlugin *FakeVolumePlugin) error { 1434 for _, mounter := range fakeVolumePlugin.GetMounters() { 1435 actualCallCount := mounter.GetSetUpCallCount() 1436 if actualCallCount >= expectedSetUpCallCount { 1437 return nil 1438 } 1439 } 1440 1441 return fmt.Errorf( 1442 "No Mounters have expected SetUpCallCount. Expected: <%v>.", 1443 expectedSetUpCallCount) 1444 } 1445 1446 // VerifyZeroSetUpCallCount ensures that all Mounters for this plugin have a 1447 // zero SetUpCallCount. Otherwise it returns an error. 1448 func VerifyZeroSetUpCallCount(fakeVolumePlugin *FakeVolumePlugin) error { 1449 for _, mounter := range fakeVolumePlugin.GetMounters() { 1450 actualCallCount := mounter.GetSetUpCallCount() 1451 if actualCallCount != 0 { 1452 return fmt.Errorf( 1453 "At least one mounter has non-zero SetUpCallCount: <%v>.", 1454 actualCallCount) 1455 } 1456 } 1457 1458 return nil 1459 } 1460 1461 // VerifyTearDownCallCount ensures that at least one of the Unounters for this 1462 // plugin has the expectedTearDownCallCount number of calls. Otherwise it 1463 // returns an error. 1464 func VerifyTearDownCallCount( 1465 expectedTearDownCallCount int, 1466 fakeVolumePlugin *FakeVolumePlugin) error { 1467 unmounters := fakeVolumePlugin.GetUnmounters() 1468 if len(unmounters) == 0 && (expectedTearDownCallCount == 0) { 1469 return nil 1470 } 1471 1472 for _, unmounter := range unmounters { 1473 actualCallCount := unmounter.GetTearDownCallCount() 1474 if expectedTearDownCallCount == 0 && actualCallCount == expectedTearDownCallCount { 1475 return nil 1476 } 1477 1478 if (expectedTearDownCallCount > 0) && (actualCallCount >= expectedTearDownCallCount) { 1479 return nil 1480 } 1481 } 1482 1483 return fmt.Errorf( 1484 "No Unmounters have expected SetUpCallCount. Expected: <%v>.", 1485 expectedTearDownCallCount) 1486 } 1487 1488 // VerifyZeroTearDownCallCount ensures that all Mounters for this plugin have a 1489 // zero TearDownCallCount. Otherwise it returns an error. 1490 func VerifyZeroTearDownCallCount(fakeVolumePlugin *FakeVolumePlugin) error { 1491 for _, mounter := range fakeVolumePlugin.GetMounters() { 1492 actualCallCount := mounter.GetTearDownCallCount() 1493 if actualCallCount != 0 { 1494 return fmt.Errorf( 1495 "At least one mounter has non-zero TearDownCallCount: <%v>.", 1496 actualCallCount) 1497 } 1498 } 1499 1500 return nil 1501 } 1502 1503 // VerifyDetachCallCount ensures that at least one of the Attachers for this 1504 // plugin has the expectedDetachCallCount number of calls. Otherwise it returns 1505 // an error. 1506 func VerifyDetachCallCount( 1507 expectedDetachCallCount int, 1508 fakeVolumePlugin *FakeVolumePlugin) error { 1509 for _, detacher := range fakeVolumePlugin.GetDetachers() { 1510 actualCallCount := detacher.GetDetachCallCount() 1511 if actualCallCount == expectedDetachCallCount { 1512 return nil 1513 } 1514 } 1515 1516 return fmt.Errorf( 1517 "No Detachers have expected DetachCallCount. Expected: <%v>.", 1518 expectedDetachCallCount) 1519 } 1520 1521 // VerifyZeroDetachCallCount ensures that all Detachers for this plugin have a 1522 // zero DetachCallCount. Otherwise it returns an error. 1523 func VerifyZeroDetachCallCount(fakeVolumePlugin *FakeVolumePlugin) error { 1524 for _, detacher := range fakeVolumePlugin.GetDetachers() { 1525 actualCallCount := detacher.GetDetachCallCount() 1526 if actualCallCount != 0 { 1527 return fmt.Errorf( 1528 "At least one detacher has non-zero DetachCallCount: <%v>.", 1529 actualCallCount) 1530 } 1531 } 1532 1533 return nil 1534 } 1535 1536 // VerifyTearDownDeviceCallCount ensures that at least one of the Unmappers for this 1537 // plugin has the expectedTearDownDeviceCallCount number of calls. Otherwise it 1538 // returns an error. 1539 func VerifyTearDownDeviceCallCount( 1540 expectedTearDownDeviceCallCount int, 1541 fakeVolumePlugin *FakeVolumePlugin) error { 1542 for _, unmapper := range fakeVolumePlugin.GetBlockVolumeUnmapper() { 1543 actualCallCount := unmapper.GetTearDownDeviceCallCount() 1544 if actualCallCount >= expectedTearDownDeviceCallCount { 1545 return nil 1546 } 1547 } 1548 1549 return fmt.Errorf( 1550 "No Unmapper have expected TearDownDeviceCallCount. Expected: <%v>.", 1551 expectedTearDownDeviceCallCount) 1552 } 1553 1554 // VerifyZeroTearDownDeviceCallCount ensures that all Mappers for this plugin have a 1555 // zero TearDownDeviceCallCount. Otherwise it returns an error. 1556 func VerifyZeroTearDownDeviceCallCount(fakeVolumePlugin *FakeVolumePlugin) error { 1557 for _, unmapper := range fakeVolumePlugin.GetBlockVolumeUnmapper() { 1558 actualCallCount := unmapper.GetTearDownDeviceCallCount() 1559 if actualCallCount != 0 { 1560 return fmt.Errorf( 1561 "At least one unmapper has non-zero TearDownDeviceCallCount: <%v>.", 1562 actualCallCount) 1563 } 1564 } 1565 1566 return nil 1567 } 1568 1569 // VerifyUnmapPodDeviceCallCount ensures that at least one of the Unmappers for this 1570 // plugin has the expected number of UnmapPodDevice calls. Otherwise it 1571 // returns an error. 1572 func VerifyUnmapPodDeviceCallCount( 1573 expectedUnmapPodDeviceCallCount int, 1574 fakeVolumePlugin *FakeVolumePlugin) error { 1575 for _, unmapper := range fakeVolumePlugin.GetBlockVolumeUnmapper() { 1576 actualCallCount := unmapper.GetUnmapPodDeviceCallCount() 1577 if actualCallCount >= expectedUnmapPodDeviceCallCount { 1578 return nil 1579 } 1580 } 1581 1582 return fmt.Errorf( 1583 "No Unmapper have expected UnmapPodDeviceCallCount. Expected: <%v>.", 1584 expectedUnmapPodDeviceCallCount) 1585 } 1586 1587 // VerifyZeroUnmapPodDeviceCallCount ensures that all Mappers for this plugin have a 1588 // zero UnmapPodDevice calls. Otherwise it returns an error. 1589 func VerifyZeroUnmapPodDeviceCallCount(fakeVolumePlugin *FakeVolumePlugin) error { 1590 for _, unmapper := range fakeVolumePlugin.GetBlockVolumeUnmapper() { 1591 actualCallCount := unmapper.GetUnmapPodDeviceCallCount() 1592 if actualCallCount != 0 { 1593 return fmt.Errorf( 1594 "At least one unmapper has non-zero UnmapPodDeviceCallCount: <%v>.", 1595 actualCallCount) 1596 } 1597 } 1598 1599 return nil 1600 } 1601 1602 // VerifyGetGlobalMapPathCallCount ensures that at least one of the Mappers for this 1603 // plugin has the expectedGlobalMapPathCallCount number of calls. Otherwise it returns 1604 // an error. 1605 func VerifyGetGlobalMapPathCallCount( 1606 expectedGlobalMapPathCallCount int, 1607 fakeVolumePlugin *FakeVolumePlugin) error { 1608 for _, mapper := range fakeVolumePlugin.GetBlockVolumeMapper() { 1609 actualCallCount := mapper.GetGlobalMapPathCallCount() 1610 if actualCallCount == expectedGlobalMapPathCallCount { 1611 return nil 1612 } 1613 } 1614 1615 return fmt.Errorf( 1616 "No Mappers have expected GetGlobalMapPathCallCount. Expected: <%v>.", 1617 expectedGlobalMapPathCallCount) 1618 } 1619 1620 // VerifyGetPodDeviceMapPathCallCount ensures that at least one of the Mappers for this 1621 // plugin has the expectedPodDeviceMapPathCallCount number of calls. Otherwise it returns 1622 // an error. 1623 func VerifyGetPodDeviceMapPathCallCount( 1624 expectedPodDeviceMapPathCallCount int, 1625 fakeVolumePlugin *FakeVolumePlugin) error { 1626 for _, mapper := range fakeVolumePlugin.GetBlockVolumeMapper() { 1627 actualCallCount := mapper.GetPodDeviceMapPathCallCount() 1628 if actualCallCount == expectedPodDeviceMapPathCallCount { 1629 return nil 1630 } 1631 } 1632 1633 return fmt.Errorf( 1634 "No Mappers have expected GetPodDeviceMapPathCallCount. Expected: <%v>.", 1635 expectedPodDeviceMapPathCallCount) 1636 } 1637 1638 // VerifyGetMapPodDeviceCallCount ensures that at least one of the Mappers for this 1639 // plugin has the expectedMapPodDeviceCallCount number of calls. Otherwise it 1640 // returns an error. 1641 func VerifyGetMapPodDeviceCallCount( 1642 expectedMapPodDeviceCallCount int, 1643 fakeVolumePlugin *FakeVolumePlugin) error { 1644 for _, mapper := range fakeVolumePlugin.GetBlockVolumeMapper() { 1645 actualCallCount := mapper.GetMapPodDeviceCallCount() 1646 if actualCallCount >= expectedMapPodDeviceCallCount { 1647 return nil 1648 } 1649 } 1650 1651 return fmt.Errorf( 1652 "No Mapper have expected MapPodDeviceCallCount. Expected: <%v>.", 1653 expectedMapPodDeviceCallCount) 1654 } 1655 1656 // GetTestVolumePluginMgr creates, initializes, and returns a test volume plugin 1657 // manager and fake volume plugin using a fake volume host. 1658 func GetTestVolumePluginMgr(t *testing.T) (*volume.VolumePluginMgr, *FakeVolumePlugin) { 1659 plugins := ProbeVolumePlugins(volume.VolumeConfig{}) 1660 v := NewFakeVolumeHost( 1661 t, 1662 "", /* rootDir */ 1663 nil, /* kubeClient */ 1664 plugins, /* plugins */ 1665 ) 1666 return v.GetPluginMgr(), plugins[0].(*FakeVolumePlugin) 1667 } 1668 1669 func GetTestKubeletVolumePluginMgr(t *testing.T) (*volume.VolumePluginMgr, *FakeVolumePlugin) { 1670 plugins := ProbeVolumePlugins(volume.VolumeConfig{}) 1671 v := NewFakeKubeletVolumeHost( 1672 t, 1673 "", /* rootDir */ 1674 nil, /* kubeClient */ 1675 plugins, /* plugins */ 1676 ) 1677 return v.GetPluginMgr(), plugins[0].(*FakeVolumePlugin) 1678 } 1679 1680 func GetTestKubeletVolumePluginMgrWithNode(t *testing.T, node *v1.Node) (*volume.VolumePluginMgr, *FakeVolumePlugin) { 1681 plugins := ProbeVolumePlugins(volume.VolumeConfig{}) 1682 v := NewFakeKubeletVolumeHost( 1683 t, 1684 "", /* rootDir */ 1685 nil, /* kubeClient */ 1686 plugins, /* plugins */ 1687 ) 1688 v.WithNode(node) 1689 1690 return v.GetPluginMgr(), plugins[0].(*FakeVolumePlugin) 1691 } 1692 1693 func GetTestKubeletVolumePluginMgrWithNodeAndRoot(t *testing.T, node *v1.Node, rootDir string) (*volume.VolumePluginMgr, *FakeVolumePlugin) { 1694 plugins := ProbeVolumePlugins(volume.VolumeConfig{}) 1695 v := NewFakeKubeletVolumeHost( 1696 t, 1697 rootDir, /* rootDir */ 1698 nil, /* kubeClient */ 1699 plugins, /* plugins */ 1700 ) 1701 v.WithNode(node) 1702 1703 return v.GetPluginMgr(), plugins[0].(*FakeVolumePlugin) 1704 } 1705 1706 // CreateTestPVC returns a provisionable PVC for tests 1707 func CreateTestPVC(capacity string, accessModes []v1.PersistentVolumeAccessMode) *v1.PersistentVolumeClaim { 1708 claim := v1.PersistentVolumeClaim{ 1709 ObjectMeta: metav1.ObjectMeta{ 1710 Name: "dummy", 1711 Namespace: "default", 1712 }, 1713 Spec: v1.PersistentVolumeClaimSpec{ 1714 AccessModes: accessModes, 1715 Resources: v1.VolumeResourceRequirements{ 1716 Requests: v1.ResourceList{ 1717 v1.ResourceName(v1.ResourceStorage): resource.MustParse(capacity), 1718 }, 1719 }, 1720 }, 1721 } 1722 return &claim 1723 } 1724 1725 func MetricsEqualIgnoreTimestamp(a *volume.Metrics, b *volume.Metrics) bool { 1726 available := a.Available == b.Available 1727 capacity := a.Capacity == b.Capacity 1728 used := a.Used == b.Used 1729 inodes := a.Inodes == b.Inodes 1730 inodesFree := a.InodesFree == b.InodesFree 1731 inodesUsed := a.InodesUsed == b.InodesUsed 1732 return available && capacity && used && inodes && inodesFree && inodesUsed 1733 } 1734 1735 func ContainsAccessMode(modes []v1.PersistentVolumeAccessMode, mode v1.PersistentVolumeAccessMode) bool { 1736 for _, m := range modes { 1737 if m == mode { 1738 return true 1739 } 1740 } 1741 return false 1742 }