Skip to content

Commit

Permalink
refactor(alloydbomni_user): use pg_user handlers and schema
Browse files Browse the repository at this point in the history
They are the same.
  • Loading branch information
byashimov committed Jan 10, 2025
1 parent cc0445d commit b12d2c9
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 201 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ nav_order: 1
- Replaced `aiven-go-client/v2` with `aiven/go-client-codegen` in `account_team_project` resource/data source
- Replaced `aiven-go-client/v2` with `aiven/go-client-codegen` in `aiven_pg_user` resource/data source
- Fix `aiven_pg_user` creating in bulk occasionally results in a 404 error
- Use `aiven_pg_user` handlers and schema in `aiven_alloydbomni_user` resource

## [4.31.1] - 2024-12-23

Expand Down
19 changes: 17 additions & 2 deletions internal/common/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/aiven/aiven-go-client/v2"
avngen "github.com/aiven/go-client-codegen"
"github.com/avast/retry-go"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
Expand Down Expand Up @@ -62,10 +63,10 @@ func GenClient() (avngen.Client, error) {
return genClientCache, nil
}

type crudHandler func(context.Context, *schema.ResourceData, avngen.Client) error
type CrudHandler func(context.Context, *schema.ResourceData, avngen.Client) error

// WithGenClient wraps CRUD handlers and runs with avngen.Client
func WithGenClient(handler crudHandler) func(context.Context, *schema.ResourceData, any) diag.Diagnostics {
func WithGenClient(handler CrudHandler) func(context.Context, *schema.ResourceData, any) diag.Diagnostics {
return func(ctx context.Context, d *schema.ResourceData, _ any) diag.Diagnostics {
return diag.FromErr(handler(ctx, d, genClientCache))
}
Expand Down Expand Up @@ -119,3 +120,17 @@ func TokenOpt(v string) ClientOpt {
o.token = v
}
}

// RetryCrudNotFound retries the handler if the error is NotFound
// This happens when GET called right after CREATE, and the resource is not yet available
func RetryCrudNotFound(f CrudHandler) CrudHandler {
return func(ctx context.Context, d *schema.ResourceData, client avngen.Client) error {
return retry.Do(
func() error {
return f(ctx, d, client)
},
retry.Context(ctx),
retry.RetryIf(avngen.IsNotFound),
)
}
}
187 changes: 6 additions & 181 deletions internal/sdkprovider/service/alloydbomni/alloydbomni_user.go
Original file line number Diff line number Diff line change
@@ -1,199 +1,24 @@
package alloydbomni

import (
"context"
"fmt"

avngen "github.com/aiven/go-client-codegen"
"github.com/aiven/go-client-codegen/handler/service"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"

"github.com/aiven/terraform-provider-aiven/internal/common"
"github.com/aiven/terraform-provider-aiven/internal/schemautil"
"github.com/aiven/terraform-provider-aiven/internal/schemautil/userconfig"
"github.com/aiven/terraform-provider-aiven/internal/sdkprovider/service/pg"
)

var aivenAlloyDBOmniUserSchema = map[string]*schema.Schema{
"project": schemautil.CommonSchemaProjectReference,
"service_name": schemautil.CommonSchemaServiceNameReference,
"username": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: schemautil.GetServiceUserValidateFunc(),
Description: userconfig.Desc("The name of the service user for this service.").ForceNew().Referenced().Build(),
},
"password": {
Type: schema.TypeString,
Optional: true,
Sensitive: true,
Computed: true,
DiffSuppressFunc: schemautil.EmptyObjectDiffSuppressFunc,
Description: "The password of the service user.",
},
"pg_allow_replication": {
Type: schema.TypeBool,
Optional: true,
Description: "Allows replication. For the default avnadmin user this attribute is required and is always `true`.",
},

// computed fields
"type": {
Type: schema.TypeString,
Computed: true,
Description: "The service user account type, either primary or regular.",
},
"access_cert": {
Type: schema.TypeString,
Sensitive: true,
Computed: true,
Description: "The access certificate for the servie user.",
},
"access_key": {
Type: schema.TypeString,
Sensitive: true,
Computed: true,
Description: "The access certificate key for the service user.",
},
}

func ResourceAlloyDBOmniUser() *schema.Resource {
return &schema.Resource{
Description: "Creates and manages an Aiven for AlloyDB Omni service user.",
CreateContext: common.WithGenClient(resourceAlloyDBOmniUserCreate),
UpdateContext: common.WithGenClient(resourceAlloyDBOmniUserUpdate),
ReadContext: common.WithGenClient(resourceAlloyDBOmniUserRead),
DeleteContext: common.WithGenClient(resourceServiceUserDelete),
CreateContext: common.WithGenClient(pg.CreateResourcePGUser),
UpdateContext: common.WithGenClient(pg.UpdateResourcePGUser),
ReadContext: common.WithGenClient(pg.ReadResourcePGUser),
DeleteContext: common.WithGenClient(schemautil.DeleteResourceServiceUser),
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},
Timeouts: schemautil.DefaultResourceTimeouts(),

Schema: aivenAlloyDBOmniUserSchema,
}
}

func resourceAlloyDBOmniUserCreate(ctx context.Context, d *schema.ResourceData, client avngen.Client) error {
projectName := d.Get("project").(string)
serviceName := d.Get("service_name").(string)

// Validates that the service is an AlloyDBOmni service
alloydb, err := client.ServiceGet(ctx, projectName, serviceName)
if err != nil {
return err
}

if alloydb.ServiceType != schemautil.ServiceTypeAlloyDBOmni {
return fmt.Errorf("expected service type %q, got %q", schemautil.ServiceTypeAlloyDBOmni, alloydb.ServiceType)
Schema: pg.SchemaResourcePGUser,
}

username := d.Get("username").(string)
allowReplication := d.Get("pg_allow_replication").(bool)
_, err = client.ServiceUserCreate(
ctx,
projectName,
serviceName,
&service.ServiceUserCreateIn{
Username: username,
AccessControl: &service.AccessControlIn{
PgAllowReplication: &allowReplication,
},
},
)
if err != nil {
return err
}

if _, ok := d.GetOk("password"); ok {
_, err = client.ServiceUserCredentialsModify(
ctx, projectName, serviceName, username,
&service.ServiceUserCredentialsModifyIn{
Operation: service.ServiceUserCredentialsModifyOperationTypeResetCredentials,
NewPassword: schemautil.OptionalStringPointer(d, "password"),
},
)
if err != nil {
return err
}
}

d.SetId(schemautil.BuildResourceID(projectName, serviceName, username))
return resourceAlloyDBOmniUserRead(ctx, d, client)
}

func resourceAlloyDBOmniUserUpdate(ctx context.Context, d *schema.ResourceData, client avngen.Client) error {
projectName, serviceName, username, err := schemautil.SplitResourceID3(d.Id())
if err != nil {
return err
}

_, err = client.ServiceUserCredentialsModify(
ctx, projectName, serviceName, username,
&service.ServiceUserCredentialsModifyIn{
Operation: service.ServiceUserCredentialsModifyOperationTypeResetCredentials,
NewPassword: schemautil.OptionalStringPointer(d, "password"),
},
)

if err != nil {
return err
}

if d.HasChange("pg_allow_replication") {
allowReplication := d.Get("pg_allow_replication").(bool)
_, err = client.ServiceUserCredentialsModify(
ctx, projectName, serviceName, username,
&service.ServiceUserCredentialsModifyIn{
Operation: service.ServiceUserCredentialsModifyOperationTypeSetAccessControl,
AccessControl: &service.AccessControlIn{
PgAllowReplication: &allowReplication,
},
},
)
if err != nil {
return err
}
}

return resourceAlloyDBOmniUserRead(ctx, d, client)
}

func resourceAlloyDBOmniUserRead(ctx context.Context, d *schema.ResourceData, client avngen.Client) error {
projectName, serviceName, username, err := schemautil.SplitResourceID3(d.Id())
if err != nil {
return err
}

user, err := client.ServiceUserGet(ctx, projectName, serviceName, username)
if err != nil {
return schemautil.ResourceReadHandleNotFound(err, d)
}

err = schemautil.ResourceDataSet(aivenAlloyDBOmniUserSchema, d, user)
if err != nil {
return err
}

if user.AccessControl != nil && user.AccessControl.PgAllowReplication != nil {
err = d.Set("pg_allow_replication", *user.AccessControl.PgAllowReplication)
if err != nil {
return err
}
}

return nil
}

func resourceServiceUserDelete(ctx context.Context, d *schema.ResourceData, client avngen.Client) error {
projectName, serviceName, username, err := schemautil.SplitResourceID3(d.Id())
if err != nil {
return err
}

err = client.ServiceUserDelete(ctx, projectName, serviceName, username)
if common.IsCritical(err) {
return err
}

return nil
}
Original file line number Diff line number Diff line change
@@ -1,29 +1,16 @@
package alloydbomni

import (
"context"

avngen "github.com/aiven/go-client-codegen"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"

"github.com/aiven/terraform-provider-aiven/internal/common"
"github.com/aiven/terraform-provider-aiven/internal/schemautil"
"github.com/aiven/terraform-provider-aiven/internal/sdkprovider/service/pg"
)

func DatasourceAlloyDBOmniUser() *schema.Resource {
return &schema.Resource{
ReadContext: common.WithGenClient(datasourceAlloyDBOmniUserRead),
Description: "Gets information about an Aiven for AlloyDB Omni service user.",
Schema: schemautil.ResourceSchemaAsDatasourceSchema(aivenAlloyDBOmniUserSchema,
"project", "service_name", "username"),
ReadContext: common.WithGenClient(pg.ReadDatasourcePGUser),
Schema: pg.SchemaDatasourcePGUser(),
}
}

func datasourceAlloyDBOmniUserRead(ctx context.Context, d *schema.ResourceData, client avngen.Client) error {
projectName := d.Get("project").(string)
serviceName := d.Get("service_name").(string)
userName := d.Get("username").(string)

d.SetId(schemautil.BuildResourceID(projectName, serviceName, userName))
return resourceAlloyDBOmniUserRead(ctx, d, client)
}
4 changes: 2 additions & 2 deletions internal/sdkprovider/service/pg/pg_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ func CreateResourcePGUser(ctx context.Context, d *schema.ResourceData, client av
}

d.SetId(schemautil.BuildResourceID(projectName, serviceName, username))
return RetryReadResourcePGUser(ctx, d, client)
return common.RetryCrudNotFound(ReadResourcePGUser)(ctx, d, client)
}

func UpdateResourcePGUser(ctx context.Context, d *schema.ResourceData, client avngen.Client) error {
Expand Down Expand Up @@ -142,7 +142,7 @@ func UpdateResourcePGUser(ctx context.Context, d *schema.ResourceData, client av
}
}

return RetryReadResourcePGUser(ctx, d, client)
return ReadResourcePGUser(ctx, d, client)
}

func ReadResourcePGUser(ctx context.Context, d *schema.ResourceData, client avngen.Client) error {
Expand Down

0 comments on commit b12d2c9

Please sign in to comment.