Commit bc2c79a4 authored by andyzhangx's avatar andyzhangx

add azure premium file support

update bazel and fix goftm use defaultStorageAccountKind fix test failure update godep license file fix staging godeps issue update staging godeps fix comments, use one API call for file creation
parent 12284c98
......@@ -80,7 +80,7 @@ func newBlobDiskController(common *controllerCommon) (*BlobDiskController, error
// If no storage account is given, search all the storage accounts associated with the resource group and pick one that
// fits storage type and location.
func (c *BlobDiskController) CreateVolume(blobName, accountName, accountType, location string, requestGB int) (string, string, int, error) {
account, key, err := c.common.cloud.ensureStorageAccount(accountName, accountType, c.common.resourceGroup, location, dedicatedDiskAccountNamePrefix)
account, key, err := c.common.cloud.ensureStorageAccount(accountName, accountType, string(defaultStorageAccountKind), c.common.resourceGroup, location, dedicatedDiskAccountNamePrefix)
if err != nil {
return "", "", 0, fmt.Errorf("could not get storage key for storage account %s: %v", accountName, err)
}
......@@ -491,7 +491,7 @@ func (c *BlobDiskController) createStorageAccount(storageAccountName string, sto
cp := storage.AccountCreateParameters{
Sku: &storage.Sku{Name: storageAccountType},
// switch to use StorageV2 as it's recommended according to https://docs.microsoft.com/en-us/azure/storage/common/storage-account-options
Kind: storage.StorageV2,
Kind: defaultStorageAccountKind,
Tags: map[string]*string{"created-by": to.StringPtr("azure-dd")},
Location: &location}
ctx, cancel := getContextWithCancel()
......
......@@ -58,22 +58,11 @@ func (f *azureFileClient) createFileShare(accountName, accountKey, name string,
if err != nil {
return err
}
// create a file share and set quota
// Note. Per https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Create-Share,
// setting x-ms-share-quota can set quota on the new share, but in reality, setting quota in CreateShare
// receives error "The metadata specified is invalid. It has characters that are not permitted."
// As a result,breaking into two API calls: create share and set quota
share := fileClient.GetShareReference(name)
share.Properties.Quota = sizeGiB
if err = share.Create(nil); err != nil {
return fmt.Errorf("failed to create file share, err: %v", err)
}
share.Properties.Quota = sizeGiB
if err = share.SetProperties(nil); err != nil {
if err := share.Delete(nil); err != nil {
glog.Errorf("Error deleting share: %v", err)
}
return fmt.Errorf("failed to set quota on file share %s, err: %v", name, err)
}
return nil
}
......
......@@ -25,18 +25,20 @@ import (
const (
defaultStorageAccountType = string(storage.StandardLRS)
defaultStorageAccountKind = storage.StorageV2
fileShareAccountNamePrefix = "f"
sharedDiskAccountNamePrefix = "ds"
dedicatedDiskAccountNamePrefix = "dd"
)
// CreateFileShare creates a file share, using a matching storage account
func (az *Cloud) CreateFileShare(shareName, accountName, accountType, resourceGroup, location string, requestGiB int) (string, string, error) {
// CreateFileShare creates a file share, using a matching storage account type, account kind, etc.
// storage account will be created if specified account is not found
func (az *Cloud) CreateFileShare(shareName, accountName, accountType, accountKind, resourceGroup, location string, requestGiB int) (string, string, error) {
if resourceGroup == "" {
resourceGroup = az.resourceGroup
}
account, key, err := az.ensureStorageAccount(accountName, accountType, resourceGroup, location, fileShareAccountNamePrefix)
account, key, err := az.ensureStorageAccount(accountName, accountType, accountKind, resourceGroup, location, fileShareAccountNamePrefix)
if err != nil {
return "", "", fmt.Errorf("could not get storage key for storage account %s: %v", accountName, err)
}
......
......@@ -30,6 +30,7 @@ func TestCreateFileShare(t *testing.T) {
name := "baz"
sku := "sku"
kind := "StorageV2"
location := "centralus"
value := "foo key"
bogus := "bogus"
......@@ -38,6 +39,7 @@ func TestCreateFileShare(t *testing.T) {
name string
acct string
acctType string
acctKind string
loc string
gb int
accounts storage.AccountListResult
......@@ -52,6 +54,7 @@ func TestCreateFileShare(t *testing.T) {
name: "foo",
acct: "bar",
acctType: "type",
acctKind: "StorageV2",
loc: "eastus",
gb: 10,
expectErr: true,
......@@ -60,6 +63,7 @@ func TestCreateFileShare(t *testing.T) {
name: "foo",
acct: "",
acctType: "type",
acctKind: "StorageV2",
loc: "eastus",
gb: 10,
expectErr: true,
......@@ -68,11 +72,12 @@ func TestCreateFileShare(t *testing.T) {
name: "foo",
acct: "",
acctType: sku,
acctKind: kind,
loc: location,
gb: 10,
accounts: storage.AccountListResult{
Value: &[]storage.Account{
{Name: &name, Sku: &storage.Sku{Name: storage.SkuName(sku)}, Location: &location},
{Name: &name, Sku: &storage.Sku{Name: storage.SkuName(sku)}, Kind: storage.Kind(kind), Location: &location},
},
},
keys: storage.AccountListKeysResult{
......@@ -87,6 +92,7 @@ func TestCreateFileShare(t *testing.T) {
name: "foo",
acct: "",
acctType: sku,
acctKind: kind,
loc: location,
gb: 10,
accounts: storage.AccountListResult{
......@@ -100,6 +106,7 @@ func TestCreateFileShare(t *testing.T) {
name: "foo",
acct: "",
acctType: sku,
acctKind: kind,
loc: location,
gb: 10,
accounts: storage.AccountListResult{
......@@ -116,7 +123,7 @@ func TestCreateFileShare(t *testing.T) {
fake.Keys = test.keys
fake.Err = test.err
account, key, err := cloud.CreateFileShare(test.name, test.acct, test.acctType, "rg", test.loc, test.gb)
account, key, err := cloud.CreateFileShare(test.name, test.acct, test.acctType, test.acctKind, "rg", test.loc, test.gb)
if test.expectErr && err == nil {
t.Errorf("unexpected non-error")
continue
......
......@@ -30,7 +30,7 @@ type accountWithLocation struct {
}
// getStorageAccounts gets name, type, location of all storage accounts in a resource group which matches matchingAccountType, matchingLocation
func (az *Cloud) getStorageAccounts(matchingAccountType, resourceGroup, matchingLocation string) ([]accountWithLocation, error) {
func (az *Cloud) getStorageAccounts(matchingAccountType, matchingAccountKind, resourceGroup, matchingLocation string) ([]accountWithLocation, error) {
ctx, cancel := getContextWithCancel()
defer cancel()
result, err := az.StorageAccountClient.ListByResourceGroup(ctx, resourceGroup)
......@@ -49,6 +49,10 @@ func (az *Cloud) getStorageAccounts(matchingAccountType, resourceGroup, matching
continue
}
if matchingAccountKind != "" && !strings.EqualFold(matchingAccountKind, string(acct.Kind)) {
continue
}
location := *acct.Location
if matchingLocation != "" && !strings.EqualFold(matchingLocation, location) {
continue
......@@ -86,10 +90,10 @@ func (az *Cloud) getStorageAccesskey(account, resourceGroup string) (string, err
}
// ensureStorageAccount search storage account, create one storage account(with genAccountNamePrefix) if not found, return accountName, accountKey
func (az *Cloud) ensureStorageAccount(accountName, accountType, resourceGroup, location, genAccountNamePrefix string) (string, string, error) {
func (az *Cloud) ensureStorageAccount(accountName, accountType, accountKind, resourceGroup, location, genAccountNamePrefix string) (string, string, error) {
if len(accountName) == 0 {
// find a storage account that matches accountType
accounts, err := az.getStorageAccounts(accountType, resourceGroup, location)
accounts, err := az.getStorageAccounts(accountType, accountKind, resourceGroup, location)
if err != nil {
return "", "", fmt.Errorf("could not list storage accounts for account type %s: %v", accountType, err)
}
......@@ -109,12 +113,16 @@ func (az *Cloud) ensureStorageAccount(accountName, accountType, resourceGroup, l
accountType = defaultStorageAccountType
}
glog.V(2).Infof("azure - no matching account found, begin to create a new account %s in resource group %s, location: %s, accountType: %s",
accountName, resourceGroup, location, accountType)
// use StorageV2 by default per https://docs.microsoft.com/en-us/azure/storage/common/storage-account-options
kind := defaultStorageAccountKind
if accountKind != "" {
kind = storage.Kind(accountKind)
}
glog.V(2).Infof("azure - no matching account found, begin to create a new account %s in resource group %s, location: %s, accountType: %s, accountKind: %s",
accountName, resourceGroup, location, accountType, kind)
cp := storage.AccountCreateParameters{
Sku: &storage.Sku{Name: storage.SkuName(accountType)},
// switch to use StorageV2 as it's recommended according to https://docs.microsoft.com/en-us/azure/storage/common/storage-account-options
Kind: storage.StorageV2,
Sku: &storage.Sku{Name: storage.SkuName(accountType)},
Kind: kind,
AccountPropertiesCreateParameters: &storage.AccountPropertiesCreateParameters{EnableHTTPSTrafficOnly: to.BoolPtr(true)},
Tags: map[string]*string{"created-by": to.StringPtr("azure")},
Location: &location}
......
......@@ -27,6 +27,7 @@ go_library(
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
"//staging/src/k8s.io/cloud-provider:go_default_library",
"//vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2018-07-01/storage:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
],
)
......
......@@ -20,7 +20,9 @@ import (
"fmt"
"strings"
"github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2018-07-01/storage"
"github.com/golang/glog"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
......@@ -38,7 +40,7 @@ var _ volume.ProvisionableVolumePlugin = &azureFilePlugin{}
// azure cloud provider should implement it
type azureCloudProvider interface {
// create a file share
CreateFileShare(shareName, accountName, accountType, resourceGroup, location string, requestGiB int) (string, string, error)
CreateFileShare(shareName, accountName, accountType, accountKind, resourceGroup, location string, requestGiB int) (string, string, error)
// delete a file share
DeleteFileShare(accountName, accountKey, shareName string) error
// resize a file share
......@@ -171,7 +173,12 @@ func (a *azureFileProvisioner) Provision(selectedNode *v1.Node, allowedTopologie
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, resourceGroup, location, requestGiB)
// when use azure file premium, account kind should be specified as FileStorage
accountKind := string(storage.StorageV2)
if strings.HasPrefix(strings.ToLower(sku), "premium") {
accountKind = string(storage.FileStorage)
}
account, key, err := a.azureProvider.CreateFileShare(name, account, sku, accountKind, resourceGroup, location, requestGiB)
if err != nil {
return nil, err
}
......
......@@ -16,23 +16,27 @@
},
{
"ImportPath": "github.com/Azure/go-autorest/autorest",
"Rev": "bca49d5b51a50dc5bb17bbf6204c711c6dbded06"
"Rev": "a88c19ef2016e095f0b6c3b451074b4663f53bed"
},
{
"ImportPath": "github.com/Azure/go-autorest/autorest/adal",
"Rev": "bca49d5b51a50dc5bb17bbf6204c711c6dbded06"
"Rev": "a88c19ef2016e095f0b6c3b451074b4663f53bed"
},
{
"ImportPath": "github.com/Azure/go-autorest/autorest/azure",
"Rev": "bca49d5b51a50dc5bb17bbf6204c711c6dbded06"
"Rev": "a88c19ef2016e095f0b6c3b451074b4663f53bed"
},
{
"ImportPath": "github.com/Azure/go-autorest/autorest/date",
"Rev": "bca49d5b51a50dc5bb17bbf6204c711c6dbded06"
"Rev": "a88c19ef2016e095f0b6c3b451074b4663f53bed"
},
{
"ImportPath": "github.com/Azure/go-autorest/logger",
"Rev": "a88c19ef2016e095f0b6c3b451074b4663f53bed"
},
{
"ImportPath": "github.com/Azure/go-autorest/version",
"Rev": "bca49d5b51a50dc5bb17bbf6204c711c6dbded06"
"Rev": "a88c19ef2016e095f0b6c3b451074b4663f53bed"
},
{
"ImportPath": "github.com/davecgh/go-spew/spew",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment