Implement resizing support for GCE

Fix GCE attacher test
Update bazel files
This commit is contained in:
Hemant Kumar 2017-11-20 13:02:13 -05:00
parent 2f2a643684
commit 7be94c4b06
8 changed files with 141 additions and 4 deletions

View File

@ -67,6 +67,7 @@ go_library(
"//vendor/google.golang.org/api/googleapi: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/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/fields:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",

View File

@ -24,6 +24,7 @@ import (
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/kubernetes/pkg/cloudprovider"
@ -90,6 +91,9 @@ type diskServiceManager interface {
instanceName string,
devicePath string) (gceObject, error)
ResizeDiskOnCloudProvider(disk *GCEDisk, sizeGb int64, zone string) (gceObject, error)
RegionalResizeDiskOnCloudProvider(disk *GCEDisk, sizeGb int64) (gceObject, error)
// Gets the persistent disk from GCE with the given diskName.
GetDiskFromCloudProvider(zone string, diskName string) (*GCEDisk, error)
@ -264,6 +268,7 @@ func (manager *gceServiceManager) GetDiskFromCloudProvider(
Name: diskAlpha.Name,
Kind: diskAlpha.Kind,
Type: diskAlpha.Type,
SizeGb: diskAlpha.SizeGb,
}, nil
}
@ -289,6 +294,7 @@ func (manager *gceServiceManager) GetDiskFromCloudProvider(
Name: diskStable.Name,
Kind: diskStable.Kind,
Type: diskStable.Type,
SizeGb: diskStable.SizeGb,
}, nil
}
@ -313,6 +319,7 @@ func (manager *gceServiceManager) GetRegionalDiskFromCloudProvider(
Name: diskAlpha.Name,
Kind: diskAlpha.Kind,
Type: diskAlpha.Type,
SizeGb: diskAlpha.SizeGb,
}, nil
}
@ -469,6 +476,30 @@ func (manager *gceServiceManager) getRegionFromZone(zoneInfo zoneType) (string,
return region, nil
}
func (manager *gceServiceManager) ResizeDiskOnCloudProvider(disk *GCEDisk, sizeGb int64, zone string) (gceObject, error) {
if manager.gce.AlphaFeatureGate.Enabled(AlphaFeatureGCEDisk) {
resizeServiceRequest := &computealpha.DisksResizeRequest{
SizeGb: sizeGb,
}
return manager.gce.serviceAlpha.Disks.Resize(manager.gce.projectID, zone, disk.Name, resizeServiceRequest).Do()
}
resizeServiceRequest := &compute.DisksResizeRequest{
SizeGb: sizeGb,
}
return manager.gce.service.Disks.Resize(manager.gce.projectID, zone, disk.Name, resizeServiceRequest).Do()
}
func (manager *gceServiceManager) RegionalResizeDiskOnCloudProvider(disk *GCEDisk, sizeGb int64) (gceObject, error) {
if manager.gce.AlphaFeatureGate.Enabled(AlphaFeatureGCEDisk) {
resizeServiceRequest := &computealpha.RegionDisksResizeRequest{
SizeGb: sizeGb,
}
return manager.gce.serviceAlpha.RegionDisks.Resize(manager.gce.projectID, disk.Region, disk.Name, resizeServiceRequest).Do()
}
return nil, fmt.Errorf("RegionalResizeDiskOnCloudProvider is a regional PD feature and is only available via the GCE Alpha API. Enable \"GCEDiskAlphaAPI\" in the list of \"alpha-features\" in \"gce.conf\" to use the feature.")
}
// Disks is interface for manipulation with GCE PDs.
type Disks interface {
// AttachDisk attaches given disk to the node with the specified NodeName.
@ -498,6 +529,9 @@ type Disks interface {
// DeleteDisk deletes PD.
DeleteDisk(diskToDelete string) error
// ResizeDisk resizes PD and returns new disk size
ResizeDisk(diskToResize string, oldSize resource.Quantity, newSize resource.Quantity) (resource.Quantity, error)
// GetAutoLabelsForPD returns labels to apply to PersistentVolume
// representing this PD, namely failure domain and zone.
// zone can be provided to specify the zone for the PD,
@ -517,6 +551,7 @@ type GCEDisk struct {
Name string
Kind string
Type string
SizeGb int64
}
type zoneType interface {
@ -801,6 +836,57 @@ func (gce *GCECloud) DeleteDisk(diskToDelete string) error {
return err
}
// ResizeDisk expands given disk and returns new disk size
func (gce *GCECloud) ResizeDisk(diskToResize string, oldSize resource.Quantity, newSize resource.Quantity) (resource.Quantity, error) {
disk, err := gce.GetDiskByNameUnknownZone(diskToResize)
if err != nil {
return oldSize, err
}
requestBytes := newSize.Value()
// GCE resizes in chunks of GBs (not GiB)
requestGB := volume.RoundUpSize(requestBytes, 1000*1000*1000)
newSizeQuant := resource.MustParse(fmt.Sprintf("%dG", requestGB))
// If disk is already of size equal or greater than requested size, we simply return
if disk.SizeGb >= requestGB {
return newSizeQuant, nil
}
var mc *metricContext
switch zoneInfo := disk.ZoneInfo.(type) {
case singleZone:
mc = newDiskMetricContextZonal("resize", disk.Region, zoneInfo.zone)
resizeOp, err := gce.manager.ResizeDiskOnCloudProvider(disk, requestGB, zoneInfo.zone)
if err != nil {
return oldSize, mc.Observe(err)
}
waitErr := gce.manager.WaitForZoneOp(resizeOp, zoneInfo.zone, mc)
if waitErr != nil {
return oldSize, waitErr
}
return newSizeQuant, nil
case multiZone:
mc = newDiskMetricContextRegional("resize", disk.Region)
resizeOp, err := gce.manager.RegionalResizeDiskOnCloudProvider(disk, requestGB)
if err != nil {
return oldSize, mc.Observe(err)
}
waitErr := gce.manager.WaitForRegionalOp(resizeOp, mc)
if waitErr != nil {
return oldSize, waitErr
}
return newSizeQuant, nil
case nil:
return oldSize, fmt.Errorf("PD has nil ZoneInfo: %v", disk)
default:
return oldSize, fmt.Errorf("disk.ZoneInfo has unexpected type %T", zoneInfo)
}
}
// Builds the labels that should be automatically added to a PersistentVolume backed by a GCE PD
// Specifically, this builds FailureDomain (zone) and Region labels.
// The PersistentVolumeLabel admission controller calls this and adds the labels when a PV is created.

View File

@ -897,6 +897,19 @@ func (manager *FakeServiceManager) GetRegionalDiskFromCloudProvider(
}, nil
}
func (manager *FakeServiceManager) ResizeDiskOnCloudProvider(
disk *GCEDisk,
size int64,
zone string) (gceObject, error) {
panic("Not implmented")
}
func (manager *FakeServiceManager) RegionalResizeDiskOnCloudProvider(
disk *GCEDisk,
size int64) (gceObject, error) {
panic("Not implemented")
}
/**
* Disk info is removed from the FakeServiceManager.
*/

View File

@ -47,6 +47,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/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",

View File

@ -22,6 +22,7 @@ import (
"testing"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/kubernetes/pkg/volume"
volumetest "k8s.io/kubernetes/pkg/volume/testing"
@ -373,3 +374,10 @@ func (testcase *testcase) DeleteDisk(diskToDelete string) error {
func (testcase *testcase) GetAutoLabelsForPD(name string, zone string) (map[string]string, error) {
return map[string]string{}, errors.New("Not implemented")
}
func (testcase *testcase) ResizeDisk(
diskName string,
oldSize resource.Quantity,
newSize resource.Quantity) (resource.Quantity, error) {
return oldSize, errors.New("Not implemented")
}

View File

@ -47,6 +47,7 @@ var _ volume.VolumePlugin = &gcePersistentDiskPlugin{}
var _ volume.PersistentVolumePlugin = &gcePersistentDiskPlugin{}
var _ volume.DeletableVolumePlugin = &gcePersistentDiskPlugin{}
var _ volume.ProvisionableVolumePlugin = &gcePersistentDiskPlugin{}
var _ volume.ExpandableVolumePlugin = &gcePersistentDiskPlugin{}
const (
gcePersistentDiskPluginName = "kubernetes.io/gce-pd"
@ -190,6 +191,28 @@ func (plugin *gcePersistentDiskPlugin) newProvisionerInternal(options volume.Vol
}, nil
}
func (plugin *gcePersistentDiskPlugin) RequiresFSResize() bool {
return true
}
func (plugin *gcePersistentDiskPlugin) ExpandVolumeDevice(
spec *volume.Spec,
newSize resource.Quantity,
oldSize resource.Quantity) (resource.Quantity, error) {
cloud, err := getCloudProvider(plugin.host.GetCloudProvider())
if err != nil {
return oldSize, err
}
pdName := spec.PersistentVolume.Spec.GCEPersistentDisk.PDName
updatedQuantity, err := cloud.ResizeDisk(pdName, oldSize, newSize)
if err != nil {
return oldSize, err
}
return updatedQuantity, nil
}
func (plugin *gcePersistentDiskPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) {
mounter := plugin.host.GetMounter(plugin.GetPluginName())
pluginDir := plugin.host.GetPluginDir(plugin.GetPluginName())

View File

@ -454,8 +454,9 @@ func (og *operationGenerator) GenerateMountVolumeFunc(
glog.Infof(volumeToMount.GenerateMsgDetailed("MountVolume.WaitForAttach succeeded", fmt.Sprintf("DevicePath %q", devicePath)))
mounter := og.volumePluginMgr.Host.GetMounter(volumePlugin.GetPluginName())
resizeError := og.resizeFileSystem(volumeToMount, devicePath, mounter)
// resizeFileSystem will resize the file system if user has requested a resize of
// underlying persistent volume and is allowed to do so.
resizeError := og.resizeFileSystem(volumeToMount, devicePath, volumePlugin.GetPluginName())
if resizeError != nil {
return volumeToMount.GenerateErrorDetailed("MountVolume.Resize failed", resizeError)
@ -538,12 +539,12 @@ func (og *operationGenerator) GenerateMountVolumeFunc(
}, volumePlugin.GetPluginName(), nil
}
func (og *operationGenerator) resizeFileSystem(volumeToMount VolumeToMount, devicePath string, mounter mount.Interface) error {
func (og *operationGenerator) resizeFileSystem(volumeToMount VolumeToMount, devicePath string, pluginName string) error {
if !utilfeature.DefaultFeatureGate.Enabled(features.ExpandPersistentVolumes) {
glog.V(6).Infof("Resizing is not enabled for this volume %s", volumeToMount.VolumeName)
return nil
}
mounter := og.volumePluginMgr.Host.GetMounter(pluginName)
// Get expander, if possible
expandableVolumePlugin, _ :=
og.volumePluginMgr.FindExpandablePluginBySpec(volumeToMount.VolumeSpec)

View File

@ -155,6 +155,10 @@ func (pvcr *persistentVolumeClaimResize) checkVolumePlugin(pv *api.PersistentVol
if pv.Spec.Cinder != nil {
return true
}
if pv.Spec.GCEPersistentDisk != nil {
return true
}
return false
}