diff --git a/CHANGELOG.md b/CHANGELOG.md index f80554724..f7887eb4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/internal/common/client.go b/internal/common/client.go index 08599f742..c513300e8 100644 --- a/internal/common/client.go +++ b/internal/common/client.go @@ -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" ) @@ -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)) } @@ -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), + ) + } +} diff --git a/internal/schemautil/service_user.go b/internal/schemautil/service_user.go index 6d31b61dc..b41daf921 100644 --- a/internal/schemautil/service_user.go +++ b/internal/schemautil/service_user.go @@ -86,7 +86,7 @@ func ResourceServiceUserRead(ctx context.Context, d *schema.ResourceData, m inte return nil } -func DeleteResourceServiceUser(ctx context.Context, d *schema.ResourceData, client avngen.Client) error { +func ResourceServiceUserDelete(ctx context.Context, d *schema.ResourceData, client avngen.Client) error { projectName, serviceName, username, err := SplitResourceID3(d.Id()) if err != nil { return err diff --git a/internal/sdkprovider/service/alloydbomni/alloydbomni_user.go b/internal/sdkprovider/service/alloydbomni/alloydbomni_user.go index 2b7202469..9952a5b3d 100644 --- a/internal/sdkprovider/service/alloydbomni/alloydbomni_user.go +++ b/internal/sdkprovider/service/alloydbomni/alloydbomni_user.go @@ -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.ResourcePGUserCreate), + UpdateContext: common.WithGenClient(pg.ResourcePGUserUpdate), + ReadContext: common.WithGenClient(pg.ResourcePGUserRead), + DeleteContext: common.WithGenClient(schemautil.ResourceServiceUserDelete), 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.ResourcePGUserSchema, } - - 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 } diff --git a/internal/sdkprovider/service/alloydbomni/alloydbomni_user_data_source.go b/internal/sdkprovider/service/alloydbomni/alloydbomni_user_data_source.go index 638e3abe1..d0084d57c 100644 --- a/internal/sdkprovider/service/alloydbomni/alloydbomni_user_data_source.go +++ b/internal/sdkprovider/service/alloydbomni/alloydbomni_user_data_source.go @@ -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.DatasourcePGUserRead), + Schema: pg.DatasourcePGUserSchema(), } } - -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) -} diff --git a/internal/sdkprovider/service/cassandra/cassandra_user.go b/internal/sdkprovider/service/cassandra/cassandra_user.go index afd17bb7a..913d5a040 100644 --- a/internal/sdkprovider/service/cassandra/cassandra_user.go +++ b/internal/sdkprovider/service/cassandra/cassandra_user.go @@ -54,7 +54,7 @@ func ResourceCassandraUser() *schema.Resource { CreateContext: schemautil.ResourceServiceUserCreate, UpdateContext: schemautil.ResourceServiceUserUpdate, ReadContext: schemautil.ResourceServiceUserRead, - DeleteContext: common.WithGenClient(schemautil.DeleteResourceServiceUser), + DeleteContext: common.WithGenClient(schemautil.ResourceServiceUserDelete), Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, diff --git a/internal/sdkprovider/service/influxdb/influxdb_user.go b/internal/sdkprovider/service/influxdb/influxdb_user.go index 57fbdc4b8..aa5050eb8 100644 --- a/internal/sdkprovider/service/influxdb/influxdb_user.go +++ b/internal/sdkprovider/service/influxdb/influxdb_user.go @@ -54,7 +54,7 @@ func ResourceInfluxDBUser() *schema.Resource { CreateContext: schemautil.ResourceServiceUserCreate, UpdateContext: schemautil.ResourceServiceUserUpdate, ReadContext: schemautil.ResourceServiceUserRead, - DeleteContext: common.WithGenClient(schemautil.DeleteResourceServiceUser), + DeleteContext: common.WithGenClient(schemautil.ResourceServiceUserDelete), Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, diff --git a/internal/sdkprovider/service/kafka/kafka_user.go b/internal/sdkprovider/service/kafka/kafka_user.go index bc9c6f141..4c8be1c43 100644 --- a/internal/sdkprovider/service/kafka/kafka_user.go +++ b/internal/sdkprovider/service/kafka/kafka_user.go @@ -54,7 +54,7 @@ func ResourceKafkaUser() *schema.Resource { CreateContext: schemautil.ResourceServiceUserCreate, UpdateContext: schemautil.ResourceServiceUserUpdate, ReadContext: schemautil.ResourceServiceUserRead, - DeleteContext: common.WithGenClient(schemautil.DeleteResourceServiceUser), + DeleteContext: common.WithGenClient(schemautil.ResourceServiceUserDelete), Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, diff --git a/internal/sdkprovider/service/m3db/m3db_user.go b/internal/sdkprovider/service/m3db/m3db_user.go index 2f385b5aa..a7ee2570e 100644 --- a/internal/sdkprovider/service/m3db/m3db_user.go +++ b/internal/sdkprovider/service/m3db/m3db_user.go @@ -42,7 +42,7 @@ func ResourceM3DBUser() *schema.Resource { CreateContext: schemautil.ResourceServiceUserCreate, UpdateContext: schemautil.ResourceServiceUserUpdate, ReadContext: schemautil.ResourceServiceUserRead, - DeleteContext: common.WithGenClient(schemautil.DeleteResourceServiceUser), + DeleteContext: common.WithGenClient(schemautil.ResourceServiceUserDelete), Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, diff --git a/internal/sdkprovider/service/mysql/mysql_user.go b/internal/sdkprovider/service/mysql/mysql_user.go index 783522428..723159ec2 100644 --- a/internal/sdkprovider/service/mysql/mysql_user.go +++ b/internal/sdkprovider/service/mysql/mysql_user.go @@ -67,7 +67,7 @@ func ResourceMySQLUser() *schema.Resource { CreateContext: resourceMySQLUserCreate, UpdateContext: resourceMySQLUserUpdate, ReadContext: schemautil.ResourceServiceUserRead, - DeleteContext: common.WithGenClient(schemautil.DeleteResourceServiceUser), + DeleteContext: common.WithGenClient(schemautil.ResourceServiceUserDelete), Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, diff --git a/internal/sdkprovider/service/pg/pg_user.go b/internal/sdkprovider/service/pg/pg_user.go index b69cd59ff..1336047a2 100644 --- a/internal/sdkprovider/service/pg/pg_user.go +++ b/internal/sdkprovider/service/pg/pg_user.go @@ -6,7 +6,6 @@ import ( avngen "github.com/aiven/go-client-codegen" "github.com/aiven/go-client-codegen/handler/service" - "github.com/avast/retry-go" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/aiven/terraform-provider-aiven/internal/common" @@ -14,7 +13,7 @@ import ( "github.com/aiven/terraform-provider-aiven/internal/schemautil/userconfig" ) -var SchemaResourcePGUser = map[string]*schema.Schema{ +var ResourcePGUserSchema = map[string]*schema.Schema{ "project": schemautil.CommonSchemaProjectReference, "service_name": schemautil.CommonSchemaServiceNameReference, "username": { @@ -61,19 +60,19 @@ var SchemaResourcePGUser = map[string]*schema.Schema{ func ResourcePGUser() *schema.Resource { return &schema.Resource{ Description: "Creates and manages an Aiven for PostgreSQL® service user.", - CreateContext: common.WithGenClient(CreateResourcePGUser), - UpdateContext: common.WithGenClient(UpdateResourcePGUser), - ReadContext: common.WithGenClient(ReadResourcePGUser), - DeleteContext: common.WithGenClient(schemautil.DeleteResourceServiceUser), + CreateContext: common.WithGenClient(ResourcePGUserCreate), + UpdateContext: common.WithGenClient(ResourcePGUserUpdate), + ReadContext: common.WithGenClient(ResourcePGUserRead), + DeleteContext: common.WithGenClient(schemautil.ResourceServiceUserDelete), Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, Timeouts: schemautil.DefaultResourceTimeouts(), - Schema: SchemaResourcePGUser, + Schema: ResourcePGUserSchema, } } -func CreateResourcePGUser(ctx context.Context, d *schema.ResourceData, client avngen.Client) error { +func ResourcePGUserCreate(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) @@ -107,10 +106,10 @@ 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(ResourcePGUserRead)(ctx, d, client) } -func UpdateResourcePGUser(ctx context.Context, d *schema.ResourceData, client avngen.Client) error { +func ResourcePGUserUpdate(ctx context.Context, d *schema.ResourceData, client avngen.Client) error { projectName, serviceName, username, err := schemautil.SplitResourceID3(d.Id()) if err != nil { return err @@ -142,10 +141,10 @@ func UpdateResourcePGUser(ctx context.Context, d *schema.ResourceData, client av } } - return RetryReadResourcePGUser(ctx, d, client) + return ResourcePGUserRead(ctx, d, client) } -func ReadResourcePGUser(ctx context.Context, d *schema.ResourceData, client avngen.Client) error { +func ResourcePGUserRead(ctx context.Context, d *schema.ResourceData, client avngen.Client) error { projectName, serviceName, username, err := schemautil.SplitResourceID3(d.Id()) if err != nil { return err @@ -156,7 +155,7 @@ func ReadResourcePGUser(ctx context.Context, d *schema.ResourceData, client avng return schemautil.ResourceReadHandleNotFound(err, d) } - err = schemautil.ResourceDataSet(SchemaResourcePGUser, d, user) + err = schemautil.ResourceDataSet(ResourcePGUserSchema, d, user) if err != nil { return err } @@ -170,13 +169,3 @@ func ReadResourcePGUser(ctx context.Context, d *schema.ResourceData, client avng return nil } - -func RetryReadResourcePGUser(ctx context.Context, d *schema.ResourceData, client avngen.Client) error { - return retry.Do( - func() error { - return ReadResourcePGUser(ctx, d, client) - }, - retry.Context(ctx), - retry.RetryIf(avngen.IsNotFound), - ) -} diff --git a/internal/sdkprovider/service/pg/pg_user_data_source.go b/internal/sdkprovider/service/pg/pg_user_data_source.go index 005cc7480..ac35c2cf7 100644 --- a/internal/sdkprovider/service/pg/pg_user_data_source.go +++ b/internal/sdkprovider/service/pg/pg_user_data_source.go @@ -12,21 +12,21 @@ import ( func DatasourcePGUser() *schema.Resource { return &schema.Resource{ - ReadContext: common.WithGenClient(ReadDatasourcePGUser), + ReadContext: common.WithGenClient(DatasourcePGUserRead), Description: "Gets information about an Aiven for PostgreSQL® service user.", - Schema: SchemaDatasourcePGUser(), + Schema: DatasourcePGUserSchema(), } } -func SchemaDatasourcePGUser() map[string]*schema.Schema { - return schemautil.ResourceSchemaAsDatasourceSchema(SchemaResourcePGUser, "project", "service_name", "username") +func DatasourcePGUserSchema() map[string]*schema.Schema { + return schemautil.ResourceSchemaAsDatasourceSchema(ResourcePGUserSchema, "project", "service_name", "username") } -func ReadDatasourcePGUser(ctx context.Context, d *schema.ResourceData, client avngen.Client) error { +func DatasourcePGUserRead(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 ReadResourcePGUser(ctx, d, client) + return ResourcePGUserRead(ctx, d, client) } diff --git a/internal/sdkprovider/service/redis/redis_user.go b/internal/sdkprovider/service/redis/redis_user.go index b8a48605f..877853ab8 100644 --- a/internal/sdkprovider/service/redis/redis_user.go +++ b/internal/sdkprovider/service/redis/redis_user.go @@ -85,7 +85,7 @@ func ResourceRedisUser() *schema.Resource { CreateContext: resourceRedisUserCreate, UpdateContext: resourceRedisUserUpdate, ReadContext: resourceRedisUserRead, - DeleteContext: common.WithGenClient(schemautil.DeleteResourceServiceUser), + DeleteContext: common.WithGenClient(schemautil.ResourceServiceUserDelete), Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, diff --git a/internal/sdkprovider/service/valkey/valkey_user.go b/internal/sdkprovider/service/valkey/valkey_user.go index 11ea852cf..48505ade6 100644 --- a/internal/sdkprovider/service/valkey/valkey_user.go +++ b/internal/sdkprovider/service/valkey/valkey_user.go @@ -85,7 +85,7 @@ func ResourceValkeyUser() *schema.Resource { CreateContext: common.WithGenClient(resourceValkeyUserCreate), UpdateContext: common.WithGenClient(resourceValkeyUserUpdate), ReadContext: common.WithGenClient(resourceValkeyUserRead), - DeleteContext: common.WithGenClient(schemautil.DeleteResourceServiceUser), + DeleteContext: common.WithGenClient(schemautil.ResourceServiceUserDelete), Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, },