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