Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

provider/azurerm: add account_kind and access_tier to storage_account #9408

Merged
merged 1 commit into from
Oct 24, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions builtin/providers/azurerm/resource_arm_storage_account.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,15 @@ import (
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/signalwrapper"
"github.com/hashicorp/terraform/helper/validation"
)

// The KeySource of storage.Encryption appears to require this value
// for Encryption services to work
var storageAccountEncryptionSource = "Microsoft.Storage"

const blobStorageAccountDefaultAccessTier = "Hot"

func resourceArmStorageAccount() *schema.Resource {
return &schema.Resource{
Create: resourceArmStorageAccountCreate,
Expand Down Expand Up @@ -50,12 +53,34 @@ func resourceArmStorageAccount() *schema.Resource {
StateFunc: azureRMNormalizeLocation,
},

"account_kind": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: validation.StringInSlice([]string{
string(storage.Storage),
string(storage.BlobStorage),
}, true),
Default: string(storage.Storage),
},

"account_type": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validateArmStorageAccountType,
},

// Only valid for BlobStorage accounts, defaults to "Hot" in create function
"access_tier": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validation.StringInSlice([]string{
string(storage.Cool),
string(storage.Hot),
}, true),
},

"enable_blob_encryption": {
Type: schema.TypeBool,
Optional: true,
Expand Down Expand Up @@ -128,7 +153,9 @@ func resourceArmStorageAccountCreate(d *schema.ResourceData, meta interface{}) e

resourceGroupName := d.Get("resource_group_name").(string)
storageAccountName := d.Get("name").(string)
accountKind := d.Get("account_kind").(string)
accountType := d.Get("account_type").(string)

location := d.Get("location").(string)
tags := d.Get("tags").(map[string]interface{})
enableBlobEncryption := d.Get("enable_blob_encryption").(bool)
Expand All @@ -141,6 +168,7 @@ func resourceArmStorageAccountCreate(d *schema.ResourceData, meta interface{}) e
Location: &location,
Sku: &sku,
Tags: expandTags(tags),
Kind: storage.Kind(accountKind),
Properties: &storage.AccountPropertiesCreateParameters{
Encryption: &storage.Encryption{
Services: &storage.EncryptionServices{
Expand All @@ -153,6 +181,17 @@ func resourceArmStorageAccountCreate(d *schema.ResourceData, meta interface{}) e
},
}

// AccessTier is only valid for BlobStorage accounts
if accountKind == string(storage.BlobStorage) {
accessTier, ok := d.GetOk("access_tier")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should add the default as part of the scheme declaration rather than defaulting in code

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue I faced is that accessTier can only be specified on requests for BlobStorage accounts, using the Default parameter meant it would be set for all types

if !ok {
// default to "Hot"
accessTier = blobStorageAccountDefaultAccessTier
}

opts.Properties.AccessTier = storage.AccessTier(accessTier.(string))
}

// Create the storage account. We wrap this so that it is cancellable
// with a Ctrl-C since this can take a LONG time.
wrap := signalwrapper.Run(func(cancelCh <-chan struct{}) error {
Expand Down Expand Up @@ -247,6 +286,22 @@ func resourceArmStorageAccountUpdate(d *schema.ResourceData, meta interface{}) e
d.SetPartial("account_type")
}

if d.HasChange("access_tier") {
accessTier := d.Get("access_tier").(string)

opts := storage.AccountUpdateParameters{
Properties: &storage.AccountPropertiesUpdateParameters{
AccessTier: storage.AccessTier(accessTier),
},
}
_, err := client.Update(resourceGroupName, storageAccountName, opts)
if err != nil {
return fmt.Errorf("Error updating Azure Storage Account access_tier %q: %s", storageAccountName, err)
}

d.SetPartial("access_tier")
}

if d.HasChange("tags") {
tags := d.Get("tags").(map[string]interface{})

Expand Down Expand Up @@ -317,10 +372,15 @@ func resourceArmStorageAccountRead(d *schema.ResourceData, meta interface{}) err
d.Set("primary_access_key", accessKeys[0].Value)
d.Set("secondary_access_key", accessKeys[1].Value)
d.Set("location", resp.Location)
d.Set("account_kind", resp.Kind)
d.Set("account_type", resp.Sku.Name)
d.Set("primary_location", resp.Properties.PrimaryLocation)
d.Set("secondary_location", resp.Properties.SecondaryLocation)

if resp.Properties.AccessTier != "" {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If access tier is computed: true, is there ever any way this can be nil?

d.Set("access_tier", resp.Properties.AccessTier)
}

if resp.Properties.PrimaryEndpoints != nil {
d.Set("primary_blob_endpoint", resp.Properties.PrimaryEndpoints.Blob)
d.Set("primary_queue_endpoint", resp.Properties.PrimaryEndpoints.Queue)
Expand Down
71 changes: 71 additions & 0 deletions builtin/providers/azurerm/resource_arm_storage_account_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,37 @@ func TestAccAzureRMStorageAccount_blobEncryption(t *testing.T) {
})
}

func TestAccAzureRMStorageAccount_blobStorageWithUpdate(t *testing.T) {
ri := acctest.RandInt()
rs := acctest.RandString(4)
preConfig := fmt.Sprintf(testAccAzureRMStorageAccount_blobStorage, ri, rs)
postConfig := fmt.Sprintf(testAccAzureRMStorageAccount_blobStorageUpdate, ri, rs)

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testCheckAzureRMStorageAccountDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: preConfig,
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMStorageAccountExists("azurerm_storage_account.testsa"),
resource.TestCheckResourceAttr("azurerm_storage_account.testsa", "account_kind", "BlobStorage"),
resource.TestCheckResourceAttr("azurerm_storage_account.testsa", "access_tier", "Hot"),
),
},

resource.TestStep{
Config: postConfig,
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMStorageAccountExists("azurerm_storage_account.testsa"),
resource.TestCheckResourceAttr("azurerm_storage_account.testsa", "access_tier", "Cool"),
),
},
},
})
}

func testCheckAzureRMStorageAccountExists(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
// Ensure we have enough information in state to look up in API
Expand Down Expand Up @@ -286,3 +317,43 @@ resource "azurerm_storage_account" "testsa" {
environment = "production"
}
}`

// BlobStorage accounts are not available in WestUS
var testAccAzureRMStorageAccount_blobStorage = `
resource "azurerm_resource_group" "testrg" {
name = "testAccAzureRMSA-%d"
location = "northeurope"
}

resource "azurerm_storage_account" "testsa" {
name = "unlikely23exst2acct%s"
resource_group_name = "${azurerm_resource_group.testrg.name}"

location = "northeurope"
account_kind = "BlobStorage"
account_type = "Standard_LRS"

tags {
environment = "production"
}
}`

var testAccAzureRMStorageAccount_blobStorageUpdate = `
resource "azurerm_resource_group" "testrg" {
name = "testAccAzureRMSA-%d"
location = "northeurope"
}

resource "azurerm_storage_account" "testsa" {
name = "unlikely23exst2acct%s"
resource_group_name = "${azurerm_resource_group.testrg.name}"

location = "northeurope"
account_kind = "BlobStorage"
account_type = "Standard_LRS"
access_tier = "Cool"

tags {
environment = "production"
}
}`
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,20 @@ The following arguments are supported:
* `location` - (Required) Specifies the supported Azure location where the
resource exists. Changing this forces a new resource to be created.

* `account_kind` - (Optional) Defines the Kind of account. Valid options are `Storage`
and `BlobStorage`. Changing this forces a new resource to be created. Defaults
to `Storage`.

* `account_type` - (Required) Defines the type of storage account to be
created. Valid options are `Standard_LRS`, `Standard_ZRS`, `Standard_GRS`,
`Standard_RAGRS`, `Premium_LRS`. Changing this is sometimes valid - see the Azure
documentation for more information on which types of accounts can be converted
into other types.

* `access_tier` - (Required for `BlobStorage` accounts) Defines the access tier
for `BlobStorage` accounts. Valid options are `Hot` and `Cold`, defaults to
`Hot`.

* `enable_bool_encryption` - (Optional) Boolean flag which controls if Encryption
Services are enabled for Blob storage, see [here](https://azure.microsoft.com/en-us/documentation/articles/storage-service-encryption/)
for more information.
Expand Down