Skip to content

Commit

Permalink
Merge pull request kubernetes-csi#39 from leakingtapan/resize-migration
Browse files Browse the repository at this point in the history
Implement CSI migration logic for volume resize
  • Loading branch information
k8s-ci-robot authored Jun 25, 2019
2 parents 7493e6d + a380b39 commit 24780ba
Show file tree
Hide file tree
Showing 17 changed files with 1,379 additions and 17 deletions.
20 changes: 20 additions & 0 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 18 additions & 2 deletions pkg/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,27 @@ func (ctrl *resizeController) updatePVC(oldObj, newObj interface{}) {
newSize := newPVC.Spec.Resources.Requests[v1.ResourceStorage]
oldSize := oldPVC.Spec.Resources.Requests[v1.ResourceStorage]

newResizerName := newPVC.Annotations[util.VolumeResizerKey]
oldResizerName := oldPVC.Annotations[util.VolumeResizerKey]

// We perform additional checks to avoid double processing of PVCs, as we will also receive Update event when:
// 1. Administrator or users may introduce other changes(such as add labels, modify annotations, etc.)
// unrelated to volume resize.
// 2. Informer will resync and send Update event periodically without any changes.
if newSize.Cmp(oldSize) > 0 {
//
// We add the PVC into work queue when the new size is larger then the old size
// or when the resizer name changes. This is needed for CSI migration for the follow two cases:
//
// 1. First time a migrated PVC is expanded:
// It does not yet have the annotation because annotation is only added by in-tree resizer when it receives a volume
// expansion request. So first update event that will be received by external-resizer will be ignored because it won't
// know how to support resizing of a "un-annotated" in-tree PVC. When in-tree resizer does add the annotation, a second
// update even will be received and we add the pvc to workqueue. If annotation matches the registered driver name in
// csi_resizer object, we proceeds with expansion internally or we discard the PVC.
// 2. An already expanded in-tree PVC:
// An in-tree PVC is resized with in-tree resizer. And later, CSI migration is turned on and resizer name is updated from
// in-tree resizer name to CSI driver name.
if newSize.Cmp(oldSize) > 0 || newResizerName != oldResizerName {
ctrl.addPVC(newObj)
}
}
Expand Down Expand Up @@ -249,7 +265,7 @@ func (ctrl *resizeController) pvcNeedResize(pvc *v1.PersistentVolumeClaim) bool

// pvNeedResize returns true if a pv supports and also requests resize.
func (ctrl *resizeController) pvNeedResize(pvc *v1.PersistentVolumeClaim, pv *v1.PersistentVolume) bool {
if !ctrl.resizer.CanSupport(pv) {
if !ctrl.resizer.CanSupport(pv, pvc) {
klog.V(4).Infof("Resizer %q doesn't support PV %q", ctrl.name, pv.Name)
return false
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/controller/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func TestController(t *testing.T) {
NodeResize: true,
},
} {
client := csi.NewMockClient(test.NodeResize, true, true)
client := csi.NewMockClient("mock", test.NodeResize, true, true)
driverName, _ := client.GetDriverName(context.TODO())

initialObjects := []runtime.Object{}
Expand Down
3 changes: 2 additions & 1 deletion pkg/csi/mock_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ package csi
import "context"

func NewMockClient(
name string,
supportsNodeResize bool,
supportsControllerResize bool,
supportsPluginControllerService bool) *MockClient {
return &MockClient{
name: "mock",
name: name,
supportsNodeResize: supportsNodeResize,
supportsControllerResize: supportsControllerResize,
supportsPluginControllerService: supportsPluginControllerService,
Expand Down
43 changes: 38 additions & 5 deletions pkg/resizer/csi_resizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,15 @@ import (
"time"

"github.com/kubernetes-csi/external-resizer/pkg/csi"
"github.com/kubernetes-csi/external-resizer/pkg/util"

"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"

csitranslationlib "k8s.io/csi-translation-lib"
"k8s.io/klog"
)

Expand Down Expand Up @@ -107,7 +110,18 @@ func (r *csiResizer) Name() string {
return r.name
}

func (r *csiResizer) CanSupport(pv *v1.PersistentVolume) bool {
// CanSupport returns whether the PV is supported by resizer
// Resizer will resize the volume if it is CSI volume or is migration enabled in-tree volume
func (r *csiResizer) CanSupport(pv *v1.PersistentVolume, pvc *v1.PersistentVolumeClaim) bool {
resizerName := pvc.Annotations[util.VolumeResizerKey]
// resizerName will be CSI driver name when CSI migration is enabled
// otherwise, it will be in-tree plugin name
// r.name is the CSI driver name, return true only when they match
// and the CSI driver is migrated
if csitranslationlib.IsMigratedCSIDriverByName(r.name) && resizerName == r.name {
return true
}

source := pv.Spec.CSI
if source == nil {
klog.V(4).Infof("PV %s is not a CSI volume, skip it", pv.Name)
Expand All @@ -120,14 +134,32 @@ func (r *csiResizer) CanSupport(pv *v1.PersistentVolume) bool {
return true
}

// Resize resizes the persistence volume given request size
// It supports both CSI volume and migrated in-tree volume
func (r *csiResizer) Resize(pv *v1.PersistentVolume, requestSize resource.Quantity) (resource.Quantity, bool, error) {
oldSize := pv.Spec.Capacity[v1.ResourceStorage]

source := pv.Spec.CSI
if source == nil {
return oldSize, false, errors.New("not a CSI volume")
var volumeID string
var source *v1.CSIPersistentVolumeSource
if pv.Spec.CSI != nil {
// handle CSI volume
source = pv.Spec.CSI
volumeID = source.VolumeHandle
} else {
if csitranslationlib.IsMigratedCSIDriverByName(r.name) {
// handle migrated in-tree volume
csiPV, err := csitranslationlib.TranslateInTreePVToCSI(pv)
if err != nil {
return oldSize, false, fmt.Errorf("failed to translate persistent volume: %v", err)
}
source = csiPV.Spec.CSI
volumeID = source.VolumeHandle
} else {
// non-migrated in-tree volume
return oldSize, false, fmt.Errorf("volume %v is not migrated to CSI", pv.Name)
}
}
volumeID := source.VolumeHandle

if len(volumeID) == 0 {
return oldSize, false, errors.New("empty volume handle")
}
Expand All @@ -148,6 +180,7 @@ func (r *csiResizer) Resize(pv *v1.PersistentVolume, requestSize resource.Quanti
if err != nil {
return oldSize, nodeResizeRequired, err
}

return *resource.NewQuantity(newSizeBytes, resource.BinarySI), nodeResizeRequired, err
}

Expand Down
Loading

0 comments on commit 24780ba

Please sign in to comment.