## Description
<!-- **Please link some issue here describing what you are trying to achieve.**
In case there is no issue present for your PR, please consider creating one.
At least please give us some description what you are trying to achieve and why your change is needed. -->
relates to #1234
## Checklist
- [ ] Issue was linked above
- [ ] Code format was applied: `make fmt`
- [ ] Examples were added / adjusted (see `examples/` directory)
- [x] Docs are up-to-date: `make generate-docs` (will be checked by CI)
- [ ] Unit tests got implemented or updated
- [ ] Acceptance tests got implemented or updated (see e.g. [here](f5f99d1709/stackit/internal/services/dns/dns_acc_test.go))
- [x] Unit tests are passing: `make test` (will be checked by CI)
- [x] No linter issues: `make lint` (will be checked by CI)
Reviewed-on: #31
Reviewed-by: Andre_Harms <andre.harms@stackit.cloud>
392 lines
15 KiB
Go
392 lines
15 KiB
Go
package sqlserverflex
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"math"
|
|
|
|
"github.com/hashicorp/terraform-plugin-framework/attr"
|
|
"github.com/hashicorp/terraform-plugin-framework/diag"
|
|
"github.com/hashicorp/terraform-plugin-framework/resource"
|
|
"github.com/hashicorp/terraform-plugin-framework/types"
|
|
sqlserverflex "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/pkg_gen/sqlserverflexalpha"
|
|
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/conversion"
|
|
sqlserverflexResGen "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexalpha/instance/resources_gen"
|
|
)
|
|
|
|
func mapResponseToModel(
|
|
ctx context.Context,
|
|
resp *sqlserverflex.GetInstanceResponse,
|
|
m *sqlserverflexResGen.InstanceModel,
|
|
tfDiags diag.Diagnostics,
|
|
) error {
|
|
m.BackupSchedule = types.StringValue(resp.GetBackupSchedule())
|
|
m.Edition = types.StringValue(string(resp.GetEdition()))
|
|
m.Encryption = handleEncryption(m, resp)
|
|
m.FlavorId = types.StringValue(resp.GetFlavorId())
|
|
m.Id = types.StringValue(resp.GetId())
|
|
m.InstanceId = types.StringValue(resp.GetId())
|
|
m.IsDeletable = types.BoolValue(resp.GetIsDeletable())
|
|
m.Name = types.StringValue(resp.GetName())
|
|
netAcl, diags := types.ListValueFrom(ctx, types.StringType, resp.Network.GetAcl())
|
|
tfDiags.Append(diags...)
|
|
if diags.HasError() {
|
|
return fmt.Errorf(
|
|
"error converting network acl response value",
|
|
)
|
|
}
|
|
net, diags := sqlserverflexResGen.NewNetworkValue(
|
|
sqlserverflexResGen.NetworkValue{}.AttributeTypes(ctx),
|
|
map[string]attr.Value{
|
|
"access_scope": types.StringValue(string(resp.Network.GetAccessScope())),
|
|
"acl": netAcl,
|
|
"instance_address": types.StringValue(resp.Network.GetInstanceAddress()),
|
|
"router_address": types.StringValue(resp.Network.GetRouterAddress()),
|
|
},
|
|
)
|
|
tfDiags.Append(diags...)
|
|
if diags.HasError() {
|
|
return fmt.Errorf(
|
|
"error converting network response value",
|
|
"access_scope",
|
|
types.StringValue(string(resp.Network.GetAccessScope())),
|
|
"acl",
|
|
netAcl,
|
|
"instance_address",
|
|
types.StringValue(resp.Network.GetInstanceAddress()),
|
|
"router_address",
|
|
types.StringValue(resp.Network.GetRouterAddress()),
|
|
)
|
|
}
|
|
m.Network = net
|
|
m.Replicas = types.Int64Value(int64(resp.GetReplicas()))
|
|
m.RetentionDays = types.Int64Value(resp.GetRetentionDays())
|
|
m.Status = types.StringValue(string(resp.GetStatus()))
|
|
|
|
stor, diags := sqlserverflexResGen.NewStorageValue(
|
|
sqlserverflexResGen.StorageValue{}.AttributeTypes(ctx),
|
|
map[string]attr.Value{
|
|
"class": types.StringValue(resp.Storage.GetClass()),
|
|
"size": types.Int64Value(resp.Storage.GetSize()),
|
|
},
|
|
)
|
|
tfDiags.Append(diags...)
|
|
if diags.HasError() {
|
|
return fmt.Errorf("error converting storage response value")
|
|
}
|
|
m.Storage = stor
|
|
|
|
m.Version = types.StringValue(string(resp.GetVersion()))
|
|
return nil
|
|
}
|
|
|
|
func handleEncryption(
|
|
m *sqlserverflexResGen.InstanceModel,
|
|
resp *sqlserverflex.GetInstanceResponse,
|
|
) sqlserverflexResGen.EncryptionValue {
|
|
if !resp.HasEncryption() ||
|
|
resp.Encryption == nil ||
|
|
resp.Encryption.KekKeyId == nil ||
|
|
resp.Encryption.KekKeyRingId == nil ||
|
|
resp.Encryption.KekKeyVersion == nil ||
|
|
resp.Encryption.ServiceAccount == nil {
|
|
|
|
if m.Encryption.IsNull() || m.Encryption.IsUnknown() {
|
|
return sqlserverflexResGen.NewEncryptionValueNull()
|
|
}
|
|
return m.Encryption
|
|
}
|
|
|
|
enc := sqlserverflexResGen.NewEncryptionValueNull()
|
|
if kVal, ok := resp.Encryption.GetKekKeyIdOk(); ok {
|
|
enc.KekKeyId = types.StringValue(kVal)
|
|
}
|
|
if kkVal, ok := resp.Encryption.GetKekKeyRingIdOk(); ok {
|
|
enc.KekKeyRingId = types.StringValue(kkVal)
|
|
}
|
|
if kkvVal, ok := resp.Encryption.GetKekKeyVersionOk(); ok {
|
|
enc.KekKeyVersion = types.StringValue(kkvVal)
|
|
}
|
|
if sa, ok := resp.Encryption.GetServiceAccountOk(); ok {
|
|
enc.ServiceAccount = types.StringValue(sa)
|
|
}
|
|
return enc
|
|
}
|
|
|
|
//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")
|
|
// }
|
|
// if model == nil {
|
|
// return fmt.Errorf("model input is nil")
|
|
// }
|
|
// instance := resp
|
|
//
|
|
// var instanceId string
|
|
// if model.InstanceId.ValueString() != "" {
|
|
// instanceId = model.InstanceId.ValueString()
|
|
// } else if instance.Id != nil {
|
|
// instanceId = *instance.Id
|
|
// } else {
|
|
// return fmt.Errorf("instance id not present")
|
|
// }
|
|
//
|
|
// var storageValues map[string]attr.Value
|
|
// if instance.Storage == nil {
|
|
// storageValues = map[string]attr.Value{
|
|
// "class": storage.Class,
|
|
// "size": storage.Size,
|
|
// }
|
|
// } else {
|
|
// storageValues = map[string]attr.Value{
|
|
// "class": types.StringValue(*instance.Storage.Class),
|
|
// "size": types.Int64PointerValue(instance.Storage.Size),
|
|
// }
|
|
// }
|
|
// storageObject, diags := types.ObjectValue(storageTypes, storageValues)
|
|
// if diags.HasError() {
|
|
// return fmt.Errorf("creating storage: %w", core.DiagsToError(diags))
|
|
// }
|
|
//
|
|
// var encryptionValues map[string]attr.Value
|
|
// if instance.Encryption == nil {
|
|
// encryptionValues = map[string]attr.Value{
|
|
// "keyring_id": encryption.KeyRingId,
|
|
// "key_id": encryption.KeyId,
|
|
// "key_version": encryption.KeyVersion,
|
|
// "service_account": encryption.ServiceAccount,
|
|
// }
|
|
// } else {
|
|
// encryptionValues = map[string]attr.Value{
|
|
// "keyring_id": types.StringValue(*instance.Encryption.KekKeyRingId),
|
|
// "key_id": types.StringValue(*instance.Encryption.KekKeyId),
|
|
// "key_version": types.StringValue(*instance.Encryption.KekKeyVersion),
|
|
// "service_account": types.StringValue(*instance.Encryption.ServiceAccount),
|
|
// }
|
|
// }
|
|
// encryptionObject, diags := types.ObjectValue(encryptionTypes, encryptionValues)
|
|
// if diags.HasError() {
|
|
// return fmt.Errorf("creating encryption: %w", core.DiagsToError(diags))
|
|
// }
|
|
//
|
|
// var networkValues map[string]attr.Value
|
|
// if instance.Network == nil {
|
|
// networkValues = map[string]attr.Value{
|
|
// "acl": network.ACL,
|
|
// "access_scope": network.AccessScope,
|
|
// "instance_address": network.InstanceAddress,
|
|
// "router_address": network.RouterAddress,
|
|
// }
|
|
// } else {
|
|
// aclList, diags := types.ListValueFrom(ctx, types.StringType, *instance.Network.Acl)
|
|
// if diags.HasError() {
|
|
// 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),
|
|
// }
|
|
// }
|
|
// networkObject, diags := types.ObjectValue(networkTypes, networkValues)
|
|
// if diags.HasError() {
|
|
// return fmt.Errorf("creating network: %w", core.DiagsToError(diags))
|
|
// }
|
|
//
|
|
// simplifiedModelBackupSchedule := utils.SimplifyBackupSchedule(model.BackupSchedule.ValueString())
|
|
// // If the value returned by the API is different from the one in the model after simplification,
|
|
// // we update the model so that it causes an error in Terraform
|
|
// if simplifiedModelBackupSchedule != types.StringPointerValue(instance.BackupSchedule).ValueString() {
|
|
// model.BackupSchedule = types.StringPointerValue(instance.BackupSchedule)
|
|
// }
|
|
//
|
|
// if instance.Replicas == nil {
|
|
// return fmt.Errorf("instance has no replicas set")
|
|
// }
|
|
//
|
|
// if instance.RetentionDays == nil {
|
|
// return fmt.Errorf("instance has no retention days set")
|
|
// }
|
|
//
|
|
// if instance.Version == nil {
|
|
// return fmt.Errorf("instance has no version set")
|
|
// }
|
|
//
|
|
// if instance.Edition == nil {
|
|
// return fmt.Errorf("instance has no edition set")
|
|
// }
|
|
//
|
|
// if instance.Status == nil {
|
|
// return fmt.Errorf("instance has no status set")
|
|
// }
|
|
//
|
|
// if instance.IsDeletable == nil {
|
|
// return fmt.Errorf("instance has no IsDeletable set")
|
|
// }
|
|
//
|
|
// model.Id = utils.BuildInternalTerraformId(model.ProjectId.ValueString(), region, instanceId)
|
|
// model.InstanceId = types.StringValue(instanceId)
|
|
// model.Name = types.StringPointerValue(instance.Name)
|
|
// model.FlavorId = types.StringPointerValue(instance.FlavorId)
|
|
// model.Replicas = types.Int64Value(int64(*instance.Replicas))
|
|
// model.Storage = storageObject
|
|
// model.Version = types.StringValue(string(*instance.Version))
|
|
// model.Edition = types.StringValue(string(*instance.Edition))
|
|
// model.Region = types.StringValue(region)
|
|
// model.Encryption = encryptionObject
|
|
// model.Network = networkObject
|
|
// model.RetentionDays = types.Int64Value(*instance.RetentionDays)
|
|
// model.Status = types.StringValue(string(*instance.Status))
|
|
// model.IsDeletable = types.BoolValue(*instance.IsDeletable)
|
|
// return nil
|
|
//}
|
|
|
|
func toCreatePayload(
|
|
ctx context.Context,
|
|
model *sqlserverflexResGen.InstanceModel,
|
|
) (*sqlserverflex.CreateInstanceRequestPayload, error) {
|
|
if model == nil {
|
|
return nil, fmt.Errorf("nil model")
|
|
}
|
|
|
|
storagePayload := &sqlserverflex.CreateInstanceRequestPayloadGetStorageArgType{}
|
|
if !model.Storage.IsNull() && !model.Storage.IsUnknown() {
|
|
storagePayload.Class = model.Storage.Class.ValueStringPointer()
|
|
storagePayload.Size = model.Storage.Size.ValueInt64Pointer()
|
|
}
|
|
|
|
var encryptionPayload *sqlserverflex.CreateInstanceRequestPayloadGetEncryptionArgType = nil
|
|
if !model.Encryption.IsNull() && !model.Encryption.IsUnknown() &&
|
|
!model.Encryption.KekKeyId.IsNull() && model.Encryption.KekKeyId.IsUnknown() && model.Encryption.KekKeyId.ValueString() != "" &&
|
|
!model.Encryption.KekKeyRingId.IsNull() && !model.Encryption.KekKeyRingId.IsUnknown() && model.Encryption.KekKeyRingId.ValueString() != "" &&
|
|
!model.Encryption.KekKeyVersion.IsNull() && !model.Encryption.KekKeyVersion.IsUnknown() && model.Encryption.KekKeyVersion.ValueString() != "" &&
|
|
!model.Encryption.ServiceAccount.IsNull() && !model.Encryption.ServiceAccount.IsUnknown() && model.Encryption.ServiceAccount.ValueString() != "" {
|
|
encryptionPayload = &sqlserverflex.CreateInstanceRequestPayloadGetEncryptionArgType{
|
|
KekKeyId: model.Encryption.KekKeyId.ValueStringPointer(),
|
|
KekKeyRingId: model.Encryption.KekKeyVersion.ValueStringPointer(),
|
|
KekKeyVersion: model.Encryption.KekKeyRingId.ValueStringPointer(),
|
|
ServiceAccount: model.Encryption.ServiceAccount.ValueStringPointer(),
|
|
}
|
|
}
|
|
|
|
networkPayload := &sqlserverflex.CreateInstanceRequestPayloadGetNetworkArgType{}
|
|
if !model.Network.IsNull() && !model.Network.IsUnknown() {
|
|
networkPayload.AccessScope = sqlserverflex.CreateInstanceRequestPayloadNetworkGetAccessScopeAttributeType(
|
|
model.Network.AccessScope.ValueStringPointer(),
|
|
)
|
|
|
|
var resList []string
|
|
diags := model.Network.Acl.ElementsAs(ctx, &resList, false)
|
|
if diags.HasError() {
|
|
return nil, fmt.Errorf("error converting network acl list")
|
|
}
|
|
networkPayload.Acl = &resList
|
|
}
|
|
|
|
return &sqlserverflex.CreateInstanceRequestPayload{
|
|
BackupSchedule: conversion.StringValueToPointer(model.BackupSchedule),
|
|
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)),
|
|
}, nil
|
|
}
|
|
|
|
////nolint:unused // TODO: remove if not needed later
|
|
//func toUpdatePartiallyPayload(
|
|
// model *Model,
|
|
// storage *storageModel,
|
|
// network *networkModel,
|
|
//) (*sqlserverflex.UpdateInstancePartiallyRequestPayload, error) {
|
|
// if model == nil {
|
|
// return nil, fmt.Errorf("nil model")
|
|
// }
|
|
//
|
|
// storagePayload := &sqlserverflex.UpdateInstanceRequestPayloadGetStorageArgType{}
|
|
// if storage != nil {
|
|
// storagePayload.Size = conversion.Int64ValueToPointer(storage.Size)
|
|
// }
|
|
//
|
|
// var aclElements []string
|
|
// if network != nil && !network.ACL.IsNull() && !network.ACL.IsUnknown() {
|
|
// aclElements = make([]string, 0, len(network.ACL.Elements()))
|
|
// diags := network.ACL.ElementsAs(context.TODO(), &aclElements, false)
|
|
// if diags.HasError() {
|
|
// return nil, fmt.Errorf("creating network: %w", core.DiagsToError(diags))
|
|
// }
|
|
// }
|
|
//
|
|
// networkPayload := &sqlserverflex.UpdateInstancePartiallyRequestPayloadGetNetworkArgType{}
|
|
// if network != nil {
|
|
// networkPayload.AccessScope = sqlserverflex.UpdateInstancePartiallyRequestPayloadNetworkGetAccessScopeAttributeType(conversion.StringValueToPointer(network.AccessScope))
|
|
// networkPayload.Acl = &aclElements
|
|
// }
|
|
//
|
|
// if model.Replicas.ValueInt64() > math.MaxInt32 {
|
|
// return nil, fmt.Errorf("replica count too big: %d", model.Replicas.ValueInt64())
|
|
// }
|
|
// replCount := int32(model.Replicas.ValueInt64()) // nolint:gosec // check is performed above
|
|
// return &sqlserverflex.UpdateInstancePartiallyRequestPayload{
|
|
// BackupSchedule: conversion.StringValueToPointer(model.BackupSchedule),
|
|
// FlavorId: conversion.StringValueToPointer(model.FlavorId),
|
|
// Name: conversion.StringValueToPointer(model.Name),
|
|
// Network: networkPayload,
|
|
// Replicas: sqlserverflex.UpdateInstancePartiallyRequestPayloadGetReplicasAttributeType(&replCount),
|
|
// RetentionDays: conversion.Int64ValueToPointer(model.RetentionDays),
|
|
// Storage: storagePayload,
|
|
// Version: sqlserverflex.UpdateInstancePartiallyRequestPayloadGetVersionAttributeType(conversion.StringValueToPointer(model.Version)),
|
|
// }, nil
|
|
//}
|
|
|
|
// TODO: check func with his args
|
|
func toUpdatePayload(
|
|
ctx context.Context,
|
|
m *sqlserverflexResGen.InstanceModel,
|
|
resp *resource.UpdateResponse,
|
|
) (*sqlserverflex.UpdateInstanceRequestPayload, error) {
|
|
if m.Replicas.ValueInt64() > math.MaxUint32 {
|
|
return nil, fmt.Errorf("replicas value is too big for uint32")
|
|
}
|
|
replVal := sqlserverflex.Replicas(uint32(m.Replicas.ValueInt64()))
|
|
|
|
var netAcl []string
|
|
diags := m.Network.Acl.ElementsAs(ctx, &netAcl, false)
|
|
resp.Diagnostics.Append(diags...)
|
|
if diags.HasError() {
|
|
return nil, fmt.Errorf("error converting model network acl value")
|
|
}
|
|
return &sqlserverflex.UpdateInstanceRequestPayload{
|
|
BackupSchedule: m.BackupSchedule.ValueStringPointer(),
|
|
FlavorId: m.FlavorId.ValueStringPointer(),
|
|
Name: m.Name.ValueStringPointer(),
|
|
Network: &sqlserverflex.CreateInstanceRequestPayloadNetwork{
|
|
AccessScope: sqlserverflex.CreateInstanceRequestPayloadNetworkGetAccessScopeAttributeType(m.Network.AccessScope.ValueStringPointer()),
|
|
Acl: &netAcl,
|
|
},
|
|
Replicas: &replVal,
|
|
RetentionDays: m.RetentionDays.ValueInt64Pointer(),
|
|
Storage: &sqlserverflex.StorageUpdate{Size: m.Storage.Size.ValueInt64Pointer()},
|
|
Version: sqlserverflex.UpdateInstanceRequestPayloadGetVersionAttributeType(m.Version.ValueStringPointer()),
|
|
}, nil
|
|
}
|