Skip to content

Commit

Permalink
Including hashicorp#24830
Browse files Browse the repository at this point in the history
* Initial Check-in...

* Add regression test case...

* Change fix design...

* Address PR comments...

* Updated description of the regression test case...
  • Loading branch information
WodansSon authored Feb 15, 2024
1 parent 2735989 commit 446a4a0
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 26 deletions.
32 changes: 23 additions & 9 deletions internal/services/cosmos/cosmosdb_account_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -354,18 +354,20 @@ func resourceCosmosDbAccount() *pluginsdk.Resource {
}, false),
},

// This value can only change if the 'consistency_level' is set to 'BoundedStaleness'
"max_interval_in_seconds": {
Type: pluginsdk.TypeInt,
Optional: true,
Computed: true,
Default: 5,
DiffSuppressFunc: suppressConsistencyPolicyStalenessConfiguration,
ValidateFunc: validation.IntBetween(5, 86400), // single region values
},

// This value can only change if the 'consistency_level' is set to 'BoundedStaleness'
"max_staleness_prefix": {
Type: pluginsdk.TypeInt,
Optional: true,
Computed: true,
Default: 100,
DiffSuppressFunc: suppressConsistencyPolicyStalenessConfiguration,
ValidateFunc: validation.IntBetween(10, 2147483647), // single region values
},
Expand Down Expand Up @@ -1907,28 +1909,37 @@ func expandCosmosdbAccountBackup(input []interface{}, backupHasChange bool, crea
switch attr["type"].(string) {
case string(cosmosdb.BackupPolicyTypeContinuous):
if v := attr["interval_in_minutes"].(int); v != 0 && !backupHasChange {
return nil, fmt.Errorf("`interval_in_minutes` can not be set when `type` in `backup` is `Continuous`")
return nil, fmt.Errorf("`interval_in_minutes` cannot be defined when the `backup.type` is set to %q", cosmosdb.BackupPolicyTypeContinuous)
}

if v := attr["retention_in_hours"].(int); v != 0 && !backupHasChange {
return nil, fmt.Errorf("`retention_in_hours` can not be set when `type` in `backup` is `Continuous`")
return nil, fmt.Errorf("`retention_in_hours` cannot be defined when the `backup.type` is set to %q", cosmosdb.BackupPolicyTypeContinuous)
}

if v := attr["storage_redundancy"].(string); v != "" && !backupHasChange {
return nil, fmt.Errorf("`storage_redundancy` can not be set when `type` in `backup` is `Continuous`")
return nil, fmt.Errorf("`storage_redundancy` cannot be defined when the `backup.type` is set to %q", cosmosdb.BackupPolicyTypeContinuous)
}

return cosmosdb.ContinuousModeBackupPolicy{}, nil

case string(cosmosdb.BackupPolicyTypePeriodic):
if createMode != "" {
return nil, fmt.Errorf("`create_mode` only works when `backup.type` is `Continuous`")
return nil, fmt.Errorf("`create_mode` can only be defined when the `backup.type` is set to %q, got %q", cosmosdb.BackupPolicyTypeContinuous, cosmosdb.BackupPolicyTypePeriodic)
}

return cosmosdb.PeriodicModeBackupPolicy{
// Mirror the behavior of the old SDK...
periodicModeBackupPolicy := cosmosdb.PeriodicModeBackupPolicy{
PeriodicModeProperties: &cosmosdb.PeriodicModeProperties{
BackupIntervalInMinutes: utils.Int64(int64(attr["interval_in_minutes"].(int))),
BackupRetentionIntervalInHours: utils.Int64(int64(attr["retention_in_hours"].(int))),
BackupStorageRedundancy: pointer.To(cosmosdb.BackupStorageRedundancy(attr["storage_redundancy"].(string))),
},
}, nil
}

if v := attr["storage_redundancy"].(string); v != "" {
periodicModeBackupPolicy.PeriodicModeProperties.BackupStorageRedundancy = pointer.To(cosmosdb.BackupStorageRedundancy(attr["storage_redundancy"].(string)))
}

return periodicModeBackupPolicy, nil

default:
return nil, fmt.Errorf("unknown `type` in `backup`:%+v", attr["type"].(string))
Expand All @@ -1953,13 +1964,16 @@ func flattenCosmosdbAccountBackup(input cosmosdb.BackupPolicy) ([]interface{}, e
if v := backupPolicy.PeriodicModeProperties.BackupIntervalInMinutes; v != nil {
interval = int(*v)
}

if v := backupPolicy.PeriodicModeProperties.BackupRetentionIntervalInHours; v != nil {
retention = int(*v)
}

var storageRedundancy cosmosdb.BackupStorageRedundancy
if backupPolicy.PeriodicModeProperties.BackupStorageRedundancy != nil {
storageRedundancy = pointer.From(backupPolicy.PeriodicModeProperties.BackupStorageRedundancy)
}

return []interface{}{
map[string]interface{}{
"type": string(cosmosdb.BackupPolicyTypePeriodic),
Expand Down
68 changes: 67 additions & 1 deletion internal/services/cosmos/cosmosdb_account_resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -992,7 +992,30 @@ func TestAccCosmosDBAccount_identity(t *testing.T) {
})
}

func TestAccCosmosDBAccount_backup(t *testing.T) {
func TestAccCosmosDBAccount_storageRedundancyUndefined(t *testing.T) {
// Regression test for MSFT IcM where the SDK is supplied a 'nil' pointer for the
// 'storage_redundancy' field, the new transport layer would send an 'empty' string
// instead of omitting the field from the PUT call which would result in the API
// returning an error...
data := acceptance.BuildTestData(t, "azurerm_cosmosdb_account", "test")
r := CosmosDBAccountResource{}

data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.storageRedundancyUndefined(data, cosmosdb.DatabaseAccountKindGlobalDocumentDB, cosmosdb.DefaultConsistencyLevelEventual),
Check: acceptance.ComposeAggregateTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("backup.0.type").HasValue("Periodic"),
check.That(data.ResourceName).Key("backup.0.interval_in_minutes").HasValue("120"),
check.That(data.ResourceName).Key("backup.0.retention_in_hours").HasValue("10"),
check.That(data.ResourceName).Key("backup.0.storage_redundancy").HasValue("Geo"),
),
},
data.ImportStep(),
})
}

func TestAccCosmosDBAccount_backupOnly(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_cosmosdb_account", "test")
r := CosmosDBAccountResource{}

Expand All @@ -1012,6 +1035,10 @@ func TestAccCosmosDBAccount_backup(t *testing.T) {
Config: r.basicWithBackupPeriodic(data, cosmosdb.DatabaseAccountKindGlobalDocumentDB, cosmosdb.DefaultConsistencyLevelEventual),
Check: acceptance.ComposeAggregateTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("backup.0.type").HasValue("Periodic"),
check.That(data.ResourceName).Key("backup.0.interval_in_minutes").HasValue("120"),
check.That(data.ResourceName).Key("backup.0.retention_in_hours").HasValue("10"),
check.That(data.ResourceName).Key("backup.0.storage_redundancy").HasValue("Geo"),
),
},
data.ImportStep(),
Expand All @@ -1020,6 +1047,9 @@ func TestAccCosmosDBAccount_backup(t *testing.T) {
Check: acceptance.ComposeAggregateTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("backup.0.type").HasValue("Periodic"),
check.That(data.ResourceName).Key("backup.0.interval_in_minutes").HasValue("60"),
check.That(data.ResourceName).Key("backup.0.retention_in_hours").HasValue("8"),
check.That(data.ResourceName).Key("backup.0.storage_redundancy").HasValue("Local"),
),
},
data.ImportStep(),
Expand Down Expand Up @@ -3380,6 +3410,42 @@ resource "azurerm_cosmosdb_account" "test" {
`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, string(kind), string(consistency))
}

func (CosmosDBAccountResource) storageRedundancyUndefined(data acceptance.TestData, kind cosmosdb.DatabaseAccountKind, consistency cosmosdb.DefaultConsistencyLevel) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "test" {
name = "acctestRG-cosmos-%d"
location = "%s"
}
resource "azurerm_cosmosdb_account" "test" {
name = "acctest-ca-%d"
location = azurerm_resource_group.test.location
resource_group_name = azurerm_resource_group.test.name
offer_type = "Standard"
kind = "%s"
consistency_policy {
consistency_level = "%s"
}
geo_location {
location = azurerm_resource_group.test.location
failover_priority = 0
}
backup {
type = "Periodic"
interval_in_minutes = 120
retention_in_hours = 10
}
}
`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, string(kind), string(consistency))
}

func (CosmosDBAccountResource) basicWithBackupPeriodicUpdate(data acceptance.TestData, kind cosmosdb.DatabaseAccountKind, consistency cosmosdb.DefaultConsistencyLevel) string {
return fmt.Sprintf(`
provider "azurerm" {
Expand Down
36 changes: 20 additions & 16 deletions website/docs/r/cosmosdb_account.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,11 @@ The following arguments are supported:

* `create_mode` - (Optional) The creation mode for the CosmosDB Account. Possible values are `Default` and `Restore`. Changing this forces a new resource to be created.

~> **NOTE:** `create_mode` only works when `backup.type` is `Continuous`.
~> **Note:** `create_mode` can only be defined when the `backup.type` is set to `Continuous`.

* `default_identity_type` - (Optional) The default identity for accessing Key Vault. Possible values are `FirstPartyIdentity`, `SystemAssignedIdentity` or `UserAssignedIdentity`. Defaults to `FirstPartyIdentity`.

~> **NOTE:** When `default_identity_type` is a `UserAssignedIdentity` it must include the User Assigned Identity ID in the following format: `UserAssignedIdentity=/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{userAssignedIdentityName}`.
~> **Note:** When `default_identity_type` is a `UserAssignedIdentity` it must include the User Assigned Identity ID in the following format: `UserAssignedIdentity=/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{userAssignedIdentityName}`.

* `kind` - (Optional) Specifies the Kind of CosmosDB to create - possible values are `GlobalDocumentDB`, `MongoDB` and `Parse`. Defaults to `GlobalDocumentDB`. Changing this forces a new resource to be created.

Expand All @@ -136,9 +136,9 @@ The following arguments are supported:

* `ip_range_filter` - (Optional) CosmosDB Firewall Support: This value specifies the set of IP addresses or IP address ranges in CIDR form to be included as the allowed list of client IPs for a given database account. IP addresses/ranges must be comma separated and must not contain any spaces.

~> **NOTE:** To enable the "Allow access from the Azure portal" behavior, you should add the IP addresses provided by the [documentation](https://docs.microsoft.com/azure/cosmos-db/how-to-configure-firewall#allow-requests-from-the-azure-portal) to this list.
~> **Note:** To enable the "Allow access from the Azure portal" behavior, you should add the IP addresses provided by the [documentation](https://docs.microsoft.com/azure/cosmos-db/how-to-configure-firewall#allow-requests-from-the-azure-portal) to this list.

~> **NOTE:** To enable the "Accept connections from within public Azure datacenters" behavior, you should add `0.0.0.0` to the list, see the [documentation](https://docs.microsoft.com/azure/cosmos-db/how-to-configure-firewall#allow-requests-from-global-azure-datacenters-or-other-sources-within-azure) for more details.
~> **Note:** To enable the "Accept connections from within public Azure datacenters" behavior, you should add `0.0.0.0` to the list, see the [documentation](https://docs.microsoft.com/azure/cosmos-db/how-to-configure-firewall#allow-requests-from-global-azure-datacenters-or-other-sources-within-azure) for more details.

* `enable_free_tier` - (Optional) Enable the Free Tier pricing option for this Cosmos DB account. Defaults to `false`. Changing this forces a new resource to be created.

Expand All @@ -156,9 +156,9 @@ The following arguments are supported:

* `key_vault_key_id` - (Optional) A versionless Key Vault Key ID for CMK encryption. Changing this forces a new resource to be created.

~> **NOTE:** When referencing an `azurerm_key_vault_key` resource, use `versionless_id` instead of `id`
~> **Note:** When referencing an `azurerm_key_vault_key` resource, use `versionless_id` instead of `id`

~> **NOTE:** In order to use a `Custom Key` from Key Vault for encryption you must grant Azure Cosmos DB Service access to your key vault. For instructions on how to configure your Key Vault correctly please refer to the [product documentation](https://docs.microsoft.com/azure/cosmos-db/how-to-setup-cmk#add-an-access-policy-to-your-azure-key-vault-instance)
~> **Note:** In order to use a `Custom Key` from Key Vault for encryption you must grant Azure Cosmos DB Service access to your key vault. For instructions on how to configure your Key Vault correctly please refer to the [product documentation](https://docs.microsoft.com/azure/cosmos-db/how-to-setup-cmk#add-an-access-policy-to-your-azure-key-vault-instance)

* `virtual_network_rule` - (Optional) Specifies a `virtual_network_rule` block as defined below, used to define which subnets are allowed to access this CosmosDB account.

Expand All @@ -182,7 +182,7 @@ The following arguments are supported:

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

~> **NOTE:** `restore` should be set when `create_mode` is `Restore`.
~> **Note:** `restore` should be set when `create_mode` is `Restore`.

---

Expand All @@ -194,7 +194,7 @@ The `consistency_policy` block Configures the database consistency and supports

* `max_staleness_prefix` - (Optional) When used with the Bounded Staleness consistency level, this value represents the number of stale requests tolerated. The accepted range for this value is `10``2147483647`. Defaults to `100`. Required when `consistency_level` is set to `BoundedStaleness`.

~> **Note:** `max_interval_in_seconds` and `max_staleness_prefix` can only be set to custom values when `consistency_level` is set to `BoundedStaleness` - otherwise they will return the default values shown above.
~> **Note:** `max_interval_in_seconds` and `max_staleness_prefix` can only be set to values other than default when the `consistency_level` is set to `BoundedStaleness`.

---

Expand All @@ -212,11 +212,11 @@ A `capabilities` block Configures the capabilities to be enabled for this Cosmos

* `name` - (Required) The capability to enable - Possible values are `AllowSelfServeUpgradeToMongo36`, `DisableRateLimitingResponses`, `EnableAggregationPipeline`, `EnableCassandra`, `EnableGremlin`, `EnableMongo`, `EnableMongo16MBDocumentSupport`, `EnableMongoRetryableWrites`, `EnableMongoRoleBasedAccessControl`, `EnablePartialUniqueIndex`, `EnableServerless`, `EnableTable`, `EnableTtlOnCustomPath`, `EnableUniqueCompoundNestedDocs`, `MongoDBv3.4` and `mongoEnableDocLevelTTL`.

~> **NOTE:** Setting `MongoDBv3.4` also requires setting `EnableMongo`.
~> **Note:** Setting `MongoDBv3.4` also requires setting `EnableMongo`.

~> **NOTE:** Only `AllowSelfServeUpgradeToMongo36`, `DisableRateLimitingResponses`, `EnableAggregationPipeline`, `MongoDBv3.4`, `EnableMongoRetryableWrites`, `EnableMongoRoleBasedAccessControl`, `EnableUniqueCompoundNestedDocs`, `EnableMongo16MBDocumentSupport`, `mongoEnableDocLevelTTL`, `EnableTtlOnCustomPath` and `EnablePartialUniqueIndex` can be added to an existing Cosmos DB account.
~> **Note:** Only `AllowSelfServeUpgradeToMongo36`, `DisableRateLimitingResponses`, `EnableAggregationPipeline`, `MongoDBv3.4`, `EnableMongoRetryableWrites`, `EnableMongoRoleBasedAccessControl`, `EnableUniqueCompoundNestedDocs`, `EnableMongo16MBDocumentSupport`, `mongoEnableDocLevelTTL`, `EnableTtlOnCustomPath` and `EnablePartialUniqueIndex` can be added to an existing Cosmos DB account.

~> **NOTE:** Only `DisableRateLimitingResponses` and `EnableMongoRetryableWrites` can be removed from an existing Cosmos DB account.
~> **Note:** Only `DisableRateLimitingResponses` and `EnableMongoRetryableWrites` can be removed from an existing Cosmos DB account.

---

Expand All @@ -241,13 +241,17 @@ A `capacity` block supports the following:

A `backup` block supports the following:

* `type` - (Required) The type of the `backup`. Possible values are `Continuous` and `Periodic`. Migration of `Periodic` to `Continuous` is one-way, changing `Continuous` to `Periodic` forces a new resource to be created.
* `type` - (Required) The type of the `backup`. Possible values are `Continuous` and `Periodic`.

* `interval_in_minutes` - (Optional) The interval in minutes between two backups. This is configurable only when `type` is `Periodic`. Possible values are between 60 and 1440.
~> **Note:** Migration of `Periodic` to `Continuous` is one-way, changing `Continuous` to `Periodic` forces a new resource to be created.

* `retention_in_hours` - (Optional) The time in hours that each backup is retained. This is configurable only when `type` is `Periodic`. Possible values are between 8 and 720.
* `interval_in_minutes` - (Optional) The interval in minutes between two backups. Possible values are between 60 and 1440. Defaults to `240`.

* `storage_redundancy` - (Optional) The storage redundancy is used to indicate the type of backup residency. This is configurable only when `type` is `Periodic`. Possible values are `Geo`, `Local` and `Zone`.
* `retention_in_hours` - (Optional) The time in hours that each backup is retained. Possible values are between 8 and 720. Defaults to `8`.

* `storage_redundancy` - (Optional) The storage redundancy is used to indicate the type of backup residency. Possible values are `Geo`, `Local` and `Zone`. Defaults to `Geo`.

~> **Note:** You can only configure `interval_in_minutes`, `retention_in_hours` and `storage_redundancy` when the `type` field is set to `Periodic`.

---

Expand Down Expand Up @@ -277,7 +281,7 @@ A `restore` block supports the following:

* `source_cosmosdb_account_id` - (Required) The resource ID of the restorable database account from which the restore has to be initiated. The example is `/subscriptions/{subscriptionId}/providers/Microsoft.DocumentDB/locations/{location}/restorableDatabaseAccounts/{restorableDatabaseAccountName}`. Changing this forces a new resource to be created.

~> **NOTE:** Any database account with `Continuous` type (live account or accounts deleted in last 30 days) is a restorable database account and there cannot be Create/Update/Delete operations on the restorable database accounts. They can only be read and retrieved by `azurerm_cosmosdb_restorable_database_accounts`.
~> **Note:** Any database account with `Continuous` type (live account or accounts deleted in last 30 days) is a restorable database account and there cannot be Create/Update/Delete operations on the restorable database accounts. They can only be read and retrieved by `azurerm_cosmosdb_restorable_database_accounts`.

* `restore_timestamp_in_utc` - (Required) The creation time of the database or the collection (Datetime Format `RFC 3339`). Changing this forces a new resource to be created.

Expand Down

0 comments on commit 446a4a0

Please sign in to comment.