Skip to content

Commit

Permalink
Implement CSI migration logic for volume resize
Browse files Browse the repository at this point in the history
* Using PVC annotation for sychronication between in-tree resizer and extternal resizer
* Modify enqueue condition for resizer migration
* Add unit tests
  • Loading branch information
Cheng Pan committed Jun 23, 2019
1 parent ad72116 commit 83d5dff
Show file tree
Hide file tree
Showing 17 changed files with 1,390 additions and 16 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.

11 changes: 9 additions & 2 deletions pkg/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,18 @@ 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 annotation is missing from old PVC
// but present in the new PVC. This is needed for CSI migration
if newSize.Cmp(oldSize) > 0 || (newResizerName != "" && oldResizerName == "") {
ctrl.addPVC(newObj)
}
}
Expand Down Expand Up @@ -249,7 +256,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: 37 additions & 6 deletions pkg/resizer/csi_resizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ 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"
Expand All @@ -33,6 +34,8 @@ import (
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
storagev1listers "k8s.io/client-go/listers/storage/v1"

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

Expand Down Expand Up @@ -118,7 +121,14 @@ 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]
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 @@ -131,14 +141,30 @@ 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
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)
}
volumeID = csiPV.Spec.CSI.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 Down Expand Up @@ -167,7 +193,12 @@ 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

if pv.Spec.VolumeMode == nil || *pv.Spec.VolumeMode == v1.PersistentVolumeFilesystem {
return *resource.NewQuantity(newSizeBytes, resource.BinarySI), nodeResizeRequired, err
}

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

func getDriverName(client csi.Client, timeout time.Duration) (string, error) {
Expand Down
Loading

0 comments on commit 83d5dff

Please sign in to comment.