diff --git a/internal/services/storage/storage_account_resource.go b/internal/services/storage/storage_account_resource.go index a953917c26eb..0927a1e08c5e 100644 --- a/internal/services/storage/storage_account_resource.go +++ b/internal/services/storage/storage_account_resource.go @@ -1324,7 +1324,7 @@ func resourceStorageAccountCreate(d *pluginsdk.ResourceData, meta interface{}) e } blobClient := meta.(*clients.Client).Storage.BlobServicesClient - blobProperties, err := expandBlobProperties(val.([]interface{})) + blobProperties, err := expandBlobProperties(storage.Kind(accountKind), val.([]interface{})) if err != nil { return err } @@ -1794,7 +1794,7 @@ func resourceStorageAccountUpdate(d *pluginsdk.ResourceData, meta interface{}) e } blobClient := meta.(*clients.Client).Storage.BlobServicesClient - blobProperties, err := expandBlobProperties(d.Get("blob_properties").([]interface{})) + blobProperties, err := expandBlobProperties(storage.Kind(accountKind), d.Get("blob_properties").([]interface{})) if err != nil { return err } @@ -2611,25 +2611,33 @@ func expandStorageAccountPrivateLinkAccess(inputs []interface{}, tenantId string return &privateLinkAccess } -func expandBlobProperties(input []interface{}) (*storage.BlobServiceProperties, error) { +func expandBlobProperties(kind storage.Kind, input []interface{}) (*storage.BlobServiceProperties, error) { props := storage.BlobServiceProperties{ BlobServicePropertiesProperties: &storage.BlobServicePropertiesProperties{ Cors: &storage.CorsRules{ CorsRules: &[]storage.CorsRule{}, }, - IsVersioningEnabled: utils.Bool(false), - ChangeFeed: &storage.ChangeFeed{ - Enabled: utils.Bool(false), - }, DeleteRetentionPolicy: &storage.DeleteRetentionPolicy{ Enabled: utils.Bool(false), }, - LastAccessTimeTrackingPolicy: &storage.LastAccessTimeTrackingPolicy{ - Enable: utils.Bool(false), - }, }, } + // `Storage` (v1) kind doesn't support: + // - LastAccessTimeTrackingPolicy: Confirmed by SRP. + // - ChangeFeed: See https://learn.microsoft.com/en-us/azure/storage/blobs/storage-blob-change-feed?tabs=azure-portal#enable-and-disable-the-change-feed. + // - Versioning: See https://learn.microsoft.com/en-us/azure/storage/blobs/versioning-overview#how-blob-versioning-works + // - Restore Policy: See https://learn.microsoft.com/en-us/azure/storage/blobs/point-in-time-restore-overview#prerequisites-for-point-in-time-restore + if kind != storage.KindStorage { + props.LastAccessTimeTrackingPolicy = &storage.LastAccessTimeTrackingPolicy{ + Enable: utils.Bool(false), + } + props.ChangeFeed = &storage.ChangeFeed{ + Enabled: utils.Bool(false), + } + props.IsVersioningEnabled = utils.Bool(false) + } + if len(input) == 0 || input[0] == nil { return &props, nil } @@ -2642,28 +2650,53 @@ func expandBlobProperties(input []interface{}) (*storage.BlobServiceProperties, containerDeletePolicyRaw := v["container_delete_retention_policy"].([]interface{}) props.BlobServicePropertiesProperties.ContainerDeleteRetentionPolicy = expandBlobPropertiesDeleteRetentionPolicy(containerDeletePolicyRaw) - restorePolicyRaw := v["restore_policy"].([]interface{}) - props.BlobServicePropertiesProperties.RestorePolicy = expandBlobPropertiesRestorePolicy(restorePolicyRaw) - corsRaw := v["cors_rule"].([]interface{}) props.BlobServicePropertiesProperties.Cors = expandBlobPropertiesCors(corsRaw) props.IsVersioningEnabled = utils.Bool(v["versioning_enabled"].(bool)) - props.ChangeFeed = &storage.ChangeFeed{ - Enabled: utils.Bool(v["change_feed_enabled"].(bool)), - } - - if v := v["change_feed_retention_in_days"].(int); v != 0 { - props.ChangeFeed.RetentionInDays = utils.Int32((int32)(v)) - } - if version, ok := v["default_service_version"].(string); ok && version != "" { props.DefaultServiceVersion = utils.String(version) } - props.LastAccessTimeTrackingPolicy = &storage.LastAccessTimeTrackingPolicy{ - Enable: utils.Bool(v["last_access_time_enabled"].(bool)), + // `Storage` (v1) kind doesn't support: + // - LastAccessTimeTrackingPolicy + // - ChangeFeed + // - Versioning + // - RestorePolicy + lastAccessTimeEnabled := v["last_access_time_enabled"].(bool) + changeFeedEnabled := v["change_feed_enabled"].(bool) + changeFeedRetentionInDays := v["change_feed_retention_in_days"].(int) + restorePolicyRaw := v["restore_policy"].([]interface{}) + versioningEnabled := v["versioning_enabled"].(bool) + if kind != storage.KindStorage { + props.BlobServicePropertiesProperties.LastAccessTimeTrackingPolicy = &storage.LastAccessTimeTrackingPolicy{ + Enable: utils.Bool(lastAccessTimeEnabled), + } + props.BlobServicePropertiesProperties.ChangeFeed = &storage.ChangeFeed{ + Enabled: utils.Bool(changeFeedEnabled), + } + if changeFeedRetentionInDays != 0 { + props.BlobServicePropertiesProperties.ChangeFeed.RetentionInDays = utils.Int32(int32(changeFeedRetentionInDays)) + } + props.BlobServicePropertiesProperties.RestorePolicy = expandBlobPropertiesRestorePolicy(restorePolicyRaw) + props.BlobServicePropertiesProperties.IsVersioningEnabled = &versioningEnabled + } else { + if lastAccessTimeEnabled { + return nil, fmt.Errorf("`last_access_time_enabled` can not be configured when `kind` is set to `Storage` (v1)") + } + if changeFeedEnabled { + return nil, fmt.Errorf("`change_feed_enabled` can not be configured when `kind` is set to `Storage` (v1)") + } + if changeFeedRetentionInDays != 0 { + return nil, fmt.Errorf("`change_feed_retention_in_days` can not be configured when `kind` is set to `Storage` (v1)") + } + if len(restorePolicyRaw) != 0 { + return nil, fmt.Errorf("`restore_policy` can not be configured when `kind` is set to `Storage` (v1)") + } + if versioningEnabled { + return nil, fmt.Errorf("`versioning_enabled` can not be configured when `kind` is set to `Storage` (v1)") + } } // Sanity check for the prerequisites of restore_policy diff --git a/internal/services/storage/storage_account_resource_test.go b/internal/services/storage/storage_account_resource_test.go index a233db540581..75e1b987bd0c 100644 --- a/internal/services/storage/storage_account_resource_test.go +++ b/internal/services/storage/storage_account_resource_test.go @@ -695,6 +695,21 @@ func TestAccStorageAccount_blobPropertiesEmptyAllowedExposedHeaders(t *testing.T }) } +func TestAccStorageAccount_blobProperties_kindStorageNotSupportLastAccessTimeEnabled(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_storage_account", "test") + r := StorageAccountResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.blobPropertiesStorageKindNotSupportLastAccessTimeEnabled(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func TestAccStorageAccount_queueProperties(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_storage_account", "test") r := StorageAccountResource{} @@ -4463,3 +4478,52 @@ resource "azurerm_storage_account" "test" { } `, data.RandomInteger, data.Locations.Primary, data.RandomString) } + +func (r StorageAccountResource) blobPropertiesStorageKindNotSupportLastAccessTimeEnabled(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestAzureRMSA-%d" + location = "%s" +} + +resource "azurerm_storage_account" "test" { + name = "unlikely23exst2acct%s" + resource_group_name = azurerm_resource_group.test.name + + location = azurerm_resource_group.test.location + account_kind = "Storage" + account_tier = "Standard" + 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", "PATCH"] + max_age_in_seconds = "500" + } + + delete_retention_policy { + days = 300 + } + + default_service_version = "2019-07-07" + container_delete_retention_policy { + days = 7 + } + + # Following properties are not supported for "Storage" (v1) kind + last_access_time_enabled = false + change_feed_enabled = false + versioning_enabled = false + # change_feed_retention_in_days + # restore_policy + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomString) +} diff --git a/website/docs/r/storage_account.html.markdown b/website/docs/r/storage_account.html.markdown index e301ad8edd02..26a0f722980e 100644 --- a/website/docs/r/storage_account.html.markdown +++ b/website/docs/r/storage_account.html.markdown @@ -183,16 +183,26 @@ A `blob_properties` block supports the following: * `restore_policy` - (Optional) A `restore_policy` block as defined below. This must be used together with `delete_retention_policy` set, `versioning_enabled` and `change_feed_enabled` set to `true`. +-> **NOTE:** This field cannot be configured when `kind` is set to `Storage` (V1). + * `versioning_enabled` - (Optional) Is versioning enabled? Default to `false`. +-> **NOTE:** This field cannot be configured when `kind` is set to `Storage` (V1). + * `change_feed_enabled` - (Optional) Is the blob service properties for change feed events enabled? Default to `false`. +-> **NOTE:** This field cannot be configured when `kind` is set to `Storage` (V1). + * `change_feed_retention_in_days` - (Optional) The duration of change feed events retention in days. The possible values are between 1 and 146000 days (400 years). Setting this to null (or omit this in the configuration file) indicates an infinite retention of the change feed. +-> **NOTE:** This field cannot be configured when `kind` is set to `Storage` (V1). + * `default_service_version` - (Optional) The API Version which should be used by default for requests to the Data Plane API if an incoming request doesn't specify an API Version. * `last_access_time_enabled` - (Optional) Is the last access time based tracking enabled? Default to `false`. +-> **NOTE:** This field cannot be configured when `kind` is set to `Storage` (V1). + * `container_delete_retention_policy` - (Optional) A `container_delete_retention_policy` block as defined below. ---