Skip to content

Commit

Permalink
Provide ability to set 'cors_rule' for blob properties
Browse files Browse the repository at this point in the history
  • Loading branch information
Jack Batzner committed Jan 16, 2020
1 parent 6206160 commit f2baa9b
Show file tree
Hide file tree
Showing 4 changed files with 222 additions and 89 deletions.
70 changes: 70 additions & 0 deletions azurerm/helpers/azure/storage_account.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package azure

import (
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate"
)

func SchemaStorageAccountCorsRule() *schema.Schema {
return &schema.Schema{
Type: schema.TypeList,
Optional: true,
MaxItems: 5,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"allowed_origins": {
Type: schema.TypeList,
Required: true,
MaxItems: 64,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validate.NoEmptyStrings,
},
},
"exposed_headers": {
Type: schema.TypeList,
Required: true,
MaxItems: 64,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validate.NoEmptyStrings,
},
},
"allowed_headers": {
Type: schema.TypeList,
Required: true,
MaxItems: 64,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validate.NoEmptyStrings,
},
},
"allowed_methods": {
Type: schema.TypeList,
Required: true,
MaxItems: 64,
Elem: &schema.Schema{
Type: schema.TypeString,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validation.StringInSlice([]string{
"DELETE",
"GET",
"HEAD",
"MERGE",
"POST",
"OPTIONS",
"PUT"}, false),
},
},
},
"max_age_in_seconds": {
Type: schema.TypeInt,
Required: true,
ValidateFunc: validation.IntBetween(1, 2000000000),
},
},
},
}
}
211 changes: 123 additions & 88 deletions azurerm/internal/services/storage/resource_arm_storage_account.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ func resourceArmStorageAccount() *schema.Resource {
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"cors_rule": azure.SchemaStorageAccountCorsRule(),
"delete_retention_policy": {
Type: schema.TypeList,
Optional: true,
Expand All @@ -307,66 +308,7 @@ func resourceArmStorageAccount() *schema.Resource {
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"cors_rule": {
Type: schema.TypeList,
Optional: true,
MaxItems: 5,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"allowed_origins": {
Type: schema.TypeList,
Required: true,
MaxItems: 64,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validate.NoEmptyStrings,
},
},
"exposed_headers": {
Type: schema.TypeList,
Required: true,
MaxItems: 64,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validate.NoEmptyStrings,
},
},
"allowed_headers": {
Type: schema.TypeList,
Required: true,
MaxItems: 64,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validate.NoEmptyStrings,
},
},
"allowed_methods": {
Type: schema.TypeList,
Required: true,
MaxItems: 64,
Elem: &schema.Schema{
Type: schema.TypeString,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validation.StringInSlice([]string{
"DELETE",
"GET",
"HEAD",
"MERGE",
"POST",
"OPTIONS",
"PUT"}, false),
},
},
},
"max_age_in_seconds": {
Type: schema.TypeInt,
Required: true,
ValidateFunc: validation.IntBetween(1, 2000000000),
},
},
},
},
"cors_rule": azure.SchemaStorageAccountCorsRule(),
"logging": {
Type: schema.TypeList,
Optional: true,
Expand Down Expand Up @@ -1428,27 +1370,70 @@ func expandStorageAccountBypass(networkRule map[string]interface{}) storage.Bypa
}

func expandBlobProperties(input []interface{}) storage.BlobServiceProperties {
properties := storage.BlobServiceProperties{
BlobServicePropertiesProperties: &storage.BlobServicePropertiesProperties{
DeleteRetentionPolicy: &storage.DeleteRetentionPolicy{
Enabled: utils.Bool(false),
},
},
blobServiceProperties := storage.BlobServicePropertiesProperties{}
blobProperties := storage.BlobServiceProperties{
BlobServicePropertiesProperties: &blobServiceProperties,
}

if len(input) == 0 || input[0] == nil {
return properties
return blobProperties
}

blobAttr := input[0].(map[string]interface{})
deletePolicy := blobAttr["delete_retention_policy"].([]interface{})
if len(deletePolicy) > 0 {
policy := deletePolicy[0].(map[string]interface{})
days := policy["days"].(int)
properties.BlobServicePropertiesProperties.DeleteRetentionPolicy.Enabled = utils.Bool(true)
properties.BlobServicePropertiesProperties.DeleteRetentionPolicy.Days = utils.Int32(int32(days))

blobServiceProperties.DeleteRetentionPolicy = expandBlobPropertiesDeleteRetentionPolicy(blobAttr["delete_retention_policy"].([]interface{}))
blobServiceProperties.Cors = expandBlobPropertiesCors(blobAttr["cors_rule"].([]interface{}))

return blobProperties
}

func expandBlobPropertiesDeleteRetentionPolicy(input []interface{}) *storage.DeleteRetentionPolicy {
deleteRetentionPolicy := storage.DeleteRetentionPolicy{
Enabled: utils.Bool(false),
}

if input == nil || len(input) == 0 {
return &deleteRetentionPolicy
}

return properties
policy := input[0].(map[string]interface{})
days := policy["days"].(int)
deleteRetentionPolicy.Enabled = utils.Bool(true)
deleteRetentionPolicy.Days = utils.Int32(int32(days))

return &deleteRetentionPolicy
}

func expandBlobPropertiesCors(input []interface{}) *storage.CorsRules {
blobCorsRules := storage.CorsRules{}

if input == nil || len(input) == 0 {
return &blobCorsRules
}

corsRules := make([]storage.CorsRule, 0)
for _, attr := range input {
corsRuleAttr := attr.(map[string]interface{})
corsRule := storage.CorsRule{}

allowedOrigins := *utils.ExpandStringSlice(corsRuleAttr["allowed_origins"].([]interface{}))
allowedHeaders := *utils.ExpandStringSlice(corsRuleAttr["allowed_headers"].([]interface{}))
allowedMethods := *utils.ExpandStringSlice(corsRuleAttr["allowed_methods"].([]interface{}))
exposedHeaders := *utils.ExpandStringSlice(corsRuleAttr["exposed_headers"].([]interface{}))
maxAgeInSeconds := int32(corsRuleAttr["max_age_in_seconds"].(int))

corsRule.AllowedOrigins = &allowedOrigins
corsRule.AllowedHeaders = &allowedHeaders
corsRule.AllowedMethods = &allowedMethods
corsRule.ExposedHeaders = &exposedHeaders
corsRule.MaxAgeInSeconds = &maxAgeInSeconds

corsRules = append(corsRules, corsRule)
}

blobCorsRules.CorsRules = &corsRules

return &blobCorsRules
}

func expandQueueProperties(input []interface{}) (queues.StorageServiceProperties, error) {
Expand Down Expand Up @@ -1607,30 +1592,80 @@ func flattenStorageAccountVirtualNetworks(input *[]storage.VirtualNetworkRule) [
}

func flattenBlobProperties(input storage.BlobServiceProperties) []interface{} {
properties := []interface{}{}
if input.BlobServicePropertiesProperties == nil {
return []interface{}{}
return properties
}

deleteRetentionPolicies := make([]interface{}, 0)
blobProperties := make(map[string]interface{})

if corsRules := input.BlobServicePropertiesProperties.Cors; corsRules != nil {
blobProperties["cors_rule"] = flattenBlobPropertiesCorsRule(corsRules)
}

if deletePolicy := input.BlobServicePropertiesProperties.DeleteRetentionPolicy; deletePolicy != nil {
if enabled := deletePolicy.Enabled; enabled != nil && *enabled {
days := 0
if deletePolicy.Days != nil {
days = int(*deletePolicy.Days)
}
blobProperties["delete_retention_policy"] = flattenBlobPropertiesDeleteRetentionPolicy(deletePolicy)
}

if len(blobProperties) == 0 {
return properties
}

return []interface{}{blobProperties}
}

func flattenBlobPropertiesCorsRule(input *storage.CorsRules) []interface{} {
corsRules := make([]interface{}, 0)

if input == nil || input.CorsRules == nil {
return corsRules
}

for _, corsRule := range *input.CorsRules {
attr := make(map[string]interface{})

deleteRetentionPolicies = append(deleteRetentionPolicies, map[string]interface{}{
"days": days,
})
if corsRule.AllowedOrigins != nil {
attr["allowed_origins"] = *corsRule.AllowedOrigins
}
if corsRule.AllowedMethods != nil {
attr["allowed_methods"] = *corsRule.AllowedMethods
}
if corsRule.AllowedHeaders != nil {
attr["allowed_headers"] = *corsRule.AllowedHeaders
}
if corsRule.ExposedHeaders != nil {
attr["exposed_headers"] = *corsRule.ExposedHeaders
}
if corsRule.MaxAgeInSeconds != nil {
attr["max_age_in_seconds"] = *corsRule.MaxAgeInSeconds
}

corsRules = append(corsRules, attr)
}

return []interface{}{
map[string]interface{}{
"delete_retention_policy": deleteRetentionPolicies,
},
return corsRules
}

func flattenBlobPropertiesDeleteRetentionPolicy(input *storage.DeleteRetentionPolicy) []interface{} {
deleteRetentionPolicy := make([]interface{}, 0)

if input == nil {
return deleteRetentionPolicy
}

if enabled := input.Enabled; enabled != nil && *enabled {
days := 0
if input.Days != nil {
days = int(*input.Days)
}

attr := make(map[string]interface{})
attr["days"] = days

deleteRetentionPolicy = append(deleteRetentionPolicy, attr)
}

return deleteRetentionPolicy
}

func flattenQueueProperties(input queues.StorageServicePropertiesResponse) []interface{} {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,7 @@ func TestAccAzureRMStorageAccount_blobProperties(t *testing.T) {
Config: testAccAzureRMStorageAccount_blobProperties(data),
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMStorageAccountExists(data.ResourceName),
resource.TestCheckResourceAttr(data.ResourceName, "blob_properties.0.cors_rule.#", "1"),
resource.TestCheckResourceAttr(data.ResourceName, "blob_properties.0.delete_retention_policy.0.days", "300"),
),
},
Expand All @@ -619,6 +620,7 @@ func TestAccAzureRMStorageAccount_blobProperties(t *testing.T) {
Config: testAccAzureRMStorageAccount_blobPropertiesUpdated(data),
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMStorageAccountExists(data.ResourceName),
resource.TestCheckResourceAttr(data.ResourceName, "blob_properties.0.cors_rule.#", "2"),
resource.TestCheckResourceAttr(data.ResourceName, "blob_properties.0.delete_retention_policy.0.days", "7"),
),
},
Expand Down Expand Up @@ -1391,6 +1393,14 @@ resource "azurerm_storage_account" "test" {
account_replication_type = "LRS"
blob_properties {
cors_rule {
allowed_origins = ["http://www.example.com"]
exposed_headers = ["x-tempo-*"]
allowed_headers = ["x-tempo-*"]
allowed_methods = ["GET", "PUT"]
max_age_in_seconds = "500"
}
delete_retention_policy {
days = 300
}
Expand All @@ -1415,6 +1425,22 @@ resource "azurerm_storage_account" "test" {
account_replication_type = "LRS"
blob_properties {
cors_rule {
allowed_origins = ["http://www.example.com"]
exposed_headers = ["x-tempo-*", "x-method-*"]
allowed_headers = ["*"]
allowed_methods = ["GET"]
max_age_in_seconds = "2000000000"
}
cors_rule {
allowed_origins = ["http://www.test.com"]
exposed_headers = ["x-tempo-*"]
allowed_headers = ["*"]
allowed_methods = ["PUT"]
max_age_in_seconds = "1000"
}
delete_retention_policy {
}
}
Expand Down
4 changes: 3 additions & 1 deletion website/docs/r/storage_account.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ The following arguments are supported:

A `blob_properties` block supports the following:

* `cors_rule` - (Optional) A `cors_rule` block as defined below.

* `delete_retention_policy` - (Optional) A `delete_retention_policy` block as defined below.

---
Expand Down Expand Up @@ -221,7 +223,7 @@ any combination of `Logging`, `Metrics`, `AzureServices`, or `None`.

A `queue_properties` block supports the following:

* `cors_rule` - (Optional) A `cors_rule` block as defined below.
* `cors_rule` - (Optional) A `cors_rule` block as defined above.

* `logging` - (Optional) A `logging` block as defined below.

Expand Down

0 comments on commit f2baa9b

Please sign in to comment.