diff --git a/docs/data-sources/rediscloud_subscription.md b/docs/data-sources/rediscloud_subscription.md index 5aa822d9..80fa3c6e 100644 --- a/docs/data-sources/rediscloud_subscription.md +++ b/docs/data-sources/rediscloud_subscription.md @@ -36,6 +36,7 @@ output "rediscloud_subscription" { * `cloud_provider` - A cloud provider object, documented below * `number_of_databases` - The number of databases that are linked to this subscription. * `status` - Current status of the subscription +* `pricing` - A list of pricing objects, documented below The `cloud_provider` block supports: @@ -57,3 +58,15 @@ The `networks` block has these attributes: * `networking_subnet_id` - The subnet that the subscription deploys into * `networking_deployment_cidr` - Deployment CIDR mask for the generated * `networking_vpc_id` - VPC id for the generated network + +The `pricing` object has these attributes: + +* `database_name` - The database this pricing entry applies to. +* `type` - The type of cost e.g. 'Shards'. +* `typeDetails` - Further detail e.g. 'micro'. +* `quantity` - Self-explanatory. +* `quantityMeasurement` - Self-explanatory. +* `pricePerUnit` - Self-explanatory. +* `priceCurrency` - Self-explanatory e.g. 'USD'. +* `pricePeriod` - Self-explanatory e.g. 'hour'. +* `region` - Self-explanatory, if the cost is associated with a particular region. diff --git a/docs/resources/rediscloud_active_active_subscription.md b/docs/resources/rediscloud_active_active_subscription.md index 43b9ddd6..5e43873b 100644 --- a/docs/resources/rediscloud_active_active_subscription.md +++ b/docs/resources/rediscloud_active_active_subscription.md @@ -77,6 +77,22 @@ The creation_plan `region` block supports: ~> **Note:** If changes are made to attributes in the subscription which require the subscription to be recreated (such as `cloud_provider`), the creation_plan will need to be defined in order to change these attributes. This is because the creation_plan is always required when a subscription is created. +## Attribute reference + +* `pricing` - A list of pricing objects, documented below + +The `pricing` object has these attributes: + +* `database_name` - The database this pricing entry applies to. +* `type` - The type of cost e.g. 'Shards'. +* `typeDetails` - Further detail e.g. 'micro'. +* `quantity` - Self-explanatory. +* `quantityMeasurement` - Self-explanatory. +* `pricePerUnit` - Self-explanatory. +* `priceCurrency` - Self-explanatory e.g. 'USD'. +* `pricePeriod` - Self-explanatory e.g. 'hour'. +* `region` - Self-explanatory, if the cost is associated with a particular region. + ### Timeouts The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: diff --git a/docs/resources/rediscloud_subscription.md b/docs/resources/rediscloud_subscription.md index c84dbfb5..a444492e 100644 --- a/docs/resources/rediscloud_subscription.md +++ b/docs/resources/rediscloud_subscription.md @@ -136,6 +136,18 @@ The `networks` block has these attributes: * `networking_deployment_cidr` - Deployment CIDR mask for the generated * `networking_vpc_id` - VPC id for the generated network +The `pricing` object has these attributes: + +* `database_name` - The database this pricing entry applies to. +* `type` - The type of cost e.g. 'Shards'. +* `typeDetails` - Further detail e.g. 'micro'. +* `quantity` - Self-explanatory. +* `quantityMeasurement` - Self-explanatory. +* `pricePerUnit` - Self-explanatory. +* `priceCurrency` - Self-explanatory e.g. 'USD'. +* `pricePeriod` - Self-explanatory e.g. 'hour'. +* `region` - Self-explanatory, if the cost is associated with a particular region. + ## Import `rediscloud_subscription` can be imported using the ID of the subscription, e.g. diff --git a/go.mod b/go.mod index 73b6865e..64b007b4 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/RedisLabs/terraform-provider-rediscloud go 1.19 require ( - github.com/RedisLabs/rediscloud-go-api v0.9.0 + github.com/RedisLabs/rediscloud-go-api v0.10.0 github.com/bflad/tfproviderlint v0.29.0 github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 github.com/hashicorp/terraform-plugin-sdk/v2 v2.28.0 @@ -16,7 +16,7 @@ require ( github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect github.com/avast/retry-go/v4 v4.5.1 // indirect github.com/bflad/gopaniccheck v0.1.0 // indirect - github.com/cloudflare/circl v1.3.3 // indirect + github.com/cloudflare/circl v1.3.7 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/fatih/color v1.13.0 // indirect github.com/golang/protobuf v1.5.3 // indirect @@ -52,15 +52,15 @@ require ( github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/zclconf/go-cty v1.13.2 // indirect - golang.org/x/crypto v0.19.0 // indirect + golang.org/x/crypto v0.22.0 // indirect golang.org/x/mod v0.15.0 // indirect - golang.org/x/net v0.21.0 // indirect - golang.org/x/sys v0.17.0 // indirect + golang.org/x/net v0.23.0 // indirect + golang.org/x/sys v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/tools v0.18.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect - google.golang.org/grpc v1.56.1 // indirect - google.golang.org/protobuf v1.31.0 // indirect + google.golang.org/grpc v1.56.3 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 48b7223e..799bfcee 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,8 @@ github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA= github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 h1:wPbRQzjjwFc0ih8puEVAOFGELsn1zoIIYdxvML7mDxA= github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g= -github.com/RedisLabs/rediscloud-go-api v0.9.0 h1:OoM/HeJDoQMflLtquB8kAT8h7RpQZ/9lqLol+95h14s= -github.com/RedisLabs/rediscloud-go-api v0.9.0/go.mod h1:ZPBvmRsO5LEj4ASPryhaov6eynd/ue+oUdA30RwH4aQ= +github.com/RedisLabs/rediscloud-go-api v0.10.0 h1:TtkhmGzDCgqUqvhPcY2ajizdx2eN76cqd++5H2D5I/0= +github.com/RedisLabs/rediscloud-go-api v0.10.0/go.mod h1:ZPBvmRsO5LEj4ASPryhaov6eynd/ue+oUdA30RwH4aQ= github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ= github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE= github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= @@ -17,8 +17,8 @@ github.com/bflad/tfproviderlint v0.29.0 h1:zxKYAAM6IZ4ace1a3LX+uzMRIMP8L+iOtEc+F github.com/bflad/tfproviderlint v0.29.0/go.mod h1:ErKVd+GRA2tXKr8T7zC0EDSrtALJL25wj0ZJ/v/klqQ= github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= -github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= -github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= +github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= +github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -132,8 +132,8 @@ github.com/zclconf/go-cty v1.13.2/go.mod h1:YKQzy/7pZ7iq2jNFzy5go57xdxdWoLLpaEp4 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= @@ -141,8 +141,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= @@ -156,10 +156,10 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= +golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -176,12 +176,12 @@ google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6 google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= -google.golang.org/grpc v1.56.1 h1:z0dNfjIl0VpaZ9iSVjA6daGatAYwPGstTjt5vkRMFkQ= -google.golang.org/grpc v1.56.1/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc= +google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/provider/datasource_rediscloud_subscription.go b/provider/datasource_rediscloud_subscription.go index 0d6f1e28..b251e365 100644 --- a/provider/datasource_rediscloud_subscription.go +++ b/provider/datasource_rediscloud_subscription.go @@ -121,6 +121,69 @@ func dataSourceRedisCloudSubscription() *schema.Resource { }, }, }, + "pricing": { + Description: "Pricing details totalled over this Subscription", + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "database_name": { + Description: "The database this pricing entry applies to", + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + "type": { + Description: "The type of cost e.g. 'Shards'", + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + "type_details": { + Description: "Further detail e.g. 'micro'", + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + "quantity": { + Description: "Self-explanatory", + Type: schema.TypeInt, + Computed: true, + Optional: true, + }, + "quantity_measurement": { + Description: "Self-explanatory", + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + "price_per_unit": { + Description: "Self-explanatory", + Type: schema.TypeFloat, + Computed: true, + Optional: true, + }, + "price_currency": { + Description: "Self-explanatory e.g. 'USD'", + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + "price_period": { + Description: "Self-explanatory e.g. 'hour'", + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + "region": { + Description: "Self-explanatory, if the cost is associated with a particular region", + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + }, + }, + }, }, } } @@ -180,7 +243,16 @@ func dataSourceRedisCloudSubscriptionRead(ctx context.Context, d *schema.Resourc return diag.FromErr(err) } - d.SetId(strconv.Itoa(redis.IntValue(sub.ID))) + subId := redis.IntValue(sub.ID) + d.SetId(strconv.Itoa(subId)) + + pricingList, err := api.client.Pricing.List(ctx, subId) + if err != nil { + return diag.FromErr(err) + } + if err := d.Set("pricing", flattenPricing(pricingList)); err != nil { + return diag.FromErr(err) + } return diags } diff --git a/provider/datasource_rediscloud_subscription_test.go b/provider/datasource_rediscloud_subscription_test.go index bd9b9a52..07dd1abb 100644 --- a/provider/datasource_rediscloud_subscription_test.go +++ b/provider/datasource_rediscloud_subscription_test.go @@ -41,6 +41,15 @@ func TestAccDataSourceRedisCloudSubscription_basic(t *testing.T) { resource.TestCheckResourceAttr(dataSourceName, "cloud_provider.0.region.0.region", "eu-west-1"), resource.TestCheckResourceAttr(dataSourceName, "cloud_provider.0.region.0.networks.0.networking_deployment_cidr", "10.0.0.0/24"), resource.TestCheckResourceAttr(dataSourceName, "status", "active"), + + resource.TestCheckResourceAttr(dataSourceName, "pricing.#", "1"), + resource.TestCheckResourceAttr(dataSourceName, "pricing.0.type", "Shards"), + resource.TestCheckResourceAttr(dataSourceName, "pricing.0.type_details", "micro"), + resource.TestCheckResourceAttr(dataSourceName, "pricing.0.quantity", "2"), + resource.TestCheckResourceAttr(dataSourceName, "pricing.0.quantity_measurement", "shards"), + resource.TestCheckResourceAttrSet(dataSourceName, "pricing.0.price_per_unit"), + resource.TestCheckResourceAttr(dataSourceName, "pricing.0.price_currency", "USD"), + resource.TestCheckResourceAttr(dataSourceName, "pricing.0.price_period", "hour"), ), }, }, diff --git a/provider/resource_rediscloud_active_active_subscription.go b/provider/resource_rediscloud_active_active_subscription.go index 753dfe74..981bf6e0 100644 --- a/provider/resource_rediscloud_active_active_subscription.go +++ b/provider/resource_rediscloud_active_active_subscription.go @@ -179,6 +179,69 @@ func resourceRedisCloudActiveActiveSubscription() *schema.Resource { ValidateDiagFunc: validation.ToDiagFunc( validation.StringMatch(regexp.MustCompile("^(default|latest)$"), "must be 'default' or 'latest'")), }, + "pricing": { + Description: "Pricing details totalled over this Subscription", + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "database_name": { + Description: "The database this pricing entry applies to", + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + "type": { + Description: "The type of cost e.g. 'Shards'", + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + "type_details": { + Description: "Further detail e.g. 'micro'", + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + "quantity": { + Description: "Self-explanatory", + Type: schema.TypeInt, + Computed: true, + Optional: true, + }, + "quantity_measurement": { + Description: "Self-explanatory", + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + "price_per_unit": { + Description: "Self-explanatory", + Type: schema.TypeFloat, + Computed: true, + Optional: true, + }, + "price_currency": { + Description: "Self-explanatory e.g. 'USD'", + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + "price_period": { + Description: "Self-explanatory e.g. 'hour'", + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + "region": { + Description: "Self-explanatory, if the cost is associated with a particular region", + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + }, + }, + }, }, } } @@ -315,6 +378,14 @@ func resourceRedisCloudActiveActiveSubscriptionRead(ctx context.Context, d *sche return diag.FromErr(err) } + pricingList, err := api.client.Pricing.List(ctx, subId) + if err != nil { + return diag.FromErr(err) + } + if err := d.Set("pricing", flattenPricing(pricingList)); err != nil { + return diag.FromErr(err) + } + return diags } diff --git a/provider/resource_rediscloud_active_active_subscription_test.go b/provider/resource_rediscloud_active_active_subscription_test.go index 5fe5ecf0..e7a7fc3c 100644 --- a/provider/resource_rediscloud_active_active_subscription_test.go +++ b/provider/resource_rediscloud_active_active_subscription_test.go @@ -50,6 +50,36 @@ func TestAccResourceRedisCloudActiveActiveSubscription_CRUDI(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "creation_plan.0.region.1.write_operations_per_second", "1000"), resource.TestCheckResourceAttr(resourceName, "creation_plan.0.region.1.read_operations_per_second", "1000"), + resource.TestCheckResourceAttr(resourceName, "pricing.#", "2"), + + resource.TestCheckResourceAttr(resourceName, "pricing.0.type", "MinimumPrice"), + resource.TestCheckResourceAttr(resourceName, "pricing.0.quantity", "1"), + resource.TestCheckResourceAttr(resourceName, "pricing.0.quantity_measurement", "subscription"), + resource.TestCheckResourceAttrSet(resourceName, "pricing.0.price_per_unit"), + resource.TestCheckResourceAttr(resourceName, "pricing.0.price_currency", "USD"), + resource.TestCheckResourceAttr(resourceName, "pricing.0.price_period", "hour"), + + resource.TestCheckResourceAttr(resourceName, "pricing.1.type", "MinimumPrice"), + resource.TestCheckResourceAttr(resourceName, "pricing.1.quantity", "1"), + resource.TestCheckResourceAttr(resourceName, "pricing.1.quantity_measurement", "subscription"), + resource.TestCheckResourceAttrSet(resourceName, "pricing.1.price_per_unit"), + resource.TestCheckResourceAttr(resourceName, "pricing.1.price_currency", "USD"), + resource.TestCheckResourceAttr(resourceName, "pricing.1.price_period", "hour"), + + func(s *terraform.State) error { + r := s.RootModule().Resources[resourceName].Primary + region1 := r.Attributes["pricing.0.region"] + region2 := r.Attributes["pricing.1.region"] + + match := (region1 == "us-east-1" && region2 == "us-east-2") || + (region2 == "us-east-1" && region1 == "us-east-2") + + if !match { + return fmt.Errorf("regions within pricing response are incorrect. expected us-east-1 and us-east-2") + } + return nil + }, + func(s *terraform.State) error { r := s.RootModule().Resources[resourceName] diff --git a/provider/resource_rediscloud_subscription.go b/provider/resource_rediscloud_subscription.go index 0dac5d07..ba76928c 100644 --- a/provider/resource_rediscloud_subscription.go +++ b/provider/resource_rediscloud_subscription.go @@ -12,6 +12,7 @@ import ( "github.com/RedisLabs/rediscloud-go-api/redis" "github.com/RedisLabs/rediscloud-go-api/service/cloud_accounts" "github.com/RedisLabs/rediscloud-go-api/service/databases" + "github.com/RedisLabs/rediscloud-go-api/service/pricing" "github.com/RedisLabs/rediscloud-go-api/service/subscriptions" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" @@ -315,6 +316,69 @@ func resourceRedisCloudSubscription() *schema.Resource { ValidateDiagFunc: validation.ToDiagFunc( validation.StringMatch(regexp.MustCompile("^(default|latest)$"), "must be 'default' or 'latest'")), }, + "pricing": { + Description: "Pricing details totalled over this Subscription", + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "database_name": { + Description: "The database this pricing entry applies to", + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + "type": { + Description: "The type of cost e.g. 'Shards'", + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + "type_details": { + Description: "Further detail e.g. 'micro'", + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + "quantity": { + Description: "Self-explanatory", + Type: schema.TypeInt, + Computed: true, + Optional: true, + }, + "quantity_measurement": { + Description: "Self-explanatory", + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + "price_per_unit": { + Description: "Self-explanatory", + Type: schema.TypeFloat, + Computed: true, + Optional: true, + }, + "price_currency": { + Description: "Self-explanatory e.g. 'USD'", + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + "price_period": { + Description: "Self-explanatory e.g. 'hour'", + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + "region": { + Description: "Self-explanatory, if the cost is associated with a particular region", + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + }, + }, + }, }, } } @@ -464,6 +528,14 @@ func resourceRedisCloudSubscriptionRead(ctx context.Context, d *schema.ResourceD } } + pricingList, err := api.client.Pricing.List(ctx, subId) + if err != nil { + return diag.FromErr(err) + } + if err := d.Set("pricing", flattenPricing(pricingList)); err != nil { + return diag.FromErr(err) + } + return diags } @@ -991,3 +1063,24 @@ func readPaymentMethodID(d *schema.ResourceData) (*int, error) { } return nil, nil } + +func flattenPricing(pricing []*pricing.Pricing) []map[string]interface{} { + var tfs = make([]map[string]interface{}, 0) + for _, p := range pricing { + + tf := map[string]interface{}{ + "database_name": p.DatabaseName, + "type": p.Type, + "type_details": p.TypeDetails, + "quantity": p.Quantity, + "quantity_measurement": p.QuantityMeasurement, + "price_per_unit": p.PricePerUnit, + "price_currency": p.PriceCurrency, + "price_period": p.PricePeriod, + "region": p.Region, + } + tfs = append(tfs, tf) + } + + return tfs +} diff --git a/provider/resource_rediscloud_subscription_database.go b/provider/resource_rediscloud_subscription_database.go index 17ccc2e5..65c7bbc3 100644 --- a/provider/resource_rediscloud_subscription_database.go +++ b/provider/resource_rediscloud_subscription_database.go @@ -374,6 +374,7 @@ func resourceRedisCloudSubscriptionDatabaseCreate(ctx context.Context, d *schema api := meta.(*apiClient) subId := d.Get("subscription_id").(int) + subscriptionMutex.Lock(subId) name := d.Get("name").(string) @@ -454,6 +455,7 @@ func resourceRedisCloudSubscriptionDatabaseCreate(ctx context.Context, d *schema dbId, err := api.client.Database.Create(ctx, subId, createDatabase) if err != nil { + subscriptionMutex.Unlock(subId) return diag.FromErr(err) } @@ -462,6 +464,7 @@ func resourceRedisCloudSubscriptionDatabaseCreate(ctx context.Context, d *schema // Confirm Subscription Active status err = waitForDatabaseToBeActive(ctx, subId, dbId, api) if err != nil { + subscriptionMutex.Unlock(subId) return diag.FromErr(err) } diff --git a/provider/resource_rediscloud_subscription_test.go b/provider/resource_rediscloud_subscription_test.go index 92273a70..d290f630 100644 --- a/provider/resource_rediscloud_subscription_test.go +++ b/provider/resource_rediscloud_subscription_test.go @@ -57,6 +57,9 @@ func TestAccResourceRedisCloudSubscription_CRUDI(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "creation_plan.0.support_oss_cluster_api", "false"), resource.TestCheckResourceAttr(resourceName, "creation_plan.0.throughput_measurement_by", "operations-per-second"), resource.TestCheckResourceAttr(resourceName, "creation_plan.0.throughput_measurement_value", "10000"), + + resource.TestCheckResourceAttr(resourceName, "pricing.#", "0"), + func(s *terraform.State) error { r := s.RootModule().Resources[resourceName]