pvc_populator.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. /*
  2. Copyright 2017 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 reconciler implements interfaces that attempt to reconcile the
  14. // desired state of the with the actual state of the world by triggering
  15. // actions.
  16. package expand
  17. import (
  18. "fmt"
  19. "time"
  20. "k8s.io/klog"
  21. "k8s.io/api/core/v1"
  22. "k8s.io/apimachinery/pkg/labels"
  23. "k8s.io/apimachinery/pkg/util/wait"
  24. clientset "k8s.io/client-go/kubernetes"
  25. "k8s.io/client-go/kubernetes/scheme"
  26. v1core "k8s.io/client-go/kubernetes/typed/core/v1"
  27. corelisters "k8s.io/client-go/listers/core/v1"
  28. "k8s.io/client-go/tools/record"
  29. "k8s.io/kubernetes/pkg/controller/volume/events"
  30. "k8s.io/kubernetes/pkg/controller/volume/expand/cache"
  31. "k8s.io/kubernetes/pkg/volume"
  32. "k8s.io/kubernetes/pkg/volume/util"
  33. )
  34. // PVCPopulator iterates through PVCs and checks if for bound PVCs
  35. // their size doesn't match with Persistent Volume size
  36. type PVCPopulator interface {
  37. Run(stopCh <-chan struct{})
  38. }
  39. type pvcPopulator struct {
  40. loopPeriod time.Duration
  41. resizeMap cache.VolumeResizeMap
  42. pvcLister corelisters.PersistentVolumeClaimLister
  43. pvLister corelisters.PersistentVolumeLister
  44. kubeClient clientset.Interface
  45. volumePluginMgr *volume.VolumePluginMgr
  46. recorder record.EventRecorder
  47. }
  48. func NewPVCPopulator(
  49. loopPeriod time.Duration,
  50. resizeMap cache.VolumeResizeMap,
  51. pvcLister corelisters.PersistentVolumeClaimLister,
  52. pvLister corelisters.PersistentVolumeLister,
  53. volumePluginMgr *volume.VolumePluginMgr,
  54. kubeClient clientset.Interface) PVCPopulator {
  55. populator := &pvcPopulator{
  56. loopPeriod: loopPeriod,
  57. pvcLister: pvcLister,
  58. pvLister: pvLister,
  59. resizeMap: resizeMap,
  60. volumePluginMgr: volumePluginMgr,
  61. kubeClient: kubeClient,
  62. }
  63. eventBroadcaster := record.NewBroadcaster()
  64. eventBroadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: kubeClient.CoreV1().Events("")})
  65. populator.recorder = eventBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "volume_expand"})
  66. return populator
  67. }
  68. func (populator *pvcPopulator) Run(stopCh <-chan struct{}) {
  69. wait.Until(populator.Sync, populator.loopPeriod, stopCh)
  70. }
  71. func (populator *pvcPopulator) Sync() {
  72. pvcs, err := populator.pvcLister.List(labels.Everything())
  73. if err != nil {
  74. klog.Errorf("Listing PVCs failed in populator : %v", err)
  75. return
  76. }
  77. for _, pvc := range pvcs {
  78. pv, err := getPersistentVolume(pvc, populator.pvLister)
  79. if err != nil {
  80. klog.V(5).Infof("Error getting persistent volume for PVC %q : %v", pvc.UID, err)
  81. continue
  82. }
  83. // Filter PVCs for which the corresponding volume plugins don't allow expansion.
  84. pvcSize := pvc.Spec.Resources.Requests[v1.ResourceStorage]
  85. pvcStatusSize := pvc.Status.Capacity[v1.ResourceStorage]
  86. volumeSpec := volume.NewSpecFromPersistentVolume(pv, false)
  87. volumePlugin, err := populator.volumePluginMgr.FindExpandablePluginBySpec(volumeSpec)
  88. if (err != nil || volumePlugin == nil) && pvcStatusSize.Cmp(pvcSize) < 0 {
  89. retErr := fmt.Errorf("didn't find a plugin capable of expanding the volume; " +
  90. "waiting for an external controller to process this PVC")
  91. eventType := v1.EventTypeNormal
  92. if err != nil {
  93. eventType = v1.EventTypeWarning
  94. }
  95. populator.recorder.Event(pvc, eventType, events.ExternalExpanding,
  96. fmt.Sprintf("Ignoring the PVC: %v.", retErr))
  97. klog.V(3).Infof("Ignoring the PVC %q (uid: %q) : %v.",
  98. util.GetPersistentVolumeClaimQualifiedName(pvc), pvc.UID, retErr)
  99. continue
  100. }
  101. // We are only going to add PVCs which are:
  102. // - bound
  103. // - pvc.Spec.Size > pvc.Status.Size
  104. // These 2 checks are already performed in AddPVCUpdate function before adding pvc for resize
  105. // and hence we do not repeat those checks here.
  106. populator.resizeMap.AddPVCUpdate(pvc, pv)
  107. }
  108. }