Skip to content
This repository has been archived by the owner on Mar 22, 2018. It is now read-only.

Commit

Permalink
Merge pull request #51498 from NickrenREN/pvc-resize-cinder
Browse files Browse the repository at this point in the history
Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

Implement volume resize for cinder

**What this PR does / why we need it**:
resize for cinder
xref: [resize proposal](kubernetes/community#657)

**Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: xref kubernetes/community#657
Follow up: #49727

**Special notes for your reviewer**:

**Release note**:
```release-note
Implement volume resize for cinder
```

wip, assign to myself first

/assign @NickrenREN
  • Loading branch information
Kubernetes Submit Queue committed Nov 22, 2017
2 parents 6edc12e + 71d59c8 commit a81422a
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 0 deletions.
2 changes: 2 additions & 0 deletions pkg/cloudprovider/providers/openstack/BUILD
Expand Up @@ -29,6 +29,7 @@ go_library(
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/github.com/gophercloud/gophercloud:go_default_library",
"//vendor/github.com/gophercloud/gophercloud/openstack:go_default_library",
"//vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/extensions/volumeactions:go_default_library",
"//vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes:go_default_library",
"//vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes:go_default_library",
"//vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/attachinterfaces:go_default_library",
Expand All @@ -51,6 +52,7 @@ go_library(
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
"//vendor/gopkg.in/gcfg.v1:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
Expand Down
64 changes: 64 additions & 0 deletions pkg/cloudprovider/providers/openstack/openstack_volumes.go
Expand Up @@ -24,9 +24,11 @@ import (
"strings"
"time"

"k8s.io/apimachinery/pkg/api/resource"
k8s_volume "k8s.io/kubernetes/pkg/volume"

"github.com/gophercloud/gophercloud"
volumeexpand "github.com/gophercloud/gophercloud/openstack/blockstorage/extensions/volumeactions"
volumes_v1 "github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes"
volumes_v2 "github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes"
"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach"
Expand All @@ -39,6 +41,7 @@ type volumeService interface {
createVolume(opts VolumeCreateOpts) (string, string, error)
getVolume(volumeID string) (Volume, error)
deleteVolume(volumeName string) error
expandVolume(volumeID string, newSize int) error
}

// Volumes implementation for v1
Expand All @@ -64,6 +67,8 @@ type Volume struct {
Name string
// Current status of the volume.
Status string
// Volume size in GB
Size int
}

type VolumeCreateOpts struct {
Expand Down Expand Up @@ -139,6 +144,7 @@ func (volumes *VolumesV1) getVolume(volumeID string) (Volume, error) {
ID: volumeV1.ID,
Name: volumeV1.Name,
Status: volumeV1.Status,
Size: volumeV1.Size,
}

if len(volumeV1.Attachments) > 0 && volumeV1.Attachments[0]["server_id"] != nil {
Expand All @@ -162,6 +168,7 @@ func (volumes *VolumesV2) getVolume(volumeID string) (Volume, error) {
ID: volumeV2.ID,
Name: volumeV2.Name,
Status: volumeV2.Status,
Size: volumeV2.Size,
}

if len(volumeV2.Attachments) > 0 {
Expand All @@ -188,6 +195,30 @@ func (volumes *VolumesV2) deleteVolume(volumeID string) error {
return err
}

func (volumes *VolumesV1) expandVolume(volumeID string, newSize int) error {
startTime := time.Now()
create_opts := volumeexpand.ExtendSizeOpts{
NewSize: newSize,
}
err := volumeexpand.ExtendSize(volumes.blockstorage, volumeID, create_opts).ExtractErr()
timeTaken := time.Since(startTime).Seconds()
recordOpenstackOperationMetric("expand_volume", timeTaken, err)

return err
}

func (volumes *VolumesV2) expandVolume(volumeID string, newSize int) error {
startTime := time.Now()
create_opts := volumeexpand.ExtendSizeOpts{
NewSize: newSize,
}
err := volumeexpand.ExtendSize(volumes.blockstorage, volumeID, create_opts).ExtractErr()
timeTaken := time.Since(startTime).Seconds()
recordOpenstackOperationMetric("expand_volume", timeTaken, err)

return err
}

func (os *OpenStack) OperationPending(diskName string) (bool, string, error) {
volume, err := os.getVolume(diskName)
if err != nil {
Expand Down Expand Up @@ -274,6 +305,39 @@ func (os *OpenStack) DetachDisk(instanceID, volumeID string) error {
return nil
}

// ExpandVolume expands the size of specific cinder volume (in GiB)
func (os *OpenStack) ExpandVolume(volumeID string, oldSize resource.Quantity, newSize resource.Quantity) (resource.Quantity, error) {
volume, err := os.getVolume(volumeID)
if err != nil {
return oldSize, err
}
if volume.Status != VolumeAvailableStatus {
// cinder volume can not be expanded if its status is not available
return oldSize, fmt.Errorf("volume status is not available")
}

volSizeBytes := newSize.Value()
// Cinder works with gigabytes, convert to GiB with rounding up
volSizeGB := int(k8s_volume.RoundUpSize(volSizeBytes, 1024*1024*1024))
newSizeQuant := resource.MustParse(fmt.Sprintf("%dGi", volSizeGB))

// if volume size equals to or greater than the newSize, return nil
if volume.Size >= volSizeGB {
return newSizeQuant, nil
}

volumes, err := os.volumeService("")
if err != nil {
return oldSize, err
}

err = volumes.expandVolume(volumeID, volSizeGB)
if err != nil {
return oldSize, err
}
return newSizeQuant, nil
}

// getVolume retrieves Volume by its ID.
func (os *OpenStack) getVolume(volumeID string) (Volume, error) {
volumes, err := os.volumeService("")
Expand Down
1 change: 1 addition & 0 deletions pkg/volume/cinder/BUILD
Expand Up @@ -52,6 +52,7 @@ go_test(
"//pkg/volume/testing:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
"//vendor/k8s.io/client-go/util/testing:go_default_library",
],
Expand Down
5 changes: 5 additions & 0 deletions pkg/volume/cinder/attacher_test.go
Expand Up @@ -22,6 +22,7 @@ import (
"testing"

"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/kubernetes/pkg/cloudprovider"
"k8s.io/kubernetes/pkg/volume"
volumetest "k8s.io/kubernetes/pkg/volume/testing"
Expand Down Expand Up @@ -583,6 +584,10 @@ func (testcase *testcase) InstanceID() (string, error) {
return testcase.instanceID, nil
}

func (testcase *testcase) ExpandVolume(volumeID string, oldSize resource.Quantity, newSize resource.Quantity) (resource.Quantity, error) {
return resource.Quantity{}, nil
}

func (testcase *testcase) DeleteVolume(volumeID string) error {
return errors.New("Not implemented")
}
Expand Down
26 changes: 26 additions & 0 deletions pkg/volume/cinder/cinder.go
Expand Up @@ -55,6 +55,7 @@ type CinderProvider interface {
DisksAreAttached(instanceID string, volumeIDs []string) (map[string]bool, error)
ShouldTrustDevicePath() bool
Instances() (cloudprovider.Instances, bool)
ExpandVolume(volumeID string, oldSize resource.Quantity, newSize resource.Quantity) (resource.Quantity, error)
}

type cinderPlugin struct {
Expand Down Expand Up @@ -227,6 +228,31 @@ func (plugin *cinderPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*
return volume.NewSpecFromVolume(cinderVolume), nil
}

var _ volume.ExpandableVolumePlugin = &cinderPlugin{}

func (plugin *cinderPlugin) ExpandVolumeDevice(spec *volume.Spec, newSize resource.Quantity, oldSize resource.Quantity) (resource.Quantity, error) {
cinder, _, err := getVolumeSource(spec)
if err != nil {
return oldSize, err
}
cloud, err := plugin.getCloudProvider()
if err != nil {
return oldSize, err
}

expandedSize, err := cloud.ExpandVolume(cinder.VolumeID, oldSize, newSize)
if err != nil {
return oldSize, err
}

glog.V(2).Infof("volume %s expanded to new size %d successfully", cinder.VolumeID, int(newSize.Value()))
return expandedSize, nil
}

func (plugin *cinderPlugin) RequiresFSResize() bool {
return true
}

// Abstract interface to PD operations.
type cdManager interface {
// Attaches the disk to the kubelet's host machine.
Expand Down

0 comments on commit a81422a

Please sign in to comment.