Commit 8a7198b0 authored by andyzhangx's avatar andyzhangx

use new account generation method for blob disk

fix comments change azureDiskSharedAccountNamePrefix var rename sharedDiskAccountNamePrefix use default vhd container name as "vhds" use one commaon func: SearchStorageAccount fix comments
parent aa21bef6
...@@ -22,10 +22,8 @@ import ( ...@@ -22,10 +22,8 @@ import (
"fmt" "fmt"
"net/url" "net/url"
"regexp" "regexp"
"sync"
"strconv"
"strings" "strings"
"sync"
"sync/atomic" "sync/atomic"
"time" "time"
...@@ -60,15 +58,11 @@ type BlobDiskController struct { ...@@ -60,15 +58,11 @@ type BlobDiskController struct {
} }
var ( var (
defaultContainerName = ""
storageAccountNamePrefix = ""
storageAccountNameMatch = ""
accountsLock = &sync.Mutex{} accountsLock = &sync.Mutex{}
) )
func newBlobDiskController(common *controllerCommon) (*BlobDiskController, error) { func newBlobDiskController(common *controllerCommon) (*BlobDiskController, error) {
c := BlobDiskController{common: common} c := BlobDiskController{common: common}
c.setUniqueStrings()
// get accounts // get accounts
accounts, err := c.getAllStorageAccounts() accounts, err := c.getAllStorageAccounts()
...@@ -84,46 +78,26 @@ func newBlobDiskController(common *controllerCommon) (*BlobDiskController, error ...@@ -84,46 +78,26 @@ func newBlobDiskController(common *controllerCommon) (*BlobDiskController, error
// CreateVolume creates a VHD blob in a storage account that has storageType and location using the given storage account. // CreateVolume creates a VHD blob in a storage account that has storageType and location using the given storage account.
// If no storage account is given, search all the storage accounts associated with the resource group and pick one that // 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. // fits storage type and location.
func (c *BlobDiskController) CreateVolume(name, storageAccount, storageAccountType, location string, requestGB int) (string, string, int, error) { func (c *BlobDiskController) CreateVolume(blobName, accountName, accountType, location string, requestGB int) (string, string, int, error) {
var err error account, key, err := c.common.cloud.ensureStorageAccount(accountName, accountType, location, dedicatedDiskAccountNamePrefix)
accounts := []accountWithLocation{}
if len(storageAccount) > 0 {
accounts = append(accounts, accountWithLocation{Name: storageAccount})
} else {
// find a storage account
accounts, err = c.common.cloud.getStorageAccounts(storageAccountType, location)
if err != nil { if err != nil {
// TODO: create a storage account and container return "", "", 0, fmt.Errorf("could not get storage key for storage account %s: %v", accountName, err)
return "", "", 0, err
}
}
for _, account := range accounts {
glog.V(4).Infof("account %s type %s location %s", account.Name, account.StorageType, account.Location)
if (storageAccountType == "" || account.StorageType == storageAccountType) && (location == "" || account.Location == location) || len(storageAccount) > 0 {
// find the access key with this account
key, err := c.common.cloud.getStorageAccesskey(account.Name)
if err != nil {
glog.V(2).Infof("no key found for storage account %s", account.Name)
continue
} }
client, err := azstorage.NewBasicClientOnSovereignCloud(account.Name, key, c.common.cloud.Environment) client, err := azstorage.NewBasicClientOnSovereignCloud(account, key, c.common.cloud.Environment)
if err != nil { if err != nil {
return "", "", 0, err return "", "", 0, err
} }
blobClient := client.GetBlobService() blobClient := client.GetBlobService()
// create a page blob in this account's vhd container // create a page blob in this account's vhd container
diskName, diskURI, err := c.createVHDBlobDisk(blobClient, account.Name, name, vhdContainerName, int64(requestGB)) diskName, diskURI, err := c.createVHDBlobDisk(blobClient, account, blobName, vhdContainerName, int64(requestGB))
if err != nil { if err != nil {
return "", "", 0, err return "", "", 0, err
} }
glog.V(4).Infof("azureDisk - created vhd blob uri: %s", diskURI) glog.V(4).Infof("azureDisk - created vhd blob uri: %s", diskURI)
return diskName, diskURI, requestGB, err return diskName, diskURI, requestGB, err
}
}
return "", "", 0, fmt.Errorf("failed to find a matching storage account")
} }
// DeleteVolume deletes a VHD blob // DeleteVolume deletes a VHD blob
...@@ -252,7 +226,7 @@ func (c *BlobDiskController) CreateBlobDisk(dataDiskName string, storageAccountT ...@@ -252,7 +226,7 @@ func (c *BlobDiskController) CreateBlobDisk(dataDiskName string, storageAccountT
return "", err return "", err
} }
_, diskURI, err := c.createVHDBlobDisk(blobClient, storageAccountName, dataDiskName, defaultContainerName, int64(sizeGB)) _, diskURI, err := c.createVHDBlobDisk(blobClient, storageAccountName, dataDiskName, vhdContainerName, int64(sizeGB))
if err != nil { if err != nil {
return "", err return "", err
} }
...@@ -281,9 +255,9 @@ func (c *BlobDiskController) DeleteBlobDisk(diskURI string) error { ...@@ -281,9 +255,9 @@ func (c *BlobDiskController) DeleteBlobDisk(diskURI string) error {
return err return err
} }
glog.V(4).Infof("azureDisk - About to delete vhd file %s on storage account %s container %s", vhdName, storageAccountName, defaultContainerName) glog.V(4).Infof("azureDisk - About to delete vhd file %s on storage account %s container %s", vhdName, storageAccountName, vhdContainerName)
container := blobSvc.GetContainerReference(defaultContainerName) container := blobSvc.GetContainerReference(vhdContainerName)
blob := container.GetBlobReference(vhdName) blob := container.GetBlobReference(vhdName)
_, err = blob.DeleteIfExists(nil) _, err = blob.DeleteIfExists(nil)
...@@ -299,19 +273,6 @@ func (c *BlobDiskController) DeleteBlobDisk(diskURI string) error { ...@@ -299,19 +273,6 @@ func (c *BlobDiskController) DeleteBlobDisk(diskURI string) error {
return err return err
} }
//Sets unique strings to be used as accountnames && || blob containers names
func (c *BlobDiskController) setUniqueStrings() {
uniqueString := c.common.resourceGroup + c.common.location + c.common.subscriptionID
hash := MakeCRC32(uniqueString)
//used to generate a unique container name used by this cluster PVC
defaultContainerName = hash
storageAccountNamePrefix = fmt.Sprintf(storageAccountNameTemplate, hash)
// Used to filter relevant accounts (accounts used by shared PVC)
storageAccountNameMatch = storageAccountNamePrefix
// Used as a template to create new names for relevant accounts
storageAccountNamePrefix = storageAccountNamePrefix + "%s"
}
func (c *BlobDiskController) getStorageAccountKey(SAName string) (string, error) { func (c *BlobDiskController) getStorageAccountKey(SAName string) (string, error) {
if account, exists := c.accounts[SAName]; exists && account.key != "" { if account, exists := c.accounts[SAName]; exists && account.key != "" {
return c.accounts[SAName].key, nil return c.accounts[SAName].key, nil
...@@ -426,13 +387,13 @@ func (c *BlobDiskController) ensureDefaultContainer(storageAccountName string) e ...@@ -426,13 +387,13 @@ func (c *BlobDiskController) ensureDefaultContainer(storageAccountName string) e
return err return err
} }
container := blobSvc.GetContainerReference(defaultContainerName) container := blobSvc.GetContainerReference(vhdContainerName)
bCreated, err := container.CreateIfNotExists(&azstorage.CreateContainerOptions{Access: azstorage.ContainerAccessTypePrivate}) bCreated, err := container.CreateIfNotExists(&azstorage.CreateContainerOptions{Access: azstorage.ContainerAccessTypePrivate})
if err != nil { if err != nil {
return err return err
} }
if bCreated { if bCreated {
glog.V(2).Infof("azureDisk - storage account:%s had no default container(%s) and it was created \n", storageAccountName, defaultContainerName) glog.V(2).Infof("azureDisk - storage account:%s had no default container(%s) and it was created \n", storageAccountName, vhdContainerName)
} }
// flag so we no longer have to check on ARM // flag so we no longer have to check on ARM
...@@ -459,7 +420,7 @@ func (c *BlobDiskController) getDiskCount(SAName string) (int, error) { ...@@ -459,7 +420,7 @@ func (c *BlobDiskController) getDiskCount(SAName string) (int, error) {
} }
params := azstorage.ListBlobsParameters{} params := azstorage.ListBlobsParameters{}
container := blobSvc.GetContainerReference(defaultContainerName) container := blobSvc.GetContainerReference(vhdContainerName)
response, err := container.ListBlobs(params) response, err := container.ListBlobs(params)
if err != nil { if err != nil {
return 0, err return 0, err
...@@ -481,13 +442,13 @@ func (c *BlobDiskController) getAllStorageAccounts() (map[string]*storageAccount ...@@ -481,13 +442,13 @@ func (c *BlobDiskController) getAllStorageAccounts() (map[string]*storageAccount
accounts := make(map[string]*storageAccountState) accounts := make(map[string]*storageAccountState)
for _, v := range *accountListResult.Value { for _, v := range *accountListResult.Value {
if strings.Index(*v.Name, storageAccountNameMatch) != 0 {
continue
}
if v.Name == nil || v.Sku == nil { if v.Name == nil || v.Sku == nil {
glog.Info("azureDisk - accountListResult Name or Sku is nil") glog.Info("azureDisk - accountListResult Name or Sku is nil")
continue continue
} }
if !strings.HasPrefix(*v.Name, sharedDiskAccountNamePrefix) {
continue
}
glog.Infof("azureDisk - identified account %s as part of shared PVC accounts", *v.Name) glog.Infof("azureDisk - identified account %s as part of shared PVC accounts", *v.Name)
sastate := &storageAccountState{ sastate := &storageAccountState{
...@@ -555,7 +516,7 @@ func (c *BlobDiskController) findSANameForDisk(storageAccountType storage.SkuNam ...@@ -555,7 +516,7 @@ func (c *BlobDiskController) findSANameForDisk(storageAccountType storage.SkuNam
countAccounts := 0 // account of this type. countAccounts := 0 // account of this type.
for _, v := range c.accounts { for _, v := range c.accounts {
// filter out any stand-alone disks/accounts // filter out any stand-alone disks/accounts
if strings.Index(v.name, storageAccountNameMatch) != 0 { if !strings.HasPrefix(v.name, sharedDiskAccountNamePrefix) {
continue continue
} }
...@@ -587,7 +548,7 @@ func (c *BlobDiskController) findSANameForDisk(storageAccountType storage.SkuNam ...@@ -587,7 +548,7 @@ func (c *BlobDiskController) findSANameForDisk(storageAccountType storage.SkuNam
// if we failed to find storageaccount // if we failed to find storageaccount
if SAName == "" { if SAName == "" {
glog.V(2).Infof("azureDisk - failed to identify a suitable account for new disk and will attempt to create new account") glog.V(2).Infof("azureDisk - failed to identify a suitable account for new disk and will attempt to create new account")
SAName = getAccountNameForNum(c.getNextAccountNum()) SAName = generateStorageAccountName(sharedDiskAccountNamePrefix)
err := c.createStorageAccount(SAName, storageAccountType, c.common.location, true) err := c.createStorageAccount(SAName, storageAccountType, c.common.location, true)
if err != nil { if err != nil {
return "", err return "", err
...@@ -603,7 +564,7 @@ func (c *BlobDiskController) findSANameForDisk(storageAccountType storage.SkuNam ...@@ -603,7 +564,7 @@ func (c *BlobDiskController) findSANameForDisk(storageAccountType storage.SkuNam
// avg are not create and we should create more accounts if we can // avg are not create and we should create more accounts if we can
if aboveAvg && countAccounts < maxStorageAccounts { if aboveAvg && countAccounts < maxStorageAccounts {
glog.V(2).Infof("azureDisk - shared storageAccounts utilization(%v) > grow-at-avg-utilization (%v). New storage account will be created", avgUtilization, storageAccountUtilizationBeforeGrowing) glog.V(2).Infof("azureDisk - shared storageAccounts utilization(%v) > grow-at-avg-utilization (%v). New storage account will be created", avgUtilization, storageAccountUtilizationBeforeGrowing)
SAName = getAccountNameForNum(c.getNextAccountNum()) SAName = generateStorageAccountName(sharedDiskAccountNamePrefix)
err := c.createStorageAccount(SAName, storageAccountType, c.common.location, true) err := c.createStorageAccount(SAName, storageAccountType, c.common.location, true)
if err != nil { if err != nil {
return "", err return "", err
...@@ -620,22 +581,6 @@ func (c *BlobDiskController) findSANameForDisk(storageAccountType storage.SkuNam ...@@ -620,22 +581,6 @@ func (c *BlobDiskController) findSANameForDisk(storageAccountType storage.SkuNam
// we found a storage accounts && [ avg are ok || we reached max sa count ] // we found a storage accounts && [ avg are ok || we reached max sa count ]
return SAName, nil return SAName, nil
} }
func (c *BlobDiskController) getNextAccountNum() int {
max := 0
for k := range c.accounts {
// filter out accounts that are for standalone
if strings.Index(k, storageAccountNameMatch) != 0 {
continue
}
num := getAccountNumFromName(k)
if num > max {
max = num
}
}
return max + 1
}
//Gets storage account exist, provisionStatus, Error if any //Gets storage account exist, provisionStatus, Error if any
func (c *BlobDiskController) getStorageAccountState(storageAccountName string) (bool, storage.ProvisioningState, error) { func (c *BlobDiskController) getStorageAccountState(storageAccountName string) (bool, storage.ProvisioningState, error) {
...@@ -655,27 +600,6 @@ func (c *BlobDiskController) addAccountState(key string, state *storageAccountSt ...@@ -655,27 +600,6 @@ func (c *BlobDiskController) addAccountState(key string, state *storageAccountSt
} }
} }
// pads account num with zeros as needed
func getAccountNameForNum(num int) string {
sNum := strconv.Itoa(num)
missingZeros := 3 - len(sNum)
strZero := ""
for missingZeros > 0 {
strZero = strZero + "0"
missingZeros = missingZeros - 1
}
sNum = strZero + sNum
return fmt.Sprintf(storageAccountNamePrefix, sNum)
}
func getAccountNumFromName(accountName string) int {
nameLen := len(accountName)
num, _ := strconv.Atoi(accountName[nameLen-3:])
return num
}
func createVHDHeader(size uint64) ([]byte, error) { func createVHDHeader(size uint64) ([]byte, error) {
h := vhd.CreateFixedHeader(size, &vhd.VHDOptions{}) h := vhd.CreateFixedHeader(size, &vhd.VHDOptions{})
b := new(bytes.Buffer) b := new(bytes.Buffer)
......
...@@ -20,66 +20,28 @@ import ( ...@@ -20,66 +20,28 @@ import (
"fmt" "fmt"
"github.com/Azure/azure-sdk-for-go/arm/storage" "github.com/Azure/azure-sdk-for-go/arm/storage"
"github.com/Azure/go-autorest/autorest/to"
"github.com/golang/glog" "github.com/golang/glog"
) )
const ( const (
defaultStorageAccountType = string(storage.StandardLRS) defaultStorageAccountType = string(storage.StandardLRS)
fileShareAccountNamePrefix = "f" fileShareAccountNamePrefix = "f"
sharedDiskAccountNamePrefix = "ds"
dedicatedDiskAccountNamePrefix = "dd"
) )
// CreateFileShare creates a file share, using a matching storage account // CreateFileShare creates a file share, using a matching storage account
func (az *Cloud) CreateFileShare(shareName, accountName, accountType, location string, requestGiB int) (string, string, error) { func (az *Cloud) CreateFileShare(shareName, accountName, accountType, location string, requestGiB int) (string, string, error) {
if len(accountName) == 0 { account, key, err := az.ensureStorageAccount(accountName, accountType, location, fileShareAccountNamePrefix)
// find a storage account that matches accountType
accounts, err := az.getStorageAccounts(accountType, location)
if err != nil {
return "", "", fmt.Errorf("could not list storage accounts for account type %s: %v", accountType, err)
}
if len(accounts) > 0 {
accountName = accounts[0].Name
glog.V(4).Infof("found a matching account %s type %s location %s", accounts[0].Name, accounts[0].StorageType, accounts[0].Location)
}
if len(accountName) == 0 {
// not found a matching account, now create a new account in current resource group
accountName = generateStorageAccountName(fileShareAccountNamePrefix)
if location == "" {
location = az.Location
}
if accountType == "" {
accountType = defaultStorageAccountType
}
glog.V(2).Infof("azureFile - no matching account found, begin to create a new account %s in resource group %s, location: %s, accountType: %s",
accountName, az.ResourceGroup, location, accountType)
cp := storage.AccountCreateParameters{
Sku: &storage.Sku{Name: storage.SkuName(accountType)},
Tags: &map[string]*string{"created-by": to.StringPtr("azure-file")},
Location: &location}
cancel := make(chan struct{})
_, errchan := az.StorageAccountClient.Create(az.ResourceGroup, accountName, cp, cancel)
err := <-errchan
if err != nil {
return "", "", fmt.Errorf(fmt.Sprintf("Failed to create storage account %s, error: %s", accountName, err))
}
}
}
// find the access key with this account
accountKey, err := az.getStorageAccesskey(accountName)
if err != nil { if err != nil {
return "", "", fmt.Errorf("could not get storage key for storage account %s: %v", accountName, err) return "", "", fmt.Errorf("could not get storage key for storage account %s: %v", accountName, err)
} }
if err := az.createFileShare(accountName, accountKey, shareName, requestGiB); err != nil { if err := az.createFileShare(account, key, shareName, requestGiB); err != nil {
return "", "", fmt.Errorf("failed to create share %s in account %s: %v", shareName, accountName, err) return "", "", fmt.Errorf("failed to create share %s in account %s: %v", shareName, account, err)
} }
glog.V(4).Infof("created share %s in account %s", shareName, accountName) glog.V(4).Infof("created share %s in account %s", shareName, account)
return accountName, accountKey, nil return account, key, nil
} }
// DeleteFileShare deletes a file share using storage account name and key // DeleteFileShare deletes a file share using storage account name and key
......
...@@ -19,13 +19,17 @@ package azure ...@@ -19,13 +19,17 @@ package azure
import ( import (
"fmt" "fmt"
"strings" "strings"
"github.com/Azure/azure-sdk-for-go/arm/storage"
"github.com/Azure/go-autorest/autorest/to"
"github.com/golang/glog"
) )
type accountWithLocation struct { type accountWithLocation struct {
Name, StorageType, Location string Name, StorageType, Location string
} }
// getStorageAccounts gets name, type, location of all storage accounts in a resource group which matches matchingAccountType // getStorageAccounts gets name, type, location of all storage accounts in a resource group which matches matchingAccountType, matchingLocation
func (az *Cloud) getStorageAccounts(matchingAccountType, matchingLocation string) ([]accountWithLocation, error) { func (az *Cloud) getStorageAccounts(matchingAccountType, matchingLocation string) ([]accountWithLocation, error) {
result, err := az.StorageAccountClient.ListByResourceGroup(az.ResourceGroup) result, err := az.StorageAccountClient.ListByResourceGroup(az.ResourceGroup)
if err != nil { if err != nil {
...@@ -75,3 +79,52 @@ func (az *Cloud) getStorageAccesskey(account string) (string, error) { ...@@ -75,3 +79,52 @@ func (az *Cloud) getStorageAccesskey(account string) (string, error) {
} }
return "", fmt.Errorf("no valid keys") return "", fmt.Errorf("no valid keys")
} }
// ensureStorageAccount search storage account, create one storage account(with genAccountNamePrefix) if not found, return accountName, accountKey
func (az *Cloud) ensureStorageAccount(accountName, accountType, location, genAccountNamePrefix string) (string, string, error) {
if len(accountName) == 0 {
// find a storage account that matches accountType
accounts, err := az.getStorageAccounts(accountType, location)
if err != nil {
return "", "", fmt.Errorf("could not list storage accounts for account type %s: %v", accountType, err)
}
if len(accounts) > 0 {
accountName = accounts[0].Name
glog.V(4).Infof("found a matching account %s type %s location %s", accounts[0].Name, accounts[0].StorageType, accounts[0].Location)
}
if len(accountName) == 0 {
// not found a matching account, now create a new account in current resource group
accountName = generateStorageAccountName(genAccountNamePrefix)
if location == "" {
location = az.Location
}
if accountType == "" {
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, az.ResourceGroup, location, accountType)
cp := storage.AccountCreateParameters{
Sku: &storage.Sku{Name: storage.SkuName(accountType)},
Tags: &map[string]*string{"created-by": to.StringPtr("azure")},
Location: &location}
cancel := make(chan struct{})
_, errchan := az.StorageAccountClient.Create(az.ResourceGroup, accountName, cp, cancel)
err := <-errchan
if err != nil {
return "", "", fmt.Errorf(fmt.Sprintf("Failed to create storage account %s, error: %s", accountName, err))
}
}
}
// find the access key with this account
accountKey, err := az.getStorageAccesskey(accountName)
if err != nil {
return "", "", fmt.Errorf("could not get storage key for storage account %s: %v", accountName, err)
}
return accountName, accountKey, nil
}
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