Skip to content

Commit

Permalink
Merge tag 'v0.5.0' into rebase-v0.5.0
Browse files Browse the repository at this point in the history
  • Loading branch information
jsafrane committed Apr 7, 2020
2 parents 2c57909 + 6a95232 commit d3aa7e6
Show file tree
Hide file tree
Showing 18 changed files with 1,249 additions and 887 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG-0.5.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Changelog since v0.4.0

## New Features

- Ability to customize PVC workqueue retry interval ([#75](https://github.com/kubernetes-csi/external-resizer/pull/75), [@zuzzas](https://github.com/zuzzas))

## Other Notable Changes

- - Pass volume capability to ControllerExpandVolume RPC call ([#70](https://github.com/kubernetes-csi/external-resizer/pull/70), [@gnufied](https://github.com/gnufied))
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ If your repo has certain guidelines for contribution, put them here ahead of the

- [Contributor License Agreement](https://git.k8s.io/community/CLA.md) Kubernetes projects require that you sign a Contributor License Agreement (CLA) before we can accept your pull requests
- [Kubernetes Contributor Guide](http://git.k8s.io/community/contributors/guide) - Main contributor documentation, or you can just jump directly to the [contributing section](http://git.k8s.io/community/contributors/guide#contributing)
- [Contributor Cheat Sheet](https://git.k8s.io/community/contributors/guide/contributor-cheatsheet.md) - Common resources for existing developers
- [Contributor Cheat Sheet](https://github.com/kubernetes/community/blob/master/contributors/guide/contributor-cheatsheet/README.md) - Common resources for existing developers

## Mentorship

Expand Down
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ This information reflects the head of this branch.

| Compatible with CSI Version | Container Image | Recommended K8s Version |
| ------------------------------------------------------------------------------------------ | -------------------------------| --------------- |
| [CSI Spec v1.1.0](https://github.com/container-storage-interface/spec/releases/tag/v1.1.0) | quay.io/k8scsi/csi-resizer | 1.16 |
| [CSI Spec v1.2.0](https://github.com/container-storage-interface/spec/releases/tag/v1.2.0) | quay.io/k8scsi/csi-resizer | 1.16 |



## Feature status
Expand Down Expand Up @@ -47,6 +48,10 @@ Note that the external-resizer does not scale with more replicas. Only one exter

* `--csiTimeout <duration>`: Timeout of all calls to CSI driver. It should be set to value that accommodates majority of `ControllerExpandVolume` calls. 15 seconds is used by default.

* `--retry-interval-start`: The starting value of the exponential backoff for failures. 1 second is used by default.

* `--retry-interval-max`: The exponential backoff maximum value. 5 minutes is used by default.

* `--workers <num>`: Number of simultaneously running `ControllerExpandVolume` operations. Default value is `10`.

* `--metrics-address`: The TCP network address where the prometheus metrics endpoint will run (example: `:8080` which corresponds to port 8080 on local host). The default is empty string, which means metrics endpoint is disabled.
Expand Down
8 changes: 7 additions & 1 deletion cmd/csi-resizer/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"context"
"flag"
"fmt"
"k8s.io/client-go/util/workqueue"
"os"
"time"

Expand All @@ -43,6 +44,9 @@ var (
csiTimeout = flag.Duration("csiTimeout", 15*time.Second, "Timeout for waiting for CSI driver socket.")
showVersion = flag.Bool("version", false, "Show version")

retryIntervalStart = flag.Duration("retry-interval-start", time.Second, "Initial retry interval of failed volume resize. It exponentially increases with each failure, up to retry-interval-max.")
retryIntervalMax = flag.Duration("retry-interval-max", 5*time.Minute, "Maximum retry interval of failed volume resize.")

enableLeaderElection = flag.Bool("leader-election", false, "Enable leader election.")
leaderElectionNamespace = flag.String("leader-election-namespace", "", "Namespace where the leader election resource lives. Defaults to the pod namespace if not set.")

Expand Down Expand Up @@ -82,7 +86,9 @@ func main() {
}

resizerName := csiResizer.Name()
rc := controller.NewResizeController(resizerName, csiResizer, kubeClient, *resyncPeriod, informerFactory)
rc := controller.NewResizeController(resizerName, csiResizer, kubeClient, *resyncPeriod, informerFactory,
workqueue.NewItemExponentialFailureRateLimiter(*retryIntervalStart, *retryIntervalMax),
)
run := func(ctx context.Context) {
informerFactory.Start(wait.NeverStop)
rc.Run(*workers, ctx)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/kubernetes-csi/external-resizer
go 1.12

require (
github.com/container-storage-interface/spec v1.1.0
github.com/container-storage-interface/spec v1.2.0
github.com/imdario/mergo v0.3.7 // indirect
github.com/kubernetes-csi/csi-lib-utils v0.7.0
google.golang.org/grpc v1.26.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/container-storage-interface/spec v1.1.0 h1:qPsTqtR1VUPvMPeK0UnCZMtXaKGyyLPG8gj/wG6VqMs=
github.com/container-storage-interface/spec v1.1.0/go.mod h1:6URME8mwIBbpVyZV93Ce5St17xBiQJQY67NDsuohiy4=
github.com/container-storage-interface/spec v1.2.0 h1:bD9KIVgaVKKkQ/UbVUY9kCaH/CJbhNxe0eeB4JeJV2s=
github.com/container-storage-interface/spec v1.2.0/go.mod h1:6URME8mwIBbpVyZV93Ce5St17xBiQJQY67NDsuohiy4=
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
Expand Down
5 changes: 3 additions & 2 deletions pkg/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ func NewResizeController(
resizer resizer.Resizer,
kubeClient kubernetes.Interface,
resyncPeriod time.Duration,
informerFactory informers.SharedInformerFactory) ResizeController {
informerFactory informers.SharedInformerFactory,
pvcRateLimiter workqueue.RateLimiter) ResizeController {
pvInformer := informerFactory.Core().V1().PersistentVolumes()
pvcInformer := informerFactory.Core().V1().PersistentVolumeClaims()

Expand All @@ -76,7 +77,7 @@ func NewResizeController(
v1.EventSource{Component: fmt.Sprintf("external-resizer %s", name)})

claimQueue := workqueue.NewNamedRateLimitingQueue(
workqueue.DefaultControllerRateLimiter(), fmt.Sprintf("%s-pvc", name))
pvcRateLimiter, fmt.Sprintf("%s-pvc", name))

ctrl := &resizeController{
name: name,
Expand Down
45 changes: 35 additions & 10 deletions pkg/controller/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package controller
import (
"context"
"fmt"
"k8s.io/client-go/util/workqueue"
"testing"
"time"

Expand All @@ -21,14 +22,17 @@ import (
)

func TestController(t *testing.T) {
blockVolumeMode := v1.PersistentVolumeBlock
fsVolumeMode := v1.PersistentVolumeFilesystem
for _, test := range []struct {
Name string
PVC *v1.PersistentVolumeClaim
PV *v1.PersistentVolume

CreateObjects bool
NodeResize bool
CallCSIExpand bool
CreateObjects bool
NodeResize bool
CallCSIExpand bool
expectBlockVolume bool
}{
{
Name: "Invalid key",
Expand All @@ -55,36 +59,45 @@ func TestController(t *testing.T) {
{
Name: "pv claimref does not have pvc UID",
PVC: createPVC(2, 1),
PV: createPV(1, "testPVC" /*pvcName*/, "test" /*pvcNamespace*/, "foobaz" /*pvcUID*/),
PV: createPV(1, "testPVC" /*pvcName*/, "test" /*pvcNamespace*/, "foobaz" /*pvcUID*/, &fsVolumeMode),
CallCSIExpand: false,
},
{
Name: "pv claimref does not have PVC namespace",
PVC: createPVC(2, 1),
PV: createPV(1, "testPVC" /*pvcName*/, "test1" /*pvcNamespace*/, "foobar" /*pvcUID*/),
PV: createPV(1, "testPVC" /*pvcName*/, "test1" /*pvcNamespace*/, "foobar" /*pvcUID*/, &fsVolumeMode),
CallCSIExpand: false,
},
{
Name: "pv claimref is nil",
PVC: createPVC(2, 1),
PV: createPV(1, "" /*pvcName*/, "test1" /*pvcNamespace*/, "foobar" /*pvcUID*/),
PV: createPV(1, "" /*pvcName*/, "test1" /*pvcNamespace*/, "foobar" /*pvcUID*/, &fsVolumeMode),
CallCSIExpand: false,
},
{
Name: "Resize PVC, no FS resize",
PVC: createPVC(2, 1),
PV: createPV(1, "testPVC", "test", "foobar"),
PV: createPV(1, "testPVC", "test", "foobar", &fsVolumeMode),
CreateObjects: true,
CallCSIExpand: true,
},
{
Name: "Resize PVC with FS resize",
PVC: createPVC(2, 1),
PV: createPV(1, "testPVC", "test", "foobar"),
PV: createPV(1, "testPVC", "test", "foobar", &fsVolumeMode),
CreateObjects: true,
NodeResize: true,
CallCSIExpand: true,
},
{
Name: "Block Resize PVC with FS resize",
PVC: createPVC(2, 1),
PV: createPV(1, "testPVC", "test", "foobar", &blockVolumeMode),
CreateObjects: true,
NodeResize: true,
CallCSIExpand: true,
expectBlockVolume: true,
},
} {
client := csi.NewMockClient("mock", test.NodeResize, true, true)
driverName, _ := client.GetDriverName(context.TODO())
Expand Down Expand Up @@ -123,7 +136,7 @@ func TestController(t *testing.T) {
t.Fatalf("Test %s: Unable to create resizer: %v", test.Name, err)
}

controller := NewResizeController(driverName, csiResizer, kubeClient, time.Second, informerFactory)
controller := NewResizeController(driverName, csiResizer, kubeClient, time.Second, informerFactory, workqueue.DefaultControllerRateLimiter())
err = controller.(*resizeController).syncPVC(fmt.Sprintf("%s/%s", test.PVC.Namespace, test.PVC.Name))
if err != nil {
t.Fatalf("Test %s: Unexpected error: %v", test.Name, err)
Expand All @@ -137,6 +150,16 @@ func TestController(t *testing.T) {
if !test.CallCSIExpand && expandCallCount > 0 {
t.Fatalf("for %s: expected no csi expand call, received csi expansion request", test.Name)
}

usedCapability := client.GetCapability()

if test.CallCSIExpand && test.expectBlockVolume && usedCapability.GetBlock() == nil {
t.Errorf("For %s: expected block accesstype got: %v", test.Name, usedCapability)
}

if test.CallCSIExpand && !test.expectBlockVolume && usedCapability.GetMount() == nil {
t.Errorf("For %s: expected mount accesstype got: %v", test.Name, usedCapability)
}
}
}

Expand Down Expand Up @@ -180,14 +203,15 @@ func createPVC(requestGB, capacityGB int) *v1.PersistentVolumeClaim {
}
}

func createPV(capacityGB int, pvcName, pvcNamespace string, pvcUID types.UID) *v1.PersistentVolume {
func createPV(capacityGB int, pvcName, pvcNamespace string, pvcUID types.UID, volumeMode *v1.PersistentVolumeMode) *v1.PersistentVolume {
capacity := quantityGB(capacityGB)

pv := &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
Name: "testPV",
},
Spec: v1.PersistentVolumeSpec{
AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce},
Capacity: map[v1.ResourceName]resource.Quantity{
v1.ResourceStorage: capacity,
},
Expand All @@ -197,6 +221,7 @@ func createPV(capacityGB int, pvcName, pvcNamespace string, pvcUID types.UID) *v
VolumeHandle: "foo",
},
},
VolumeMode: volumeMode,
},
}
if len(pvcName) > 0 {
Expand Down
12 changes: 7 additions & 5 deletions pkg/csi/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ type Client interface {

// Expand expands the volume to a new size at least as big as requestBytes.
// It returns the new size and whether the volume need expand operation on the node.
Expand(ctx context.Context, volumeID string, requestBytes int64, secrets map[string]string) (int64, bool, error)
Expand(ctx context.Context, volumeID string, requestBytes int64, secrets map[string]string, capability *csi.VolumeCapability) (int64, bool, error)
}

// New creates a new CSI client.
Expand Down Expand Up @@ -120,11 +120,13 @@ func (c *client) Expand(
ctx context.Context,
volumeID string,
requestBytes int64,
secrets map[string]string) (int64, bool, error) {
secrets map[string]string,
capability *csi.VolumeCapability) (int64, bool, error) {
req := &csi.ControllerExpandVolumeRequest{
Secrets: secrets,
VolumeId: volumeID,
CapacityRange: &csi.CapacityRange{RequiredBytes: requestBytes},
Secrets: secrets,
VolumeId: volumeID,
CapacityRange: &csi.CapacityRange{RequiredBytes: requestBytes},
VolumeCapability: capability,
}
resp, err := c.ctrlClient.ControllerExpandVolume(ctx, req)
if err != nil {
Expand Down
15 changes: 13 additions & 2 deletions pkg/csi/mock_client.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package csi

import "context"
import (
"context"

"github.com/container-storage-interface/spec/lib/go/csi"
)

func NewMockClient(
name string,
Expand All @@ -23,6 +27,7 @@ type MockClient struct {
supportsPluginControllerService bool
expandCalled int
usedSecrets map[string]string
usedCapability *csi.VolumeCapability
}

func (c *MockClient) GetDriverName(context.Context) (string, error) {
Expand All @@ -45,17 +50,23 @@ func (c *MockClient) Expand(
ctx context.Context,
volumeID string,
requestBytes int64,
secrets map[string]string) (int64, bool, error) {
secrets map[string]string,
capability *csi.VolumeCapability) (int64, bool, error) {
// TODO: Determine whether the operation succeeds or fails by parameters.
c.expandCalled++
c.usedSecrets = secrets
c.usedCapability = capability
return requestBytes, c.supportsNodeResize, nil
}

func (c *MockClient) GetExpandCount() int {
return c.expandCalled
}

func (c *MockClient) GetCapability() *csi.VolumeCapability {
return c.usedCapability
}

// GetSecrets returns secrets used for volume expansion
func (c *MockClient) GetSecrets() map[string]string {
return c.usedSecrets
Expand Down
Loading

0 comments on commit d3aa7e6

Please sign in to comment.