func (env *azureEnviron) getStorageAccountLocked(refresh bool) (*storage.Account, error) { if !refresh && env.storageAccount != nil { return env.storageAccount, nil } client := storage.AccountsClient{env.storage} var account storage.Account if err := env.callAPI(func() (autorest.Response, error) { var err error account, err = client.GetProperties(env.resourceGroup, env.storageAccountName) return account.Response, err }); err != nil { if account.Response.Response != nil && account.Response.StatusCode == http.StatusNotFound { return nil, errors.NewNotFound(err, fmt.Sprintf("storage account not found")) } return nil, errors.Annotate(err, "getting storage account") } env.storageAccount = &account return env.storageAccount, nil }
// getStorageAccountKey returns the key for the storage account. func getStorageAccountKey( callAPI callAPIFunc, client armstorage.AccountsClient, resourceGroup, accountName string, ) (*armstorage.AccountKey, error) { logger.Debugf("getting keys for storage account %q", accountName) var listKeysResult armstorage.AccountListKeysResult if err := callAPI(func() (autorest.Response, error) { var err error listKeysResult, err = client.ListKeys(resourceGroup, accountName) return listKeysResult.Response, err }); err != nil { if listKeysResult.Response.Response != nil && listKeysResult.StatusCode == http.StatusNotFound { return nil, errors.NewNotFound(err, "storage account keys not found") } return nil, errors.Annotate(err, "listing storage account keys") } if listKeysResult.Keys == nil { return nil, errors.NotFoundf("storage account keys") } // We need a storage key with full permissions. var fullKey *armstorage.AccountKey for _, key := range *listKeysResult.Keys { logger.Debugf("storage account key: %#v", key) // At least some of the time, Azure returns the permissions // in title-case, which does not match the constant. if strings.ToUpper(string(key.Permissions)) != string(armstorage.FULL) { continue } fullKey = &key break } if fullKey == nil { return nil, errors.NotFoundf( "storage account key with %q permission", armstorage.FULL, ) } return fullKey, nil }
func createStorageAccount( client storage.AccountsClient, accountType storage.AccountType, resourceGroup string, location string, tags map[string]string, accountNameGenerator func() string, ) (string, string, error) { logger.Debugf("creating storage account (finding available name)") const maxAttempts = 10 for remaining := maxAttempts; remaining > 0; remaining-- { accountName := accountNameGenerator() logger.Debugf("- checking storage account name %q", accountName) result, err := client.CheckNameAvailability( storage.AccountCheckNameAvailabilityParameters{ Name: to.StringPtr(accountName), // Azure is a little inconsistent with when Type is // required. It's required here. Type: to.StringPtr("Microsoft.Storage/storageAccounts"), }, ) if err != nil { return "", "", errors.Annotate(err, "checking account name availability") } if !to.Bool(result.NameAvailable) { logger.Debugf( "%q is not available (%v): %v", accountName, result.Reason, result.Message, ) continue } createParams := storage.AccountCreateParameters{ Location: to.StringPtr(location), Tags: toTagsPtr(tags), Properties: &storage.AccountPropertiesCreateParameters{ AccountType: accountType, }, } logger.Debugf("- creating %q storage account %q", accountType, accountName) // TODO(axw) account creation can fail if the account name is // available, but contains profanity. We should retry a set // number of times even if creating fails. if _, err := client.Create(resourceGroup, accountName, createParams); err != nil { return "", "", errors.Trace(err) } logger.Debugf("- listing storage account keys") listKeysResult, err := client.ListKeys(resourceGroup, accountName) if err != nil { return "", "", errors.Annotate(err, "listing storage account keys") } return accountName, to.String(listKeysResult.Key1), nil } return "", "", errors.New("could not find available storage account name") }