fix: re-implement acl part in top level
feat: implement tf identity
This commit is contained in:
parent
1027643f95
commit
29f693308e
6 changed files with 116 additions and 36 deletions
|
|
@ -17,6 +17,26 @@ import (
|
|||
// checks if the CreateInstanceRequestPayload type satisfies the MappedNullable interface at compile time
|
||||
var _ MappedNullable = &CreateInstanceRequestPayload{}
|
||||
|
||||
/*
|
||||
types and functions for acl
|
||||
*/
|
||||
|
||||
// isArray
|
||||
type CreateInstanceRequestPayloadGetAclAttributeType = *[]string
|
||||
type CreateInstanceRequestPayloadGetAclArgType = []string
|
||||
type CreateInstanceRequestPayloadGetAclRetType = []string
|
||||
|
||||
func getCreateInstanceRequestPayloadGetAclAttributeTypeOk(arg CreateInstanceRequestPayloadGetAclAttributeType) (ret CreateInstanceRequestPayloadGetAclRetType, ok bool) {
|
||||
if arg == nil {
|
||||
return ret, false
|
||||
}
|
||||
return *arg, true
|
||||
}
|
||||
|
||||
func setCreateInstanceRequestPayloadGetAclAttributeType(arg *CreateInstanceRequestPayloadGetAclAttributeType, val CreateInstanceRequestPayloadGetAclRetType) {
|
||||
*arg = &val
|
||||
}
|
||||
|
||||
/*
|
||||
types and functions for backupSchedule
|
||||
*/
|
||||
|
|
@ -203,6 +223,7 @@ type CreateInstanceRequestPayloadGetVersionRetType = string
|
|||
|
||||
// CreateInstanceRequestPayload struct for CreateInstanceRequestPayload
|
||||
type CreateInstanceRequestPayload struct {
|
||||
Acl CreateInstanceRequestPayloadGetAclAttributeType `json:"acl" required:"true"`
|
||||
// The schedule for on what time and how often the database backup will be created. The schedule is written as a cron schedule.
|
||||
// REQUIRED
|
||||
BackupSchedule CreateInstanceRequestPayloadGetBackupScheduleAttributeType `json:"backupSchedule" required:"true"`
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
// Copyright (c) STACKIT
|
||||
|
||||
package wait
|
||||
|
||||
import (
|
||||
|
|
@ -14,15 +12,18 @@ import (
|
|||
"github.com/stackitcloud/stackit-sdk-go/core/wait"
|
||||
)
|
||||
|
||||
// "READY" "PENDING" "PROGRESSING" "FAILURE" "UNKNOWN" "TERMINATING"
|
||||
const (
|
||||
InstanceStateEmpty = ""
|
||||
InstanceStateProgressing = "Progressing"
|
||||
InstanceStateSuccess = "Ready"
|
||||
InstanceStateFailed = "Failure"
|
||||
InstanceStateDeleted = "Deleted"
|
||||
InstanceStateProgressing = "PROGRESSING"
|
||||
InstanceStateSuccess = "READY"
|
||||
InstanceStateFailed = "FAILURE"
|
||||
InstanceStateTerminating = "TERMINATING"
|
||||
InstanceStateUnknown = "UNKNOWN"
|
||||
InstanceStatePending = "PENDING"
|
||||
)
|
||||
|
||||
// Interface needed for tests
|
||||
// APIClientInstanceInterface Interface needed for tests
|
||||
type APIClientInstanceInterface interface {
|
||||
GetInstanceRequestExecute(ctx context.Context, projectId, region, instanceId string) (
|
||||
*postgresflex.GetInstanceResponse,
|
||||
|
|
@ -30,12 +31,14 @@ type APIClientInstanceInterface interface {
|
|||
)
|
||||
|
||||
ListUsersRequestExecute(
|
||||
ctx context.Context, projectId string, region string,
|
||||
ctx context.Context,
|
||||
projectId string,
|
||||
region string,
|
||||
instanceId string,
|
||||
) (*postgresflex.ListUserResponse, error)
|
||||
}
|
||||
|
||||
// Interface needed for tests
|
||||
// APIClientUserInterface Interface needed for tests
|
||||
type APIClientUserInterface interface {
|
||||
GetUserRequestExecute(ctx context.Context, projectId, region, instanceId string, userId int64) (
|
||||
*postgresflex.GetUserResponse,
|
||||
|
|
@ -66,6 +69,10 @@ func CreateInstanceWaitHandler(
|
|||
return true, s, fmt.Errorf("instance with id %s has unexpected status %s", instanceId, *s.Status)
|
||||
case InstanceStateEmpty:
|
||||
return false, nil, nil
|
||||
case InstanceStatePending:
|
||||
return false, nil, nil
|
||||
case InstanceStateUnknown:
|
||||
return false, nil, nil
|
||||
case InstanceStateProgressing:
|
||||
return false, nil, nil
|
||||
case InstanceStateSuccess:
|
||||
|
|
@ -80,7 +87,10 @@ func CreateInstanceWaitHandler(
|
|||
instanceCreated = true
|
||||
instanceGetResponse = s
|
||||
case InstanceStateFailed:
|
||||
return true, s, fmt.Errorf("create failed for instance with id %s", instanceId)
|
||||
tflog.Warn(ctx, fmt.Sprintf("Wait handler got status FAILURE for instance: %s", instanceId))
|
||||
return false, nil, nil
|
||||
// API responds with FAILURE for some seconds and then the instance goes to READY
|
||||
// return true, s, fmt.Errorf("create failed for instance with id %s", instanceId)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -90,7 +100,7 @@ func CreateInstanceWaitHandler(
|
|||
if err == nil {
|
||||
return true, instanceGetResponse, 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
|
||||
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
|
||||
if !ok {
|
||||
return false, nil, err
|
||||
}
|
||||
|
|
@ -127,7 +137,9 @@ func PartialUpdateInstanceWaitHandler(
|
|||
return true, s, fmt.Errorf("instance with id %s has unexpected status %s", instanceId, *s.Status)
|
||||
case InstanceStateEmpty:
|
||||
return false, nil, nil
|
||||
case InstanceStateProgressing:
|
||||
case InstanceStateUnknown:
|
||||
return false, nil, nil
|
||||
case InstanceStateTerminating:
|
||||
return false, nil, nil
|
||||
case InstanceStateSuccess:
|
||||
return true, s, nil
|
||||
|
|
@ -155,20 +167,31 @@ func DeleteInstanceWaitHandler(
|
|||
if s == nil || s.Id == nil || *s.Id != instanceId || s.Status == nil {
|
||||
return false, nil, nil
|
||||
}
|
||||
switch *s.Status {
|
||||
default:
|
||||
return true, nil, fmt.Errorf("instance with id %s has unexpected status %s", instanceId, *s.Status)
|
||||
case InstanceStateSuccess:
|
||||
return false, nil, nil
|
||||
case InstanceStateDeleted:
|
||||
return true, nil, nil
|
||||
// TODO - maybe we want to validate status if no 404 error (only unknown or terminating should be valid)
|
||||
//switch *s.Status {
|
||||
//default:
|
||||
// return true, nil, fmt.Errorf("instance with id %s has unexpected status %s", instanceId, *s.Status)
|
||||
//case InstanceStateSuccess:
|
||||
// return false, nil, nil
|
||||
//case InstanceStateTerminating:
|
||||
// return false, nil, nil
|
||||
//}
|
||||
// TODO - add tflog for ignored cases
|
||||
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
|
||||
if !ok {
|
||||
return false, nil, err
|
||||
}
|
||||
if oapiErr.StatusCode != 404 {
|
||||
return false, nil, err
|
||||
}
|
||||
return true, nil, nil
|
||||
},
|
||||
)
|
||||
handler.SetTimeout(5 * time.Minute)
|
||||
return handler
|
||||
}
|
||||
|
||||
// TODO - remove
|
||||
// ForceDeleteInstanceWaitHandler will wait for instance deletion
|
||||
func ForceDeleteInstanceWaitHandler(
|
||||
ctx context.Context,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ import (
|
|||
|
||||
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
"github.com/mhenselin/terraform-provider-stackitprivatepreview/pkg/postgresflexalpha/wait"
|
||||
)
|
||||
|
||||
// Ensure the implementation satisfies the expected interfaces.
|
||||
|
|
@ -227,11 +226,11 @@ func (r *instanceDataSource) Read(ctx context.Context, req datasource.ReadReques
|
|||
|
||||
ctx = core.LogResponse(ctx)
|
||||
|
||||
if instanceResp != nil && instanceResp.Status != nil && *instanceResp.Status == wait.InstanceStateDeleted {
|
||||
resp.State.RemoveResource(ctx)
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", "Instance was deleted successfully")
|
||||
return
|
||||
}
|
||||
//if instanceResp != nil && instanceResp.Status != nil && *instanceResp.Status == wait.InstanceStateDeleted {
|
||||
// resp.State.RemoveResource(ctx)
|
||||
// core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", "Instance was deleted successfully")
|
||||
// return
|
||||
//}
|
||||
|
||||
var flavor = &flavorModel{}
|
||||
if instanceResp != nil && instanceResp.FlavorId != nil {
|
||||
|
|
|
|||
|
|
@ -253,6 +253,7 @@ func toCreatePayload(
|
|||
}
|
||||
|
||||
return &postgresflex.CreateInstanceRequestPayload{
|
||||
Acl: &aclElements,
|
||||
BackupSchedule: conversion.StringValueToPointer(model.BackupSchedule),
|
||||
Encryption: encryptionPayload,
|
||||
FlavorId: conversion.StringValueToPointer(flavor.Id),
|
||||
|
|
|
|||
|
|
@ -22,6 +22,10 @@ type Model struct {
|
|||
Network types.Object `tfsdk:"network"`
|
||||
}
|
||||
|
||||
type IdentityModel struct {
|
||||
ID types.String `tfsdk:"id"`
|
||||
}
|
||||
|
||||
type encryptionModel struct {
|
||||
KeyRingId types.String `tfsdk:"keyring_id"`
|
||||
KeyId types.String `tfsdk:"key_id"`
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/identityschema"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
|
||||
postgresflex "github.com/mhenselin/terraform-provider-stackitprivatepreview/pkg/postgresflexalpha"
|
||||
"github.com/mhenselin/terraform-provider-stackitprivatepreview/pkg/postgresflexalpha/wait"
|
||||
|
|
@ -41,6 +42,7 @@ var (
|
|||
_ resource.ResourceWithImportState = &instanceResource{}
|
||||
_ resource.ResourceWithModifyPlan = &instanceResource{}
|
||||
_ resource.ResourceWithValidateConfig = &instanceResource{}
|
||||
_ resource.ResourceWithIdentity = &instanceResource{}
|
||||
)
|
||||
|
||||
// NewInstanceResource is a helper function to simplify the provider implementation.
|
||||
|
|
@ -388,6 +390,16 @@ func (r *instanceResource) Schema(_ context.Context, req resource.SchemaRequest,
|
|||
}
|
||||
}
|
||||
|
||||
func (r *instanceResource) IdentitySchema(_ context.Context, _ resource.IdentitySchemaRequest, resp *resource.IdentitySchemaResponse) {
|
||||
resp.IdentitySchema = identityschema.Schema{
|
||||
Attributes: map[string]identityschema.Attribute{
|
||||
"id": identityschema.StringAttribute{
|
||||
RequiredForImport: true, // must be set during import by the practitioner
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Create creates the resource and sets the initial Terraform state.
|
||||
func (r *instanceResource) Create(
|
||||
ctx context.Context,
|
||||
|
|
@ -495,18 +507,24 @@ func (r *instanceResource) Create(
|
|||
}
|
||||
|
||||
ctx = core.LogResponse(ctx)
|
||||
|
||||
instanceId := *createResp.Id
|
||||
utils.SetAndLogStateFields(ctx, &resp.Diagnostics, &resp.State, map[string]any{
|
||||
"instance_id": instanceId,
|
||||
})
|
||||
|
||||
model.InstanceId = types.StringValue(instanceId)
|
||||
model.Id = utils.BuildInternalTerraformId(projectId, region, instanceId)
|
||||
resp.Diagnostics.Append(resp.State.Set(ctx, &model)...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
// Set data returned by API in identity
|
||||
identity := IdentityModel{
|
||||
ID: utils.BuildInternalTerraformId(projectId, region, instanceId),
|
||||
}
|
||||
resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...)
|
||||
|
||||
waitResp, err := wait.CreateInstanceWaitHandler(ctx, r.client, projectId, region, instanceId).WaitWithContext(ctx)
|
||||
if err != nil {
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Instance creation waiting: %v", err))
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Wait handler error: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -534,6 +552,13 @@ func (r *instanceResource) Read(ctx context.Context, req resource.ReadRequest, r
|
|||
return
|
||||
}
|
||||
|
||||
// Read identity data
|
||||
var identityData IdentityModel
|
||||
resp.Diagnostics.Append(req.Identity.Get(ctx, &identityData)...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
ctx = core.InitProviderContext(ctx)
|
||||
|
||||
projectId := model.ProjectId.ValueString()
|
||||
|
|
@ -591,10 +616,10 @@ func (r *instanceResource) Read(ctx context.Context, req resource.ReadRequest, r
|
|||
|
||||
ctx = core.LogResponse(ctx)
|
||||
|
||||
if instanceResp != nil && instanceResp.Status != nil && *instanceResp.Status == wait.InstanceStateDeleted {
|
||||
resp.State.RemoveResource(ctx)
|
||||
return
|
||||
}
|
||||
//if instanceResp != nil && instanceResp.Status != nil && *instanceResp.Status == wait.InstanceStateDeleted {
|
||||
// resp.State.RemoveResource(ctx)
|
||||
// return
|
||||
//}
|
||||
|
||||
// Map response body to schema
|
||||
err = mapFields(ctx, instanceResp, &model, flavor, storage, encryption, network, region)
|
||||
|
|
@ -602,12 +627,19 @@ func (r *instanceResource) Read(ctx context.Context, req resource.ReadRequest, r
|
|||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Processing API payload: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
// Set refreshed state
|
||||
diags = resp.State.Set(ctx, model)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
resp.Diagnostics.Append(resp.State.Set(ctx, model)...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
identityData.ID = model.Id
|
||||
resp.Diagnostics.Append(resp.Identity.Set(ctx, identityData)...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
tflog.Info(ctx, "Postgres Flex instance read")
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue