operation_generator.go 70 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660
  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. package operationexecutor
  14. import (
  15. "context"
  16. goerrors "errors"
  17. "fmt"
  18. "path/filepath"
  19. "strings"
  20. "time"
  21. v1 "k8s.io/api/core/v1"
  22. "k8s.io/apimachinery/pkg/api/errors"
  23. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  24. "k8s.io/apimachinery/pkg/types"
  25. utilfeature "k8s.io/apiserver/pkg/util/feature"
  26. clientset "k8s.io/client-go/kubernetes"
  27. "k8s.io/client-go/tools/record"
  28. volerr "k8s.io/cloud-provider/volume/errors"
  29. csitrans "k8s.io/csi-translation-lib"
  30. "k8s.io/klog"
  31. "k8s.io/kubernetes/pkg/features"
  32. kevents "k8s.io/kubernetes/pkg/kubelet/events"
  33. "k8s.io/kubernetes/pkg/volume"
  34. "k8s.io/kubernetes/pkg/volume/util"
  35. ioutil "k8s.io/kubernetes/pkg/volume/util"
  36. "k8s.io/kubernetes/pkg/volume/util/hostutil"
  37. volumetypes "k8s.io/kubernetes/pkg/volume/util/types"
  38. "k8s.io/kubernetes/pkg/volume/util/volumepathhandler"
  39. )
  40. const (
  41. unknownVolumePlugin string = "UnknownVolumePlugin"
  42. unknownAttachableVolumePlugin string = "UnknownAttachableVolumePlugin"
  43. )
  44. // InTreeToCSITranslator contains methods required to check migratable status
  45. // and perform translations from InTree PVs and Inline to CSI
  46. type InTreeToCSITranslator interface {
  47. IsPVMigratable(pv *v1.PersistentVolume) bool
  48. IsInlineMigratable(vol *v1.Volume) bool
  49. IsMigratableIntreePluginByName(inTreePluginName string) bool
  50. GetInTreePluginNameFromSpec(pv *v1.PersistentVolume, vol *v1.Volume) (string, error)
  51. GetCSINameFromInTreeName(pluginName string) (string, error)
  52. TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error)
  53. TranslateInTreeInlineVolumeToCSI(volume *v1.Volume) (*v1.PersistentVolume, error)
  54. }
  55. var _ OperationGenerator = &operationGenerator{}
  56. type operationGenerator struct {
  57. // Used to fetch objects from the API server like Node in the
  58. // VerifyControllerAttachedVolume operation.
  59. kubeClient clientset.Interface
  60. // volumePluginMgr is the volume plugin manager used to create volume
  61. // plugin objects.
  62. volumePluginMgr *volume.VolumePluginMgr
  63. // recorder is used to record events in the API server
  64. recorder record.EventRecorder
  65. // checkNodeCapabilitiesBeforeMount, if set, enables the CanMount check,
  66. // which verifies that the components (binaries, etc.) required to mount
  67. // the volume are available on the underlying node before attempting mount.
  68. checkNodeCapabilitiesBeforeMount bool
  69. // blkUtil provides volume path related operations for block volume
  70. blkUtil volumepathhandler.BlockVolumePathHandler
  71. translator InTreeToCSITranslator
  72. }
  73. // NewOperationGenerator is returns instance of operationGenerator
  74. func NewOperationGenerator(kubeClient clientset.Interface,
  75. volumePluginMgr *volume.VolumePluginMgr,
  76. recorder record.EventRecorder,
  77. checkNodeCapabilitiesBeforeMount bool,
  78. blkUtil volumepathhandler.BlockVolumePathHandler) OperationGenerator {
  79. return &operationGenerator{
  80. kubeClient: kubeClient,
  81. volumePluginMgr: volumePluginMgr,
  82. recorder: recorder,
  83. checkNodeCapabilitiesBeforeMount: checkNodeCapabilitiesBeforeMount,
  84. blkUtil: blkUtil,
  85. translator: csitrans.New(),
  86. }
  87. }
  88. // OperationGenerator interface that extracts out the functions from operation_executor to make it dependency injectable
  89. type OperationGenerator interface {
  90. // Generates the MountVolume function needed to perform the mount of a volume plugin
  91. GenerateMountVolumeFunc(waitForAttachTimeout time.Duration, volumeToMount VolumeToMount, actualStateOfWorldMounterUpdater ActualStateOfWorldMounterUpdater, isRemount bool) volumetypes.GeneratedOperations
  92. // Generates the UnmountVolume function needed to perform the unmount of a volume plugin
  93. GenerateUnmountVolumeFunc(volumeToUnmount MountedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater, podsDir string) (volumetypes.GeneratedOperations, error)
  94. // Generates the AttachVolume function needed to perform attach of a volume plugin
  95. GenerateAttachVolumeFunc(volumeToAttach VolumeToAttach, actualStateOfWorld ActualStateOfWorldAttacherUpdater) volumetypes.GeneratedOperations
  96. // Generates the DetachVolume function needed to perform the detach of a volume plugin
  97. GenerateDetachVolumeFunc(volumeToDetach AttachedVolume, verifySafeToDetach bool, actualStateOfWorld ActualStateOfWorldAttacherUpdater) (volumetypes.GeneratedOperations, error)
  98. // Generates the VolumesAreAttached function needed to verify if volume plugins are attached
  99. GenerateVolumesAreAttachedFunc(attachedVolumes []AttachedVolume, nodeName types.NodeName, actualStateOfWorld ActualStateOfWorldAttacherUpdater) (volumetypes.GeneratedOperations, error)
  100. // Generates the UnMountDevice function needed to perform the unmount of a device
  101. GenerateUnmountDeviceFunc(deviceToDetach AttachedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater, mounter hostutil.HostUtils) (volumetypes.GeneratedOperations, error)
  102. // Generates the function needed to check if the attach_detach controller has attached the volume plugin
  103. GenerateVerifyControllerAttachedVolumeFunc(volumeToMount VolumeToMount, nodeName types.NodeName, actualStateOfWorld ActualStateOfWorldAttacherUpdater) (volumetypes.GeneratedOperations, error)
  104. // Generates the MapVolume function needed to perform the map of a volume plugin
  105. GenerateMapVolumeFunc(waitForAttachTimeout time.Duration, volumeToMount VolumeToMount, actualStateOfWorldMounterUpdater ActualStateOfWorldMounterUpdater) (volumetypes.GeneratedOperations, error)
  106. // Generates the UnmapVolume function needed to perform the unmap of a volume plugin
  107. GenerateUnmapVolumeFunc(volumeToUnmount MountedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater) (volumetypes.GeneratedOperations, error)
  108. // Generates the UnmapDevice function needed to perform the unmap of a device
  109. GenerateUnmapDeviceFunc(deviceToDetach AttachedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater, mounter hostutil.HostUtils) (volumetypes.GeneratedOperations, error)
  110. // GetVolumePluginMgr returns volume plugin manager
  111. GetVolumePluginMgr() *volume.VolumePluginMgr
  112. // GetCSITranslator returns the CSI Translation Library
  113. GetCSITranslator() InTreeToCSITranslator
  114. GenerateBulkVolumeVerifyFunc(
  115. map[types.NodeName][]*volume.Spec,
  116. string,
  117. map[*volume.Spec]v1.UniqueVolumeName, ActualStateOfWorldAttacherUpdater) (volumetypes.GeneratedOperations, error)
  118. GenerateExpandVolumeFunc(*v1.PersistentVolumeClaim, *v1.PersistentVolume) (volumetypes.GeneratedOperations, error)
  119. // Generates the volume file system resize function, which can resize volume's file system to expected size without unmounting the volume.
  120. GenerateExpandInUseVolumeFunc(volumeToMount VolumeToMount, actualStateOfWorld ActualStateOfWorldMounterUpdater) (volumetypes.GeneratedOperations, error)
  121. }
  122. func (og *operationGenerator) GenerateVolumesAreAttachedFunc(
  123. attachedVolumes []AttachedVolume,
  124. nodeName types.NodeName,
  125. actualStateOfWorld ActualStateOfWorldAttacherUpdater) (volumetypes.GeneratedOperations, error) {
  126. // volumesPerPlugin maps from a volume plugin to a list of volume specs which belong
  127. // to this type of plugin
  128. volumesPerPlugin := make(map[string][]*volume.Spec)
  129. // volumeSpecMap maps from a volume spec to its unique volumeName which will be used
  130. // when calling MarkVolumeAsDetached
  131. volumeSpecMap := make(map[*volume.Spec]v1.UniqueVolumeName)
  132. // Iterate each volume spec and put them into a map index by the pluginName
  133. for _, volumeAttached := range attachedVolumes {
  134. if volumeAttached.VolumeSpec == nil {
  135. klog.Errorf("VerifyVolumesAreAttached.GenerateVolumesAreAttachedFunc: nil spec for volume %s", volumeAttached.VolumeName)
  136. continue
  137. }
  138. volumePlugin, err :=
  139. og.volumePluginMgr.FindPluginBySpec(volumeAttached.VolumeSpec)
  140. if err != nil || volumePlugin == nil {
  141. klog.Errorf(volumeAttached.GenerateErrorDetailed("VolumesAreAttached.FindPluginBySpec failed", err).Error())
  142. continue
  143. }
  144. volumeSpecList, pluginExists := volumesPerPlugin[volumePlugin.GetPluginName()]
  145. if !pluginExists {
  146. volumeSpecList = []*volume.Spec{}
  147. }
  148. volumeSpecList = append(volumeSpecList, volumeAttached.VolumeSpec)
  149. volumesPerPlugin[volumePlugin.GetPluginName()] = volumeSpecList
  150. // Migration: VolumeSpecMap contains original VolumeName for use in ActualStateOfWorld
  151. volumeSpecMap[volumeAttached.VolumeSpec] = volumeAttached.VolumeName
  152. }
  153. volumesAreAttachedFunc := func() (error, error) {
  154. // For each volume plugin, pass the list of volume specs to VolumesAreAttached to check
  155. // whether the volumes are still attached.
  156. for pluginName, volumesSpecs := range volumesPerPlugin {
  157. attachableVolumePlugin, err :=
  158. og.volumePluginMgr.FindAttachablePluginByName(pluginName)
  159. if err != nil || attachableVolumePlugin == nil {
  160. klog.Errorf(
  161. "VolumeAreAttached.FindAttachablePluginBySpec failed for plugin %q with: %v",
  162. pluginName,
  163. err)
  164. continue
  165. }
  166. volumeAttacher, newAttacherErr := attachableVolumePlugin.NewAttacher()
  167. if newAttacherErr != nil {
  168. klog.Errorf(
  169. "VolumesAreAttached.NewAttacher failed for getting plugin %q with: %v",
  170. pluginName,
  171. newAttacherErr)
  172. continue
  173. }
  174. attached, areAttachedErr := volumeAttacher.VolumesAreAttached(volumesSpecs, nodeName)
  175. if areAttachedErr != nil {
  176. klog.Errorf(
  177. "VolumesAreAttached failed for checking on node %q with: %v",
  178. nodeName,
  179. areAttachedErr)
  180. continue
  181. }
  182. for spec, check := range attached {
  183. if !check {
  184. actualStateOfWorld.MarkVolumeAsDetached(volumeSpecMap[spec], nodeName)
  185. klog.V(1).Infof("VerifyVolumesAreAttached determined volume %q (spec.Name: %q) is no longer attached to node %q, therefore it was marked as detached.",
  186. volumeSpecMap[spec], spec.Name(), nodeName)
  187. }
  188. }
  189. }
  190. return nil, nil
  191. }
  192. return volumetypes.GeneratedOperations{
  193. OperationName: "verify_volumes_are_attached_per_node",
  194. OperationFunc: volumesAreAttachedFunc,
  195. CompleteFunc: util.OperationCompleteHook(util.GetFullQualifiedPluginNameForVolume("<n/a>", nil), "verify_volumes_are_attached_per_node"),
  196. EventRecorderFunc: nil, // nil because we do not want to generate event on error
  197. }, nil
  198. }
  199. func (og *operationGenerator) GenerateBulkVolumeVerifyFunc(
  200. pluginNodeVolumes map[types.NodeName][]*volume.Spec,
  201. pluginName string,
  202. volumeSpecMap map[*volume.Spec]v1.UniqueVolumeName,
  203. actualStateOfWorld ActualStateOfWorldAttacherUpdater) (volumetypes.GeneratedOperations, error) {
  204. // Migration: All inputs already should be translated by caller for this
  205. // function except volumeSpecMap which contains original volume names for
  206. // use with actualStateOfWorld
  207. bulkVolumeVerifyFunc := func() (error, error) {
  208. attachableVolumePlugin, err :=
  209. og.volumePluginMgr.FindAttachablePluginByName(pluginName)
  210. if err != nil || attachableVolumePlugin == nil {
  211. klog.Errorf(
  212. "BulkVerifyVolume.FindAttachablePluginBySpec failed for plugin %q with: %v",
  213. pluginName,
  214. err)
  215. return nil, nil
  216. }
  217. volumeAttacher, newAttacherErr := attachableVolumePlugin.NewAttacher()
  218. if newAttacherErr != nil {
  219. klog.Errorf(
  220. "BulkVerifyVolume.NewAttacher failed for getting plugin %q with: %v",
  221. attachableVolumePlugin,
  222. newAttacherErr)
  223. return nil, nil
  224. }
  225. bulkVolumeVerifier, ok := volumeAttacher.(volume.BulkVolumeVerifier)
  226. if !ok {
  227. klog.Errorf("BulkVerifyVolume failed to type assert attacher %q", bulkVolumeVerifier)
  228. return nil, nil
  229. }
  230. attached, bulkAttachErr := bulkVolumeVerifier.BulkVerifyVolumes(pluginNodeVolumes)
  231. if bulkAttachErr != nil {
  232. klog.Errorf("BulkVerifyVolume.BulkVerifyVolumes Error checking volumes are attached with %v", bulkAttachErr)
  233. return nil, nil
  234. }
  235. for nodeName, volumeSpecs := range pluginNodeVolumes {
  236. for _, volumeSpec := range volumeSpecs {
  237. nodeVolumeSpecs, nodeChecked := attached[nodeName]
  238. if !nodeChecked {
  239. klog.V(2).Infof("VerifyVolumesAreAttached.BulkVerifyVolumes failed for node %q and leaving volume %q as attached",
  240. nodeName,
  241. volumeSpec.Name())
  242. continue
  243. }
  244. check := nodeVolumeSpecs[volumeSpec]
  245. if !check {
  246. klog.V(2).Infof("VerifyVolumesAreAttached.BulkVerifyVolumes failed for node %q and volume %q",
  247. nodeName,
  248. volumeSpec.Name())
  249. actualStateOfWorld.MarkVolumeAsDetached(volumeSpecMap[volumeSpec], nodeName)
  250. }
  251. }
  252. }
  253. return nil, nil
  254. }
  255. return volumetypes.GeneratedOperations{
  256. OperationName: "verify_volumes_are_attached",
  257. OperationFunc: bulkVolumeVerifyFunc,
  258. CompleteFunc: util.OperationCompleteHook(util.GetFullQualifiedPluginNameForVolume(pluginName, nil), "verify_volumes_are_attached"),
  259. EventRecorderFunc: nil, // nil because we do not want to generate event on error
  260. }, nil
  261. }
  262. func (og *operationGenerator) GenerateAttachVolumeFunc(
  263. volumeToAttach VolumeToAttach,
  264. actualStateOfWorld ActualStateOfWorldAttacherUpdater) volumetypes.GeneratedOperations {
  265. attachVolumeFunc := func() (error, error) {
  266. attachableVolumePlugin, err :=
  267. og.volumePluginMgr.FindAttachablePluginBySpec(volumeToAttach.VolumeSpec)
  268. if err != nil || attachableVolumePlugin == nil {
  269. return volumeToAttach.GenerateError("AttachVolume.FindAttachablePluginBySpec failed", err)
  270. }
  271. volumeAttacher, newAttacherErr := attachableVolumePlugin.NewAttacher()
  272. if newAttacherErr != nil {
  273. return volumeToAttach.GenerateError("AttachVolume.NewAttacher failed", newAttacherErr)
  274. }
  275. // Execute attach
  276. devicePath, attachErr := volumeAttacher.Attach(
  277. volumeToAttach.VolumeSpec, volumeToAttach.NodeName)
  278. if attachErr != nil {
  279. uncertainNode := volumeToAttach.NodeName
  280. if derr, ok := attachErr.(*volerr.DanglingAttachError); ok {
  281. uncertainNode = derr.CurrentNode
  282. }
  283. addErr := actualStateOfWorld.MarkVolumeAsUncertain(
  284. v1.UniqueVolumeName(""),
  285. volumeToAttach.VolumeSpec,
  286. uncertainNode)
  287. if addErr != nil {
  288. klog.Errorf("AttachVolume.MarkVolumeAsUncertain fail to add the volume %q to actual state with %s", volumeToAttach.VolumeName, addErr)
  289. }
  290. // On failure, return error. Caller will log and retry.
  291. return volumeToAttach.GenerateError("AttachVolume.Attach failed", attachErr)
  292. }
  293. // Successful attach event is useful for user debugging
  294. simpleMsg, _ := volumeToAttach.GenerateMsg("AttachVolume.Attach succeeded", "")
  295. for _, pod := range volumeToAttach.ScheduledPods {
  296. og.recorder.Eventf(pod, v1.EventTypeNormal, kevents.SuccessfulAttachVolume, simpleMsg)
  297. }
  298. klog.Infof(volumeToAttach.GenerateMsgDetailed("AttachVolume.Attach succeeded", ""))
  299. // Update actual state of world
  300. addVolumeNodeErr := actualStateOfWorld.MarkVolumeAsAttached(
  301. v1.UniqueVolumeName(""), volumeToAttach.VolumeSpec, volumeToAttach.NodeName, devicePath)
  302. if addVolumeNodeErr != nil {
  303. // On failure, return error. Caller will log and retry.
  304. return volumeToAttach.GenerateError("AttachVolume.MarkVolumeAsAttached failed", addVolumeNodeErr)
  305. }
  306. return nil, nil
  307. }
  308. eventRecorderFunc := func(err *error) {
  309. if *err != nil {
  310. for _, pod := range volumeToAttach.ScheduledPods {
  311. og.recorder.Eventf(pod, v1.EventTypeWarning, kevents.FailedAttachVolume, (*err).Error())
  312. }
  313. }
  314. }
  315. attachableVolumePluginName := unknownAttachableVolumePlugin
  316. // Get attacher plugin
  317. attachableVolumePlugin, err :=
  318. og.volumePluginMgr.FindAttachablePluginBySpec(volumeToAttach.VolumeSpec)
  319. // It's ok to ignore the error, returning error is not expected from this function.
  320. // If an error case occurred during the function generation, this error case(skipped one) will also trigger an error
  321. // while the generated function is executed. And those errors will be handled during the execution of the generated
  322. // function with a back off policy.
  323. if err == nil && attachableVolumePlugin != nil {
  324. attachableVolumePluginName = attachableVolumePlugin.GetPluginName()
  325. }
  326. return volumetypes.GeneratedOperations{
  327. OperationName: "volume_attach",
  328. OperationFunc: attachVolumeFunc,
  329. EventRecorderFunc: eventRecorderFunc,
  330. CompleteFunc: util.OperationCompleteHook(util.GetFullQualifiedPluginNameForVolume(attachableVolumePluginName, volumeToAttach.VolumeSpec), "volume_attach"),
  331. }
  332. }
  333. func (og *operationGenerator) GetVolumePluginMgr() *volume.VolumePluginMgr {
  334. return og.volumePluginMgr
  335. }
  336. func (og *operationGenerator) GetCSITranslator() InTreeToCSITranslator {
  337. return og.translator
  338. }
  339. func (og *operationGenerator) GenerateDetachVolumeFunc(
  340. volumeToDetach AttachedVolume,
  341. verifySafeToDetach bool,
  342. actualStateOfWorld ActualStateOfWorldAttacherUpdater) (volumetypes.GeneratedOperations, error) {
  343. var volumeName string
  344. var attachableVolumePlugin volume.AttachableVolumePlugin
  345. var pluginName string
  346. var err error
  347. if volumeToDetach.VolumeSpec != nil {
  348. attachableVolumePlugin, err =
  349. og.volumePluginMgr.FindAttachablePluginBySpec(volumeToDetach.VolumeSpec)
  350. if err != nil || attachableVolumePlugin == nil {
  351. return volumetypes.GeneratedOperations{}, volumeToDetach.GenerateErrorDetailed("DetachVolume.FindAttachablePluginBySpec failed", err)
  352. }
  353. volumeName, err =
  354. attachableVolumePlugin.GetVolumeName(volumeToDetach.VolumeSpec)
  355. if err != nil {
  356. return volumetypes.GeneratedOperations{}, volumeToDetach.GenerateErrorDetailed("DetachVolume.GetVolumeName failed", err)
  357. }
  358. } else {
  359. // Get attacher plugin and the volumeName by splitting the volume unique name in case
  360. // there's no VolumeSpec: this happens only on attach/detach controller crash recovery
  361. // when a pod has been deleted during the controller downtime
  362. pluginName, volumeName, err = util.SplitUniqueName(volumeToDetach.VolumeName)
  363. if err != nil {
  364. return volumetypes.GeneratedOperations{}, volumeToDetach.GenerateErrorDetailed("DetachVolume.SplitUniqueName failed", err)
  365. }
  366. attachableVolumePlugin, err = og.volumePluginMgr.FindAttachablePluginByName(pluginName)
  367. if err != nil || attachableVolumePlugin == nil {
  368. return volumetypes.GeneratedOperations{}, volumeToDetach.GenerateErrorDetailed("DetachVolume.FindAttachablePluginByName failed", err)
  369. }
  370. }
  371. if pluginName == "" {
  372. pluginName = attachableVolumePlugin.GetPluginName()
  373. }
  374. volumeDetacher, err := attachableVolumePlugin.NewDetacher()
  375. if err != nil {
  376. return volumetypes.GeneratedOperations{}, volumeToDetach.GenerateErrorDetailed("DetachVolume.NewDetacher failed", err)
  377. }
  378. getVolumePluginMgrFunc := func() (error, error) {
  379. var err error
  380. if verifySafeToDetach {
  381. err = og.verifyVolumeIsSafeToDetach(volumeToDetach)
  382. }
  383. if err == nil {
  384. err = volumeDetacher.Detach(volumeName, volumeToDetach.NodeName)
  385. }
  386. if err != nil {
  387. // On failure, add volume back to ReportAsAttached list
  388. actualStateOfWorld.AddVolumeToReportAsAttached(
  389. volumeToDetach.VolumeName, volumeToDetach.NodeName)
  390. return volumeToDetach.GenerateError("DetachVolume.Detach failed", err)
  391. }
  392. klog.Infof(volumeToDetach.GenerateMsgDetailed("DetachVolume.Detach succeeded", ""))
  393. // Update actual state of world
  394. actualStateOfWorld.MarkVolumeAsDetached(
  395. volumeToDetach.VolumeName, volumeToDetach.NodeName)
  396. return nil, nil
  397. }
  398. return volumetypes.GeneratedOperations{
  399. OperationName: "volume_detach",
  400. OperationFunc: getVolumePluginMgrFunc,
  401. CompleteFunc: util.OperationCompleteHook(util.GetFullQualifiedPluginNameForVolume(pluginName, volumeToDetach.VolumeSpec), "volume_detach"),
  402. EventRecorderFunc: nil, // nil because we do not want to generate event on error
  403. }, nil
  404. }
  405. func (og *operationGenerator) GenerateMountVolumeFunc(
  406. waitForAttachTimeout time.Duration,
  407. volumeToMount VolumeToMount,
  408. actualStateOfWorld ActualStateOfWorldMounterUpdater,
  409. isRemount bool) volumetypes.GeneratedOperations {
  410. volumePluginName := unknownVolumePlugin
  411. volumePlugin, err :=
  412. og.volumePluginMgr.FindPluginBySpec(volumeToMount.VolumeSpec)
  413. if err == nil && volumePlugin != nil {
  414. volumePluginName = volumePlugin.GetPluginName()
  415. }
  416. mountVolumeFunc := func() (error, error) {
  417. // Get mounter plugin
  418. volumePlugin, err := og.volumePluginMgr.FindPluginBySpec(volumeToMount.VolumeSpec)
  419. if err != nil || volumePlugin == nil {
  420. return volumeToMount.GenerateError("MountVolume.FindPluginBySpec failed", err)
  421. }
  422. affinityErr := checkNodeAffinity(og, volumeToMount)
  423. if affinityErr != nil {
  424. return volumeToMount.GenerateError("MountVolume.NodeAffinity check failed", affinityErr)
  425. }
  426. volumeMounter, newMounterErr := volumePlugin.NewMounter(
  427. volumeToMount.VolumeSpec,
  428. volumeToMount.Pod,
  429. volume.VolumeOptions{})
  430. if newMounterErr != nil {
  431. return volumeToMount.GenerateError("MountVolume.NewMounter initialization failed", newMounterErr)
  432. }
  433. mountCheckError := checkMountOptionSupport(og, volumeToMount, volumePlugin)
  434. if mountCheckError != nil {
  435. return volumeToMount.GenerateError("MountVolume.MountOptionSupport check failed", mountCheckError)
  436. }
  437. // Get attacher, if possible
  438. attachableVolumePlugin, _ :=
  439. og.volumePluginMgr.FindAttachablePluginBySpec(volumeToMount.VolumeSpec)
  440. var volumeAttacher volume.Attacher
  441. if attachableVolumePlugin != nil {
  442. volumeAttacher, _ = attachableVolumePlugin.NewAttacher()
  443. }
  444. // get deviceMounter, if possible
  445. deviceMountableVolumePlugin, _ := og.volumePluginMgr.FindDeviceMountablePluginBySpec(volumeToMount.VolumeSpec)
  446. var volumeDeviceMounter volume.DeviceMounter
  447. if deviceMountableVolumePlugin != nil {
  448. volumeDeviceMounter, _ = deviceMountableVolumePlugin.NewDeviceMounter()
  449. }
  450. var fsGroup *int64
  451. if volumeToMount.Pod.Spec.SecurityContext != nil &&
  452. volumeToMount.Pod.Spec.SecurityContext.FSGroup != nil {
  453. fsGroup = volumeToMount.Pod.Spec.SecurityContext.FSGroup
  454. }
  455. devicePath := volumeToMount.DevicePath
  456. if volumeAttacher != nil {
  457. // Wait for attachable volumes to finish attaching
  458. klog.Infof(volumeToMount.GenerateMsgDetailed("MountVolume.WaitForAttach entering", fmt.Sprintf("DevicePath %q", volumeToMount.DevicePath)))
  459. devicePath, err = volumeAttacher.WaitForAttach(
  460. volumeToMount.VolumeSpec, devicePath, volumeToMount.Pod, waitForAttachTimeout)
  461. if err != nil {
  462. // On failure, return error. Caller will log and retry.
  463. return volumeToMount.GenerateError("MountVolume.WaitForAttach failed", err)
  464. }
  465. klog.Infof(volumeToMount.GenerateMsgDetailed("MountVolume.WaitForAttach succeeded", fmt.Sprintf("DevicePath %q", devicePath)))
  466. }
  467. var resizeDone bool
  468. var resizeError error
  469. resizeOptions := volume.NodeResizeOptions{
  470. DevicePath: devicePath,
  471. }
  472. if volumeDeviceMounter != nil {
  473. deviceMountPath, err :=
  474. volumeDeviceMounter.GetDeviceMountPath(volumeToMount.VolumeSpec)
  475. if err != nil {
  476. // On failure, return error. Caller will log and retry.
  477. return volumeToMount.GenerateError("MountVolume.GetDeviceMountPath failed", err)
  478. }
  479. // Mount device to global mount path
  480. err = volumeDeviceMounter.MountDevice(
  481. volumeToMount.VolumeSpec,
  482. devicePath,
  483. deviceMountPath)
  484. if err != nil {
  485. og.checkForFailedMount(volumeToMount, err)
  486. og.markDeviceErrorState(volumeToMount, devicePath, deviceMountPath, err, actualStateOfWorld)
  487. // On failure, return error. Caller will log and retry.
  488. return volumeToMount.GenerateError("MountVolume.MountDevice failed", err)
  489. }
  490. klog.Infof(volumeToMount.GenerateMsgDetailed("MountVolume.MountDevice succeeded", fmt.Sprintf("device mount path %q", deviceMountPath)))
  491. // Update actual state of world to reflect volume is globally mounted
  492. markDeviceMountedErr := actualStateOfWorld.MarkDeviceAsMounted(
  493. volumeToMount.VolumeName, devicePath, deviceMountPath)
  494. if markDeviceMountedErr != nil {
  495. // On failure, return error. Caller will log and retry.
  496. return volumeToMount.GenerateError("MountVolume.MarkDeviceAsMounted failed", markDeviceMountedErr)
  497. }
  498. resizeOptions.DeviceMountPath = deviceMountPath
  499. resizeOptions.CSIVolumePhase = volume.CSIVolumeStaged
  500. // NodeExpandVolume will resize the file system if user has requested a resize of
  501. // underlying persistent volume and is allowed to do so.
  502. resizeDone, resizeError = og.nodeExpandVolume(volumeToMount, resizeOptions)
  503. if resizeError != nil {
  504. klog.Errorf("MountVolume.NodeExpandVolume failed with %v", resizeError)
  505. return volumeToMount.GenerateError("MountVolume.MountDevice failed while expanding volume", resizeError)
  506. }
  507. }
  508. if og.checkNodeCapabilitiesBeforeMount {
  509. if canMountErr := volumeMounter.CanMount(); canMountErr != nil {
  510. err = fmt.Errorf(
  511. "Verify that your node machine has the required components before attempting to mount this volume type. %s",
  512. canMountErr)
  513. return volumeToMount.GenerateError("MountVolume.CanMount failed", err)
  514. }
  515. }
  516. // Execute mount
  517. mountErr := volumeMounter.SetUp(volume.MounterArgs{
  518. FsGroup: fsGroup,
  519. DesiredSize: volumeToMount.DesiredSizeLimit,
  520. })
  521. // Update actual state of world
  522. markOpts := MarkVolumeOpts{
  523. PodName: volumeToMount.PodName,
  524. PodUID: volumeToMount.Pod.UID,
  525. VolumeName: volumeToMount.VolumeName,
  526. Mounter: volumeMounter,
  527. OuterVolumeSpecName: volumeToMount.OuterVolumeSpecName,
  528. VolumeGidVolume: volumeToMount.VolumeGidValue,
  529. VolumeSpec: volumeToMount.VolumeSpec,
  530. VolumeMountState: VolumeMounted,
  531. }
  532. if mountErr != nil {
  533. og.checkForFailedMount(volumeToMount, mountErr)
  534. og.markVolumeErrorState(volumeToMount, markOpts, mountErr, actualStateOfWorld)
  535. // On failure, return error. Caller will log and retry.
  536. return volumeToMount.GenerateError("MountVolume.SetUp failed", mountErr)
  537. }
  538. _, detailedMsg := volumeToMount.GenerateMsg("MountVolume.SetUp succeeded", "")
  539. verbosity := klog.Level(1)
  540. if isRemount {
  541. verbosity = klog.Level(4)
  542. }
  543. klog.V(verbosity).Infof(detailedMsg)
  544. resizeOptions.DeviceMountPath = volumeMounter.GetPath()
  545. resizeOptions.CSIVolumePhase = volume.CSIVolumePublished
  546. // We need to call resizing here again in case resizing was not done during device mount. There could be
  547. // two reasons of that:
  548. // - Volume does not support DeviceMounter interface.
  549. // - In case of CSI the volume does not have node stage_unstage capability.
  550. if !resizeDone {
  551. _, resizeError = og.nodeExpandVolume(volumeToMount, resizeOptions)
  552. if resizeError != nil {
  553. klog.Errorf("MountVolume.NodeExpandVolume failed with %v", resizeError)
  554. return volumeToMount.GenerateError("MountVolume.Setup failed while expanding volume", resizeError)
  555. }
  556. }
  557. markVolMountedErr := actualStateOfWorld.MarkVolumeAsMounted(markOpts)
  558. if markVolMountedErr != nil {
  559. // On failure, return error. Caller will log and retry.
  560. return volumeToMount.GenerateError("MountVolume.MarkVolumeAsMounted failed", markVolMountedErr)
  561. }
  562. return nil, nil
  563. }
  564. eventRecorderFunc := func(err *error) {
  565. if *err != nil {
  566. og.recorder.Eventf(volumeToMount.Pod, v1.EventTypeWarning, kevents.FailedMountVolume, (*err).Error())
  567. }
  568. }
  569. return volumetypes.GeneratedOperations{
  570. OperationName: "volume_mount",
  571. OperationFunc: mountVolumeFunc,
  572. EventRecorderFunc: eventRecorderFunc,
  573. CompleteFunc: util.OperationCompleteHook(util.GetFullQualifiedPluginNameForVolume(volumePluginName, volumeToMount.VolumeSpec), "volume_mount"),
  574. }
  575. }
  576. func (og *operationGenerator) checkForFailedMount(volumeToMount VolumeToMount, mountError error) {
  577. pv := volumeToMount.VolumeSpec.PersistentVolume
  578. if pv == nil {
  579. return
  580. }
  581. if volumetypes.IsFilesystemMismatchError(mountError) {
  582. simpleMsg, _ := volumeToMount.GenerateMsg("MountVolume failed", mountError.Error())
  583. og.recorder.Eventf(pv, v1.EventTypeWarning, kevents.FailedMountOnFilesystemMismatch, simpleMsg)
  584. }
  585. }
  586. func (og *operationGenerator) markDeviceErrorState(volumeToMount VolumeToMount, devicePath, deviceMountPath string, mountError error, actualStateOfWorld ActualStateOfWorldMounterUpdater) {
  587. if volumetypes.IsOperationFinishedError(mountError) &&
  588. actualStateOfWorld.GetDeviceMountState(volumeToMount.VolumeName) == DeviceMountUncertain {
  589. // Only devices which were uncertain can be marked as unmounted
  590. markDeviceUnmountError := actualStateOfWorld.MarkDeviceAsUnmounted(volumeToMount.VolumeName)
  591. if markDeviceUnmountError != nil {
  592. klog.Errorf(volumeToMount.GenerateErrorDetailed("MountDevice.MarkDeviceAsUnmounted failed", markDeviceUnmountError).Error())
  593. }
  594. return
  595. }
  596. if volumetypes.IsUncertainProgressError(mountError) &&
  597. actualStateOfWorld.GetDeviceMountState(volumeToMount.VolumeName) == DeviceNotMounted {
  598. // only devices which are not mounted can be marked as uncertain. We do not want to mark a device
  599. // which was previously marked as mounted here as uncertain.
  600. markDeviceUncertainError := actualStateOfWorld.MarkDeviceAsUncertain(volumeToMount.VolumeName, devicePath, deviceMountPath)
  601. if markDeviceUncertainError != nil {
  602. klog.Errorf(volumeToMount.GenerateErrorDetailed("MountDevice.MarkDeviceAsUncertain failed", markDeviceUncertainError).Error())
  603. }
  604. }
  605. }
  606. func (og *operationGenerator) markVolumeErrorState(volumeToMount VolumeToMount, markOpts MarkVolumeOpts, mountError error, actualStateOfWorld ActualStateOfWorldMounterUpdater) {
  607. if volumetypes.IsOperationFinishedError(mountError) &&
  608. actualStateOfWorld.GetVolumeMountState(volumeToMount.VolumeName, markOpts.PodName) == VolumeMountUncertain {
  609. t := actualStateOfWorld.MarkVolumeAsUnmounted(volumeToMount.PodName, volumeToMount.VolumeName)
  610. if t != nil {
  611. klog.Errorf(volumeToMount.GenerateErrorDetailed("MountVolume.MarkVolumeAsUnmounted failed", t).Error())
  612. }
  613. return
  614. }
  615. if volumetypes.IsUncertainProgressError(mountError) &&
  616. actualStateOfWorld.GetVolumeMountState(volumeToMount.VolumeName, markOpts.PodName) == VolumeNotMounted {
  617. t := actualStateOfWorld.MarkVolumeMountAsUncertain(markOpts)
  618. if t != nil {
  619. klog.Errorf(volumeToMount.GenerateErrorDetailed("MountVolume.MarkVolumeMountAsUncertain failed", t).Error())
  620. }
  621. }
  622. }
  623. func (og *operationGenerator) GenerateUnmountVolumeFunc(
  624. volumeToUnmount MountedVolume,
  625. actualStateOfWorld ActualStateOfWorldMounterUpdater,
  626. podsDir string) (volumetypes.GeneratedOperations, error) {
  627. // Get mountable plugin
  628. volumePlugin, err := og.volumePluginMgr.FindPluginByName(volumeToUnmount.PluginName)
  629. if err != nil || volumePlugin == nil {
  630. return volumetypes.GeneratedOperations{}, volumeToUnmount.GenerateErrorDetailed("UnmountVolume.FindPluginByName failed", err)
  631. }
  632. volumeUnmounter, newUnmounterErr := volumePlugin.NewUnmounter(
  633. volumeToUnmount.InnerVolumeSpecName, volumeToUnmount.PodUID)
  634. if newUnmounterErr != nil {
  635. return volumetypes.GeneratedOperations{}, volumeToUnmount.GenerateErrorDetailed("UnmountVolume.NewUnmounter failed", newUnmounterErr)
  636. }
  637. unmountVolumeFunc := func() (error, error) {
  638. subpather := og.volumePluginMgr.Host.GetSubpather()
  639. // Remove all bind-mounts for subPaths
  640. podDir := filepath.Join(podsDir, string(volumeToUnmount.PodUID))
  641. if err := subpather.CleanSubPaths(podDir, volumeToUnmount.InnerVolumeSpecName); err != nil {
  642. return volumeToUnmount.GenerateError("error cleaning subPath mounts", err)
  643. }
  644. // Execute unmount
  645. unmountErr := volumeUnmounter.TearDown()
  646. if unmountErr != nil {
  647. // On failure, return error. Caller will log and retry.
  648. return volumeToUnmount.GenerateError("UnmountVolume.TearDown failed", unmountErr)
  649. }
  650. klog.Infof(
  651. "UnmountVolume.TearDown succeeded for volume %q (OuterVolumeSpecName: %q) pod %q (UID: %q). InnerVolumeSpecName %q. PluginName %q, VolumeGidValue %q",
  652. volumeToUnmount.VolumeName,
  653. volumeToUnmount.OuterVolumeSpecName,
  654. volumeToUnmount.PodName,
  655. volumeToUnmount.PodUID,
  656. volumeToUnmount.InnerVolumeSpecName,
  657. volumeToUnmount.PluginName,
  658. volumeToUnmount.VolumeGidValue)
  659. // Update actual state of world
  660. markVolMountedErr := actualStateOfWorld.MarkVolumeAsUnmounted(
  661. volumeToUnmount.PodName, volumeToUnmount.VolumeName)
  662. if markVolMountedErr != nil {
  663. // On failure, just log and exit
  664. klog.Errorf(volumeToUnmount.GenerateErrorDetailed("UnmountVolume.MarkVolumeAsUnmounted failed", markVolMountedErr).Error())
  665. }
  666. return nil, nil
  667. }
  668. return volumetypes.GeneratedOperations{
  669. OperationName: "volume_unmount",
  670. OperationFunc: unmountVolumeFunc,
  671. CompleteFunc: util.OperationCompleteHook(util.GetFullQualifiedPluginNameForVolume(volumePlugin.GetPluginName(), volumeToUnmount.VolumeSpec), "volume_unmount"),
  672. EventRecorderFunc: nil, // nil because we do not want to generate event on error
  673. }, nil
  674. }
  675. func (og *operationGenerator) GenerateUnmountDeviceFunc(
  676. deviceToDetach AttachedVolume,
  677. actualStateOfWorld ActualStateOfWorldMounterUpdater,
  678. hostutil hostutil.HostUtils) (volumetypes.GeneratedOperations, error) {
  679. // Get DeviceMounter plugin
  680. deviceMountableVolumePlugin, err :=
  681. og.volumePluginMgr.FindDeviceMountablePluginByName(deviceToDetach.PluginName)
  682. if err != nil || deviceMountableVolumePlugin == nil {
  683. return volumetypes.GeneratedOperations{}, deviceToDetach.GenerateErrorDetailed("UnmountDevice.FindDeviceMountablePluginByName failed", err)
  684. }
  685. volumeDeviceUmounter, err := deviceMountableVolumePlugin.NewDeviceUnmounter()
  686. if err != nil {
  687. return volumetypes.GeneratedOperations{}, deviceToDetach.GenerateErrorDetailed("UnmountDevice.NewDeviceUmounter failed", err)
  688. }
  689. volumeDeviceMounter, err := deviceMountableVolumePlugin.NewDeviceMounter()
  690. if err != nil {
  691. return volumetypes.GeneratedOperations{}, deviceToDetach.GenerateErrorDetailed("UnmountDevice.NewDeviceMounter failed", err)
  692. }
  693. unmountDeviceFunc := func() (error, error) {
  694. //deviceMountPath := deviceToDetach.DeviceMountPath
  695. deviceMountPath, err :=
  696. volumeDeviceMounter.GetDeviceMountPath(deviceToDetach.VolumeSpec)
  697. if err != nil {
  698. // On failure, return error. Caller will log and retry.
  699. return deviceToDetach.GenerateError("GetDeviceMountPath failed", err)
  700. }
  701. refs, err := deviceMountableVolumePlugin.GetDeviceMountRefs(deviceMountPath)
  702. if err != nil || util.HasMountRefs(deviceMountPath, refs) {
  703. if err == nil {
  704. err = fmt.Errorf("The device mount path %q is still mounted by other references %v", deviceMountPath, refs)
  705. }
  706. return deviceToDetach.GenerateError("GetDeviceMountRefs check failed", err)
  707. }
  708. // Execute unmount
  709. unmountDeviceErr := volumeDeviceUmounter.UnmountDevice(deviceMountPath)
  710. if unmountDeviceErr != nil {
  711. // On failure, return error. Caller will log and retry.
  712. return deviceToDetach.GenerateError("UnmountDevice failed", unmountDeviceErr)
  713. }
  714. // Before logging that UnmountDevice succeeded and moving on,
  715. // use hostutil.PathIsDevice to check if the path is a device,
  716. // if so use hostutil.DeviceOpened to check if the device is in use anywhere
  717. // else on the system. Retry if it returns true.
  718. deviceOpened, deviceOpenedErr := isDeviceOpened(deviceToDetach, hostutil)
  719. if deviceOpenedErr != nil {
  720. return nil, deviceOpenedErr
  721. }
  722. // The device is still in use elsewhere. Caller will log and retry.
  723. if deviceOpened {
  724. return deviceToDetach.GenerateError(
  725. "UnmountDevice failed",
  726. goerrors.New("the device is in use when it was no longer expected to be in use"))
  727. }
  728. klog.Infof(deviceToDetach.GenerateMsg("UnmountDevice succeeded", ""))
  729. // Update actual state of world
  730. markDeviceUnmountedErr := actualStateOfWorld.MarkDeviceAsUnmounted(
  731. deviceToDetach.VolumeName)
  732. if markDeviceUnmountedErr != nil {
  733. // On failure, return error. Caller will log and retry.
  734. return deviceToDetach.GenerateError("MarkDeviceAsUnmounted failed", markDeviceUnmountedErr)
  735. }
  736. return nil, nil
  737. }
  738. return volumetypes.GeneratedOperations{
  739. OperationName: "unmount_device",
  740. OperationFunc: unmountDeviceFunc,
  741. CompleteFunc: util.OperationCompleteHook(util.GetFullQualifiedPluginNameForVolume(deviceMountableVolumePlugin.GetPluginName(), deviceToDetach.VolumeSpec), "unmount_device"),
  742. EventRecorderFunc: nil, // nil because we do not want to generate event on error
  743. }, nil
  744. }
  745. // GenerateMapVolumeFunc marks volume as mounted based on following steps.
  746. // If plugin is attachable, call WaitForAttach() and then mark the device
  747. // as mounted. On next step, SetUpDevice is called without dependent of
  748. // plugin type, but this method mainly is targeted for none attachable plugin.
  749. // After setup is done, create symbolic links on both global map path and pod
  750. // device map path. Once symbolic links are created, take fd lock by
  751. // loopback for the device to avoid silent volume replacement. This lock
  752. // will be released once no one uses the device.
  753. // If all steps are completed, the volume is marked as mounted.
  754. func (og *operationGenerator) GenerateMapVolumeFunc(
  755. waitForAttachTimeout time.Duration,
  756. volumeToMount VolumeToMount,
  757. actualStateOfWorld ActualStateOfWorldMounterUpdater) (volumetypes.GeneratedOperations, error) {
  758. // Get block volume mapper plugin
  759. blockVolumePlugin, err :=
  760. og.volumePluginMgr.FindMapperPluginBySpec(volumeToMount.VolumeSpec)
  761. if err != nil {
  762. return volumetypes.GeneratedOperations{}, volumeToMount.GenerateErrorDetailed("MapVolume.FindMapperPluginBySpec failed", err)
  763. }
  764. if blockVolumePlugin == nil {
  765. return volumetypes.GeneratedOperations{}, volumeToMount.GenerateErrorDetailed("MapVolume.FindMapperPluginBySpec failed to find BlockVolumeMapper plugin. Volume plugin is nil.", nil)
  766. }
  767. affinityErr := checkNodeAffinity(og, volumeToMount)
  768. if affinityErr != nil {
  769. eventErr, detailedErr := volumeToMount.GenerateError("MapVolume.NodeAffinity check failed", affinityErr)
  770. og.recorder.Eventf(volumeToMount.Pod, v1.EventTypeWarning, kevents.FailedMountVolume, eventErr.Error())
  771. return volumetypes.GeneratedOperations{}, detailedErr
  772. }
  773. blockVolumeMapper, newMapperErr := blockVolumePlugin.NewBlockVolumeMapper(
  774. volumeToMount.VolumeSpec,
  775. volumeToMount.Pod,
  776. volume.VolumeOptions{})
  777. if newMapperErr != nil {
  778. eventErr, detailedErr := volumeToMount.GenerateError("MapVolume.NewBlockVolumeMapper initialization failed", newMapperErr)
  779. og.recorder.Eventf(volumeToMount.Pod, v1.EventTypeWarning, kevents.FailedMapVolume, eventErr.Error())
  780. return volumetypes.GeneratedOperations{}, detailedErr
  781. }
  782. // Get attacher, if possible
  783. attachableVolumePlugin, _ :=
  784. og.volumePluginMgr.FindAttachablePluginBySpec(volumeToMount.VolumeSpec)
  785. var volumeAttacher volume.Attacher
  786. if attachableVolumePlugin != nil {
  787. volumeAttacher, _ = attachableVolumePlugin.NewAttacher()
  788. }
  789. mapVolumeFunc := func() (error, error) {
  790. var devicePath string
  791. // Set up global map path under the given plugin directory using symbolic link
  792. globalMapPath, err :=
  793. blockVolumeMapper.GetGlobalMapPath(volumeToMount.VolumeSpec)
  794. if err != nil {
  795. // On failure, return error. Caller will log and retry.
  796. return volumeToMount.GenerateError("MapVolume.GetGlobalMapPath failed", err)
  797. }
  798. if volumeAttacher != nil {
  799. // Wait for attachable volumes to finish attaching
  800. klog.Infof(volumeToMount.GenerateMsgDetailed("MapVolume.WaitForAttach entering", fmt.Sprintf("DevicePath %q", volumeToMount.DevicePath)))
  801. devicePath, err = volumeAttacher.WaitForAttach(
  802. volumeToMount.VolumeSpec, volumeToMount.DevicePath, volumeToMount.Pod, waitForAttachTimeout)
  803. if err != nil {
  804. // On failure, return error. Caller will log and retry.
  805. return volumeToMount.GenerateError("MapVolume.WaitForAttach failed", err)
  806. }
  807. klog.Infof(volumeToMount.GenerateMsgDetailed("MapVolume.WaitForAttach succeeded", fmt.Sprintf("DevicePath %q", devicePath)))
  808. }
  809. // Call SetUpDevice if blockVolumeMapper implements CustomBlockVolumeMapper
  810. if customBlockVolumeMapper, ok := blockVolumeMapper.(volume.CustomBlockVolumeMapper); ok {
  811. mapErr := customBlockVolumeMapper.SetUpDevice()
  812. if mapErr != nil {
  813. // On failure, return error. Caller will log and retry.
  814. return volumeToMount.GenerateError("MapVolume.SetUpDevice failed", mapErr)
  815. }
  816. }
  817. // Update actual state of world to reflect volume is globally mounted
  818. markedDevicePath := devicePath
  819. markDeviceMappedErr := actualStateOfWorld.MarkDeviceAsMounted(
  820. volumeToMount.VolumeName, markedDevicePath, globalMapPath)
  821. if markDeviceMappedErr != nil {
  822. // On failure, return error. Caller will log and retry.
  823. return volumeToMount.GenerateError("MapVolume.MarkDeviceAsMounted failed", markDeviceMappedErr)
  824. }
  825. // Call MapPodDevice if blockVolumeMapper implements CustomBlockVolumeMapper
  826. if customBlockVolumeMapper, ok := blockVolumeMapper.(volume.CustomBlockVolumeMapper); ok {
  827. // Execute driver specific map
  828. pluginDevicePath, mapErr := customBlockVolumeMapper.MapPodDevice()
  829. if mapErr != nil {
  830. // On failure, return error. Caller will log and retry.
  831. return volumeToMount.GenerateError("MapVolume.MapPodDevice failed", mapErr)
  832. }
  833. // if pluginDevicePath is provided, assume attacher may not provide device
  834. // or attachment flow uses SetupDevice to get device path
  835. if len(pluginDevicePath) != 0 {
  836. devicePath = pluginDevicePath
  837. }
  838. if len(devicePath) == 0 {
  839. return volumeToMount.GenerateError("MapVolume failed", goerrors.New("Device path of the volume is empty"))
  840. }
  841. }
  842. // When kubelet is containerized, devicePath may be a symlink at a place unavailable to
  843. // kubelet, so evaluate it on the host and expect that it links to a device in /dev,
  844. // which will be available to containerized kubelet. If still it does not exist,
  845. // AttachFileDevice will fail. If kubelet is not containerized, eval it anyway.
  846. kvh, ok := og.GetVolumePluginMgr().Host.(volume.KubeletVolumeHost)
  847. if !ok {
  848. return volumeToMount.GenerateError("MapVolume type assertion error", fmt.Errorf("volume host does not implement KubeletVolumeHost interface"))
  849. }
  850. hu := kvh.GetHostUtil()
  851. devicePath, err = hu.EvalHostSymlinks(devicePath)
  852. if err != nil {
  853. return volumeToMount.GenerateError("MapVolume.EvalHostSymlinks failed", err)
  854. }
  855. // Update actual state of world with the devicePath again, if devicePath has changed from markedDevicePath
  856. // TODO: This can be improved after #82492 is merged and ASW has state.
  857. if markedDevicePath != devicePath {
  858. markDeviceMappedErr := actualStateOfWorld.MarkDeviceAsMounted(
  859. volumeToMount.VolumeName, devicePath, globalMapPath)
  860. if markDeviceMappedErr != nil {
  861. // On failure, return error. Caller will log and retry.
  862. return volumeToMount.GenerateError("MapVolume.MarkDeviceAsMounted failed", markDeviceMappedErr)
  863. }
  864. }
  865. // Execute common map
  866. volumeMapPath, volName := blockVolumeMapper.GetPodDeviceMapPath()
  867. mapErr := ioutil.MapBlockVolume(og.blkUtil, devicePath, globalMapPath, volumeMapPath, volName, volumeToMount.Pod.UID)
  868. if mapErr != nil {
  869. // On failure, return error. Caller will log and retry.
  870. return volumeToMount.GenerateError("MapVolume.MapBlockVolume failed", mapErr)
  871. }
  872. // Device mapping for global map path succeeded
  873. simpleMsg, detailedMsg := volumeToMount.GenerateMsg("MapVolume.MapPodDevice succeeded", fmt.Sprintf("globalMapPath %q", globalMapPath))
  874. verbosity := klog.Level(4)
  875. og.recorder.Eventf(volumeToMount.Pod, v1.EventTypeNormal, kevents.SuccessfulMountVolume, simpleMsg)
  876. klog.V(verbosity).Infof(detailedMsg)
  877. // Device mapping for pod device map path succeeded
  878. simpleMsg, detailedMsg = volumeToMount.GenerateMsg("MapVolume.MapPodDevice succeeded", fmt.Sprintf("volumeMapPath %q", volumeMapPath))
  879. verbosity = klog.Level(1)
  880. og.recorder.Eventf(volumeToMount.Pod, v1.EventTypeNormal, kevents.SuccessfulMountVolume, simpleMsg)
  881. klog.V(verbosity).Infof(detailedMsg)
  882. resizeOptions := volume.NodeResizeOptions{
  883. DevicePath: devicePath,
  884. CSIVolumePhase: volume.CSIVolumePublished,
  885. }
  886. _, resizeError := og.nodeExpandVolume(volumeToMount, resizeOptions)
  887. if resizeError != nil {
  888. klog.Errorf("MapVolume.NodeExpandVolume failed with %v", resizeError)
  889. return volumeToMount.GenerateError("MapVolume.MarkVolumeAsMounted failed while expanding volume", resizeError)
  890. }
  891. markVolumeOpts := MarkVolumeOpts{
  892. PodName: volumeToMount.PodName,
  893. PodUID: volumeToMount.Pod.UID,
  894. VolumeName: volumeToMount.VolumeName,
  895. BlockVolumeMapper: blockVolumeMapper,
  896. OuterVolumeSpecName: volumeToMount.OuterVolumeSpecName,
  897. VolumeGidVolume: volumeToMount.VolumeGidValue,
  898. VolumeSpec: volumeToMount.VolumeSpec,
  899. VolumeMountState: VolumeMounted,
  900. }
  901. markVolMountedErr := actualStateOfWorld.MarkVolumeAsMounted(markVolumeOpts)
  902. if markVolMountedErr != nil {
  903. // On failure, return error. Caller will log and retry.
  904. return volumeToMount.GenerateError("MapVolume.MarkVolumeAsMounted failed", markVolMountedErr)
  905. }
  906. return nil, nil
  907. }
  908. eventRecorderFunc := func(err *error) {
  909. if *err != nil {
  910. og.recorder.Eventf(volumeToMount.Pod, v1.EventTypeWarning, kevents.FailedMapVolume, (*err).Error())
  911. }
  912. }
  913. return volumetypes.GeneratedOperations{
  914. OperationName: "map_volume",
  915. OperationFunc: mapVolumeFunc,
  916. EventRecorderFunc: eventRecorderFunc,
  917. CompleteFunc: util.OperationCompleteHook(util.GetFullQualifiedPluginNameForVolume(blockVolumePlugin.GetPluginName(), volumeToMount.VolumeSpec), "map_volume"),
  918. }, nil
  919. }
  920. // GenerateUnmapVolumeFunc marks volume as unmonuted based on following steps.
  921. // Remove symbolic links from pod device map path dir and global map path dir.
  922. // Once those cleanups are done, remove pod device map path dir.
  923. // If all steps are completed, the volume is marked as unmounted.
  924. func (og *operationGenerator) GenerateUnmapVolumeFunc(
  925. volumeToUnmount MountedVolume,
  926. actualStateOfWorld ActualStateOfWorldMounterUpdater) (volumetypes.GeneratedOperations, error) {
  927. // Get block volume unmapper plugin
  928. blockVolumePlugin, err :=
  929. og.volumePluginMgr.FindMapperPluginByName(volumeToUnmount.PluginName)
  930. if err != nil {
  931. return volumetypes.GeneratedOperations{}, volumeToUnmount.GenerateErrorDetailed("UnmapVolume.FindMapperPluginByName failed", err)
  932. }
  933. if blockVolumePlugin == nil {
  934. return volumetypes.GeneratedOperations{}, volumeToUnmount.GenerateErrorDetailed("UnmapVolume.FindMapperPluginByName failed to find BlockVolumeMapper plugin. Volume plugin is nil.", nil)
  935. }
  936. blockVolumeUnmapper, newUnmapperErr := blockVolumePlugin.NewBlockVolumeUnmapper(
  937. volumeToUnmount.InnerVolumeSpecName, volumeToUnmount.PodUID)
  938. if newUnmapperErr != nil {
  939. return volumetypes.GeneratedOperations{}, volumeToUnmount.GenerateErrorDetailed("UnmapVolume.NewUnmapper failed", newUnmapperErr)
  940. }
  941. unmapVolumeFunc := func() (error, error) {
  942. // pods/{podUid}/volumeDevices/{escapeQualifiedPluginName}/{volumeName}
  943. podDeviceUnmapPath, volName := blockVolumeUnmapper.GetPodDeviceMapPath()
  944. // plugins/kubernetes.io/{PluginName}/volumeDevices/{volumePluginDependentPath}/{podUID}
  945. globalUnmapPath := volumeToUnmount.DeviceMountPath
  946. // Execute common unmap
  947. unmapErr := ioutil.UnmapBlockVolume(og.blkUtil, globalUnmapPath, podDeviceUnmapPath, volName, volumeToUnmount.PodUID)
  948. if unmapErr != nil {
  949. // On failure, return error. Caller will log and retry.
  950. return volumeToUnmount.GenerateError("UnmapVolume.UnmapBlockVolume failed", unmapErr)
  951. }
  952. // Call UnmapPodDevice if blockVolumeUnmapper implements CustomBlockVolumeUnmapper
  953. if customBlockVolumeUnmapper, ok := blockVolumeUnmapper.(volume.CustomBlockVolumeUnmapper); ok {
  954. // Execute plugin specific unmap
  955. unmapErr = customBlockVolumeUnmapper.UnmapPodDevice()
  956. if unmapErr != nil {
  957. // On failure, return error. Caller will log and retry.
  958. return volumeToUnmount.GenerateError("UnmapVolume.UnmapPodDevice failed", unmapErr)
  959. }
  960. }
  961. klog.Infof(
  962. "UnmapVolume succeeded for volume %q (OuterVolumeSpecName: %q) pod %q (UID: %q). InnerVolumeSpecName %q. PluginName %q, VolumeGidValue %q",
  963. volumeToUnmount.VolumeName,
  964. volumeToUnmount.OuterVolumeSpecName,
  965. volumeToUnmount.PodName,
  966. volumeToUnmount.PodUID,
  967. volumeToUnmount.InnerVolumeSpecName,
  968. volumeToUnmount.PluginName,
  969. volumeToUnmount.VolumeGidValue)
  970. // Update actual state of world
  971. markVolUnmountedErr := actualStateOfWorld.MarkVolumeAsUnmounted(
  972. volumeToUnmount.PodName, volumeToUnmount.VolumeName)
  973. if markVolUnmountedErr != nil {
  974. // On failure, just log and exit
  975. klog.Errorf(volumeToUnmount.GenerateErrorDetailed("UnmapVolume.MarkVolumeAsUnmounted failed", markVolUnmountedErr).Error())
  976. }
  977. return nil, nil
  978. }
  979. return volumetypes.GeneratedOperations{
  980. OperationName: "unmap_volume",
  981. OperationFunc: unmapVolumeFunc,
  982. CompleteFunc: util.OperationCompleteHook(util.GetFullQualifiedPluginNameForVolume(blockVolumePlugin.GetPluginName(), volumeToUnmount.VolumeSpec), "unmap_volume"),
  983. EventRecorderFunc: nil, // nil because we do not want to generate event on error
  984. }, nil
  985. }
  986. // GenerateUnmapDeviceFunc marks device as unmounted based on following steps.
  987. // Check under globalMapPath dir if there isn't pod's symbolic links in it.
  988. // If symbolic link isn't there, the device isn't referenced from Pods.
  989. // Call plugin TearDownDevice to clean-up device connection, stored data under
  990. // globalMapPath, these operations depend on plugin implementation.
  991. // Once TearDownDevice is completed, remove globalMapPath dir.
  992. // After globalMapPath is removed, fd lock by loopback for the device can
  993. // be released safely because no one can consume the device at this point.
  994. // At last, device open status will be checked just in case.
  995. // If all steps are completed, the device is marked as unmounted.
  996. func (og *operationGenerator) GenerateUnmapDeviceFunc(
  997. deviceToDetach AttachedVolume,
  998. actualStateOfWorld ActualStateOfWorldMounterUpdater,
  999. hostutil hostutil.HostUtils) (volumetypes.GeneratedOperations, error) {
  1000. blockVolumePlugin, err :=
  1001. og.volumePluginMgr.FindMapperPluginByName(deviceToDetach.PluginName)
  1002. if err != nil {
  1003. return volumetypes.GeneratedOperations{}, deviceToDetach.GenerateErrorDetailed("UnmapDevice.FindMapperPluginByName failed", err)
  1004. }
  1005. if blockVolumePlugin == nil {
  1006. return volumetypes.GeneratedOperations{}, deviceToDetach.GenerateErrorDetailed("UnmapDevice.FindMapperPluginByName failed to find BlockVolumeMapper plugin. Volume plugin is nil.", nil)
  1007. }
  1008. blockVolumeUnmapper, newUnmapperErr := blockVolumePlugin.NewBlockVolumeUnmapper(
  1009. deviceToDetach.VolumeSpec.Name(),
  1010. "" /* podUID */)
  1011. if newUnmapperErr != nil {
  1012. return volumetypes.GeneratedOperations{}, deviceToDetach.GenerateErrorDetailed("UnmapDevice.NewUnmapper failed", newUnmapperErr)
  1013. }
  1014. unmapDeviceFunc := func() (error, error) {
  1015. // Search under globalMapPath dir if all symbolic links from pods have been removed already.
  1016. // If symbolic links are there, pods may still refer the volume.
  1017. globalMapPath := deviceToDetach.DeviceMountPath
  1018. refs, err := og.blkUtil.GetDeviceBindMountRefs(deviceToDetach.DevicePath, globalMapPath)
  1019. if err != nil {
  1020. return deviceToDetach.GenerateError("UnmapDevice.GetDeviceBindMountRefs check failed", err)
  1021. }
  1022. if len(refs) > 0 {
  1023. err = fmt.Errorf("The device %q is still referenced from other Pods %v", globalMapPath, refs)
  1024. return deviceToDetach.GenerateError("UnmapDevice failed", err)
  1025. }
  1026. // Call TearDownDevice if blockVolumeUnmapper implements CustomBlockVolumeUnmapper
  1027. if customBlockVolumeUnmapper, ok := blockVolumeUnmapper.(volume.CustomBlockVolumeUnmapper); ok {
  1028. // Execute tear down device
  1029. unmapErr := customBlockVolumeUnmapper.TearDownDevice(globalMapPath, deviceToDetach.DevicePath)
  1030. if unmapErr != nil {
  1031. // On failure, return error. Caller will log and retry.
  1032. return deviceToDetach.GenerateError("UnmapDevice.TearDownDevice failed", unmapErr)
  1033. }
  1034. }
  1035. // Plugin finished TearDownDevice(). Now globalMapPath dir and plugin's stored data
  1036. // on the dir are unnecessary, clean up it.
  1037. removeMapPathErr := og.blkUtil.RemoveMapPath(globalMapPath)
  1038. if removeMapPathErr != nil {
  1039. // On failure, return error. Caller will log and retry.
  1040. return deviceToDetach.GenerateError("UnmapDevice.RemoveMapPath failed", removeMapPathErr)
  1041. }
  1042. // Before logging that UnmapDevice succeeded and moving on,
  1043. // use hostutil.PathIsDevice to check if the path is a device,
  1044. // if so use hostutil.DeviceOpened to check if the device is in use anywhere
  1045. // else on the system. Retry if it returns true.
  1046. deviceOpened, deviceOpenedErr := isDeviceOpened(deviceToDetach, hostutil)
  1047. if deviceOpenedErr != nil {
  1048. return nil, deviceOpenedErr
  1049. }
  1050. // The device is still in use elsewhere. Caller will log and retry.
  1051. if deviceOpened {
  1052. return deviceToDetach.GenerateError(
  1053. "UnmapDevice failed",
  1054. fmt.Errorf("the device is in use when it was no longer expected to be in use"))
  1055. }
  1056. klog.Infof(deviceToDetach.GenerateMsgDetailed("UnmapDevice succeeded", ""))
  1057. // Update actual state of world
  1058. markDeviceUnmountedErr := actualStateOfWorld.MarkDeviceAsUnmounted(
  1059. deviceToDetach.VolumeName)
  1060. if markDeviceUnmountedErr != nil {
  1061. // On failure, return error. Caller will log and retry.
  1062. return deviceToDetach.GenerateError("MarkDeviceAsUnmounted failed", markDeviceUnmountedErr)
  1063. }
  1064. return nil, nil
  1065. }
  1066. return volumetypes.GeneratedOperations{
  1067. OperationName: "unmap_device",
  1068. OperationFunc: unmapDeviceFunc,
  1069. CompleteFunc: util.OperationCompleteHook(util.GetFullQualifiedPluginNameForVolume(blockVolumePlugin.GetPluginName(), deviceToDetach.VolumeSpec), "unmap_device"),
  1070. EventRecorderFunc: nil, // nil because we do not want to generate event on error
  1071. }, nil
  1072. }
  1073. func (og *operationGenerator) GenerateVerifyControllerAttachedVolumeFunc(
  1074. volumeToMount VolumeToMount,
  1075. nodeName types.NodeName,
  1076. actualStateOfWorld ActualStateOfWorldAttacherUpdater) (volumetypes.GeneratedOperations, error) {
  1077. volumePlugin, err :=
  1078. og.volumePluginMgr.FindPluginBySpec(volumeToMount.VolumeSpec)
  1079. if err != nil || volumePlugin == nil {
  1080. return volumetypes.GeneratedOperations{}, volumeToMount.GenerateErrorDetailed("VerifyControllerAttachedVolume.FindPluginBySpec failed", err)
  1081. }
  1082. verifyControllerAttachedVolumeFunc := func() (error, error) {
  1083. if !volumeToMount.PluginIsAttachable {
  1084. // If the volume does not implement the attacher interface, it is
  1085. // assumed to be attached and the actual state of the world is
  1086. // updated accordingly.
  1087. addVolumeNodeErr := actualStateOfWorld.MarkVolumeAsAttached(
  1088. volumeToMount.VolumeName, volumeToMount.VolumeSpec, nodeName, "" /* devicePath */)
  1089. if addVolumeNodeErr != nil {
  1090. // On failure, return error. Caller will log and retry.
  1091. return volumeToMount.GenerateError("VerifyControllerAttachedVolume.MarkVolumeAsAttachedByUniqueVolumeName failed", addVolumeNodeErr)
  1092. }
  1093. return nil, nil
  1094. }
  1095. if !volumeToMount.ReportedInUse {
  1096. // If the given volume has not yet been added to the list of
  1097. // VolumesInUse in the node's volume status, do not proceed, return
  1098. // error. Caller will log and retry. The node status is updated
  1099. // periodically by kubelet, so it may take as much as 10 seconds
  1100. // before this clears.
  1101. // Issue #28141 to enable on demand status updates.
  1102. return volumeToMount.GenerateError("Volume has not been added to the list of VolumesInUse in the node's volume status", nil)
  1103. }
  1104. // Fetch current node object
  1105. node, fetchErr := og.kubeClient.CoreV1().Nodes().Get(context.TODO(), string(nodeName), metav1.GetOptions{})
  1106. if fetchErr != nil {
  1107. // On failure, return error. Caller will log and retry.
  1108. return volumeToMount.GenerateError("VerifyControllerAttachedVolume failed fetching node from API server", fetchErr)
  1109. }
  1110. if node == nil {
  1111. // On failure, return error. Caller will log and retry.
  1112. return volumeToMount.GenerateError(
  1113. "VerifyControllerAttachedVolume failed",
  1114. fmt.Errorf("Node object retrieved from API server is nil"))
  1115. }
  1116. for _, attachedVolume := range node.Status.VolumesAttached {
  1117. if attachedVolume.Name == volumeToMount.VolumeName {
  1118. addVolumeNodeErr := actualStateOfWorld.MarkVolumeAsAttached(
  1119. v1.UniqueVolumeName(""), volumeToMount.VolumeSpec, nodeName, attachedVolume.DevicePath)
  1120. klog.Infof(volumeToMount.GenerateMsgDetailed("Controller attach succeeded", fmt.Sprintf("device path: %q", attachedVolume.DevicePath)))
  1121. if addVolumeNodeErr != nil {
  1122. // On failure, return error. Caller will log and retry.
  1123. return volumeToMount.GenerateError("VerifyControllerAttachedVolume.MarkVolumeAsAttached failed", addVolumeNodeErr)
  1124. }
  1125. return nil, nil
  1126. }
  1127. }
  1128. // Volume not attached, return error. Caller will log and retry.
  1129. return volumeToMount.GenerateError("Volume not attached according to node status", nil)
  1130. }
  1131. return volumetypes.GeneratedOperations{
  1132. OperationName: "verify_controller_attached_volume",
  1133. OperationFunc: verifyControllerAttachedVolumeFunc,
  1134. CompleteFunc: util.OperationCompleteHook(util.GetFullQualifiedPluginNameForVolume(volumePlugin.GetPluginName(), volumeToMount.VolumeSpec), "verify_controller_attached_volume"),
  1135. EventRecorderFunc: nil, // nil because we do not want to generate event on error
  1136. }, nil
  1137. }
  1138. func (og *operationGenerator) verifyVolumeIsSafeToDetach(
  1139. volumeToDetach AttachedVolume) error {
  1140. // Fetch current node object
  1141. node, fetchErr := og.kubeClient.CoreV1().Nodes().Get(context.TODO(), string(volumeToDetach.NodeName), metav1.GetOptions{})
  1142. if fetchErr != nil {
  1143. if errors.IsNotFound(fetchErr) {
  1144. klog.Warningf(volumeToDetach.GenerateMsgDetailed("Node not found on API server. DetachVolume will skip safe to detach check", ""))
  1145. return nil
  1146. }
  1147. // On failure, return error. Caller will log and retry.
  1148. return volumeToDetach.GenerateErrorDetailed("DetachVolume failed fetching node from API server", fetchErr)
  1149. }
  1150. if node == nil {
  1151. // On failure, return error. Caller will log and retry.
  1152. return volumeToDetach.GenerateErrorDetailed(
  1153. "DetachVolume failed fetching node from API server",
  1154. fmt.Errorf("node object retrieved from API server is nil"))
  1155. }
  1156. for _, inUseVolume := range node.Status.VolumesInUse {
  1157. if inUseVolume == volumeToDetach.VolumeName {
  1158. return volumeToDetach.GenerateErrorDetailed(
  1159. "DetachVolume failed",
  1160. fmt.Errorf("volume is still in use by node, according to Node status"))
  1161. }
  1162. }
  1163. // Volume is not marked as in use by node
  1164. klog.Infof(volumeToDetach.GenerateMsgDetailed("Verified volume is safe to detach", ""))
  1165. return nil
  1166. }
  1167. func (og *operationGenerator) GenerateExpandVolumeFunc(
  1168. pvc *v1.PersistentVolumeClaim,
  1169. pv *v1.PersistentVolume) (volumetypes.GeneratedOperations, error) {
  1170. volumeSpec := volume.NewSpecFromPersistentVolume(pv, false)
  1171. volumePlugin, err := og.volumePluginMgr.FindExpandablePluginBySpec(volumeSpec)
  1172. if err != nil {
  1173. return volumetypes.GeneratedOperations{}, fmt.Errorf("Error finding plugin for expanding volume: %q with error %v", util.GetPersistentVolumeClaimQualifiedName(pvc), err)
  1174. }
  1175. if volumePlugin == nil {
  1176. return volumetypes.GeneratedOperations{}, fmt.Errorf("Can not find plugin for expanding volume: %q", util.GetPersistentVolumeClaimQualifiedName(pvc))
  1177. }
  1178. expandVolumeFunc := func() (error, error) {
  1179. newSize := pvc.Spec.Resources.Requests[v1.ResourceStorage]
  1180. statusSize := pvc.Status.Capacity[v1.ResourceStorage]
  1181. pvSize := pv.Spec.Capacity[v1.ResourceStorage]
  1182. if pvSize.Cmp(newSize) < 0 {
  1183. updatedSize, expandErr := volumePlugin.ExpandVolumeDevice(
  1184. volumeSpec,
  1185. newSize,
  1186. statusSize)
  1187. if expandErr != nil {
  1188. detailedErr := fmt.Errorf("error expanding volume %q of plugin %q: %v", util.GetPersistentVolumeClaimQualifiedName(pvc), volumePlugin.GetPluginName(), expandErr)
  1189. return detailedErr, detailedErr
  1190. }
  1191. klog.Infof("ExpandVolume succeeded for volume %s", util.GetPersistentVolumeClaimQualifiedName(pvc))
  1192. newSize = updatedSize
  1193. // k8s doesn't have transactions, we can't guarantee that after updating PV - updating PVC will be
  1194. // successful, that is why all PVCs for which pvc.Spec.Size > pvc.Status.Size must be reprocessed
  1195. // until they reflect user requested size in pvc.Status.Size
  1196. updateErr := util.UpdatePVSize(pv, newSize, og.kubeClient)
  1197. if updateErr != nil {
  1198. detailedErr := fmt.Errorf("Error updating PV spec capacity for volume %q with : %v", util.GetPersistentVolumeClaimQualifiedName(pvc), updateErr)
  1199. return detailedErr, detailedErr
  1200. }
  1201. klog.Infof("ExpandVolume.UpdatePV succeeded for volume %s", util.GetPersistentVolumeClaimQualifiedName(pvc))
  1202. }
  1203. fsVolume, _ := util.CheckVolumeModeFilesystem(volumeSpec)
  1204. // No Cloudprovider resize needed, lets mark resizing as done
  1205. // Rest of the volume expand controller code will assume PVC as *not* resized until pvc.Status.Size
  1206. // reflects user requested size.
  1207. if !volumePlugin.RequiresFSResize() || !fsVolume {
  1208. klog.V(4).Infof("Controller resizing done for PVC %s", util.GetPersistentVolumeClaimQualifiedName(pvc))
  1209. err := util.MarkResizeFinished(pvc, newSize, og.kubeClient)
  1210. if err != nil {
  1211. detailedErr := fmt.Errorf("Error marking pvc %s as resized : %v", util.GetPersistentVolumeClaimQualifiedName(pvc), err)
  1212. return detailedErr, detailedErr
  1213. }
  1214. successMsg := fmt.Sprintf("ExpandVolume succeeded for volume %s", util.GetPersistentVolumeClaimQualifiedName(pvc))
  1215. og.recorder.Eventf(pvc, v1.EventTypeNormal, kevents.VolumeResizeSuccess, successMsg)
  1216. } else {
  1217. err := util.MarkForFSResize(pvc, og.kubeClient)
  1218. if err != nil {
  1219. detailedErr := fmt.Errorf("Error updating pvc %s condition for fs resize : %v", util.GetPersistentVolumeClaimQualifiedName(pvc), err)
  1220. klog.Warning(detailedErr)
  1221. return nil, nil
  1222. }
  1223. }
  1224. return nil, nil
  1225. }
  1226. eventRecorderFunc := func(err *error) {
  1227. if *err != nil {
  1228. og.recorder.Eventf(pvc, v1.EventTypeWarning, kevents.VolumeResizeFailed, (*err).Error())
  1229. }
  1230. }
  1231. return volumetypes.GeneratedOperations{
  1232. OperationName: "expand_volume",
  1233. OperationFunc: expandVolumeFunc,
  1234. EventRecorderFunc: eventRecorderFunc,
  1235. CompleteFunc: util.OperationCompleteHook(util.GetFullQualifiedPluginNameForVolume(volumePlugin.GetPluginName(), volumeSpec), "expand_volume"),
  1236. }, nil
  1237. }
  1238. func (og *operationGenerator) GenerateExpandInUseVolumeFunc(
  1239. volumeToMount VolumeToMount,
  1240. actualStateOfWorld ActualStateOfWorldMounterUpdater) (volumetypes.GeneratedOperations, error) {
  1241. volumePlugin, err :=
  1242. og.volumePluginMgr.FindPluginBySpec(volumeToMount.VolumeSpec)
  1243. if err != nil || volumePlugin == nil {
  1244. return volumetypes.GeneratedOperations{}, volumeToMount.GenerateErrorDetailed("NodeExpandVolume.FindPluginBySpec failed", err)
  1245. }
  1246. fsResizeFunc := func() (error, error) {
  1247. var resizeDone bool
  1248. var simpleErr, detailedErr error
  1249. resizeOptions := volume.NodeResizeOptions{
  1250. VolumeSpec: volumeToMount.VolumeSpec,
  1251. }
  1252. attachableVolumePlugin, _ :=
  1253. og.volumePluginMgr.FindAttachablePluginBySpec(volumeToMount.VolumeSpec)
  1254. if attachableVolumePlugin != nil {
  1255. volumeAttacher, _ := attachableVolumePlugin.NewAttacher()
  1256. if volumeAttacher != nil {
  1257. resizeOptions.CSIVolumePhase = volume.CSIVolumeStaged
  1258. resizeOptions.DevicePath = volumeToMount.DevicePath
  1259. dmp, err := volumeAttacher.GetDeviceMountPath(volumeToMount.VolumeSpec)
  1260. if err != nil {
  1261. return volumeToMount.GenerateError("NodeExpandVolume.GetDeviceMountPath failed", err)
  1262. }
  1263. resizeOptions.DeviceMountPath = dmp
  1264. resizeDone, simpleErr, detailedErr = og.doOnlineExpansion(volumeToMount, actualStateOfWorld, resizeOptions)
  1265. if simpleErr != nil || detailedErr != nil {
  1266. return simpleErr, detailedErr
  1267. }
  1268. if resizeDone {
  1269. return nil, nil
  1270. }
  1271. }
  1272. }
  1273. // if we are here that means volume plugin does not support attach interface
  1274. volumeMounter, newMounterErr := volumePlugin.NewMounter(
  1275. volumeToMount.VolumeSpec,
  1276. volumeToMount.Pod,
  1277. volume.VolumeOptions{})
  1278. if newMounterErr != nil {
  1279. return volumeToMount.GenerateError("NodeExpandVolume.NewMounter initialization failed", newMounterErr)
  1280. }
  1281. resizeOptions.DeviceMountPath = volumeMounter.GetPath()
  1282. resizeOptions.CSIVolumePhase = volume.CSIVolumePublished
  1283. resizeDone, simpleErr, detailedErr = og.doOnlineExpansion(volumeToMount, actualStateOfWorld, resizeOptions)
  1284. if simpleErr != nil || detailedErr != nil {
  1285. return simpleErr, detailedErr
  1286. }
  1287. if resizeDone {
  1288. return nil, nil
  1289. }
  1290. // This is a placeholder error - we should NEVER reach here.
  1291. err = fmt.Errorf("volume resizing failed for unknown reason")
  1292. return volumeToMount.GenerateError("NodeExpandVolume.NodeExpandVolume failed to resize volume", err)
  1293. }
  1294. eventRecorderFunc := func(err *error) {
  1295. if *err != nil {
  1296. og.recorder.Eventf(volumeToMount.Pod, v1.EventTypeWarning, kevents.VolumeResizeFailed, (*err).Error())
  1297. }
  1298. }
  1299. return volumetypes.GeneratedOperations{
  1300. OperationName: "volume_fs_resize",
  1301. OperationFunc: fsResizeFunc,
  1302. EventRecorderFunc: eventRecorderFunc,
  1303. CompleteFunc: util.OperationCompleteHook(util.GetFullQualifiedPluginNameForVolume(volumePlugin.GetPluginName(), volumeToMount.VolumeSpec), "volume_fs_resize"),
  1304. }, nil
  1305. }
  1306. func (og *operationGenerator) doOnlineExpansion(volumeToMount VolumeToMount,
  1307. actualStateOfWorld ActualStateOfWorldMounterUpdater,
  1308. resizeOptions volume.NodeResizeOptions) (bool, error, error) {
  1309. resizeDone, err := og.nodeExpandVolume(volumeToMount, resizeOptions)
  1310. if err != nil {
  1311. klog.Errorf("NodeExpandVolume.NodeExpandVolume failed : %v", err)
  1312. e1, e2 := volumeToMount.GenerateError("NodeExpandVolume.NodeExpandVolume failed", err)
  1313. return false, e1, e2
  1314. }
  1315. if resizeDone {
  1316. markFSResizedErr := actualStateOfWorld.MarkVolumeAsResized(volumeToMount.PodName, volumeToMount.VolumeName)
  1317. if markFSResizedErr != nil {
  1318. // On failure, return error. Caller will log and retry.
  1319. e1, e2 := volumeToMount.GenerateError("NodeExpandVolume.MarkVolumeAsResized failed", markFSResizedErr)
  1320. return false, e1, e2
  1321. }
  1322. return true, nil, nil
  1323. }
  1324. return false, nil, nil
  1325. }
  1326. func (og *operationGenerator) nodeExpandVolume(volumeToMount VolumeToMount, rsOpts volume.NodeResizeOptions) (bool, error) {
  1327. if !utilfeature.DefaultFeatureGate.Enabled(features.ExpandPersistentVolumes) {
  1328. klog.V(4).Infof("Resizing is not enabled for this volume %s", volumeToMount.VolumeName)
  1329. return true, nil
  1330. }
  1331. if volumeToMount.VolumeSpec != nil &&
  1332. volumeToMount.VolumeSpec.InlineVolumeSpecForCSIMigration {
  1333. klog.V(4).Infof("This volume %s is a migrated inline volume and is not resizable", volumeToMount.VolumeName)
  1334. return true, nil
  1335. }
  1336. // Get expander, if possible
  1337. expandableVolumePlugin, _ :=
  1338. og.volumePluginMgr.FindNodeExpandablePluginBySpec(volumeToMount.VolumeSpec)
  1339. if expandableVolumePlugin != nil &&
  1340. expandableVolumePlugin.RequiresFSResize() &&
  1341. volumeToMount.VolumeSpec.PersistentVolume != nil {
  1342. pv := volumeToMount.VolumeSpec.PersistentVolume
  1343. pvc, err := og.kubeClient.CoreV1().PersistentVolumeClaims(pv.Spec.ClaimRef.Namespace).Get(context.TODO(), pv.Spec.ClaimRef.Name, metav1.GetOptions{})
  1344. if err != nil {
  1345. // Return error rather than leave the file system un-resized, caller will log and retry
  1346. return false, fmt.Errorf("MountVolume.NodeExpandVolume get PVC failed : %v", err)
  1347. }
  1348. pvcStatusCap := pvc.Status.Capacity[v1.ResourceStorage]
  1349. pvSpecCap := pv.Spec.Capacity[v1.ResourceStorage]
  1350. if pvcStatusCap.Cmp(pvSpecCap) < 0 {
  1351. // File system resize was requested, proceed
  1352. klog.V(4).Infof(volumeToMount.GenerateMsgDetailed("MountVolume.NodeExpandVolume entering", fmt.Sprintf("DevicePath %q", volumeToMount.DevicePath)))
  1353. if volumeToMount.VolumeSpec.ReadOnly {
  1354. simpleMsg, detailedMsg := volumeToMount.GenerateMsg("MountVolume.NodeExpandVolume failed", "requested read-only file system")
  1355. klog.Warningf(detailedMsg)
  1356. og.recorder.Eventf(volumeToMount.Pod, v1.EventTypeWarning, kevents.FileSystemResizeFailed, simpleMsg)
  1357. og.recorder.Eventf(pvc, v1.EventTypeWarning, kevents.FileSystemResizeFailed, simpleMsg)
  1358. return true, nil
  1359. }
  1360. rsOpts.VolumeSpec = volumeToMount.VolumeSpec
  1361. rsOpts.NewSize = pvSpecCap
  1362. rsOpts.OldSize = pvcStatusCap
  1363. resizeDone, resizeErr := expandableVolumePlugin.NodeExpand(rsOpts)
  1364. if resizeErr != nil {
  1365. return false, fmt.Errorf("MountVolume.NodeExpandVolume failed : %v", resizeErr)
  1366. }
  1367. // Volume resizing is not done but it did not error out. This could happen if a CSI volume
  1368. // does not have node stage_unstage capability but was asked to resize the volume before
  1369. // node publish. In which case - we must retry resizing after node publish.
  1370. if !resizeDone {
  1371. return false, nil
  1372. }
  1373. simpleMsg, detailedMsg := volumeToMount.GenerateMsg("MountVolume.NodeExpandVolume succeeded", "")
  1374. og.recorder.Eventf(volumeToMount.Pod, v1.EventTypeNormal, kevents.FileSystemResizeSuccess, simpleMsg)
  1375. og.recorder.Eventf(pvc, v1.EventTypeNormal, kevents.FileSystemResizeSuccess, simpleMsg)
  1376. klog.Infof(detailedMsg)
  1377. // File system resize succeeded, now update the PVC's Capacity to match the PV's
  1378. err = util.MarkFSResizeFinished(pvc, pvSpecCap, og.kubeClient)
  1379. if err != nil {
  1380. // On retry, NodeExpandVolume will be called again but do nothing
  1381. return false, fmt.Errorf("MountVolume.NodeExpandVolume update PVC status failed : %v", err)
  1382. }
  1383. return true, nil
  1384. }
  1385. }
  1386. return true, nil
  1387. }
  1388. func checkMountOptionSupport(og *operationGenerator, volumeToMount VolumeToMount, plugin volume.VolumePlugin) error {
  1389. mountOptions := util.MountOptionFromSpec(volumeToMount.VolumeSpec)
  1390. if len(mountOptions) > 0 && !plugin.SupportsMountOption() {
  1391. return fmt.Errorf("Mount options are not supported for this volume type")
  1392. }
  1393. return nil
  1394. }
  1395. // checkNodeAffinity looks at the PV node affinity, and checks if the node has the same corresponding labels
  1396. // This ensures that we don't mount a volume that doesn't belong to this node
  1397. func checkNodeAffinity(og *operationGenerator, volumeToMount VolumeToMount) error {
  1398. pv := volumeToMount.VolumeSpec.PersistentVolume
  1399. if pv != nil {
  1400. nodeLabels, err := og.volumePluginMgr.Host.GetNodeLabels()
  1401. if err != nil {
  1402. return err
  1403. }
  1404. err = util.CheckNodeAffinity(pv, nodeLabels)
  1405. if err != nil {
  1406. return err
  1407. }
  1408. }
  1409. return nil
  1410. }
  1411. // isDeviceOpened checks the device status if the device is in use anywhere else on the system
  1412. func isDeviceOpened(deviceToDetach AttachedVolume, hostUtil hostutil.HostUtils) (bool, error) {
  1413. isDevicePath, devicePathErr := hostUtil.PathIsDevice(deviceToDetach.DevicePath)
  1414. var deviceOpened bool
  1415. var deviceOpenedErr error
  1416. if !isDevicePath && devicePathErr == nil ||
  1417. (devicePathErr != nil && strings.Contains(devicePathErr.Error(), "does not exist")) {
  1418. // not a device path or path doesn't exist
  1419. //TODO: refer to #36092
  1420. klog.V(3).Infof("The path isn't device path or doesn't exist. Skip checking device path: %s", deviceToDetach.DevicePath)
  1421. deviceOpened = false
  1422. } else if devicePathErr != nil {
  1423. return false, deviceToDetach.GenerateErrorDetailed("PathIsDevice failed", devicePathErr)
  1424. } else {
  1425. deviceOpened, deviceOpenedErr = hostUtil.DeviceOpened(deviceToDetach.DevicePath)
  1426. if deviceOpenedErr != nil {
  1427. return false, deviceToDetach.GenerateErrorDetailed("DeviceOpened failed", deviceOpenedErr)
  1428. }
  1429. }
  1430. return deviceOpened, nil
  1431. }