actual_state_of_world.go 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913
  1. /*
  2. Copyright 2016 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. /*
  14. Package cache implements data structures used by the kubelet volume manager to
  15. keep track of attached volumes and the pods that mounted them.
  16. */
  17. package cache
  18. import (
  19. "fmt"
  20. "sync"
  21. v1 "k8s.io/api/core/v1"
  22. "k8s.io/apimachinery/pkg/types"
  23. utilfeature "k8s.io/apiserver/pkg/util/feature"
  24. "k8s.io/klog"
  25. "k8s.io/kubernetes/pkg/features"
  26. "k8s.io/kubernetes/pkg/volume"
  27. "k8s.io/kubernetes/pkg/volume/util"
  28. "k8s.io/kubernetes/pkg/volume/util/operationexecutor"
  29. volumetypes "k8s.io/kubernetes/pkg/volume/util/types"
  30. )
  31. // ActualStateOfWorld defines a set of thread-safe operations for the kubelet
  32. // volume manager's actual state of the world cache.
  33. // This cache contains volumes->pods i.e. a set of all volumes attached to this
  34. // node and the pods that the manager believes have successfully mounted the
  35. // volume.
  36. // Note: This is distinct from the ActualStateOfWorld implemented by the
  37. // attach/detach controller. They both keep track of different objects. This
  38. // contains kubelet volume manager specific state.
  39. type ActualStateOfWorld interface {
  40. // ActualStateOfWorld must implement the methods required to allow
  41. // operationexecutor to interact with it.
  42. operationexecutor.ActualStateOfWorldMounterUpdater
  43. // ActualStateOfWorld must implement the methods required to allow
  44. // operationexecutor to interact with it.
  45. operationexecutor.ActualStateOfWorldAttacherUpdater
  46. // AddPodToVolume adds the given pod to the given volume in the cache
  47. // indicating the specified volume has been successfully mounted to the
  48. // specified pod.
  49. // If a pod with the same unique name already exists under the specified
  50. // volume, reset the pod's remountRequired value.
  51. // If a volume with the name volumeName does not exist in the list of
  52. // attached volumes, an error is returned.
  53. AddPodToVolume(operationexecutor.MarkVolumeOpts) error
  54. // MarkRemountRequired marks each volume that is successfully attached and
  55. // mounted for the specified pod as requiring remount (if the plugin for the
  56. // volume indicates it requires remounting on pod updates). Atomically
  57. // updating volumes depend on this to update the contents of the volume on
  58. // pod update.
  59. MarkRemountRequired(podName volumetypes.UniquePodName)
  60. // SetDeviceMountState sets device mount state for the given volume. When deviceMountState is set to DeviceGloballyMounted
  61. // then device is mounted at a global mount point. When it is set to DeviceMountUncertain then also it means volume
  62. // MAY be globally mounted at a global mount point. In both cases - the volume must be unmounted from
  63. // global mount point prior to detach.
  64. // If a volume with the name volumeName does not exist in the list of
  65. // attached volumes, an error is returned.
  66. SetDeviceMountState(volumeName v1.UniqueVolumeName, deviceMountState operationexecutor.DeviceMountState, devicePath, deviceMountPath string) error
  67. // DeletePodFromVolume removes the given pod from the given volume in the
  68. // cache indicating the volume has been successfully unmounted from the pod.
  69. // If a pod with the same unique name does not exist under the specified
  70. // volume, this is a no-op.
  71. // If a volume with the name volumeName does not exist in the list of
  72. // attached volumes, an error is returned.
  73. DeletePodFromVolume(podName volumetypes.UniquePodName, volumeName v1.UniqueVolumeName) error
  74. // DeleteVolume removes the given volume from the list of attached volumes
  75. // in the cache indicating the volume has been successfully detached from
  76. // this node.
  77. // If a volume with the name volumeName does not exist in the list of
  78. // attached volumes, this is a no-op.
  79. // If a volume with the name volumeName exists and its list of mountedPods
  80. // is not empty, an error is returned.
  81. DeleteVolume(volumeName v1.UniqueVolumeName) error
  82. // PodExistsInVolume returns true if the given pod exists in the list of
  83. // mountedPods for the given volume in the cache, indicating that the volume
  84. // is attached to this node and the pod has successfully mounted it.
  85. // If a pod with the same unique name does not exist under the specified
  86. // volume, false is returned.
  87. // If a volume with the name volumeName does not exist in the list of
  88. // attached volumes, a volumeNotAttachedError is returned indicating the
  89. // given volume is not yet attached.
  90. // If the given volumeName/podName combo exists but the value of
  91. // remountRequired is true, a remountRequiredError is returned indicating
  92. // the given volume has been successfully mounted to this pod but should be
  93. // remounted to reflect changes in the referencing pod. Atomically updating
  94. // volumes, depend on this to update the contents of the volume.
  95. // All volume mounting calls should be idempotent so a second mount call for
  96. // volumes that do not need to update contents should not fail.
  97. PodExistsInVolume(podName volumetypes.UniquePodName, volumeName v1.UniqueVolumeName) (bool, string, error)
  98. // VolumeExistsWithSpecName returns true if the given volume specified with the
  99. // volume spec name (a.k.a., InnerVolumeSpecName) exists in the list of
  100. // volumes that should be attached to this node.
  101. // If a pod with the same name does not exist under the specified
  102. // volume, false is returned.
  103. VolumeExistsWithSpecName(podName volumetypes.UniquePodName, volumeSpecName string) bool
  104. // VolumeExists returns true if the given volume exists in the list of
  105. // attached volumes in the cache, indicating the volume is attached to this
  106. // node.
  107. VolumeExists(volumeName v1.UniqueVolumeName) bool
  108. // GetMountedVolumes generates and returns a list of volumes and the pods
  109. // they are successfully attached and mounted for based on the current
  110. // actual state of the world.
  111. GetMountedVolumes() []MountedVolume
  112. // GetAllMountedVolumes returns list of all possibly mounted volumes including
  113. // those that are in VolumeMounted state and VolumeMountUncertain state.
  114. GetAllMountedVolumes() []MountedVolume
  115. // GetMountedVolumesForPod generates and returns a list of volumes that are
  116. // successfully attached and mounted for the specified pod based on the
  117. // current actual state of the world.
  118. GetMountedVolumesForPod(podName volumetypes.UniquePodName) []MountedVolume
  119. // GetGloballyMountedVolumes generates and returns a list of all attached
  120. // volumes that are globally mounted. This list can be used to determine
  121. // which volumes should be reported as "in use" in the node's VolumesInUse
  122. // status field. Globally mounted here refers to the shared plugin mount
  123. // point for the attachable volume from which the pod specific mount points
  124. // are created (via bind mount).
  125. GetGloballyMountedVolumes() []AttachedVolume
  126. // GetUnmountedVolumes generates and returns a list of attached volumes that
  127. // have no mountedPods. This list can be used to determine which volumes are
  128. // no longer referenced and may be globally unmounted and detached.
  129. GetUnmountedVolumes() []AttachedVolume
  130. // MarkFSResizeRequired marks each volume that is successfully attached and
  131. // mounted for the specified pod as requiring file system resize (if the plugin for the
  132. // volume indicates it requires file system resize).
  133. MarkFSResizeRequired(volumeName v1.UniqueVolumeName, podName volumetypes.UniquePodName)
  134. // GetAttachedVolumes returns a list of volumes that is known to be attached
  135. // to the node. This list can be used to determine volumes that are either in-use
  136. // or have a mount/unmount operation pending.
  137. GetAttachedVolumes() []AttachedVolume
  138. }
  139. // MountedVolume represents a volume that has successfully been mounted to a pod.
  140. type MountedVolume struct {
  141. operationexecutor.MountedVolume
  142. }
  143. // AttachedVolume represents a volume that is attached to a node.
  144. type AttachedVolume struct {
  145. operationexecutor.AttachedVolume
  146. // DeviceMountState indicates if device has been globally mounted or is not.
  147. DeviceMountState operationexecutor.DeviceMountState
  148. }
  149. // DeviceMayBeMounted returns true if device is mounted in global path or is in
  150. // uncertain state.
  151. func (av AttachedVolume) DeviceMayBeMounted() bool {
  152. return av.DeviceMountState == operationexecutor.DeviceGloballyMounted ||
  153. av.DeviceMountState == operationexecutor.DeviceMountUncertain
  154. }
  155. // NewActualStateOfWorld returns a new instance of ActualStateOfWorld.
  156. func NewActualStateOfWorld(
  157. nodeName types.NodeName,
  158. volumePluginMgr *volume.VolumePluginMgr) ActualStateOfWorld {
  159. return &actualStateOfWorld{
  160. nodeName: nodeName,
  161. attachedVolumes: make(map[v1.UniqueVolumeName]attachedVolume),
  162. volumePluginMgr: volumePluginMgr,
  163. }
  164. }
  165. // IsVolumeNotAttachedError returns true if the specified error is a
  166. // volumeNotAttachedError.
  167. func IsVolumeNotAttachedError(err error) bool {
  168. _, ok := err.(volumeNotAttachedError)
  169. return ok
  170. }
  171. // IsRemountRequiredError returns true if the specified error is a
  172. // remountRequiredError.
  173. func IsRemountRequiredError(err error) bool {
  174. _, ok := err.(remountRequiredError)
  175. return ok
  176. }
  177. type actualStateOfWorld struct {
  178. // nodeName is the name of this node. This value is passed to Attach/Detach
  179. nodeName types.NodeName
  180. // attachedVolumes is a map containing the set of volumes the kubelet volume
  181. // manager believes to be successfully attached to this node. Volume types
  182. // that do not implement an attacher interface are assumed to be in this
  183. // state by default.
  184. // The key in this map is the name of the volume and the value is an object
  185. // containing more information about the attached volume.
  186. attachedVolumes map[v1.UniqueVolumeName]attachedVolume
  187. // volumePluginMgr is the volume plugin manager used to create volume
  188. // plugin objects.
  189. volumePluginMgr *volume.VolumePluginMgr
  190. sync.RWMutex
  191. }
  192. // attachedVolume represents a volume the kubelet volume manager believes to be
  193. // successfully attached to a node it is managing. Volume types that do not
  194. // implement an attacher are assumed to be in this state.
  195. type attachedVolume struct {
  196. // volumeName contains the unique identifier for this volume.
  197. volumeName v1.UniqueVolumeName
  198. // mountedPods is a map containing the set of pods that this volume has been
  199. // successfully mounted to. The key in this map is the name of the pod and
  200. // the value is a mountedPod object containing more information about the
  201. // pod.
  202. mountedPods map[volumetypes.UniquePodName]mountedPod
  203. // spec is the volume spec containing the specification for this volume.
  204. // Used to generate the volume plugin object, and passed to plugin methods.
  205. // In particular, the Unmount method uses spec.Name() as the volumeSpecName
  206. // in the mount path:
  207. // /var/lib/kubelet/pods/{podUID}/volumes/{escapeQualifiedPluginName}/{volumeSpecName}/
  208. spec *volume.Spec
  209. // pluginName is the Unescaped Qualified name of the volume plugin used to
  210. // attach and mount this volume. It is stored separately in case the full
  211. // volume spec (everything except the name) can not be reconstructed for a
  212. // volume that should be unmounted (which would be the case for a mount path
  213. // read from disk without a full volume spec).
  214. pluginName string
  215. // pluginIsAttachable indicates the volume plugin used to attach and mount
  216. // this volume implements the volume.Attacher interface
  217. pluginIsAttachable bool
  218. // deviceMountState stores information that tells us if device is mounted
  219. // globally or not
  220. deviceMountState operationexecutor.DeviceMountState
  221. // devicePath contains the path on the node where the volume is attached for
  222. // attachable volumes
  223. devicePath string
  224. // deviceMountPath contains the path on the node where the device should
  225. // be mounted after it is attached.
  226. deviceMountPath string
  227. }
  228. // The mountedPod object represents a pod for which the kubelet volume manager
  229. // believes the underlying volume has been successfully been mounted.
  230. type mountedPod struct {
  231. // the name of the pod
  232. podName volumetypes.UniquePodName
  233. // the UID of the pod
  234. podUID types.UID
  235. // mounter used to mount
  236. mounter volume.Mounter
  237. // mapper used to block volumes support
  238. blockVolumeMapper volume.BlockVolumeMapper
  239. // spec is the volume spec containing the specification for this volume.
  240. // Used to generate the volume plugin object, and passed to plugin methods.
  241. // In particular, the Unmount method uses spec.Name() as the volumeSpecName
  242. // in the mount path:
  243. // /var/lib/kubelet/pods/{podUID}/volumes/{escapeQualifiedPluginName}/{volumeSpecName}/
  244. volumeSpec *volume.Spec
  245. // outerVolumeSpecName is the volume.Spec.Name() of the volume as referenced
  246. // directly in the pod. If the volume was referenced through a persistent
  247. // volume claim, this contains the volume.Spec.Name() of the persistent
  248. // volume claim
  249. outerVolumeSpecName string
  250. // remountRequired indicates the underlying volume has been successfully
  251. // mounted to this pod but it should be remounted to reflect changes in the
  252. // referencing pod.
  253. // Atomically updating volumes depend on this to update the contents of the
  254. // volume. All volume mounting calls should be idempotent so a second mount
  255. // call for volumes that do not need to update contents should not fail.
  256. remountRequired bool
  257. // volumeGidValue contains the value of the GID annotation, if present.
  258. volumeGidValue string
  259. // fsResizeRequired indicates the underlying volume has been successfully
  260. // mounted to this pod but its size has been expanded after that.
  261. fsResizeRequired bool
  262. // volumeMountStateForPod stores state of volume mount for the pod. if it is:
  263. // - VolumeMounted: means volume for pod has been successfully mounted
  264. // - VolumeMountUncertain: means volume for pod may not be mounted, but it must be unmounted
  265. volumeMountStateForPod operationexecutor.VolumeMountState
  266. }
  267. func (asw *actualStateOfWorld) MarkVolumeAsAttached(
  268. volumeName v1.UniqueVolumeName, volumeSpec *volume.Spec, _ types.NodeName, devicePath string) error {
  269. return asw.addVolume(volumeName, volumeSpec, devicePath)
  270. }
  271. func (asw *actualStateOfWorld) MarkVolumeAsUncertain(
  272. volumeName v1.UniqueVolumeName, volumeSpec *volume.Spec, _ types.NodeName) error {
  273. return nil
  274. }
  275. func (asw *actualStateOfWorld) MarkVolumeAsDetached(
  276. volumeName v1.UniqueVolumeName, nodeName types.NodeName) {
  277. asw.DeleteVolume(volumeName)
  278. }
  279. func (asw *actualStateOfWorld) MarkVolumeAsMounted(markVolumeOpts operationexecutor.MarkVolumeOpts) error {
  280. return asw.AddPodToVolume(markVolumeOpts)
  281. }
  282. func (asw *actualStateOfWorld) AddVolumeToReportAsAttached(volumeName v1.UniqueVolumeName, nodeName types.NodeName) {
  283. // no operation for kubelet side
  284. }
  285. func (asw *actualStateOfWorld) RemoveVolumeFromReportAsAttached(volumeName v1.UniqueVolumeName, nodeName types.NodeName) error {
  286. // no operation for kubelet side
  287. return nil
  288. }
  289. func (asw *actualStateOfWorld) MarkVolumeAsUnmounted(
  290. podName volumetypes.UniquePodName, volumeName v1.UniqueVolumeName) error {
  291. return asw.DeletePodFromVolume(podName, volumeName)
  292. }
  293. func (asw *actualStateOfWorld) MarkDeviceAsMounted(
  294. volumeName v1.UniqueVolumeName, devicePath, deviceMountPath string) error {
  295. return asw.SetDeviceMountState(volumeName, operationexecutor.DeviceGloballyMounted, devicePath, deviceMountPath)
  296. }
  297. func (asw *actualStateOfWorld) MarkDeviceAsUncertain(
  298. volumeName v1.UniqueVolumeName, devicePath, deviceMountPath string) error {
  299. return asw.SetDeviceMountState(volumeName, operationexecutor.DeviceMountUncertain, devicePath, deviceMountPath)
  300. }
  301. func (asw *actualStateOfWorld) MarkVolumeMountAsUncertain(markVolumeOpts operationexecutor.MarkVolumeOpts) error {
  302. markVolumeOpts.VolumeMountState = operationexecutor.VolumeMountUncertain
  303. return asw.AddPodToVolume(markVolumeOpts)
  304. }
  305. func (asw *actualStateOfWorld) MarkDeviceAsUnmounted(
  306. volumeName v1.UniqueVolumeName) error {
  307. return asw.SetDeviceMountState(volumeName, operationexecutor.DeviceNotMounted, "", "")
  308. }
  309. func (asw *actualStateOfWorld) GetDeviceMountState(volumeName v1.UniqueVolumeName) operationexecutor.DeviceMountState {
  310. asw.RLock()
  311. defer asw.RUnlock()
  312. volumeObj, volumeExists := asw.attachedVolumes[volumeName]
  313. if !volumeExists {
  314. return operationexecutor.DeviceNotMounted
  315. }
  316. return volumeObj.deviceMountState
  317. }
  318. func (asw *actualStateOfWorld) GetVolumeMountState(volumeName v1.UniqueVolumeName, podName volumetypes.UniquePodName) operationexecutor.VolumeMountState {
  319. asw.RLock()
  320. defer asw.RUnlock()
  321. volumeObj, volumeExists := asw.attachedVolumes[volumeName]
  322. if !volumeExists {
  323. return operationexecutor.VolumeNotMounted
  324. }
  325. podObj, podExists := volumeObj.mountedPods[podName]
  326. if !podExists {
  327. return operationexecutor.VolumeNotMounted
  328. }
  329. return podObj.volumeMountStateForPod
  330. }
  331. // addVolume adds the given volume to the cache indicating the specified
  332. // volume is attached to this node. If no volume name is supplied, a unique
  333. // volume name is generated from the volumeSpec and returned on success. If a
  334. // volume with the same generated name already exists, this is a noop. If no
  335. // volume plugin can support the given volumeSpec or more than one plugin can
  336. // support it, an error is returned.
  337. func (asw *actualStateOfWorld) addVolume(
  338. volumeName v1.UniqueVolumeName, volumeSpec *volume.Spec, devicePath string) error {
  339. asw.Lock()
  340. defer asw.Unlock()
  341. volumePlugin, err := asw.volumePluginMgr.FindPluginBySpec(volumeSpec)
  342. if err != nil || volumePlugin == nil {
  343. return fmt.Errorf(
  344. "failed to get Plugin from volumeSpec for volume %q err=%v",
  345. volumeSpec.Name(),
  346. err)
  347. }
  348. if len(volumeName) == 0 {
  349. volumeName, err = util.GetUniqueVolumeNameFromSpec(volumePlugin, volumeSpec)
  350. if err != nil {
  351. return fmt.Errorf(
  352. "failed to GetUniqueVolumeNameFromSpec for volumeSpec %q using volume plugin %q err=%v",
  353. volumeSpec.Name(),
  354. volumePlugin.GetPluginName(),
  355. err)
  356. }
  357. }
  358. pluginIsAttachable := false
  359. if attachablePlugin, err := asw.volumePluginMgr.FindAttachablePluginBySpec(volumeSpec); err == nil && attachablePlugin != nil {
  360. pluginIsAttachable = true
  361. }
  362. volumeObj, volumeExists := asw.attachedVolumes[volumeName]
  363. if !volumeExists {
  364. volumeObj = attachedVolume{
  365. volumeName: volumeName,
  366. spec: volumeSpec,
  367. mountedPods: make(map[volumetypes.UniquePodName]mountedPod),
  368. pluginName: volumePlugin.GetPluginName(),
  369. pluginIsAttachable: pluginIsAttachable,
  370. deviceMountState: operationexecutor.DeviceNotMounted,
  371. devicePath: devicePath,
  372. }
  373. } else {
  374. // If volume object already exists, update the fields such as device path
  375. volumeObj.devicePath = devicePath
  376. klog.V(2).Infof("Volume %q is already added to attachedVolume list, update device path %q",
  377. volumeName,
  378. devicePath)
  379. }
  380. asw.attachedVolumes[volumeName] = volumeObj
  381. return nil
  382. }
  383. func (asw *actualStateOfWorld) AddPodToVolume(markVolumeOpts operationexecutor.MarkVolumeOpts) error {
  384. podName := markVolumeOpts.PodName
  385. podUID := markVolumeOpts.PodUID
  386. volumeName := markVolumeOpts.VolumeName
  387. mounter := markVolumeOpts.Mounter
  388. blockVolumeMapper := markVolumeOpts.BlockVolumeMapper
  389. outerVolumeSpecName := markVolumeOpts.OuterVolumeSpecName
  390. volumeGidValue := markVolumeOpts.VolumeGidVolume
  391. volumeSpec := markVolumeOpts.VolumeSpec
  392. asw.Lock()
  393. defer asw.Unlock()
  394. volumeObj, volumeExists := asw.attachedVolumes[volumeName]
  395. if !volumeExists {
  396. return fmt.Errorf(
  397. "no volume with the name %q exists in the list of attached volumes",
  398. volumeName)
  399. }
  400. podObj, podExists := volumeObj.mountedPods[podName]
  401. if !podExists {
  402. podObj = mountedPod{
  403. podName: podName,
  404. podUID: podUID,
  405. mounter: mounter,
  406. blockVolumeMapper: blockVolumeMapper,
  407. outerVolumeSpecName: outerVolumeSpecName,
  408. volumeGidValue: volumeGidValue,
  409. volumeSpec: volumeSpec,
  410. volumeMountStateForPod: markVolumeOpts.VolumeMountState,
  411. }
  412. }
  413. // If pod exists, reset remountRequired value
  414. podObj.remountRequired = false
  415. podObj.volumeMountStateForPod = markVolumeOpts.VolumeMountState
  416. asw.attachedVolumes[volumeName].mountedPods[podName] = podObj
  417. return nil
  418. }
  419. func (asw *actualStateOfWorld) MarkVolumeAsResized(
  420. podName volumetypes.UniquePodName,
  421. volumeName v1.UniqueVolumeName) error {
  422. asw.Lock()
  423. defer asw.Unlock()
  424. volumeObj, volumeExists := asw.attachedVolumes[volumeName]
  425. if !volumeExists {
  426. return fmt.Errorf(
  427. "no volume with the name %q exists in the list of attached volumes",
  428. volumeName)
  429. }
  430. podObj, podExists := volumeObj.mountedPods[podName]
  431. if !podExists {
  432. return fmt.Errorf(
  433. "no pod with the name %q exists in the mounted pods list of volume %s",
  434. podName,
  435. volumeName)
  436. }
  437. klog.V(5).Infof("Volume %s(OuterVolumeSpecName %s) of pod %s has been resized",
  438. volumeName, podObj.outerVolumeSpecName, podName)
  439. podObj.fsResizeRequired = false
  440. asw.attachedVolumes[volumeName].mountedPods[podName] = podObj
  441. return nil
  442. }
  443. func (asw *actualStateOfWorld) MarkRemountRequired(
  444. podName volumetypes.UniquePodName) {
  445. asw.Lock()
  446. defer asw.Unlock()
  447. for volumeName, volumeObj := range asw.attachedVolumes {
  448. if podObj, podExists := volumeObj.mountedPods[podName]; podExists {
  449. volumePlugin, err :=
  450. asw.volumePluginMgr.FindPluginBySpec(podObj.volumeSpec)
  451. if err != nil || volumePlugin == nil {
  452. // Log and continue processing
  453. klog.Errorf(
  454. "MarkRemountRequired failed to FindPluginBySpec for pod %q (podUid %q) volume: %q (volSpecName: %q)",
  455. podObj.podName,
  456. podObj.podUID,
  457. volumeObj.volumeName,
  458. podObj.volumeSpec.Name())
  459. continue
  460. }
  461. if volumePlugin.RequiresRemount() {
  462. podObj.remountRequired = true
  463. asw.attachedVolumes[volumeName].mountedPods[podName] = podObj
  464. }
  465. }
  466. }
  467. }
  468. func (asw *actualStateOfWorld) MarkFSResizeRequired(
  469. volumeName v1.UniqueVolumeName,
  470. podName volumetypes.UniquePodName) {
  471. asw.Lock()
  472. defer asw.Unlock()
  473. volumeObj, volumeExists := asw.attachedVolumes[volumeName]
  474. if !volumeExists {
  475. klog.Warningf("MarkFSResizeRequired for volume %s failed as volume not exist", volumeName)
  476. return
  477. }
  478. podObj, podExists := volumeObj.mountedPods[podName]
  479. if !podExists {
  480. klog.Warningf("MarkFSResizeRequired for volume %s failed "+
  481. "as pod(%s) not exist", volumeName, podName)
  482. return
  483. }
  484. volumePlugin, err :=
  485. asw.volumePluginMgr.FindNodeExpandablePluginBySpec(podObj.volumeSpec)
  486. if err != nil || volumePlugin == nil {
  487. // Log and continue processing
  488. klog.Errorf(
  489. "MarkFSResizeRequired failed to find expandable plugin for pod %q volume: %q (volSpecName: %q)",
  490. podObj.podName,
  491. volumeObj.volumeName,
  492. podObj.volumeSpec.Name())
  493. return
  494. }
  495. if volumePlugin.RequiresFSResize() {
  496. if !podObj.fsResizeRequired {
  497. klog.V(3).Infof("PVC volume %s(OuterVolumeSpecName %s) of pod %s requires file system resize",
  498. volumeName, podObj.outerVolumeSpecName, podName)
  499. podObj.fsResizeRequired = true
  500. }
  501. asw.attachedVolumes[volumeName].mountedPods[podName] = podObj
  502. }
  503. }
  504. func (asw *actualStateOfWorld) SetDeviceMountState(
  505. volumeName v1.UniqueVolumeName, deviceMountState operationexecutor.DeviceMountState, devicePath, deviceMountPath string) error {
  506. asw.Lock()
  507. defer asw.Unlock()
  508. volumeObj, volumeExists := asw.attachedVolumes[volumeName]
  509. if !volumeExists {
  510. return fmt.Errorf(
  511. "no volume with the name %q exists in the list of attached volumes",
  512. volumeName)
  513. }
  514. volumeObj.deviceMountState = deviceMountState
  515. volumeObj.deviceMountPath = deviceMountPath
  516. if devicePath != "" {
  517. volumeObj.devicePath = devicePath
  518. }
  519. asw.attachedVolumes[volumeName] = volumeObj
  520. return nil
  521. }
  522. func (asw *actualStateOfWorld) DeletePodFromVolume(
  523. podName volumetypes.UniquePodName, volumeName v1.UniqueVolumeName) error {
  524. asw.Lock()
  525. defer asw.Unlock()
  526. volumeObj, volumeExists := asw.attachedVolumes[volumeName]
  527. if !volumeExists {
  528. return fmt.Errorf(
  529. "no volume with the name %q exists in the list of attached volumes",
  530. volumeName)
  531. }
  532. _, podExists := volumeObj.mountedPods[podName]
  533. if podExists {
  534. delete(asw.attachedVolumes[volumeName].mountedPods, podName)
  535. }
  536. return nil
  537. }
  538. func (asw *actualStateOfWorld) DeleteVolume(volumeName v1.UniqueVolumeName) error {
  539. asw.Lock()
  540. defer asw.Unlock()
  541. volumeObj, volumeExists := asw.attachedVolumes[volumeName]
  542. if !volumeExists {
  543. return nil
  544. }
  545. if len(volumeObj.mountedPods) != 0 {
  546. return fmt.Errorf(
  547. "failed to DeleteVolume %q, it still has %v mountedPods",
  548. volumeName,
  549. len(volumeObj.mountedPods))
  550. }
  551. delete(asw.attachedVolumes, volumeName)
  552. return nil
  553. }
  554. func (asw *actualStateOfWorld) PodExistsInVolume(
  555. podName volumetypes.UniquePodName,
  556. volumeName v1.UniqueVolumeName) (bool, string, error) {
  557. asw.RLock()
  558. defer asw.RUnlock()
  559. volumeObj, volumeExists := asw.attachedVolumes[volumeName]
  560. if !volumeExists {
  561. return false, "", newVolumeNotAttachedError(volumeName)
  562. }
  563. podObj, podExists := volumeObj.mountedPods[podName]
  564. if podExists {
  565. // if volume mount was uncertain we should keep trying to mount the volume
  566. if podObj.volumeMountStateForPod == operationexecutor.VolumeMountUncertain {
  567. return false, volumeObj.devicePath, nil
  568. }
  569. if podObj.remountRequired {
  570. return true, volumeObj.devicePath, newRemountRequiredError(volumeObj.volumeName, podObj.podName)
  571. }
  572. if podObj.fsResizeRequired &&
  573. utilfeature.DefaultFeatureGate.Enabled(features.ExpandInUsePersistentVolumes) {
  574. return true, volumeObj.devicePath, newFsResizeRequiredError(volumeObj.volumeName, podObj.podName)
  575. }
  576. }
  577. return podExists, volumeObj.devicePath, nil
  578. }
  579. func (asw *actualStateOfWorld) VolumeExistsWithSpecName(podName volumetypes.UniquePodName, volumeSpecName string) bool {
  580. asw.RLock()
  581. defer asw.RUnlock()
  582. for _, volumeObj := range asw.attachedVolumes {
  583. if podObj, podExists := volumeObj.mountedPods[podName]; podExists {
  584. if podObj.volumeSpec.Name() == volumeSpecName {
  585. return true
  586. }
  587. }
  588. }
  589. return false
  590. }
  591. func (asw *actualStateOfWorld) VolumeExists(
  592. volumeName v1.UniqueVolumeName) bool {
  593. asw.RLock()
  594. defer asw.RUnlock()
  595. _, volumeExists := asw.attachedVolumes[volumeName]
  596. return volumeExists
  597. }
  598. func (asw *actualStateOfWorld) GetMountedVolumes() []MountedVolume {
  599. asw.RLock()
  600. defer asw.RUnlock()
  601. mountedVolume := make([]MountedVolume, 0 /* len */, len(asw.attachedVolumes) /* cap */)
  602. for _, volumeObj := range asw.attachedVolumes {
  603. for _, podObj := range volumeObj.mountedPods {
  604. if podObj.volumeMountStateForPod == operationexecutor.VolumeMounted {
  605. mountedVolume = append(
  606. mountedVolume,
  607. getMountedVolume(&podObj, &volumeObj))
  608. }
  609. }
  610. }
  611. return mountedVolume
  612. }
  613. // GetAllMountedVolumes returns all volumes which could be locally mounted for a pod.
  614. func (asw *actualStateOfWorld) GetAllMountedVolumes() []MountedVolume {
  615. asw.RLock()
  616. defer asw.RUnlock()
  617. mountedVolume := make([]MountedVolume, 0 /* len */, len(asw.attachedVolumes) /* cap */)
  618. for _, volumeObj := range asw.attachedVolumes {
  619. for _, podObj := range volumeObj.mountedPods {
  620. if podObj.volumeMountStateForPod == operationexecutor.VolumeMounted ||
  621. podObj.volumeMountStateForPod == operationexecutor.VolumeMountUncertain {
  622. mountedVolume = append(
  623. mountedVolume,
  624. getMountedVolume(&podObj, &volumeObj))
  625. }
  626. }
  627. }
  628. return mountedVolume
  629. }
  630. func (asw *actualStateOfWorld) GetMountedVolumesForPod(
  631. podName volumetypes.UniquePodName) []MountedVolume {
  632. asw.RLock()
  633. defer asw.RUnlock()
  634. mountedVolume := make([]MountedVolume, 0 /* len */, len(asw.attachedVolumes) /* cap */)
  635. for _, volumeObj := range asw.attachedVolumes {
  636. for mountedPodName, podObj := range volumeObj.mountedPods {
  637. if mountedPodName == podName && podObj.volumeMountStateForPod == operationexecutor.VolumeMounted {
  638. mountedVolume = append(
  639. mountedVolume,
  640. getMountedVolume(&podObj, &volumeObj))
  641. }
  642. }
  643. }
  644. return mountedVolume
  645. }
  646. func (asw *actualStateOfWorld) GetGloballyMountedVolumes() []AttachedVolume {
  647. asw.RLock()
  648. defer asw.RUnlock()
  649. globallyMountedVolumes := make(
  650. []AttachedVolume, 0 /* len */, len(asw.attachedVolumes) /* cap */)
  651. for _, volumeObj := range asw.attachedVolumes {
  652. if volumeObj.deviceMountState == operationexecutor.DeviceGloballyMounted {
  653. globallyMountedVolumes = append(
  654. globallyMountedVolumes,
  655. asw.newAttachedVolume(&volumeObj))
  656. }
  657. }
  658. return globallyMountedVolumes
  659. }
  660. func (asw *actualStateOfWorld) GetAttachedVolumes() []AttachedVolume {
  661. asw.RLock()
  662. defer asw.RUnlock()
  663. allAttachedVolumes := make(
  664. []AttachedVolume, 0 /* len */, len(asw.attachedVolumes) /* cap */)
  665. for _, volumeObj := range asw.attachedVolumes {
  666. allAttachedVolumes = append(
  667. allAttachedVolumes,
  668. asw.newAttachedVolume(&volumeObj))
  669. }
  670. return allAttachedVolumes
  671. }
  672. func (asw *actualStateOfWorld) GetUnmountedVolumes() []AttachedVolume {
  673. asw.RLock()
  674. defer asw.RUnlock()
  675. unmountedVolumes := make([]AttachedVolume, 0 /* len */, len(asw.attachedVolumes) /* cap */)
  676. for _, volumeObj := range asw.attachedVolumes {
  677. if len(volumeObj.mountedPods) == 0 {
  678. unmountedVolumes = append(
  679. unmountedVolumes,
  680. asw.newAttachedVolume(&volumeObj))
  681. }
  682. }
  683. return unmountedVolumes
  684. }
  685. func (asw *actualStateOfWorld) newAttachedVolume(
  686. attachedVolume *attachedVolume) AttachedVolume {
  687. return AttachedVolume{
  688. AttachedVolume: operationexecutor.AttachedVolume{
  689. VolumeName: attachedVolume.volumeName,
  690. VolumeSpec: attachedVolume.spec,
  691. NodeName: asw.nodeName,
  692. PluginIsAttachable: attachedVolume.pluginIsAttachable,
  693. DevicePath: attachedVolume.devicePath,
  694. DeviceMountPath: attachedVolume.deviceMountPath,
  695. PluginName: attachedVolume.pluginName},
  696. DeviceMountState: attachedVolume.deviceMountState,
  697. }
  698. }
  699. // Compile-time check to ensure volumeNotAttachedError implements the error interface
  700. var _ error = volumeNotAttachedError{}
  701. // volumeNotAttachedError is an error returned when PodExistsInVolume() fails to
  702. // find specified volume in the list of attached volumes.
  703. type volumeNotAttachedError struct {
  704. volumeName v1.UniqueVolumeName
  705. }
  706. func (err volumeNotAttachedError) Error() string {
  707. return fmt.Sprintf(
  708. "volumeName %q does not exist in the list of attached volumes",
  709. err.volumeName)
  710. }
  711. func newVolumeNotAttachedError(volumeName v1.UniqueVolumeName) error {
  712. return volumeNotAttachedError{
  713. volumeName: volumeName,
  714. }
  715. }
  716. // Compile-time check to ensure remountRequiredError implements the error interface
  717. var _ error = remountRequiredError{}
  718. // remountRequiredError is an error returned when PodExistsInVolume() found
  719. // volume/pod attached/mounted but remountRequired was true, indicating the
  720. // given volume should be remounted to the pod to reflect changes in the
  721. // referencing pod.
  722. type remountRequiredError struct {
  723. volumeName v1.UniqueVolumeName
  724. podName volumetypes.UniquePodName
  725. }
  726. func (err remountRequiredError) Error() string {
  727. return fmt.Sprintf(
  728. "volumeName %q is mounted to %q but should be remounted",
  729. err.volumeName, err.podName)
  730. }
  731. func newRemountRequiredError(
  732. volumeName v1.UniqueVolumeName, podName volumetypes.UniquePodName) error {
  733. return remountRequiredError{
  734. volumeName: volumeName,
  735. podName: podName,
  736. }
  737. }
  738. // fsResizeRequiredError is an error returned when PodExistsInVolume() found
  739. // volume/pod attached/mounted but fsResizeRequired was true, indicating the
  740. // given volume receives an resize request after attached/mounted.
  741. type fsResizeRequiredError struct {
  742. volumeName v1.UniqueVolumeName
  743. podName volumetypes.UniquePodName
  744. }
  745. func (err fsResizeRequiredError) Error() string {
  746. return fmt.Sprintf(
  747. "volumeName %q mounted to %q needs to resize file system",
  748. err.volumeName, err.podName)
  749. }
  750. func newFsResizeRequiredError(
  751. volumeName v1.UniqueVolumeName, podName volumetypes.UniquePodName) error {
  752. return fsResizeRequiredError{
  753. volumeName: volumeName,
  754. podName: podName,
  755. }
  756. }
  757. // IsFSResizeRequiredError returns true if the specified error is a
  758. // fsResizeRequiredError.
  759. func IsFSResizeRequiredError(err error) bool {
  760. _, ok := err.(fsResizeRequiredError)
  761. return ok
  762. }
  763. // getMountedVolume constructs and returns a MountedVolume object from the given
  764. // mountedPod and attachedVolume objects.
  765. func getMountedVolume(
  766. mountedPod *mountedPod, attachedVolume *attachedVolume) MountedVolume {
  767. return MountedVolume{
  768. MountedVolume: operationexecutor.MountedVolume{
  769. PodName: mountedPod.podName,
  770. VolumeName: attachedVolume.volumeName,
  771. InnerVolumeSpecName: mountedPod.volumeSpec.Name(),
  772. OuterVolumeSpecName: mountedPod.outerVolumeSpecName,
  773. PluginName: attachedVolume.pluginName,
  774. PodUID: mountedPod.podUID,
  775. Mounter: mountedPod.mounter,
  776. BlockVolumeMapper: mountedPod.blockVolumeMapper,
  777. VolumeGidValue: mountedPod.volumeGidValue,
  778. VolumeSpec: mountedPod.volumeSpec,
  779. DeviceMountPath: attachedVolume.deviceMountPath}}
  780. }