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
|
// checks if the CreateInstanceRequestPayload type satisfies the MappedNullable interface at compile time
|
||||||
var _ MappedNullable = &CreateInstanceRequestPayload{}
|
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
|
types and functions for backupSchedule
|
||||||
*/
|
*/
|
||||||
|
|
@ -203,6 +223,7 @@ type CreateInstanceRequestPayloadGetVersionRetType = string
|
||||||
|
|
||||||
// CreateInstanceRequestPayload struct for CreateInstanceRequestPayload
|
// CreateInstanceRequestPayload struct for CreateInstanceRequestPayload
|
||||||
type CreateInstanceRequestPayload struct {
|
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.
|
// The schedule for on what time and how often the database backup will be created. The schedule is written as a cron schedule.
|
||||||
// REQUIRED
|
// REQUIRED
|
||||||
BackupSchedule CreateInstanceRequestPayloadGetBackupScheduleAttributeType `json:"backupSchedule" required:"true"`
|
BackupSchedule CreateInstanceRequestPayloadGetBackupScheduleAttributeType `json:"backupSchedule" required:"true"`
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
// Copyright (c) STACKIT
|
|
||||||
|
|
||||||
package wait
|
package wait
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
@ -14,15 +12,18 @@ import (
|
||||||
"github.com/stackitcloud/stackit-sdk-go/core/wait"
|
"github.com/stackitcloud/stackit-sdk-go/core/wait"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// "READY" "PENDING" "PROGRESSING" "FAILURE" "UNKNOWN" "TERMINATING"
|
||||||
const (
|
const (
|
||||||
InstanceStateEmpty = ""
|
InstanceStateEmpty = ""
|
||||||
InstanceStateProgressing = "Progressing"
|
InstanceStateProgressing = "PROGRESSING"
|
||||||
InstanceStateSuccess = "Ready"
|
InstanceStateSuccess = "READY"
|
||||||
InstanceStateFailed = "Failure"
|
InstanceStateFailed = "FAILURE"
|
||||||
InstanceStateDeleted = "Deleted"
|
InstanceStateTerminating = "TERMINATING"
|
||||||
|
InstanceStateUnknown = "UNKNOWN"
|
||||||
|
InstanceStatePending = "PENDING"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Interface needed for tests
|
// APIClientInstanceInterface Interface needed for tests
|
||||||
type APIClientInstanceInterface interface {
|
type APIClientInstanceInterface interface {
|
||||||
GetInstanceRequestExecute(ctx context.Context, projectId, region, instanceId string) (
|
GetInstanceRequestExecute(ctx context.Context, projectId, region, instanceId string) (
|
||||||
*postgresflex.GetInstanceResponse,
|
*postgresflex.GetInstanceResponse,
|
||||||
|
|
@ -30,12 +31,14 @@ type APIClientInstanceInterface interface {
|
||||||
)
|
)
|
||||||
|
|
||||||
ListUsersRequestExecute(
|
ListUsersRequestExecute(
|
||||||
ctx context.Context, projectId string, region string,
|
ctx context.Context,
|
||||||
|
projectId string,
|
||||||
|
region string,
|
||||||
instanceId string,
|
instanceId string,
|
||||||
) (*postgresflex.ListUserResponse, error)
|
) (*postgresflex.ListUserResponse, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 int64) (
|
||||||
*postgresflex.GetUserResponse,
|
*postgresflex.GetUserResponse,
|
||||||
|
|
@ -66,6 +69,10 @@ func CreateInstanceWaitHandler(
|
||||||
return true, s, fmt.Errorf("instance with id %s has unexpected status %s", instanceId, *s.Status)
|
return true, s, fmt.Errorf("instance with id %s has unexpected status %s", instanceId, *s.Status)
|
||||||
case InstanceStateEmpty:
|
case InstanceStateEmpty:
|
||||||
return false, nil, nil
|
return false, nil, nil
|
||||||
|
case InstanceStatePending:
|
||||||
|
return false, nil, nil
|
||||||
|
case InstanceStateUnknown:
|
||||||
|
return false, nil, nil
|
||||||
case InstanceStateProgressing:
|
case InstanceStateProgressing:
|
||||||
return false, nil, nil
|
return false, nil, nil
|
||||||
case InstanceStateSuccess:
|
case InstanceStateSuccess:
|
||||||
|
|
@ -80,7 +87,10 @@ func CreateInstanceWaitHandler(
|
||||||
instanceCreated = true
|
instanceCreated = true
|
||||||
instanceGetResponse = s
|
instanceGetResponse = s
|
||||||
case InstanceStateFailed:
|
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 {
|
if err == nil {
|
||||||
return true, instanceGetResponse, 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 {
|
if !ok {
|
||||||
return false, nil, err
|
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)
|
return true, s, fmt.Errorf("instance with id %s has unexpected status %s", instanceId, *s.Status)
|
||||||
case InstanceStateEmpty:
|
case InstanceStateEmpty:
|
||||||
return false, nil, nil
|
return false, nil, nil
|
||||||
case InstanceStateProgressing:
|
case InstanceStateUnknown:
|
||||||
|
return false, nil, nil
|
||||||
|
case InstanceStateTerminating:
|
||||||
return false, nil, nil
|
return false, nil, nil
|
||||||
case InstanceStateSuccess:
|
case InstanceStateSuccess:
|
||||||
return true, s, nil
|
return true, s, nil
|
||||||
|
|
@ -155,20 +167,31 @@ func DeleteInstanceWaitHandler(
|
||||||
if s == nil || s.Id == nil || *s.Id != instanceId || s.Status == nil {
|
if s == nil || s.Id == nil || *s.Id != instanceId || s.Status == nil {
|
||||||
return false, nil, nil
|
return false, nil, nil
|
||||||
}
|
}
|
||||||
switch *s.Status {
|
// TODO - maybe we want to validate status if no 404 error (only unknown or terminating should be valid)
|
||||||
default:
|
//switch *s.Status {
|
||||||
return true, nil, fmt.Errorf("instance with id %s has unexpected status %s", instanceId, *s.Status)
|
//default:
|
||||||
case InstanceStateSuccess:
|
// return true, nil, fmt.Errorf("instance with id %s has unexpected status %s", instanceId, *s.Status)
|
||||||
return false, nil, nil
|
//case InstanceStateSuccess:
|
||||||
case InstanceStateDeleted:
|
// return false, nil, nil
|
||||||
return true, 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)
|
handler.SetTimeout(5 * time.Minute)
|
||||||
return handler
|
return handler
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO - remove
|
||||||
// ForceDeleteInstanceWaitHandler will wait for instance deletion
|
// ForceDeleteInstanceWaitHandler will wait for instance deletion
|
||||||
func ForceDeleteInstanceWaitHandler(
|
func ForceDeleteInstanceWaitHandler(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ import (
|
||||||
|
|
||||||
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
|
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||||
"github.com/mhenselin/terraform-provider-stackitprivatepreview/pkg/postgresflexalpha/wait"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Ensure the implementation satisfies the expected interfaces.
|
// 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)
|
ctx = core.LogResponse(ctx)
|
||||||
|
|
||||||
if instanceResp != nil && instanceResp.Status != nil && *instanceResp.Status == wait.InstanceStateDeleted {
|
//if instanceResp != nil && instanceResp.Status != nil && *instanceResp.Status == wait.InstanceStateDeleted {
|
||||||
resp.State.RemoveResource(ctx)
|
// resp.State.RemoveResource(ctx)
|
||||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", "Instance was deleted successfully")
|
// core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", "Instance was deleted successfully")
|
||||||
return
|
// return
|
||||||
}
|
//}
|
||||||
|
|
||||||
var flavor = &flavorModel{}
|
var flavor = &flavorModel{}
|
||||||
if instanceResp != nil && instanceResp.FlavorId != nil {
|
if instanceResp != nil && instanceResp.FlavorId != nil {
|
||||||
|
|
|
||||||
|
|
@ -253,6 +253,7 @@ func toCreatePayload(
|
||||||
}
|
}
|
||||||
|
|
||||||
return &postgresflex.CreateInstanceRequestPayload{
|
return &postgresflex.CreateInstanceRequestPayload{
|
||||||
|
Acl: &aclElements,
|
||||||
BackupSchedule: conversion.StringValueToPointer(model.BackupSchedule),
|
BackupSchedule: conversion.StringValueToPointer(model.BackupSchedule),
|
||||||
Encryption: encryptionPayload,
|
Encryption: encryptionPayload,
|
||||||
FlavorId: conversion.StringValueToPointer(flavor.Id),
|
FlavorId: conversion.StringValueToPointer(flavor.Id),
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,10 @@ type Model struct {
|
||||||
Network types.Object `tfsdk:"network"`
|
Network types.Object `tfsdk:"network"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type IdentityModel struct {
|
||||||
|
ID types.String `tfsdk:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
type encryptionModel struct {
|
type encryptionModel struct {
|
||||||
KeyRingId types.String `tfsdk:"keyring_id"`
|
KeyRingId types.String `tfsdk:"keyring_id"`
|
||||||
KeyId types.String `tfsdk:"key_id"`
|
KeyId types.String `tfsdk:"key_id"`
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework/resource/identityschema"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
|
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
|
||||||
postgresflex "github.com/mhenselin/terraform-provider-stackitprivatepreview/pkg/postgresflexalpha"
|
postgresflex "github.com/mhenselin/terraform-provider-stackitprivatepreview/pkg/postgresflexalpha"
|
||||||
"github.com/mhenselin/terraform-provider-stackitprivatepreview/pkg/postgresflexalpha/wait"
|
"github.com/mhenselin/terraform-provider-stackitprivatepreview/pkg/postgresflexalpha/wait"
|
||||||
|
|
@ -41,6 +42,7 @@ var (
|
||||||
_ resource.ResourceWithImportState = &instanceResource{}
|
_ resource.ResourceWithImportState = &instanceResource{}
|
||||||
_ resource.ResourceWithModifyPlan = &instanceResource{}
|
_ resource.ResourceWithModifyPlan = &instanceResource{}
|
||||||
_ resource.ResourceWithValidateConfig = &instanceResource{}
|
_ resource.ResourceWithValidateConfig = &instanceResource{}
|
||||||
|
_ resource.ResourceWithIdentity = &instanceResource{}
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewInstanceResource is a helper function to simplify the provider implementation.
|
// 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.
|
// Create creates the resource and sets the initial Terraform state.
|
||||||
func (r *instanceResource) Create(
|
func (r *instanceResource) Create(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
|
|
@ -495,18 +507,24 @@ func (r *instanceResource) Create(
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = core.LogResponse(ctx)
|
ctx = core.LogResponse(ctx)
|
||||||
|
|
||||||
instanceId := *createResp.Id
|
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() {
|
if resp.Diagnostics.HasError() {
|
||||||
return
|
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)
|
waitResp, err := wait.CreateInstanceWaitHandler(ctx, r.client, projectId, region, instanceId).WaitWithContext(ctx)
|
||||||
if err != nil {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -534,6 +552,13 @@ func (r *instanceResource) Read(ctx context.Context, req resource.ReadRequest, r
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read identity data
|
||||||
|
var identityData IdentityModel
|
||||||
|
resp.Diagnostics.Append(req.Identity.Get(ctx, &identityData)...)
|
||||||
|
if resp.Diagnostics.HasError() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ctx = core.InitProviderContext(ctx)
|
ctx = core.InitProviderContext(ctx)
|
||||||
|
|
||||||
projectId := model.ProjectId.ValueString()
|
projectId := model.ProjectId.ValueString()
|
||||||
|
|
@ -591,10 +616,10 @@ func (r *instanceResource) Read(ctx context.Context, req resource.ReadRequest, r
|
||||||
|
|
||||||
ctx = core.LogResponse(ctx)
|
ctx = core.LogResponse(ctx)
|
||||||
|
|
||||||
if instanceResp != nil && instanceResp.Status != nil && *instanceResp.Status == wait.InstanceStateDeleted {
|
//if instanceResp != nil && instanceResp.Status != nil && *instanceResp.Status == wait.InstanceStateDeleted {
|
||||||
resp.State.RemoveResource(ctx)
|
// resp.State.RemoveResource(ctx)
|
||||||
return
|
// return
|
||||||
}
|
//}
|
||||||
|
|
||||||
// Map response body to schema
|
// Map response body to schema
|
||||||
err = mapFields(ctx, instanceResp, &model, flavor, storage, encryption, network, region)
|
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))
|
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Processing API payload: %v", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set refreshed state
|
// Set refreshed state
|
||||||
diags = resp.State.Set(ctx, model)
|
resp.Diagnostics.Append(resp.State.Set(ctx, model)...)
|
||||||
resp.Diagnostics.Append(diags...)
|
|
||||||
if resp.Diagnostics.HasError() {
|
if resp.Diagnostics.HasError() {
|
||||||
return
|
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")
|
tflog.Info(ctx, "Postgres Flex instance read")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue