Skip to content

Commit

Permalink
dbaas: support for users (#401)
Browse files Browse the repository at this point in the history
# Description
<!--
* Prefix: the title with the component name being changed. Add a short
and self describing sentence to ease the review
* Please add a few lines providing context and describing the change
* Please self comment changes whenever applicable to help with the
review process
* Please keep the checklist as part of the PR. Tick what applies to this
change.
-->

For services that allow user creation, we are adding new resources that
correspond to a user.

## Checklist
(For exoscale contributors)

* [ ] Changelog updated (under *Unreleased* block)
* [x] Acceptance tests OK
* [x] For a new resource, datasource or new attributes: acceptance test
added/updated

## Testing

<!--
Describe the tests you did
-->
Local tests + acceptance tests

---------

Co-authored-by: Philipp Sauter <[email protected]>
  • Loading branch information
tgrondier and sauterp authored Dec 24, 2024
1 parent 27d980f commit 077c43f
Show file tree
Hide file tree
Showing 144 changed files with 9,531 additions and 205 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
FEATURES:

- InstancePool: min-available support #406
- dbaas: support for users #401

BUG FIXES:

Expand Down
49 changes: 49 additions & 0 deletions docs/resources/dbaas_kafka_user.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "exoscale_dbaas_kafka_user Resource - terraform-provider-exoscale"
subcategory: ""
description: |-
Manage service users for a Kafka Exoscale Database Services (DBaaS) https://community.exoscale.com/documentation/dbaas/.
---

# exoscale_dbaas_kafka_user (Resource)

Manage service users for a Kafka Exoscale [Database Services (DBaaS)](https://community.exoscale.com/documentation/dbaas/).



<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `service` (String) ❗ The name of the database service.
- `username` (String) ❗ The name of the user for this service.
- `zone` (String) ❗ The Exoscale [Zone](https://www.exoscale.com/datacenters/) name.

### Optional

- `timeouts` (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))

### Read-Only

- `access_cert` (String, Sensitive) Access certificate for the user.
- `access_cert_expiry` (String) Access certificate expiry date.
- `access_key` (String, Sensitive) Access certificate key for the user.
- `id` (String) The ID of this resource, computed as service/username
- `password` (String, Sensitive) The password of the service user.
- `type` (String) The type of the service user.

<a id="nestedblock--timeouts"></a>
### Nested Schema for `timeouts`

Optional:

- `create` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours).
- `delete` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours). Setting a timeout for a Delete operation is only applicable if changes are saved into state before the destroy operation occurs.
- `read` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours). Read operations occur during any refresh or planning operation when refresh is enabled.
- `update` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours).

-> The symbol ❗ in an attribute indicates that modifying it, will force the creation of a new resource.


47 changes: 47 additions & 0 deletions docs/resources/dbaas_mysql_user.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "exoscale_dbaas_mysql_user Resource - terraform-provider-exoscale"
subcategory: ""
description: |-
Manage service users for MySQL Exoscale Database Services (DBaaS) https://community.exoscale.com/documentation/dbaas/.
---

# exoscale_dbaas_mysql_user (Resource)

Manage service users for MySQL Exoscale [Database Services (DBaaS)](https://community.exoscale.com/documentation/dbaas/).



<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `service` (String) ❗ The name of the database service.
- `username` (String) ❗ The name of the user for this service.
- `zone` (String) ❗ The Exoscale [Zone](https://www.exoscale.com/datacenters/) name.

### Optional

- `authentication` (String) ❗ Authentication details. The possible values are `null`, `caching_sha2_password` and `mysql_native_password`.
- `timeouts` (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))

### Read-Only

- `id` (String) The ID of this resource, computed as service/username
- `password` (String, Sensitive) The password of the service user.
- `type` (String) The type of the service user.

<a id="nestedblock--timeouts"></a>
### Nested Schema for `timeouts`

Optional:

- `create` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours).
- `delete` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours). Setting a timeout for a Delete operation is only applicable if changes are saved into state before the destroy operation occurs.
- `read` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours). Read operations occur during any refresh or planning operation when refresh is enabled.
- `update` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours).

-> The symbol ❗ in an attribute indicates that modifying it, will force the creation of a new resource.


46 changes: 46 additions & 0 deletions docs/resources/dbaas_opensearch_user.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "exoscale_dbaas_opensearch_user Resource - terraform-provider-exoscale"
subcategory: ""
description: |-
Manage service users for an Opensearch Exoscale Database Services (DBaaS) https://community.exoscale.com/documentation/dbaas/.
---

# exoscale_dbaas_opensearch_user (Resource)

Manage service users for an Opensearch Exoscale [Database Services (DBaaS)](https://community.exoscale.com/documentation/dbaas/).



<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `service` (String) ❗ The name of the database service.
- `username` (String) ❗ The name of the user for this service.
- `zone` (String) ❗ The Exoscale [Zone](https://www.exoscale.com/datacenters/) name.

### Optional

- `timeouts` (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))

### Read-Only

- `id` (String) The ID of this resource, computed as service/username
- `password` (String, Sensitive) The password of the service user.
- `type` (String) The type of the service user.

<a id="nestedblock--timeouts"></a>
### Nested Schema for `timeouts`

Optional:

- `create` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours).
- `delete` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours). Setting a timeout for a Delete operation is only applicable if changes are saved into state before the destroy operation occurs.
- `read` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours). Read operations occur during any refresh or planning operation when refresh is enabled.
- `update` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours).

-> The symbol ❗ in an attribute indicates that modifying it, will force the creation of a new resource.


47 changes: 47 additions & 0 deletions docs/resources/dbaas_pg_user.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "exoscale_dbaas_pg_user Resource - terraform-provider-exoscale"
subcategory: ""
description: |-
❗ Manage service users for a PostgreSQL Exoscale Database Services (DBaaS) https://community.exoscale.com/documentation/dbaas/.
---

# exoscale_dbaas_pg_user (Resource)

❗ Manage service users for a PostgreSQL Exoscale [Database Services (DBaaS)](https://community.exoscale.com/documentation/dbaas/).



<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `service` (String) ❗ The name of the database service.
- `username` (String) ❗ The name of the user for this service.
- `zone` (String) ❗ The Exoscale [Zone](https://www.exoscale.com/datacenters/) name.

### Optional

- `allow_replication` (Boolean) Allows replication
- `timeouts` (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))

### Read-Only

- `id` (String) The ID of this resource, computed as service/username
- `password` (String, Sensitive) The password of the service user.
- `type` (String) The type of the service user.

<a id="nestedblock--timeouts"></a>
### Nested Schema for `timeouts`

Optional:

- `create` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours).
- `delete` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours). Setting a timeout for a Delete operation is only applicable if changes are saved into state before the destroy operation occurs.
- `read` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours). Read operations occur during any refresh or planning operation when refresh is enabled.
- `update` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours).

-> The symbol ❗ in an attribute indicates that modifying it, will force the creation of a new resource.


2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ require (
github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320
github.com/hashicorp/go-retryablehttp v0.7.7
github.com/hashicorp/terraform-plugin-docs v0.16.0
github.com/hashicorp/terraform-plugin-framework v1.11.0
github.com/hashicorp/terraform-plugin-framework v1.13.0
github.com/hashicorp/terraform-plugin-framework-jsontypes v0.2.0
github.com/hashicorp/terraform-plugin-framework-timeouts v0.4.0
github.com/hashicorp/terraform-plugin-framework-validators v0.10.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,8 @@ github.com/hashicorp/terraform-json v0.22.1 h1:xft84GZR0QzjPVWs4lRUwvTcPnegqlyS7
github.com/hashicorp/terraform-json v0.22.1/go.mod h1:JbWSQCLFSXFFhg42T7l9iJwdGXBYV8fmmD6o/ML4p3A=
github.com/hashicorp/terraform-plugin-docs v0.16.0 h1:UmxFr3AScl6Wged84jndJIfFccGyBZn52KtMNsS12dI=
github.com/hashicorp/terraform-plugin-docs v0.16.0/go.mod h1:M3ZrlKBJAbPMtNOPwHicGi1c+hZUh7/g0ifT/z7TVfA=
github.com/hashicorp/terraform-plugin-framework v1.11.0 h1:M7+9zBArexHFXDx/pKTxjE6n/2UCXY6b8FIq9ZYhwfE=
github.com/hashicorp/terraform-plugin-framework v1.11.0/go.mod h1:qBXLDn69kM97NNVi/MQ9qgd1uWWsVftGSnygYG1tImM=
github.com/hashicorp/terraform-plugin-framework v1.13.0 h1:8OTG4+oZUfKgnfTdPTJwZ532Bh2BobF4H+yBiYJ/scw=
github.com/hashicorp/terraform-plugin-framework v1.13.0/go.mod h1:j64rwMGpgM3NYXTKuxrCnyubQb/4VKldEKlcG8cvmjU=
github.com/hashicorp/terraform-plugin-framework-jsontypes v0.2.0 h1:SJXL5FfJJm17554Kpt9jFXngdM6fXbnUnZ6iT2IeiYA=
github.com/hashicorp/terraform-plugin-framework-jsontypes v0.2.0/go.mod h1:p0phD0IYhsu9bR4+6OetVvvH59I6LwjXGnTVEr8ox6E=
github.com/hashicorp/terraform-plugin-framework-timeouts v0.4.0 h1:9buCmO0ciBITSCuw5ag6RdOwSsnBMl7OxOKOyXvRiZM=
Expand Down
4 changes: 4 additions & 0 deletions pkg/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,10 @@ func (p *ExoscaleProvider) DataSources(ctx context.Context) []func() datasource.
func (p *ExoscaleProvider) Resources(ctx context.Context) []func() resource.Resource {
return []func() resource.Resource{
database.NewResource,
database.NewMysqlUserResource,
database.NewKafkaUserResource,
database.NewOpensearchUserResource,
database.NewPGUserResource,
iam.NewResourceOrgPolicy,
iam.NewResourceRole,
iam.NewResourceAPIKey,
Expand Down
37 changes: 37 additions & 0 deletions pkg/resources/database/datasource_uri.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,43 @@ polling:
return service, nil
}

// waitForDBAASServiceReadyForUsers polls the database service until it is ready to accept user creation
func waitForDBAASServiceReadyForUsers[T any](
ctx context.Context,
getService func(context.Context, string) (*T, error),
serviceName string,
usersReady func(*T) bool,
) (*T, error) {
ticker := time.NewTicker(2 * time.Second)
defer ticker.Stop()

polling:
for {
select {
case <-ticker.C:
service, err := getService(ctx, serviceName)
if err != nil {
return nil, fmt.Errorf("error polling service status: %w", err)
}

usersReady := usersReady(service)
if usersReady {
break polling
}

case <-ctx.Done():
return nil, ctx.Err()
}
}

// Get final state after breaking from polling loop
service, err := getService(ctx, serviceName)
if err != nil {
return nil, fmt.Errorf("error getting final service state: %w", err)
}
return service, nil
}

// Read defines how the data source updates Terraform's state to reflect the retrieved data.
func (d *DataSourceURI) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var data DataSourceURIModel
Expand Down
12 changes: 6 additions & 6 deletions pkg/resources/database/datasource_uri_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func testDataSourceURI(t *testing.T) {

resource.Test(t, resource.TestCase{
PreCheck: func() { testutils.AccPreCheck(t) },
CheckDestroy: CheckDestroy("pg", resourcePg.Name),
CheckDestroy: CheckServiceDestroy("pg", resourcePg.Name),
ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
{
Expand Down Expand Up @@ -110,7 +110,7 @@ func testDataSourceURI(t *testing.T) {

resource.Test(t, resource.TestCase{
PreCheck: func() { testutils.AccPreCheck(t) },
CheckDestroy: CheckDestroy("mysql", resourceMysql.Name),
CheckDestroy: CheckServiceDestroy("mysql", resourceMysql.Name),
ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
{
Expand Down Expand Up @@ -157,7 +157,7 @@ func testDataSourceURI(t *testing.T) {

resource.Test(t, resource.TestCase{
PreCheck: func() { testutils.AccPreCheck(t) },
CheckDestroy: CheckDestroy("redis", resourceRedis.Name),
CheckDestroy: CheckServiceDestroy("redis", resourceRedis.Name),
ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
{
Expand Down Expand Up @@ -204,7 +204,7 @@ func testDataSourceURI(t *testing.T) {

resource.Test(t, resource.TestCase{
PreCheck: func() { testutils.AccPreCheck(t) },
CheckDestroy: CheckDestroy("kafka", resourceKafka.Name),
CheckDestroy: CheckServiceDestroy("kafka", resourceKafka.Name),
ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
{
Expand Down Expand Up @@ -252,7 +252,7 @@ func testDataSourceURI(t *testing.T) {

resource.Test(t, resource.TestCase{
PreCheck: func() { testutils.AccPreCheck(t) },
CheckDestroy: CheckDestroy("opensearch", resourceOpensearch.Name),
CheckDestroy: CheckServiceDestroy("opensearch", resourceOpensearch.Name),
ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
{
Expand Down Expand Up @@ -299,7 +299,7 @@ func testDataSourceURI(t *testing.T) {

resource.Test(t, resource.TestCase{
PreCheck: func() { testutils.AccPreCheck(t) },
CheckDestroy: CheckDestroy("grafana", resourceGrafana.Name),
CheckDestroy: CheckServiceDestroy("grafana", resourceGrafana.Name),
ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
{
Expand Down
2 changes: 1 addition & 1 deletion pkg/resources/database/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func TestDatabase(t *testing.T) {
t.Run("DataSourceURI", testDataSourceURI)
}

func CheckDestroy(dbType, name string) resource.TestCheckFunc {
func CheckServiceDestroy(dbType, name string) resource.TestCheckFunc {
return func(_ *terraform.State) error {
client, err := testutils.APIClient()
if err != nil {
Expand Down
8 changes: 5 additions & 3 deletions pkg/resources/database/resource_grafana_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"fmt"
"net/http"
"strconv"
"strings"
"testing"
"text/template"

Expand Down Expand Up @@ -78,7 +79,7 @@ func testResourceGrafana(t *testing.T) {

resource.Test(t, resource.TestCase{
PreCheck: func() { testutils.AccPreCheck(t) },
CheckDestroy: CheckDestroy("grafana", dataBase.Name),
CheckDestroy: CheckServiceDestroy("grafana", dataBase.Name),
ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
{
Expand Down Expand Up @@ -124,8 +125,9 @@ func testResourceGrafana(t *testing.T) {
return fmt.Sprintf("%s@%s", dataBase.Name, dataBase.Zone), nil
}
}(),
ImportState: true,
ImportStateVerify: true,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: strings.Fields("updated_at state"),
},
},
})
Expand Down
Loading

0 comments on commit 077c43f

Please sign in to comment.