Feat/separate functions (#19)
* chore: work save * fix: refactor flavors * fix: refactor pg user and database * fix: refactor flavor parameters * fix: refactor tf script * chore: work save * chore: work save * chore: work save --------- Co-authored-by: Marcel S. Henselin <marcel.henselin@stackit.cloud>
This commit is contained in:
parent
910551f09d
commit
0150fea302
54 changed files with 6010 additions and 2826 deletions
|
|
@ -100,25 +100,11 @@ func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaReques
|
|||
"backup_schedule": schema.StringAttribute{
|
||||
Computed: true,
|
||||
},
|
||||
"flavor": schema.SingleNestedAttribute{
|
||||
"retention_days": schema.Int64Attribute{
|
||||
Computed: true,
|
||||
},
|
||||
"flavor_id": schema.StringAttribute{
|
||||
Computed: true,
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"id": schema.StringAttribute{
|
||||
Computed: true,
|
||||
},
|
||||
"description": schema.StringAttribute{
|
||||
Computed: true,
|
||||
},
|
||||
"cpu": schema.Int64Attribute{
|
||||
Computed: true,
|
||||
},
|
||||
"ram": schema.Int64Attribute{
|
||||
Computed: true,
|
||||
},
|
||||
"node_type": schema.StringAttribute{
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
"replicas": schema.Int64Attribute{
|
||||
Computed: true,
|
||||
|
|
@ -226,31 +212,6 @@ func (r *instanceDataSource) Read(ctx context.Context, req datasource.ReadReques
|
|||
|
||||
ctx = core.LogResponse(ctx)
|
||||
|
||||
var flavor = &flavorModel{}
|
||||
if instanceResp != nil && instanceResp.FlavorId != nil {
|
||||
flavor.Id = types.StringValue(*instanceResp.FlavorId)
|
||||
}
|
||||
|
||||
if !model.Flavor.IsNull() && !model.Flavor.IsUnknown() {
|
||||
diags = model.Flavor.As(ctx, flavor, basetypes.ObjectAsOptions{})
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
err := getFlavorModelById(ctx, r.client, &model, flavor)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError(err.Error(), err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
diags = model.Flavor.As(ctx, flavor, basetypes.ObjectAsOptions{})
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var storage = &storageModel{}
|
||||
if !model.Storage.IsNull() && !model.Storage.IsUnknown() {
|
||||
diags = model.Storage.As(ctx, storage, basetypes.ObjectAsOptions{})
|
||||
|
|
@ -278,7 +239,7 @@ func (r *instanceDataSource) Read(ctx context.Context, req datasource.ReadReques
|
|||
}
|
||||
}
|
||||
|
||||
err = mapFields(ctx, instanceResp, &model, flavor, storage, encryption, network, region)
|
||||
err = mapFields(ctx, r.client, instanceResp, &model, storage, encryption, network, region)
|
||||
if err != nil {
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Processing API payload: %v", err))
|
||||
return
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework/attr"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
|
|
@ -20,9 +19,9 @@ type postgresflexClient interface {
|
|||
|
||||
func mapFields(
|
||||
ctx context.Context,
|
||||
client postgresflexClient,
|
||||
resp *postgresflex.GetInstanceResponse,
|
||||
model *Model,
|
||||
flavor *flavorModel,
|
||||
storage *storageModel,
|
||||
encryption *encryptionModel,
|
||||
network *networkModel,
|
||||
|
|
@ -80,19 +79,11 @@ func mapFields(
|
|||
return fmt.Errorf("creating network (acl list): %w", core.DiagsToError(diags))
|
||||
}
|
||||
|
||||
var routerAddress string
|
||||
if instance.Network.RouterAddress != nil {
|
||||
routerAddress = *instance.Network.RouterAddress
|
||||
diags.AddWarning("field missing while mapping fields", "router_address was empty in API response")
|
||||
}
|
||||
if instance.Network.InstanceAddress == nil {
|
||||
return fmt.Errorf("creating network: no instance address returned")
|
||||
}
|
||||
networkValues = map[string]attr.Value{
|
||||
"acl": aclList,
|
||||
"access_scope": types.StringValue(string(*instance.Network.AccessScope)),
|
||||
"instance_address": types.StringValue(*instance.Network.InstanceAddress),
|
||||
"router_address": types.StringValue(routerAddress),
|
||||
"access_scope": types.StringPointerValue((*string)(instance.Network.AccessScope)),
|
||||
"instance_address": types.StringPointerValue(instance.Network.InstanceAddress),
|
||||
"router_address": types.StringPointerValue(instance.Network.RouterAddress),
|
||||
}
|
||||
}
|
||||
networkObject, diags := types.ObjectValue(networkTypes, networkValues)
|
||||
|
|
@ -100,48 +91,6 @@ func mapFields(
|
|||
return fmt.Errorf("creating network: %w", core.DiagsToError(diags))
|
||||
}
|
||||
|
||||
var flavorValues map[string]attr.Value
|
||||
if instance.FlavorId == nil || *instance.FlavorId == "" {
|
||||
return fmt.Errorf("instance has no flavor id")
|
||||
}
|
||||
if !flavor.Id.IsUnknown() && !flavor.Id.IsNull() {
|
||||
if *instance.FlavorId != flavor.Id.ValueString() {
|
||||
return fmt.Errorf("instance has different flavor id %s - %s", *instance.FlavorId, flavor.Id.ValueString())
|
||||
}
|
||||
}
|
||||
if model.Flavor.IsNull() || model.Flavor.IsUnknown() {
|
||||
var nodeType string
|
||||
if flavor.NodeType.IsUnknown() || flavor.NodeType.IsNull() {
|
||||
if instance.Replicas == nil {
|
||||
return fmt.Errorf("instance has no replicas setting")
|
||||
}
|
||||
switch *instance.Replicas {
|
||||
case 1:
|
||||
nodeType = "Single"
|
||||
case 3:
|
||||
nodeType = "Replicas"
|
||||
default:
|
||||
return fmt.Errorf("could not determine replicas settings")
|
||||
}
|
||||
} else {
|
||||
nodeType = flavor.NodeType.ValueString()
|
||||
}
|
||||
flavorValues = map[string]attr.Value{
|
||||
"id": flavor.Id,
|
||||
"description": flavor.Description,
|
||||
"cpu": flavor.CPU,
|
||||
"ram": flavor.RAM,
|
||||
"node_type": types.StringValue(nodeType),
|
||||
}
|
||||
} else {
|
||||
flavorValues = model.Flavor.Attributes()
|
||||
}
|
||||
|
||||
flavorObject, diags := types.ObjectValue(flavorTypes, flavorValues)
|
||||
if diags.HasError() {
|
||||
return fmt.Errorf("creating flavor: %w", core.DiagsToError(diags))
|
||||
}
|
||||
|
||||
var storageValues map[string]attr.Value
|
||||
if instance.Storage == nil {
|
||||
storageValues = map[string]attr.Value{
|
||||
|
|
@ -167,10 +116,8 @@ func mapFields(
|
|||
model.Id = utils.BuildInternalTerraformId(model.ProjectId.ValueString(), region, instanceId)
|
||||
model.InstanceId = types.StringValue(instanceId)
|
||||
model.Name = types.StringPointerValue(instance.Name)
|
||||
model.Network = networkObject
|
||||
model.BackupSchedule = types.StringPointerValue(instance.BackupSchedule)
|
||||
model.Flavor = flavorObject
|
||||
// TODO - verify working
|
||||
model.FlavorId = types.StringPointerValue(instance.FlavorId)
|
||||
model.Replicas = types.Int64Value(int64(*instance.Replicas))
|
||||
model.Storage = storageObject
|
||||
model.Version = types.StringPointerValue(instance.Version)
|
||||
|
|
@ -182,7 +129,6 @@ func mapFields(
|
|||
|
||||
func toCreatePayload(
|
||||
model *Model,
|
||||
flavor *flavorModel,
|
||||
storage *storageModel,
|
||||
enc *encryptionModel,
|
||||
net *networkModel,
|
||||
|
|
@ -190,9 +136,6 @@ func toCreatePayload(
|
|||
if model == nil {
|
||||
return nil, fmt.Errorf("nil model")
|
||||
}
|
||||
if flavor == nil {
|
||||
return nil, fmt.Errorf("nil flavor")
|
||||
}
|
||||
if storage == nil {
|
||||
return nil, fmt.Errorf("nil storage")
|
||||
}
|
||||
|
|
@ -239,24 +182,11 @@ func toCreatePayload(
|
|||
}
|
||||
}
|
||||
|
||||
if model.Replicas.IsNull() || model.Replicas.IsUnknown() {
|
||||
if !flavor.NodeType.IsNull() && !flavor.NodeType.IsUnknown() {
|
||||
switch strings.ToLower(flavor.NodeType.ValueString()) {
|
||||
case "single":
|
||||
replVal = int32(1)
|
||||
case "replica":
|
||||
replVal = int32(3)
|
||||
default:
|
||||
return nil, fmt.Errorf("flavor has invalid replica attribute")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &postgresflex.CreateInstanceRequestPayload{
|
||||
Acl: &aclElements,
|
||||
BackupSchedule: conversion.StringValueToPointer(model.BackupSchedule),
|
||||
Encryption: encryptionPayload,
|
||||
FlavorId: conversion.StringValueToPointer(flavor.Id),
|
||||
FlavorId: conversion.StringValueToPointer(model.FlavorId),
|
||||
Name: conversion.StringValueToPointer(model.Name),
|
||||
Network: networkPayload,
|
||||
Replicas: postgresflex.CreateInstanceRequestPayloadGetReplicasAttributeType(&replVal),
|
||||
|
|
@ -266,13 +196,14 @@ func toCreatePayload(
|
|||
}, nil
|
||||
}
|
||||
|
||||
func toUpdatePayload(model *Model, flavor *flavorModel, storage *storageModel, _ *networkModel) (*postgresflex.UpdateInstancePartiallyRequestPayload, error) {
|
||||
func toUpdatePayload(
|
||||
model *Model,
|
||||
storage *storageModel,
|
||||
_ *networkModel,
|
||||
) (*postgresflex.UpdateInstancePartiallyRequestPayload, error) {
|
||||
if model == nil {
|
||||
return nil, fmt.Errorf("nil model")
|
||||
}
|
||||
if flavor == nil {
|
||||
return nil, fmt.Errorf("nil flavor")
|
||||
}
|
||||
if storage == nil {
|
||||
return nil, fmt.Errorf("nil storage")
|
||||
}
|
||||
|
|
@ -282,7 +213,7 @@ func toUpdatePayload(model *Model, flavor *flavorModel, storage *storageModel, _
|
|||
// Items: &acl,
|
||||
// },
|
||||
BackupSchedule: conversion.StringValueToPointer(model.BackupSchedule),
|
||||
FlavorId: conversion.StringValueToPointer(flavor.Id),
|
||||
FlavorId: conversion.StringValueToPointer(model.FlavorId),
|
||||
Name: conversion.StringValueToPointer(model.Name),
|
||||
// Replicas: conversion.Int64ValueToPointer(model.Replicas),
|
||||
Storage: &postgresflex.StorageUpdate{
|
||||
|
|
@ -291,187 +222,3 @@ func toUpdatePayload(model *Model, flavor *flavorModel, storage *storageModel, _
|
|||
Version: conversion.StringValueToPointer(model.Version),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func loadFlavorId(ctx context.Context, client postgresflexClient, model *Model, flavor *flavorModel, storage *storageModel) error {
|
||||
if model == nil {
|
||||
return fmt.Errorf("nil model")
|
||||
}
|
||||
if flavor == nil {
|
||||
return fmt.Errorf("nil flavor")
|
||||
}
|
||||
cpu := flavor.CPU.ValueInt64()
|
||||
if cpu == 0 {
|
||||
return fmt.Errorf("nil CPU")
|
||||
}
|
||||
ram := flavor.RAM.ValueInt64()
|
||||
if ram == 0 {
|
||||
return fmt.Errorf("nil RAM")
|
||||
}
|
||||
|
||||
nodeType := flavor.NodeType.ValueString()
|
||||
if nodeType == "" {
|
||||
if model.Replicas.IsNull() || model.Replicas.IsUnknown() {
|
||||
return fmt.Errorf("nil NodeType")
|
||||
}
|
||||
switch model.Replicas.ValueInt64() {
|
||||
case 1:
|
||||
nodeType = "Single"
|
||||
case 3:
|
||||
nodeType = "Replica"
|
||||
default:
|
||||
return fmt.Errorf("unknown Replicas value: %d", model.Replicas.ValueInt64())
|
||||
}
|
||||
}
|
||||
|
||||
storageClass := conversion.StringValueToPointer(storage.Class)
|
||||
if storageClass == nil {
|
||||
return fmt.Errorf("nil StorageClass")
|
||||
}
|
||||
storageSize := conversion.Int64ValueToPointer(storage.Size)
|
||||
if storageSize == nil {
|
||||
return fmt.Errorf("nil StorageSize")
|
||||
}
|
||||
|
||||
projectId := model.ProjectId.ValueString()
|
||||
region := model.Region.ValueString()
|
||||
|
||||
flavorList, err := getAllFlavors(ctx, client, projectId, region)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
avl := ""
|
||||
foundFlavorCount := 0
|
||||
var foundFlavors []string
|
||||
for _, f := range flavorList {
|
||||
if f.Id == nil || f.Cpu == nil || f.Memory == nil {
|
||||
continue
|
||||
}
|
||||
if !strings.EqualFold(*f.NodeType, nodeType) {
|
||||
continue
|
||||
}
|
||||
if *f.Cpu == cpu && *f.Memory == ram {
|
||||
var useSc *postgresflex.FlavorStorageClassesStorageClass
|
||||
for _, sc := range *f.StorageClasses {
|
||||
if *sc.Class != *storageClass {
|
||||
continue
|
||||
}
|
||||
if *storageSize < *f.MinGB || *storageSize > *f.MaxGB {
|
||||
return fmt.Errorf("storage size %d out of bounds (min: %d - max: %d)", *storageSize, *f.MinGB, *f.MaxGB)
|
||||
}
|
||||
useSc = &sc
|
||||
}
|
||||
if useSc == nil {
|
||||
return fmt.Errorf("no storage class found for %s", *storageClass)
|
||||
}
|
||||
|
||||
flavor.Id = types.StringValue(*f.Id)
|
||||
flavor.Description = types.StringValue(*f.Description)
|
||||
foundFlavors = append(foundFlavors, fmt.Sprintf("%s (%d/%d - %s)", *f.Id, *f.Cpu, *f.Memory, *f.NodeType))
|
||||
foundFlavorCount++
|
||||
}
|
||||
for _, cls := range *f.StorageClasses {
|
||||
avl = fmt.Sprintf("%s\n- %d CPU, %d GB RAM, storage %s (min: %d - max: %d)", avl, *f.Cpu, *f.Memory, *cls.Class, *f.MinGB, *f.MaxGB)
|
||||
}
|
||||
}
|
||||
if foundFlavorCount > 1 {
|
||||
return fmt.Errorf(
|
||||
"number of flavors returned: %d\nmultiple flavors found: %d flavors\n %s",
|
||||
len(flavorList),
|
||||
foundFlavorCount,
|
||||
strings.Join(foundFlavors, "\n "),
|
||||
)
|
||||
}
|
||||
if flavor.Id.ValueString() == "" {
|
||||
return fmt.Errorf("couldn't find flavor, available specs are:%s", avl)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getAllFlavors(ctx context.Context, client postgresflexClient, projectId, region string) ([]postgresflex.ListFlavors, error) {
|
||||
if projectId == "" || region == "" {
|
||||
return nil, fmt.Errorf("listing postgresflex flavors: projectId and region are required")
|
||||
}
|
||||
var flavorList []postgresflex.ListFlavors
|
||||
|
||||
page := int64(1)
|
||||
size := int64(10)
|
||||
sort := postgresflex.FLAVORSORT_INDEX_ASC
|
||||
counter := 0
|
||||
for {
|
||||
res, err := client.GetFlavorsRequestExecute(ctx, projectId, region, &page, &size, &sort)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("listing postgresflex flavors: %w", err)
|
||||
}
|
||||
if res.Flavors == nil {
|
||||
return nil, fmt.Errorf("finding flavors for project %s", projectId)
|
||||
}
|
||||
pagination := res.GetPagination()
|
||||
flavors := res.GetFlavors()
|
||||
flavorList = append(flavorList, flavors...)
|
||||
|
||||
if *pagination.TotalRows < int64(len(flavorList)) {
|
||||
return nil, fmt.Errorf("total rows is smaller than current accumulated list - that should not happen")
|
||||
}
|
||||
if *pagination.TotalRows == int64(len(flavorList)) {
|
||||
break
|
||||
}
|
||||
page++
|
||||
|
||||
if page > *pagination.TotalPages {
|
||||
break
|
||||
}
|
||||
|
||||
// implement a breakpoint
|
||||
counter++
|
||||
if counter > 1000 {
|
||||
panic("too many pagination results")
|
||||
}
|
||||
}
|
||||
return flavorList, nil
|
||||
}
|
||||
|
||||
func getFlavorModelById(ctx context.Context, client postgresflexClient, model *Model, flavor *flavorModel) error {
|
||||
if model == nil {
|
||||
return fmt.Errorf("nil model")
|
||||
}
|
||||
if flavor == nil {
|
||||
return fmt.Errorf("nil flavor")
|
||||
}
|
||||
id := conversion.StringValueToPointer(flavor.Id)
|
||||
if id == nil {
|
||||
return fmt.Errorf("nil flavor ID")
|
||||
}
|
||||
|
||||
flavor.Id = types.StringValue("")
|
||||
|
||||
projectId := model.ProjectId.ValueString()
|
||||
region := model.Region.ValueString()
|
||||
|
||||
flavorList, err := getAllFlavors(ctx, client, projectId, region)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
avl := ""
|
||||
for _, f := range flavorList {
|
||||
if f.Id == nil || f.Cpu == nil || f.Memory == nil {
|
||||
continue
|
||||
}
|
||||
if *f.Id == *id {
|
||||
flavor.Id = types.StringValue(*f.Id)
|
||||
flavor.Description = types.StringValue(*f.Description)
|
||||
flavor.CPU = types.Int64Value(*f.Cpu)
|
||||
flavor.RAM = types.Int64Value(*f.Memory)
|
||||
flavor.NodeType = types.StringValue(*f.NodeType)
|
||||
break
|
||||
}
|
||||
avl = fmt.Sprintf("%s\n- %d CPU, %d GB RAM", avl, *f.Cpu, *f.Memory)
|
||||
}
|
||||
if flavor.Id.ValueString() == "" {
|
||||
return fmt.Errorf("couldn't find flavor, available specs are: %s", avl)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,11 +3,7 @@ package postgresflexalpha
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
|
||||
postgresflex "github.com/mhenselin/terraform-provider-stackitprivatepreview/pkg/postgresflexalpha"
|
||||
"github.com/stackitcloud/stackit-sdk-go/core/utils"
|
||||
)
|
||||
|
|
@ -490,327 +486,303 @@ func (c postgresFlexClientMocked) GetFlavorsRequestExecute(
|
|||
return &res, nil
|
||||
}
|
||||
|
||||
func Test_getAllFlavors(t *testing.T) {
|
||||
type args struct {
|
||||
projectId string
|
||||
region string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
firstItem int
|
||||
lastItem int
|
||||
want []postgresflex.ListFlavors
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "find exactly one flavor",
|
||||
args: args{
|
||||
projectId: "project",
|
||||
region: "region",
|
||||
},
|
||||
firstItem: 0,
|
||||
lastItem: 0,
|
||||
want: []postgresflex.ListFlavors{
|
||||
testFlavorToResponseFlavor(responseList[0]),
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "get exactly 1 page flavors",
|
||||
args: args{
|
||||
projectId: "project",
|
||||
region: "region",
|
||||
},
|
||||
firstItem: 0,
|
||||
lastItem: 9,
|
||||
want: testFlavorListToResponseFlavorList(responseList[0:10]),
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "get exactly 20 flavors",
|
||||
args: args{
|
||||
projectId: "project",
|
||||
region: "region",
|
||||
},
|
||||
firstItem: 0,
|
||||
lastItem: 20,
|
||||
// 0 indexed therefore we want :21
|
||||
want: testFlavorListToResponseFlavorList(responseList[0:21]),
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "get all flavors",
|
||||
args: args{
|
||||
projectId: "project",
|
||||
region: "region",
|
||||
},
|
||||
firstItem: 0,
|
||||
lastItem: len(responseList),
|
||||
want: testFlavorListToResponseFlavorList(responseList),
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
first := tt.firstItem
|
||||
if first > len(responseList)-1 {
|
||||
first = len(responseList) - 1
|
||||
}
|
||||
last := tt.lastItem
|
||||
if last > len(responseList)-1 {
|
||||
last = len(responseList) - 1
|
||||
}
|
||||
mockClient := postgresFlexClientMocked{
|
||||
returnError: tt.wantErr,
|
||||
firstItem: first,
|
||||
lastItem: last,
|
||||
}
|
||||
got, err := getAllFlavors(context.TODO(), mockClient, tt.args.projectId, tt.args.region)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("getAllFlavors() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
//func Test_getAllFlavors(t *testing.T) {
|
||||
// type args struct {
|
||||
// projectId string
|
||||
// region string
|
||||
// }
|
||||
// tests := []struct {
|
||||
// name string
|
||||
// args args
|
||||
// firstItem int
|
||||
// lastItem int
|
||||
// want []postgresflex.ListFlavors
|
||||
// wantErr bool
|
||||
// }{
|
||||
// {
|
||||
// name: "find exactly one flavor",
|
||||
// args: args{
|
||||
// projectId: "project",
|
||||
// region: "region",
|
||||
// },
|
||||
// firstItem: 0,
|
||||
// lastItem: 0,
|
||||
// want: []postgresflex.ListFlavors{
|
||||
// testFlavorToResponseFlavor(responseList[0]),
|
||||
// },
|
||||
// wantErr: false,
|
||||
// },
|
||||
// {
|
||||
// name: "get exactly 1 page flavors",
|
||||
// args: args{
|
||||
// projectId: "project",
|
||||
// region: "region",
|
||||
// },
|
||||
// firstItem: 0,
|
||||
// lastItem: 9,
|
||||
// want: testFlavorListToResponseFlavorList(responseList[0:10]),
|
||||
// wantErr: false,
|
||||
// },
|
||||
// {
|
||||
// name: "get exactly 20 flavors",
|
||||
// args: args{
|
||||
// projectId: "project",
|
||||
// region: "region",
|
||||
// },
|
||||
// firstItem: 0,
|
||||
// lastItem: 20,
|
||||
// // 0 indexed therefore we want :21
|
||||
// want: testFlavorListToResponseFlavorList(responseList[0:21]),
|
||||
// wantErr: false,
|
||||
// },
|
||||
// {
|
||||
// name: "get all flavors",
|
||||
// args: args{
|
||||
// projectId: "project",
|
||||
// region: "region",
|
||||
// },
|
||||
// firstItem: 0,
|
||||
// lastItem: len(responseList),
|
||||
// want: testFlavorListToResponseFlavorList(responseList),
|
||||
// wantErr: false,
|
||||
// },
|
||||
// }
|
||||
// for _, tt := range tests {
|
||||
// t.Run(tt.name, func(t *testing.T) {
|
||||
// first := tt.firstItem
|
||||
// if first > len(responseList)-1 {
|
||||
// first = len(responseList) - 1
|
||||
// }
|
||||
// last := tt.lastItem
|
||||
// if last > len(responseList)-1 {
|
||||
// last = len(responseList) - 1
|
||||
// }
|
||||
// mockClient := postgresFlexClientMocked{
|
||||
// returnError: tt.wantErr,
|
||||
// firstItem: first,
|
||||
// lastItem: last,
|
||||
// }
|
||||
// got, err := getAllFlavors(context.TODO(), mockClient, tt.args.projectId, tt.args.region)
|
||||
// if (err != nil) != tt.wantErr {
|
||||
// t.Errorf("getAllFlavors() error = %v, wantErr %v", err, tt.wantErr)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// if diff := cmp.Diff(tt.want, got); diff != "" {
|
||||
// t.Errorf("mismatch (-want +got):\n%s", diff)
|
||||
// }
|
||||
//
|
||||
// if !reflect.DeepEqual(got, tt.want) {
|
||||
// t.Errorf("getAllFlavors() got = %v, want %v", got, tt.want)
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
//}
|
||||
|
||||
if diff := cmp.Diff(tt.want, got); diff != "" {
|
||||
t.Errorf("mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("getAllFlavors() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_loadFlavorId(t *testing.T) {
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
model *Model
|
||||
flavor *flavorModel
|
||||
storage *storageModel
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
firstItem int
|
||||
lastItem int
|
||||
want []postgresflex.ListFlavors
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "find a single flavor",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
model: &Model{
|
||||
ProjectId: basetypes.NewStringValue("project"),
|
||||
Region: basetypes.NewStringValue("region"),
|
||||
},
|
||||
flavor: &flavorModel{
|
||||
CPU: basetypes.NewInt64Value(1),
|
||||
RAM: basetypes.NewInt64Value(1),
|
||||
NodeType: basetypes.NewStringValue("Single"),
|
||||
},
|
||||
storage: &storageModel{
|
||||
Class: basetypes.NewStringValue("sc1"),
|
||||
Size: basetypes.NewInt64Value(100),
|
||||
},
|
||||
},
|
||||
firstItem: 0,
|
||||
lastItem: 3,
|
||||
want: []postgresflex.ListFlavors{
|
||||
testFlavorToResponseFlavor(responseList[0]),
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "find a single flavor by replicas option",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
model: &Model{
|
||||
ProjectId: basetypes.NewStringValue("project"),
|
||||
Region: basetypes.NewStringValue("region"),
|
||||
Replicas: basetypes.NewInt64Value(1),
|
||||
},
|
||||
flavor: &flavorModel{
|
||||
CPU: basetypes.NewInt64Value(1),
|
||||
RAM: basetypes.NewInt64Value(1),
|
||||
},
|
||||
storage: &storageModel{
|
||||
Class: basetypes.NewStringValue("sc1"),
|
||||
Size: basetypes.NewInt64Value(100),
|
||||
},
|
||||
},
|
||||
firstItem: 0,
|
||||
lastItem: 3,
|
||||
want: []postgresflex.ListFlavors{
|
||||
testFlavorToResponseFlavor(responseList[0]),
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "fail finding find a single flavor by replicas option",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
model: &Model{
|
||||
ProjectId: basetypes.NewStringValue("project"),
|
||||
Region: basetypes.NewStringValue("region"),
|
||||
Replicas: basetypes.NewInt64Value(1),
|
||||
},
|
||||
flavor: &flavorModel{
|
||||
CPU: basetypes.NewInt64Value(1),
|
||||
RAM: basetypes.NewInt64Value(1),
|
||||
},
|
||||
storage: &storageModel{
|
||||
Class: basetypes.NewStringValue("sc1"),
|
||||
Size: basetypes.NewInt64Value(100),
|
||||
},
|
||||
},
|
||||
firstItem: 13,
|
||||
lastItem: 23,
|
||||
want: []postgresflex.ListFlavors{},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "find a replicas flavor lower case",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
model: &Model{
|
||||
ProjectId: basetypes.NewStringValue("project"),
|
||||
Region: basetypes.NewStringValue("region"),
|
||||
},
|
||||
flavor: &flavorModel{
|
||||
CPU: basetypes.NewInt64Value(1),
|
||||
RAM: basetypes.NewInt64Value(1),
|
||||
NodeType: basetypes.NewStringValue("replica"),
|
||||
},
|
||||
storage: &storageModel{
|
||||
Class: basetypes.NewStringValue("sc1"),
|
||||
Size: basetypes.NewInt64Value(100),
|
||||
},
|
||||
},
|
||||
firstItem: 0,
|
||||
lastItem: len(responseList) - 1,
|
||||
want: []postgresflex.ListFlavors{
|
||||
testFlavorToResponseFlavor(responseList[16]),
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "find a replicas flavor CamelCase",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
model: &Model{
|
||||
ProjectId: basetypes.NewStringValue("project"),
|
||||
Region: basetypes.NewStringValue("region"),
|
||||
},
|
||||
flavor: &flavorModel{
|
||||
CPU: basetypes.NewInt64Value(1),
|
||||
RAM: basetypes.NewInt64Value(1),
|
||||
NodeType: basetypes.NewStringValue("Replica"),
|
||||
},
|
||||
storage: &storageModel{
|
||||
Class: basetypes.NewStringValue("sc1"),
|
||||
Size: basetypes.NewInt64Value(100),
|
||||
},
|
||||
},
|
||||
firstItem: 0,
|
||||
lastItem: len(responseList) - 1,
|
||||
want: []postgresflex.ListFlavors{
|
||||
testFlavorToResponseFlavor(responseList[16]),
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "find a replicas flavor by replicas option",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
model: &Model{
|
||||
ProjectId: basetypes.NewStringValue("project"),
|
||||
Region: basetypes.NewStringValue("region"),
|
||||
Replicas: basetypes.NewInt64Value(3),
|
||||
},
|
||||
flavor: &flavorModel{
|
||||
CPU: basetypes.NewInt64Value(1),
|
||||
RAM: basetypes.NewInt64Value(1),
|
||||
},
|
||||
storage: &storageModel{
|
||||
Class: basetypes.NewStringValue("sc1"),
|
||||
Size: basetypes.NewInt64Value(100),
|
||||
},
|
||||
},
|
||||
firstItem: 0,
|
||||
lastItem: len(responseList) - 1,
|
||||
want: []postgresflex.ListFlavors{
|
||||
testFlavorToResponseFlavor(responseList[16]),
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "fail finding a replica flavor",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
model: &Model{
|
||||
ProjectId: basetypes.NewStringValue("project"),
|
||||
Region: basetypes.NewStringValue("region"),
|
||||
Replicas: basetypes.NewInt64Value(3),
|
||||
},
|
||||
flavor: &flavorModel{
|
||||
CPU: basetypes.NewInt64Value(1),
|
||||
RAM: basetypes.NewInt64Value(1),
|
||||
},
|
||||
storage: &storageModel{
|
||||
Class: basetypes.NewStringValue("sc1"),
|
||||
Size: basetypes.NewInt64Value(100),
|
||||
},
|
||||
},
|
||||
firstItem: 0,
|
||||
lastItem: 10,
|
||||
want: []postgresflex.ListFlavors{},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "no flavor found error",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
model: &Model{
|
||||
ProjectId: basetypes.NewStringValue("project"),
|
||||
Region: basetypes.NewStringValue("region"),
|
||||
},
|
||||
flavor: &flavorModel{
|
||||
CPU: basetypes.NewInt64Value(10),
|
||||
RAM: basetypes.NewInt64Value(1000),
|
||||
NodeType: basetypes.NewStringValue("Single"),
|
||||
},
|
||||
storage: &storageModel{
|
||||
Class: basetypes.NewStringValue("sc1"),
|
||||
Size: basetypes.NewInt64Value(100),
|
||||
},
|
||||
},
|
||||
firstItem: 0,
|
||||
lastItem: 3,
|
||||
want: []postgresflex.ListFlavors{},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
first := tt.firstItem
|
||||
if first > len(responseList)-1 {
|
||||
first = len(responseList) - 1
|
||||
}
|
||||
last := tt.lastItem
|
||||
if last > len(responseList)-1 {
|
||||
last = len(responseList) - 1
|
||||
}
|
||||
mockClient := postgresFlexClientMocked{
|
||||
returnError: tt.wantErr,
|
||||
firstItem: first,
|
||||
lastItem: last,
|
||||
}
|
||||
if err := loadFlavorId(tt.args.ctx, mockClient, tt.args.model, tt.args.flavor, tt.args.storage); (err != nil) != tt.wantErr {
|
||||
t.Errorf("loadFlavorId() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
//func Test_loadFlavorId(t *testing.T) {
|
||||
// type args struct {
|
||||
// ctx context.Context
|
||||
// model *Model
|
||||
// storage *storageModel
|
||||
// }
|
||||
// tests := []struct {
|
||||
// name string
|
||||
// args args
|
||||
// firstItem int
|
||||
// lastItem int
|
||||
// want []postgresflex.ListFlavors
|
||||
// wantErr bool
|
||||
// }{
|
||||
// {
|
||||
// name: "find a single flavor",
|
||||
// args: args{
|
||||
// ctx: context.Background(),
|
||||
// model: &Model{
|
||||
// ProjectId: basetypes.NewStringValue("project"),
|
||||
// Region: basetypes.NewStringValue("region"),
|
||||
// },
|
||||
// storage: &storageModel{
|
||||
// Class: basetypes.NewStringValue("sc1"),
|
||||
// Size: basetypes.NewInt64Value(100),
|
||||
// },
|
||||
// },
|
||||
// firstItem: 0,
|
||||
// lastItem: 3,
|
||||
// want: []postgresflex.ListFlavors{
|
||||
// testFlavorToResponseFlavor(responseList[0]),
|
||||
// },
|
||||
// wantErr: false,
|
||||
// },
|
||||
// {
|
||||
// name: "find a single flavor by replicas option",
|
||||
// args: args{
|
||||
// ctx: context.Background(),
|
||||
// model: &Model{
|
||||
// ProjectId: basetypes.NewStringValue("project"),
|
||||
// Region: basetypes.NewStringValue("region"),
|
||||
// Replicas: basetypes.NewInt64Value(1),
|
||||
// },
|
||||
// storage: &storageModel{
|
||||
// Class: basetypes.NewStringValue("sc1"),
|
||||
// Size: basetypes.NewInt64Value(100),
|
||||
// },
|
||||
// },
|
||||
// firstItem: 0,
|
||||
// lastItem: 3,
|
||||
// want: []postgresflex.ListFlavors{
|
||||
// testFlavorToResponseFlavor(responseList[0]),
|
||||
// },
|
||||
// wantErr: false,
|
||||
// },
|
||||
// {
|
||||
// name: "fail finding find a single flavor by replicas option",
|
||||
// args: args{
|
||||
// ctx: context.Background(),
|
||||
// model: &Model{
|
||||
// ProjectId: basetypes.NewStringValue("project"),
|
||||
// Region: basetypes.NewStringValue("region"),
|
||||
// Replicas: basetypes.NewInt64Value(1),
|
||||
// },
|
||||
// storage: &storageModel{
|
||||
// Class: basetypes.NewStringValue("sc1"),
|
||||
// Size: basetypes.NewInt64Value(100),
|
||||
// },
|
||||
// },
|
||||
// firstItem: 13,
|
||||
// lastItem: 23,
|
||||
// want: []postgresflex.ListFlavors{},
|
||||
// wantErr: true,
|
||||
// },
|
||||
// {
|
||||
// name: "find a replicas flavor lower case",
|
||||
// args: args{
|
||||
// ctx: context.Background(),
|
||||
// model: &Model{
|
||||
// ProjectId: basetypes.NewStringValue("project"),
|
||||
// Region: basetypes.NewStringValue("region"),
|
||||
// },
|
||||
// storage: &storageModel{
|
||||
// Class: basetypes.NewStringValue("sc1"),
|
||||
// Size: basetypes.NewInt64Value(100),
|
||||
// },
|
||||
// },
|
||||
// firstItem: 0,
|
||||
// lastItem: len(responseList) - 1,
|
||||
// want: []postgresflex.ListFlavors{
|
||||
// testFlavorToResponseFlavor(responseList[16]),
|
||||
// },
|
||||
// wantErr: false,
|
||||
// },
|
||||
// {
|
||||
// name: "find a replicas flavor CamelCase",
|
||||
// args: args{
|
||||
// ctx: context.Background(),
|
||||
// model: &Model{
|
||||
// ProjectId: basetypes.NewStringValue("project"),
|
||||
// Region: basetypes.NewStringValue("region"),
|
||||
// },
|
||||
// storage: &storageModel{
|
||||
// Class: basetypes.NewStringValue("sc1"),
|
||||
// Size: basetypes.NewInt64Value(100),
|
||||
// },
|
||||
// },
|
||||
// firstItem: 0,
|
||||
// lastItem: len(responseList) - 1,
|
||||
// want: []postgresflex.ListFlavors{
|
||||
// testFlavorToResponseFlavor(responseList[16]),
|
||||
// },
|
||||
// wantErr: false,
|
||||
// },
|
||||
// {
|
||||
// name: "find a replicas flavor by replicas option",
|
||||
// args: args{
|
||||
// ctx: context.Background(),
|
||||
// model: &Model{
|
||||
// ProjectId: basetypes.NewStringValue("project"),
|
||||
// Region: basetypes.NewStringValue("region"),
|
||||
// Replicas: basetypes.NewInt64Value(3),
|
||||
// },
|
||||
// flavor: &flavorModel{
|
||||
// CPU: basetypes.NewInt64Value(1),
|
||||
// RAM: basetypes.NewInt64Value(1),
|
||||
// },
|
||||
// storage: &storageModel{
|
||||
// Class: basetypes.NewStringValue("sc1"),
|
||||
// Size: basetypes.NewInt64Value(100),
|
||||
// },
|
||||
// },
|
||||
// firstItem: 0,
|
||||
// lastItem: len(responseList) - 1,
|
||||
// want: []postgresflex.ListFlavors{
|
||||
// testFlavorToResponseFlavor(responseList[16]),
|
||||
// },
|
||||
// wantErr: false,
|
||||
// },
|
||||
// {
|
||||
// name: "fail finding a replica flavor",
|
||||
// args: args{
|
||||
// ctx: context.Background(),
|
||||
// model: &Model{
|
||||
// ProjectId: basetypes.NewStringValue("project"),
|
||||
// Region: basetypes.NewStringValue("region"),
|
||||
// Replicas: basetypes.NewInt64Value(3),
|
||||
// },
|
||||
// flavor: &flavorModel{
|
||||
// CPU: basetypes.NewInt64Value(1),
|
||||
// RAM: basetypes.NewInt64Value(1),
|
||||
// },
|
||||
// storage: &storageModel{
|
||||
// Class: basetypes.NewStringValue("sc1"),
|
||||
// Size: basetypes.NewInt64Value(100),
|
||||
// },
|
||||
// },
|
||||
// firstItem: 0,
|
||||
// lastItem: 10,
|
||||
// want: []postgresflex.ListFlavors{},
|
||||
// wantErr: true,
|
||||
// },
|
||||
// {
|
||||
// name: "no flavor found error",
|
||||
// args: args{
|
||||
// ctx: context.Background(),
|
||||
// model: &Model{
|
||||
// ProjectId: basetypes.NewStringValue("project"),
|
||||
// Region: basetypes.NewStringValue("region"),
|
||||
// },
|
||||
// flavor: &flavorModel{
|
||||
// CPU: basetypes.NewInt64Value(10),
|
||||
// RAM: basetypes.NewInt64Value(1000),
|
||||
// NodeType: basetypes.NewStringValue("Single"),
|
||||
// },
|
||||
// storage: &storageModel{
|
||||
// Class: basetypes.NewStringValue("sc1"),
|
||||
// Size: basetypes.NewInt64Value(100),
|
||||
// },
|
||||
// },
|
||||
// firstItem: 0,
|
||||
// lastItem: 3,
|
||||
// want: []postgresflex.ListFlavors{},
|
||||
// wantErr: true,
|
||||
// },
|
||||
// }
|
||||
// for _, tt := range tests {
|
||||
// t.Run(tt.name, func(t *testing.T) {
|
||||
// first := tt.firstItem
|
||||
// if first > len(responseList)-1 {
|
||||
// first = len(responseList) - 1
|
||||
// }
|
||||
// last := tt.lastItem
|
||||
// if last > len(responseList)-1 {
|
||||
// last = len(responseList) - 1
|
||||
// }
|
||||
// mockClient := postgresFlexClientMocked{
|
||||
// returnError: tt.wantErr,
|
||||
// firstItem: first,
|
||||
// lastItem: last,
|
||||
// }
|
||||
// if err := loadFlavorId(tt.args.ctx, mockClient, tt.args.model, tt.args.flavor, tt.args.storage); (err != nil) != tt.wantErr {
|
||||
// t.Errorf("loadFlavorId() error = %v, wantErr %v", err, tt.wantErr)
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
//}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ type Model struct {
|
|||
ProjectId types.String `tfsdk:"project_id"`
|
||||
Name types.String `tfsdk:"name"`
|
||||
BackupSchedule types.String `tfsdk:"backup_schedule"`
|
||||
Flavor types.Object `tfsdk:"flavor"`
|
||||
FlavorId types.String `tfsdk:"flavor_id"`
|
||||
Replicas types.Int64 `tfsdk:"replicas"`
|
||||
RetentionDays types.Int64 `tfsdk:"retention_days"`
|
||||
Storage types.Object `tfsdk:"storage"`
|
||||
|
|
@ -22,9 +22,11 @@ type Model struct {
|
|||
Network types.Object `tfsdk:"network"`
|
||||
}
|
||||
|
||||
type IdentityModel struct {
|
||||
ID types.String `tfsdk:"id"`
|
||||
}
|
||||
//type IdentityModel struct {
|
||||
// InstanceId types.String `tfsdk:"instance_id"`
|
||||
// Region types.String `tfsdk:"region"`
|
||||
// ProjectId types.String `tfsdk:"project_id"`
|
||||
//}
|
||||
|
||||
type encryptionModel struct {
|
||||
KeyRingId types.String `tfsdk:"keyring_id"`
|
||||
|
|
@ -54,24 +56,6 @@ var networkTypes = map[string]attr.Type{
|
|||
"router_address": basetypes.StringType{},
|
||||
}
|
||||
|
||||
// Struct corresponding to Model.Flavor
|
||||
type flavorModel struct {
|
||||
Id types.String `tfsdk:"id"`
|
||||
Description types.String `tfsdk:"description"`
|
||||
CPU types.Int64 `tfsdk:"cpu"`
|
||||
RAM types.Int64 `tfsdk:"ram"`
|
||||
NodeType types.String `tfsdk:"node_type"`
|
||||
}
|
||||
|
||||
// Types corresponding to flavorModel
|
||||
var flavorTypes = map[string]attr.Type{
|
||||
"id": basetypes.StringType{},
|
||||
"description": basetypes.StringType{},
|
||||
"cpu": basetypes.Int64Type{},
|
||||
"ram": basetypes.Int64Type{},
|
||||
"node_type": basetypes.StringType{},
|
||||
}
|
||||
|
||||
// Struct corresponding to Model.Storage
|
||||
type storageModel struct {
|
||||
Class types.String `tfsdk:"class"`
|
||||
|
|
|
|||
|
|
@ -6,16 +6,13 @@ import (
|
|||
"net/http"
|
||||
"regexp"
|
||||
"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"
|
||||
postgresflexUtils "github.com/mhenselin/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/utils"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
|
||||
"github.com/hashicorp/terraform-plugin-framework/attr"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
|
||||
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
|
||||
|
|
@ -42,7 +39,7 @@ var (
|
|||
_ resource.ResourceWithImportState = &instanceResource{}
|
||||
_ resource.ResourceWithModifyPlan = &instanceResource{}
|
||||
_ resource.ResourceWithValidateConfig = &instanceResource{}
|
||||
_ resource.ResourceWithIdentity = &instanceResource{}
|
||||
//_ resource.ResourceWithIdentity = &instanceResource{}
|
||||
)
|
||||
|
||||
// NewInstanceResource is a helper function to simplify the provider implementation.
|
||||
|
|
@ -128,35 +125,30 @@ func (r *instanceResource) Configure(ctx context.Context, req resource.Configure
|
|||
// Schema defines the schema for the resource.
|
||||
func (r *instanceResource) Schema(_ context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
|
||||
descriptions := map[string]string{
|
||||
"main": "Postgres Flex instance resource schema. Must have a `region` specified in the provider configuration.",
|
||||
"id": "Terraform's internal resource ID. It is structured as \"`project_id`,`region`,`instance_id`\".",
|
||||
"instance_id": "ID of the PostgresFlex instance.",
|
||||
"project_id": "STACKIT project ID to which the instance is associated.",
|
||||
"name": "Instance name.",
|
||||
"backup_schedule": "The schedule for on what time and how often the database backup will be created. The schedule is written as a cron schedule.",
|
||||
"retention_days": "The days of the retention period.",
|
||||
"flavor": "The block that defines the flavor data.",
|
||||
"flavor_id": "The ID of the flavor.",
|
||||
"flavor_description": "The flavor detailed flavor name.",
|
||||
"flavor_cpu": "The CPU count of the flavor.",
|
||||
"flavor_ram": "The RAM count of the flavor.",
|
||||
"flavor_node_type": "The node type of the flavor. (Single or Replicas)",
|
||||
"replicas": "The number of replicas.",
|
||||
"storage": "The block of the storage configuration.",
|
||||
"storage_class": "The storage class used.",
|
||||
"storage_size": "The disk size of the storage.",
|
||||
"region": "The resource region. If not defined, the provider region is used.",
|
||||
"version": "The database version used.",
|
||||
"encryption": "The encryption block.",
|
||||
"keyring_id": "KeyRing ID of the encryption key.",
|
||||
"key_id": "Key ID of the encryption key.",
|
||||
"key_version": "Key version of the encryption key.",
|
||||
"service_account": "The service account ID of the service account.",
|
||||
"network": "The network block configuration.",
|
||||
"access_scope": "The access scope. (Either SNA or PUBLIC)",
|
||||
"acl": "The Access Control List (ACL) for the PostgresFlex instance.",
|
||||
"instance_address": "The returned instance address.",
|
||||
"router_address": "The returned router address.",
|
||||
"main": "Postgres Flex instance resource schema. Must have a `region` specified in the provider configuration.",
|
||||
"id": "Terraform's internal resource ID. It is structured as \"`project_id`,`region`,`instance_id`\".",
|
||||
"instance_id": "ID of the PostgresFlex instance.",
|
||||
"project_id": "STACKIT project ID to which the instance is associated.",
|
||||
"name": "Instance name.",
|
||||
"backup_schedule": "The schedule for on what time and how often the database backup will be created. The schedule is written as a cron schedule.",
|
||||
"retention_days": "The days of the retention period.",
|
||||
"flavor_id": "The ID of the flavor.",
|
||||
"replicas": "The number of replicas.",
|
||||
"storage": "The block of the storage configuration.",
|
||||
"storage_class": "The storage class used.",
|
||||
"storage_size": "The disk size of the storage.",
|
||||
"region": "The resource region. If not defined, the provider region is used.",
|
||||
"version": "The database version used.",
|
||||
"encryption": "The encryption block.",
|
||||
"keyring_id": "KeyRing ID of the encryption key.",
|
||||
"key_id": "Key ID of the encryption key.",
|
||||
"key_version": "Key version of the encryption key.",
|
||||
"service_account": "The service account ID of the service account.",
|
||||
"network": "The network block configuration.",
|
||||
"access_scope": "The access scope. (Either SNA or PUBLIC)",
|
||||
"acl": "The Access Control List (ACL) for the PostgresFlex instance.",
|
||||
"instance_address": "The returned instance address.",
|
||||
"router_address": "The returned router address.",
|
||||
}
|
||||
|
||||
resp.Schema = schema.Schema{
|
||||
|
|
@ -210,45 +202,8 @@ func (r *instanceResource) Schema(_ context.Context, req resource.SchemaRequest,
|
|||
Description: descriptions["retention_days"],
|
||||
Required: true,
|
||||
},
|
||||
"flavor": schema.SingleNestedAttribute{
|
||||
Required: true,
|
||||
Description: descriptions["flavor"],
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"id": schema.StringAttribute{
|
||||
Description: descriptions["flavor_id"],
|
||||
Computed: true,
|
||||
Optional: true,
|
||||
PlanModifiers: []planmodifier.String{
|
||||
UseStateForUnknownIfFlavorUnchanged(req),
|
||||
stringplanmodifier.RequiresReplace(),
|
||||
},
|
||||
},
|
||||
"description": schema.StringAttribute{
|
||||
Computed: true,
|
||||
Description: descriptions["flavor_description"],
|
||||
PlanModifiers: []planmodifier.String{
|
||||
UseStateForUnknownIfFlavorUnchanged(req),
|
||||
},
|
||||
},
|
||||
"cpu": schema.Int64Attribute{
|
||||
Description: descriptions["flavor_cpu"],
|
||||
Required: true,
|
||||
},
|
||||
"ram": schema.Int64Attribute{
|
||||
Description: descriptions["flavor_ram"],
|
||||
Required: true,
|
||||
},
|
||||
"node_type": schema.StringAttribute{
|
||||
Description: descriptions["flavor_node_type"],
|
||||
Computed: true,
|
||||
Optional: true,
|
||||
PlanModifiers: []planmodifier.String{
|
||||
// TODO @mhenselin anschauen
|
||||
UseStateForUnknownIfFlavorUnchanged(req),
|
||||
stringplanmodifier.RequiresReplace(),
|
||||
},
|
||||
},
|
||||
},
|
||||
"flavor_id": schema.StringAttribute{
|
||||
Required: true,
|
||||
},
|
||||
"replicas": schema.Int64Attribute{
|
||||
Required: true,
|
||||
|
|
@ -390,15 +345,21 @@ 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
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
//func (r *instanceResource) IdentitySchema(_ context.Context, _ resource.IdentitySchemaRequest, resp *resource.IdentitySchemaResponse) {
|
||||
// resp.IdentitySchema = identityschema.Schema{
|
||||
// Attributes: map[string]identityschema.Attribute{
|
||||
// "project_id": identityschema.StringAttribute{
|
||||
// RequiredForImport: true, // must be set during import by the practitioner
|
||||
// },
|
||||
// "region": identityschema.StringAttribute{
|
||||
// RequiredForImport: true, // must be set during import by the practitioner
|
||||
// },
|
||||
// "instance_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(
|
||||
|
|
@ -406,7 +367,6 @@ func (r *instanceResource) Create(
|
|||
req resource.CreateRequest,
|
||||
resp *resource.CreateResponse,
|
||||
) { // nolint:gocritic // function signature required by Terraform
|
||||
// Retrieve values from plan
|
||||
var model Model
|
||||
diags := req.Plan.Get(ctx, &model)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
|
|
@ -430,42 +390,6 @@ func (r *instanceResource) Create(
|
|||
}
|
||||
}
|
||||
|
||||
var flavor = &flavorModel{}
|
||||
if !model.Flavor.IsNull() && !model.Flavor.IsUnknown() {
|
||||
diags = model.Flavor.As(ctx, flavor, basetypes.ObjectAsOptions{})
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
err := loadFlavorId(ctx, r.client, &model, flavor, storage)
|
||||
if err != nil {
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Loading flavor ID: %v", err))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if flavor.Id.IsNull() || flavor.Id.IsUnknown() {
|
||||
err := loadFlavorId(ctx, r.client, &model, flavor, storage)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError(err.Error(), err.Error())
|
||||
return
|
||||
}
|
||||
flavorValues := map[string]attr.Value{
|
||||
"id": flavor.Id,
|
||||
"description": flavor.Description,
|
||||
"cpu": flavor.CPU,
|
||||
"ram": flavor.RAM,
|
||||
"node_type": flavor.NodeType,
|
||||
}
|
||||
var flavorObject basetypes.ObjectValue
|
||||
flavorObject, diags = types.ObjectValue(flavorTypes, flavorValues)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if diags.HasError() {
|
||||
return
|
||||
}
|
||||
model.Flavor = flavorObject
|
||||
}
|
||||
|
||||
var encryption = &encryptionModel{}
|
||||
if !model.Encryption.IsNull() && !model.Encryption.IsUnknown() {
|
||||
diags = model.Encryption.As(ctx, encryption, basetypes.ObjectAsOptions{})
|
||||
|
|
@ -494,7 +418,7 @@ func (r *instanceResource) Create(
|
|||
}
|
||||
|
||||
// Generate API request body from model
|
||||
payload, err := toCreatePayload(&model, flavor, storage, encryption, network)
|
||||
payload, err := toCreatePayload(&model, storage, encryption, network)
|
||||
if err != nil {
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Creating API payload: %v", err))
|
||||
return
|
||||
|
|
@ -516,11 +440,13 @@ func (r *instanceResource) Create(
|
|||
return
|
||||
}
|
||||
|
||||
// Set data returned by API in identity
|
||||
identity := IdentityModel{
|
||||
ID: utils.BuildInternalTerraformId(projectId, region, instanceId),
|
||||
}
|
||||
resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...)
|
||||
//// Set data returned by API in identity
|
||||
//identity := IdentityModel{
|
||||
// InstanceId: types.StringValue(instanceId),
|
||||
// Region: types.StringValue(region),
|
||||
// ProjectId: types.StringValue(projectId),
|
||||
//}
|
||||
//resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...)
|
||||
|
||||
waitResp, err := wait.CreateInstanceWaitHandler(ctx, r.client, projectId, region, instanceId).WaitWithContext(ctx)
|
||||
if err != nil {
|
||||
|
|
@ -529,7 +455,7 @@ func (r *instanceResource) Create(
|
|||
}
|
||||
|
||||
// Map response body to schema
|
||||
err = mapFields(ctx, waitResp, &model, flavor, storage, encryption, network, region)
|
||||
err = mapFields(ctx, r.client, waitResp, &model, storage, encryption, network, region)
|
||||
if err != nil {
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Processing API payload: %v", err))
|
||||
return
|
||||
|
|
@ -552,12 +478,12 @@ 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
|
||||
}
|
||||
//// Read identity data
|
||||
//var identityData IdentityModel
|
||||
//resp.Diagnostics.Append(req.Identity.Get(ctx, &identityData)...)
|
||||
//if resp.Diagnostics.HasError() {
|
||||
// return
|
||||
//}
|
||||
|
||||
ctx = core.InitProviderContext(ctx)
|
||||
|
||||
|
|
@ -568,35 +494,27 @@ func (r *instanceResource) Read(ctx context.Context, req resource.ReadRequest, r
|
|||
ctx = tflog.SetField(ctx, "instance_id", instanceId)
|
||||
ctx = tflog.SetField(ctx, "region", region)
|
||||
|
||||
var flavor = &flavorModel{}
|
||||
if !model.Flavor.IsNull() && !model.Flavor.IsUnknown() {
|
||||
diags = model.Flavor.As(ctx, flavor, basetypes.ObjectAsOptions{})
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
}
|
||||
var storage = &storageModel{}
|
||||
var storage = storageModel{}
|
||||
if !model.Storage.IsNull() && !model.Storage.IsUnknown() {
|
||||
diags = model.Storage.As(ctx, storage, basetypes.ObjectAsOptions{})
|
||||
diags = model.Storage.As(ctx, &storage, basetypes.ObjectAsOptions{})
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var network = &networkModel{}
|
||||
var network = networkModel{}
|
||||
if !model.Network.IsNull() && !model.Network.IsUnknown() {
|
||||
diags = model.Network.As(ctx, network, basetypes.ObjectAsOptions{})
|
||||
diags = model.Network.As(ctx, &network, basetypes.ObjectAsOptions{})
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var encryption = &encryptionModel{}
|
||||
var encryption = encryptionModel{}
|
||||
if !model.Encryption.IsNull() && !model.Encryption.IsUnknown() {
|
||||
diags = model.Encryption.As(ctx, encryption, basetypes.ObjectAsOptions{})
|
||||
diags = model.Encryption.As(ctx, &encryption, basetypes.ObjectAsOptions{})
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
|
|
@ -617,7 +535,7 @@ func (r *instanceResource) Read(ctx context.Context, req resource.ReadRequest, r
|
|||
ctx = core.LogResponse(ctx)
|
||||
|
||||
// Map response body to schema
|
||||
err = mapFields(ctx, instanceResp, &model, flavor, storage, encryption, network, region)
|
||||
err = mapFields(ctx, r.client, instanceResp, &model, &storage, &encryption, &network, region)
|
||||
if err != nil {
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Processing API payload: %v", err))
|
||||
return
|
||||
|
|
@ -629,18 +547,19 @@ func (r *instanceResource) Read(ctx context.Context, req resource.ReadRequest, r
|
|||
return
|
||||
}
|
||||
|
||||
identityData.ID = model.Id
|
||||
resp.Diagnostics.Append(resp.Identity.Set(ctx, identityData)...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
//identityData.InstanceId = model.InstanceId
|
||||
//identityData.Region = model.Region
|
||||
//identityData.ProjectId = model.ProjectId
|
||||
//resp.Diagnostics.Append(resp.Identity.Set(ctx, identityData)...)
|
||||
//if resp.Diagnostics.HasError() {
|
||||
// return
|
||||
//}
|
||||
|
||||
tflog.Info(ctx, "Postgres Flex instance read")
|
||||
}
|
||||
|
||||
// Update updates the resource and sets the updated Terraform state on success.
|
||||
func (r *instanceResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform
|
||||
// Retrieve values from plan
|
||||
var model Model
|
||||
diags := req.Plan.Get(ctx, &model)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
|
|
@ -676,20 +595,6 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques
|
|||
}
|
||||
}
|
||||
|
||||
var flavor = &flavorModel{}
|
||||
if !model.Flavor.IsNull() && !model.Flavor.IsUnknown() {
|
||||
diags = model.Flavor.As(ctx, flavor, basetypes.ObjectAsOptions{})
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
err := loadFlavorId(ctx, r.client, &model, flavor, storage)
|
||||
if err != nil {
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Loading flavor ID: %v", err))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var network = &networkModel{}
|
||||
if !model.Network.IsNull() && !model.Network.IsUnknown() {
|
||||
diags = model.Network.As(ctx, network, basetypes.ObjectAsOptions{})
|
||||
|
|
@ -709,7 +614,7 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques
|
|||
}
|
||||
|
||||
// Generate API request body from model
|
||||
payload, err := toUpdatePayload(&model, flavor, storage, network)
|
||||
payload, err := toUpdatePayload(&model, storage, network)
|
||||
if err != nil {
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Creating API payload: %v", err))
|
||||
return
|
||||
|
|
@ -730,7 +635,7 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques
|
|||
}
|
||||
|
||||
// Map response body to schema
|
||||
err = mapFields(ctx, waitResp, &model, flavor, storage, encryption, network, region)
|
||||
err = mapFields(ctx, r.client, waitResp, &model, storage, encryption, network, region)
|
||||
if err != nil {
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Processing API payload: %v", err))
|
||||
return
|
||||
|
|
@ -745,7 +650,6 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques
|
|||
|
||||
// Delete deletes the resource and removes the Terraform state on success.
|
||||
func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform
|
||||
// Retrieve values from state
|
||||
var model Model
|
||||
diags := req.State.Get(ctx, &model)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
|
|
@ -771,11 +675,22 @@ func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteReques
|
|||
|
||||
ctx = core.LogResponse(ctx)
|
||||
|
||||
_, err = wait.DeleteInstanceWaitHandler(ctx, r.client, projectId, region, instanceId).SetTimeout(45 * time.Minute).WaitWithContext(ctx)
|
||||
//_, err = wait.DeleteInstanceWaitHandler(ctx, r.client, projectId, region, instanceId).SetTimeout(45 * time.Minute).WaitWithContext(ctx)
|
||||
//if err != nil {
|
||||
// core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", fmt.Sprintf("Instance deletion waiting: %v", err))
|
||||
// return
|
||||
//}
|
||||
|
||||
_, err = r.client.GetInstanceRequest(ctx, projectId, region, instanceId).Execute()
|
||||
if err != nil {
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", fmt.Sprintf("Instance deletion waiting: %v", err))
|
||||
return
|
||||
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 && oapiErr.StatusCode != http.StatusNotFound {
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
resp.State.RemoveResource(ctx)
|
||||
tflog.Info(ctx, "Postgres Flex instance deleted")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ func TestMapFields(t *testing.T) {
|
|||
description string
|
||||
state Model
|
||||
input *postgresflex.GetInstanceResponse
|
||||
flavor *flavorModel
|
||||
storage *storageModel
|
||||
encryption *encryptionModel
|
||||
network *networkModel
|
||||
|
|
@ -51,9 +50,6 @@ func TestMapFields(t *testing.T) {
|
|||
FlavorId: utils.Ptr("flavor_id"),
|
||||
Replicas: postgresflex.GetInstanceResponseGetReplicasAttributeType(utils.Ptr(int32(1))),
|
||||
},
|
||||
&flavorModel{
|
||||
NodeType: types.StringValue("Single"),
|
||||
},
|
||||
&storageModel{},
|
||||
&encryptionModel{},
|
||||
&networkModel{
|
||||
|
|
@ -67,16 +63,10 @@ func TestMapFields(t *testing.T) {
|
|||
InstanceId: types.StringValue("iid"),
|
||||
ProjectId: types.StringValue("pid"),
|
||||
Name: types.StringNull(),
|
||||
FlavorId: types.StringValue("flavor_id"),
|
||||
//ACL: types.ListNull(types.StringType),
|
||||
BackupSchedule: types.StringNull(),
|
||||
Flavor: types.ObjectValueMust(flavorTypes, map[string]attr.Value{
|
||||
"id": types.StringNull(),
|
||||
"description": types.StringNull(),
|
||||
"cpu": types.Int64Null(),
|
||||
"ram": types.Int64Null(),
|
||||
"node_type": types.StringValue("Single"),
|
||||
}),
|
||||
Replicas: types.Int64Value(1),
|
||||
Replicas: types.Int64Value(1),
|
||||
Encryption: types.ObjectValueMust(encryptionTypes, map[string]attr.Value{
|
||||
"keyring_id": types.StringNull(),
|
||||
"key_id": types.StringNull(),
|
||||
|
|
@ -171,7 +161,6 @@ func TestMapFields(t *testing.T) {
|
|||
ProjectId: types.StringValue("pid"),
|
||||
},
|
||||
nil,
|
||||
&flavorModel{},
|
||||
&storageModel{},
|
||||
&encryptionModel{},
|
||||
&networkModel{},
|
||||
|
|
@ -186,7 +175,6 @@ func TestMapFields(t *testing.T) {
|
|||
ProjectId: types.StringValue("pid"),
|
||||
},
|
||||
&postgresflex.GetInstanceResponse{},
|
||||
&flavorModel{},
|
||||
&storageModel{},
|
||||
&encryptionModel{},
|
||||
&networkModel{},
|
||||
|
|
@ -197,7 +185,21 @@ func TestMapFields(t *testing.T) {
|
|||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.description, func(t *testing.T) {
|
||||
err := mapFields(context.Background(), tt.input, &tt.state, tt.flavor, tt.storage, tt.encryption, tt.network, tt.region)
|
||||
client := postgresFlexClientMocked{
|
||||
returnError: false,
|
||||
firstItem: 0,
|
||||
lastItem: 0,
|
||||
}
|
||||
err := mapFields(
|
||||
context.Background(),
|
||||
client,
|
||||
tt.input,
|
||||
&tt.state,
|
||||
tt.storage,
|
||||
tt.encryption,
|
||||
tt.network,
|
||||
tt.region,
|
||||
)
|
||||
if !tt.isValid && err == nil {
|
||||
t.Fatalf("Should have failed")
|
||||
}
|
||||
|
|
@ -219,7 +221,6 @@ func TestToCreatePayload(t *testing.T) {
|
|||
description string
|
||||
input *Model
|
||||
inputAcl []string
|
||||
inputFlavor *flavorModel
|
||||
inputStorage *storageModel
|
||||
inputEncryption *encryptionModel
|
||||
inputNetwork *networkModel
|
||||
|
|
@ -232,34 +233,6 @@ func TestToCreatePayload(t *testing.T) {
|
|||
Replicas: types.Int64Value(1),
|
||||
},
|
||||
[]string{},
|
||||
&flavorModel{},
|
||||
&storageModel{},
|
||||
&encryptionModel{},
|
||||
&networkModel{
|
||||
ACL: types.ListValueMust(types.StringType, []attr.Value{
|
||||
types.StringValue("0.0.0.0/0"),
|
||||
}),
|
||||
},
|
||||
&postgresflex.CreateInstanceRequestPayload{
|
||||
Acl: &[]string{"0.0.0.0/0"},
|
||||
Storage: postgresflex.CreateInstanceRequestPayloadGetStorageAttributeType(&postgresflex.Storage{}),
|
||||
Encryption: &postgresflex.InstanceEncryption{},
|
||||
Network: &postgresflex.InstanceNetwork{
|
||||
Acl: &[]string{"0.0.0.0/0"},
|
||||
},
|
||||
Replicas: postgresflex.CreateInstanceRequestPayloadGetReplicasAttributeType(utils.Ptr(int32(1))),
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"use flavor node_type instead of replicas",
|
||||
&Model{},
|
||||
[]string{
|
||||
"0.0.0.0/0",
|
||||
},
|
||||
&flavorModel{
|
||||
NodeType: types.StringValue("Single"),
|
||||
},
|
||||
&storageModel{},
|
||||
&encryptionModel{},
|
||||
&networkModel{
|
||||
|
|
@ -282,7 +255,6 @@ func TestToCreatePayload(t *testing.T) {
|
|||
"nil_model",
|
||||
nil,
|
||||
[]string{},
|
||||
&flavorModel{},
|
||||
&storageModel{},
|
||||
&encryptionModel{},
|
||||
&networkModel{},
|
||||
|
|
@ -293,7 +265,6 @@ func TestToCreatePayload(t *testing.T) {
|
|||
"nil_acl",
|
||||
&Model{},
|
||||
nil,
|
||||
&flavorModel{},
|
||||
&storageModel{},
|
||||
&encryptionModel{},
|
||||
&networkModel{},
|
||||
|
|
@ -304,7 +275,6 @@ func TestToCreatePayload(t *testing.T) {
|
|||
"nil_flavor",
|
||||
&Model{},
|
||||
[]string{},
|
||||
nil,
|
||||
&storageModel{},
|
||||
&encryptionModel{},
|
||||
&networkModel{},
|
||||
|
|
@ -315,7 +285,6 @@ func TestToCreatePayload(t *testing.T) {
|
|||
"nil_storage",
|
||||
&Model{},
|
||||
[]string{},
|
||||
&flavorModel{},
|
||||
nil,
|
||||
&encryptionModel{},
|
||||
&networkModel{},
|
||||
|
|
@ -325,7 +294,7 @@ func TestToCreatePayload(t *testing.T) {
|
|||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.description, func(t *testing.T) {
|
||||
output, err := toCreatePayload(tt.input, tt.inputFlavor, tt.inputStorage, tt.inputEncryption, tt.inputNetwork)
|
||||
output, err := toCreatePayload(tt.input, tt.inputStorage, tt.inputEncryption, tt.inputNetwork)
|
||||
if !tt.isValid && err == nil {
|
||||
t.Fatalf("Should have failed")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,85 +0,0 @@
|
|||
package postgresflexalpha
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
|
||||
)
|
||||
|
||||
type useStateForUnknownIfFlavorUnchangedModifier struct {
|
||||
Req resource.SchemaRequest
|
||||
}
|
||||
|
||||
// UseStateForUnknownIfFlavorUnchanged returns a plan modifier similar to UseStateForUnknown
|
||||
// if the RAM and CPU values are not changed in the plan. Otherwise, the plan modifier does nothing.
|
||||
func UseStateForUnknownIfFlavorUnchanged(req resource.SchemaRequest) planmodifier.String {
|
||||
return useStateForUnknownIfFlavorUnchangedModifier{
|
||||
Req: req,
|
||||
}
|
||||
}
|
||||
|
||||
func (m useStateForUnknownIfFlavorUnchangedModifier) Description(context.Context) string {
|
||||
return "UseStateForUnknownIfFlavorUnchanged returns a plan modifier similar to UseStateForUnknown if the RAM and CPU values are not changed in the plan. Otherwise, the plan modifier does nothing."
|
||||
}
|
||||
|
||||
func (m useStateForUnknownIfFlavorUnchangedModifier) MarkdownDescription(ctx context.Context) string {
|
||||
return m.Description(ctx)
|
||||
}
|
||||
|
||||
func (m useStateForUnknownIfFlavorUnchangedModifier) PlanModifyString(ctx context.Context, req planmodifier.StringRequest, resp *planmodifier.StringResponse) { // nolint:gocritic // function signature required by Terraform
|
||||
// Do nothing if there is no state value.
|
||||
if req.StateValue.IsNull() {
|
||||
return
|
||||
}
|
||||
|
||||
// Do nothing if there is a known planned value.
|
||||
if !req.PlanValue.IsUnknown() {
|
||||
return
|
||||
}
|
||||
|
||||
// Do nothing if there is an unknown configuration value, otherwise interpolation gets messed up.
|
||||
if req.ConfigValue.IsUnknown() {
|
||||
return
|
||||
}
|
||||
|
||||
// The above checks are taken from the UseStateForUnknown plan modifier implementation
|
||||
// (https://github.com/hashicorp/terraform-plugin-framework/blob/main/resource/schema/stringplanmodifier/use_state_for_unknown.go#L38)
|
||||
|
||||
var stateModel Model
|
||||
diags := req.State.Get(ctx, &stateModel)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
var stateFlavor = &flavorModel{}
|
||||
if !stateModel.Flavor.IsNull() && !stateModel.Flavor.IsUnknown() {
|
||||
diags = stateModel.Flavor.As(ctx, stateFlavor, basetypes.ObjectAsOptions{})
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var planModel Model
|
||||
diags = req.Plan.Get(ctx, &planModel)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
var planFlavor = &flavorModel{}
|
||||
if !planModel.Flavor.IsNull() && !planModel.Flavor.IsUnknown() {
|
||||
diags = planModel.Flavor.As(ctx, planFlavor, basetypes.ObjectAsOptions{})
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if planFlavor.CPU == stateFlavor.CPU && planFlavor.RAM == stateFlavor.RAM {
|
||||
resp.PlanValue = req.StateValue
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue