fix: postgres_fixes #54
10 changed files with 242 additions and 140 deletions
|
|
@ -123,3 +123,7 @@ func StringFromTemplate(tplFile string, data any) (string, error) {
|
||||||
|
|
||||||
return tplBuf.String(), nil
|
return tplBuf.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ResStr(prefix, resource, name string) string {
|
||||||
|
return fmt.Sprintf("%s_%s.%s", prefix, resource, name)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,8 +51,8 @@ func mapFields(
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// mapResourceFields maps fields from a ListDatabase API response to a resourceModel for the resource.
|
// mapResourceFields maps fields from a GetDatabase API response to a resourceModel for the resource.
|
||||||
func mapResourceFields(source *postgresflexalpha.ListDatabase, model *resourceModel) error {
|
func mapResourceFields(source *postgresflexalpha.GetDatabaseResponse, model *resourceModel) error {
|
||||||
if source == nil {
|
if source == nil {
|
||||||
return fmt.Errorf("response is nil")
|
return fmt.Errorf("response is nil")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,22 +6,22 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"net/http"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform-plugin-framework/path"
|
"github.com/hashicorp/terraform-plugin-framework/path"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/resource"
|
"github.com/hashicorp/terraform-plugin-framework/resource"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/resource/identityschema"
|
"github.com/hashicorp/terraform-plugin-framework/resource/identityschema"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||||
"github.com/hashicorp/terraform-plugin-log/tflog"
|
"github.com/hashicorp/terraform-plugin-log/tflog"
|
||||||
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
|
|
||||||
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/pkg_gen/postgresflexalpha"
|
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/pkg_gen/postgresflexalpha"
|
||||||
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/conversion"
|
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/conversion"
|
||||||
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/core"
|
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/core"
|
||||||
postgresflexalpha2 "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/database/resources_gen"
|
postgresflexalpha2 "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/database/resources_gen"
|
||||||
postgresflexUtils "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/utils"
|
postgresflexUtils "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/utils"
|
||||||
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/utils"
|
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/utils"
|
||||||
|
postgresflexalpha3 "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/wait/postgresflexalpha"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -236,7 +236,10 @@ func (r *databaseResource) Create(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
database, err := getDatabaseById(ctx, r.client, projectId, region, instanceId, databaseId)
|
database, err := postgresflexalpha3.GetDatabaseByIdWaitHandler(ctx, r.client, projectId, region, instanceId, databaseId).
|
||||||
|
SetTimeout(15 * time.Minute).
|
||||||
|
SetSleepBeforeWait(15 * time.Second).
|
||||||
|
WaitWithContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
core.LogAndAddError(
|
core.LogAndAddError(
|
||||||
ctx,
|
ctx,
|
||||||
|
|
@ -304,14 +307,17 @@ func (r *databaseResource) Read(
|
||||||
ctx = tflog.SetField(ctx, "region", region)
|
ctx = tflog.SetField(ctx, "region", region)
|
||||||
ctx = tflog.SetField(ctx, "database_id", databaseId)
|
ctx = tflog.SetField(ctx, "database_id", databaseId)
|
||||||
|
|
||||||
databaseResp, err := getDatabaseById(ctx, r.client, projectId, region, instanceId, databaseId)
|
databaseResp, err := postgresflexalpha3.GetDatabaseByIdWaitHandler(ctx, r.client, projectId, region, instanceId, databaseId).
|
||||||
|
SetTimeout(15 * time.Minute).
|
||||||
|
SetSleepBeforeWait(15 * time.Second).
|
||||||
|
WaitWithContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped
|
core.LogAndAddError(
|
||||||
if (ok && oapiErr.StatusCode == http.StatusNotFound) || errors.Is(err, errDatabaseNotFound) {
|
ctx,
|
||||||
resp.State.RemoveResource(ctx)
|
&resp.Diagnostics,
|
||||||
return
|
"Error creating database",
|
||||||
}
|
fmt.Sprintf("Getting database details after creation: %v", err),
|
||||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading database", fmt.Sprintf("Calling API: %v", err))
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -433,15 +439,12 @@ func (r *databaseResource) Update(
|
||||||
|
|
||||||
ctx = core.LogResponse(ctx)
|
ctx = core.LogResponse(ctx)
|
||||||
|
|
||||||
// Map response body to schema
|
databaseResp, err := postgresflexalpha3.GetDatabaseByIdWaitHandler(ctx, r.client, projectId, region, instanceId, databaseId64).
|
||||||
databaseResp, err := getDatabaseById(ctx, r.client, projectId, region, instanceId, databaseId64)
|
SetTimeout(15 * time.Minute).
|
||||||
|
SetSleepBeforeWait(15 * time.Second).
|
||||||
|
WaitWithContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped
|
core.LogAndAddError(ctx, &resp.Diagnostics, "error updating database", err.Error())
|
||||||
if (ok && oapiErr.StatusCode == http.StatusNotFound) || errors.Is(err, errDatabaseNotFound) {
|
|
||||||
resp.State.RemoveResource(ctx)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading database", fmt.Sprintf("Calling API: %v", err))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ import (
|
||||||
fwresource "github.com/hashicorp/terraform-plugin-framework/resource"
|
fwresource "github.com/hashicorp/terraform-plugin-framework/resource"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const pfx = "stackitprivatepreview_postgresflexalpha"
|
||||||
|
|
||||||
func TestInstanceResourceSchema(t *testing.T) {
|
func TestInstanceResourceSchema(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|
@ -149,6 +151,8 @@ func getExample() resData {
|
||||||
|
|
||||||
func TestAccInstance(t *testing.T) {
|
func TestAccInstance(t *testing.T) {
|
||||||
exData := getExample()
|
exData := getExample()
|
||||||
|
t.Logf(" ... working on instance %s", exData.TfName)
|
||||||
|
|
||||||
resName := fmt.Sprintf(
|
resName := fmt.Sprintf(
|
||||||
"stackitprivatepreview_postgresflexalpha_instance.%s",
|
"stackitprivatepreview_postgresflexalpha_instance.%s",
|
||||||
exData.TfName,
|
exData.TfName,
|
||||||
|
|
@ -211,6 +215,8 @@ func TestAccInstance(t *testing.T) {
|
||||||
|
|
||||||
func TestAccInstanceWithUsers(t *testing.T) {
|
func TestAccInstanceWithUsers(t *testing.T) {
|
||||||
data := getExample()
|
data := getExample()
|
||||||
|
t.Logf(" ... working on instance %s", data.TfName)
|
||||||
|
|
||||||
userName := "testUser"
|
userName := "testUser"
|
||||||
data.Users = []User{
|
data.Users = []User{
|
||||||
{
|
{
|
||||||
|
|
@ -220,16 +226,6 @@ func TestAccInstanceWithUsers(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
resName := fmt.Sprintf(
|
|
||||||
"stackitprivatepreview_postgresflexalpha_instance.%s",
|
|
||||||
data.TfName,
|
|
||||||
)
|
|
||||||
|
|
||||||
resUserName := fmt.Sprintf(
|
|
||||||
"stackitprivatepreview_postgresflexalpha_user.%s",
|
|
||||||
userName,
|
|
||||||
)
|
|
||||||
|
|
||||||
resource.Test(t, resource.TestCase{
|
resource.Test(t, resource.TestCase{
|
||||||
PreCheck: func() { testAccPreCheck(t) },
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories,
|
ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories,
|
||||||
|
|
@ -241,10 +237,10 @@ func TestAccInstanceWithUsers(t *testing.T) {
|
||||||
data,
|
data,
|
||||||
),
|
),
|
||||||
Check: resource.ComposeAggregateTestCheckFunc(
|
Check: resource.ComposeAggregateTestCheckFunc(
|
||||||
resource.TestCheckResourceAttr(resName, "name", data.Name),
|
resource.TestCheckResourceAttr(testutils.ResStr(pfx, "instance", data.TfName), "name", data.Name),
|
||||||
resource.TestCheckResourceAttrSet(resName, "id"),
|
resource.TestCheckResourceAttrSet(testutils.ResStr(pfx, "instance", data.TfName), "id"),
|
||||||
resource.TestCheckResourceAttr(resUserName, "name", userName),
|
resource.TestCheckResourceAttr(testutils.ResStr(pfx, "user", userName), "name", userName),
|
||||||
resource.TestCheckResourceAttrSet(resUserName, "id"),
|
resource.TestCheckResourceAttrSet(testutils.ResStr(pfx, "user", userName), "id"),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -253,6 +249,8 @@ func TestAccInstanceWithUsers(t *testing.T) {
|
||||||
|
|
||||||
func TestAccInstanceWithDatabases(t *testing.T) {
|
func TestAccInstanceWithDatabases(t *testing.T) {
|
||||||
data := getExample()
|
data := getExample()
|
||||||
|
t.Logf(" ... working on instance %s", data.TfName)
|
||||||
|
|
||||||
dbName := "testDb"
|
dbName := "testDb"
|
||||||
userName := "testUser"
|
userName := "testUser"
|
||||||
data.Users = []User{
|
data.Users = []User{
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"github.com/hashicorp/terraform-plugin-framework/attr"
|
"github.com/hashicorp/terraform-plugin-framework/attr"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||||
postgresflex "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/pkg_gen/postgresflexalpha"
|
postgresflex "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/pkg_gen/postgresflexalpha"
|
||||||
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/conversion"
|
|
||||||
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/core"
|
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/core"
|
||||||
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/utils"
|
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
@ -80,7 +79,7 @@ func toUpdatePayload(model *resourceModel, roles *[]string) (
|
||||||
}
|
}
|
||||||
|
|
||||||
return &postgresflex.UpdateUserRequestPayload{
|
return &postgresflex.UpdateUserRequestPayload{
|
||||||
Name: conversion.StringValueToPointer(model.Name),
|
Name: model.Name.ValueStringPointer(),
|
||||||
Roles: toPayloadRoles(roles),
|
Roles: toPayloadRoles(roles),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
@ -96,7 +95,7 @@ func toCreatePayload(model *resourceModel, roles *[]string) (*postgresflex.Creat
|
||||||
|
|
||||||
return &postgresflex.CreateUserRequestPayload{
|
return &postgresflex.CreateUserRequestPayload{
|
||||||
Roles: toPayloadRoles(roles),
|
Roles: toPayloadRoles(roles),
|
||||||
Name: conversion.StringValueToPointer(model.Name),
|
Name: model.Name.ValueStringPointer(),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,24 +3,23 @@ package postgresflexalpha
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
_ "embed"
|
_ "embed"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"net/http"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform-plugin-framework/diag"
|
"github.com/hashicorp/terraform-plugin-framework/diag"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/resource/identityschema"
|
"github.com/hashicorp/terraform-plugin-framework/resource/identityschema"
|
||||||
postgresflex "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/pkg_gen/postgresflexalpha"
|
postgresflex "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/pkg_gen/postgresflexalpha"
|
||||||
postgresflexalpha "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/user/resources_gen"
|
postgresflexalpha "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/user/resources_gen"
|
||||||
postgresflexUtils "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/utils"
|
postgresflexUtils "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/utils"
|
||||||
|
postgresflexalphaWait "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/wait/postgresflexalpha"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform-plugin-framework/path"
|
"github.com/hashicorp/terraform-plugin-framework/path"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/resource"
|
"github.com/hashicorp/terraform-plugin-framework/resource"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||||
"github.com/hashicorp/terraform-plugin-log/tflog"
|
"github.com/hashicorp/terraform-plugin-log/tflog"
|
||||||
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
|
|
||||||
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/conversion"
|
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/conversion"
|
||||||
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/core"
|
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/core"
|
||||||
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/utils"
|
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/utils"
|
||||||
|
|
@ -52,7 +51,7 @@ type UserResourceIdentityModel struct {
|
||||||
ProjectID types.String `tfsdk:"project_id"`
|
ProjectID types.String `tfsdk:"project_id"`
|
||||||
Region types.String `tfsdk:"region"`
|
Region types.String `tfsdk:"region"`
|
||||||
InstanceID types.String `tfsdk:"instance_id"`
|
InstanceID types.String `tfsdk:"instance_id"`
|
||||||
UserID types.Int64 `tfsdk:"database_id"`
|
UserID types.Int64 `tfsdk:"user_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// userResource implements the resource handling for a PostgreSQL Flex user.
|
// userResource implements the resource handling for a PostgreSQL Flex user.
|
||||||
|
|
@ -150,13 +149,6 @@ func (r *userResource) Create(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read identity data
|
|
||||||
var identityData UserResourceIdentityModel
|
|
||||||
resp.Diagnostics.Append(req.Identity.Get(ctx, &identityData)...)
|
|
||||||
if resp.Diagnostics.HasError() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx = core.InitProviderContext(ctx)
|
ctx = core.InitProviderContext(ctx)
|
||||||
|
|
||||||
arg := &clientArg{
|
arg := &clientArg{
|
||||||
|
|
@ -178,6 +170,7 @@ func (r *userResource) Create(
|
||||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating user", fmt.Sprintf("Creating API payload: %v", err))
|
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating user", fmt.Sprintf("Creating API payload: %v", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new user
|
// Create new user
|
||||||
userResp, err := r.client.CreateUserRequest(
|
userResp, err := r.client.CreateUserRequest(
|
||||||
ctx,
|
ctx,
|
||||||
|
|
@ -185,13 +178,13 @@ func (r *userResource) Create(
|
||||||
arg.region,
|
arg.region,
|
||||||
arg.instanceId,
|
arg.instanceId,
|
||||||
).CreateUserRequestPayload(*payload).Execute()
|
).CreateUserRequestPayload(*payload).Execute()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating user", fmt.Sprintf("Calling API: %v", err))
|
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating user", fmt.Sprintf("Calling API: %v", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if userResp.Id == nil || *userResp.Id == 0 {
|
id, ok := userResp.GetIdOk()
|
||||||
|
if !ok || id == 0 {
|
||||||
core.LogAndAddError(
|
core.LogAndAddError(
|
||||||
ctx,
|
ctx,
|
||||||
&resp.Diagnostics,
|
&resp.Diagnostics,
|
||||||
|
|
@ -200,13 +193,9 @@ func (r *userResource) Create(
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
model.Id = types.Int64Value(userResp.GetId())
|
arg.userId = id
|
||||||
model.UserId = types.Int64Value(userResp.GetId())
|
|
||||||
model.Password = types.StringValue(userResp.GetPassword())
|
|
||||||
model.Status = types.StringValue(userResp.GetStatus())
|
|
||||||
model.ConnectionString = types.StringValue(userResp.GetConnectionString())
|
|
||||||
|
|
||||||
ctx = tflog.SetField(ctx, "user_id", userResp.GetId())
|
ctx = tflog.SetField(ctx, "user_id", id)
|
||||||
|
|
||||||
ctx = core.LogResponse(ctx)
|
ctx = core.LogResponse(ctx)
|
||||||
|
|
||||||
|
|
@ -215,28 +204,65 @@ func (r *userResource) Create(
|
||||||
ProjectID: types.StringValue(arg.projectId),
|
ProjectID: types.StringValue(arg.projectId),
|
||||||
Region: types.StringValue(arg.region),
|
Region: types.StringValue(arg.region),
|
||||||
InstanceID: types.StringValue(arg.instanceId),
|
InstanceID: types.StringValue(arg.instanceId),
|
||||||
UserID: types.Int64Value(userResp.GetId()),
|
UserID: types.Int64Value(id),
|
||||||
}
|
}
|
||||||
resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...)
|
resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...)
|
||||||
if resp.Diagnostics.HasError() {
|
if resp.Diagnostics.HasError() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify creation
|
model.Id = types.Int64Value(id)
|
||||||
exists, err := r.getUserResource(ctx, &model, arg)
|
model.UserId = types.Int64Value(id)
|
||||||
|
model.Password = types.StringValue(userResp.GetPassword())
|
||||||
|
model.Status = types.StringValue(userResp.GetStatus())
|
||||||
|
model.ConnectionString = types.StringValue(userResp.GetConnectionString())
|
||||||
|
|
||||||
|
waitResp, err := postgresflexalphaWait.GetUserByIdWaitHandler(
|
||||||
|
ctx,
|
||||||
|
r.client,
|
||||||
|
arg.projectId,
|
||||||
|
arg.instanceId,
|
||||||
|
arg.region,
|
||||||
|
id,
|
||||||
|
).SetSleepBeforeWait(
|
||||||
|
10 * time.Second,
|
||||||
|
).SetTimeout(
|
||||||
|
15 * time.Minute,
|
||||||
|
).WaitWithContext(ctx)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating user", fmt.Sprintf("Calling API: %v", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !exists {
|
|
||||||
core.LogAndAddError(
|
core.LogAndAddError(
|
||||||
ctx, &resp.Diagnostics, "Error creating user",
|
ctx,
|
||||||
fmt.Sprintf("User ID '%v' resource not found after creation", model.UserId.ValueInt64()),
|
&resp.Diagnostics,
|
||||||
|
"create user",
|
||||||
|
fmt.Sprintf("Instance creation waiting: %v", err),
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if waitResp.Id == nil {
|
||||||
|
core.LogAndAddError(
|
||||||
|
ctx,
|
||||||
|
&resp.Diagnostics,
|
||||||
|
"create user",
|
||||||
|
"Instance creation waiting: returned id is nil",
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if waitResp.Id == nil || *waitResp.Id != id {
|
||||||
|
core.LogAndAddError(
|
||||||
|
ctx,
|
||||||
|
&resp.Diagnostics,
|
||||||
|
"create user",
|
||||||
|
fmt.Sprintf(
|
||||||
|
"Instance creation waiting: returned id is wrong: %+v - %+v",
|
||||||
|
waitResp.Id,
|
||||||
|
id,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Set state to fully populated data
|
// Set state to fully populated data
|
||||||
diags = resp.State.Set(ctx, model)
|
diags = resp.State.Set(ctx, model)
|
||||||
resp.Diagnostics.Append(diags...)
|
resp.Diagnostics.Append(diags...)
|
||||||
|
|
@ -272,17 +298,39 @@ func (r *userResource) Read(
|
||||||
ctx = core.InitProviderContext(ctx)
|
ctx = core.InitProviderContext(ctx)
|
||||||
|
|
||||||
// Read resource state
|
// Read resource state
|
||||||
exists, err := r.getUserResource(ctx, &model, arg)
|
waitResp, err := postgresflexalphaWait.GetUserByIdWaitHandler(
|
||||||
|
ctx,
|
||||||
|
r.client,
|
||||||
|
arg.projectId,
|
||||||
|
arg.instanceId,
|
||||||
|
arg.region,
|
||||||
|
model.UserId.ValueInt64(),
|
||||||
|
).SetSleepBeforeWait(
|
||||||
|
10 * time.Second,
|
||||||
|
).SetTimeout(
|
||||||
|
15 * time.Minute,
|
||||||
|
).WaitWithContext(ctx)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading user", fmt.Sprintf("Calling API: %v", err))
|
core.LogAndAddError(
|
||||||
|
ctx,
|
||||||
|
&resp.Diagnostics,
|
||||||
|
"read user",
|
||||||
|
fmt.Sprintf("Instance creation waiting: %v", err),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !exists {
|
if waitResp.Id == nil || *waitResp.Id != model.UserId.ValueInt64() {
|
||||||
resp.State.RemoveResource(ctx)
|
core.LogAndAddError(
|
||||||
|
ctx,
|
||||||
|
&resp.Diagnostics,
|
||||||
|
"read user",
|
||||||
|
"Instance creation waiting: returned id is nil or wrong",
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
arg.userId = *waitResp.Id
|
||||||
|
|
||||||
ctx = core.LogResponse(ctx)
|
ctx = core.LogResponse(ctx)
|
||||||
|
|
||||||
|
|
@ -320,23 +368,12 @@ func (r *userResource) Update(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read identity data
|
|
||||||
var identityData UserResourceIdentityModel
|
|
||||||
resp.Diagnostics.Append(req.Identity.Get(ctx, &identityData)...)
|
|
||||||
if resp.Diagnostics.HasError() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx = core.InitProviderContext(ctx)
|
ctx = core.InitProviderContext(ctx)
|
||||||
|
|
||||||
arg, errExt := r.extractIdentityData(model, identityData)
|
arg := &clientArg{
|
||||||
if errExt != nil {
|
projectId: model.ProjectId.ValueString(),
|
||||||
core.LogAndAddError(
|
instanceId: model.InstanceId.ValueString(),
|
||||||
ctx,
|
region: r.providerData.GetRegionWithOverride(model.Region),
|
||||||
&resp.Diagnostics,
|
|
||||||
extractErrorSummary,
|
|
||||||
fmt.Sprintf(extractErrorMessage, errExt),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = r.setTFLogFields(ctx, arg)
|
ctx = r.setTFLogFields(ctx, arg)
|
||||||
|
|
@ -397,21 +434,40 @@ func (r *userResource) Update(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify update
|
// Verify update
|
||||||
exists, err := r.getUserResource(ctx, &stateModel, arg)
|
waitResp, err := postgresflexalphaWait.GetUserByIdWaitHandler(
|
||||||
|
ctx,
|
||||||
|
r.client,
|
||||||
|
arg.projectId,
|
||||||
|
arg.instanceId,
|
||||||
|
arg.region,
|
||||||
|
model.UserId.ValueInt64(),
|
||||||
|
).SetSleepBeforeWait(
|
||||||
|
10 * time.Second,
|
||||||
|
).SetTimeout(
|
||||||
|
15 * time.Minute,
|
||||||
|
).WaitWithContext(ctx)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating user", fmt.Sprintf("Calling API: %v", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !exists {
|
|
||||||
core.LogAndAddError(
|
core.LogAndAddError(
|
||||||
ctx, &resp.Diagnostics, "Error updating user",
|
ctx,
|
||||||
fmt.Sprintf("User ID '%v' resource not found after update", stateModel.UserId.ValueInt64()),
|
&resp.Diagnostics,
|
||||||
|
"read user",
|
||||||
|
fmt.Sprintf("Instance creation waiting: %v", err),
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if waitResp.Id == nil || *waitResp.Id != model.UserId.ValueInt64() {
|
||||||
|
core.LogAndAddError(
|
||||||
|
ctx,
|
||||||
|
&resp.Diagnostics,
|
||||||
|
"read user",
|
||||||
|
"Instance creation waiting: returned id is nil or wrong",
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
arg.userId = *waitResp.Id
|
||||||
|
|
||||||
// Set state to fully populated data
|
// Set state to fully populated data
|
||||||
diags = resp.State.Set(ctx, stateModel)
|
diags = resp.State.Set(ctx, stateModel)
|
||||||
resp.Diagnostics.Append(diags...)
|
resp.Diagnostics.Append(diags...)
|
||||||
|
|
@ -470,19 +526,19 @@ func (r *userResource) Delete(
|
||||||
|
|
||||||
ctx = core.LogResponse(ctx)
|
ctx = core.LogResponse(ctx)
|
||||||
|
|
||||||
// Verify deletion
|
// TODO: Verify deletion
|
||||||
exists, err := r.getUserResource(ctx, &model, arg)
|
//exists, err := r.getUserResource(ctx, &model, arg)
|
||||||
if err != nil {
|
//if err != nil {
|
||||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting user", fmt.Sprintf("Calling API: %v", err))
|
// core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting user", fmt.Sprintf("Calling API: %v", err))
|
||||||
return
|
// return
|
||||||
}
|
//}
|
||||||
if exists {
|
//if exists {
|
||||||
core.LogAndAddError(
|
// core.LogAndAddError(
|
||||||
ctx, &resp.Diagnostics, "Error deleting user",
|
// ctx, &resp.Diagnostics, "Error deleting user",
|
||||||
fmt.Sprintf("User ID '%v' resource still exists after deletion", model.UserId.ValueInt64()),
|
// fmt.Sprintf("User ID '%v' resource still exists after deletion", model.UserId.ValueInt64()),
|
||||||
)
|
// )
|
||||||
return
|
// return
|
||||||
}
|
//}
|
||||||
|
|
||||||
resp.State.RemoveResource(ctx)
|
resp.State.RemoveResource(ctx)
|
||||||
|
|
||||||
|
|
@ -513,34 +569,6 @@ func (r *userResource) IdentitySchema(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// getUserResource refreshes the resource state by calling the API and mapping the response to the model.
|
|
||||||
// Returns true if the resource state was successfully refreshed, false if the resource does not exist.
|
|
||||||
func (r *userResource) getUserResource(ctx context.Context, model *resourceModel, arg *clientArg) (bool, error) {
|
|
||||||
|
|
||||||
if arg.userId > math.MaxInt32 {
|
|
||||||
return false, errors.New("error in type conversion: int value too large (userId)")
|
|
||||||
}
|
|
||||||
userId := int32(arg.userId)
|
|
||||||
|
|
||||||
// API Call
|
|
||||||
userResp, err := r.client.GetUserRequest(ctx, arg.projectId, arg.region, arg.instanceId, userId).Execute()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
var oapiErr *oapierror.GenericOpenAPIError
|
|
||||||
if errors.As(err, &oapiErr) && oapiErr.StatusCode == http.StatusNotFound {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, fmt.Errorf("error fetching user resource: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := mapResourceFields(userResp, model, arg.region); err != nil {
|
|
||||||
return false, fmt.Errorf("error mapping user resource: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// clientArg holds the arguments for API calls.
|
// clientArg holds the arguments for API calls.
|
||||||
type clientArg struct {
|
type clientArg struct {
|
||||||
projectId string
|
projectId string
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ fields:
|
||||||
|
|
||||||
- name: 'owner'
|
- name: 'owner'
|
||||||
modifiers:
|
modifiers:
|
||||||
- 'RequiresReplace'
|
- 'UseStateForUnknown'
|
||||||
|
|
||||||
- name: 'database_name'
|
- name: 'database_name'
|
||||||
modifiers:
|
modifiers:
|
||||||
|
|
@ -43,6 +43,7 @@ fields:
|
||||||
|
|
||||||
- name: 'compatibility'
|
- name: 'compatibility'
|
||||||
modifiers:
|
modifiers:
|
||||||
|
- 'UseStateForUnknown'
|
||||||
- 'RequiresReplace'
|
- 'RequiresReplace'
|
||||||
|
|
||||||
- name: 'compatibility_level'
|
- name: 'compatibility_level'
|
||||||
|
|
|
||||||
|
|
@ -120,6 +120,7 @@ func getExample() resData {
|
||||||
|
|
||||||
func TestAccInstance(t *testing.T) {
|
func TestAccInstance(t *testing.T) {
|
||||||
exData := getExample()
|
exData := getExample()
|
||||||
|
t.Logf(" ... working on instance %s", exData.TfName)
|
||||||
|
|
||||||
updNameData := exData
|
updNameData := exData
|
||||||
updNameData.Name = "name-updated"
|
updNameData.Name = "name-updated"
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,13 @@ fields:
|
||||||
modifiers:
|
modifiers:
|
||||||
- 'UseStateForUnknown'
|
- 'UseStateForUnknown'
|
||||||
|
|
||||||
- name: 'user_id'
|
|
||||||
modifiers:
|
|
||||||
- 'UseStateForUnknown'
|
|
||||||
|
|
||||||
- name: 'instance_id'
|
- name: 'instance_id'
|
||||||
validators:
|
validators:
|
||||||
- validate.NoSeparator
|
- validate.NoSeparator
|
||||||
- validate.UUID
|
- validate.UUID
|
||||||
modifiers:
|
modifiers:
|
||||||
- 'UseStateForUnknown'
|
- 'UseStateForUnknown'
|
||||||
|
- 'RequiresReplace'
|
||||||
|
|
||||||
- name: 'project_id'
|
- name: 'project_id'
|
||||||
validators:
|
validators:
|
||||||
|
|
@ -28,6 +25,7 @@ fields:
|
||||||
|
|
||||||
- name: 'user_id'
|
- name: 'user_id'
|
||||||
modifiers:
|
modifiers:
|
||||||
|
- 'UseStateForUnknown'
|
||||||
- 'RequiresReplace'
|
- 'RequiresReplace'
|
||||||
|
|
||||||
- name: 'username'
|
- name: 'username'
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,10 @@ package postgresflexalpha
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform-plugin-log/tflog"
|
"github.com/hashicorp/terraform-plugin-log/tflog"
|
||||||
|
|
@ -40,10 +43,18 @@ type APIClientInstanceInterface interface {
|
||||||
|
|
||||||
// APIClientUserInterface Interface needed for tests
|
// APIClientUserInterface Interface needed for tests
|
||||||
type APIClientUserInterface interface {
|
type APIClientUserInterface interface {
|
||||||
GetUserRequestExecute(ctx context.Context, projectId, region, instanceId string, userId int64) (
|
GetUserRequestExecute(ctx context.Context, projectId, region, instanceId string, userId int32) (
|
||||||
*postgresflex.GetUserResponse,
|
*postgresflex.GetUserResponse,
|
||||||
error,
|
error,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
GetDatabaseRequestExecute(
|
||||||
|
ctx context.Context,
|
||||||
|
projectId string,
|
||||||
|
region string,
|
||||||
|
instanceId string,
|
||||||
|
databaseId int32,
|
||||||
|
) (*postgresflex.GetDatabaseResponse, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateInstanceWaitHandler will wait for instance creation
|
// CreateInstanceWaitHandler will wait for instance creation
|
||||||
|
|
@ -202,3 +213,62 @@ func PartialUpdateInstanceWaitHandler(
|
||||||
handler.SetTimeout(45 * time.Minute).SetSleepBeforeWait(30 * time.Second)
|
handler.SetTimeout(45 * time.Minute).SetSleepBeforeWait(30 * time.Second)
|
||||||
return handler
|
return handler
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetUserByIdWaitHandler will wait for instance creation
|
||||||
|
func GetUserByIdWaitHandler(
|
||||||
|
ctx context.Context,
|
||||||
|
a APIClientUserInterface,
|
||||||
|
projectId, instanceId, region string,
|
||||||
|
userId int64,
|
||||||
|
) *wait.AsyncActionHandler[postgresflex.GetUserResponse] {
|
||||||
|
handler := wait.New(
|
||||||
|
func() (waitFinished bool, response *postgresflex.GetUserResponse, err error) {
|
||||||
|
if userId > math.MaxInt32 {
|
||||||
|
return false, nil, fmt.Errorf("userId value is too big for int32")
|
||||||
|
}
|
||||||
|
userId32 := int32(userId)
|
||||||
|
s, err := a.GetUserRequestExecute(ctx, projectId, region, instanceId, userId32)
|
||||||
|
if err != nil {
|
||||||
|
var oapiErr *oapierror.GenericOpenAPIError
|
||||||
|
ok := errors.As(err, &oapiErr)
|
||||||
|
if !ok {
|
||||||
|
return false, nil, fmt.Errorf("could not convert error to oapierror.GenericOpenAPIError")
|
||||||
|
}
|
||||||
|
if oapiErr.StatusCode != http.StatusNotFound {
|
||||||
|
return false, nil, err
|
||||||
|
}
|
||||||
|
return false, nil, nil
|
||||||
|
}
|
||||||
|
return true, s, nil
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return handler
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDatabaseByIdWaitHandler will wait for instance creation
|
||||||
|
func GetDatabaseByIdWaitHandler(
|
||||||
|
ctx context.Context,
|
||||||
|
a APIClientUserInterface,
|
||||||
|
projectId, instanceId, region string,
|
||||||
|
databaseId int64,
|
||||||
|
) *wait.AsyncActionHandler[postgresflex.GetDatabaseResponse] {
|
||||||
|
handler := wait.New(
|
||||||
|
func() (waitFinished bool, response *postgresflex.GetDatabaseResponse, err error) {
|
||||||
|
dbId32 := int32(databaseId)
|
||||||
|
s, err := a.GetDatabaseRequestExecute(ctx, projectId, region, instanceId, dbId32)
|
||||||
|
if err != nil {
|
||||||
|
var oapiErr *oapierror.GenericOpenAPIError
|
||||||
|
ok := errors.As(err, &oapiErr)
|
||||||
|
if !ok {
|
||||||
|
return false, nil, fmt.Errorf("could not convert error to oapierror.GenericOpenAPIError")
|
||||||
|
}
|
||||||
|
if oapiErr.StatusCode != http.StatusNotFound {
|
||||||
|
return false, nil, err
|
||||||
|
}
|
||||||
|
return false, nil, nil
|
||||||
|
}
|
||||||
|
return true, s, nil
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return handler
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue