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
|
|
@ -253,22 +253,6 @@ func (r *instanceDataSource) Read(ctx context.Context, req datasource.ReadReques
|
|||
|
||||
ctx = core.LogResponse(ctx)
|
||||
|
||||
var flavor = &flavorModel{}
|
||||
if model.Flavor.IsNull() || model.Flavor.IsUnknown() {
|
||||
flavor.Id = types.StringValue(*instanceResp.FlavorId)
|
||||
if flavor.Id.IsNull() || flavor.Id.IsUnknown() || flavor.Id.String() == "" {
|
||||
panic("WTF FlavorId can not be null or empty string")
|
||||
}
|
||||
err = getFlavorModelById(ctx, r.client, &model, flavor)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError(err.Error(), err.Error())
|
||||
return
|
||||
}
|
||||
if flavor.CPU.IsNull() || flavor.CPU.IsUnknown() || flavor.CPU.String() == "" {
|
||||
panic("WTF FlavorId can not be null or empty string")
|
||||
}
|
||||
}
|
||||
|
||||
var storage = &storageModel{}
|
||||
if !model.Storage.IsNull() && !model.Storage.IsUnknown() {
|
||||
diags = model.Storage.As(ctx, storage, basetypes.ObjectAsOptions{})
|
||||
|
|
@ -296,7 +280,7 @@ func (r *instanceDataSource) Read(ctx context.Context, req datasource.ReadReques
|
|||
}
|
||||
}
|
||||
|
||||
err = mapFields(ctx, instanceResp, &model, flavor, storage, encryption, network, region)
|
||||
err = mapFields(ctx, 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,11 +4,9 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework/attr"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
|
||||
sqlserverflex "github.com/mhenselin/terraform-provider-stackitprivatepreview/pkg/sqlserverflexalpha"
|
||||
"github.com/mhenselin/terraform-provider-stackitprivatepreview/stackit/internal/conversion"
|
||||
"github.com/mhenselin/terraform-provider-stackitprivatepreview/stackit/internal/core"
|
||||
|
|
@ -19,7 +17,7 @@ type sqlserverflexClient interface {
|
|||
GetFlavorsRequestExecute(ctx context.Context, projectId, region string, page, size *int64, sort *sqlserverflex.FlavorSort) (*sqlserverflex.GetFlavorsResponse, error)
|
||||
}
|
||||
|
||||
func mapFields(ctx context.Context, resp *sqlserverflex.GetInstanceResponse, model *Model, flavor *flavorModel, storage *storageModel, encryption *encryptionModel, network *networkModel, region string) error {
|
||||
func mapFields(ctx context.Context, resp *sqlserverflex.GetInstanceResponse, model *Model, storage *storageModel, encryption *encryptionModel, network *networkModel, region string) error {
|
||||
if resp == nil {
|
||||
return fmt.Errorf("response input is nil")
|
||||
}
|
||||
|
|
@ -37,26 +35,6 @@ func mapFields(ctx context.Context, resp *sqlserverflex.GetInstanceResponse, mod
|
|||
return fmt.Errorf("instance id not present")
|
||||
}
|
||||
|
||||
var flavorValues map[string]attr.Value
|
||||
if instance.FlavorId == nil {
|
||||
return fmt.Errorf("instance has no flavor id")
|
||||
}
|
||||
if *instance.FlavorId != flavor.Id.ValueString() {
|
||||
return fmt.Errorf("instance has different flavor id %s - %s", *instance.FlavorId, flavor.Id.ValueString())
|
||||
}
|
||||
|
||||
flavorValues = map[string]attr.Value{
|
||||
"id": flavor.Id,
|
||||
"description": flavor.Description,
|
||||
"cpu": flavor.CPU,
|
||||
"ram": flavor.RAM,
|
||||
"node_type": flavor.NodeType,
|
||||
}
|
||||
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{
|
||||
|
|
@ -163,7 +141,7 @@ func mapFields(ctx context.Context, resp *sqlserverflex.GetInstanceResponse, mod
|
|||
model.Id = utils.BuildInternalTerraformId(model.ProjectId.ValueString(), region, instanceId)
|
||||
model.InstanceId = types.StringValue(instanceId)
|
||||
model.Name = types.StringPointerValue(instance.Name)
|
||||
model.Flavor = flavorObject
|
||||
model.FlavorId = types.StringPointerValue(instance.FlavorId)
|
||||
model.Replicas = types.Int64Value(int64(*instance.Replicas))
|
||||
model.Storage = storageObject
|
||||
model.Version = types.StringValue(string(*instance.Version))
|
||||
|
|
@ -182,10 +160,6 @@ func toCreatePayload(model *Model, storage *storageModel, encryption *encryption
|
|||
return nil, fmt.Errorf("nil model")
|
||||
}
|
||||
|
||||
if model.Flavor.IsNull() || model.Flavor.IsUnknown() {
|
||||
return nil, fmt.Errorf("nil flavor")
|
||||
}
|
||||
|
||||
storagePayload := &sqlserverflex.CreateInstanceRequestPayloadGetStorageArgType{}
|
||||
if storage != nil {
|
||||
storagePayload.Class = conversion.StringValueToPointer(storage.Class)
|
||||
|
|
@ -200,16 +174,6 @@ func toCreatePayload(model *Model, storage *storageModel, encryption *encryption
|
|||
encryptionPayload.ServiceAccount = conversion.StringValueToPointer(encryption.ServiceAccount)
|
||||
}
|
||||
|
||||
flavorId := ""
|
||||
if !model.Flavor.IsNull() && !model.Flavor.IsUnknown() {
|
||||
modelValues := model.Flavor.Attributes()
|
||||
if _, ok := modelValues["id"]; !ok {
|
||||
return nil, fmt.Errorf("flavor has not yet been created")
|
||||
}
|
||||
// TODO - how to get rid of that trim?
|
||||
flavorId = strings.Trim(modelValues["id"].String(), "\"")
|
||||
}
|
||||
|
||||
var aclElements []string
|
||||
if network != nil && !network.ACL.IsNull() && !network.ACL.IsUnknown() {
|
||||
aclElements = make([]string, 0, len(network.ACL.Elements()))
|
||||
|
|
@ -227,31 +191,20 @@ func toCreatePayload(model *Model, storage *storageModel, encryption *encryption
|
|||
|
||||
return &sqlserverflex.CreateInstanceRequestPayload{
|
||||
BackupSchedule: conversion.StringValueToPointer(model.BackupSchedule),
|
||||
FlavorId: &flavorId,
|
||||
Encryption: encryptionPayload,
|
||||
FlavorId: conversion.StringValueToPointer(model.FlavorId),
|
||||
Name: conversion.StringValueToPointer(model.Name),
|
||||
Network: networkPayload,
|
||||
RetentionDays: conversion.Int64ValueToPointer(model.RetentionDays),
|
||||
Storage: storagePayload,
|
||||
Version: sqlserverflex.CreateInstanceRequestPayloadGetVersionAttributeType(conversion.StringValueToPointer(model.Version)),
|
||||
Encryption: encryptionPayload,
|
||||
RetentionDays: conversion.Int64ValueToPointer(model.RetentionDays),
|
||||
Network: networkPayload,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func toUpdatePayload(model *Model, storage *storageModel, network *networkModel) (*sqlserverflex.UpdateInstancePartiallyRequestPayload, error) {
|
||||
func toUpdatePartiallyPayload(model *Model, storage *storageModel, network *networkModel) (*sqlserverflex.UpdateInstancePartiallyRequestPayload, error) {
|
||||
if model == nil {
|
||||
return nil, fmt.Errorf("nil model")
|
||||
}
|
||||
if model.Flavor.IsNull() || model.Flavor.IsUnknown() {
|
||||
return nil, fmt.Errorf("nil flavor")
|
||||
}
|
||||
var flavorMdl flavorModel
|
||||
diag := model.Flavor.As(context.Background(), &flavorMdl, basetypes.ObjectAsOptions{
|
||||
UnhandledNullAsEmpty: true,
|
||||
UnhandledUnknownAsEmpty: false,
|
||||
})
|
||||
if diag.HasError() {
|
||||
return nil, fmt.Errorf("flavor conversion error: %v", diag.Errors())
|
||||
}
|
||||
|
||||
storagePayload := &sqlserverflex.UpdateInstanceRequestPayloadGetStorageArgType{}
|
||||
if storage != nil {
|
||||
|
|
@ -277,12 +230,11 @@ func toUpdatePayload(model *Model, storage *storageModel, network *networkModel)
|
|||
return nil, fmt.Errorf("replica count too big: %d", model.Replicas.ValueInt64())
|
||||
}
|
||||
replCount := int32(model.Replicas.ValueInt64()) // nolint:gosec // check is performed above
|
||||
flavorId := flavorMdl.Id.ValueString()
|
||||
return &sqlserverflex.UpdateInstancePartiallyRequestPayload{
|
||||
Network: networkPayload,
|
||||
BackupSchedule: conversion.StringValueToPointer(model.BackupSchedule),
|
||||
FlavorId: &flavorId,
|
||||
FlavorId: conversion.StringValueToPointer(model.FlavorId),
|
||||
Name: conversion.StringValueToPointer(model.Name),
|
||||
Network: networkPayload,
|
||||
Replicas: sqlserverflex.UpdateInstancePartiallyRequestPayloadGetReplicasAttributeType(&replCount),
|
||||
RetentionDays: conversion.Int64ValueToPointer(model.RetentionDays),
|
||||
Storage: storagePayload,
|
||||
|
|
@ -290,152 +242,15 @@ func toUpdatePayload(model *Model, storage *storageModel, network *networkModel)
|
|||
}, nil
|
||||
}
|
||||
|
||||
func getAllFlavors(ctx context.Context, client sqlserverflexClient, projectId, region string) ([]sqlserverflex.ListFlavors, error) {
|
||||
if projectId == "" || region == "" {
|
||||
return nil, fmt.Errorf("listing sqlserverflex flavors: projectId and region are required")
|
||||
}
|
||||
var flavorList []sqlserverflex.ListFlavors
|
||||
|
||||
page := int64(1)
|
||||
size := int64(10)
|
||||
for {
|
||||
sort := sqlserverflex.FLAVORSORT_INDEX_ASC
|
||||
res, err := client.GetFlavorsRequestExecute(ctx, projectId, region, &page, &size, &sort)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("listing sqlserverflex flavors: %w", err)
|
||||
}
|
||||
if res.Flavors == nil {
|
||||
return nil, fmt.Errorf("finding flavors for project %s", projectId)
|
||||
}
|
||||
pagination := res.GetPagination()
|
||||
flavorList = append(flavorList, *res.Flavors...)
|
||||
|
||||
if *pagination.TotalRows == int64(len(flavorList)) {
|
||||
break
|
||||
}
|
||||
page++
|
||||
}
|
||||
return flavorList, nil
|
||||
}
|
||||
|
||||
func loadFlavorId(ctx context.Context, client sqlserverflexClient, model *Model, flavor *flavorModel, storage *storageModel) error {
|
||||
if model == nil {
|
||||
return fmt.Errorf("nil model")
|
||||
}
|
||||
if flavor == nil {
|
||||
return fmt.Errorf("nil flavor")
|
||||
}
|
||||
cpu := conversion.Int64ValueToPointer(flavor.CPU)
|
||||
if cpu == nil {
|
||||
return fmt.Errorf("nil CPU")
|
||||
}
|
||||
ram := conversion.Int64ValueToPointer(flavor.RAM)
|
||||
if ram == nil {
|
||||
return fmt.Errorf("nil RAM")
|
||||
}
|
||||
nodeType := conversion.StringValueToPointer(flavor.NodeType)
|
||||
if nodeType == nil {
|
||||
return fmt.Errorf("nil NodeType")
|
||||
}
|
||||
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
|
||||
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 *sqlserverflex.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)
|
||||
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("multiple flavors found: %d flavors", foundFlavorCount)
|
||||
}
|
||||
if flavor.Id.ValueString() == "" {
|
||||
return fmt.Errorf("couldn't find flavor, available specs are:%s", avl)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getFlavorModelById(ctx context.Context, client sqlserverflexClient, 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
|
||||
func toUpdatePayload(model *Model, storage *storageModel, network *networkModel) (*sqlserverflex.UpdateInstanceRequestPayload, error) {
|
||||
return &sqlserverflex.UpdateInstanceRequestPayload{
|
||||
BackupSchedule: nil,
|
||||
FlavorId: nil,
|
||||
Name: nil,
|
||||
Network: nil,
|
||||
Replicas: nil,
|
||||
RetentionDays: nil,
|
||||
Storage: nil,
|
||||
Version: nil,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier"
|
||||
sqlserverflexUtils "github.com/mhenselin/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexalpha/utils"
|
||||
|
|
@ -57,7 +56,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"`
|
||||
Encryption types.Object `tfsdk:"encryption"`
|
||||
IsDeletable types.Bool `tfsdk:"is_deletable"`
|
||||
Storage types.Object `tfsdk:"storage"`
|
||||
|
|
@ -98,24 +97,6 @@ var networkTypes = map[string]attr.Type{
|
|||
"router_address": basetypes.StringType{},
|
||||
}
|
||||
|
||||
// Struct corresponding to Model.FlavorId
|
||||
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"`
|
||||
|
|
@ -198,11 +179,13 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r
|
|||
"instance_id": "ID of the SQLServer Flex instance.",
|
||||
"project_id": "STACKIT project ID to which the instance is associated.",
|
||||
"name": "Instance name.",
|
||||
"access_scope": "The access scope of the instance. (e.g. SNA)",
|
||||
"access_scope": "The access scope of the instance. (SNA | PUBLIC)",
|
||||
"flavor_id": "The flavor ID of the instance.",
|
||||
"acl": "The Access Control List (ACL) for the SQLServer Flex instance.",
|
||||
"backup_schedule": `The backup schedule. Should follow the cron scheduling system format (e.g. "0 0 * * *")`,
|
||||
"region": "The resource region. If not defined, the provider region is used.",
|
||||
"encryption": "The encryption block.",
|
||||
"replicas": "The number of replicas of the SQLServer Flex instance.",
|
||||
"network": "The network block.",
|
||||
"keyring_id": "STACKIT KMS - KeyRing ID of the encryption key to use.",
|
||||
"key_id": "STACKIT KMS - Key ID of the encryption key to use.",
|
||||
|
|
@ -271,78 +254,12 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r
|
|||
boolplanmodifier.UseStateForUnknown(),
|
||||
},
|
||||
},
|
||||
// TODO - make it either flavor_id or ram, cpu and node_type
|
||||
"flavor": schema.SingleNestedAttribute{
|
||||
PlanModifiers: []planmodifier.Object{
|
||||
objectplanmodifier.RequiresReplace(),
|
||||
objectplanmodifier.UseStateForUnknown(),
|
||||
"flavor_id": schema.StringAttribute{
|
||||
PlanModifiers: []planmodifier.String{
|
||||
stringplanmodifier.RequiresReplace(),
|
||||
stringplanmodifier.UseStateForUnknown(),
|
||||
},
|
||||
Required: true,
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"id": schema.StringAttribute{
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
PlanModifiers: []planmodifier.String{
|
||||
stringplanmodifier.RequiresReplace(),
|
||||
stringplanmodifier.UseStateForUnknown(),
|
||||
},
|
||||
},
|
||||
"description": schema.StringAttribute{
|
||||
Computed: true,
|
||||
PlanModifiers: []planmodifier.String{
|
||||
stringplanmodifier.UseStateForUnknown(),
|
||||
},
|
||||
},
|
||||
"node_type": schema.StringAttribute{
|
||||
Required: true,
|
||||
PlanModifiers: []planmodifier.String{
|
||||
stringplanmodifier.RequiresReplace(),
|
||||
stringplanmodifier.UseStateForUnknown(),
|
||||
},
|
||||
Validators: []validator.String{
|
||||
stringvalidator.ConflictsWith([]path.Expression{
|
||||
path.MatchRelative().AtParent().AtName("id"),
|
||||
}...),
|
||||
stringvalidator.OneOfCaseInsensitive(validNodeTypes...),
|
||||
stringvalidator.AlsoRequires([]path.Expression{
|
||||
path.MatchRelative().AtParent().AtName("cpu"),
|
||||
path.MatchRelative().AtParent().AtName("ram"),
|
||||
}...),
|
||||
},
|
||||
},
|
||||
"cpu": schema.Int64Attribute{
|
||||
Required: true,
|
||||
PlanModifiers: []planmodifier.Int64{
|
||||
int64planmodifier.RequiresReplace(),
|
||||
int64planmodifier.UseStateForUnknown(),
|
||||
},
|
||||
Validators: []validator.Int64{
|
||||
int64validator.ConflictsWith([]path.Expression{
|
||||
path.MatchRelative().AtParent().AtName("id"),
|
||||
}...),
|
||||
int64validator.AlsoRequires([]path.Expression{
|
||||
path.MatchRelative().AtParent().AtName("node_type"),
|
||||
path.MatchRelative().AtParent().AtName("ram"),
|
||||
}...),
|
||||
},
|
||||
},
|
||||
"ram": schema.Int64Attribute{
|
||||
Required: true,
|
||||
PlanModifiers: []planmodifier.Int64{
|
||||
int64planmodifier.RequiresReplace(),
|
||||
int64planmodifier.UseStateForUnknown(),
|
||||
},
|
||||
Validators: []validator.Int64{
|
||||
int64validator.ConflictsWith([]path.Expression{
|
||||
path.MatchRelative().AtParent().AtName("id"),
|
||||
}...),
|
||||
int64validator.AlsoRequires([]path.Expression{
|
||||
path.MatchRelative().AtParent().AtName("node_type"),
|
||||
path.MatchRelative().AtParent().AtName("cpu"),
|
||||
}...),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"replicas": schema.Int64Attribute{
|
||||
Computed: true,
|
||||
|
|
@ -506,7 +423,6 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r
|
|||
|
||||
// Create creates the resource and sets the initial Terraform state.
|
||||
func (r *instanceResource) Create(ctx context.Context, 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...)
|
||||
|
|
@ -548,37 +464,6 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques
|
|||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// Generate API request body from model
|
||||
payload, err := toCreatePayload(&model, storage, encryption, network)
|
||||
if err != nil {
|
||||
|
|
@ -596,6 +481,7 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques
|
|||
|
||||
instanceId := *createResp.Id
|
||||
utils.SetAndLogStateFields(ctx, &resp.Diagnostics, &resp.State, map[string]any{
|
||||
"id": utils.BuildInternalTerraformId(projectId, region, instanceId),
|
||||
"instance_id": instanceId,
|
||||
})
|
||||
if resp.Diagnostics.HasError() {
|
||||
|
|
@ -615,25 +501,8 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques
|
|||
return
|
||||
}
|
||||
|
||||
if *waitResp.FlavorId != flavor.Id.ValueString() {
|
||||
core.LogAndAddError(
|
||||
ctx,
|
||||
&resp.Diagnostics,
|
||||
"Error creating instance",
|
||||
fmt.Sprintf("Instance creation waiting: returned flavor id differs (expected: %s, current: %s)", flavor.Id.ValueString(), *waitResp.FlavorId),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if flavor.CPU.IsNull() || flavor.CPU.IsUnknown() {
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", "Instance creation waiting: flavor cpu is null or unknown")
|
||||
}
|
||||
if flavor.RAM.IsNull() || flavor.RAM.IsUnknown() {
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", "Instance creation waiting: flavor ram is null or unknown")
|
||||
}
|
||||
|
||||
// Map response body to schema
|
||||
err = mapFields(ctx, waitResp, &model, flavor, storage, encryption, network, region)
|
||||
err = mapFields(ctx, 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
|
||||
|
|
@ -672,27 +541,6 @@ 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
|
||||
}
|
||||
|
||||
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{})
|
||||
|
|
@ -734,7 +582,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, 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
|
||||
|
|
@ -795,37 +643,6 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques
|
|||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// Generate API request body from model
|
||||
payload, err := toUpdatePayload(&model, storage, network)
|
||||
if err != nil {
|
||||
|
|
@ -833,7 +650,8 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques
|
|||
return
|
||||
}
|
||||
// Update existing instance
|
||||
err = r.client.UpdateInstancePartiallyRequest(ctx, projectId, region, instanceId).UpdateInstancePartiallyRequestPayload(*payload).Execute()
|
||||
err = r.client.UpdateInstanceRequest(ctx, projectId, region, instanceId).UpdateInstanceRequestPayload(*payload).Execute()
|
||||
// err = r.client.UpdateInstancePartiallyRequest(ctx, projectId, region, instanceId).UpdateInstancePartiallyRequestPayload(*payload).Execute()
|
||||
if err != nil {
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", err.Error())
|
||||
return
|
||||
|
|
@ -848,7 +666,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, 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
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ func TestMapFields(t *testing.T) {
|
|||
description string
|
||||
state Model
|
||||
input *sqlserverflex.GetInstanceResponse
|
||||
flavor *flavorModel
|
||||
storage *storageModel
|
||||
encryption *encryptionModel
|
||||
network *networkModel
|
||||
|
|
@ -53,13 +52,6 @@ func TestMapFields(t *testing.T) {
|
|||
Edition: types.StringValue("edition 1"),
|
||||
Status: types.StringValue("status"),
|
||||
IsDeletable: types.BoolValue(true),
|
||||
Flavor: types.ObjectValueMust(flavorTypes, map[string]attr.Value{
|
||||
"id": types.StringValue("flavor_id"),
|
||||
"description": types.StringNull(),
|
||||
"cpu": types.Int64Null(),
|
||||
"ram": types.Int64Null(),
|
||||
"node_type": types.StringNull(),
|
||||
}),
|
||||
},
|
||||
&sqlserverflex.GetInstanceResponse{
|
||||
FlavorId: utils.Ptr("flavor_id"),
|
||||
|
|
@ -70,9 +62,6 @@ func TestMapFields(t *testing.T) {
|
|||
Status: sqlserverflex.GetInstanceResponseGetStatusAttributeType(utils.Ptr("status")),
|
||||
IsDeletable: utils.Ptr(true),
|
||||
},
|
||||
&flavorModel{
|
||||
Id: types.StringValue("flavor_id"),
|
||||
},
|
||||
&storageModel{},
|
||||
&encryptionModel{},
|
||||
&networkModel{
|
||||
|
|
@ -85,14 +74,7 @@ func TestMapFields(t *testing.T) {
|
|||
ProjectId: types.StringValue("pid"),
|
||||
Name: types.StringNull(),
|
||||
BackupSchedule: types.StringNull(),
|
||||
Flavor: types.ObjectValueMust(flavorTypes, map[string]attr.Value{
|
||||
"id": types.StringValue("flavor_id"),
|
||||
"description": types.StringNull(),
|
||||
"cpu": types.Int64Null(),
|
||||
"ram": types.Int64Null(),
|
||||
"node_type": types.StringNull(),
|
||||
}),
|
||||
Replicas: types.Int64Value(1),
|
||||
Replicas: types.Int64Value(1),
|
||||
Storage: types.ObjectValueMust(storageTypes, map[string]attr.Value{
|
||||
"class": types.StringNull(),
|
||||
"size": types.Int64Null(),
|
||||
|
|
@ -151,13 +133,6 @@ func TestMapFields(t *testing.T) {
|
|||
RouterAddress: nil,
|
||||
},
|
||||
},
|
||||
&flavorModel{
|
||||
Id: basetypes.NewStringValue("flavor_id"),
|
||||
Description: basetypes.NewStringValue("description"),
|
||||
CPU: basetypes.NewInt64Value(12),
|
||||
RAM: basetypes.NewInt64Value(34),
|
||||
NodeType: basetypes.NewStringValue("node_type"),
|
||||
},
|
||||
&storageModel{},
|
||||
&encryptionModel{},
|
||||
&networkModel{
|
||||
|
|
@ -174,14 +149,7 @@ func TestMapFields(t *testing.T) {
|
|||
ProjectId: types.StringValue("pid"),
|
||||
Name: types.StringValue("name"),
|
||||
BackupSchedule: types.StringValue("schedule"),
|
||||
Flavor: types.ObjectValueMust(flavorTypes, map[string]attr.Value{
|
||||
"id": types.StringValue("flavor_id"),
|
||||
"description": types.StringValue("description"),
|
||||
"cpu": types.Int64Value(12),
|
||||
"ram": types.Int64Value(34),
|
||||
"node_type": types.StringValue("node_type"),
|
||||
}),
|
||||
Replicas: types.Int64Value(56),
|
||||
Replicas: types.Int64Value(56),
|
||||
Storage: types.ObjectValueMust(storageTypes, map[string]attr.Value{
|
||||
"class": types.StringValue("class"),
|
||||
"size": types.Int64Value(78),
|
||||
|
|
@ -380,7 +348,7 @@ 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)
|
||||
err := mapFields(context.Background(), tt.input, &tt.state, tt.storage, tt.encryption, tt.network, tt.region)
|
||||
if !tt.isValid && err == nil {
|
||||
t.Fatalf("Should have failed")
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue