diff --git a/azurerm/internal/services/cosmos/resource_arm_cosmosdb_mongo_collection.go b/azurerm/internal/services/cosmos/resource_arm_cosmosdb_mongo_collection.go index 5b6cb44645ec..6ff840c1edae 100644 --- a/azurerm/internal/services/cosmos/resource_arm_cosmosdb_mongo_collection.go +++ b/azurerm/internal/services/cosmos/resource_arm_cosmosdb_mongo_collection.go @@ -82,6 +82,45 @@ func resourceArmCosmosDbMongoCollection() *schema.Resource { Computed: true, ValidateFunc: validate.CosmosThroughput, }, + + "index": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "keys": { + Type: schema.TypeSet, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + + "unique": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + }, + }, + }, + + "system_indexes": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "keys": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + + "unique": { + Type: schema.TypeBool, + Computed: true, + }, + }, + }, + }, }, } } @@ -121,7 +160,7 @@ func resourceArmCosmosDbMongoCollectionCreate(d *schema.ResourceData, meta inter MongoDBCollectionCreateUpdateProperties: &documentdb.MongoDBCollectionCreateUpdateProperties{ Resource: &documentdb.MongoDBCollectionResource{ ID: &name, - Indexes: expandCosmosMongoCollectionIndexes(ttl), + Indexes: expandCosmosMongoCollectionIndex(d.Get("index").(*schema.Set).List(), ttl), }, Options: map[string]*string{}, }, @@ -181,7 +220,7 @@ func resourceArmCosmosDbMongoCollectionUpdate(d *schema.ResourceData, meta inter MongoDBCollectionCreateUpdateProperties: &documentdb.MongoDBCollectionCreateUpdateProperties{ Resource: &documentdb.MongoDBCollectionResource{ ID: &id.Collection, - Indexes: expandCosmosMongoCollectionIndexes(ttl), + Indexes: expandCosmosMongoCollectionIndex(d.Get("index").(*schema.Set).List(), ttl), }, Options: map[string]*string{}, }, @@ -263,8 +302,15 @@ func resourceArmCosmosDbMongoCollectionRead(d *schema.ResourceData, meta interfa d.Set("shard_key", k) } - if props.Indexes != nil { - d.Set("default_ttl_seconds", flattenCosmosMongoCollectionIndexes(props.Indexes)) + indexes, systemIndexes, ttl := flattenCosmosMongoCollectionIndex(props.Indexes) + if err := d.Set("default_ttl_seconds", ttl); err != nil { + return fmt.Errorf("failed to set `default_ttl_seconds`: %+v", err) + } + if err := d.Set("index", indexes); err != nil { + return fmt.Errorf("failed to set `index`: %+v", err) + } + if err := d.Set("system_indexes", systemIndexes); err != nil { + return fmt.Errorf("failed to set `system_indexes`: %+v", err) } } @@ -307,11 +353,26 @@ func resourceArmCosmosDbMongoCollectionDelete(d *schema.ResourceData, meta inter return nil } -func expandCosmosMongoCollectionIndexes(defaultTtl *int) *[]documentdb.MongoIndex { - outputs := make([]documentdb.MongoIndex, 0) +func expandCosmosMongoCollectionIndex(indexes []interface{}, defaultTtl *int) *[]documentdb.MongoIndex { + results := make([]documentdb.MongoIndex, 0) + + if len(indexes) != 0 { + for _, v := range indexes { + index := v.(map[string]interface{}) + + results = append(results, documentdb.MongoIndex{ + Key: &documentdb.MongoIndexKeys{ + Keys: utils.ExpandStringSlice(index["keys"].(*schema.Set).List()), + }, + Options: &documentdb.MongoIndexOptions{ + Unique: utils.Bool(index["unique"].(bool)), + }, + }) + } + } if defaultTtl != nil { - outputs = append(outputs, documentdb.MongoIndex{ + results = append(results, documentdb.MongoIndex{ Key: &documentdb.MongoIndexKeys{ Keys: &[]string{"_ts"}, }, @@ -321,24 +382,62 @@ func expandCosmosMongoCollectionIndexes(defaultTtl *int) *[]documentdb.MongoInde }) } - return &outputs + return &results } -func flattenCosmosMongoCollectionIndexes(indexes *[]documentdb.MongoIndex) *int { - var ttl int - for _, i := range *indexes { - if key := i.Key; key != nil { - var ttlInner int32 +func flattenCosmosMongoCollectionIndex(input *[]documentdb.MongoIndex) (*[]map[string]interface{}, *[]map[string]interface{}, *int32) { + indexes := make([]map[string]interface{}, 0) + systemIndexes := make([]map[string]interface{}, 0) + var ttl *int32 + if input == nil { + return &indexes, &systemIndexes, ttl + } + + for _, v := range *input { + index := map[string]interface{}{} + systemIndex := map[string]interface{}{} + + if v.Key != nil && v.Key.Keys != nil && len(*v.Key.Keys) > 0 { + key := (*v.Key.Keys)[0] + + switch key { + // As `DocumentDBDefaultIndex` and `_id` cannot be updated, so they would be moved into `system_indexes`. + case "_id": + systemIndex["keys"] = utils.FlattenStringSlice(v.Key.Keys) + // The system index `_id` is always unique but api returns nil and it would be converted to `false` by zero-value. So it has to be manually set as `true`. + systemIndex["unique"] = true - if keys := key.Keys; keys != nil && len(*keys) > 0 { - k := (*keys)[0] + systemIndexes = append(systemIndexes, systemIndex) + case "DocumentDBDefaultIndex": + // Updating system index `DocumentDBDefaultIndex` is not a supported scenario. + systemIndex["keys"] = utils.FlattenStringSlice(v.Key.Keys) - if k == "_ts" { - ttl = int(ttlInner) + isUnique := false + if v.Options != nil && v.Options.Unique != nil { + isUnique = *v.Options.Unique } + systemIndex["unique"] = isUnique + + systemIndexes = append(systemIndexes, systemIndex) + case "_ts": + if v.Options != nil && v.Options.ExpireAfterSeconds != nil { + // As `ExpireAfterSeconds` only can be applied to system index `_ts`, so it would be set in `default_ttl_seconds`. + ttl = v.Options.ExpireAfterSeconds + } + default: + // The other settable indexes would be set in `index` + index["keys"] = utils.FlattenStringSlice(v.Key.Keys) + + isUnique := false + if v.Options != nil && v.Options.Unique != nil { + isUnique = *v.Options.Unique + } + index["unique"] = isUnique + + indexes = append(indexes, index) } } } - return &ttl + return &indexes, &systemIndexes, ttl } diff --git a/azurerm/internal/services/cosmos/tests/resource_arm_cosmosdb_mongo_collection_test.go b/azurerm/internal/services/cosmos/tests/resource_arm_cosmosdb_mongo_collection_test.go index 0a84cb94d9e6..8605cc6aa0ec 100644 --- a/azurerm/internal/services/cosmos/tests/resource_arm_cosmosdb_mongo_collection_test.go +++ b/azurerm/internal/services/cosmos/tests/resource_arm_cosmosdb_mongo_collection_test.go @@ -121,6 +121,28 @@ func TestAccAzureRMCosmosDbMongoCollection_throughput(t *testing.T) { }) } +func TestAccAzureRMCosmosDbMongoCollection_withIndex(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_cosmosdb_mongo_collection", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMCosmosDbMongoCollectionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMCosmosDbMongoCollection_withIndex(data), + Check: resource.ComposeAggregateTestCheckFunc( + testCheckAzureRMCosmosDbMongoCollectionExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "default_ttl_seconds", "707"), + resource.TestCheckResourceAttr(data.ResourceName, "index.#", "3"), + resource.TestCheckResourceAttr(data.ResourceName, "system_indexes.#", "2"), + ), + }, + data.ImportStep(), + }, + }) +} + func testCheckAzureRMCosmosDbMongoCollectionDestroy(s *terraform.State) error { client := acceptance.AzureProvider.Meta().(*clients.Client).Cosmos.DatabaseClient ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext @@ -238,3 +260,32 @@ resource "azurerm_cosmosdb_mongo_collection" "test" { } `, testAccAzureRMCosmosDbMongoDatabase_basic(data), data.RandomInteger, throughput) } + +func testAccAzureRMCosmosDbMongoCollection_withIndex(data acceptance.TestData) string { + return fmt.Sprintf(` +%[1]s + +resource "azurerm_cosmosdb_mongo_collection" "test" { + name = "acctest-%[2]d" + resource_group_name = azurerm_cosmosdb_mongo_database.test.resource_group_name + account_name = azurerm_cosmosdb_mongo_database.test.account_name + database_name = azurerm_cosmosdb_mongo_database.test.name + default_ttl_seconds = 707 + throughput = 400 + + index { + keys = ["seven", "six"] + unique = true + } + + index { + keys = ["day"] + unique = false + } + + index { + keys = ["month"] + } +} +`, testAccAzureRMCosmosDbMongoDatabase_basic(data), data.RandomInteger) +} diff --git a/website/docs/r/cosmosdb_mongo_collection.html.markdown b/website/docs/r/cosmosdb_mongo_collection.html.markdown index a24f69d3c3a6..e71cdf464fbe 100644 --- a/website/docs/r/cosmosdb_mongo_collection.html.markdown +++ b/website/docs/r/cosmosdb_mongo_collection.html.markdown @@ -45,14 +45,33 @@ The following arguments are supported: * `database_name` - (Required) The name of the Cosmos DB Mongo Database in which the Cosmos DB Mongo Collection is created. Changing this forces a new resource to be created. * `default_ttl_seconds` - (Required) The default Time To Live in seconds. If the value is `0` items are not automatically expired. * `shard_key` - (Required) The name of the key to partition on for sharding. There must not be any other unique index keys. +* `index` - (Optional) One or more `index` blocks as defined below. * `throughput` - (Optional) The throughput of the MongoDB collection (RU/s). Must be set in increments of `100`. The minimum value is `400`. This must be set upon database creation otherwise it cannot be updated without a manual terraform destroy-apply. +--- + +The `index` block supports the following: + +* `keys` - (Required) Specifies the list of user settable keys for each Cosmos DB Mongo Collection. + +* `unique` - (Optional) Is the index unique or not? Defaults to `false`. + ## Attributes Reference The following attributes are exported: * `id` - The ID of the Cosmos DB Mongo Collection. +* `system_indexes` - One or more `system_indexes` blocks as defined below. + +--- + +The `system_indexes` block supports the following: + +* `keys` - The list of system keys which are not settable for each Cosmos DB Mongo Collection. + +* `unique` - Identifies whether the table contains no duplicate values. + ## Timeouts The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: