diff --git a/docs/data-sources/postgresflexalpha_instance.md b/docs/data-sources/postgresflexalpha_instance.md index c5c4785d..b7756a9b 100644 --- a/docs/data-sources/postgresflexalpha_instance.md +++ b/docs/data-sources/postgresflexalpha_instance.md @@ -3,12 +3,12 @@ page_title: "stackitprivatepreview_postgresflexalpha_instance Data Source - stackitprivatepreview" subcategory: "" description: |- - Postgres Flex instance data source schema. Must have a region specified in the provider configuration. + --- # stackitprivatepreview_postgresflexalpha_instance (Data Source) -Postgres Flex instance data source schema. Must have a `region` specified in the provider configuration. + ## Example Usage @@ -24,44 +24,31 @@ data "stackitprivatepreview_postgresflexalpha_instance" "example" { ### Required -- `instance_id` (String) ID of the PostgresFlex instance. -- `project_id` (String) STACKIT project ID to which the instance is associated. - -### Optional - -- `region` (String) The resource region. If not defined, the provider region is used. +- `instance_id` (String) The ID of the instance. +- `project_id` (String) The STACKIT project ID. +- `region` (String) The region which should be addressed ### Read-Only -- `backup_schedule` (String) -- `encryption` (Attributes) (see [below for nested schema](#nestedatt--encryption)) -- `flavor_id` (String) -- `id` (String) Terraform's internal data source. ID. It is structured as "`project_id`,`region`,`instance_id`". -- `name` (String) Instance name. -- `network` (Attributes) (see [below for nested schema](#nestedatt--network)) -- `replicas` (Number) -- `retention_days` (Number) -- `storage` (Attributes) (see [below for nested schema](#nestedatt--storage)) -- `version` (String) - - -### Nested Schema for `encryption` - -Read-Only: - -- `key_id` (String) -- `key_version` (String) -- `keyring_id` (String) -- `service_account` (String) - +- `backup_schedule` (String) The schedule for on what time and how often the database backup will be created. The schedule is written as a cron schedule. +- `flavor_id` (String) The id of the instance flavor. +- `id` (String) The ID of the instance. +- `is_deletable` (Boolean) Whether the instance can be deleted or not. +- `name` (String) The name of the instance. +- `network` (Attributes) The access configuration of the instance (see [below for nested schema](#nestedatt--network)) +- `replicas` (Number) How many replicas the instance should have. +- `retention_days` (Number) How long backups are retained. The value can only be between 32 and 365 days. +- `status` (String) The current status of the instance. +- `storage` (Attributes) The object containing information about the storage size and class. (see [below for nested schema](#nestedatt--storage)) +- `version` (String) The Postgres version used for the instance. See [Versions Endpoint](/documentation/postgres-flex-service/version/v3alpha1#tag/Version) for supported version parameters. ### Nested Schema for `network` Read-Only: -- `access_scope` (String) -- `acl` (List of String) The Access Control List (ACL) for the PostgresFlex instance. +- `access_scope` (String) The access scope of the instance. It defines if the instance is public or airgapped. +- `acl` (List of String) List of IPV4 cidr. - `instance_address` (String) - `router_address` (String) @@ -71,5 +58,5 @@ Read-Only: Read-Only: -- `class` (String) -- `size` (Number) +- `performance_class` (String) The storage class for the storage. +- `size` (Number) The storage size in Gigabytes. diff --git a/docs/resources/postgresflexalpha_instance.md b/docs/resources/postgresflexalpha_instance.md index ec20a30e..af2d0d7b 100644 --- a/docs/resources/postgresflexalpha_instance.md +++ b/docs/resources/postgresflexalpha_instance.md @@ -3,12 +3,12 @@ page_title: "stackitprivatepreview_postgresflexalpha_instance Resource - stackitprivatepreview" subcategory: "" description: |- - Postgres Flex instance resource schema. Must have a region specified in the provider configuration. + --- # stackitprivatepreview_postgresflexalpha_instance (Resource) -Postgres Flex instance resource schema. Must have a `region` specified in the provider configuration. + ## Example Usage @@ -42,49 +42,42 @@ import { ### Required -- `backup_schedule` (String) -- `encryption` (Attributes) The encryption block. (see [below for nested schema](#nestedatt--encryption)) -- `flavor_id` (String) -- `name` (String) Instance name. -- `network` (Attributes) The network block configuration. (see [below for nested schema](#nestedatt--network)) -- `project_id` (String) STACKIT project ID to which the instance is associated. -- `replicas` (Number) -- `retention_days` (Number) The days of the retention period. -- `storage` (Attributes) (see [below for nested schema](#nestedatt--storage)) -- `version` (String) The database version used. +- `backup_schedule` (String) The schedule for on what time and how often the database backup will be created. The schedule is written as a cron schedule. +- `flavor_id` (String) The id of the instance flavor. +- `name` (String) The name of the instance. +- `network` (Attributes) The access configuration of the instance (see [below for nested schema](#nestedatt--network)) +- `replicas` (Number) How many replicas the instance should have. +- `retention_days` (Number) How long backups are retained. The value can only be between 32 and 365 days. +- `storage` (Attributes) The object containing information about the storage size and class. (see [below for nested schema](#nestedatt--storage)) +- `version` (String) The Postgres version used for the instance. See [Versions Endpoint](/documentation/postgres-flex-service/version/v3alpha1#tag/Version) for supported version parameters. ### Optional -- `region` (String) The resource region. If not defined, the provider region is used. +- `encryption` (Attributes) The configuration for instance's volume and backup storage encryption. + +⚠️ **Note:** This feature is in private preview. Supplying this object is only permitted for enabled accounts. If your account does not have access, the request will be rejected. (see [below for nested schema](#nestedatt--encryption)) +- `instance_id` (String) The ID of the instance. +- `project_id` (String) The STACKIT project ID. +- `region` (String) The region which should be addressed ### Read-Only -- `id` (String) Terraform's internal resource ID. It is structured as "`project_id`,`region`,`instance_id`". -- `instance_id` (String) ID of the PostgresFlex instance. - - -### Nested Schema for `encryption` - -Required: - -- `key_id` (String) Key ID of the encryption key. -- `key_version` (String) Key version of the encryption key. -- `keyring_id` (String) KeyRing ID of the encryption key. -- `service_account` (String) The service account ID of the service account. - +- `id` (String) The ID of the instance. +- `is_deletable` (Boolean) Whether the instance can be deleted or not. +- `status` (String) The current status of the instance. ### Nested Schema for `network` Required: -- `acl` (List of String) The Access Control List (ACL) for the PostgresFlex instance. +- `acl` (List of String) List of IPV4 cidr. Optional: -- `access_scope` (String) The access scope. (Either SNA or PUBLIC) -- `instance_address` (String) The returned instance address. -- `router_address` (String) The returned router address. +- `access_scope` (String) The access scope of the instance. It defines if the instance is public or airgapped. +- `instance_address` (String) +- `router_address` (String) @@ -92,5 +85,16 @@ Optional: Required: -- `class` (String) The storage class used. -- `size` (Number) The disk size of the storage. +- `performance_class` (String) The storage class for the storage. +- `size` (Number) The storage size in Gigabytes. + + + +### Nested Schema for `encryption` + +Required: + +- `kek_key_id` (String) The encryption-key key identifier +- `kek_key_ring_id` (String) The encryption-key keyring identifier +- `kek_key_version` (String) The encryption-key version +- `service_account` (String) diff --git a/pkg/postgresflexalpha/wait/wait.go b/pkg/postgresflexalpha/wait/wait.go index 5c03789b..2f2e28b5 100644 --- a/pkg/postgresflexalpha/wait/wait.go +++ b/pkg/postgresflexalpha/wait/wait.go @@ -146,6 +146,8 @@ func PartialUpdateInstanceWaitHandler( return false, nil, nil case InstanceStateTerminating: return false, nil, nil + case InstanceStatePending: + return false, nil, nil case InstanceStateSuccess: return true, s, nil case InstanceStateFailed: diff --git a/sample/postgres/postresql.tf b/sample/postgres/postresql.tf index 27595809..89937c4b 100644 --- a/sample/postgres/postresql.tf +++ b/sample/postgres/postresql.tf @@ -9,22 +9,22 @@ data "stackitprivatepreview_postgresflexalpha_flavor" "pgsql_flavor" { resource "stackitprivatepreview_postgresflexalpha_instance" "msh-sna-pe-example" { project_id = var.project_id - name = "msh-sna-pe-example" + name = "mshpetest2" backup_schedule = "0 0 * * *" - retention_days = 33 + retention_days = 45 flavor_id = data.stackitprivatepreview_postgresflexalpha_flavor.pgsql_flavor.flavor_id replicas = 1 storage = { # class = "premium-perf2-stackit" - class = data.stackitprivatepreview_postgresflexalpha_flavor.pgsql_flavor.storage_class + performance_class = data.stackitprivatepreview_postgresflexalpha_flavor.pgsql_flavor.storage_class size = 10 } encryption = { # key_id = stackit_kms_key.key.key_id # keyring_id = stackit_kms_keyring.keyring.keyring_id - key_id = var.key_id - keyring_id = var.keyring_id - key_version = var.key_version + kek_key_id = var.key_id + kek_key_ring_id = var.keyring_id + kek_key_version = var.key_version service_account = var.sa_email } network = { diff --git a/stackit/internal/services/postgresflexalpha/instance/datasource.go b/stackit/internal/services/postgresflexalpha/instance/datasource.go index c08ec8b9..498ce251 100644 --- a/stackit/internal/services/postgresflexalpha/instance/datasource.go +++ b/stackit/internal/services/postgresflexalpha/instance/datasource.go @@ -7,18 +7,13 @@ import ( "github.com/mhenselin/terraform-provider-stackitprivatepreview/pkg/postgresflexalpha" "github.com/mhenselin/terraform-provider-stackitprivatepreview/stackit/internal/conversion" + postgresflexalpha2 "github.com/mhenselin/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/instance/datasources_gen" postgresflexUtils "github.com/mhenselin/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/utils" "github.com/hashicorp/terraform-plugin-framework/datasource" - "github.com/hashicorp/terraform-plugin-framework/schema/validator" - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/mhenselin/terraform-provider-stackitprivatepreview/stackit/internal/core" "github.com/mhenselin/terraform-provider-stackitprivatepreview/stackit/internal/utils" - "github.com/mhenselin/terraform-provider-stackitprivatepreview/stackit/internal/validate" - - "github.com/hashicorp/terraform-plugin-framework/datasource/schema" - "github.com/hashicorp/terraform-plugin-framework/types" ) // Ensure the implementation satisfies the expected interfaces. @@ -38,20 +33,12 @@ type instanceDataSource struct { } // Metadata returns the data source type name. -func (r *instanceDataSource) Metadata( - _ context.Context, - req datasource.MetadataRequest, - resp *datasource.MetadataResponse, -) { +func (r *instanceDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_postgresflexalpha_instance" } // Configure adds the provider configured client to the data source. -func (r *instanceDataSource) Configure( - ctx context.Context, - req datasource.ConfigureRequest, - resp *datasource.ConfigureResponse, -) { +func (r *instanceDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { var ok bool r.providerData, ok = conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics) if !ok { @@ -67,131 +54,13 @@ func (r *instanceDataSource) Configure( } // Schema defines the schema for the data source. -func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { - descriptions := map[string]string{ - "main": "Postgres Flex instance data source schema. Must have a `region` specified in the provider configuration.", - "id": "Terraform's internal data source. 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.", - "acl": "The Access Control List (ACL) for the PostgresFlex instance.", - "region": "The resource region. If not defined, the provider region is used.", - } - - resp.Schema = schema.Schema{ - Description: descriptions["main"], - Attributes: map[string]schema.Attribute{ - "id": schema.StringAttribute{ - Description: descriptions["id"], - Computed: true, - }, - "instance_id": schema.StringAttribute{ - Description: descriptions["instance_id"], - Required: true, - Validators: []validator.String{ - validate.UUID(), - validate.NoSeparator(), - }, - }, - "project_id": schema.StringAttribute{ - Description: descriptions["project_id"], - Required: true, - Validators: []validator.String{ - validate.UUID(), - validate.NoSeparator(), - }, - }, - "name": schema.StringAttribute{ - Description: descriptions["name"], - Computed: true, - }, - "backup_schedule": schema.StringAttribute{ - Computed: true, - }, - "retention_days": schema.Int64Attribute{ - Computed: true, - }, - "flavor_id": schema.StringAttribute{ - Computed: true, - }, - "replicas": schema.Int64Attribute{ - Computed: true, - }, - "storage": schema.SingleNestedAttribute{ - Computed: true, - Attributes: map[string]schema.Attribute{ - "class": schema.StringAttribute{ - Computed: true, - }, - "size": schema.Int64Attribute{ - Computed: true, - }, - }, - }, - "version": schema.StringAttribute{ - Computed: true, - }, - "region": schema.StringAttribute{ - // the region cannot be found, so it has to be passed - Optional: true, - Description: descriptions["region"], - }, - "encryption": schema.SingleNestedAttribute{ - Computed: true, - Attributes: map[string]schema.Attribute{ - "key_id": schema.StringAttribute{ - Description: descriptions["key_id"], - Computed: true, - }, - "key_version": schema.StringAttribute{ - Description: descriptions["key_version"], - Computed: true, - }, - "keyring_id": schema.StringAttribute{ - Description: descriptions["keyring_id"], - Computed: true, - }, - "service_account": schema.StringAttribute{ - Description: descriptions["service_account"], - Computed: true, - }, - }, - Description: descriptions["encryption"], - }, - "network": schema.SingleNestedAttribute{ - Computed: true, - Attributes: map[string]schema.Attribute{ - "access_scope": schema.StringAttribute{ - Description: descriptions["access_scope"], - Computed: true, - }, - "acl": schema.ListAttribute{ - Description: descriptions["acl"], - ElementType: types.StringType, - Computed: true, - }, - "instance_address": schema.StringAttribute{ - Description: descriptions["instance_address"], - Computed: true, - }, - "router_address": schema.StringAttribute{ - Description: descriptions["router_address"], - Computed: true, - }, - }, - Description: descriptions["network"], - }, - }, - } +func (r *instanceDataSource) Schema(ctx context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = postgresflexalpha2.InstanceDataSourceSchema(ctx) } // Read refreshes the Terraform state with the latest data. -func (r *instanceDataSource) Read( - ctx context.Context, - req datasource.ReadRequest, - resp *datasource.ReadResponse, -) { // nolint:gocritic // function signature required by Terraform - var model Model +func (r *instanceDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { // nolint:gocritic // function signature required by Terraform + var model postgresflexalpha2.InstanceModel diags := req.Config.Get(ctx, &model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { @@ -224,43 +93,12 @@ func (r *instanceDataSource) Read( ctx = core.LogResponse(ctx) - var storage = &storageModel{} - if !model.Storage.IsNull() && !model.Storage.IsUnknown() { - diags = model.Storage.As(ctx, storage, basetypes.ObjectAsOptions{}) - resp.Diagnostics.Append(diags...) - if resp.Diagnostics.HasError() { - return - } - } - - var network = &networkModel{} - if !model.Network.IsNull() && !model.Network.IsUnknown() { - diags = model.Network.As(ctx, network, basetypes.ObjectAsOptions{}) - resp.Diagnostics.Append(diags...) - if resp.Diagnostics.HasError() { - return - } - } - - var encryption = &encryptionModel{} - if !model.Encryption.IsNull() && !model.Encryption.IsUnknown() { - diags = model.Encryption.As(ctx, encryption, basetypes.ObjectAsOptions{}) - resp.Diagnostics.Append(diags...) - if resp.Diagnostics.HasError() { - return - } - } - - err = mapFields(ctx, instanceResp, &model, storage, encryption, network, region) + err = mapGetDataInstanceResponseToModel(ctx, &model, instanceResp) if err != nil { - core.LogAndAddError( - ctx, - &resp.Diagnostics, - "Error reading instance", - fmt.Sprintf("Processing API payload: %v", err), - ) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Calling API: %v", err)) return } + // Set refreshed state diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) diff --git a/stackit/internal/services/postgresflexalpha/instance/functions.go b/stackit/internal/services/postgresflexalpha/instance/functions.go index 968eb2da..4bab64aa 100644 --- a/stackit/internal/services/postgresflexalpha/instance/functions.go +++ b/stackit/internal/services/postgresflexalpha/instance/functions.go @@ -3,217 +3,119 @@ package postgresflexalpha import ( "context" "fmt" - "math" "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/types" postgresflex "github.com/mhenselin/terraform-provider-stackitprivatepreview/pkg/postgresflexalpha" - "github.com/mhenselin/terraform-provider-stackitprivatepreview/stackit/internal/conversion" - "github.com/mhenselin/terraform-provider-stackitprivatepreview/stackit/internal/core" + postgresflexalphadatasource "github.com/mhenselin/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/instance/datasources_gen" + postgresflexalpharesource "github.com/mhenselin/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/instance/resources_gen" "github.com/mhenselin/terraform-provider-stackitprivatepreview/stackit/internal/utils" ) -func mapFields( - ctx context.Context, - resp *postgresflex.GetInstanceResponse, - model *Model, - storage *storageModel, - encryption *encryptionModel, - network *networkModel, - region string, -) error { - if resp == nil { - return fmt.Errorf("response input is nil") +func mapGetInstanceResponseToModel(ctx context.Context, m *postgresflexalpharesource.InstanceModel, resp *postgresflex.GetInstanceResponse) error { + m.BackupSchedule = types.StringValue(resp.GetBackupSchedule()) + // need to leave out encryption, as the GetInstance endpoint does not provide it + //m.Encryption = postgresflexalpharesource.NewEncryptionValueMust( + // m.Encryption.AttributeTypes(ctx), + // map[string]attr.Value{ + // "kek_key_id": types.StringValue(resp.Encryption.GetKekKeyId()), + // "kek_key_ring_id": types.StringValue(resp.Encryption.GetKekKeyRingId()), + // "kek_key_version": types.StringValue(resp.Encryption.GetKekKeyVersion()), + // "service_account": types.StringValue(resp.Encryption.GetServiceAccount()), + // }, + //) + m.FlavorId = types.StringValue(resp.GetFlavorId()) + if m.Id.IsNull() || m.Id.IsUnknown() { + m.Id = utils.BuildInternalTerraformId(m.ProjectId.ValueString(), m.Region.ValueString(), m.InstanceId.ValueString()) } - if model == nil { - return fmt.Errorf("model input is nil") - } - instance := resp + m.InstanceId = types.StringPointerValue(resp.Id) + m.IsDeletable = types.BoolValue(resp.GetIsDeletable()) + m.Name = types.StringValue(resp.GetName()) - 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 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) + netAcl, diags := types.ListValueFrom(ctx, types.StringType, resp.Network.GetAcl()) if diags.HasError() { - return fmt.Errorf("creating encryption: %w", core.DiagsToError(diags)) + return fmt.Errorf("failed converting network acl from response") } - 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)) - } - - networkValues = map[string]attr.Value{ - "acl": aclList, - "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) + net, diags := postgresflexalpharesource.NewNetworkValue( + postgresflexalpharesource.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()), + }, + ) if diags.HasError() { - return fmt.Errorf("creating network: %w", core.DiagsToError(diags)) + return fmt.Errorf("failed converting network from response") } - 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.PerformanceClass), - "size": types.Int64PointerValue(instance.Storage.Size), - } - } - storageObject, diags := types.ObjectValue(storageTypes, storageValues) + m.Network = net + m.Replicas = types.Int64Value(int64(resp.GetReplicas())) + m.RetentionDays = types.Int64Value(resp.GetRetentionDays()) + m.Status = types.StringValue(string(resp.GetStatus())) + + storage, diags := postgresflexalpharesource.NewStorageValue( + postgresflexalpharesource.StorageValue{}.AttributeTypes(ctx), + map[string]attr.Value{ + "performance_class": types.StringValue(resp.Storage.GetPerformanceClass()), + "size": types.Int64Value(resp.Storage.GetSize()), + }, + ) if diags.HasError() { - return fmt.Errorf("creating storage: %w", core.DiagsToError(diags)) + return fmt.Errorf("failed converting storage from response") } - - if instance.Replicas == nil { - diags.AddError("error mapping fields", "replicas is nil") - return fmt.Errorf("replicas is nil") - } - - model.Id = utils.BuildInternalTerraformId(model.ProjectId.ValueString(), region, instanceId) - model.InstanceId = types.StringValue(instanceId) - model.Name = types.StringPointerValue(instance.Name) - model.BackupSchedule = types.StringPointerValue(instance.BackupSchedule) - model.FlavorId = types.StringPointerValue(instance.FlavorId) - model.Replicas = types.Int64Value(int64(*instance.Replicas)) - model.Storage = storageObject - model.Version = types.StringPointerValue(instance.Version) - model.Region = types.StringValue(region) - model.Encryption = encryptionObject - model.Network = networkObject + m.Storage = storage + m.Version = types.StringValue(resp.GetVersion()) return nil } -func toCreatePayload( - model *Model, - storage *storageModel, - enc *encryptionModel, - net *networkModel, -) (*postgresflex.CreateInstanceRequestPayload, error) { - if model == nil { - return nil, fmt.Errorf("nil model") - } - if storage == nil { - return nil, fmt.Errorf("nil storage") +func mapGetDataInstanceResponseToModel(ctx context.Context, m *postgresflexalphadatasource.InstanceModel, resp *postgresflex.GetInstanceResponse) error { + m.BackupSchedule = types.StringValue(resp.GetBackupSchedule()) + //m.Encryption = postgresflexalpharesource.EncryptionValue{ + // KekKeyId: types.StringValue(resp.Encryption.GetKekKeyId()), + // KekKeyRingId: types.StringValue(resp.Encryption.GetKekKeyRingId()), + // KekKeyVersion: types.StringValue(resp.Encryption.GetKekKeyVersion()), + // ServiceAccount: types.StringValue(resp.Encryption.GetServiceAccount()), + //} + m.FlavorId = types.StringValue(resp.GetFlavorId()) + m.Id = utils.BuildInternalTerraformId(m.ProjectId.ValueString(), m.Region.ValueString(), m.InstanceId.ValueString()) + m.InstanceId = types.StringPointerValue(resp.Id) + m.IsDeletable = types.BoolValue(resp.GetIsDeletable()) + m.Name = types.StringValue(resp.GetName()) + netAcl, diags := types.ListValueFrom(ctx, types.StringType, resp.Network.GetAcl()) + if diags.HasError() { + return fmt.Errorf("failed converting network acl from response") } - var replVal int32 - if !model.Replicas.IsNull() && !model.Replicas.IsUnknown() { - if model.Replicas.ValueInt64() > math.MaxInt32 { - return nil, fmt.Errorf("replica count too big: %d", model.Replicas.ValueInt64()) - } - replVal = int32(model.Replicas.ValueInt64()) // nolint:gosec // check is performed above - } - - storagePayload := &postgresflex.CreateInstanceRequestPayloadGetStorageArgType{ - PerformanceClass: conversion.StringValueToPointer(storage.Class), - Size: conversion.Int64ValueToPointer(storage.Size), - } - - encryptionPayload := &postgresflex.CreateInstanceRequestPayloadGetEncryptionArgType{} - if enc != nil { - encryptionPayload.KekKeyId = conversion.StringValueToPointer(enc.KeyId) - encryptionPayload.KekKeyVersion = conversion.StringValueToPointer(enc.KeyVersion) - encryptionPayload.KekKeyRingId = conversion.StringValueToPointer(enc.KeyRingId) - encryptionPayload.ServiceAccount = conversion.StringValueToPointer(enc.ServiceAccount) - } - - var aclElements []string - if net != nil && !net.ACL.IsNull() && !net.ACL.IsUnknown() { - aclElements = make([]string, 0, len(net.ACL.Elements())) - diags := net.ACL.ElementsAs(context.TODO(), &aclElements, false) - if diags.HasError() { - return nil, fmt.Errorf("creating network: %w", core.DiagsToError(diags)) - } - } - - if len(aclElements) < 1 { - return nil, fmt.Errorf("no acl elements found") - } - - networkPayload := &postgresflex.CreateInstanceRequestPayloadGetNetworkArgType{} - if net != nil { - networkPayload = &postgresflex.CreateInstanceRequestPayloadGetNetworkArgType{ - AccessScope: postgresflex.InstanceNetworkGetAccessScopeAttributeType(conversion.StringValueToPointer(net.AccessScope)), - Acl: &aclElements, - } - } - - return &postgresflex.CreateInstanceRequestPayload{ - Acl: &aclElements, - BackupSchedule: conversion.StringValueToPointer(model.BackupSchedule), - Encryption: encryptionPayload, - FlavorId: conversion.StringValueToPointer(model.FlavorId), - Name: conversion.StringValueToPointer(model.Name), - Network: networkPayload, - Replicas: postgresflex.CreateInstanceRequestPayloadGetReplicasAttributeType(&replVal), - RetentionDays: conversion.Int64ValueToPointer(model.RetentionDays), - Storage: storagePayload, - Version: conversion.StringValueToPointer(model.Version), - }, nil -} - -func toUpdatePayload( - model *Model, - storage *storageModel, - _ *networkModel, -) (*postgresflex.UpdateInstancePartiallyRequestPayload, error) { - if model == nil { - return nil, fmt.Errorf("nil model") - } - if storage == nil { - return nil, fmt.Errorf("nil storage") - } - - return &postgresflex.UpdateInstancePartiallyRequestPayload{ - // Acl: postgresflexalpha.UpdateInstancePartiallyRequestPayloadGetAclAttributeType{ - // Items: &acl, - // }, - BackupSchedule: conversion.StringValueToPointer(model.BackupSchedule), - FlavorId: conversion.StringValueToPointer(model.FlavorId), - Name: conversion.StringValueToPointer(model.Name), - // Replicas: conversion.Int64ValueToPointer(model.Replicas), - Storage: &postgresflex.StorageUpdate{ - Size: conversion.Int64ValueToPointer(storage.Size), + net, diags := postgresflexalphadatasource.NewNetworkValue( + postgresflexalphadatasource.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()), }, - Version: conversion.StringValueToPointer(model.Version), - }, nil + ) + if diags.HasError() { + return fmt.Errorf("failed converting network from response") + } + + m.Network = net + m.Replicas = types.Int64Value(int64(resp.GetReplicas())) + m.RetentionDays = types.Int64Value(resp.GetRetentionDays()) + m.Status = types.StringValue(string(resp.GetStatus())) + storage, diags := postgresflexalphadatasource.NewStorageValue( + postgresflexalphadatasource.StorageValue{}.AttributeTypes(ctx), + map[string]attr.Value{ + "performance_class": types.StringValue(resp.Storage.GetPerformanceClass()), + "size": types.Int64Value(resp.Storage.GetSize()), + }, + ) + if diags.HasError() { + return fmt.Errorf("failed converting storage from response") + } + m.Storage = storage + m.Version = types.StringValue(resp.GetVersion()) + return nil } diff --git a/stackit/internal/services/postgresflexalpha/instance/resource.go b/stackit/internal/services/postgresflexalpha/instance/resource.go index 1c243826..748d5c98 100644 --- a/stackit/internal/services/postgresflexalpha/instance/resource.go +++ b/stackit/internal/services/postgresflexalpha/instance/resource.go @@ -3,32 +3,24 @@ package postgresflexalpha import ( "context" "fmt" + "math" "net/http" - "regexp" "strings" - "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/resource/schema/listplanmodifier" - "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" - "github.com/hashicorp/terraform-plugin-framework/schema/validator" - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" - "github.com/hashicorp/terraform-plugin-log/tflog" - "github.com/mhenselin/terraform-provider-stackitprivatepreview/stackit/internal/conversion" - "github.com/mhenselin/terraform-provider-stackitprivatepreview/stackit/internal/core" - "github.com/mhenselin/terraform-provider-stackitprivatepreview/stackit/internal/utils" - "github.com/mhenselin/terraform-provider-stackitprivatepreview/stackit/internal/validate" - "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" + postgresflex "github.com/mhenselin/terraform-provider-stackitprivatepreview/pkg/postgresflexalpha" + "github.com/mhenselin/terraform-provider-stackitprivatepreview/pkg/postgresflexalpha/wait" + "github.com/mhenselin/terraform-provider-stackitprivatepreview/stackit/internal/conversion" + "github.com/mhenselin/terraform-provider-stackitprivatepreview/stackit/internal/core" + postgresflexalpha "github.com/mhenselin/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/instance/resources_gen" + postgresflexUtils "github.com/mhenselin/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/utils" + "github.com/mhenselin/terraform-provider-stackitprivatepreview/stackit/internal/utils" "github.com/stackitcloud/stackit-sdk-go/core/oapierror" ) @@ -53,12 +45,9 @@ type instanceResource struct { providerData core.ProviderData } -func (r *instanceResource) ValidateConfig( - ctx context.Context, - req resource.ValidateConfigRequest, - resp *resource.ValidateConfigResponse, -) { - var data Model +func (r *instanceResource) ValidateConfig(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) { + var data postgresflexalpha.InstanceModel + // var data Model resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) if resp.Diagnostics.HasError() { @@ -77,12 +66,9 @@ func (r *instanceResource) ValidateConfig( // ModifyPlan implements resource.ResourceWithModifyPlan. // Use the modifier to set the effective region in the current plan. -func (r *instanceResource) ModifyPlan( - ctx context.Context, - req resource.ModifyPlanRequest, - resp *resource.ModifyPlanResponse, -) { // nolint:gocritic // function signature required by Terraform - var configModel Model +func (r *instanceResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { // nolint:gocritic // function signature required by Terraform + var configModel postgresflexalpha.InstanceModel + // var configModel Model // skip initial empty configuration to avoid follow-up errors if req.Config.Raw.IsNull() { return @@ -92,7 +78,8 @@ func (r *instanceResource) ModifyPlan( return } - var planModel Model + var planModel postgresflexalpha.InstanceModel + // var planModel Model resp.Diagnostics.Append(req.Plan.Get(ctx, &planModel)...) if resp.Diagnostics.HasError() { return @@ -135,243 +122,19 @@ func (r *instanceResource) Configure( } // Schema defines the schema for the resource. -func (r *instanceResource) Schema(_ context.Context, _ 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_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{ - Description: descriptions["main"], - Attributes: map[string]schema.Attribute{ - "id": schema.StringAttribute{ - Description: descriptions["id"], - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "instance_id": schema.StringAttribute{ - Description: descriptions["instance_id"], - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - Validators: []validator.String{ - validate.UUID(), - validate.NoSeparator(), - }, - }, - "project_id": schema.StringAttribute{ - Description: descriptions["project_id"], - Required: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - stringplanmodifier.UseStateForUnknown(), - }, - Validators: []validator.String{ - validate.UUID(), - validate.NoSeparator(), - }, - }, - "name": schema.StringAttribute{ - Description: descriptions["name"], - Required: true, - Validators: []validator.String{ - stringvalidator.LengthAtLeast(1), - stringvalidator.RegexMatches( - regexp.MustCompile("^[a-z]([-a-z0-9]*[a-z0-9])?$"), - "must start with a letter, must have lower case letters, numbers or hyphens, and no hyphen at the end", - ), - }, - }, - "backup_schedule": schema.StringAttribute{ - Required: true, - }, - "retention_days": schema.Int64Attribute{ - Description: descriptions["retention_days"], - Required: true, - }, - "flavor_id": schema.StringAttribute{ - Required: true, - }, - "replicas": schema.Int64Attribute{ - Required: true, - PlanModifiers: []planmodifier.Int64{ - int64planmodifier.RequiresReplace(), - }, - }, - "storage": schema.SingleNestedAttribute{ - Required: true, - Attributes: map[string]schema.Attribute{ - "class": schema.StringAttribute{ - Required: true, - Description: descriptions["storage_class"], - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, - }, - "size": schema.Int64Attribute{ - Description: descriptions["storage_size"], - Required: true, - // PlanModifiers: []planmodifier.Int64{ - // TODO - req replace if new size smaller than state size - // int64planmodifier.RequiresReplaceIf(), - // }, - }, - }, - }, - "version": schema.StringAttribute{ - Description: descriptions["version"], - Required: true, - }, - "region": schema.StringAttribute{ - Optional: true, - // must be computed to allow for storing the override value from the provider - Computed: true, - Description: descriptions["region"], - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, - }, - "encryption": schema.SingleNestedAttribute{ - Required: true, - Attributes: map[string]schema.Attribute{ - "key_id": schema.StringAttribute{ - Description: descriptions["key_id"], - Required: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, - Validators: []validator.String{ - validate.NoSeparator(), - }, - }, - "key_version": schema.StringAttribute{ - Description: descriptions["key_version"], - Required: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, - Validators: []validator.String{ - validate.NoSeparator(), - }, - }, - "keyring_id": schema.StringAttribute{ - Description: descriptions["keyring_id"], - Required: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, - Validators: []validator.String{ - validate.NoSeparator(), - }, - }, - "service_account": schema.StringAttribute{ - Description: descriptions["service_account"], - Required: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, - Validators: []validator.String{ - validate.NoSeparator(), - }, - }, - }, - Description: descriptions["encryption"], - //Validators: nil, - PlanModifiers: []planmodifier.Object{}, - }, - "network": schema.SingleNestedAttribute{ - Required: true, - Attributes: map[string]schema.Attribute{ - "access_scope": schema.StringAttribute{ - Default: stringdefault.StaticString( - "PUBLIC", - ), - Description: descriptions["access_scope"], - Computed: true, - Optional: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - stringplanmodifier.UseStateForUnknown(), - }, - Validators: []validator.String{ - validate.NoSeparator(), - stringvalidator.OneOf("SNA", "PUBLIC"), - }, - }, - "acl": schema.ListAttribute{ - Description: descriptions["acl"], - ElementType: types.StringType, - Required: true, - PlanModifiers: []planmodifier.List{ - listplanmodifier.UseStateForUnknown(), - }, - }, - "instance_address": schema.StringAttribute{ - Description: descriptions["instance_address"], - Computed: true, - Optional: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "router_address": schema.StringAttribute{ - Description: descriptions["router_address"], - Computed: true, - Optional: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - }, - Description: descriptions["network"], - //MarkdownDescription: "", - //Validators: nil, - PlanModifiers: []planmodifier.Object{}, - }, - }, - } +func (r *instanceResource) Schema(ctx context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = postgresflexalpha.InstanceResourceSchema(ctx) + resp.Schema = addPlanModifiers(resp.Schema) } -// 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 -// }, -// }, -// } -//} +func addPlanModifiers(s schema.Schema) schema.Schema { + attr := s.Attributes["backup_schedule"].(schema.StringAttribute) + attr.PlanModifiers = []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + } + s.Attributes["backup_schedule"] = attr + return s +} // Create creates the resource and sets the initial Terraform state. func (r *instanceResource) Create( @@ -379,7 +142,8 @@ func (r *instanceResource) Create( req resource.CreateRequest, resp *resource.CreateResponse, ) { // nolint:gocritic // function signature required by Terraform - var model Model + var model postgresflexalpha.InstanceModel + //var model Model diags := req.Plan.Get(ctx, &model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { @@ -393,59 +157,22 @@ func (r *instanceResource) Create( ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "region", region) - var storage = &storageModel{} - if !model.Storage.IsNull() && !model.Storage.IsUnknown() { - diags = model.Storage.As(ctx, storage, basetypes.ObjectAsOptions{}) - resp.Diagnostics.Append(diags...) - if resp.Diagnostics.HasError() { - return - } - } - - var encryption = &encryptionModel{} - if !model.Encryption.IsNull() && !model.Encryption.IsUnknown() { - diags = model.Encryption.As(ctx, encryption, basetypes.ObjectAsOptions{}) - resp.Diagnostics.Append(diags...) - if resp.Diagnostics.HasError() { - return - } - } - - var network = &networkModel{} - if !model.Network.IsNull() && !model.Network.IsUnknown() { - diags = model.Network.As(ctx, network, basetypes.ObjectAsOptions{}) - resp.Diagnostics.Append(diags...) - if resp.Diagnostics.HasError() { - return - } - } - - var acl []string - if !network.ACL.IsNull() && !network.ACL.IsUnknown() { - diags = network.ACL.ElementsAs(ctx, &acl, false) - resp.Diagnostics.Append(diags...) - if resp.Diagnostics.HasError() { - return - } - } - - // Generate API request body from model - 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), - ) + var netAcl []string + diag := model.Network.Acl.ElementsAs(ctx, &netAcl, false) + resp.Diagnostics.Append(diags...) + if diag.HasError() { return } + + if model.Replicas.ValueInt64() > math.MaxInt32 { + resp.Diagnostics.AddError("invalid int32 value", "provided int64 value does not fit into int32") + return + } + replVal := int32(model.Replicas.ValueInt64()) // nolint:gosec // check is performed above + payload := modelToCreateInstancePayload(netAcl, model, replVal) + // Create new instance - createResp, err := r.client.CreateInstanceRequest( - ctx, - projectId, - region, - ).CreateInstanceRequestPayload(*payload).Execute() + createResp, err := r.client.CreateInstanceRequest(ctx, projectId, region).CreateInstanceRequestPayload(payload).Execute() if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Calling API: %v", err)) return @@ -463,26 +190,16 @@ func (r *instanceResource) Create( waitResp, err := wait.CreateInstanceWaitHandler(ctx, r.client, projectId, region, instanceId).WaitWithContext(ctx) if err != nil { - core.LogAndAddError( - ctx, - &resp.Diagnostics, - "Error creating instance", - fmt.Sprintf("Wait handler error: %v", err), - ) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Wait handler error: %v", err)) return } - // Map response body to schema - err = mapFields(ctx, waitResp, &model, storage, encryption, network, region) + err = mapGetInstanceResponseToModel(ctx, &model, waitResp) if err != nil { - core.LogAndAddError( - ctx, - &resp.Diagnostics, - "Error creating instance", - fmt.Sprintf("Processing API payload: %v", err), - ) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Error creating model: %v", err)) return } + // Set state to fully populated data diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) @@ -492,13 +209,41 @@ func (r *instanceResource) Create( tflog.Info(ctx, "Postgres Flex instance created") } +func modelToCreateInstancePayload(netAcl []string, model postgresflexalpha.InstanceModel, replVal int32) postgresflex.CreateInstanceRequestPayload { + payload := postgresflex.CreateInstanceRequestPayload{ + Acl: &netAcl, + BackupSchedule: model.BackupSchedule.ValueStringPointer(), + Encryption: &postgresflex.InstanceEncryption{ + KekKeyId: model.Encryption.KekKeyId.ValueStringPointer(), + KekKeyRingId: model.Encryption.KekKeyRingId.ValueStringPointer(), + KekKeyVersion: model.Encryption.KekKeyVersion.ValueStringPointer(), + ServiceAccount: model.Encryption.ServiceAccount.ValueStringPointer(), + }, + FlavorId: model.FlavorId.ValueStringPointer(), + Name: model.Name.ValueStringPointer(), + Network: &postgresflex.InstanceNetwork{ + AccessScope: postgresflex.InstanceNetworkGetAccessScopeAttributeType( + model.Network.AccessScope.ValueStringPointer(), + ), + Acl: &netAcl, + InstanceAddress: model.Network.InstanceAddress.ValueStringPointer(), + RouterAddress: model.Network.RouterAddress.ValueStringPointer(), + }, + Replicas: postgresflex.CreateInstanceRequestPayloadGetReplicasAttributeType(&replVal), + RetentionDays: model.RetentionDays.ValueInt64Pointer(), + Storage: &postgresflex.StorageCreate{ + PerformanceClass: model.Storage.PerformanceClass.ValueStringPointer(), + Size: model.Storage.Size.ValueInt64Pointer(), + }, + Version: model.Version.ValueStringPointer(), + } + return payload +} + // Read refreshes the Terraform state with the latest data. -func (r *instanceResource) Read( - ctx context.Context, - req resource.ReadRequest, - resp *resource.ReadResponse, -) { // nolint:gocritic // function signature required by Terraform - var model Model +func (r *instanceResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform + var model postgresflexalpha.InstanceModel + //var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { @@ -514,33 +259,6 @@ func (r *instanceResource) Read( ctx = tflog.SetField(ctx, "instance_id", instanceId) ctx = tflog.SetField(ctx, "region", region) - var storage = storageModel{} - if !model.Storage.IsNull() && !model.Storage.IsUnknown() { - diags = model.Storage.As(ctx, &storage, basetypes.ObjectAsOptions{}) - resp.Diagnostics.Append(diags...) - if resp.Diagnostics.HasError() { - return - } - } - - var network = networkModel{} - if !model.Network.IsNull() && !model.Network.IsUnknown() { - diags = model.Network.As(ctx, &network, basetypes.ObjectAsOptions{}) - resp.Diagnostics.Append(diags...) - if resp.Diagnostics.HasError() { - return - } - } - - var encryption = encryptionModel{} - if !model.Encryption.IsNull() && !model.Encryption.IsUnknown() { - diags = model.Encryption.As(ctx, &encryption, basetypes.ObjectAsOptions{}) - resp.Diagnostics.Append(diags...) - if resp.Diagnostics.HasError() { - return - } - } - instanceResp, err := r.client.GetInstanceRequest(ctx, projectId, region, instanceId).Execute() if err != nil { oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped @@ -554,15 +272,9 @@ func (r *instanceResource) Read( ctx = core.LogResponse(ctx) - // Map response body to schema - err = mapFields(ctx, instanceResp, &model, &storage, &encryption, &network, region) + err = mapGetInstanceResponseToModel(ctx, &model, instanceResp) if err != nil { - core.LogAndAddError( - ctx, - &resp.Diagnostics, - "Error reading instance", - fmt.Sprintf("Processing API payload: %v", err), - ) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Processing API payload: %v", err)) return } @@ -576,12 +288,9 @@ func (r *instanceResource) 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 - var model Model +func (r *instanceResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform + var model postgresflexalpha.InstanceModel + //var model Model diags := req.Plan.Get(ctx, &model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { @@ -597,61 +306,38 @@ func (r *instanceResource) Update( ctx = tflog.SetField(ctx, "instance_id", instanceId) ctx = tflog.SetField(ctx, "region", region) - // nolint:gocritic // need that code later - // var acl []string - // if !(model.ACL.IsNull() || model.ACL.IsUnknown()) { - // diags = model.ACL.ElementsAs(ctx, &acl, false) - // 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{}) - resp.Diagnostics.Append(diags...) - if resp.Diagnostics.HasError() { - return - } - } - - var network = &networkModel{} - if !model.Network.IsNull() && !model.Network.IsUnknown() { - diags = model.Network.As(ctx, network, basetypes.ObjectAsOptions{}) - resp.Diagnostics.Append(diags...) - if resp.Diagnostics.HasError() { - return - } - } - - var encryption = &encryptionModel{} - if !model.Encryption.IsNull() && !model.Encryption.IsUnknown() { - diags = model.Encryption.As(ctx, encryption, basetypes.ObjectAsOptions{}) - resp.Diagnostics.Append(diags...) - if resp.Diagnostics.HasError() { - return - } - } - - // Generate API request body from model - payload, err := toUpdatePayload(&model, storage, network) - if err != nil { - core.LogAndAddError( - ctx, - &resp.Diagnostics, - "Error updating instance", - fmt.Sprintf("Creating API payload: %v", err), - ) + var netAcl []string + diag := model.Network.Acl.ElementsAs(ctx, &netAcl, false) + resp.Diagnostics.Append(diags...) + if diag.HasError() { return } + replInt32 := int32(model.Replicas.ValueInt64()) + payload := postgresflex.UpdateInstancePartiallyRequestPayload{ + BackupSchedule: model.BackupSchedule.ValueStringPointer(), + FlavorId: model.FlavorId.ValueStringPointer(), + Name: model.Name.ValueStringPointer(), + Network: &postgresflex.InstanceNetwork{ + AccessScope: postgresflex.InstanceNetworkGetAccessScopeAttributeType( + model.Network.AccessScope.ValueStringPointer(), + ), + Acl: &netAcl, + }, + Replicas: postgresflex.UpdateInstancePartiallyRequestPayloadGetReplicasAttributeType(&replInt32), + RetentionDays: model.RetentionDays.ValueInt64Pointer(), + Storage: &postgresflex.StorageUpdate{ + Size: model.Storage.Size.ValueInt64Pointer(), + }, + Version: model.Version.ValueStringPointer(), + } + // Update existing instance - err = r.client.UpdateInstancePartiallyRequest( + err := r.client.UpdateInstancePartiallyRequest( ctx, projectId, region, instanceId, - ).UpdateInstancePartiallyRequestPayload(*payload).Execute() + ).UpdateInstancePartiallyRequestPayload(payload).Execute() if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", err.Error()) return @@ -659,34 +345,18 @@ func (r *instanceResource) Update( ctx = core.LogResponse(ctx) - waitResp, err := wait.PartialUpdateInstanceWaitHandler( - ctx, - r.client, - projectId, - region, - instanceId, - ).WaitWithContext(ctx) + waitResp, err := wait.PartialUpdateInstanceWaitHandler(ctx, r.client, projectId, region, instanceId).WaitWithContext(ctx) if err != nil { - core.LogAndAddError( - ctx, - &resp.Diagnostics, - "Error updating instance", - fmt.Sprintf("Instance update waiting: %v", err), - ) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Instance update waiting: %v", err)) return } - // Map response body to schema - err = mapFields(ctx, waitResp, &model, storage, encryption, network, region) + err = mapGetInstanceResponseToModel(ctx, &model, waitResp) if err != nil { - core.LogAndAddError( - ctx, - &resp.Diagnostics, - "Error updating instance", - fmt.Sprintf("Processing API payload: %v", err), - ) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Processing API payload: %v", err)) return } + diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { @@ -696,12 +366,9 @@ func (r *instanceResource) Update( } // 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 - var model Model +func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform + var model postgresflexalpha.InstanceModel + //var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { @@ -741,16 +408,11 @@ func (r *instanceResource) Delete( // ImportState imports a resource into the Terraform state on success. // The expected format of the resource import identifier is: project_id,instance_id -func (r *instanceResource) ImportState( - ctx context.Context, - req resource.ImportStateRequest, - resp *resource.ImportStateResponse, -) { +func (r *instanceResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { - core.LogAndAddError( - ctx, &resp.Diagnostics, + core.LogAndAddError(ctx, &resp.Diagnostics, "Error importing instance", fmt.Sprintf("Expected import identifier with format: [project_id],[region],[instance_id] Got: %q", req.ID), ) diff --git a/stackit/internal/services/postgresflexalpha/instance/resource_test.go b/stackit/internal/services/postgresflexalpha/instance/resource_test.go index 781a96be..46d935a5 100644 --- a/stackit/internal/services/postgresflexalpha/instance/resource_test.go +++ b/stackit/internal/services/postgresflexalpha/instance/resource_test.go @@ -1,16 +1,10 @@ package postgresflexalpha import ( - "context" "reflect" "testing" - "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/resource" - "github.com/hashicorp/terraform-plugin-framework/types" - postgresflex "github.com/mhenselin/terraform-provider-stackitprivatepreview/pkg/postgresflexalpha" - "github.com/stackitcloud/stackit-sdk-go/core/utils" ) // type postgresFlexClientMocked struct { @@ -26,608 +20,6 @@ import ( // return c.getFlavorsResp, nil // } -func TestMapFields(t *testing.T) { - const testRegion = "region" - tests := []struct { - description string - state Model - input *postgresflex.GetInstanceResponse - storage *storageModel - encryption *encryptionModel - network *networkModel - region string - expected Model - isValid bool - }{ - { - "default_values does exactly mean what?", - Model{ - InstanceId: types.StringValue("iid"), - ProjectId: types.StringValue("pid"), - Replicas: types.Int64Value(1), - }, - &postgresflex.GetInstanceResponse{ - FlavorId: utils.Ptr("flavor_id"), - Replicas: postgresflex.GetInstanceResponseGetReplicasAttributeType(utils.Ptr(int32(1))), - }, - &storageModel{}, - &encryptionModel{}, - &networkModel{ - ACL: types.ListValueMust( - types.StringType, []attr.Value{ - types.StringValue("0.0.0.0/0"), - }, - ), - }, - testRegion, - Model{ - Id: types.StringValue("pid,region,iid"), - InstanceId: types.StringValue("iid"), - ProjectId: types.StringValue("pid"), - Name: types.StringNull(), - FlavorId: types.StringValue("flavor_id"), - //ACL: types.ListNull(types.StringType), - BackupSchedule: types.StringNull(), - Replicas: types.Int64Value(1), - Encryption: types.ObjectValueMust( - encryptionTypes, map[string]attr.Value{ - "keyring_id": types.StringNull(), - "key_id": types.StringNull(), - "key_version": types.StringNull(), - "service_account": types.StringNull(), - }, - ), - Storage: types.ObjectValueMust( - storageTypes, map[string]attr.Value{ - "class": types.StringNull(), - "size": types.Int64Null(), - }, - ), - Network: types.ObjectValueMust( - networkTypes, map[string]attr.Value{ - "acl": types.ListValueMust( - types.StringType, []attr.Value{ - types.StringValue("0.0.0.0/0"), - }, - ), - "access_scope": types.StringNull(), - "instance_address": types.StringNull(), - "router_address": types.StringNull(), - }, - ), - Version: types.StringNull(), - Region: types.StringValue(testRegion), - }, - true, - }, - // { - // "acl_unordered", - // Model{ - // InstanceId: types.StringValue("iid"), - // ProjectId: types.StringValue("pid"), - // // ACL: types.ListValueMust(types.StringType, []attr.Value{ - // // types.StringValue("ip2"), - // // types.StringValue(""), - // // types.StringValue("ip1"), - // // }), - // }, - // &postgresflex.GetInstanceResponse{ - // // Acl: &[]string{ - // // "", - // // "ip1", - // // "ip2", - // // }, - // BackupSchedule: utils.Ptr("schedule"), - // FlavorId: nil, - // Id: utils.Ptr("iid"), - // Name: utils.Ptr("name"), - // Replicas: postgresflex.GetInstanceResponseGetReplicasAttributeType(utils.Ptr(int32(56))), - // Status: postgresflex.GetInstanceResponseGetStatusAttributeType(utils.Ptr("status")), - // Storage: nil, - // Version: utils.Ptr("version"), - // }, - // &flavorModel{ - // CPU: types.Int64Value(12), - // RAM: types.Int64Value(34), - // }, - // &storageModel{ - // Class: types.StringValue("class"), - // Size: types.Int64Value(78), - // }, - // &encryptionModel{}, - // &networkModel{}, - // testRegion, - // Model{ - // Id: types.StringValue("pid,region,iid"), - // InstanceId: types.StringValue("iid"), - // ProjectId: types.StringValue("pid"), - // Name: types.StringValue("name"), - // // ACL: types.ListValueMust(types.StringType, []attr.Value{ - // // types.StringValue("ip2"), - // // types.StringValue(""), - // // types.StringValue("ip1"), - // // }), - // BackupSchedule: types.StringValue("schedule"), - // Flavor: types.ObjectValueMust(flavorTypes, map[string]attr.Value{ - // "id": types.StringNull(), - // "description": types.StringNull(), - // "cpu": types.Int64Value(12), - // "ram": types.Int64Value(34), - // }), - // Replicas: types.Int64Value(56), - // Storage: types.ObjectValueMust(storageTypes, map[string]attr.Value{ - // "class": types.StringValue("class"), - // "size": types.Int64Value(78), - // }), - // Version: types.StringValue("version"), - // Region: types.StringValue(testRegion), - // }, - // true, - // }, - { - "nil_response", - Model{ - InstanceId: types.StringValue("iid"), - ProjectId: types.StringValue("pid"), - }, - nil, - &storageModel{}, - &encryptionModel{}, - &networkModel{}, - testRegion, - Model{}, - false, - }, - { - "no_resource_id", - Model{ - InstanceId: types.StringValue("iid"), - ProjectId: types.StringValue("pid"), - }, - &postgresflex.GetInstanceResponse{}, - &storageModel{}, - &encryptionModel{}, - &networkModel{}, - testRegion, - Model{}, - false, - }, - } - for _, tt := range tests { - t.Run( - tt.description, func(t *testing.T) { - 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") - } - if tt.isValid && err != nil { - t.Fatalf("Should not have failed: %v", err) - } - if tt.isValid { - diff := cmp.Diff(tt.expected, tt.state) - if diff != "" { - t.Fatalf("Data does not match: %s", diff) - } - } - }, - ) - } -} - -func TestToCreatePayload(t *testing.T) { - tests := []struct { - description string - input *Model - inputAcl []string - inputStorage *storageModel - inputEncryption *encryptionModel - inputNetwork *networkModel - expected *postgresflex.CreateInstanceRequestPayload - isValid bool - }{ - { - "default_values", - &Model{ - Replicas: types.Int64Value(1), - }, - []string{}, - &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, - }, - { - "nil_model", - nil, - []string{}, - &storageModel{}, - &encryptionModel{}, - &networkModel{}, - nil, - false, - }, - { - "nil_acl", - &Model{}, - nil, - &storageModel{}, - &encryptionModel{}, - &networkModel{}, - nil, - false, - }, - { - "nil_flavor", - &Model{}, - []string{}, - &storageModel{}, - &encryptionModel{}, - &networkModel{}, - nil, - false, - }, - { - "nil_storage", - &Model{}, - []string{}, - nil, - &encryptionModel{}, - &networkModel{}, - nil, - false, - }, - } - for _, tt := range tests { - t.Run( - tt.description, func(t *testing.T) { - output, err := toCreatePayload(tt.input, tt.inputStorage, tt.inputEncryption, tt.inputNetwork) - if !tt.isValid && err == nil { - t.Fatalf("Should have failed") - } - if tt.isValid && err != nil { - t.Fatalf("Should not have failed: %v", err) - } - if tt.isValid { - diff := cmp.Diff(tt.expected, output) - if diff != "" { - t.Fatalf("Data does not match: %s", diff) - } - } - }, - ) - } -} - -// func TestToUpdatePayload(t *testing.T) { -// tests := []struct { -// description string -// input *Model -// inputAcl []string -// inputFlavor *flavorModel -// inputStorage *storageModel -// expected *postgresflex.PartialUpdateInstancePayload -// isValid bool -// }{ -// { -// "default_values", -// &Model{}, -// []string{}, -// &flavorModel{}, -// &storageModel{}, -// &postgresflex.PartialUpdateInstancePayload{ -// Acl: &postgresflex.ACL{ -// Items: &[]string{}, -// }, -// Storage: &postgresflex.Storage{}, -// }, -// true, -// }, -// { -// "simple_values", -// &Model{ -// BackupSchedule: types.StringValue("schedule"), -// Name: types.StringValue("name"), -// Replicas: types.Int64Value(12), -// Version: types.StringValue("version"), -// }, -// []string{ -// "ip_1", -// "ip_2", -// }, -// &flavorModel{ -// Id: types.StringValue("flavor_id"), -// }, -// &storageModel{ -// Class: types.StringValue("class"), -// Size: types.Int64Value(34), -// }, -// &postgresflex.PartialUpdateInstancePayload{ -// Acl: &postgresflex.ACL{ -// Items: &[]string{ -// "ip_1", -// "ip_2", -// }, -// }, -// BackupSchedule: utils.Ptr("schedule"), -// FlavorId: utils.Ptr("flavor_id"), -// Name: utils.Ptr("name"), -// Replicas: utils.Ptr(int64(12)), -// Storage: &postgresflex.Storage{ -// Class: utils.Ptr("class"), -// Size: utils.Ptr(int64(34)), -// }, -// Version: utils.Ptr("version"), -// }, -// true, -// }, -// { -// "null_fields_and_int_conversions", -// &Model{ -// BackupSchedule: types.StringNull(), -// Name: types.StringNull(), -// Replicas: types.Int64Value(2123456789), -// Version: types.StringNull(), -// }, -// []string{ -// "", -// }, -// &flavorModel{ -// Id: types.StringNull(), -// }, -// &storageModel{ -// Class: types.StringNull(), -// Size: types.Int64Null(), -// }, -// &postgresflex.PartialUpdateInstancePayload{ -// Acl: &postgresflex.ACL{ -// Items: &[]string{ -// "", -// }, -// }, -// BackupSchedule: nil, -// FlavorId: nil, -// Name: nil, -// Replicas: utils.Ptr(int64(2123456789)), -// Storage: &postgresflex.Storage{ -// Class: nil, -// Size: nil, -// }, -// Version: nil, -// }, -// true, -// }, -// { -// "nil_model", -// nil, -// []string{}, -// &flavorModel{}, -// &storageModel{}, -// nil, -// false, -// }, -// { -// "nil_acl", -// &Model{}, -// nil, -// &flavorModel{}, -// &storageModel{}, -// nil, -// false, -// }, -// { -// "nil_flavor", -// &Model{}, -// []string{}, -// nil, -// &storageModel{}, -// nil, -// false, -// }, -// { -// "nil_storage", -// &Model{}, -// []string{}, -// &flavorModel{}, -// nil, -// nil, -// false, -// }, -// } -// for _, tt := range tests { -// t.Run(tt.description, func(t *testing.T) { -// output, err := toUpdatePayload(tt.input, tt.inputAcl, tt.inputFlavor, tt.inputStorage) -// if !tt.isValid && err == nil { -// t.Fatalf("Should have failed") -// } -// if tt.isValid && err != nil { -// t.Fatalf("Should not have failed: %v", err) -// } -// if tt.isValid { -// diff := cmp.Diff(output, tt.expected) -// if diff != "" { -// t.Fatalf("Data does not match: %s", diff) -// } -// } -// }) -// } -// } -// -// func TestLoadFlavorId(t *testing.T) { -// tests := []struct { -// description string -// inputFlavor *flavorModel -// mockedResp *postgresflex.ListFlavorsResponse -// expected *flavorModel -// getFlavorsFails bool -// isValid bool -// }{ -// { -// "ok_flavor", -// &flavorModel{ -// CPU: types.Int64Value(2), -// RAM: types.Int64Value(8), -// }, -// &postgresflex.ListFlavorsResponse{ -// Flavors: &[]postgresflex.Flavor{ -// { -// Id: utils.Ptr("fid-1"), -// Cpu: utils.Ptr(int64(2)), -// Description: utils.Ptr("description"), -// Ram: utils.Ptr(int64(8)), -// }, -// }, -// }, -// &flavorModel{ -// Id: types.StringValue("fid-1"), -// Description: types.StringValue("description"), -// CPU: types.Int64Value(2), -// RAM: types.Int64Value(8), -// }, -// false, -// true, -// }, -// { -// "ok_flavor_2", -// &flavorModel{ -// CPU: types.Int64Value(2), -// RAM: types.Int64Value(8), -// }, -// &postgresflex.ListFlavorsResponse{ -// Flavors: &[]postgresflex.Flavor{ -// { -// Id: utils.Ptr("fid-1"), -// Cpu: utils.Ptr(int64(2)), -// Description: utils.Ptr("description"), -// Ram: utils.Ptr(int64(8)), -// }, -// { -// Id: utils.Ptr("fid-2"), -// Cpu: utils.Ptr(int64(1)), -// Description: utils.Ptr("description"), -// Ram: utils.Ptr(int64(4)), -// }, -// }, -// }, -// &flavorModel{ -// Id: types.StringValue("fid-1"), -// Description: types.StringValue("description"), -// CPU: types.Int64Value(2), -// RAM: types.Int64Value(8), -// }, -// false, -// true, -// }, -// { -// "no_matching_flavor", -// &flavorModel{ -// CPU: types.Int64Value(2), -// RAM: types.Int64Value(8), -// }, -// &postgresflex.ListFlavorsResponse{ -// Flavors: &[]postgresflex.Flavor{ -// { -// Id: utils.Ptr("fid-1"), -// Cpu: utils.Ptr(int64(1)), -// Description: utils.Ptr("description"), -// Ram: utils.Ptr(int64(8)), -// }, -// { -// Id: utils.Ptr("fid-2"), -// Cpu: utils.Ptr(int64(1)), -// Description: utils.Ptr("description"), -// Ram: utils.Ptr(int64(4)), -// }, -// }, -// }, -// &flavorModel{ -// CPU: types.Int64Value(2), -// RAM: types.Int64Value(8), -// }, -// false, -// false, -// }, -// { -// "nil_response", -// &flavorModel{ -// CPU: types.Int64Value(2), -// RAM: types.Int64Value(8), -// }, -// &postgresflex.ListFlavorsResponse{}, -// &flavorModel{ -// CPU: types.Int64Value(2), -// RAM: types.Int64Value(8), -// }, -// false, -// false, -// }, -// { -// "error_response", -// &flavorModel{ -// CPU: types.Int64Value(2), -// RAM: types.Int64Value(8), -// }, -// &postgresflex.ListFlavorsResponse{}, -// &flavorModel{ -// CPU: types.Int64Value(2), -// RAM: types.Int64Value(8), -// }, -// true, -// false, -// }, -// } -// for _, tt := range tests { -// t.Run(tt.description, func(t *testing.T) { -// client := &postgresFlexClientMocked{ -// returnError: tt.getFlavorsFails, -// getFlavorsResp: tt.mockedResp, -// } -// model := &Model{ -// ProjectId: types.StringValue("pid"), -// } -// flavorModel := &flavorModel{ -// CPU: tt.inputFlavor.CPU, -// RAM: tt.inputFlavor.RAM, -// } -// err := loadFlavorId(context.Background(), client, model, flavorModel) -// if !tt.isValid && err == nil { -// t.Fatalf("Should have failed") -// } -// if tt.isValid && err != nil { -// t.Fatalf("Should not have failed: %v", err) -// } -// if tt.isValid { -// diff := cmp.Diff(flavorModel, tt.expected) -// if diff != "" { -// t.Fatalf("Data does not match: %s", diff) -// } -// } -// }) -// } -// } - func TestNewInstanceResource(t *testing.T) { tests := []struct { name string @@ -639,12 +31,10 @@ func TestNewInstanceResource(t *testing.T) { }, } for _, tt := range tests { - t.Run( - tt.name, func(t *testing.T) { - if got := NewInstanceResource(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("NewInstanceResource() = %v, want %v", got, tt.want) - } - }, - ) + t.Run(tt.name, func(t *testing.T) { + if got := NewInstanceResource(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("NewInstanceResource() = %v, want %v", got, tt.want) + } + }) } }