Merge pull request #57017 from andyzhangx/azurefile-growsize
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>. add PV size grow feature for azure file **What this PR does / why we need it**: According to kubernetes/features#284, add size grow feature for azure file **Which issue(s) this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when PR gets merged)*: Fixes #56462 **Special notes for your reviewer**: Since azure file is using SMB 3.0 protocal, there is no necessary to resize filesystem on agent side, the agent node will detect the changed size automatically. **Release note**: ``` add size grow feature for azure file ``` /sig azure @gnufied @rootfs @brendandburns
This commit is contained in:
commit
ffda1e2200
@ -102,6 +102,7 @@ func ProbeExpandableVolumePlugins(config componentconfig.VolumeConfiguration) []
|
|||||||
allPlugins = append(allPlugins, glusterfs.ProbeVolumePlugins()...)
|
allPlugins = append(allPlugins, glusterfs.ProbeVolumePlugins()...)
|
||||||
allPlugins = append(allPlugins, rbd.ProbeVolumePlugins()...)
|
allPlugins = append(allPlugins, rbd.ProbeVolumePlugins()...)
|
||||||
allPlugins = append(allPlugins, azure_dd.ProbeVolumePlugins()...)
|
allPlugins = append(allPlugins, azure_dd.ProbeVolumePlugins()...)
|
||||||
|
allPlugins = append(allPlugins, azure_file.ProbeVolumePlugins()...)
|
||||||
allPlugins = append(allPlugins, photon_pd.ProbeVolumePlugins()...)
|
allPlugins = append(allPlugins, photon_pd.ProbeVolumePlugins()...)
|
||||||
allPlugins = append(allPlugins, scaleio.ProbeVolumePlugins()...)
|
allPlugins = append(allPlugins, scaleio.ProbeVolumePlugins()...)
|
||||||
allPlugins = append(allPlugins, storageos.ProbeVolumePlugins()...)
|
allPlugins = append(allPlugins, storageos.ProbeVolumePlugins()...)
|
||||||
|
@ -930,7 +930,7 @@ func (fRTC *fakeRouteTablesClient) Get(resourceGroupName string, routeTableName
|
|||||||
type fakeFileClient struct {
|
type fakeFileClient struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fFC *fakeFileClient) createFileShare(accountName, accountKey, name string, sizeGB int) error {
|
func (fFC *fakeFileClient) createFileShare(accountName, accountKey, name string, sizeGiB int) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -938,6 +938,10 @@ func (fFC *fakeFileClient) deleteFileShare(accountName, accountKey, name string)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fFC *fakeFileClient) resizeFileShare(accountName, accountKey, name string, sizeGiB int) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type fakeStorageAccountClient struct {
|
type fakeStorageAccountClient struct {
|
||||||
mutex *sync.Mutex
|
mutex *sync.Mutex
|
||||||
FakeStore map[string]map[string]storage.Account
|
FakeStore map[string]map[string]storage.Account
|
||||||
|
@ -31,24 +31,29 @@ const (
|
|||||||
// FileClient is the interface for creating file shares, interface for test
|
// FileClient is the interface for creating file shares, interface for test
|
||||||
// injection.
|
// injection.
|
||||||
type FileClient interface {
|
type FileClient interface {
|
||||||
createFileShare(accountName, accountKey, name string, sizeGB int) error
|
createFileShare(accountName, accountKey, name string, sizeGiB int) error
|
||||||
deleteFileShare(accountName, accountKey, name string) error
|
deleteFileShare(accountName, accountKey, name string) error
|
||||||
|
resizeFileShare(accountName, accountKey, name string, sizeGiB int) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// create file share
|
// create file share
|
||||||
func (az *Cloud) createFileShare(accountName, accountKey, name string, sizeGB int) error {
|
func (az *Cloud) createFileShare(accountName, accountKey, name string, sizeGiB int) error {
|
||||||
return az.FileClient.createFileShare(accountName, accountKey, name, sizeGB)
|
return az.FileClient.createFileShare(accountName, accountKey, name, sizeGiB)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (az *Cloud) deleteFileShare(accountName, accountKey, name string) error {
|
func (az *Cloud) deleteFileShare(accountName, accountKey, name string) error {
|
||||||
return az.FileClient.deleteFileShare(accountName, accountKey, name)
|
return az.FileClient.deleteFileShare(accountName, accountKey, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (az *Cloud) resizeFileShare(accountName, accountKey, name string, sizeGiB int) error {
|
||||||
|
return az.FileClient.resizeFileShare(accountName, accountKey, name, sizeGiB)
|
||||||
|
}
|
||||||
|
|
||||||
type azureFileClient struct {
|
type azureFileClient struct {
|
||||||
env azure.Environment
|
env azure.Environment
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *azureFileClient) createFileShare(accountName, accountKey, name string, sizeGB int) error {
|
func (f *azureFileClient) createFileShare(accountName, accountKey, name string, sizeGiB int) error {
|
||||||
fileClient, err := f.getFileSvcClient(accountName, accountKey)
|
fileClient, err := f.getFileSvcClient(accountName, accountKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -62,7 +67,7 @@ func (f *azureFileClient) createFileShare(accountName, accountKey, name string,
|
|||||||
if err = share.Create(nil); err != nil {
|
if err = share.Create(nil); err != nil {
|
||||||
return fmt.Errorf("failed to create file share, err: %v", err)
|
return fmt.Errorf("failed to create file share, err: %v", err)
|
||||||
}
|
}
|
||||||
share.Properties.Quota = sizeGB
|
share.Properties.Quota = sizeGiB
|
||||||
if err = share.SetProperties(nil); err != nil {
|
if err = share.SetProperties(nil); err != nil {
|
||||||
if err := share.Delete(nil); err != nil {
|
if err := share.Delete(nil); err != nil {
|
||||||
glog.Errorf("Error deleting share: %v", err)
|
glog.Errorf("Error deleting share: %v", err)
|
||||||
@ -81,6 +86,25 @@ func (f *azureFileClient) deleteFileShare(accountName, accountKey, name string)
|
|||||||
return fileClient.GetShareReference(name).Delete(nil)
|
return fileClient.GetShareReference(name).Delete(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *azureFileClient) resizeFileShare(accountName, accountKey, name string, sizeGiB int) error {
|
||||||
|
fileClient, err := f.getFileSvcClient(accountName, accountKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
share := fileClient.GetShareReference(name)
|
||||||
|
if share.Properties.Quota >= sizeGiB {
|
||||||
|
glog.Warningf("file share size(%dGi) is already greater or equal than requested size(%dGi), accountName: %s, shareName: %s",
|
||||||
|
share.Properties.Quota, sizeGiB, accountName, name)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
share.Properties.Quota = sizeGiB
|
||||||
|
if err = share.SetProperties(nil); err != nil {
|
||||||
|
return fmt.Errorf("failed to set quota on file share %s, err: %v", name, err)
|
||||||
|
}
|
||||||
|
glog.V(4).Infof("resize file share completed, accountName: %s, shareName: %s, sizeGiB: %d", accountName, name, sizeGiB)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (f *azureFileClient) getFileSvcClient(accountName, accountKey string) (*azs.FileServiceClient, error) {
|
func (f *azureFileClient) getFileSvcClient(accountName, accountKey string) (*azs.FileServiceClient, error) {
|
||||||
fileClient, err := azs.NewClient(accountName, accountKey, f.env.StorageEndpointSuffix, azs.DefaultAPIVersion, useHTTPS)
|
fileClient, err := azs.NewClient(accountName, accountKey, f.env.StorageEndpointSuffix, azs.DefaultAPIVersion, useHTTPS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -23,7 +23,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// CreateFileShare creates a file share, using a matching storage account
|
// CreateFileShare creates a file share, using a matching storage account
|
||||||
func (az *Cloud) CreateFileShare(name, storageAccount, storageType, location string, requestGB int) (string, string, error) {
|
func (az *Cloud) CreateFileShare(name, storageAccount, storageType, location string, requestGiB int) (string, string, error) {
|
||||||
var errResult error
|
var errResult error
|
||||||
accounts := []accountWithLocation{}
|
accounts := []accountWithLocation{}
|
||||||
if len(storageAccount) > 0 {
|
if len(storageAccount) > 0 {
|
||||||
@ -46,7 +46,7 @@ func (az *Cloud) CreateFileShare(name, storageAccount, storageType, location str
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if innerErr = az.createFileShare(account.Name, key, name, requestGB); innerErr != nil {
|
if innerErr = az.createFileShare(account.Name, key, name, requestGiB); innerErr != nil {
|
||||||
errResult = fmt.Errorf("failed to create share %s in account %s: %v", name, account.Name, innerErr)
|
errResult = fmt.Errorf("failed to create share %s in account %s: %v", name, account.Name, innerErr)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -69,3 +69,8 @@ func (az *Cloud) DeleteFileShare(accountName, key, name string) error {
|
|||||||
glog.V(4).Infof("share %s deleted", name)
|
glog.V(4).Infof("share %s deleted", name)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ResizeFileShare resizes a file share
|
||||||
|
func (az *Cloud) ResizeFileShare(accountName, accountKey, name string, sizeGiB int) error {
|
||||||
|
return az.resizeFileShare(accountName, accountKey, name, sizeGiB)
|
||||||
|
}
|
||||||
|
@ -21,16 +21,16 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
"k8s.io/kubernetes/pkg/cloudprovider"
|
||||||
|
"k8s.io/kubernetes/pkg/cloudprovider/providers/azure"
|
||||||
"k8s.io/kubernetes/pkg/util/mount"
|
"k8s.io/kubernetes/pkg/util/mount"
|
||||||
kstrings "k8s.io/kubernetes/pkg/util/strings"
|
kstrings "k8s.io/kubernetes/pkg/util/strings"
|
||||||
"k8s.io/kubernetes/pkg/volume"
|
"k8s.io/kubernetes/pkg/volume"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
|
||||||
"k8s.io/kubernetes/pkg/cloudprovider"
|
|
||||||
"k8s.io/kubernetes/pkg/cloudprovider/providers/azure"
|
|
||||||
"k8s.io/kubernetes/pkg/volume/util"
|
"k8s.io/kubernetes/pkg/volume/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -45,6 +45,7 @@ type azureFilePlugin struct {
|
|||||||
|
|
||||||
var _ volume.VolumePlugin = &azureFilePlugin{}
|
var _ volume.VolumePlugin = &azureFilePlugin{}
|
||||||
var _ volume.PersistentVolumePlugin = &azureFilePlugin{}
|
var _ volume.PersistentVolumePlugin = &azureFilePlugin{}
|
||||||
|
var _ volume.ExpandableVolumePlugin = &azureFilePlugin{}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
azureFilePluginName = "kubernetes.io/azure-file"
|
azureFilePluginName = "kubernetes.io/azure-file"
|
||||||
@ -139,6 +140,41 @@ func (plugin *azureFilePlugin) newUnmounterInternal(volName string, podUID types
|
|||||||
}}, nil
|
}}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (plugin *azureFilePlugin) RequiresFSResize() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (plugin *azureFilePlugin) ExpandVolumeDevice(
|
||||||
|
spec *volume.Spec,
|
||||||
|
newSize resource.Quantity,
|
||||||
|
oldSize resource.Quantity) (resource.Quantity, error) {
|
||||||
|
|
||||||
|
if spec.PersistentVolume != nil || spec.PersistentVolume.Spec.AzureFile == nil {
|
||||||
|
return oldSize, fmt.Errorf("invalid PV spec")
|
||||||
|
}
|
||||||
|
shareName := spec.PersistentVolume.Spec.AzureFile.ShareName
|
||||||
|
azure, err := getAzureCloudProvider(plugin.host.GetCloudProvider())
|
||||||
|
if err != nil {
|
||||||
|
return oldSize, err
|
||||||
|
}
|
||||||
|
|
||||||
|
secretName, secretNamespace, err := getSecretNameAndNamespace(spec, spec.PersistentVolume.Spec.ClaimRef.Namespace)
|
||||||
|
if err != nil {
|
||||||
|
return oldSize, err
|
||||||
|
}
|
||||||
|
|
||||||
|
accountName, accountKey, err := (&azureSvc{}).GetAzureCredentials(plugin.host, secretNamespace, secretName)
|
||||||
|
if err != nil {
|
||||||
|
return oldSize, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := azure.ResizeFileShare(accountName, accountKey, shareName, int(volume.RoundUpToGiB(newSize))); err != nil {
|
||||||
|
return oldSize, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return newSize, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (plugin *azureFilePlugin) ConstructVolumeSpec(volName, mountPath string) (*volume.Spec, error) {
|
func (plugin *azureFilePlugin) ConstructVolumeSpec(volName, mountPath string) (*volume.Spec, error) {
|
||||||
azureVolume := &v1.Volume{
|
azureVolume := &v1.Volume{
|
||||||
Name: volName,
|
Name: volName,
|
||||||
|
@ -38,9 +38,11 @@ var _ volume.ProvisionableVolumePlugin = &azureFilePlugin{}
|
|||||||
// azure cloud provider should implement it
|
// azure cloud provider should implement it
|
||||||
type azureCloudProvider interface {
|
type azureCloudProvider interface {
|
||||||
// create a file share
|
// create a file share
|
||||||
CreateFileShare(name, storageAccount, storageType, location string, requestGB int) (string, string, error)
|
CreateFileShare(name, storageAccount, storageType, location string, requestGiB int) (string, string, error)
|
||||||
// delete a file share
|
// delete a file share
|
||||||
DeleteFileShare(accountName, key, name string) error
|
DeleteFileShare(accountName, key, name string) error
|
||||||
|
// resize a file share
|
||||||
|
ResizeFileShare(accountName, accountKey, name string, sizeGiB int) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type azureFileDeleter struct {
|
type azureFileDeleter struct {
|
||||||
@ -141,7 +143,7 @@ func (a *azureFileProvisioner) Provision() (*v1.PersistentVolume, error) {
|
|||||||
name = strings.Replace(name, "--", "-", -1)
|
name = strings.Replace(name, "--", "-", -1)
|
||||||
capacity := a.options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)]
|
capacity := a.options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)]
|
||||||
requestBytes := capacity.Value()
|
requestBytes := capacity.Value()
|
||||||
requestGB := int(volume.RoundUpSize(requestBytes, 1024*1024*1024))
|
requestGiB := int(volume.RoundUpSize(requestBytes, 1024*1024*1024))
|
||||||
secretNamespace := a.options.PVC.Namespace
|
secretNamespace := a.options.PVC.Namespace
|
||||||
// Apply ProvisionerParameters (case-insensitive). We leave validation of
|
// Apply ProvisionerParameters (case-insensitive). We leave validation of
|
||||||
// the values to the cloud provider.
|
// the values to the cloud provider.
|
||||||
@ -164,7 +166,7 @@ func (a *azureFileProvisioner) Provision() (*v1.PersistentVolume, error) {
|
|||||||
return nil, fmt.Errorf("claim.Spec.Selector is not supported for dynamic provisioning on Azure file")
|
return nil, fmt.Errorf("claim.Spec.Selector is not supported for dynamic provisioning on Azure file")
|
||||||
}
|
}
|
||||||
|
|
||||||
account, key, err := a.azureProvider.CreateFileShare(name, account, sku, location, requestGB)
|
account, key, err := a.azureProvider.CreateFileShare(name, account, sku, location, requestGiB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -187,7 +189,7 @@ func (a *azureFileProvisioner) Provision() (*v1.PersistentVolume, error) {
|
|||||||
PersistentVolumeReclaimPolicy: a.options.PersistentVolumeReclaimPolicy,
|
PersistentVolumeReclaimPolicy: a.options.PersistentVolumeReclaimPolicy,
|
||||||
AccessModes: a.options.PVC.Spec.AccessModes,
|
AccessModes: a.options.PVC.Spec.AccessModes,
|
||||||
Capacity: v1.ResourceList{
|
Capacity: v1.ResourceList{
|
||||||
v1.ResourceName(v1.ResourceStorage): resource.MustParse(fmt.Sprintf("%dGi", requestGB)),
|
v1.ResourceName(v1.ResourceStorage): resource.MustParse(fmt.Sprintf("%dGi", requestGiB)),
|
||||||
},
|
},
|
||||||
PersistentVolumeSource: v1.PersistentVolumeSource{
|
PersistentVolumeSource: v1.PersistentVolumeSource{
|
||||||
AzureFile: &v1.AzureFilePersistentVolumeSource{
|
AzureFile: &v1.AzureFilePersistentVolumeSource{
|
||||||
|
@ -161,5 +161,8 @@ func (pvcr *persistentVolumeClaimResize) checkVolumePlugin(pv *api.PersistentVol
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if pv.Spec.AzureFile != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user