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

Support autoscaling Cosmos DB databases and containers #7773

Merged
merged 25 commits into from
Sep 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
6363a28
Support Cosmos DB Autoscaling in SQL Databases
marc-sensenich Jul 16, 2020
55c106f
gofmt and lint of Cosmos SQL Database
marc-sensenich Jul 20, 2020
f0d0473
Support Cosmos DB Autoscaling in SQL Containers
marc-sensenich Jul 20, 2020
366f5bf
Support Cosmos DB Autoscaling in Mongo Databases
marc-sensenich Jul 20, 2020
69052a6
Support Cosmos DB Autoscaling in Gremlin Databases
marc-sensenich Jul 20, 2020
ef96502
Support Cosmos DB Autoscaling in Gremlin Graphs
marc-sensenich Jul 20, 2020
ad78641
Support Cosmos DB Autoscaling in Mongo Collections
marc-sensenich Jul 20, 2020
627ec69
Support Cosmos DB Autoscaling in Tables
marc-sensenich Jul 20, 2020
a2eb0fe
Support Cosmos DB Autoscaling in Cassandra Keyspaces
marc-sensenich Jul 20, 2020
9ea59de
fixup! Support Cosmos DB Autoscaling in Mongo Collections
marc-sensenich Jul 20, 2020
d6697a8
fixup! Support Cosmos DB Autoscaling in Tables
marc-sensenich Jul 20, 2020
886eefb
fixup! Support Cosmos DB Autoscaling in Gremlin Graphs
marc-sensenich Jul 20, 2020
7836979
fixup! Support Cosmos DB Autoscaling in Mongo Collections
marc-sensenich Jul 20, 2020
c07c48b
Add documentation for Cosmos DB autoscale_settings
marc-sensenich Jul 21, 2020
f50c2db
fixup! Add documentation for Cosmos DB autoscale_settings
marc-sensenich Jul 21, 2020
97b4f34
fixup! fixup! Add documentation for Cosmos DB autoscale_settings
marc-sensenich Jul 21, 2020
aa28074
fixup! Add documentation for Cosmos DB autoscale_settings
marc-sensenich Jul 21, 2020
2f2629c
Update CosmosMaxThroughput validator to align with conventions
marc-sensenich Aug 15, 2020
1d980ed
fixup! Update CosmosMaxThroughput validator to align with conventions
marc-sensenich Aug 15, 2020
063cebe
Update azurerm/internal/services/cosmos/cosmosdb_table_resource.go
marc-sensenich Sep 11, 2020
e6dd978
Update azurerm/internal/services/cosmos/cosmosdb_gremlin_graph_resour…
marc-sensenich Sep 11, 2020
b7d0d99
Update azurerm/internal/services/cosmos/common/throughput.go
marc-sensenich Sep 11, 2020
464d931
Update azurerm/internal/services/cosmos/common/throughput.go
marc-sensenich Sep 11, 2020
a25ae40
Address PR comments from 2020/09/11
marc-sensenich Sep 11, 2020
324d259
fixup! Address PR comments from 2020/09/11
marc-sensenich Sep 11, 2020
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
25 changes: 25 additions & 0 deletions azurerm/helpers/validate/cosmos.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,28 @@ func CosmosThroughput(v interface{}, k string) (warnings []string, errors []erro

return warnings, errors
}

func CosmosMaxThroughput(i interface{}, k string) (warnings []string, errors []error) {
v, ok := i.(int)
if !ok {
errors = append(errors, fmt.Errorf("expected type of %q to be int", k))
return
}

if v < 4000 {
errors = append(errors, fmt.Errorf(
"%s must be a minimum of 4000", k))
}

if v > 1000000 {
errors = append(errors, fmt.Errorf(
"%s must be a maximum of 1000000", k))
}

if v%1000 != 0 {
errors = append(errors, fmt.Errorf(
"%q must be set in increments of 1000", k))
}

return warnings, errors
}
51 changes: 51 additions & 0 deletions azurerm/helpers/validate/cosmos_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,54 @@ func TestCosmosThroughput(t *testing.T) {
}
}
}

func TestCosmosMaxThroughput(t *testing.T) {
cases := []struct {
Value interface{}
Errors int
}{
{
Value: 400,
Errors: 2,
},
{
Value: 1000,
Errors: 1,
},
{
Value: 4000,
Errors: 0,
},
{
Value: 4001,
Errors: 1,
},
{
Value: 10000,
Errors: 0,
},
{
Value: 54000,
Errors: 0,
},
{
Value: 1000000,
Errors: 0,
},
{
Value: 1100000,
Errors: 1,
},
{
Value: "400",
Errors: 1,
},
}

for _, tc := range cases {
_, errors := CosmosMaxThroughput(tc.Value, "throughput")
if len(errors) != tc.Errors {
t.Fatalf("Expected CosmosMaxThroughput to trigger '%d' errors for '%d' - got '%d'", tc.Errors, tc.Value, len(errors))
}
}
}
62 changes: 62 additions & 0 deletions azurerm/internal/services/cosmos/common/autoscale_settings.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package common

import (
"log"

"github.com/Azure/azure-sdk-for-go/services/cosmos-db/mgmt/2020-04-01/documentdb"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)

func ExpandCosmosDbAutoscaleSettings(d *schema.ResourceData) *documentdb.AutoscaleSettings {
i := d.Get("autoscale_settings").([]interface{})
if len(i) == 0 || i[0] == nil {
log.Printf("[DEBUG] Cosmos DB autoscale settings are not set on the resource")
return nil
}
input := i[0].(map[string]interface{})

autoscaleSettings := documentdb.AutoscaleSettings{}

if maxThroughput, ok := input["max_throughput"].(int); ok {
autoscaleSettings.MaxThroughput = utils.Int32(int32(maxThroughput))
}

return &autoscaleSettings
}

func FlattenCosmosDbAutoscaleSettings(throughputResponse documentdb.ThroughputSettingsGetResults) []interface{} {
results := make([]interface{}, 0)

props := throughputResponse.ThroughputSettingsGetProperties
if props == nil {
return results
}

res := props.Resource
if res == nil {
return results
}

autoscaleSettings := res.AutoscaleSettings
if autoscaleSettings == nil {
log.Printf("[DEBUG] Cosmos DB autoscale settings are not set on the throughput response")
return results
}

result := make(map[string]interface{})

if autoscaleSettings.MaxThroughput != nil {
result["max_throughput"] = autoscaleSettings.MaxThroughput
}

return append(results, result)
}

func ExpandCosmosDbAutoscaleSettingsResource(d *schema.ResourceData) *documentdb.AutoscaleSettingsResource {
autoscaleSettings := ExpandCosmosDbAutoscaleSettings(d)
autoscaleSettingResource := documentdb.AutoscaleSettingsResource{}

autoscaleSettingResource.MaxThroughput = autoscaleSettings.MaxThroughput
return &autoscaleSettingResource
}
39 changes: 39 additions & 0 deletions azurerm/internal/services/cosmos/common/schema.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package common

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

func DatabaseAutoscaleSettingsSchema() *schema.Schema {
return &schema.Schema{
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"max_throughput": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
ConflictsWith: []string{"throughput"},
ValidateFunc: validate.CosmosMaxThroughput,
},
},
},
}
}

func ContainerAutoscaleSettingsSchema() *schema.Schema {
autoscaleSettingsDatabaseSchema := DatabaseAutoscaleSettingsSchema()
autoscaleSettingsDatabaseSchema.RequiredWith = []string{"partition_key_path"}

return autoscaleSettingsDatabaseSchema
}

func MongoCollectionAutoscaleSettingsSchema() *schema.Schema {
autoscaleSettingsDatabaseSchema := DatabaseAutoscaleSettingsSchema()
autoscaleSettingsDatabaseSchema.RequiredWith = []string{"shard_key"}

return autoscaleSettingsDatabaseSchema
}
42 changes: 42 additions & 0 deletions azurerm/internal/services/cosmos/common/throughput.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package common

import (
"fmt"

"github.com/Azure/azure-sdk-for-go/services/cosmos-db/mgmt/2020-04-01/documentdb"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)

Expand All @@ -22,3 +25,42 @@ func GetThroughputFromResult(throughputResponse documentdb.ThroughputSettingsGet
func ConvertThroughputFromResourceData(throughput interface{}) *int32 {
return utils.Int32(int32(throughput.(int)))
}

func ExpandCosmosDBThroughputSettingsUpdateParameters(d *schema.ResourceData) *documentdb.ThroughputSettingsUpdateParameters {
throughputParameters := documentdb.ThroughputSettingsUpdateParameters{
ThroughputSettingsUpdateProperties: &documentdb.ThroughputSettingsUpdateProperties{
Resource: &documentdb.ThroughputSettingsResource{},
},
}

if v, exists := d.GetOk("throughput"); exists {
throughputParameters.ThroughputSettingsUpdateProperties.Resource.Throughput = ConvertThroughputFromResourceData(v)
}

if _, hasAutoscaleSettings := d.GetOk("autoscale_settings"); hasAutoscaleSettings {
// If updating the autoscale throughput, set the manual throughput to nil to ensure the autoscale throughput is applied
throughputParameters.ThroughputSettingsUpdateProperties.Resource.Throughput = nil
throughputParameters.ThroughputSettingsUpdateProperties.Resource.AutoscaleSettings = ExpandCosmosDbAutoscaleSettingsResource(d)
}

return &throughputParameters
}

func SetResourceDataThroughputFromResponse(throughputResponse documentdb.ThroughputSettingsGetResults, d *schema.ResourceData) {
d.Set("throughput", GetThroughputFromResult(throughputResponse))

autoscaleSettings := FlattenCosmosDbAutoscaleSettings(throughputResponse)
d.Set("autoscale_settings", autoscaleSettings)
}

func CheckForChangeFromAutoscaleAndManualThroughput(d *schema.ResourceData) error {
if d.HasChange("throughput") && d.HasChange("autoscale_settings") {
return fmt.Errorf("switching between autoscale and manually provisioned throughput via Terraform is not supported at this time")
}

return nil
}

func HasThroughputChange(d *schema.ResourceData) bool {
return d.HasChanges("throughput", "autoscale_settings")
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ func resourceArmCosmosDbCassandraKeyspace() *schema.Resource {
Computed: true,
ValidateFunc: validate.CosmosThroughput,
},

"autoscale_settings": common.DatabaseAutoscaleSettingsSchema(),
},
}
}
Expand Down Expand Up @@ -105,7 +107,13 @@ func resourceArmCosmosDbCassandraKeyspaceCreate(d *schema.ResourceData, meta int
}

if throughput, hasThroughput := d.GetOk("throughput"); hasThroughput {
db.CassandraKeyspaceCreateUpdateProperties.Options.Throughput = common.ConvertThroughputFromResourceData(throughput)
if throughput != 0 {
db.CassandraKeyspaceCreateUpdateProperties.Options.Throughput = common.ConvertThroughputFromResourceData(throughput)
}
}

if _, hasAutoscaleSettings := d.GetOk("autoscale_settings"); hasAutoscaleSettings {
db.CassandraKeyspaceCreateUpdateProperties.Options.AutoscaleSettings = common.ExpandCosmosDbAutoscaleSettings(d)
}

future, err := client.CreateUpdateCassandraKeyspace(ctx, resourceGroup, account, name, db)
Expand Down Expand Up @@ -141,6 +149,11 @@ func resourceArmCosmosDbCassandraKeyspaceUpdate(d *schema.ResourceData, meta int
return err
}

err = common.CheckForChangeFromAutoscaleAndManualThroughput(d)
if err != nil {
return fmt.Errorf("Error updating Cosmos Cassandra Keyspace %q (Account: %q) - %+v", id.Name, id.Account, err)
}

db := documentdb.CassandraKeyspaceCreateUpdateParameters{
CassandraKeyspaceCreateUpdateProperties: &documentdb.CassandraKeyspaceCreateUpdateProperties{
Resource: &documentdb.CassandraKeyspaceResource{
Expand All @@ -159,16 +172,9 @@ func resourceArmCosmosDbCassandraKeyspaceUpdate(d *schema.ResourceData, meta int
return fmt.Errorf("Error waiting on create/update future for Cosmos Cassandra Keyspace %q (Account: %q): %+v", id.ResourceGroup, id.Account, err)
}

if d.HasChange("throughput") {
throughputParameters := documentdb.ThroughputSettingsUpdateParameters{
ThroughputSettingsUpdateProperties: &documentdb.ThroughputSettingsUpdateProperties{
Resource: &documentdb.ThroughputSettingsResource{
Throughput: common.ConvertThroughputFromResourceData(d.Get("throughput")),
},
},
}

throughputFuture, err := client.UpdateCassandraKeyspaceThroughput(ctx, id.ResourceGroup, id.Account, id.Name, throughputParameters)
if common.HasThroughputChange(d) {
throughputParameters := common.ExpandCosmosDBThroughputSettingsUpdateParameters(d)
throughputFuture, err := client.UpdateCassandraKeyspaceThroughput(ctx, id.ResourceGroup, id.Account, id.Name, *throughputParameters)
if err != nil {
if response.WasNotFound(throughputFuture.Response()) {
return fmt.Errorf("Error setting Throughput for Cosmos Cassandra Keyspace %q (Account: %q): %+v - "+
Expand Down Expand Up @@ -219,9 +225,10 @@ func resourceArmCosmosDbCassandraKeyspaceRead(d *schema.ResourceData, meta inter
return fmt.Errorf("Error reading Throughput on Cosmos Cassandra Keyspace %q (Account: %q): %+v", id.Name, id.Account, err)
} else {
d.Set("throughput", nil)
d.Set("autoscale_settings", nil)
}
} else {
d.Set("throughput", common.GetThroughputFromResult(throughputResp))
common.SetResourceDataThroughputFromResponse(throughputResp, d)
}

return nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ func resourceArmCosmosGremlinDatabase() *schema.Resource {
Computed: true,
ValidateFunc: validate.CosmosThroughput,
},

"autoscale_settings": common.DatabaseAutoscaleSettingsSchema(),
},
}
}
Expand Down Expand Up @@ -105,7 +107,13 @@ func resourceArmCosmosGremlinDatabaseCreate(d *schema.ResourceData, meta interfa
}

if throughput, hasThroughput := d.GetOk("throughput"); hasThroughput {
db.GremlinDatabaseCreateUpdateProperties.Options.Throughput = common.ConvertThroughputFromResourceData(throughput)
if throughput != 0 {
db.GremlinDatabaseCreateUpdateProperties.Options.Throughput = common.ConvertThroughputFromResourceData(throughput)
}
}

if _, hasAutoscaleSettings := d.GetOk("autoscale_settings"); hasAutoscaleSettings {
db.GremlinDatabaseCreateUpdateProperties.Options.AutoscaleSettings = common.ExpandCosmosDbAutoscaleSettings(d)
}

future, err := client.CreateUpdateGremlinDatabase(ctx, resourceGroup, account, name, db)
Expand Down Expand Up @@ -141,6 +149,11 @@ func resourceArmCosmosGremlinDatabaseUpdate(d *schema.ResourceData, meta interfa
return err
}

err = common.CheckForChangeFromAutoscaleAndManualThroughput(d)
if err != nil {
return fmt.Errorf("Error updating Cosmos Gremlin Database %q (Account: %q) - %+v", id.Name, id.Account, err)
}

db := documentdb.GremlinDatabaseCreateUpdateParameters{
GremlinDatabaseCreateUpdateProperties: &documentdb.GremlinDatabaseCreateUpdateProperties{
Resource: &documentdb.GremlinDatabaseResource{
Expand All @@ -159,16 +172,9 @@ func resourceArmCosmosGremlinDatabaseUpdate(d *schema.ResourceData, meta interfa
return fmt.Errorf("Error waiting on create/update future for Cosmos Gremlin Database %q (Account: %q): %+v", id.Name, id.Account, err)
}

if d.HasChange("throughput") {
throughputParameters := documentdb.ThroughputSettingsUpdateParameters{
ThroughputSettingsUpdateProperties: &documentdb.ThroughputSettingsUpdateProperties{
Resource: &documentdb.ThroughputSettingsResource{
Throughput: common.ConvertThroughputFromResourceData(d.Get("throughput")),
},
},
}

throughputFuture, err := client.UpdateGremlinDatabaseThroughput(ctx, id.ResourceGroup, id.Account, id.Name, throughputParameters)
if common.HasThroughputChange(d) {
throughputParameters := common.ExpandCosmosDBThroughputSettingsUpdateParameters(d)
throughputFuture, err := client.UpdateGremlinDatabaseThroughput(ctx, id.ResourceGroup, id.Account, id.Name, *throughputParameters)
if err != nil {
if response.WasNotFound(throughputFuture.Response()) {
return fmt.Errorf("Error setting Throughput for Cosmos Gremlin Database %q (Account: %q): %+v - "+
Expand Down Expand Up @@ -223,9 +229,10 @@ func resourceArmCosmosGremlinDatabaseRead(d *schema.ResourceData, meta interface
return fmt.Errorf("Error reading Throughput on Cosmos Gremlin Database %q (Account: %q): %+v", id.Name, id.Account, err)
} else {
d.Set("throughput", nil)
d.Set("autoscale_settings", nil)
}
} else {
d.Set("throughput", common.GetThroughputFromResult(throughputResp))
common.SetResourceDataThroughputFromResponse(throughputResp, d)
}

return nil
Expand Down
Loading