fix: pgsql user waiter
This commit is contained in:
parent
459120d3b3
commit
4189a5ebcb
7 changed files with 101 additions and 61 deletions
|
|
@ -123,3 +123,7 @@ func StringFromTemplate(tplFile string, data any) (string, error) {
|
|||
|
||||
return tplBuf.String(), nil
|
||||
}
|
||||
|
||||
func ResStr(prefix, resource, name string) string {
|
||||
return fmt.Sprintf("%s_%s.%s", prefix, resource, name)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ import (
|
|||
fwresource "github.com/hashicorp/terraform-plugin-framework/resource"
|
||||
)
|
||||
|
||||
const pfx = "stackitprivatepreview_postgresflexalpha"
|
||||
|
||||
func TestInstanceResourceSchema(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
|
@ -149,6 +151,8 @@ func getExample() resData {
|
|||
|
||||
func TestAccInstance(t *testing.T) {
|
||||
exData := getExample()
|
||||
t.Logf(" ... working on instance %s", exData.TfName)
|
||||
|
||||
resName := fmt.Sprintf(
|
||||
"stackitprivatepreview_postgresflexalpha_instance.%s",
|
||||
exData.TfName,
|
||||
|
|
@ -211,6 +215,8 @@ func TestAccInstance(t *testing.T) {
|
|||
|
||||
func TestAccInstanceWithUsers(t *testing.T) {
|
||||
data := getExample()
|
||||
t.Logf(" ... working on instance %s", data.TfName)
|
||||
|
||||
userName := "testUser"
|
||||
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{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories,
|
||||
|
|
@ -241,10 +237,10 @@ func TestAccInstanceWithUsers(t *testing.T) {
|
|||
data,
|
||||
),
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
resource.TestCheckResourceAttr(resName, "name", data.Name),
|
||||
resource.TestCheckResourceAttrSet(resName, "id"),
|
||||
resource.TestCheckResourceAttr(resUserName, "name", userName),
|
||||
resource.TestCheckResourceAttrSet(resUserName, "id"),
|
||||
resource.TestCheckResourceAttr(testutils.ResStr(pfx, "instance", data.TfName), "name", data.Name),
|
||||
resource.TestCheckResourceAttrSet(testutils.ResStr(pfx, "instance", data.TfName), "id"),
|
||||
resource.TestCheckResourceAttr(testutils.ResStr(pfx, "user", userName), "name", userName),
|
||||
resource.TestCheckResourceAttrSet(testutils.ResStr(pfx, "user", userName), "id"),
|
||||
),
|
||||
},
|
||||
},
|
||||
|
|
@ -253,6 +249,8 @@ func TestAccInstanceWithUsers(t *testing.T) {
|
|||
|
||||
func TestAccInstanceWithDatabases(t *testing.T) {
|
||||
data := getExample()
|
||||
t.Logf(" ... working on instance %s", data.TfName)
|
||||
|
||||
dbName := "testDb"
|
||||
userName := "testUser"
|
||||
data.Users = []User{
|
||||
|
|
|
|||
|
|
@ -9,12 +9,14 @@ import (
|
|||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework/diag"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/identityschema"
|
||||
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"
|
||||
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/resource"
|
||||
|
|
@ -52,7 +54,7 @@ type UserResourceIdentityModel struct {
|
|||
ProjectID types.String `tfsdk:"project_id"`
|
||||
Region types.String `tfsdk:"region"`
|
||||
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.
|
||||
|
|
@ -150,13 +152,6 @@ func (r *userResource) Create(
|
|||
return
|
||||
}
|
||||
|
||||
// Read identity data
|
||||
var identityData UserResourceIdentityModel
|
||||
resp.Diagnostics.Append(req.Identity.Get(ctx, &identityData)...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
ctx = core.InitProviderContext(ctx)
|
||||
|
||||
arg := &clientArg{
|
||||
|
|
@ -178,6 +173,7 @@ func (r *userResource) Create(
|
|||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating user", fmt.Sprintf("Creating API payload: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
// Create new user
|
||||
userResp, err := r.client.CreateUserRequest(
|
||||
ctx,
|
||||
|
|
@ -185,13 +181,13 @@ func (r *userResource) Create(
|
|||
arg.region,
|
||||
arg.instanceId,
|
||||
).CreateUserRequestPayload(*payload).Execute()
|
||||
|
||||
if err != nil {
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating user", fmt.Sprintf("Calling API: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
if userResp.Id == nil || *userResp.Id == 0 {
|
||||
id, ok := userResp.GetIdOk()
|
||||
if !ok || id == 0 {
|
||||
core.LogAndAddError(
|
||||
ctx,
|
||||
&resp.Diagnostics,
|
||||
|
|
@ -200,13 +196,8 @@ func (r *userResource) Create(
|
|||
)
|
||||
return
|
||||
}
|
||||
model.Id = types.Int64Value(userResp.GetId())
|
||||
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)
|
||||
|
||||
|
|
@ -215,28 +206,52 @@ func (r *userResource) Create(
|
|||
ProjectID: types.StringValue(arg.projectId),
|
||||
Region: types.StringValue(arg.region),
|
||||
InstanceID: types.StringValue(arg.instanceId),
|
||||
UserID: types.Int64Value(userResp.GetId()),
|
||||
UserID: types.Int64Value(id),
|
||||
}
|
||||
resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
// Verify creation
|
||||
exists, err := r.getUserResource(ctx, &model, arg)
|
||||
model.Id = types.Int64Value(id)
|
||||
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.CreateUserWaitHandler(
|
||||
ctx,
|
||||
r.client,
|
||||
arg.projectId,
|
||||
arg.instanceId,
|
||||
arg.region,
|
||||
arg.userId,
|
||||
).SetSleepBeforeWait(
|
||||
10 * time.Second,
|
||||
).SetTimeout(
|
||||
15 * time.Minute,
|
||||
).WaitWithContext(ctx)
|
||||
|
||||
if err != nil {
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating user", fmt.Sprintf("Calling API: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
if !exists {
|
||||
core.LogAndAddError(
|
||||
ctx, &resp.Diagnostics, "Error creating user",
|
||||
fmt.Sprintf("User ID '%v' resource not found after creation", model.UserId.ValueInt64()),
|
||||
ctx,
|
||||
&resp.Diagnostics,
|
||||
"create user",
|
||||
fmt.Sprintf("Instance creation waiting: %v", err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if waitResp.Id == nil || *waitResp.Id != arg.userId {
|
||||
core.LogAndAddError(
|
||||
ctx,
|
||||
&resp.Diagnostics,
|
||||
"create user",
|
||||
"Instance creation waiting: returned id is nil or wrong",
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// Set state to fully populated data
|
||||
diags = resp.State.Set(ctx, model)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
|
|
@ -320,23 +335,12 @@ func (r *userResource) Update(
|
|||
return
|
||||
}
|
||||
|
||||
// Read identity data
|
||||
var identityData UserResourceIdentityModel
|
||||
resp.Diagnostics.Append(req.Identity.Get(ctx, &identityData)...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
ctx = core.InitProviderContext(ctx)
|
||||
|
||||
arg, errExt := r.extractIdentityData(model, identityData)
|
||||
if errExt != nil {
|
||||
core.LogAndAddError(
|
||||
ctx,
|
||||
&resp.Diagnostics,
|
||||
extractErrorSummary,
|
||||
fmt.Sprintf(extractErrorMessage, errExt),
|
||||
)
|
||||
arg := &clientArg{
|
||||
projectId: model.ProjectId.ValueString(),
|
||||
instanceId: model.InstanceId.ValueString(),
|
||||
region: r.providerData.GetRegionWithOverride(model.Region),
|
||||
}
|
||||
|
||||
ctx = r.setTFLogFields(ctx, arg)
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ fields:
|
|||
|
||||
- name: 'owner'
|
||||
modifiers:
|
||||
- 'RequiresReplace'
|
||||
- 'UseStateForUnknown'
|
||||
|
||||
- name: 'database_name'
|
||||
modifiers:
|
||||
|
|
@ -43,6 +43,7 @@ fields:
|
|||
|
||||
- name: 'compatibility'
|
||||
modifiers:
|
||||
- 'UseStateForUnknown'
|
||||
- 'RequiresReplace'
|
||||
|
||||
- name: 'compatibility_level'
|
||||
|
|
|
|||
|
|
@ -120,6 +120,7 @@ func getExample() resData {
|
|||
|
||||
func TestAccInstance(t *testing.T) {
|
||||
exData := getExample()
|
||||
t.Logf(" ... working on instance %s", exData.TfName)
|
||||
|
||||
updNameData := exData
|
||||
updNameData.Name = "name-updated"
|
||||
|
|
|
|||
|
|
@ -3,16 +3,13 @@ fields:
|
|||
modifiers:
|
||||
- 'UseStateForUnknown'
|
||||
|
||||
- name: 'user_id'
|
||||
modifiers:
|
||||
- 'UseStateForUnknown'
|
||||
|
||||
- name: 'instance_id'
|
||||
validators:
|
||||
- validate.NoSeparator
|
||||
- validate.UUID
|
||||
modifiers:
|
||||
- 'UseStateForUnknown'
|
||||
- 'RequiresReplace'
|
||||
|
||||
- name: 'project_id'
|
||||
validators:
|
||||
|
|
@ -28,6 +25,7 @@ fields:
|
|||
|
||||
- name: 'user_id'
|
||||
modifiers:
|
||||
- 'UseStateForUnknown'
|
||||
- 'RequiresReplace'
|
||||
|
||||
- name: 'username'
|
||||
|
|
|
|||
|
|
@ -2,7 +2,10 @@ package postgresflexalpha
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-log/tflog"
|
||||
|
|
@ -40,7 +43,7 @@ type APIClientInstanceInterface interface {
|
|||
|
||||
// APIClientUserInterface Interface needed for tests
|
||||
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,
|
||||
error,
|
||||
)
|
||||
|
|
@ -202,3 +205,34 @@ func PartialUpdateInstanceWaitHandler(
|
|||
handler.SetTimeout(45 * time.Minute).SetSleepBeforeWait(30 * time.Second)
|
||||
return handler
|
||||
}
|
||||
|
||||
// CreateUserWaitHandler will wait for instance creation
|
||||
func CreateUserWaitHandler(
|
||||
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
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue