k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/kubelet/volumemanager/cache/actual_state_of_world.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 /* 18 Package cache implements data structures used by the kubelet volume manager to 19 keep track of attached volumes and the pods that mounted them. 20 */ 21 package cache 22 23 import ( 24 "fmt" 25 "sync" 26 27 v1 "k8s.io/api/core/v1" 28 "k8s.io/apimachinery/pkg/api/resource" 29 "k8s.io/apimachinery/pkg/types" 30 utilfeature "k8s.io/apiserver/pkg/util/feature" 31 "k8s.io/klog/v2" 32 "k8s.io/kubernetes/pkg/features" 33 "k8s.io/kubernetes/pkg/volume" 34 "k8s.io/kubernetes/pkg/volume/util" 35 "k8s.io/kubernetes/pkg/volume/util/operationexecutor" 36 volumetypes "k8s.io/kubernetes/pkg/volume/util/types" 37 ) 38 39 // ActualStateOfWorld defines a set of thread-safe operations for the kubelet 40 // volume manager's actual state of the world cache. 41 // This cache contains volumes->pods i.e. a set of all volumes attached to this 42 // node and the pods that the manager believes have successfully mounted the 43 // volume. 44 // Note: This is distinct from the ActualStateOfWorld implemented by the 45 // attach/detach controller. They both keep track of different objects. This 46 // contains kubelet volume manager specific state. 47 type ActualStateOfWorld interface { 48 // ActualStateOfWorld must implement the methods required to allow 49 // operationexecutor to interact with it. 50 operationexecutor.ActualStateOfWorldMounterUpdater 51 52 // ActualStateOfWorld must implement the methods required to allow 53 // operationexecutor to interact with it. 54 operationexecutor.ActualStateOfWorldAttacherUpdater 55 56 // AddPodToVolume adds the given pod to the given volume in the cache 57 // indicating the specified volume has been successfully mounted to the 58 // specified pod. 59 // If a pod with the same unique name already exists under the specified 60 // volume, reset the pod's remountRequired value. 61 // If a volume with the name volumeName does not exist in the list of 62 // attached volumes, an error is returned. 63 AddPodToVolume(operationexecutor.MarkVolumeOpts) error 64 65 // MarkRemountRequired marks each volume that is successfully attached and 66 // mounted for the specified pod as requiring remount (if the plugin for the 67 // volume indicates it requires remounting on pod updates). Atomically 68 // updating volumes depend on this to update the contents of the volume on 69 // pod update. 70 MarkRemountRequired(podName volumetypes.UniquePodName) 71 72 // SetDeviceMountState sets device mount state for the given volume. When deviceMountState is set to DeviceGloballyMounted 73 // then device is mounted at a global mount point. When it is set to DeviceMountUncertain then also it means volume 74 // MAY be globally mounted at a global mount point. In both cases - the volume must be unmounted from 75 // global mount point prior to detach. 76 // If a volume with the name volumeName does not exist in the list of 77 // attached volumes, an error is returned. 78 SetDeviceMountState(volumeName v1.UniqueVolumeName, deviceMountState operationexecutor.DeviceMountState, devicePath, deviceMountPath, seLinuxMountContext string) error 79 80 // DeletePodFromVolume removes the given pod from the given volume in the 81 // cache indicating the volume has been successfully unmounted from the pod. 82 // If a pod with the same unique name does not exist under the specified 83 // volume, this is a no-op. 84 // If a volume with the name volumeName does not exist in the list of 85 // attached volumes, an error is returned. 86 DeletePodFromVolume(podName volumetypes.UniquePodName, volumeName v1.UniqueVolumeName) error 87 88 // DeleteVolume removes the given volume from the list of attached volumes 89 // in the cache indicating the volume has been successfully detached from 90 // this node. 91 // If a volume with the name volumeName does not exist in the list of 92 // attached volumes, this is a no-op. 93 // If a volume with the name volumeName exists and its list of mountedPods 94 // is not empty, an error is returned. 95 DeleteVolume(volumeName v1.UniqueVolumeName) error 96 97 // PodExistsInVolume returns true if the given pod exists in the list of 98 // mountedPods for the given volume in the cache, indicating that the volume 99 // is attached to this node and the pod has successfully mounted it. 100 // If a pod with the same unique name does not exist under the specified 101 // volume, false is returned. 102 // If a volume with the name volumeName does not exist in the list of 103 // attached volumes, a volumeNotAttachedError is returned indicating the 104 // given volume is not yet attached. 105 // If the given volumeName/podName combo exists but the value of 106 // remountRequired is true, a remountRequiredError is returned indicating 107 // the given volume has been successfully mounted to this pod but should be 108 // remounted to reflect changes in the referencing pod. Atomically updating 109 // volumes, depend on this to update the contents of the volume. 110 // All volume mounting calls should be idempotent so a second mount call for 111 // volumes that do not need to update contents should not fail. 112 PodExistsInVolume(podName volumetypes.UniquePodName, volumeName v1.UniqueVolumeName, desiredVolumeSize resource.Quantity, seLinuxLabel string) (bool, string, error) 113 114 // PodRemovedFromVolume returns true if the given pod does not exist in the list of 115 // mountedPods for the given volume in the cache, indicating that the pod has 116 // fully unmounted it or it was never mounted the volume. 117 // If the volume is fully mounted or is in uncertain mount state for the pod, it is 118 // considered that the pod still exists in volume manager's actual state of the world 119 // and false is returned. 120 PodRemovedFromVolume(podName volumetypes.UniquePodName, volumeName v1.UniqueVolumeName) bool 121 122 // VolumeExistsWithSpecName returns true if the given volume specified with the 123 // volume spec name (a.k.a., InnerVolumeSpecName) exists in the list of 124 // volumes that should be attached to this node. 125 // If a pod with the same name does not exist under the specified 126 // volume, false is returned. 127 VolumeExistsWithSpecName(podName volumetypes.UniquePodName, volumeSpecName string) bool 128 129 // VolumeExists returns true if the given volume exists in the list of 130 // attached volumes in the cache, indicating the volume is attached to this 131 // node. 132 VolumeExists(volumeName v1.UniqueVolumeName) bool 133 134 // GetMountedVolumes generates and returns a list of volumes and the pods 135 // they are successfully attached and mounted for based on the current 136 // actual state of the world. 137 GetMountedVolumes() []MountedVolume 138 139 // GetAllMountedVolumes returns list of all possibly mounted volumes including 140 // those that are in VolumeMounted state and VolumeMountUncertain state. 141 GetAllMountedVolumes() []MountedVolume 142 143 // GetMountedVolumesForPod generates and returns a list of volumes that are 144 // successfully attached and mounted for the specified pod based on the 145 // current actual state of the world. 146 GetMountedVolumesForPod(podName volumetypes.UniquePodName) []MountedVolume 147 148 // GetPossiblyMountedVolumesForPod generates and returns a list of volumes for 149 // the specified pod that either are attached and mounted or are "uncertain", 150 // i.e. a volume plugin may be mounting the volume right now. 151 GetPossiblyMountedVolumesForPod(podName volumetypes.UniquePodName) []MountedVolume 152 153 // GetGloballyMountedVolumes generates and returns a list of all attached 154 // volumes that are globally mounted. This list can be used to determine 155 // which volumes should be reported as "in use" in the node's VolumesInUse 156 // status field. Globally mounted here refers to the shared plugin mount 157 // point for the attachable volume from which the pod specific mount points 158 // are created (via bind mount). 159 GetGloballyMountedVolumes() []AttachedVolume 160 161 // GetUnmountedVolumes generates and returns a list of attached volumes that 162 // have no mountedPods. This list can be used to determine which volumes are 163 // no longer referenced and may be globally unmounted and detached. 164 GetUnmountedVolumes() []AttachedVolume 165 166 // GetAttachedVolumes returns a list of volumes that is known to be attached 167 // to the node. This list can be used to determine volumes that are either in-use 168 // or have a mount/unmount operation pending. 169 GetAttachedVolumes() []AttachedVolume 170 171 // Add the specified volume to ASW as uncertainly attached. 172 AddAttachUncertainReconstructedVolume(volumeName v1.UniqueVolumeName, volumeSpec *volume.Spec, nodeName types.NodeName, devicePath string) error 173 174 // UpdateReconstructedDevicePath updates devicePath of a reconstructed volume 175 // from Node.Status.VolumesAttached. The ASW is updated only when the volume is still 176 // uncertain. If the volume got mounted in the meantime, its devicePath must have 177 // been fixed by such an update. 178 UpdateReconstructedDevicePath(volumeName v1.UniqueVolumeName, devicePath string) 179 180 // UpdateReconstructedVolumeAttachability updates volume attachability from the API server. 181 UpdateReconstructedVolumeAttachability(volumeName v1.UniqueVolumeName, volumeAttachable bool) 182 } 183 184 // MountedVolume represents a volume that has successfully been mounted to a pod. 185 type MountedVolume struct { 186 operationexecutor.MountedVolume 187 } 188 189 // AttachedVolume represents a volume that is attached to a node. 190 type AttachedVolume struct { 191 operationexecutor.AttachedVolume 192 193 // DeviceMountState indicates if device has been globally mounted or is not. 194 DeviceMountState operationexecutor.DeviceMountState 195 196 // SELinuxMountContext is the context with that the volume is globally mounted 197 // (via -o context=XYZ mount option). If empty, the volume is not mounted with 198 // "-o context=". 199 SELinuxMountContext string 200 } 201 202 // DeviceMayBeMounted returns true if device is mounted in global path or is in 203 // uncertain state. 204 func (av AttachedVolume) DeviceMayBeMounted() bool { 205 return av.DeviceMountState == operationexecutor.DeviceGloballyMounted || 206 av.DeviceMountState == operationexecutor.DeviceMountUncertain 207 } 208 209 // NewActualStateOfWorld returns a new instance of ActualStateOfWorld. 210 func NewActualStateOfWorld( 211 nodeName types.NodeName, 212 volumePluginMgr *volume.VolumePluginMgr) ActualStateOfWorld { 213 return &actualStateOfWorld{ 214 nodeName: nodeName, 215 attachedVolumes: make(map[v1.UniqueVolumeName]attachedVolume), 216 foundDuringReconstruction: make(map[v1.UniqueVolumeName]map[volumetypes.UniquePodName]types.UID), 217 volumePluginMgr: volumePluginMgr, 218 } 219 } 220 221 // IsVolumeNotAttachedError returns true if the specified error is a 222 // volumeNotAttachedError. 223 func IsVolumeNotAttachedError(err error) bool { 224 _, ok := err.(volumeNotAttachedError) 225 return ok 226 } 227 228 // IsRemountRequiredError returns true if the specified error is a 229 // remountRequiredError. 230 func IsRemountRequiredError(err error) bool { 231 _, ok := err.(remountRequiredError) 232 return ok 233 } 234 235 type actualStateOfWorld struct { 236 // nodeName is the name of this node. This value is passed to Attach/Detach 237 nodeName types.NodeName 238 239 // attachedVolumes is a map containing the set of volumes the kubelet volume 240 // manager believes to be successfully attached to this node. Volume types 241 // that do not implement an attacher interface are assumed to be in this 242 // state by default. 243 // The key in this map is the name of the volume and the value is an object 244 // containing more information about the attached volume. 245 attachedVolumes map[v1.UniqueVolumeName]attachedVolume 246 // foundDuringReconstruction is a map of volumes which were discovered 247 // from kubelet root directory when kubelet was restarted. 248 foundDuringReconstruction map[v1.UniqueVolumeName]map[volumetypes.UniquePodName]types.UID 249 250 // volumePluginMgr is the volume plugin manager used to create volume 251 // plugin objects. 252 volumePluginMgr *volume.VolumePluginMgr 253 sync.RWMutex 254 } 255 256 type volumeAttachability string 257 258 const ( 259 volumeAttachabilityTrue volumeAttachability = "True" 260 volumeAttachabilityFalse volumeAttachability = "False" 261 volumeAttachabilityUncertain volumeAttachability = "Uncertain" 262 ) 263 264 // attachedVolume represents a volume the kubelet volume manager believes to be 265 // successfully attached to a node it is managing. Volume types that do not 266 // implement an attacher are assumed to be in this state. 267 type attachedVolume struct { 268 // volumeName contains the unique identifier for this volume. 269 volumeName v1.UniqueVolumeName 270 271 // mountedPods is a map containing the set of pods that this volume has been 272 // successfully mounted to. The key in this map is the name of the pod and 273 // the value is a mountedPod object containing more information about the 274 // pod. 275 mountedPods map[volumetypes.UniquePodName]mountedPod 276 277 // spec is the volume spec containing the specification for this volume. 278 // Used to generate the volume plugin object, and passed to plugin methods. 279 // In particular, the Unmount method uses spec.Name() as the volumeSpecName 280 // in the mount path: 281 // /var/lib/kubelet/pods/{podUID}/volumes/{escapeQualifiedPluginName}/{volumeSpecName}/ 282 spec *volume.Spec 283 284 // pluginName is the Unescaped Qualified name of the volume plugin used to 285 // attach and mount this volume. It is stored separately in case the full 286 // volume spec (everything except the name) can not be reconstructed for a 287 // volume that should be unmounted (which would be the case for a mount path 288 // read from disk without a full volume spec). 289 pluginName string 290 291 // pluginIsAttachable indicates the volume plugin used to attach and mount 292 // this volume implements the volume.Attacher interface 293 pluginIsAttachable volumeAttachability 294 295 // deviceMountState stores information that tells us if device is mounted 296 // globally or not 297 deviceMountState operationexecutor.DeviceMountState 298 299 // devicePath contains the path on the node where the volume is attached for 300 // attachable volumes 301 devicePath string 302 303 // deviceMountPath contains the path on the node where the device should 304 // be mounted after it is attached. 305 deviceMountPath string 306 307 // volumeInUseErrorForExpansion indicates volume driver has previously returned volume-in-use error 308 // for this volume and volume expansion on this node should not be retried 309 volumeInUseErrorForExpansion bool 310 311 // persistentVolumeSize records size of the volume when pod was started or 312 // size after successful completion of volume expansion operation. 313 persistentVolumeSize *resource.Quantity 314 315 // seLinuxMountContext is the context with that the volume is mounted to global directory 316 // (via -o context=XYZ mount option). If nil, the volume is not mounted. If "", the volume is 317 // mounted without "-o context=". 318 seLinuxMountContext *string 319 } 320 321 // The mountedPod object represents a pod for which the kubelet volume manager 322 // believes the underlying volume has been successfully been mounted. 323 type mountedPod struct { 324 // the name of the pod 325 podName volumetypes.UniquePodName 326 327 // the UID of the pod 328 podUID types.UID 329 330 // mounter used to mount 331 mounter volume.Mounter 332 333 // mapper used to block volumes support 334 blockVolumeMapper volume.BlockVolumeMapper 335 336 // spec is the volume spec containing the specification for this volume. 337 // Used to generate the volume plugin object, and passed to plugin methods. 338 // In particular, the Unmount method uses spec.Name() as the volumeSpecName 339 // in the mount path: 340 // /var/lib/kubelet/pods/{podUID}/volumes/{escapeQualifiedPluginName}/{volumeSpecName}/ 341 volumeSpec *volume.Spec 342 343 // outerVolumeSpecName is the volume.Spec.Name() of the volume as referenced 344 // directly in the pod. If the volume was referenced through a persistent 345 // volume claim, this contains the volume.Spec.Name() of the persistent 346 // volume claim 347 outerVolumeSpecName string 348 349 // remountRequired indicates the underlying volume has been successfully 350 // mounted to this pod but it should be remounted to reflect changes in the 351 // referencing pod. 352 // Atomically updating volumes depend on this to update the contents of the 353 // volume. All volume mounting calls should be idempotent so a second mount 354 // call for volumes that do not need to update contents should not fail. 355 remountRequired bool 356 357 // volumeGidValue contains the value of the GID annotation, if present. 358 volumeGidValue string 359 360 // volumeMountStateForPod stores state of volume mount for the pod. if it is: 361 // - VolumeMounted: means volume for pod has been successfully mounted 362 // - VolumeMountUncertain: means volume for pod may not be mounted, but it must be unmounted 363 volumeMountStateForPod operationexecutor.VolumeMountState 364 365 // seLinuxMountContext is the context with that the volume is mounted to Pod directory 366 // (via -o context=XYZ mount option). If nil, the volume is not mounted. If "", the volume is 367 // mounted without "-o context=". 368 seLinuxMountContext string 369 } 370 371 func (asw *actualStateOfWorld) MarkVolumeAsAttached( 372 logger klog.Logger, 373 volumeName v1.UniqueVolumeName, volumeSpec *volume.Spec, _ types.NodeName, devicePath string) error { 374 375 pluginIsAttachable := volumeAttachabilityFalse 376 if attachablePlugin, err := asw.volumePluginMgr.FindAttachablePluginBySpec(volumeSpec); err == nil && attachablePlugin != nil { 377 pluginIsAttachable = volumeAttachabilityTrue 378 } 379 380 return asw.addVolume(volumeName, volumeSpec, devicePath, pluginIsAttachable) 381 } 382 383 func (asw *actualStateOfWorld) AddAttachUncertainReconstructedVolume( 384 volumeName v1.UniqueVolumeName, volumeSpec *volume.Spec, _ types.NodeName, devicePath string) error { 385 386 return asw.addVolume(volumeName, volumeSpec, devicePath, volumeAttachabilityUncertain) 387 } 388 389 func (asw *actualStateOfWorld) MarkVolumeAsUncertain( 390 logger klog.Logger, volumeName v1.UniqueVolumeName, volumeSpec *volume.Spec, _ types.NodeName) error { 391 return nil 392 } 393 394 func (asw *actualStateOfWorld) MarkVolumeAsDetached( 395 volumeName v1.UniqueVolumeName, nodeName types.NodeName) { 396 asw.DeleteVolume(volumeName) 397 } 398 399 func (asw *actualStateOfWorld) IsVolumeReconstructed(volumeName v1.UniqueVolumeName, podName volumetypes.UniquePodName) bool { 400 volumeState := asw.GetVolumeMountState(volumeName, podName) 401 402 // only uncertain volumes are reconstructed 403 if volumeState != operationexecutor.VolumeMountUncertain { 404 return false 405 } 406 407 asw.RLock() 408 defer asw.RUnlock() 409 podMap, ok := asw.foundDuringReconstruction[volumeName] 410 if !ok { 411 return false 412 } 413 _, foundPod := podMap[podName] 414 return foundPod 415 } 416 417 func (asw *actualStateOfWorld) IsVolumeDeviceReconstructed(volumeName v1.UniqueVolumeName) bool { 418 asw.RLock() 419 defer asw.RUnlock() 420 _, ok := asw.foundDuringReconstruction[volumeName] 421 return ok 422 } 423 424 func (asw *actualStateOfWorld) CheckAndMarkVolumeAsUncertainViaReconstruction(opts operationexecutor.MarkVolumeOpts) (bool, error) { 425 asw.Lock() 426 defer asw.Unlock() 427 428 volumeObj, volumeExists := asw.attachedVolumes[opts.VolumeName] 429 if !volumeExists { 430 return false, nil 431 } 432 433 podObj, podExists := volumeObj.mountedPods[opts.PodName] 434 if podExists { 435 // if volume mount was uncertain we should keep trying to unmount the volume 436 if podObj.volumeMountStateForPod == operationexecutor.VolumeMountUncertain { 437 return false, nil 438 } 439 if podObj.volumeMountStateForPod == operationexecutor.VolumeMounted { 440 return false, nil 441 } 442 } 443 444 podName := opts.PodName 445 podUID := opts.PodUID 446 volumeName := opts.VolumeName 447 mounter := opts.Mounter 448 blockVolumeMapper := opts.BlockVolumeMapper 449 outerVolumeSpecName := opts.OuterVolumeSpecName 450 volumeGidValue := opts.VolumeGidVolume 451 volumeSpec := opts.VolumeSpec 452 453 podObj = mountedPod{ 454 podName: podName, 455 podUID: podUID, 456 mounter: mounter, 457 blockVolumeMapper: blockVolumeMapper, 458 outerVolumeSpecName: outerVolumeSpecName, 459 volumeGidValue: volumeGidValue, 460 volumeSpec: volumeSpec, 461 remountRequired: false, 462 volumeMountStateForPod: operationexecutor.VolumeMountUncertain, 463 } 464 465 if mounter != nil { 466 // The mounter stored in the object may have old information, 467 // use the newest one. 468 podObj.mounter = mounter 469 } 470 471 asw.attachedVolumes[volumeName].mountedPods[podName] = podObj 472 473 podMap, ok := asw.foundDuringReconstruction[opts.VolumeName] 474 if !ok { 475 podMap = map[volumetypes.UniquePodName]types.UID{} 476 } 477 podMap[opts.PodName] = opts.PodUID 478 asw.foundDuringReconstruction[opts.VolumeName] = podMap 479 return true, nil 480 } 481 482 func (asw *actualStateOfWorld) CheckAndMarkDeviceUncertainViaReconstruction(volumeName v1.UniqueVolumeName, deviceMountPath string) bool { 483 asw.Lock() 484 defer asw.Unlock() 485 486 volumeObj, volumeExists := asw.attachedVolumes[volumeName] 487 // CheckAndMarkDeviceUncertainViaReconstruction requires volume to be marked as attached, so if 488 // volume does not exist in ASOW or is in any state other than DeviceNotMounted we should return 489 if !volumeExists || volumeObj.deviceMountState != operationexecutor.DeviceNotMounted { 490 return false 491 } 492 493 volumeObj.deviceMountState = operationexecutor.DeviceMountUncertain 494 // we are only changing deviceMountPath because devicePath at at this stage is 495 // determined from node object. 496 volumeObj.deviceMountPath = deviceMountPath 497 asw.attachedVolumes[volumeName] = volumeObj 498 return true 499 500 } 501 502 func (asw *actualStateOfWorld) MarkVolumeAsMounted(markVolumeOpts operationexecutor.MarkVolumeOpts) error { 503 return asw.AddPodToVolume(markVolumeOpts) 504 } 505 506 func (asw *actualStateOfWorld) AddVolumeToReportAsAttached(logger klog.Logger, volumeName v1.UniqueVolumeName, nodeName types.NodeName) { 507 // no operation for kubelet side 508 } 509 510 func (asw *actualStateOfWorld) RemoveVolumeFromReportAsAttached(volumeName v1.UniqueVolumeName, nodeName types.NodeName) error { 511 // no operation for kubelet side 512 return nil 513 } 514 515 func (asw *actualStateOfWorld) MarkVolumeAsUnmounted( 516 podName volumetypes.UniquePodName, volumeName v1.UniqueVolumeName) error { 517 return asw.DeletePodFromVolume(podName, volumeName) 518 } 519 520 func (asw *actualStateOfWorld) MarkDeviceAsMounted( 521 volumeName v1.UniqueVolumeName, devicePath, deviceMountPath, seLinuxMountContext string) error { 522 return asw.SetDeviceMountState(volumeName, operationexecutor.DeviceGloballyMounted, devicePath, deviceMountPath, seLinuxMountContext) 523 } 524 525 func (asw *actualStateOfWorld) MarkDeviceAsUncertain( 526 volumeName v1.UniqueVolumeName, devicePath, deviceMountPath, seLinuxMountContext string) error { 527 return asw.SetDeviceMountState(volumeName, operationexecutor.DeviceMountUncertain, devicePath, deviceMountPath, seLinuxMountContext) 528 } 529 530 func (asw *actualStateOfWorld) MarkVolumeMountAsUncertain(markVolumeOpts operationexecutor.MarkVolumeOpts) error { 531 markVolumeOpts.VolumeMountState = operationexecutor.VolumeMountUncertain 532 return asw.AddPodToVolume(markVolumeOpts) 533 } 534 535 func (asw *actualStateOfWorld) MarkDeviceAsUnmounted( 536 volumeName v1.UniqueVolumeName) error { 537 return asw.SetDeviceMountState(volumeName, operationexecutor.DeviceNotMounted, "", "", "") 538 } 539 540 func (asw *actualStateOfWorld) UpdateReconstructedDevicePath(volumeName v1.UniqueVolumeName, devicePath string) { 541 asw.Lock() 542 defer asw.Unlock() 543 544 volumeObj, volumeExists := asw.attachedVolumes[volumeName] 545 if !volumeExists { 546 return 547 } 548 if volumeObj.deviceMountState != operationexecutor.DeviceMountUncertain { 549 // Reconciler must have updated volume state, i.e. when a pod uses the volume and 550 // succeeded mounting the volume. Such update has fixed the device path. 551 return 552 } 553 554 volumeObj.devicePath = devicePath 555 asw.attachedVolumes[volumeName] = volumeObj 556 } 557 558 func (asw *actualStateOfWorld) UpdateReconstructedVolumeAttachability(volumeName v1.UniqueVolumeName, attachable bool) { 559 asw.Lock() 560 defer asw.Unlock() 561 562 volumeObj, volumeExists := asw.attachedVolumes[volumeName] 563 if !volumeExists { 564 return 565 } 566 if volumeObj.pluginIsAttachable != volumeAttachabilityUncertain { 567 // Reconciler must have updated volume state, i.e. when a pod uses the volume and 568 // succeeded mounting the volume. Such update has fixed the device path. 569 return 570 } 571 572 if attachable { 573 volumeObj.pluginIsAttachable = volumeAttachabilityTrue 574 } else { 575 volumeObj.pluginIsAttachable = volumeAttachabilityFalse 576 } 577 asw.attachedVolumes[volumeName] = volumeObj 578 } 579 580 func (asw *actualStateOfWorld) GetDeviceMountState(volumeName v1.UniqueVolumeName) operationexecutor.DeviceMountState { 581 asw.RLock() 582 defer asw.RUnlock() 583 584 volumeObj, volumeExists := asw.attachedVolumes[volumeName] 585 if !volumeExists { 586 return operationexecutor.DeviceNotMounted 587 } 588 589 return volumeObj.deviceMountState 590 } 591 592 func (asw *actualStateOfWorld) MarkForInUseExpansionError(volumeName v1.UniqueVolumeName) { 593 asw.Lock() 594 defer asw.Unlock() 595 596 volumeObj, ok := asw.attachedVolumes[volumeName] 597 if ok { 598 volumeObj.volumeInUseErrorForExpansion = true 599 asw.attachedVolumes[volumeName] = volumeObj 600 } 601 } 602 603 func (asw *actualStateOfWorld) GetVolumeMountState(volumeName v1.UniqueVolumeName, podName volumetypes.UniquePodName) operationexecutor.VolumeMountState { 604 asw.RLock() 605 defer asw.RUnlock() 606 607 volumeObj, volumeExists := asw.attachedVolumes[volumeName] 608 if !volumeExists { 609 return operationexecutor.VolumeNotMounted 610 } 611 612 podObj, podExists := volumeObj.mountedPods[podName] 613 if !podExists { 614 return operationexecutor.VolumeNotMounted 615 } 616 return podObj.volumeMountStateForPod 617 } 618 619 func (asw *actualStateOfWorld) IsVolumeMountedElsewhere(volumeName v1.UniqueVolumeName, podName volumetypes.UniquePodName) bool { 620 asw.RLock() 621 defer asw.RUnlock() 622 623 volumeObj, volumeExists := asw.attachedVolumes[volumeName] 624 if !volumeExists { 625 return false 626 } 627 628 for _, podObj := range volumeObj.mountedPods { 629 if podName != podObj.podName { 630 // Treat uncertain mount state as mounted until certain. 631 if podObj.volumeMountStateForPod != operationexecutor.VolumeNotMounted { 632 return true 633 } 634 } 635 } 636 return false 637 } 638 639 // addVolume adds the given volume to the cache indicating the specified 640 // volume is attached to this node. If no volume name is supplied, a unique 641 // volume name is generated from the volumeSpec and returned on success. If a 642 // volume with the same generated name already exists, this is a noop. If no 643 // volume plugin can support the given volumeSpec or more than one plugin can 644 // support it, an error is returned. 645 func (asw *actualStateOfWorld) addVolume( 646 volumeName v1.UniqueVolumeName, volumeSpec *volume.Spec, devicePath string, attachability volumeAttachability) error { 647 asw.Lock() 648 defer asw.Unlock() 649 650 volumePlugin, err := asw.volumePluginMgr.FindPluginBySpec(volumeSpec) 651 if err != nil || volumePlugin == nil { 652 return fmt.Errorf( 653 "failed to get Plugin from volumeSpec for volume %q err=%v", 654 volumeSpec.Name(), 655 err) 656 } 657 658 if len(volumeName) == 0 { 659 volumeName, err = util.GetUniqueVolumeNameFromSpec(volumePlugin, volumeSpec) 660 if err != nil { 661 return fmt.Errorf( 662 "failed to GetUniqueVolumeNameFromSpec for volumeSpec %q using volume plugin %q err=%v", 663 volumeSpec.Name(), 664 volumePlugin.GetPluginName(), 665 err) 666 } 667 } 668 669 volumeObj, volumeExists := asw.attachedVolumes[volumeName] 670 if !volumeExists { 671 volumeObj = attachedVolume{ 672 volumeName: volumeName, 673 spec: volumeSpec, 674 mountedPods: make(map[volumetypes.UniquePodName]mountedPod), 675 pluginName: volumePlugin.GetPluginName(), 676 pluginIsAttachable: attachability, 677 deviceMountState: operationexecutor.DeviceNotMounted, 678 devicePath: devicePath, 679 } 680 } else { 681 // If volume object already exists, update the fields such as device path 682 volumeObj.devicePath = devicePath 683 klog.V(2).InfoS("Volume is already added to attachedVolume list, update device path", "volumeName", volumeName, "path", devicePath) 684 } 685 asw.attachedVolumes[volumeName] = volumeObj 686 687 return nil 688 } 689 690 func (asw *actualStateOfWorld) AddPodToVolume(markVolumeOpts operationexecutor.MarkVolumeOpts) error { 691 podName := markVolumeOpts.PodName 692 podUID := markVolumeOpts.PodUID 693 volumeName := markVolumeOpts.VolumeName 694 mounter := markVolumeOpts.Mounter 695 blockVolumeMapper := markVolumeOpts.BlockVolumeMapper 696 outerVolumeSpecName := markVolumeOpts.OuterVolumeSpecName 697 volumeGidValue := markVolumeOpts.VolumeGidVolume 698 volumeSpec := markVolumeOpts.VolumeSpec 699 asw.Lock() 700 defer asw.Unlock() 701 702 volumeObj, volumeExists := asw.attachedVolumes[volumeName] 703 if !volumeExists { 704 return fmt.Errorf( 705 "no volume with the name %q exists in the list of attached volumes", 706 volumeName) 707 } 708 709 podObj, podExists := volumeObj.mountedPods[podName] 710 711 updateUncertainVolume := false 712 if podExists { 713 // Update uncertain volumes - the new markVolumeOpts may have updated information. 714 // Especially reconstructed volumes (marked as uncertain during reconstruction) need 715 // an update. 716 updateUncertainVolume = utilfeature.DefaultFeatureGate.Enabled(features.NewVolumeManagerReconstruction) && podObj.volumeMountStateForPod == operationexecutor.VolumeMountUncertain 717 } 718 if !podExists || updateUncertainVolume { 719 // Add new mountedPod or update existing one. 720 podObj = mountedPod{ 721 podName: podName, 722 podUID: podUID, 723 mounter: mounter, 724 blockVolumeMapper: blockVolumeMapper, 725 outerVolumeSpecName: outerVolumeSpecName, 726 volumeGidValue: volumeGidValue, 727 volumeSpec: volumeSpec, 728 volumeMountStateForPod: markVolumeOpts.VolumeMountState, 729 seLinuxMountContext: markVolumeOpts.SELinuxMountContext, 730 } 731 } 732 733 // If pod exists, reset remountRequired value 734 podObj.remountRequired = false 735 podObj.volumeMountStateForPod = markVolumeOpts.VolumeMountState 736 737 // if volume is mounted successfully, then it should be removed from foundDuringReconstruction map 738 if markVolumeOpts.VolumeMountState == operationexecutor.VolumeMounted { 739 delete(asw.foundDuringReconstruction[volumeName], podName) 740 } 741 if mounter != nil { 742 // The mounter stored in the object may have old information, 743 // use the newest one. 744 podObj.mounter = mounter 745 } 746 asw.attachedVolumes[volumeName].mountedPods[podName] = podObj 747 if utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) { 748 // Store the mount context also in the AttachedVolume to have a global volume context 749 // for a quick comparison in PodExistsInVolume. 750 if volumeObj.seLinuxMountContext == nil { 751 volumeObj.seLinuxMountContext = &markVolumeOpts.SELinuxMountContext 752 asw.attachedVolumes[volumeName] = volumeObj 753 } 754 } 755 756 return nil 757 } 758 759 func (asw *actualStateOfWorld) MarkVolumeAsResized(volumeName v1.UniqueVolumeName, claimSize *resource.Quantity) bool { 760 asw.Lock() 761 defer asw.Unlock() 762 763 volumeObj, ok := asw.attachedVolumes[volumeName] 764 if ok { 765 volumeObj.persistentVolumeSize = claimSize 766 asw.attachedVolumes[volumeName] = volumeObj 767 return true 768 } 769 return false 770 } 771 772 func (asw *actualStateOfWorld) MarkRemountRequired( 773 podName volumetypes.UniquePodName) { 774 asw.Lock() 775 defer asw.Unlock() 776 for volumeName, volumeObj := range asw.attachedVolumes { 777 if podObj, podExists := volumeObj.mountedPods[podName]; podExists { 778 volumePlugin, err := 779 asw.volumePluginMgr.FindPluginBySpec(podObj.volumeSpec) 780 if err != nil || volumePlugin == nil { 781 // Log and continue processing 782 klog.ErrorS(nil, "MarkRemountRequired failed to FindPluginBySpec for volume", "uniquePodName", podObj.podName, "podUID", podObj.podUID, "volumeName", volumeName, "volumeSpecName", podObj.volumeSpec.Name()) 783 continue 784 } 785 786 if volumePlugin.RequiresRemount(podObj.volumeSpec) { 787 podObj.remountRequired = true 788 asw.attachedVolumes[volumeName].mountedPods[podName] = podObj 789 } 790 } 791 } 792 } 793 794 func (asw *actualStateOfWorld) SetDeviceMountState( 795 volumeName v1.UniqueVolumeName, deviceMountState operationexecutor.DeviceMountState, devicePath, deviceMountPath, seLinuxMountContext string) error { 796 asw.Lock() 797 defer asw.Unlock() 798 799 volumeObj, volumeExists := asw.attachedVolumes[volumeName] 800 if !volumeExists { 801 return fmt.Errorf( 802 "no volume with the name %q exists in the list of attached volumes", 803 volumeName) 804 } 805 806 volumeObj.deviceMountState = deviceMountState 807 volumeObj.deviceMountPath = deviceMountPath 808 if devicePath != "" { 809 volumeObj.devicePath = devicePath 810 } 811 if utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) { 812 if seLinuxMountContext != "" { 813 volumeObj.seLinuxMountContext = &seLinuxMountContext 814 } 815 } 816 817 asw.attachedVolumes[volumeName] = volumeObj 818 return nil 819 } 820 821 func (asw *actualStateOfWorld) InitializeClaimSize(logger klog.Logger, volumeName v1.UniqueVolumeName, claimSize *resource.Quantity) { 822 asw.Lock() 823 defer asw.Unlock() 824 825 volumeObj, ok := asw.attachedVolumes[volumeName] 826 // only set volume claim size if claimStatusSize is zero 827 // this can happen when volume was rebuilt after kubelet startup 828 if ok && volumeObj.persistentVolumeSize == nil { 829 volumeObj.persistentVolumeSize = claimSize 830 asw.attachedVolumes[volumeName] = volumeObj 831 } 832 } 833 834 func (asw *actualStateOfWorld) GetClaimSize(volumeName v1.UniqueVolumeName) *resource.Quantity { 835 asw.RLock() 836 defer asw.RUnlock() 837 838 volumeObj, ok := asw.attachedVolumes[volumeName] 839 if ok { 840 return volumeObj.persistentVolumeSize 841 } 842 return nil 843 } 844 845 func (asw *actualStateOfWorld) DeletePodFromVolume( 846 podName volumetypes.UniquePodName, volumeName v1.UniqueVolumeName) error { 847 asw.Lock() 848 defer asw.Unlock() 849 850 volumeObj, volumeExists := asw.attachedVolumes[volumeName] 851 if !volumeExists { 852 return fmt.Errorf( 853 "no volume with the name %q exists in the list of attached volumes", 854 volumeName) 855 } 856 857 _, podExists := volumeObj.mountedPods[podName] 858 if podExists { 859 delete(asw.attachedVolumes[volumeName].mountedPods, podName) 860 } 861 862 // if there were reconstructed volumes, we should remove them 863 _, podExists = asw.foundDuringReconstruction[volumeName] 864 if podExists { 865 delete(asw.foundDuringReconstruction[volumeName], podName) 866 } 867 868 return nil 869 } 870 871 func (asw *actualStateOfWorld) DeleteVolume(volumeName v1.UniqueVolumeName) error { 872 asw.Lock() 873 defer asw.Unlock() 874 875 volumeObj, volumeExists := asw.attachedVolumes[volumeName] 876 if !volumeExists { 877 return nil 878 } 879 880 if len(volumeObj.mountedPods) != 0 { 881 return fmt.Errorf( 882 "failed to DeleteVolume %q, it still has %v mountedPods", 883 volumeName, 884 len(volumeObj.mountedPods)) 885 } 886 887 delete(asw.attachedVolumes, volumeName) 888 delete(asw.foundDuringReconstruction, volumeName) 889 return nil 890 } 891 892 func (asw *actualStateOfWorld) PodExistsInVolume(podName volumetypes.UniquePodName, volumeName v1.UniqueVolumeName, desiredVolumeSize resource.Quantity, seLinuxLabel string) (bool, string, error) { 893 asw.RLock() 894 defer asw.RUnlock() 895 896 volumeObj, volumeExists := asw.attachedVolumes[volumeName] 897 if !volumeExists { 898 return false, "", newVolumeNotAttachedError(volumeName) 899 } 900 901 // The volume exists, check its SELinux context mount option 902 if utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) { 903 if volumeObj.seLinuxMountContext != nil && *volumeObj.seLinuxMountContext != seLinuxLabel { 904 fullErr := newSELinuxMountMismatchError(volumeName) 905 return false, volumeObj.devicePath, fullErr 906 } 907 } 908 909 podObj, podExists := volumeObj.mountedPods[podName] 910 if podExists { 911 // if volume mount was uncertain we should keep trying to mount the volume 912 if podObj.volumeMountStateForPod == operationexecutor.VolumeMountUncertain { 913 return false, volumeObj.devicePath, nil 914 } 915 if podObj.remountRequired { 916 return true, volumeObj.devicePath, newRemountRequiredError(volumeObj.volumeName, podObj.podName) 917 } 918 if currentSize, expandVolume := asw.volumeNeedsExpansion(volumeObj, desiredVolumeSize); expandVolume { 919 return true, volumeObj.devicePath, newFsResizeRequiredError(volumeObj.volumeName, podObj.podName, currentSize) 920 } 921 } 922 923 return podExists, volumeObj.devicePath, nil 924 } 925 926 func (asw *actualStateOfWorld) volumeNeedsExpansion(volumeObj attachedVolume, desiredVolumeSize resource.Quantity) (resource.Quantity, bool) { 927 currentSize := resource.Quantity{} 928 if volumeObj.persistentVolumeSize != nil { 929 currentSize = volumeObj.persistentVolumeSize.DeepCopy() 930 } 931 if volumeObj.volumeInUseErrorForExpansion { 932 return currentSize, false 933 } 934 if volumeObj.persistentVolumeSize == nil || desiredVolumeSize.IsZero() { 935 return currentSize, false 936 } 937 938 if desiredVolumeSize.Cmp(*volumeObj.persistentVolumeSize) > 0 { 939 volumePlugin, err := asw.volumePluginMgr.FindNodeExpandablePluginBySpec(volumeObj.spec) 940 if err != nil || volumePlugin == nil { 941 // Log and continue processing 942 klog.InfoS("PodExistsInVolume failed to find expandable plugin", 943 "volume", volumeObj.volumeName, 944 "volumeSpecName", volumeObj.spec.Name()) 945 return currentSize, false 946 } 947 if volumePlugin.RequiresFSResize() { 948 return currentSize, true 949 } 950 } 951 return currentSize, false 952 } 953 954 func (asw *actualStateOfWorld) PodRemovedFromVolume( 955 podName volumetypes.UniquePodName, 956 volumeName v1.UniqueVolumeName) bool { 957 asw.RLock() 958 defer asw.RUnlock() 959 960 volumeObj, volumeExists := asw.attachedVolumes[volumeName] 961 if !volumeExists { 962 return true 963 } 964 965 podObj, podExists := volumeObj.mountedPods[podName] 966 if podExists { 967 // if volume mount was uncertain we should keep trying to unmount the volume 968 if podObj.volumeMountStateForPod == operationexecutor.VolumeMountUncertain { 969 return false 970 } 971 if podObj.volumeMountStateForPod == operationexecutor.VolumeMounted { 972 return false 973 } 974 } 975 return true 976 } 977 978 func (asw *actualStateOfWorld) VolumeExistsWithSpecName(podName volumetypes.UniquePodName, volumeSpecName string) bool { 979 asw.RLock() 980 defer asw.RUnlock() 981 for _, volumeObj := range asw.attachedVolumes { 982 if podObj, podExists := volumeObj.mountedPods[podName]; podExists { 983 if podObj.volumeSpec.Name() == volumeSpecName { 984 return true 985 } 986 } 987 } 988 return false 989 } 990 991 func (asw *actualStateOfWorld) VolumeExists( 992 volumeName v1.UniqueVolumeName) bool { 993 asw.RLock() 994 defer asw.RUnlock() 995 996 _, volumeExists := asw.attachedVolumes[volumeName] 997 return volumeExists 998 } 999 1000 func (asw *actualStateOfWorld) GetMountedVolumes() []MountedVolume { 1001 asw.RLock() 1002 defer asw.RUnlock() 1003 mountedVolume := make([]MountedVolume, 0 /* len */, len(asw.attachedVolumes) /* cap */) 1004 for _, volumeObj := range asw.attachedVolumes { 1005 for _, podObj := range volumeObj.mountedPods { 1006 if podObj.volumeMountStateForPod == operationexecutor.VolumeMounted { 1007 mountedVolume = append( 1008 mountedVolume, 1009 getMountedVolume(&podObj, &volumeObj)) 1010 } 1011 } 1012 } 1013 return mountedVolume 1014 } 1015 1016 // GetAllMountedVolumes returns all volumes which could be locally mounted for a pod. 1017 func (asw *actualStateOfWorld) GetAllMountedVolumes() []MountedVolume { 1018 asw.RLock() 1019 defer asw.RUnlock() 1020 mountedVolume := make([]MountedVolume, 0 /* len */, len(asw.attachedVolumes) /* cap */) 1021 for _, volumeObj := range asw.attachedVolumes { 1022 for _, podObj := range volumeObj.mountedPods { 1023 if podObj.volumeMountStateForPod == operationexecutor.VolumeMounted || 1024 podObj.volumeMountStateForPod == operationexecutor.VolumeMountUncertain { 1025 mountedVolume = append( 1026 mountedVolume, 1027 getMountedVolume(&podObj, &volumeObj)) 1028 } 1029 } 1030 } 1031 1032 return mountedVolume 1033 } 1034 1035 func (asw *actualStateOfWorld) GetMountedVolumesForPod( 1036 podName volumetypes.UniquePodName) []MountedVolume { 1037 asw.RLock() 1038 defer asw.RUnlock() 1039 mountedVolume := make([]MountedVolume, 0 /* len */, len(asw.attachedVolumes) /* cap */) 1040 for _, volumeObj := range asw.attachedVolumes { 1041 for mountedPodName, podObj := range volumeObj.mountedPods { 1042 if mountedPodName == podName && podObj.volumeMountStateForPod == operationexecutor.VolumeMounted { 1043 mountedVolume = append( 1044 mountedVolume, 1045 getMountedVolume(&podObj, &volumeObj)) 1046 } 1047 } 1048 } 1049 1050 return mountedVolume 1051 } 1052 1053 func (asw *actualStateOfWorld) GetPossiblyMountedVolumesForPod( 1054 podName volumetypes.UniquePodName) []MountedVolume { 1055 asw.RLock() 1056 defer asw.RUnlock() 1057 mountedVolume := make([]MountedVolume, 0 /* len */, len(asw.attachedVolumes) /* cap */) 1058 for _, volumeObj := range asw.attachedVolumes { 1059 for mountedPodName, podObj := range volumeObj.mountedPods { 1060 if mountedPodName == podName && 1061 (podObj.volumeMountStateForPod == operationexecutor.VolumeMounted || 1062 podObj.volumeMountStateForPod == operationexecutor.VolumeMountUncertain) { 1063 mountedVolume = append( 1064 mountedVolume, 1065 getMountedVolume(&podObj, &volumeObj)) 1066 } 1067 } 1068 } 1069 1070 return mountedVolume 1071 } 1072 1073 func (asw *actualStateOfWorld) GetGloballyMountedVolumes() []AttachedVolume { 1074 asw.RLock() 1075 defer asw.RUnlock() 1076 globallyMountedVolumes := make( 1077 []AttachedVolume, 0 /* len */, len(asw.attachedVolumes) /* cap */) 1078 for _, volumeObj := range asw.attachedVolumes { 1079 if volumeObj.deviceMountState == operationexecutor.DeviceGloballyMounted { 1080 globallyMountedVolumes = append( 1081 globallyMountedVolumes, 1082 asw.newAttachedVolume(&volumeObj)) 1083 } 1084 } 1085 1086 return globallyMountedVolumes 1087 } 1088 1089 func (asw *actualStateOfWorld) GetAttachedVolumes() []AttachedVolume { 1090 asw.RLock() 1091 defer asw.RUnlock() 1092 allAttachedVolumes := make( 1093 []AttachedVolume, 0 /* len */, len(asw.attachedVolumes) /* cap */) 1094 for _, volumeObj := range asw.attachedVolumes { 1095 allAttachedVolumes = append( 1096 allAttachedVolumes, 1097 asw.newAttachedVolume(&volumeObj)) 1098 } 1099 1100 return allAttachedVolumes 1101 } 1102 1103 func (asw *actualStateOfWorld) GetUnmountedVolumes() []AttachedVolume { 1104 asw.RLock() 1105 defer asw.RUnlock() 1106 unmountedVolumes := make([]AttachedVolume, 0 /* len */, len(asw.attachedVolumes) /* cap */) 1107 for _, volumeObj := range asw.attachedVolumes { 1108 if len(volumeObj.mountedPods) == 0 { 1109 unmountedVolumes = append( 1110 unmountedVolumes, 1111 asw.newAttachedVolume(&volumeObj)) 1112 } 1113 } 1114 1115 return unmountedVolumes 1116 } 1117 1118 func (asw *actualStateOfWorld) newAttachedVolume( 1119 attachedVolume *attachedVolume) AttachedVolume { 1120 seLinuxMountContext := "" 1121 if utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) { 1122 if attachedVolume.seLinuxMountContext != nil { 1123 seLinuxMountContext = *attachedVolume.seLinuxMountContext 1124 } 1125 } 1126 return AttachedVolume{ 1127 AttachedVolume: operationexecutor.AttachedVolume{ 1128 VolumeName: attachedVolume.volumeName, 1129 VolumeSpec: attachedVolume.spec, 1130 NodeName: asw.nodeName, 1131 PluginIsAttachable: attachedVolume.pluginIsAttachable == volumeAttachabilityTrue, 1132 DevicePath: attachedVolume.devicePath, 1133 DeviceMountPath: attachedVolume.deviceMountPath, 1134 PluginName: attachedVolume.pluginName, 1135 SELinuxMountContext: seLinuxMountContext}, 1136 DeviceMountState: attachedVolume.deviceMountState, 1137 SELinuxMountContext: seLinuxMountContext, 1138 } 1139 } 1140 1141 // Compile-time check to ensure volumeNotAttachedError implements the error interface 1142 var _ error = volumeNotAttachedError{} 1143 1144 // volumeNotAttachedError is an error returned when PodExistsInVolume() fails to 1145 // find specified volume in the list of attached volumes. 1146 type volumeNotAttachedError struct { 1147 volumeName v1.UniqueVolumeName 1148 } 1149 1150 func (err volumeNotAttachedError) Error() string { 1151 return fmt.Sprintf( 1152 "volumeName %q does not exist in the list of attached volumes", 1153 err.volumeName) 1154 } 1155 1156 func newVolumeNotAttachedError(volumeName v1.UniqueVolumeName) error { 1157 return volumeNotAttachedError{ 1158 volumeName: volumeName, 1159 } 1160 } 1161 1162 // Compile-time check to ensure remountRequiredError implements the error interface 1163 var _ error = remountRequiredError{} 1164 1165 // remountRequiredError is an error returned when PodExistsInVolume() found 1166 // volume/pod attached/mounted but remountRequired was true, indicating the 1167 // given volume should be remounted to the pod to reflect changes in the 1168 // referencing pod. 1169 type remountRequiredError struct { 1170 volumeName v1.UniqueVolumeName 1171 podName volumetypes.UniquePodName 1172 } 1173 1174 func (err remountRequiredError) Error() string { 1175 return fmt.Sprintf( 1176 "volumeName %q is mounted to %q but should be remounted", 1177 err.volumeName, err.podName) 1178 } 1179 1180 func newRemountRequiredError( 1181 volumeName v1.UniqueVolumeName, podName volumetypes.UniquePodName) error { 1182 return remountRequiredError{ 1183 volumeName: volumeName, 1184 podName: podName, 1185 } 1186 } 1187 1188 // fsResizeRequiredError is an error returned when PodExistsInVolume() found 1189 // volume/pod attached/mounted but fsResizeRequired was true, indicating the 1190 // given volume receives an resize request after attached/mounted. 1191 type FsResizeRequiredError struct { 1192 CurrentSize resource.Quantity 1193 volumeName v1.UniqueVolumeName 1194 podName volumetypes.UniquePodName 1195 } 1196 1197 func (err FsResizeRequiredError) Error() string { 1198 return fmt.Sprintf( 1199 "volumeName %q mounted to %q needs to resize file system", 1200 err.volumeName, err.podName) 1201 } 1202 1203 func newFsResizeRequiredError( 1204 volumeName v1.UniqueVolumeName, podName volumetypes.UniquePodName, currentSize resource.Quantity) error { 1205 return FsResizeRequiredError{ 1206 CurrentSize: currentSize, 1207 volumeName: volumeName, 1208 podName: podName, 1209 } 1210 } 1211 1212 // IsFSResizeRequiredError returns true if the specified error is a 1213 // fsResizeRequiredError. 1214 func IsFSResizeRequiredError(err error) bool { 1215 _, ok := err.(FsResizeRequiredError) 1216 return ok 1217 } 1218 1219 // getMountedVolume constructs and returns a MountedVolume object from the given 1220 // mountedPod and attachedVolume objects. 1221 func getMountedVolume( 1222 mountedPod *mountedPod, attachedVolume *attachedVolume) MountedVolume { 1223 seLinuxMountContext := "" 1224 if attachedVolume.seLinuxMountContext != nil { 1225 seLinuxMountContext = *attachedVolume.seLinuxMountContext 1226 } 1227 return MountedVolume{ 1228 MountedVolume: operationexecutor.MountedVolume{ 1229 PodName: mountedPod.podName, 1230 VolumeName: attachedVolume.volumeName, 1231 InnerVolumeSpecName: mountedPod.volumeSpec.Name(), 1232 OuterVolumeSpecName: mountedPod.outerVolumeSpecName, 1233 PluginName: attachedVolume.pluginName, 1234 PodUID: mountedPod.podUID, 1235 Mounter: mountedPod.mounter, 1236 BlockVolumeMapper: mountedPod.blockVolumeMapper, 1237 VolumeGidValue: mountedPod.volumeGidValue, 1238 VolumeSpec: mountedPod.volumeSpec, 1239 DeviceMountPath: attachedVolume.deviceMountPath, 1240 SELinuxMountContext: seLinuxMountContext}} 1241 1242 } 1243 1244 // seLinuxMountMismatchError is an error returned when PodExistsInVolume() found 1245 // a volume mounted with a different SELinux label than expected. 1246 type seLinuxMountMismatchError struct { 1247 volumeName v1.UniqueVolumeName 1248 } 1249 1250 func (err seLinuxMountMismatchError) Error() string { 1251 return fmt.Sprintf( 1252 "waiting for unmount of volume %q, because it is already mounted to a different pod with a different SELinux label", 1253 err.volumeName) 1254 } 1255 1256 func newSELinuxMountMismatchError(volumeName v1.UniqueVolumeName) error { 1257 return seLinuxMountMismatchError{ 1258 volumeName: volumeName, 1259 } 1260 } 1261 1262 // IsSELinuxMountMismatchError returns true if the specified error is a 1263 // seLinuxMountMismatchError. 1264 func IsSELinuxMountMismatchError(err error) bool { 1265 _, ok := err.(seLinuxMountMismatchError) 1266 return ok 1267 }