pv_controller.go 77 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792
  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 persistentvolume
  14. import (
  15. "context"
  16. "fmt"
  17. "reflect"
  18. "strings"
  19. "time"
  20. v1 "k8s.io/api/core/v1"
  21. storage "k8s.io/api/storage/v1"
  22. apierrors "k8s.io/apimachinery/pkg/api/errors"
  23. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  24. "k8s.io/apimachinery/pkg/labels"
  25. "k8s.io/apimachinery/pkg/util/sets"
  26. utilfeature "k8s.io/apiserver/pkg/util/feature"
  27. clientset "k8s.io/client-go/kubernetes"
  28. "k8s.io/client-go/kubernetes/scheme"
  29. corelisters "k8s.io/client-go/listers/core/v1"
  30. storagelisters "k8s.io/client-go/listers/storage/v1"
  31. "k8s.io/client-go/tools/cache"
  32. "k8s.io/client-go/tools/record"
  33. ref "k8s.io/client-go/tools/reference"
  34. "k8s.io/client-go/util/workqueue"
  35. cloudprovider "k8s.io/cloud-provider"
  36. volerr "k8s.io/cloud-provider/volume/errors"
  37. v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
  38. "k8s.io/kubernetes/pkg/controller/volume/events"
  39. "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/metrics"
  40. pvutil "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/util"
  41. "k8s.io/kubernetes/pkg/features"
  42. "k8s.io/kubernetes/pkg/util/goroutinemap"
  43. "k8s.io/kubernetes/pkg/util/goroutinemap/exponentialbackoff"
  44. vol "k8s.io/kubernetes/pkg/volume"
  45. "k8s.io/kubernetes/pkg/volume/util"
  46. "k8s.io/kubernetes/pkg/volume/util/recyclerclient"
  47. "k8s.io/klog"
  48. )
  49. // ==================================================================
  50. // PLEASE DO NOT ATTEMPT TO SIMPLIFY THIS CODE.
  51. // KEEP THE SPACE SHUTTLE FLYING.
  52. // ==================================================================
  53. //
  54. // This controller is intentionally written in a very verbose style. You will
  55. // notice:
  56. //
  57. // 1. Every 'if' statement has a matching 'else' (exception: simple error
  58. // checks for a client API call)
  59. // 2. Things that may seem obvious are commented explicitly
  60. //
  61. // We call this style 'space shuttle style'. Space shuttle style is meant to
  62. // ensure that every branch and condition is considered and accounted for -
  63. // the same way code is written at NASA for applications like the space
  64. // shuttle.
  65. //
  66. // Originally, the work of this controller was split amongst three
  67. // controllers. This controller is the result a large effort to simplify the
  68. // PV subsystem. During that effort, it became clear that we needed to ensure
  69. // that every single condition was handled and accounted for in the code, even
  70. // if it resulted in no-op code branches.
  71. //
  72. // As a result, the controller code may seem overly verbose, commented, and
  73. // 'branchy'. However, a large amount of business knowledge and context is
  74. // recorded here in order to ensure that future maintainers can correctly
  75. // reason through the complexities of the binding behavior. For that reason,
  76. // changes to this file should preserve and add to the space shuttle style.
  77. //
  78. // ==================================================================
  79. // PLEASE DO NOT ATTEMPT TO SIMPLIFY THIS CODE.
  80. // KEEP THE SPACE SHUTTLE FLYING.
  81. // ==================================================================
  82. // Design:
  83. //
  84. // The fundamental key to this design is the bi-directional "pointer" between
  85. // PersistentVolumes (PVs) and PersistentVolumeClaims (PVCs), which is
  86. // represented here as pvc.Spec.VolumeName and pv.Spec.ClaimRef. The bi-
  87. // directionality is complicated to manage in a transactionless system, but
  88. // without it we can't ensure sane behavior in the face of different forms of
  89. // trouble. For example, a rogue HA controller instance could end up racing
  90. // and making multiple bindings that are indistinguishable, resulting in
  91. // potential data loss.
  92. //
  93. // This controller is designed to work in active-passive high availability
  94. // mode. It *could* work also in active-active HA mode, all the object
  95. // transitions are designed to cope with this, however performance could be
  96. // lower as these two active controllers will step on each other toes
  97. // frequently.
  98. //
  99. // This controller supports pre-bound (by the creator) objects in both
  100. // directions: a PVC that wants a specific PV or a PV that is reserved for a
  101. // specific PVC.
  102. //
  103. // The binding is two-step process. PV.Spec.ClaimRef is modified first and
  104. // PVC.Spec.VolumeName second. At any point of this transaction, the PV or PVC
  105. // can be modified by user or other controller or completely deleted. Also,
  106. // two (or more) controllers may try to bind different volumes to different
  107. // claims at the same time. The controller must recover from any conflicts
  108. // that may arise from these conditions.
  109. // CloudVolumeCreatedForClaimNamespaceTag is a name of a tag attached to a real volume in cloud (e.g. AWS EBS or GCE PD)
  110. // with namespace of a persistent volume claim used to create this volume.
  111. const CloudVolumeCreatedForClaimNamespaceTag = "kubernetes.io/created-for/pvc/namespace"
  112. // CloudVolumeCreatedForClaimNameTag is a name of a tag attached to a real volume in cloud (e.g. AWS EBS or GCE PD)
  113. // with name of a persistent volume claim used to create this volume.
  114. const CloudVolumeCreatedForClaimNameTag = "kubernetes.io/created-for/pvc/name"
  115. // CloudVolumeCreatedForVolumeNameTag is a name of a tag attached to a real volume in cloud (e.g. AWS EBS or GCE PD)
  116. // with name of appropriate Kubernetes persistent volume .
  117. const CloudVolumeCreatedForVolumeNameTag = "kubernetes.io/created-for/pv/name"
  118. // Number of retries when we create a PV object for a provisioned volume.
  119. const createProvisionedPVRetryCount = 5
  120. // Interval between retries when we create a PV object for a provisioned volume.
  121. const createProvisionedPVInterval = 10 * time.Second
  122. // CSINameTranslator can get the CSI Driver name based on the in-tree plugin name
  123. type CSINameTranslator interface {
  124. GetCSINameFromInTreeName(pluginName string) (string, error)
  125. }
  126. // CSIMigratedPluginManager keeps track of CSI migration status of a plugin
  127. type CSIMigratedPluginManager interface {
  128. IsMigrationEnabledForPlugin(pluginName string) bool
  129. }
  130. // PersistentVolumeController is a controller that synchronizes
  131. // PersistentVolumeClaims and PersistentVolumes. It starts two
  132. // cache.Controllers that watch PersistentVolume and PersistentVolumeClaim
  133. // changes.
  134. type PersistentVolumeController struct {
  135. volumeLister corelisters.PersistentVolumeLister
  136. volumeListerSynced cache.InformerSynced
  137. claimLister corelisters.PersistentVolumeClaimLister
  138. claimListerSynced cache.InformerSynced
  139. classLister storagelisters.StorageClassLister
  140. classListerSynced cache.InformerSynced
  141. podLister corelisters.PodLister
  142. podListerSynced cache.InformerSynced
  143. NodeLister corelisters.NodeLister
  144. NodeListerSynced cache.InformerSynced
  145. kubeClient clientset.Interface
  146. eventRecorder record.EventRecorder
  147. cloud cloudprovider.Interface
  148. volumePluginMgr vol.VolumePluginMgr
  149. enableDynamicProvisioning bool
  150. clusterName string
  151. resyncPeriod time.Duration
  152. // Cache of the last known version of volumes and claims. This cache is
  153. // thread safe as long as the volumes/claims there are not modified, they
  154. // must be cloned before any modification. These caches get updated both by
  155. // "xxx added/updated/deleted" events from etcd and by the controller when
  156. // it saves newer version to etcd.
  157. // Why local cache: binding a volume to a claim generates 4 events, roughly
  158. // in this order (depends on goroutine ordering):
  159. // - volume.Spec update
  160. // - volume.Status update
  161. // - claim.Spec update
  162. // - claim.Status update
  163. // With these caches, the controller can check that it has already saved
  164. // volume.Status and claim.Spec+Status and does not need to do anything
  165. // when e.g. volume.Spec update event arrives before all the other events.
  166. // Without this cache, it would see the old version of volume.Status and
  167. // claim in the informers (it has not been updated from API server events
  168. // yet) and it would try to fix these objects to be bound together.
  169. // Any write to API server would fail with version conflict - these objects
  170. // have been already written.
  171. volumes persistentVolumeOrderedIndex
  172. claims cache.Store
  173. // Work queues of claims and volumes to process. Every queue should have
  174. // exactly one worker thread, especially syncClaim() is not reentrant.
  175. // Two syncClaims could bind two different claims to the same volume or one
  176. // claim to two volumes. The controller would recover from this (due to
  177. // version errors in API server and other checks in this controller),
  178. // however overall speed of multi-worker controller would be lower than if
  179. // it runs single thread only.
  180. claimQueue *workqueue.Type
  181. volumeQueue *workqueue.Type
  182. // Map of scheduled/running operations.
  183. runningOperations goroutinemap.GoRoutineMap
  184. // For testing only: hook to call before an asynchronous operation starts.
  185. // Not used when set to nil.
  186. preOperationHook func(operationName string)
  187. createProvisionedPVRetryCount int
  188. createProvisionedPVInterval time.Duration
  189. // operationTimestamps caches start timestamp of operations
  190. // (currently provision + binding/deletion) for metric recording.
  191. // Detailed lifecycle/key for each operation
  192. // 1. provision + binding
  193. // key: claimKey
  194. // start time: user has NOT provide any volume ref in the claim AND
  195. // there is no existing volume found for the claim,
  196. // "provisionClaim" is called with a valid plugin/external provisioner
  197. // to provision a volume
  198. // end time: after a volume has been provisioned and bound to the claim successfully
  199. // the corresponding timestamp entry will be deleted from cache
  200. // abort: claim has not been bound to a volume yet but a claim deleted event
  201. // has been received from API server
  202. // 2. deletion
  203. // key: volumeName
  204. // start time: when "reclaimVolume" process a volume with reclaim policy
  205. // set to be "PersistentVolumeReclaimDelete"
  206. // end time: after a volume deleted event has been received from API server
  207. // the corresponding timestamp entry will be deleted from cache
  208. // abort: N.A.
  209. operationTimestamps metrics.OperationStartTimeCache
  210. translator CSINameTranslator
  211. csiMigratedPluginManager CSIMigratedPluginManager
  212. }
  213. // syncClaim is the main controller method to decide what to do with a claim.
  214. // It's invoked by appropriate cache.Controller callbacks when a claim is
  215. // created, updated or periodically synced. We do not differentiate between
  216. // these events.
  217. // For easier readability, it was split into syncUnboundClaim and syncBoundClaim
  218. // methods.
  219. func (ctrl *PersistentVolumeController) syncClaim(claim *v1.PersistentVolumeClaim) error {
  220. klog.V(4).Infof("synchronizing PersistentVolumeClaim[%s]: %s", claimToClaimKey(claim), getClaimStatusForLogging(claim))
  221. // Set correct "migrated-to" annotations on PVC and update in API server if
  222. // necessary
  223. newClaim, err := ctrl.updateClaimMigrationAnnotations(claim)
  224. if err != nil {
  225. // Nothing was saved; we will fall back into the same
  226. // condition in the next call to this method
  227. return err
  228. }
  229. claim = newClaim
  230. if !metav1.HasAnnotation(claim.ObjectMeta, pvutil.AnnBindCompleted) {
  231. return ctrl.syncUnboundClaim(claim)
  232. } else {
  233. return ctrl.syncBoundClaim(claim)
  234. }
  235. }
  236. // checkVolumeSatisfyClaim checks if the volume requested by the claim satisfies the requirements of the claim
  237. func checkVolumeSatisfyClaim(volume *v1.PersistentVolume, claim *v1.PersistentVolumeClaim) error {
  238. requestedQty := claim.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)]
  239. requestedSize := requestedQty.Value()
  240. // check if PV's DeletionTimeStamp is set, if so, return error.
  241. if utilfeature.DefaultFeatureGate.Enabled(features.StorageObjectInUseProtection) {
  242. if volume.ObjectMeta.DeletionTimestamp != nil {
  243. return fmt.Errorf("the volume is marked for deletion %q", volume.Name)
  244. }
  245. }
  246. volumeQty := volume.Spec.Capacity[v1.ResourceStorage]
  247. volumeSize := volumeQty.Value()
  248. if volumeSize < requestedSize {
  249. return fmt.Errorf("requested PV is too small")
  250. }
  251. requestedClass := v1helper.GetPersistentVolumeClaimClass(claim)
  252. if v1helper.GetPersistentVolumeClass(volume) != requestedClass {
  253. return fmt.Errorf("storageClassName does not match")
  254. }
  255. if pvutil.CheckVolumeModeMismatches(&claim.Spec, &volume.Spec) {
  256. return fmt.Errorf("incompatible volumeMode")
  257. }
  258. if !pvutil.CheckAccessModes(claim, volume) {
  259. return fmt.Errorf("incompatible accessMode")
  260. }
  261. return nil
  262. }
  263. // syncUnboundClaim is the main controller method to decide what to do with an
  264. // unbound claim.
  265. func (ctrl *PersistentVolumeController) syncUnboundClaim(claim *v1.PersistentVolumeClaim) error {
  266. // This is a new PVC that has not completed binding
  267. // OBSERVATION: pvc is "Pending"
  268. if claim.Spec.VolumeName == "" {
  269. // User did not care which PV they get.
  270. delayBinding, err := pvutil.IsDelayBindingMode(claim, ctrl.classLister)
  271. if err != nil {
  272. return err
  273. }
  274. // [Unit test set 1]
  275. volume, err := ctrl.volumes.findBestMatchForClaim(claim, delayBinding)
  276. if err != nil {
  277. klog.V(2).Infof("synchronizing unbound PersistentVolumeClaim[%s]: Error finding PV for claim: %v", claimToClaimKey(claim), err)
  278. return fmt.Errorf("Error finding PV for claim %q: %v", claimToClaimKey(claim), err)
  279. }
  280. if volume == nil {
  281. klog.V(4).Infof("synchronizing unbound PersistentVolumeClaim[%s]: no volume found", claimToClaimKey(claim))
  282. // No PV could be found
  283. // OBSERVATION: pvc is "Pending", will retry
  284. switch {
  285. case delayBinding && !pvutil.IsDelayBindingProvisioning(claim):
  286. ctrl.eventRecorder.Event(claim, v1.EventTypeNormal, events.WaitForFirstConsumer, "waiting for first consumer to be created before binding")
  287. case v1helper.GetPersistentVolumeClaimClass(claim) != "":
  288. if err = ctrl.provisionClaim(claim); err != nil {
  289. return err
  290. }
  291. return nil
  292. default:
  293. ctrl.eventRecorder.Event(claim, v1.EventTypeNormal, events.FailedBinding, "no persistent volumes available for this claim and no storage class is set")
  294. }
  295. // Mark the claim as Pending and try to find a match in the next
  296. // periodic syncClaim
  297. if _, err = ctrl.updateClaimStatus(claim, v1.ClaimPending, nil); err != nil {
  298. return err
  299. }
  300. return nil
  301. } else /* pv != nil */ {
  302. // Found a PV for this claim
  303. // OBSERVATION: pvc is "Pending", pv is "Available"
  304. claimKey := claimToClaimKey(claim)
  305. klog.V(4).Infof("synchronizing unbound PersistentVolumeClaim[%s]: volume %q found: %s", claimKey, volume.Name, getVolumeStatusForLogging(volume))
  306. if err = ctrl.bind(volume, claim); err != nil {
  307. // On any error saving the volume or the claim, subsequent
  308. // syncClaim will finish the binding.
  309. // record count error for provision if exists
  310. // timestamp entry will remain in cache until a success binding has happened
  311. metrics.RecordMetric(claimKey, &ctrl.operationTimestamps, err)
  312. return err
  313. }
  314. // OBSERVATION: claim is "Bound", pv is "Bound"
  315. // if exists a timestamp entry in cache, record end to end provision latency and clean up cache
  316. // End of the provision + binding operation lifecycle, cache will be cleaned by "RecordMetric"
  317. // [Unit test 12-1, 12-2, 12-4]
  318. metrics.RecordMetric(claimKey, &ctrl.operationTimestamps, nil)
  319. return nil
  320. }
  321. } else /* pvc.Spec.VolumeName != nil */ {
  322. // [Unit test set 2]
  323. // User asked for a specific PV.
  324. klog.V(4).Infof("synchronizing unbound PersistentVolumeClaim[%s]: volume %q requested", claimToClaimKey(claim), claim.Spec.VolumeName)
  325. obj, found, err := ctrl.volumes.store.GetByKey(claim.Spec.VolumeName)
  326. if err != nil {
  327. return err
  328. }
  329. if !found {
  330. // User asked for a PV that does not exist.
  331. // OBSERVATION: pvc is "Pending"
  332. // Retry later.
  333. klog.V(4).Infof("synchronizing unbound PersistentVolumeClaim[%s]: volume %q requested and not found, will try again next time", claimToClaimKey(claim), claim.Spec.VolumeName)
  334. if _, err = ctrl.updateClaimStatus(claim, v1.ClaimPending, nil); err != nil {
  335. return err
  336. }
  337. return nil
  338. } else {
  339. volume, ok := obj.(*v1.PersistentVolume)
  340. if !ok {
  341. return fmt.Errorf("Cannot convert object from volume cache to volume %q!?: %+v", claim.Spec.VolumeName, obj)
  342. }
  343. klog.V(4).Infof("synchronizing unbound PersistentVolumeClaim[%s]: volume %q requested and found: %s", claimToClaimKey(claim), claim.Spec.VolumeName, getVolumeStatusForLogging(volume))
  344. if volume.Spec.ClaimRef == nil {
  345. // User asked for a PV that is not claimed
  346. // OBSERVATION: pvc is "Pending", pv is "Available"
  347. klog.V(4).Infof("synchronizing unbound PersistentVolumeClaim[%s]: volume is unbound, binding", claimToClaimKey(claim))
  348. if err = checkVolumeSatisfyClaim(volume, claim); err != nil {
  349. klog.V(4).Infof("Can't bind the claim to volume %q: %v", volume.Name, err)
  350. // send an event
  351. msg := fmt.Sprintf("Cannot bind to requested volume %q: %s", volume.Name, err)
  352. ctrl.eventRecorder.Event(claim, v1.EventTypeWarning, events.VolumeMismatch, msg)
  353. // volume does not satisfy the requirements of the claim
  354. if _, err = ctrl.updateClaimStatus(claim, v1.ClaimPending, nil); err != nil {
  355. return err
  356. }
  357. } else if err = ctrl.bind(volume, claim); err != nil {
  358. // On any error saving the volume or the claim, subsequent
  359. // syncClaim will finish the binding.
  360. return err
  361. }
  362. // OBSERVATION: pvc is "Bound", pv is "Bound"
  363. return nil
  364. } else if pvutil.IsVolumeBoundToClaim(volume, claim) {
  365. // User asked for a PV that is claimed by this PVC
  366. // OBSERVATION: pvc is "Pending", pv is "Bound"
  367. klog.V(4).Infof("synchronizing unbound PersistentVolumeClaim[%s]: volume already bound, finishing the binding", claimToClaimKey(claim))
  368. // Finish the volume binding by adding claim UID.
  369. if err = ctrl.bind(volume, claim); err != nil {
  370. return err
  371. }
  372. // OBSERVATION: pvc is "Bound", pv is "Bound"
  373. return nil
  374. } else {
  375. // User asked for a PV that is claimed by someone else
  376. // OBSERVATION: pvc is "Pending", pv is "Bound"
  377. if !metav1.HasAnnotation(claim.ObjectMeta, pvutil.AnnBoundByController) {
  378. klog.V(4).Infof("synchronizing unbound PersistentVolumeClaim[%s]: volume already bound to different claim by user, will retry later", claimToClaimKey(claim))
  379. // User asked for a specific PV, retry later
  380. if _, err = ctrl.updateClaimStatus(claim, v1.ClaimPending, nil); err != nil {
  381. return err
  382. }
  383. return nil
  384. } else {
  385. // This should never happen because someone had to remove
  386. // AnnBindCompleted annotation on the claim.
  387. klog.V(4).Infof("synchronizing unbound PersistentVolumeClaim[%s]: volume already bound to different claim %q by controller, THIS SHOULD NEVER HAPPEN", claimToClaimKey(claim), claimrefToClaimKey(volume.Spec.ClaimRef))
  388. return fmt.Errorf("Invalid binding of claim %q to volume %q: volume already claimed by %q", claimToClaimKey(claim), claim.Spec.VolumeName, claimrefToClaimKey(volume.Spec.ClaimRef))
  389. }
  390. }
  391. }
  392. }
  393. }
  394. // syncBoundClaim is the main controller method to decide what to do with a
  395. // bound claim.
  396. func (ctrl *PersistentVolumeController) syncBoundClaim(claim *v1.PersistentVolumeClaim) error {
  397. // HasAnnotation(pvc, pvutil.AnnBindCompleted)
  398. // This PVC has previously been bound
  399. // OBSERVATION: pvc is not "Pending"
  400. // [Unit test set 3]
  401. if claim.Spec.VolumeName == "" {
  402. // Claim was bound before but not any more.
  403. if _, err := ctrl.updateClaimStatusWithEvent(claim, v1.ClaimLost, nil, v1.EventTypeWarning, "ClaimLost", "Bound claim has lost reference to PersistentVolume. Data on the volume is lost!"); err != nil {
  404. return err
  405. }
  406. return nil
  407. }
  408. obj, found, err := ctrl.volumes.store.GetByKey(claim.Spec.VolumeName)
  409. if err != nil {
  410. return err
  411. }
  412. if !found {
  413. // Claim is bound to a non-existing volume.
  414. if _, err = ctrl.updateClaimStatusWithEvent(claim, v1.ClaimLost, nil, v1.EventTypeWarning, "ClaimLost", "Bound claim has lost its PersistentVolume. Data on the volume is lost!"); err != nil {
  415. return err
  416. }
  417. return nil
  418. } else {
  419. volume, ok := obj.(*v1.PersistentVolume)
  420. if !ok {
  421. return fmt.Errorf("Cannot convert object from volume cache to volume %q!?: %#v", claim.Spec.VolumeName, obj)
  422. }
  423. klog.V(4).Infof("synchronizing bound PersistentVolumeClaim[%s]: volume %q found: %s", claimToClaimKey(claim), claim.Spec.VolumeName, getVolumeStatusForLogging(volume))
  424. if volume.Spec.ClaimRef == nil {
  425. // Claim is bound but volume has come unbound.
  426. // Or, a claim was bound and the controller has not received updated
  427. // volume yet. We can't distinguish these cases.
  428. // Bind the volume again and set all states to Bound.
  429. klog.V(4).Infof("synchronizing bound PersistentVolumeClaim[%s]: volume is unbound, fixing", claimToClaimKey(claim))
  430. if err = ctrl.bind(volume, claim); err != nil {
  431. // Objects not saved, next syncPV or syncClaim will try again
  432. return err
  433. }
  434. return nil
  435. } else if volume.Spec.ClaimRef.UID == claim.UID {
  436. // All is well
  437. // NOTE: syncPV can handle this so it can be left out.
  438. // NOTE: bind() call here will do nothing in most cases as
  439. // everything should be already set.
  440. klog.V(4).Infof("synchronizing bound PersistentVolumeClaim[%s]: claim is already correctly bound", claimToClaimKey(claim))
  441. if err = ctrl.bind(volume, claim); err != nil {
  442. // Objects not saved, next syncPV or syncClaim will try again
  443. return err
  444. }
  445. return nil
  446. } else {
  447. // Claim is bound but volume has a different claimant.
  448. // Set the claim phase to 'Lost', which is a terminal
  449. // phase.
  450. if _, err = ctrl.updateClaimStatusWithEvent(claim, v1.ClaimLost, nil, v1.EventTypeWarning, "ClaimMisbound", "Two claims are bound to the same volume, this one is bound incorrectly"); err != nil {
  451. return err
  452. }
  453. return nil
  454. }
  455. }
  456. }
  457. // syncVolume is the main controller method to decide what to do with a volume.
  458. // It's invoked by appropriate cache.Controller callbacks when a volume is
  459. // created, updated or periodically synced. We do not differentiate between
  460. // these events.
  461. func (ctrl *PersistentVolumeController) syncVolume(volume *v1.PersistentVolume) error {
  462. klog.V(4).Infof("synchronizing PersistentVolume[%s]: %s", volume.Name, getVolumeStatusForLogging(volume))
  463. // Set correct "migrated-to" annotations on PV and update in API server if
  464. // necessary
  465. newVolume, err := ctrl.updateVolumeMigrationAnnotations(volume)
  466. if err != nil {
  467. // Nothing was saved; we will fall back into the same
  468. // condition in the next call to this method
  469. return err
  470. }
  471. volume = newVolume
  472. // [Unit test set 4]
  473. if volume.Spec.ClaimRef == nil {
  474. // Volume is unused
  475. klog.V(4).Infof("synchronizing PersistentVolume[%s]: volume is unused", volume.Name)
  476. if _, err := ctrl.updateVolumePhase(volume, v1.VolumeAvailable, ""); err != nil {
  477. // Nothing was saved; we will fall back into the same
  478. // condition in the next call to this method
  479. return err
  480. }
  481. return nil
  482. } else /* pv.Spec.ClaimRef != nil */ {
  483. // Volume is bound to a claim.
  484. if volume.Spec.ClaimRef.UID == "" {
  485. // The PV is reserved for a PVC; that PVC has not yet been
  486. // bound to this PV; the PVC sync will handle it.
  487. klog.V(4).Infof("synchronizing PersistentVolume[%s]: volume is pre-bound to claim %s", volume.Name, claimrefToClaimKey(volume.Spec.ClaimRef))
  488. if _, err := ctrl.updateVolumePhase(volume, v1.VolumeAvailable, ""); err != nil {
  489. // Nothing was saved; we will fall back into the same
  490. // condition in the next call to this method
  491. return err
  492. }
  493. return nil
  494. }
  495. klog.V(4).Infof("synchronizing PersistentVolume[%s]: volume is bound to claim %s", volume.Name, claimrefToClaimKey(volume.Spec.ClaimRef))
  496. // Get the PVC by _name_
  497. var claim *v1.PersistentVolumeClaim
  498. claimName := claimrefToClaimKey(volume.Spec.ClaimRef)
  499. obj, found, err := ctrl.claims.GetByKey(claimName)
  500. if err != nil {
  501. return err
  502. }
  503. if !found && metav1.HasAnnotation(volume.ObjectMeta, pvutil.AnnBoundByController) {
  504. // If PV is bound by external PV binder (e.g. kube-scheduler), it's
  505. // possible on heavy load that corresponding PVC is not synced to
  506. // controller local cache yet. So we need to double-check PVC in
  507. // 1) informer cache
  508. // 2) apiserver if not found in informer cache
  509. // to make sure we will not reclaim a PV wrongly.
  510. // Note that only non-released and non-failed volumes will be
  511. // updated to Released state when PVC does not exist.
  512. if volume.Status.Phase != v1.VolumeReleased && volume.Status.Phase != v1.VolumeFailed {
  513. obj, err = ctrl.claimLister.PersistentVolumeClaims(volume.Spec.ClaimRef.Namespace).Get(volume.Spec.ClaimRef.Name)
  514. if err != nil && !apierrors.IsNotFound(err) {
  515. return err
  516. }
  517. found = !apierrors.IsNotFound(err)
  518. if !found {
  519. obj, err = ctrl.kubeClient.CoreV1().PersistentVolumeClaims(volume.Spec.ClaimRef.Namespace).Get(context.TODO(), volume.Spec.ClaimRef.Name, metav1.GetOptions{})
  520. if err != nil && !apierrors.IsNotFound(err) {
  521. return err
  522. }
  523. found = !apierrors.IsNotFound(err)
  524. }
  525. }
  526. }
  527. if !found {
  528. klog.V(4).Infof("synchronizing PersistentVolume[%s]: claim %s not found", volume.Name, claimrefToClaimKey(volume.Spec.ClaimRef))
  529. // Fall through with claim = nil
  530. } else {
  531. var ok bool
  532. claim, ok = obj.(*v1.PersistentVolumeClaim)
  533. if !ok {
  534. return fmt.Errorf("Cannot convert object from volume cache to volume %q!?: %#v", claim.Spec.VolumeName, obj)
  535. }
  536. klog.V(4).Infof("synchronizing PersistentVolume[%s]: claim %s found: %s", volume.Name, claimrefToClaimKey(volume.Spec.ClaimRef), getClaimStatusForLogging(claim))
  537. }
  538. if claim != nil && claim.UID != volume.Spec.ClaimRef.UID {
  539. // The claim that the PV was pointing to was deleted, and another
  540. // with the same name created.
  541. klog.V(4).Infof("synchronizing PersistentVolume[%s]: claim %s has different UID, the old one must have been deleted", volume.Name, claimrefToClaimKey(volume.Spec.ClaimRef))
  542. // Treat the volume as bound to a missing claim.
  543. claim = nil
  544. }
  545. if claim == nil {
  546. // If we get into this block, the claim must have been deleted;
  547. // NOTE: reclaimVolume may either release the PV back into the pool or
  548. // recycle it or do nothing (retain)
  549. // Do not overwrite previous Failed state - let the user see that
  550. // something went wrong, while we still re-try to reclaim the
  551. // volume.
  552. if volume.Status.Phase != v1.VolumeReleased && volume.Status.Phase != v1.VolumeFailed {
  553. // Also, log this only once:
  554. klog.V(2).Infof("volume %q is released and reclaim policy %q will be executed", volume.Name, volume.Spec.PersistentVolumeReclaimPolicy)
  555. if volume, err = ctrl.updateVolumePhase(volume, v1.VolumeReleased, ""); err != nil {
  556. // Nothing was saved; we will fall back into the same condition
  557. // in the next call to this method
  558. return err
  559. }
  560. }
  561. if err = ctrl.reclaimVolume(volume); err != nil {
  562. // Release failed, we will fall back into the same condition
  563. // in the next call to this method
  564. return err
  565. }
  566. return nil
  567. } else if claim.Spec.VolumeName == "" {
  568. if pvutil.CheckVolumeModeMismatches(&claim.Spec, &volume.Spec) {
  569. // Binding for the volume won't be called in syncUnboundClaim,
  570. // because findBestMatchForClaim won't return the volume due to volumeMode mismatch.
  571. volumeMsg := fmt.Sprintf("Cannot bind PersistentVolume to requested PersistentVolumeClaim %q due to incompatible volumeMode.", claim.Name)
  572. ctrl.eventRecorder.Event(volume, v1.EventTypeWarning, events.VolumeMismatch, volumeMsg)
  573. claimMsg := fmt.Sprintf("Cannot bind PersistentVolume %q to requested PersistentVolumeClaim due to incompatible volumeMode.", volume.Name)
  574. ctrl.eventRecorder.Event(claim, v1.EventTypeWarning, events.VolumeMismatch, claimMsg)
  575. // Skipping syncClaim
  576. return nil
  577. }
  578. if metav1.HasAnnotation(volume.ObjectMeta, pvutil.AnnBoundByController) {
  579. // The binding is not completed; let PVC sync handle it
  580. klog.V(4).Infof("synchronizing PersistentVolume[%s]: volume not bound yet, waiting for syncClaim to fix it", volume.Name)
  581. } else {
  582. // Dangling PV; try to re-establish the link in the PVC sync
  583. klog.V(4).Infof("synchronizing PersistentVolume[%s]: volume was bound and got unbound (by user?), waiting for syncClaim to fix it", volume.Name)
  584. }
  585. // In both cases, the volume is Bound and the claim is Pending.
  586. // Next syncClaim will fix it. To speed it up, we enqueue the claim
  587. // into the controller, which results in syncClaim to be called
  588. // shortly (and in the right worker goroutine).
  589. // This speeds up binding of provisioned volumes - provisioner saves
  590. // only the new PV and it expects that next syncClaim will bind the
  591. // claim to it.
  592. ctrl.claimQueue.Add(claimToClaimKey(claim))
  593. return nil
  594. } else if claim.Spec.VolumeName == volume.Name {
  595. // Volume is bound to a claim properly, update status if necessary
  596. klog.V(4).Infof("synchronizing PersistentVolume[%s]: all is bound", volume.Name)
  597. if _, err = ctrl.updateVolumePhase(volume, v1.VolumeBound, ""); err != nil {
  598. // Nothing was saved; we will fall back into the same
  599. // condition in the next call to this method
  600. return err
  601. }
  602. return nil
  603. } else {
  604. // Volume is bound to a claim, but the claim is bound elsewhere
  605. if metav1.HasAnnotation(volume.ObjectMeta, pvutil.AnnDynamicallyProvisioned) && volume.Spec.PersistentVolumeReclaimPolicy == v1.PersistentVolumeReclaimDelete {
  606. // This volume was dynamically provisioned for this claim. The
  607. // claim got bound elsewhere, and thus this volume is not
  608. // needed. Delete it.
  609. // Mark the volume as Released for external deleters and to let
  610. // the user know. Don't overwrite existing Failed status!
  611. if volume.Status.Phase != v1.VolumeReleased && volume.Status.Phase != v1.VolumeFailed {
  612. // Also, log this only once:
  613. klog.V(2).Infof("dynamically volume %q is released and it will be deleted", volume.Name)
  614. if volume, err = ctrl.updateVolumePhase(volume, v1.VolumeReleased, ""); err != nil {
  615. // Nothing was saved; we will fall back into the same condition
  616. // in the next call to this method
  617. return err
  618. }
  619. }
  620. if err = ctrl.reclaimVolume(volume); err != nil {
  621. // Deletion failed, we will fall back into the same condition
  622. // in the next call to this method
  623. return err
  624. }
  625. return nil
  626. } else {
  627. // Volume is bound to a claim, but the claim is bound elsewhere
  628. // and it's not dynamically provisioned.
  629. if metav1.HasAnnotation(volume.ObjectMeta, pvutil.AnnBoundByController) {
  630. // This is part of the normal operation of the controller; the
  631. // controller tried to use this volume for a claim but the claim
  632. // was fulfilled by another volume. We did this; fix it.
  633. klog.V(4).Infof("synchronizing PersistentVolume[%s]: volume is bound by controller to a claim that is bound to another volume, unbinding", volume.Name)
  634. if err = ctrl.unbindVolume(volume); err != nil {
  635. return err
  636. }
  637. return nil
  638. } else {
  639. // The PV must have been created with this ptr; leave it alone.
  640. klog.V(4).Infof("synchronizing PersistentVolume[%s]: volume is bound by user to a claim that is bound to another volume, waiting for the claim to get unbound", volume.Name)
  641. // This just updates the volume phase and clears
  642. // volume.Spec.ClaimRef.UID. It leaves the volume pre-bound
  643. // to the claim.
  644. if err = ctrl.unbindVolume(volume); err != nil {
  645. return err
  646. }
  647. return nil
  648. }
  649. }
  650. }
  651. }
  652. }
  653. // updateClaimStatus saves new claim.Status to API server.
  654. // Parameters:
  655. // claim - claim to update
  656. // phase - phase to set
  657. // volume - volume which Capacity is set into claim.Status.Capacity
  658. func (ctrl *PersistentVolumeController) updateClaimStatus(claim *v1.PersistentVolumeClaim, phase v1.PersistentVolumeClaimPhase, volume *v1.PersistentVolume) (*v1.PersistentVolumeClaim, error) {
  659. klog.V(4).Infof("updating PersistentVolumeClaim[%s] status: set phase %s", claimToClaimKey(claim), phase)
  660. dirty := false
  661. claimClone := claim.DeepCopy()
  662. if claim.Status.Phase != phase {
  663. claimClone.Status.Phase = phase
  664. dirty = true
  665. }
  666. if volume == nil {
  667. // Need to reset AccessModes and Capacity
  668. if claim.Status.AccessModes != nil {
  669. claimClone.Status.AccessModes = nil
  670. dirty = true
  671. }
  672. if claim.Status.Capacity != nil {
  673. claimClone.Status.Capacity = nil
  674. dirty = true
  675. }
  676. } else {
  677. // Need to update AccessModes and Capacity
  678. if !reflect.DeepEqual(claim.Status.AccessModes, volume.Spec.AccessModes) {
  679. claimClone.Status.AccessModes = volume.Spec.AccessModes
  680. dirty = true
  681. }
  682. // Update Capacity if the claim is becoming Bound, not if it was already.
  683. // A discrepancy can be intentional to mean that the PVC filesystem size
  684. // doesn't match the PV block device size, so don't clobber it
  685. if claim.Status.Phase != phase {
  686. volumeCap, ok := volume.Spec.Capacity[v1.ResourceStorage]
  687. if !ok {
  688. return nil, fmt.Errorf("PersistentVolume %q is without a storage capacity", volume.Name)
  689. }
  690. claimCap, ok := claim.Status.Capacity[v1.ResourceStorage]
  691. if !ok || volumeCap.Cmp(claimCap) != 0 {
  692. claimClone.Status.Capacity = volume.Spec.Capacity
  693. dirty = true
  694. }
  695. }
  696. }
  697. if !dirty {
  698. // Nothing to do.
  699. klog.V(4).Infof("updating PersistentVolumeClaim[%s] status: phase %s already set", claimToClaimKey(claim), phase)
  700. return claim, nil
  701. }
  702. newClaim, err := ctrl.kubeClient.CoreV1().PersistentVolumeClaims(claimClone.Namespace).UpdateStatus(context.TODO(), claimClone, metav1.UpdateOptions{})
  703. if err != nil {
  704. klog.V(4).Infof("updating PersistentVolumeClaim[%s] status: set phase %s failed: %v", claimToClaimKey(claim), phase, err)
  705. return newClaim, err
  706. }
  707. _, err = ctrl.storeClaimUpdate(newClaim)
  708. if err != nil {
  709. klog.V(4).Infof("updating PersistentVolumeClaim[%s] status: cannot update internal cache: %v", claimToClaimKey(claim), err)
  710. return newClaim, err
  711. }
  712. klog.V(2).Infof("claim %q entered phase %q", claimToClaimKey(claim), phase)
  713. return newClaim, nil
  714. }
  715. // updateClaimStatusWithEvent saves new claim.Status to API server and emits
  716. // given event on the claim. It saves the status and emits the event only when
  717. // the status has actually changed from the version saved in API server.
  718. // Parameters:
  719. // claim - claim to update
  720. // phase - phase to set
  721. // volume - volume which Capacity is set into claim.Status.Capacity
  722. // eventtype, reason, message - event to send, see EventRecorder.Event()
  723. func (ctrl *PersistentVolumeController) updateClaimStatusWithEvent(claim *v1.PersistentVolumeClaim, phase v1.PersistentVolumeClaimPhase, volume *v1.PersistentVolume, eventtype, reason, message string) (*v1.PersistentVolumeClaim, error) {
  724. klog.V(4).Infof("updating updateClaimStatusWithEvent[%s]: set phase %s", claimToClaimKey(claim), phase)
  725. if claim.Status.Phase == phase {
  726. // Nothing to do.
  727. klog.V(4).Infof("updating updateClaimStatusWithEvent[%s]: phase %s already set", claimToClaimKey(claim), phase)
  728. return claim, nil
  729. }
  730. newClaim, err := ctrl.updateClaimStatus(claim, phase, volume)
  731. if err != nil {
  732. return nil, err
  733. }
  734. // Emit the event only when the status change happens, not every time
  735. // syncClaim is called.
  736. klog.V(3).Infof("claim %q changed status to %q: %s", claimToClaimKey(claim), phase, message)
  737. ctrl.eventRecorder.Event(newClaim, eventtype, reason, message)
  738. return newClaim, nil
  739. }
  740. // updateVolumePhase saves new volume phase to API server.
  741. func (ctrl *PersistentVolumeController) updateVolumePhase(volume *v1.PersistentVolume, phase v1.PersistentVolumePhase, message string) (*v1.PersistentVolume, error) {
  742. klog.V(4).Infof("updating PersistentVolume[%s]: set phase %s", volume.Name, phase)
  743. if volume.Status.Phase == phase {
  744. // Nothing to do.
  745. klog.V(4).Infof("updating PersistentVolume[%s]: phase %s already set", volume.Name, phase)
  746. return volume, nil
  747. }
  748. volumeClone := volume.DeepCopy()
  749. volumeClone.Status.Phase = phase
  750. volumeClone.Status.Message = message
  751. newVol, err := ctrl.kubeClient.CoreV1().PersistentVolumes().UpdateStatus(context.TODO(), volumeClone, metav1.UpdateOptions{})
  752. if err != nil {
  753. klog.V(4).Infof("updating PersistentVolume[%s]: set phase %s failed: %v", volume.Name, phase, err)
  754. return newVol, err
  755. }
  756. _, err = ctrl.storeVolumeUpdate(newVol)
  757. if err != nil {
  758. klog.V(4).Infof("updating PersistentVolume[%s]: cannot update internal cache: %v", volume.Name, err)
  759. return newVol, err
  760. }
  761. klog.V(2).Infof("volume %q entered phase %q", volume.Name, phase)
  762. return newVol, err
  763. }
  764. // updateVolumePhaseWithEvent saves new volume phase to API server and emits
  765. // given event on the volume. It saves the phase and emits the event only when
  766. // the phase has actually changed from the version saved in API server.
  767. func (ctrl *PersistentVolumeController) updateVolumePhaseWithEvent(volume *v1.PersistentVolume, phase v1.PersistentVolumePhase, eventtype, reason, message string) (*v1.PersistentVolume, error) {
  768. klog.V(4).Infof("updating updateVolumePhaseWithEvent[%s]: set phase %s", volume.Name, phase)
  769. if volume.Status.Phase == phase {
  770. // Nothing to do.
  771. klog.V(4).Infof("updating updateVolumePhaseWithEvent[%s]: phase %s already set", volume.Name, phase)
  772. return volume, nil
  773. }
  774. newVol, err := ctrl.updateVolumePhase(volume, phase, message)
  775. if err != nil {
  776. return nil, err
  777. }
  778. // Emit the event only when the status change happens, not every time
  779. // syncClaim is called.
  780. klog.V(3).Infof("volume %q changed status to %q: %s", volume.Name, phase, message)
  781. ctrl.eventRecorder.Event(newVol, eventtype, reason, message)
  782. return newVol, nil
  783. }
  784. // bindVolumeToClaim modifies given volume to be bound to a claim and saves it to
  785. // API server. The claim is not modified in this method!
  786. func (ctrl *PersistentVolumeController) bindVolumeToClaim(volume *v1.PersistentVolume, claim *v1.PersistentVolumeClaim) (*v1.PersistentVolume, error) {
  787. klog.V(4).Infof("updating PersistentVolume[%s]: binding to %q", volume.Name, claimToClaimKey(claim))
  788. volumeClone, dirty, err := pvutil.GetBindVolumeToClaim(volume, claim)
  789. if err != nil {
  790. return nil, err
  791. }
  792. // Save the volume only if something was changed
  793. if dirty {
  794. return ctrl.updateBindVolumeToClaim(volumeClone, true)
  795. }
  796. klog.V(4).Infof("updating PersistentVolume[%s]: already bound to %q", volume.Name, claimToClaimKey(claim))
  797. return volume, nil
  798. }
  799. // updateBindVolumeToClaim modifies given volume to be bound to a claim and saves it to
  800. // API server. The claim is not modified in this method!
  801. func (ctrl *PersistentVolumeController) updateBindVolumeToClaim(volumeClone *v1.PersistentVolume, updateCache bool) (*v1.PersistentVolume, error) {
  802. claimKey := claimrefToClaimKey(volumeClone.Spec.ClaimRef)
  803. klog.V(2).Infof("claim %q bound to volume %q", claimKey, volumeClone.Name)
  804. newVol, err := ctrl.kubeClient.CoreV1().PersistentVolumes().Update(context.TODO(), volumeClone, metav1.UpdateOptions{})
  805. if err != nil {
  806. klog.V(4).Infof("updating PersistentVolume[%s]: binding to %q failed: %v", volumeClone.Name, claimKey, err)
  807. return newVol, err
  808. }
  809. if updateCache {
  810. _, err = ctrl.storeVolumeUpdate(newVol)
  811. if err != nil {
  812. klog.V(4).Infof("updating PersistentVolume[%s]: cannot update internal cache: %v", volumeClone.Name, err)
  813. return newVol, err
  814. }
  815. }
  816. klog.V(4).Infof("updating PersistentVolume[%s]: bound to %q", newVol.Name, claimKey)
  817. return newVol, nil
  818. }
  819. // bindClaimToVolume modifies the given claim to be bound to a volume and
  820. // saves it to API server. The volume is not modified in this method!
  821. func (ctrl *PersistentVolumeController) bindClaimToVolume(claim *v1.PersistentVolumeClaim, volume *v1.PersistentVolume) (*v1.PersistentVolumeClaim, error) {
  822. klog.V(4).Infof("updating PersistentVolumeClaim[%s]: binding to %q", claimToClaimKey(claim), volume.Name)
  823. dirty := false
  824. // Check if the claim was already bound (either by controller or by user)
  825. shouldBind := false
  826. if volume.Name != claim.Spec.VolumeName {
  827. shouldBind = true
  828. }
  829. // The claim from method args can be pointing to watcher cache. We must not
  830. // modify these, therefore create a copy.
  831. claimClone := claim.DeepCopy()
  832. if shouldBind {
  833. dirty = true
  834. // Bind the claim to the volume
  835. claimClone.Spec.VolumeName = volume.Name
  836. // Set AnnBoundByController if it is not set yet
  837. if !metav1.HasAnnotation(claimClone.ObjectMeta, pvutil.AnnBoundByController) {
  838. metav1.SetMetaDataAnnotation(&claimClone.ObjectMeta, pvutil.AnnBoundByController, "yes")
  839. }
  840. }
  841. // Set AnnBindCompleted if it is not set yet
  842. if !metav1.HasAnnotation(claimClone.ObjectMeta, pvutil.AnnBindCompleted) {
  843. metav1.SetMetaDataAnnotation(&claimClone.ObjectMeta, pvutil.AnnBindCompleted, "yes")
  844. dirty = true
  845. }
  846. if dirty {
  847. klog.V(2).Infof("volume %q bound to claim %q", volume.Name, claimToClaimKey(claim))
  848. newClaim, err := ctrl.kubeClient.CoreV1().PersistentVolumeClaims(claim.Namespace).Update(context.TODO(), claimClone, metav1.UpdateOptions{})
  849. if err != nil {
  850. klog.V(4).Infof("updating PersistentVolumeClaim[%s]: binding to %q failed: %v", claimToClaimKey(claim), volume.Name, err)
  851. return newClaim, err
  852. }
  853. _, err = ctrl.storeClaimUpdate(newClaim)
  854. if err != nil {
  855. klog.V(4).Infof("updating PersistentVolumeClaim[%s]: cannot update internal cache: %v", claimToClaimKey(claim), err)
  856. return newClaim, err
  857. }
  858. klog.V(4).Infof("updating PersistentVolumeClaim[%s]: bound to %q", claimToClaimKey(claim), volume.Name)
  859. return newClaim, nil
  860. }
  861. klog.V(4).Infof("updating PersistentVolumeClaim[%s]: already bound to %q", claimToClaimKey(claim), volume.Name)
  862. return claim, nil
  863. }
  864. // bind saves binding information both to the volume and the claim and marks
  865. // both objects as Bound. Volume is saved first.
  866. // It returns on first error, it's up to the caller to implement some retry
  867. // mechanism.
  868. func (ctrl *PersistentVolumeController) bind(volume *v1.PersistentVolume, claim *v1.PersistentVolumeClaim) error {
  869. var err error
  870. // use updateClaim/updatedVolume to keep the original claim/volume for
  871. // logging in error cases.
  872. var updatedClaim *v1.PersistentVolumeClaim
  873. var updatedVolume *v1.PersistentVolume
  874. klog.V(4).Infof("binding volume %q to claim %q", volume.Name, claimToClaimKey(claim))
  875. if updatedVolume, err = ctrl.bindVolumeToClaim(volume, claim); err != nil {
  876. klog.V(3).Infof("error binding volume %q to claim %q: failed saving the volume: %v", volume.Name, claimToClaimKey(claim), err)
  877. return err
  878. }
  879. volume = updatedVolume
  880. if updatedVolume, err = ctrl.updateVolumePhase(volume, v1.VolumeBound, ""); err != nil {
  881. klog.V(3).Infof("error binding volume %q to claim %q: failed saving the volume status: %v", volume.Name, claimToClaimKey(claim), err)
  882. return err
  883. }
  884. volume = updatedVolume
  885. if updatedClaim, err = ctrl.bindClaimToVolume(claim, volume); err != nil {
  886. klog.V(3).Infof("error binding volume %q to claim %q: failed saving the claim: %v", volume.Name, claimToClaimKey(claim), err)
  887. return err
  888. }
  889. claim = updatedClaim
  890. if updatedClaim, err = ctrl.updateClaimStatus(claim, v1.ClaimBound, volume); err != nil {
  891. klog.V(3).Infof("error binding volume %q to claim %q: failed saving the claim status: %v", volume.Name, claimToClaimKey(claim), err)
  892. return err
  893. }
  894. claim = updatedClaim
  895. klog.V(4).Infof("volume %q bound to claim %q", volume.Name, claimToClaimKey(claim))
  896. klog.V(4).Infof("volume %q status after binding: %s", volume.Name, getVolumeStatusForLogging(volume))
  897. klog.V(4).Infof("claim %q status after binding: %s", claimToClaimKey(claim), getClaimStatusForLogging(claim))
  898. return nil
  899. }
  900. // unbindVolume rolls back previous binding of the volume. This may be necessary
  901. // when two controllers bound two volumes to single claim - when we detect this,
  902. // only one binding succeeds and the second one must be rolled back.
  903. // This method updates both Spec and Status.
  904. // It returns on first error, it's up to the caller to implement some retry
  905. // mechanism.
  906. func (ctrl *PersistentVolumeController) unbindVolume(volume *v1.PersistentVolume) error {
  907. klog.V(4).Infof("updating PersistentVolume[%s]: rolling back binding from %q", volume.Name, claimrefToClaimKey(volume.Spec.ClaimRef))
  908. // Save the PV only when any modification is necessary.
  909. volumeClone := volume.DeepCopy()
  910. if metav1.HasAnnotation(volume.ObjectMeta, pvutil.AnnBoundByController) {
  911. // The volume was bound by the controller.
  912. volumeClone.Spec.ClaimRef = nil
  913. delete(volumeClone.Annotations, pvutil.AnnBoundByController)
  914. if len(volumeClone.Annotations) == 0 {
  915. // No annotations look better than empty annotation map (and it's easier
  916. // to test).
  917. volumeClone.Annotations = nil
  918. }
  919. } else {
  920. // The volume was pre-bound by user. Clear only the binding UID.
  921. volumeClone.Spec.ClaimRef.UID = ""
  922. }
  923. newVol, err := ctrl.kubeClient.CoreV1().PersistentVolumes().Update(context.TODO(), volumeClone, metav1.UpdateOptions{})
  924. if err != nil {
  925. klog.V(4).Infof("updating PersistentVolume[%s]: rollback failed: %v", volume.Name, err)
  926. return err
  927. }
  928. _, err = ctrl.storeVolumeUpdate(newVol)
  929. if err != nil {
  930. klog.V(4).Infof("updating PersistentVolume[%s]: cannot update internal cache: %v", volume.Name, err)
  931. return err
  932. }
  933. klog.V(4).Infof("updating PersistentVolume[%s]: rolled back", newVol.Name)
  934. // Update the status
  935. _, err = ctrl.updateVolumePhase(newVol, v1.VolumeAvailable, "")
  936. return err
  937. }
  938. // reclaimVolume implements volume.Spec.PersistentVolumeReclaimPolicy and
  939. // starts appropriate reclaim action.
  940. func (ctrl *PersistentVolumeController) reclaimVolume(volume *v1.PersistentVolume) error {
  941. if migrated := volume.Annotations[pvutil.AnnMigratedTo]; len(migrated) > 0 {
  942. // PV is Migrated. The PV controller should stand down and the external
  943. // provisioner will handle this PV
  944. return nil
  945. }
  946. switch volume.Spec.PersistentVolumeReclaimPolicy {
  947. case v1.PersistentVolumeReclaimRetain:
  948. klog.V(4).Infof("reclaimVolume[%s]: policy is Retain, nothing to do", volume.Name)
  949. case v1.PersistentVolumeReclaimRecycle:
  950. klog.V(4).Infof("reclaimVolume[%s]: policy is Recycle", volume.Name)
  951. opName := fmt.Sprintf("recycle-%s[%s]", volume.Name, string(volume.UID))
  952. ctrl.scheduleOperation(opName, func() error {
  953. ctrl.recycleVolumeOperation(volume)
  954. return nil
  955. })
  956. case v1.PersistentVolumeReclaimDelete:
  957. klog.V(4).Infof("reclaimVolume[%s]: policy is Delete", volume.Name)
  958. opName := fmt.Sprintf("delete-%s[%s]", volume.Name, string(volume.UID))
  959. // create a start timestamp entry in cache for deletion operation if no one exists with
  960. // key = volume.Name, pluginName = provisionerName, operation = "delete"
  961. ctrl.operationTimestamps.AddIfNotExist(volume.Name, ctrl.getProvisionerNameFromVolume(volume), "delete")
  962. ctrl.scheduleOperation(opName, func() error {
  963. _, err := ctrl.deleteVolumeOperation(volume)
  964. if err != nil {
  965. // only report error count to "volume_operation_total_errors"
  966. // latency reporting will happen when the volume get finally
  967. // deleted and a volume deleted event is captured
  968. metrics.RecordMetric(volume.Name, &ctrl.operationTimestamps, err)
  969. }
  970. return err
  971. })
  972. default:
  973. // Unknown PersistentVolumeReclaimPolicy
  974. if _, err := ctrl.updateVolumePhaseWithEvent(volume, v1.VolumeFailed, v1.EventTypeWarning, "VolumeUnknownReclaimPolicy", "Volume has unrecognized PersistentVolumeReclaimPolicy"); err != nil {
  975. return err
  976. }
  977. }
  978. return nil
  979. }
  980. // recycleVolumeOperation recycles a volume. This method is running in
  981. // standalone goroutine and already has all necessary locks.
  982. func (ctrl *PersistentVolumeController) recycleVolumeOperation(volume *v1.PersistentVolume) {
  983. klog.V(4).Infof("recycleVolumeOperation [%s] started", volume.Name)
  984. // This method may have been waiting for a volume lock for some time.
  985. // Previous recycleVolumeOperation might just have saved an updated version,
  986. // so read current volume state now.
  987. newVolume, err := ctrl.kubeClient.CoreV1().PersistentVolumes().Get(context.TODO(), volume.Name, metav1.GetOptions{})
  988. if err != nil {
  989. klog.V(3).Infof("error reading persistent volume %q: %v", volume.Name, err)
  990. return
  991. }
  992. needsReclaim, err := ctrl.isVolumeReleased(newVolume)
  993. if err != nil {
  994. klog.V(3).Infof("error reading claim for volume %q: %v", volume.Name, err)
  995. return
  996. }
  997. if !needsReclaim {
  998. klog.V(3).Infof("volume %q no longer needs recycling, skipping", volume.Name)
  999. return
  1000. }
  1001. pods, used, err := ctrl.isVolumeUsed(newVolume)
  1002. if err != nil {
  1003. klog.V(3).Infof("can't recycle volume %q: %v", volume.Name, err)
  1004. return
  1005. }
  1006. // Verify the claim is in cache: if so, then it is a different PVC with the same name
  1007. // since the volume is known to be released at this moment. The new (cached) PVC must use
  1008. // a different PV -- we checked that the PV is unused in isVolumeReleased.
  1009. // So the old PV is safe to be recycled.
  1010. claimName := claimrefToClaimKey(volume.Spec.ClaimRef)
  1011. _, claimCached, err := ctrl.claims.GetByKey(claimName)
  1012. if err != nil {
  1013. klog.V(3).Infof("error getting the claim %s from cache", claimName)
  1014. return
  1015. }
  1016. if used && !claimCached {
  1017. msg := fmt.Sprintf("Volume is used by pods: %s", strings.Join(pods, ","))
  1018. klog.V(3).Infof("can't recycle volume %q: %s", volume.Name, msg)
  1019. ctrl.eventRecorder.Event(volume, v1.EventTypeNormal, events.VolumeFailedRecycle, msg)
  1020. return
  1021. }
  1022. // Use the newest volume copy, this will save us from version conflicts on
  1023. // saving.
  1024. volume = newVolume
  1025. // Find a plugin.
  1026. spec := vol.NewSpecFromPersistentVolume(volume, false)
  1027. plugin, err := ctrl.volumePluginMgr.FindRecyclablePluginBySpec(spec)
  1028. if err != nil {
  1029. // No recycler found. Emit an event and mark the volume Failed.
  1030. if _, err = ctrl.updateVolumePhaseWithEvent(volume, v1.VolumeFailed, v1.EventTypeWarning, events.VolumeFailedRecycle, "No recycler plugin found for the volume!"); err != nil {
  1031. klog.V(4).Infof("recycleVolumeOperation [%s]: failed to mark volume as failed: %v", volume.Name, err)
  1032. // Save failed, retry on the next deletion attempt
  1033. return
  1034. }
  1035. // Despite the volume being Failed, the controller will retry recycling
  1036. // the volume in every syncVolume() call.
  1037. return
  1038. }
  1039. // Plugin found
  1040. recorder := ctrl.newRecyclerEventRecorder(volume)
  1041. if err = plugin.Recycle(volume.Name, spec, recorder); err != nil {
  1042. // Recycler failed
  1043. strerr := fmt.Sprintf("Recycle failed: %s", err)
  1044. if _, err = ctrl.updateVolumePhaseWithEvent(volume, v1.VolumeFailed, v1.EventTypeWarning, events.VolumeFailedRecycle, strerr); err != nil {
  1045. klog.V(4).Infof("recycleVolumeOperation [%s]: failed to mark volume as failed: %v", volume.Name, err)
  1046. // Save failed, retry on the next deletion attempt
  1047. return
  1048. }
  1049. // Despite the volume being Failed, the controller will retry recycling
  1050. // the volume in every syncVolume() call.
  1051. return
  1052. }
  1053. klog.V(2).Infof("volume %q recycled", volume.Name)
  1054. // Send an event
  1055. ctrl.eventRecorder.Event(volume, v1.EventTypeNormal, events.VolumeRecycled, "Volume recycled")
  1056. // Make the volume available again
  1057. if err = ctrl.unbindVolume(volume); err != nil {
  1058. // Oops, could not save the volume and therefore the controller will
  1059. // recycle the volume again on next update. We _could_ maintain a cache
  1060. // of "recently recycled volumes" and avoid unnecessary recycling, this
  1061. // is left out as future optimization.
  1062. klog.V(3).Infof("recycleVolumeOperation [%s]: failed to make recycled volume 'Available' (%v), we will recycle the volume again", volume.Name, err)
  1063. return
  1064. }
  1065. return
  1066. }
  1067. // deleteVolumeOperation deletes a volume. This method is running in standalone
  1068. // goroutine and already has all necessary locks.
  1069. func (ctrl *PersistentVolumeController) deleteVolumeOperation(volume *v1.PersistentVolume) (string, error) {
  1070. klog.V(4).Infof("deleteVolumeOperation [%s] started", volume.Name)
  1071. // This method may have been waiting for a volume lock for some time.
  1072. // Previous deleteVolumeOperation might just have saved an updated version, so
  1073. // read current volume state now.
  1074. newVolume, err := ctrl.kubeClient.CoreV1().PersistentVolumes().Get(context.TODO(), volume.Name, metav1.GetOptions{})
  1075. if err != nil {
  1076. klog.V(3).Infof("error reading persistent volume %q: %v", volume.Name, err)
  1077. return "", nil
  1078. }
  1079. if newVolume.GetDeletionTimestamp() != nil {
  1080. klog.V(3).Infof("Volume %q is already being deleted", volume.Name)
  1081. return "", nil
  1082. }
  1083. needsReclaim, err := ctrl.isVolumeReleased(newVolume)
  1084. if err != nil {
  1085. klog.V(3).Infof("error reading claim for volume %q: %v", volume.Name, err)
  1086. return "", nil
  1087. }
  1088. if !needsReclaim {
  1089. klog.V(3).Infof("volume %q no longer needs deletion, skipping", volume.Name)
  1090. return "", nil
  1091. }
  1092. pluginName, deleted, err := ctrl.doDeleteVolume(volume)
  1093. if err != nil {
  1094. // Delete failed, update the volume and emit an event.
  1095. klog.V(3).Infof("deletion of volume %q failed: %v", volume.Name, err)
  1096. if volerr.IsDeletedVolumeInUse(err) {
  1097. // The plugin needs more time, don't mark the volume as Failed
  1098. // and send Normal event only
  1099. ctrl.eventRecorder.Event(volume, v1.EventTypeNormal, events.VolumeDelete, err.Error())
  1100. } else {
  1101. // The plugin failed, mark the volume as Failed and send Warning
  1102. // event
  1103. if _, err := ctrl.updateVolumePhaseWithEvent(volume, v1.VolumeFailed, v1.EventTypeWarning, events.VolumeFailedDelete, err.Error()); err != nil {
  1104. klog.V(4).Infof("deleteVolumeOperation [%s]: failed to mark volume as failed: %v", volume.Name, err)
  1105. // Save failed, retry on the next deletion attempt
  1106. return pluginName, err
  1107. }
  1108. }
  1109. // Despite the volume being Failed, the controller will retry deleting
  1110. // the volume in every syncVolume() call.
  1111. return pluginName, err
  1112. }
  1113. if !deleted {
  1114. // The volume waits for deletion by an external plugin. Do nothing.
  1115. return pluginName, nil
  1116. }
  1117. klog.V(4).Infof("deleteVolumeOperation [%s]: success", volume.Name)
  1118. // Delete the volume
  1119. if err = ctrl.kubeClient.CoreV1().PersistentVolumes().Delete(context.TODO(), volume.Name, nil); err != nil {
  1120. // Oops, could not delete the volume and therefore the controller will
  1121. // try to delete the volume again on next update. We _could_ maintain a
  1122. // cache of "recently deleted volumes" and avoid unnecessary deletion,
  1123. // this is left out as future optimization.
  1124. klog.V(3).Infof("failed to delete volume %q from database: %v", volume.Name, err)
  1125. return pluginName, nil
  1126. }
  1127. return pluginName, nil
  1128. }
  1129. // isVolumeReleased returns true if given volume is released and can be recycled
  1130. // or deleted, based on its retain policy. I.e. the volume is bound to a claim
  1131. // and the claim does not exist or exists and is bound to different volume.
  1132. func (ctrl *PersistentVolumeController) isVolumeReleased(volume *v1.PersistentVolume) (bool, error) {
  1133. // A volume needs reclaim if it has ClaimRef and appropriate claim does not
  1134. // exist.
  1135. if volume.Spec.ClaimRef == nil {
  1136. klog.V(4).Infof("isVolumeReleased[%s]: ClaimRef is nil", volume.Name)
  1137. return false, nil
  1138. }
  1139. if volume.Spec.ClaimRef.UID == "" {
  1140. // This is a volume bound by user and the controller has not finished
  1141. // binding to the real claim yet.
  1142. klog.V(4).Infof("isVolumeReleased[%s]: ClaimRef is not bound", volume.Name)
  1143. return false, nil
  1144. }
  1145. var claim *v1.PersistentVolumeClaim
  1146. claimName := claimrefToClaimKey(volume.Spec.ClaimRef)
  1147. obj, found, err := ctrl.claims.GetByKey(claimName)
  1148. if err != nil {
  1149. return false, err
  1150. }
  1151. if !found {
  1152. // Fall through with claim = nil
  1153. } else {
  1154. var ok bool
  1155. claim, ok = obj.(*v1.PersistentVolumeClaim)
  1156. if !ok {
  1157. return false, fmt.Errorf("Cannot convert object from claim cache to claim!?: %#v", obj)
  1158. }
  1159. }
  1160. if claim != nil && claim.UID == volume.Spec.ClaimRef.UID {
  1161. // the claim still exists and has the right UID
  1162. if len(claim.Spec.VolumeName) > 0 && claim.Spec.VolumeName != volume.Name {
  1163. // the claim is bound to another PV, this PV *is* released
  1164. return true, nil
  1165. }
  1166. klog.V(4).Infof("isVolumeReleased[%s]: ClaimRef is still valid, volume is not released", volume.Name)
  1167. return false, nil
  1168. }
  1169. klog.V(2).Infof("isVolumeReleased[%s]: volume is released", volume.Name)
  1170. return true, nil
  1171. }
  1172. // isVolumeUsed returns list of pods that use given PV.
  1173. func (ctrl *PersistentVolumeController) isVolumeUsed(pv *v1.PersistentVolume) ([]string, bool, error) {
  1174. if pv.Spec.ClaimRef == nil {
  1175. return nil, false, nil
  1176. }
  1177. claimName := pv.Spec.ClaimRef.Name
  1178. podNames := sets.NewString()
  1179. pods, err := ctrl.podLister.Pods(pv.Spec.ClaimRef.Namespace).List(labels.Everything())
  1180. if err != nil {
  1181. return nil, false, fmt.Errorf("error listing pods: %s", err)
  1182. }
  1183. for _, pod := range pods {
  1184. if util.IsPodTerminated(pod, pod.Status) {
  1185. continue
  1186. }
  1187. for i := range pod.Spec.Volumes {
  1188. usedPV := &pod.Spec.Volumes[i]
  1189. if usedPV.PersistentVolumeClaim != nil && usedPV.PersistentVolumeClaim.ClaimName == claimName {
  1190. podNames.Insert(pod.Namespace + "/" + pod.Name)
  1191. }
  1192. }
  1193. }
  1194. return podNames.List(), podNames.Len() != 0, nil
  1195. }
  1196. // doDeleteVolume finds appropriate delete plugin and deletes given volume, returning
  1197. // the volume plugin name. Also, it returns 'true', when the volume was deleted and
  1198. // 'false' when the volume cannot be deleted because the deleter is external. No
  1199. // error should be reported in this case.
  1200. func (ctrl *PersistentVolumeController) doDeleteVolume(volume *v1.PersistentVolume) (string, bool, error) {
  1201. klog.V(4).Infof("doDeleteVolume [%s]", volume.Name)
  1202. var err error
  1203. plugin, err := ctrl.findDeletablePlugin(volume)
  1204. if err != nil {
  1205. return "", false, err
  1206. }
  1207. if plugin == nil {
  1208. // External deleter is requested, do nothing
  1209. klog.V(3).Infof("external deleter for volume %q requested, ignoring", volume.Name)
  1210. return "", false, nil
  1211. }
  1212. // Plugin found
  1213. pluginName := plugin.GetPluginName()
  1214. klog.V(5).Infof("found a deleter plugin %q for volume %q", pluginName, volume.Name)
  1215. spec := vol.NewSpecFromPersistentVolume(volume, false)
  1216. deleter, err := plugin.NewDeleter(spec)
  1217. if err != nil {
  1218. // Cannot create deleter
  1219. return pluginName, false, fmt.Errorf("Failed to create deleter for volume %q: %v", volume.Name, err)
  1220. }
  1221. opComplete := util.OperationCompleteHook(pluginName, "volume_delete")
  1222. err = deleter.Delete()
  1223. opComplete(&err)
  1224. if err != nil {
  1225. // Deleter failed
  1226. return pluginName, false, err
  1227. }
  1228. klog.V(2).Infof("volume %q deleted", volume.Name)
  1229. return pluginName, true, nil
  1230. }
  1231. // provisionClaim starts new asynchronous operation to provision a claim if
  1232. // provisioning is enabled.
  1233. func (ctrl *PersistentVolumeController) provisionClaim(claim *v1.PersistentVolumeClaim) error {
  1234. if !ctrl.enableDynamicProvisioning {
  1235. return nil
  1236. }
  1237. klog.V(4).Infof("provisionClaim[%s]: started", claimToClaimKey(claim))
  1238. opName := fmt.Sprintf("provision-%s[%s]", claimToClaimKey(claim), string(claim.UID))
  1239. plugin, storageClass, err := ctrl.findProvisionablePlugin(claim)
  1240. // findProvisionablePlugin does not return err for external provisioners
  1241. if err != nil {
  1242. ctrl.eventRecorder.Event(claim, v1.EventTypeWarning, events.ProvisioningFailed, err.Error())
  1243. klog.Errorf("error finding provisioning plugin for claim %s: %v", claimToClaimKey(claim), err)
  1244. // failed to find the requested provisioning plugin, directly return err for now.
  1245. // controller will retry the provisioning in every syncUnboundClaim() call
  1246. // retain the original behavior of returning nil from provisionClaim call
  1247. return nil
  1248. }
  1249. ctrl.scheduleOperation(opName, func() error {
  1250. // create a start timestamp entry in cache for provision operation if no one exists with
  1251. // key = claimKey, pluginName = provisionerName, operation = "provision"
  1252. claimKey := claimToClaimKey(claim)
  1253. ctrl.operationTimestamps.AddIfNotExist(claimKey, ctrl.getProvisionerName(plugin, storageClass), "provision")
  1254. var err error
  1255. if plugin == nil {
  1256. _, err = ctrl.provisionClaimOperationExternal(claim, storageClass)
  1257. } else {
  1258. _, err = ctrl.provisionClaimOperation(claim, plugin, storageClass)
  1259. }
  1260. // if error happened, record an error count metric
  1261. // timestamp entry will remain in cache until a success binding has happened
  1262. if err != nil {
  1263. metrics.RecordMetric(claimKey, &ctrl.operationTimestamps, err)
  1264. }
  1265. return err
  1266. })
  1267. return nil
  1268. }
  1269. // provisionClaimOperation provisions a volume. This method is running in
  1270. // standalone goroutine and already has all necessary locks.
  1271. func (ctrl *PersistentVolumeController) provisionClaimOperation(
  1272. claim *v1.PersistentVolumeClaim,
  1273. plugin vol.ProvisionableVolumePlugin,
  1274. storageClass *storage.StorageClass) (string, error) {
  1275. claimClass := v1helper.GetPersistentVolumeClaimClass(claim)
  1276. klog.V(4).Infof("provisionClaimOperation [%s] started, class: %q", claimToClaimKey(claim), claimClass)
  1277. // called from provisionClaim(), in this case, plugin MUST NOT be nil
  1278. // NOTE: checks on plugin/storageClass has been saved
  1279. pluginName := plugin.GetPluginName()
  1280. provisionerName := storageClass.Provisioner
  1281. // Add provisioner annotation to be consistent with external provisioner workflow
  1282. newClaim, err := ctrl.setClaimProvisioner(claim, provisionerName)
  1283. if err != nil {
  1284. // Save failed, the controller will retry in the next sync
  1285. klog.V(2).Infof("error saving claim %s: %v", claimToClaimKey(claim), err)
  1286. return pluginName, err
  1287. }
  1288. claim = newClaim
  1289. // internal provisioning
  1290. // A previous provisionClaimOperation may just have finished while we were waiting for
  1291. // the locks. Check that PV (with deterministic name) hasn't been provisioned
  1292. // yet.
  1293. pvName := ctrl.getProvisionedVolumeNameForClaim(claim)
  1294. volume, err := ctrl.kubeClient.CoreV1().PersistentVolumes().Get(context.TODO(), pvName, metav1.GetOptions{})
  1295. if err != nil && !apierrors.IsNotFound(err) {
  1296. klog.V(3).Infof("error reading persistent volume %q: %v", pvName, err)
  1297. return pluginName, err
  1298. }
  1299. if err == nil && volume != nil {
  1300. // Volume has been already provisioned, nothing to do.
  1301. klog.V(4).Infof("provisionClaimOperation [%s]: volume already exists, skipping", claimToClaimKey(claim))
  1302. return pluginName, err
  1303. }
  1304. // Prepare a claimRef to the claim early (to fail before a volume is
  1305. // provisioned)
  1306. claimRef, err := ref.GetReference(scheme.Scheme, claim)
  1307. if err != nil {
  1308. klog.V(3).Infof("unexpected error getting claim reference: %v", err)
  1309. return pluginName, err
  1310. }
  1311. // Gather provisioning options
  1312. tags := make(map[string]string)
  1313. tags[CloudVolumeCreatedForClaimNamespaceTag] = claim.Namespace
  1314. tags[CloudVolumeCreatedForClaimNameTag] = claim.Name
  1315. tags[CloudVolumeCreatedForVolumeNameTag] = pvName
  1316. options := vol.VolumeOptions{
  1317. PersistentVolumeReclaimPolicy: *storageClass.ReclaimPolicy,
  1318. MountOptions: storageClass.MountOptions,
  1319. CloudTags: &tags,
  1320. ClusterName: ctrl.clusterName,
  1321. PVName: pvName,
  1322. PVC: claim,
  1323. Parameters: storageClass.Parameters,
  1324. }
  1325. // Refuse to provision if the plugin doesn't support mount options, creation
  1326. // of PV would be rejected by validation anyway
  1327. if !plugin.SupportsMountOption() && len(options.MountOptions) > 0 {
  1328. strerr := fmt.Sprintf("Mount options are not supported by the provisioner but StorageClass %q has mount options %v", storageClass.Name, options.MountOptions)
  1329. klog.V(2).Infof("Mount options are not supported by the provisioner but claim %q's StorageClass %q has mount options %v", claimToClaimKey(claim), storageClass.Name, options.MountOptions)
  1330. ctrl.eventRecorder.Event(claim, v1.EventTypeWarning, events.ProvisioningFailed, strerr)
  1331. return pluginName, fmt.Errorf("provisioner %q doesn't support mount options", plugin.GetPluginName())
  1332. }
  1333. // Provision the volume
  1334. provisioner, err := plugin.NewProvisioner(options)
  1335. if err != nil {
  1336. strerr := fmt.Sprintf("Failed to create provisioner: %v", err)
  1337. klog.V(2).Infof("failed to create provisioner for claim %q with StorageClass %q: %v", claimToClaimKey(claim), storageClass.Name, err)
  1338. ctrl.eventRecorder.Event(claim, v1.EventTypeWarning, events.ProvisioningFailed, strerr)
  1339. return pluginName, err
  1340. }
  1341. var selectedNode *v1.Node = nil
  1342. if nodeName, ok := claim.Annotations[pvutil.AnnSelectedNode]; ok {
  1343. selectedNode, err = ctrl.NodeLister.Get(nodeName)
  1344. if err != nil {
  1345. strerr := fmt.Sprintf("Failed to get target node: %v", err)
  1346. klog.V(3).Infof("unexpected error getting target node %q for claim %q: %v", nodeName, claimToClaimKey(claim), err)
  1347. ctrl.eventRecorder.Event(claim, v1.EventTypeWarning, events.ProvisioningFailed, strerr)
  1348. return pluginName, err
  1349. }
  1350. }
  1351. allowedTopologies := storageClass.AllowedTopologies
  1352. opComplete := util.OperationCompleteHook(plugin.GetPluginName(), "volume_provision")
  1353. volume, err = provisioner.Provision(selectedNode, allowedTopologies)
  1354. opComplete(&err)
  1355. if err != nil {
  1356. // Other places of failure have nothing to do with VolumeScheduling,
  1357. // so just let controller retry in the next sync. We'll only call func
  1358. // rescheduleProvisioning here when the underlying provisioning actually failed.
  1359. ctrl.rescheduleProvisioning(claim)
  1360. strerr := fmt.Sprintf("Failed to provision volume with StorageClass %q: %v", storageClass.Name, err)
  1361. klog.V(2).Infof("failed to provision volume for claim %q with StorageClass %q: %v", claimToClaimKey(claim), storageClass.Name, err)
  1362. ctrl.eventRecorder.Event(claim, v1.EventTypeWarning, events.ProvisioningFailed, strerr)
  1363. return pluginName, err
  1364. }
  1365. klog.V(3).Infof("volume %q for claim %q created", volume.Name, claimToClaimKey(claim))
  1366. // Create Kubernetes PV object for the volume.
  1367. if volume.Name == "" {
  1368. volume.Name = pvName
  1369. }
  1370. // Bind it to the claim
  1371. volume.Spec.ClaimRef = claimRef
  1372. volume.Status.Phase = v1.VolumeBound
  1373. volume.Spec.StorageClassName = claimClass
  1374. // Add AnnBoundByController (used in deleting the volume)
  1375. metav1.SetMetaDataAnnotation(&volume.ObjectMeta, pvutil.AnnBoundByController, "yes")
  1376. metav1.SetMetaDataAnnotation(&volume.ObjectMeta, pvutil.AnnDynamicallyProvisioned, plugin.GetPluginName())
  1377. // Try to create the PV object several times
  1378. for i := 0; i < ctrl.createProvisionedPVRetryCount; i++ {
  1379. klog.V(4).Infof("provisionClaimOperation [%s]: trying to save volume %s", claimToClaimKey(claim), volume.Name)
  1380. var newVol *v1.PersistentVolume
  1381. if newVol, err = ctrl.kubeClient.CoreV1().PersistentVolumes().Create(context.TODO(), volume, metav1.CreateOptions{}); err == nil || apierrors.IsAlreadyExists(err) {
  1382. // Save succeeded.
  1383. if err != nil {
  1384. klog.V(3).Infof("volume %q for claim %q already exists, reusing", volume.Name, claimToClaimKey(claim))
  1385. err = nil
  1386. } else {
  1387. klog.V(3).Infof("volume %q for claim %q saved", volume.Name, claimToClaimKey(claim))
  1388. _, updateErr := ctrl.storeVolumeUpdate(newVol)
  1389. if updateErr != nil {
  1390. // We will get an "volume added" event soon, this is not a big error
  1391. klog.V(4).Infof("provisionClaimOperation [%s]: cannot update internal cache: %v", volume.Name, updateErr)
  1392. }
  1393. }
  1394. break
  1395. }
  1396. // Save failed, try again after a while.
  1397. klog.V(3).Infof("failed to save volume %q for claim %q: %v", volume.Name, claimToClaimKey(claim), err)
  1398. time.Sleep(ctrl.createProvisionedPVInterval)
  1399. }
  1400. if err != nil {
  1401. // Save failed. Now we have a storage asset outside of Kubernetes,
  1402. // but we don't have appropriate PV object for it.
  1403. // Emit some event here and try to delete the storage asset several
  1404. // times.
  1405. strerr := fmt.Sprintf("Error creating provisioned PV object for claim %s: %v. Deleting the volume.", claimToClaimKey(claim), err)
  1406. klog.V(3).Info(strerr)
  1407. ctrl.eventRecorder.Event(claim, v1.EventTypeWarning, events.ProvisioningFailed, strerr)
  1408. var deleteErr error
  1409. var deleted bool
  1410. for i := 0; i < ctrl.createProvisionedPVRetryCount; i++ {
  1411. _, deleted, deleteErr = ctrl.doDeleteVolume(volume)
  1412. if deleteErr == nil && deleted {
  1413. // Delete succeeded
  1414. klog.V(4).Infof("provisionClaimOperation [%s]: cleaning volume %s succeeded", claimToClaimKey(claim), volume.Name)
  1415. break
  1416. }
  1417. if !deleted {
  1418. // This is unreachable code, the volume was provisioned by an
  1419. // internal plugin and therefore there MUST be an internal
  1420. // plugin that deletes it.
  1421. klog.Errorf("Error finding internal deleter for volume plugin %q", plugin.GetPluginName())
  1422. break
  1423. }
  1424. // Delete failed, try again after a while.
  1425. klog.V(3).Infof("failed to delete volume %q: %v", volume.Name, deleteErr)
  1426. time.Sleep(ctrl.createProvisionedPVInterval)
  1427. }
  1428. if deleteErr != nil {
  1429. // Delete failed several times. There is an orphaned volume and there
  1430. // is nothing we can do about it.
  1431. strerr := fmt.Sprintf("Error cleaning provisioned volume for claim %s: %v. Please delete manually.", claimToClaimKey(claim), deleteErr)
  1432. klog.V(2).Info(strerr)
  1433. ctrl.eventRecorder.Event(claim, v1.EventTypeWarning, events.ProvisioningCleanupFailed, strerr)
  1434. }
  1435. } else {
  1436. klog.V(2).Infof("volume %q provisioned for claim %q", volume.Name, claimToClaimKey(claim))
  1437. msg := fmt.Sprintf("Successfully provisioned volume %s using %s", volume.Name, plugin.GetPluginName())
  1438. ctrl.eventRecorder.Event(claim, v1.EventTypeNormal, events.ProvisioningSucceeded, msg)
  1439. }
  1440. return pluginName, nil
  1441. }
  1442. // provisionClaimOperationExternal provisions a volume using external provisioner async-ly
  1443. // This method will be running in a standalone go-routine scheduled in "provisionClaim"
  1444. func (ctrl *PersistentVolumeController) provisionClaimOperationExternal(
  1445. claim *v1.PersistentVolumeClaim,
  1446. storageClass *storage.StorageClass) (string, error) {
  1447. claimClass := v1helper.GetPersistentVolumeClaimClass(claim)
  1448. klog.V(4).Infof("provisionClaimOperationExternal [%s] started, class: %q", claimToClaimKey(claim), claimClass)
  1449. // Set provisionerName to external provisioner name by setClaimProvisioner
  1450. var err error
  1451. provisionerName := storageClass.Provisioner
  1452. if ctrl.csiMigratedPluginManager.IsMigrationEnabledForPlugin(storageClass.Provisioner) {
  1453. // update the provisioner name to use the migrated CSI plugin name
  1454. provisionerName, err = ctrl.translator.GetCSINameFromInTreeName(storageClass.Provisioner)
  1455. if err != nil {
  1456. strerr := fmt.Sprintf("error getting CSI name for In tree plugin %s: %v", storageClass.Provisioner, err)
  1457. klog.V(2).Infof("%s", strerr)
  1458. ctrl.eventRecorder.Event(claim, v1.EventTypeWarning, events.ProvisioningFailed, strerr)
  1459. return provisionerName, err
  1460. }
  1461. }
  1462. // Add provisioner annotation so external provisioners know when to start
  1463. newClaim, err := ctrl.setClaimProvisioner(claim, provisionerName)
  1464. if err != nil {
  1465. // Save failed, the controller will retry in the next sync
  1466. klog.V(2).Infof("error saving claim %s: %v", claimToClaimKey(claim), err)
  1467. return provisionerName, err
  1468. }
  1469. claim = newClaim
  1470. msg := fmt.Sprintf("waiting for a volume to be created, either by external provisioner %q or manually created by system administrator", provisionerName)
  1471. // External provisioner has been requested for provisioning the volume
  1472. // Report an event and wait for external provisioner to finish
  1473. ctrl.eventRecorder.Event(claim, v1.EventTypeNormal, events.ExternalProvisioning, msg)
  1474. klog.V(3).Infof("provisionClaimOperationExternal provisioning claim %q: %s", claimToClaimKey(claim), msg)
  1475. // return provisioner name here for metric reporting
  1476. return provisionerName, nil
  1477. }
  1478. // rescheduleProvisioning signal back to the scheduler to retry dynamic provisioning
  1479. // by removing the AnnSelectedNode annotation
  1480. func (ctrl *PersistentVolumeController) rescheduleProvisioning(claim *v1.PersistentVolumeClaim) {
  1481. if _, ok := claim.Annotations[pvutil.AnnSelectedNode]; !ok {
  1482. // Provisioning not triggered by the scheduler, skip
  1483. return
  1484. }
  1485. // The claim from method args can be pointing to watcher cache. We must not
  1486. // modify these, therefore create a copy.
  1487. newClaim := claim.DeepCopy()
  1488. delete(newClaim.Annotations, pvutil.AnnSelectedNode)
  1489. // Try to update the PVC object
  1490. if _, err := ctrl.kubeClient.CoreV1().PersistentVolumeClaims(newClaim.Namespace).Update(context.TODO(), newClaim, metav1.UpdateOptions{}); err != nil {
  1491. klog.V(4).Infof("Failed to delete annotation 'pvutil.AnnSelectedNode' for PersistentVolumeClaim %q: %v", claimToClaimKey(newClaim), err)
  1492. return
  1493. }
  1494. if _, err := ctrl.storeClaimUpdate(newClaim); err != nil {
  1495. // We will get an "claim updated" event soon, this is not a big error
  1496. klog.V(4).Infof("Updating PersistentVolumeClaim %q: cannot update internal cache: %v", claimToClaimKey(newClaim), err)
  1497. }
  1498. }
  1499. // getProvisionedVolumeNameForClaim returns PV.Name for the provisioned volume.
  1500. // The name must be unique.
  1501. func (ctrl *PersistentVolumeController) getProvisionedVolumeNameForClaim(claim *v1.PersistentVolumeClaim) string {
  1502. return "pvc-" + string(claim.UID)
  1503. }
  1504. // scheduleOperation starts given asynchronous operation on given volume. It
  1505. // makes sure the operation is already not running.
  1506. func (ctrl *PersistentVolumeController) scheduleOperation(operationName string, operation func() error) {
  1507. klog.V(4).Infof("scheduleOperation[%s]", operationName)
  1508. // Poke test code that an operation is just about to get started.
  1509. if ctrl.preOperationHook != nil {
  1510. ctrl.preOperationHook(operationName)
  1511. }
  1512. err := ctrl.runningOperations.Run(operationName, operation)
  1513. if err != nil {
  1514. switch {
  1515. case goroutinemap.IsAlreadyExists(err):
  1516. klog.V(4).Infof("operation %q is already running, skipping", operationName)
  1517. case exponentialbackoff.IsExponentialBackoff(err):
  1518. klog.V(4).Infof("operation %q postponed due to exponential backoff", operationName)
  1519. default:
  1520. klog.Errorf("error scheduling operation %q: %v", operationName, err)
  1521. }
  1522. }
  1523. }
  1524. // newRecyclerEventRecorder returns a RecycleEventRecorder that sends all events
  1525. // to given volume.
  1526. func (ctrl *PersistentVolumeController) newRecyclerEventRecorder(volume *v1.PersistentVolume) recyclerclient.RecycleEventRecorder {
  1527. return func(eventtype, message string) {
  1528. ctrl.eventRecorder.Eventf(volume, eventtype, events.RecyclerPod, "Recycler pod: %s", message)
  1529. }
  1530. }
  1531. // findProvisionablePlugin finds a provisioner plugin for a given claim.
  1532. // It returns either the provisioning plugin or nil when an external
  1533. // provisioner is requested.
  1534. func (ctrl *PersistentVolumeController) findProvisionablePlugin(claim *v1.PersistentVolumeClaim) (vol.ProvisionableVolumePlugin, *storage.StorageClass, error) {
  1535. // provisionClaim() which leads here is never called with claimClass=="", we
  1536. // can save some checks.
  1537. claimClass := v1helper.GetPersistentVolumeClaimClass(claim)
  1538. class, err := ctrl.classLister.Get(claimClass)
  1539. if err != nil {
  1540. return nil, nil, err
  1541. }
  1542. // Find a plugin for the class
  1543. if ctrl.csiMigratedPluginManager.IsMigrationEnabledForPlugin(class.Provisioner) {
  1544. // CSI migration scenario - do not depend on in-tree plugin
  1545. return nil, class, nil
  1546. }
  1547. plugin, err := ctrl.volumePluginMgr.FindProvisionablePluginByName(class.Provisioner)
  1548. if err != nil {
  1549. if !strings.HasPrefix(class.Provisioner, "kubernetes.io/") {
  1550. // External provisioner is requested, do not report error
  1551. return nil, class, nil
  1552. }
  1553. return nil, class, err
  1554. }
  1555. return plugin, class, nil
  1556. }
  1557. // findDeletablePlugin finds a deleter plugin for a given volume. It returns
  1558. // either the deleter plugin or nil when an external deleter is requested.
  1559. func (ctrl *PersistentVolumeController) findDeletablePlugin(volume *v1.PersistentVolume) (vol.DeletableVolumePlugin, error) {
  1560. // Find a plugin. Try to find the same plugin that provisioned the volume
  1561. var plugin vol.DeletableVolumePlugin
  1562. if metav1.HasAnnotation(volume.ObjectMeta, pvutil.AnnDynamicallyProvisioned) {
  1563. provisionPluginName := volume.Annotations[pvutil.AnnDynamicallyProvisioned]
  1564. if provisionPluginName != "" {
  1565. plugin, err := ctrl.volumePluginMgr.FindDeletablePluginByName(provisionPluginName)
  1566. if err != nil {
  1567. if !strings.HasPrefix(provisionPluginName, "kubernetes.io/") {
  1568. // External provisioner is requested, do not report error
  1569. return nil, nil
  1570. }
  1571. return nil, err
  1572. }
  1573. return plugin, nil
  1574. }
  1575. }
  1576. // The plugin that provisioned the volume was not found or the volume
  1577. // was not dynamically provisioned. Try to find a plugin by spec.
  1578. spec := vol.NewSpecFromPersistentVolume(volume, false)
  1579. plugin, err := ctrl.volumePluginMgr.FindDeletablePluginBySpec(spec)
  1580. if err != nil {
  1581. // No deleter found. Emit an event and mark the volume Failed.
  1582. return nil, fmt.Errorf("Error getting deleter volume plugin for volume %q: %v", volume.Name, err)
  1583. }
  1584. return plugin, nil
  1585. }
  1586. // obtain provisioner/deleter name for a volume
  1587. func (ctrl *PersistentVolumeController) getProvisionerNameFromVolume(volume *v1.PersistentVolume) string {
  1588. plugin, err := ctrl.findDeletablePlugin(volume)
  1589. if err != nil {
  1590. return "N/A"
  1591. }
  1592. if plugin != nil {
  1593. return plugin.GetPluginName()
  1594. }
  1595. // If reached here, Either an external provisioner was used for provisioning
  1596. // or a plugin has been migrated to CSI.
  1597. // If an external provisioner was used, i.e., plugin == nil, instead of using
  1598. // the AnnDynamicallyProvisioned annotation value, use the storageClass's Provisioner
  1599. // field to avoid explosion of the metric in the cases like local storage provisioner
  1600. // tagging a volume with arbitrary provisioner names
  1601. storageClass := v1helper.GetPersistentVolumeClass(volume)
  1602. class, err := ctrl.classLister.Get(storageClass)
  1603. if err != nil {
  1604. return "N/A"
  1605. }
  1606. if ctrl.csiMigratedPluginManager.IsMigrationEnabledForPlugin(class.Provisioner) {
  1607. provisionerName, err := ctrl.translator.GetCSINameFromInTreeName(class.Provisioner)
  1608. if err != nil {
  1609. return "N/A"
  1610. }
  1611. return provisionerName
  1612. }
  1613. return class.Provisioner
  1614. }
  1615. // obtain plugin/external provisioner name from plugin and storage class for timestamp logging purposes
  1616. func (ctrl *PersistentVolumeController) getProvisionerName(plugin vol.ProvisionableVolumePlugin, storageClass *storage.StorageClass) string {
  1617. // non CSI-migrated in-tree plugin, returns the plugin's name
  1618. if plugin != nil {
  1619. return plugin.GetPluginName()
  1620. }
  1621. if ctrl.csiMigratedPluginManager.IsMigrationEnabledForPlugin(storageClass.Provisioner) {
  1622. // get the name of the CSI plugin that the in-tree storage class
  1623. // provisioner has migrated to
  1624. provisionerName, err := ctrl.translator.GetCSINameFromInTreeName(storageClass.Provisioner)
  1625. if err != nil {
  1626. return "N/A"
  1627. }
  1628. return provisionerName
  1629. }
  1630. return storageClass.Provisioner
  1631. }