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") }