chore: work save
This commit is contained in:
parent
2abd4e2c72
commit
c329d58970
8 changed files with 292 additions and 1507 deletions
|
|
@ -3,12 +3,12 @@
|
||||||
page_title: "stackitprivatepreview_postgresflexalpha_instance Data Source - stackitprivatepreview"
|
page_title: "stackitprivatepreview_postgresflexalpha_instance Data Source - stackitprivatepreview"
|
||||||
subcategory: ""
|
subcategory: ""
|
||||||
description: |-
|
description: |-
|
||||||
Postgres Flex instance data source schema. Must have a region specified in the provider configuration.
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# stackitprivatepreview_postgresflexalpha_instance (Data Source)
|
# stackitprivatepreview_postgresflexalpha_instance (Data Source)
|
||||||
|
|
||||||
Postgres Flex instance data source schema. Must have a `region` specified in the provider configuration.
|
|
||||||
|
|
||||||
## Example Usage
|
## Example Usage
|
||||||
|
|
||||||
|
|
@ -24,44 +24,31 @@ data "stackitprivatepreview_postgresflexalpha_instance" "example" {
|
||||||
|
|
||||||
### Required
|
### Required
|
||||||
|
|
||||||
- `instance_id` (String) ID of the PostgresFlex instance.
|
- `instance_id` (String) The ID of the instance.
|
||||||
- `project_id` (String) STACKIT project ID to which the instance is associated.
|
- `project_id` (String) The STACKIT project ID.
|
||||||
|
- `region` (String) The region which should be addressed
|
||||||
### Optional
|
|
||||||
|
|
||||||
- `region` (String) The resource region. If not defined, the provider region is used.
|
|
||||||
|
|
||||||
### Read-Only
|
### Read-Only
|
||||||
|
|
||||||
- `backup_schedule` (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.
|
||||||
- `encryption` (Attributes) (see [below for nested schema](#nestedatt--encryption))
|
- `flavor_id` (String) The id of the instance flavor.
|
||||||
- `flavor_id` (String)
|
- `id` (String) The ID of the instance.
|
||||||
- `id` (String) Terraform's internal data source. ID. It is structured as "`project_id`,`region`,`instance_id`".
|
- `is_deletable` (Boolean) Whether the instance can be deleted or not.
|
||||||
- `name` (String) Instance name.
|
- `name` (String) The name of the instance.
|
||||||
- `network` (Attributes) (see [below for nested schema](#nestedatt--network))
|
- `network` (Attributes) The access configuration of the instance (see [below for nested schema](#nestedatt--network))
|
||||||
- `replicas` (Number)
|
- `replicas` (Number) How many replicas the instance should have.
|
||||||
- `retention_days` (Number)
|
- `retention_days` (Number) How long backups are retained. The value can only be between 32 and 365 days.
|
||||||
- `storage` (Attributes) (see [below for nested schema](#nestedatt--storage))
|
- `status` (String) The current status of the instance.
|
||||||
- `version` (String)
|
- `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.
|
||||||
<a id="nestedatt--encryption"></a>
|
|
||||||
### Nested Schema for `encryption`
|
|
||||||
|
|
||||||
Read-Only:
|
|
||||||
|
|
||||||
- `key_id` (String)
|
|
||||||
- `key_version` (String)
|
|
||||||
- `keyring_id` (String)
|
|
||||||
- `service_account` (String)
|
|
||||||
|
|
||||||
|
|
||||||
<a id="nestedatt--network"></a>
|
<a id="nestedatt--network"></a>
|
||||||
### Nested Schema for `network`
|
### Nested Schema for `network`
|
||||||
|
|
||||||
Read-Only:
|
Read-Only:
|
||||||
|
|
||||||
- `access_scope` (String)
|
- `access_scope` (String) The access scope of the instance. It defines if the instance is public or airgapped.
|
||||||
- `acl` (List of String) The Access Control List (ACL) for the PostgresFlex instance.
|
- `acl` (List of String) List of IPV4 cidr.
|
||||||
- `instance_address` (String)
|
- `instance_address` (String)
|
||||||
- `router_address` (String)
|
- `router_address` (String)
|
||||||
|
|
||||||
|
|
@ -71,5 +58,5 @@ Read-Only:
|
||||||
|
|
||||||
Read-Only:
|
Read-Only:
|
||||||
|
|
||||||
- `class` (String)
|
- `performance_class` (String) The storage class for the storage.
|
||||||
- `size` (Number)
|
- `size` (Number) The storage size in Gigabytes.
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,12 @@
|
||||||
page_title: "stackitprivatepreview_postgresflexalpha_instance Resource - stackitprivatepreview"
|
page_title: "stackitprivatepreview_postgresflexalpha_instance Resource - stackitprivatepreview"
|
||||||
subcategory: ""
|
subcategory: ""
|
||||||
description: |-
|
description: |-
|
||||||
Postgres Flex instance resource schema. Must have a region specified in the provider configuration.
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# stackitprivatepreview_postgresflexalpha_instance (Resource)
|
# stackitprivatepreview_postgresflexalpha_instance (Resource)
|
||||||
|
|
||||||
Postgres Flex instance resource schema. Must have a `region` specified in the provider configuration.
|
|
||||||
|
|
||||||
## Example Usage
|
## Example Usage
|
||||||
|
|
||||||
|
|
@ -42,49 +42,42 @@ import {
|
||||||
|
|
||||||
### Required
|
### Required
|
||||||
|
|
||||||
- `backup_schedule` (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.
|
||||||
- `encryption` (Attributes) The encryption block. (see [below for nested schema](#nestedatt--encryption))
|
- `flavor_id` (String) The id of the instance flavor.
|
||||||
- `flavor_id` (String)
|
- `name` (String) The name of the instance.
|
||||||
- `name` (String) Instance name.
|
- `network` (Attributes) The access configuration of the instance (see [below for nested schema](#nestedatt--network))
|
||||||
- `network` (Attributes) The network block configuration. (see [below for nested schema](#nestedatt--network))
|
- `replicas` (Number) How many replicas the instance should have.
|
||||||
- `project_id` (String) STACKIT project ID to which the instance is associated.
|
- `retention_days` (Number) How long backups are retained. The value can only be between 32 and 365 days.
|
||||||
- `replicas` (Number)
|
- `storage` (Attributes) The object containing information about the storage size and class. (see [below for nested schema](#nestedatt--storage))
|
||||||
- `retention_days` (Number) The days of the retention period.
|
- `version` (String) The Postgres version used for the instance. See [Versions Endpoint](/documentation/postgres-flex-service/version/v3alpha1#tag/Version) for supported version parameters.
|
||||||
- `storage` (Attributes) (see [below for nested schema](#nestedatt--storage))
|
|
||||||
- `version` (String) The database version used.
|
|
||||||
|
|
||||||
### Optional
|
### 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
|
### Read-Only
|
||||||
|
|
||||||
- `id` (String) Terraform's internal resource ID. It is structured as "`project_id`,`region`,`instance_id`".
|
- `id` (String) The ID of the instance.
|
||||||
- `instance_id` (String) ID of the PostgresFlex instance.
|
- `is_deletable` (Boolean) Whether the instance can be deleted or not.
|
||||||
|
- `status` (String) The current status of the instance.
|
||||||
<a id="nestedatt--encryption"></a>
|
|
||||||
### 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.
|
|
||||||
|
|
||||||
|
|
||||||
<a id="nestedatt--network"></a>
|
<a id="nestedatt--network"></a>
|
||||||
### Nested Schema for `network`
|
### Nested Schema for `network`
|
||||||
|
|
||||||
Required:
|
Required:
|
||||||
|
|
||||||
- `acl` (List of String) The Access Control List (ACL) for the PostgresFlex instance.
|
- `acl` (List of String) List of IPV4 cidr.
|
||||||
|
|
||||||
Optional:
|
Optional:
|
||||||
|
|
||||||
- `access_scope` (String) The access scope. (Either SNA or PUBLIC)
|
- `access_scope` (String) The access scope of the instance. It defines if the instance is public or airgapped.
|
||||||
- `instance_address` (String) The returned instance address.
|
- `instance_address` (String)
|
||||||
- `router_address` (String) The returned router address.
|
- `router_address` (String)
|
||||||
|
|
||||||
|
|
||||||
<a id="nestedatt--storage"></a>
|
<a id="nestedatt--storage"></a>
|
||||||
|
|
@ -92,5 +85,16 @@ Optional:
|
||||||
|
|
||||||
Required:
|
Required:
|
||||||
|
|
||||||
- `class` (String) The storage class used.
|
- `performance_class` (String) The storage class for the storage.
|
||||||
- `size` (Number) The disk size of the storage.
|
- `size` (Number) The storage size in Gigabytes.
|
||||||
|
|
||||||
|
|
||||||
|
<a id="nestedatt--encryption"></a>
|
||||||
|
### 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)
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,8 @@ func PartialUpdateInstanceWaitHandler(
|
||||||
return false, nil, nil
|
return false, nil, nil
|
||||||
case InstanceStateTerminating:
|
case InstanceStateTerminating:
|
||||||
return false, nil, nil
|
return false, nil, nil
|
||||||
|
case InstanceStatePending:
|
||||||
|
return false, nil, nil
|
||||||
case InstanceStateSuccess:
|
case InstanceStateSuccess:
|
||||||
return true, s, nil
|
return true, s, nil
|
||||||
case InstanceStateFailed:
|
case InstanceStateFailed:
|
||||||
|
|
|
||||||
|
|
@ -9,22 +9,22 @@ data "stackitprivatepreview_postgresflexalpha_flavor" "pgsql_flavor" {
|
||||||
|
|
||||||
resource "stackitprivatepreview_postgresflexalpha_instance" "msh-sna-pe-example" {
|
resource "stackitprivatepreview_postgresflexalpha_instance" "msh-sna-pe-example" {
|
||||||
project_id = var.project_id
|
project_id = var.project_id
|
||||||
name = "msh-sna-pe-example"
|
name = "mshpetest2"
|
||||||
backup_schedule = "0 0 * * *"
|
backup_schedule = "0 0 * * *"
|
||||||
retention_days = 33
|
retention_days = 45
|
||||||
flavor_id = data.stackitprivatepreview_postgresflexalpha_flavor.pgsql_flavor.flavor_id
|
flavor_id = data.stackitprivatepreview_postgresflexalpha_flavor.pgsql_flavor.flavor_id
|
||||||
replicas = 1
|
replicas = 1
|
||||||
storage = {
|
storage = {
|
||||||
# class = "premium-perf2-stackit"
|
# 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
|
size = 10
|
||||||
}
|
}
|
||||||
encryption = {
|
encryption = {
|
||||||
# key_id = stackit_kms_key.key.key_id
|
# key_id = stackit_kms_key.key.key_id
|
||||||
# keyring_id = stackit_kms_keyring.keyring.keyring_id
|
# keyring_id = stackit_kms_keyring.keyring.keyring_id
|
||||||
key_id = var.key_id
|
kek_key_id = var.key_id
|
||||||
keyring_id = var.keyring_id
|
kek_key_ring_id = var.keyring_id
|
||||||
key_version = var.key_version
|
kek_key_version = var.key_version
|
||||||
service_account = var.sa_email
|
service_account = var.sa_email
|
||||||
}
|
}
|
||||||
network = {
|
network = {
|
||||||
|
|
|
||||||
|
|
@ -7,18 +7,13 @@ import (
|
||||||
|
|
||||||
"github.com/mhenselin/terraform-provider-stackitprivatepreview/pkg/postgresflexalpha"
|
"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/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"
|
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/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/hashicorp/terraform-plugin-log/tflog"
|
||||||
"github.com/mhenselin/terraform-provider-stackitprivatepreview/stackit/internal/core"
|
"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/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.
|
// Ensure the implementation satisfies the expected interfaces.
|
||||||
|
|
@ -38,20 +33,12 @@ type instanceDataSource struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Metadata returns the data source type name.
|
// Metadata returns the data source type name.
|
||||||
func (r *instanceDataSource) Metadata(
|
func (r *instanceDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
|
||||||
_ context.Context,
|
|
||||||
req datasource.MetadataRequest,
|
|
||||||
resp *datasource.MetadataResponse,
|
|
||||||
) {
|
|
||||||
resp.TypeName = req.ProviderTypeName + "_postgresflexalpha_instance"
|
resp.TypeName = req.ProviderTypeName + "_postgresflexalpha_instance"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure adds the provider configured client to the data source.
|
// Configure adds the provider configured client to the data source.
|
||||||
func (r *instanceDataSource) Configure(
|
func (r *instanceDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
|
||||||
ctx context.Context,
|
|
||||||
req datasource.ConfigureRequest,
|
|
||||||
resp *datasource.ConfigureResponse,
|
|
||||||
) {
|
|
||||||
var ok bool
|
var ok bool
|
||||||
r.providerData, ok = conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics)
|
r.providerData, ok = conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
@ -67,131 +54,13 @@ func (r *instanceDataSource) Configure(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Schema defines the schema for the data source.
|
// Schema defines the schema for the data source.
|
||||||
func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
|
func (r *instanceDataSource) Schema(ctx context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
|
||||||
descriptions := map[string]string{
|
resp.Schema = postgresflexalpha2.InstanceDataSourceSchema(ctx)
|
||||||
"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"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read refreshes the Terraform state with the latest data.
|
// Read refreshes the Terraform state with the latest data.
|
||||||
func (r *instanceDataSource) Read(
|
func (r *instanceDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { // nolint:gocritic // function signature required by Terraform
|
||||||
ctx context.Context,
|
var model postgresflexalpha2.InstanceModel
|
||||||
req datasource.ReadRequest,
|
|
||||||
resp *datasource.ReadResponse,
|
|
||||||
) { // nolint:gocritic // function signature required by Terraform
|
|
||||||
var model Model
|
|
||||||
diags := req.Config.Get(ctx, &model)
|
diags := req.Config.Get(ctx, &model)
|
||||||
resp.Diagnostics.Append(diags...)
|
resp.Diagnostics.Append(diags...)
|
||||||
if resp.Diagnostics.HasError() {
|
if resp.Diagnostics.HasError() {
|
||||||
|
|
@ -224,43 +93,12 @@ func (r *instanceDataSource) Read(
|
||||||
|
|
||||||
ctx = core.LogResponse(ctx)
|
ctx = core.LogResponse(ctx)
|
||||||
|
|
||||||
var storage = &storageModel{}
|
err = mapGetDataInstanceResponseToModel(ctx, &model, instanceResp)
|
||||||
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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
core.LogAndAddError(
|
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Calling API: %v", err))
|
||||||
ctx,
|
|
||||||
&resp.Diagnostics,
|
|
||||||
"Error reading instance",
|
|
||||||
fmt.Sprintf("Processing API payload: %v", err),
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set refreshed state
|
// Set refreshed state
|
||||||
diags = resp.State.Set(ctx, model)
|
diags = resp.State.Set(ctx, model)
|
||||||
resp.Diagnostics.Append(diags...)
|
resp.Diagnostics.Append(diags...)
|
||||||
|
|
|
||||||
|
|
@ -3,217 +3,119 @@ package postgresflexalpha
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
|
||||||
|
|
||||||
"github.com/hashicorp/terraform-plugin-framework/attr"
|
"github.com/hashicorp/terraform-plugin-framework/attr"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||||
postgresflex "github.com/mhenselin/terraform-provider-stackitprivatepreview/pkg/postgresflexalpha"
|
postgresflex "github.com/mhenselin/terraform-provider-stackitprivatepreview/pkg/postgresflexalpha"
|
||||||
"github.com/mhenselin/terraform-provider-stackitprivatepreview/stackit/internal/conversion"
|
postgresflexalphadatasource "github.com/mhenselin/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/instance/datasources_gen"
|
||||||
"github.com/mhenselin/terraform-provider-stackitprivatepreview/stackit/internal/core"
|
postgresflexalpharesource "github.com/mhenselin/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/instance/resources_gen"
|
||||||
"github.com/mhenselin/terraform-provider-stackitprivatepreview/stackit/internal/utils"
|
"github.com/mhenselin/terraform-provider-stackitprivatepreview/stackit/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func mapFields(
|
func mapGetInstanceResponseToModel(ctx context.Context, m *postgresflexalpharesource.InstanceModel, resp *postgresflex.GetInstanceResponse) error {
|
||||||
ctx context.Context,
|
m.BackupSchedule = types.StringValue(resp.GetBackupSchedule())
|
||||||
resp *postgresflex.GetInstanceResponse,
|
// need to leave out encryption, as the GetInstance endpoint does not provide it
|
||||||
model *Model,
|
//m.Encryption = postgresflexalpharesource.NewEncryptionValueMust(
|
||||||
storage *storageModel,
|
// m.Encryption.AttributeTypes(ctx),
|
||||||
encryption *encryptionModel,
|
// map[string]attr.Value{
|
||||||
network *networkModel,
|
// "kek_key_id": types.StringValue(resp.Encryption.GetKekKeyId()),
|
||||||
region string,
|
// "kek_key_ring_id": types.StringValue(resp.Encryption.GetKekKeyRingId()),
|
||||||
) error {
|
// "kek_key_version": types.StringValue(resp.Encryption.GetKekKeyVersion()),
|
||||||
if resp == nil {
|
// "service_account": types.StringValue(resp.Encryption.GetServiceAccount()),
|
||||||
return fmt.Errorf("response input is nil")
|
// },
|
||||||
|
//)
|
||||||
|
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 {
|
m.InstanceId = types.StringPointerValue(resp.Id)
|
||||||
return fmt.Errorf("model input is nil")
|
m.IsDeletable = types.BoolValue(resp.GetIsDeletable())
|
||||||
}
|
m.Name = types.StringValue(resp.GetName())
|
||||||
instance := resp
|
|
||||||
|
|
||||||
var instanceId string
|
netAcl, diags := types.ListValueFrom(ctx, types.StringType, resp.Network.GetAcl())
|
||||||
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)
|
|
||||||
if diags.HasError() {
|
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
|
net, diags := postgresflexalpharesource.NewNetworkValue(
|
||||||
if instance.Network == nil {
|
postgresflexalpharesource.NetworkValue{}.AttributeTypes(ctx),
|
||||||
networkValues = map[string]attr.Value{
|
map[string]attr.Value{
|
||||||
"acl": network.ACL,
|
"access_scope": types.StringValue(string(resp.Network.GetAccessScope())),
|
||||||
"access_scope": network.AccessScope,
|
"acl": netAcl,
|
||||||
"instance_address": network.InstanceAddress,
|
"instance_address": types.StringValue(resp.Network.GetInstanceAddress()),
|
||||||
"router_address": network.RouterAddress,
|
"router_address": types.StringValue(resp.Network.GetRouterAddress()),
|
||||||
}
|
},
|
||||||
} 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)
|
|
||||||
if diags.HasError() {
|
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
|
m.Network = net
|
||||||
if instance.Storage == nil {
|
m.Replicas = types.Int64Value(int64(resp.GetReplicas()))
|
||||||
storageValues = map[string]attr.Value{
|
m.RetentionDays = types.Int64Value(resp.GetRetentionDays())
|
||||||
"class": storage.Class,
|
m.Status = types.StringValue(string(resp.GetStatus()))
|
||||||
"size": storage.Size,
|
|
||||||
}
|
storage, diags := postgresflexalpharesource.NewStorageValue(
|
||||||
} else {
|
postgresflexalpharesource.StorageValue{}.AttributeTypes(ctx),
|
||||||
storageValues = map[string]attr.Value{
|
map[string]attr.Value{
|
||||||
"class": types.StringValue(*instance.Storage.PerformanceClass),
|
"performance_class": types.StringValue(resp.Storage.GetPerformanceClass()),
|
||||||
"size": types.Int64PointerValue(instance.Storage.Size),
|
"size": types.Int64Value(resp.Storage.GetSize()),
|
||||||
}
|
},
|
||||||
}
|
)
|
||||||
storageObject, diags := types.ObjectValue(storageTypes, storageValues)
|
|
||||||
if diags.HasError() {
|
if diags.HasError() {
|
||||||
return fmt.Errorf("creating storage: %w", core.DiagsToError(diags))
|
return fmt.Errorf("failed converting storage from response")
|
||||||
}
|
}
|
||||||
|
m.Storage = storage
|
||||||
if instance.Replicas == nil {
|
m.Version = types.StringValue(resp.GetVersion())
|
||||||
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
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func toCreatePayload(
|
func mapGetDataInstanceResponseToModel(ctx context.Context, m *postgresflexalphadatasource.InstanceModel, resp *postgresflex.GetInstanceResponse) error {
|
||||||
model *Model,
|
m.BackupSchedule = types.StringValue(resp.GetBackupSchedule())
|
||||||
storage *storageModel,
|
//m.Encryption = postgresflexalpharesource.EncryptionValue{
|
||||||
enc *encryptionModel,
|
// KekKeyId: types.StringValue(resp.Encryption.GetKekKeyId()),
|
||||||
net *networkModel,
|
// KekKeyRingId: types.StringValue(resp.Encryption.GetKekKeyRingId()),
|
||||||
) (*postgresflex.CreateInstanceRequestPayload, error) {
|
// KekKeyVersion: types.StringValue(resp.Encryption.GetKekKeyVersion()),
|
||||||
if model == nil {
|
// ServiceAccount: types.StringValue(resp.Encryption.GetServiceAccount()),
|
||||||
return nil, fmt.Errorf("nil model")
|
//}
|
||||||
}
|
m.FlavorId = types.StringValue(resp.GetFlavorId())
|
||||||
if storage == nil {
|
m.Id = utils.BuildInternalTerraformId(m.ProjectId.ValueString(), m.Region.ValueString(), m.InstanceId.ValueString())
|
||||||
return nil, fmt.Errorf("nil storage")
|
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
|
net, diags := postgresflexalphadatasource.NewNetworkValue(
|
||||||
if !model.Replicas.IsNull() && !model.Replicas.IsUnknown() {
|
postgresflexalphadatasource.NetworkValue{}.AttributeTypes(ctx),
|
||||||
if model.Replicas.ValueInt64() > math.MaxInt32 {
|
map[string]attr.Value{
|
||||||
return nil, fmt.Errorf("replica count too big: %d", model.Replicas.ValueInt64())
|
"access_scope": types.StringValue(string(resp.Network.GetAccessScope())),
|
||||||
}
|
"acl": netAcl,
|
||||||
replVal = int32(model.Replicas.ValueInt64()) // nolint:gosec // check is performed above
|
"instance_address": types.StringValue(resp.Network.GetInstanceAddress()),
|
||||||
}
|
"router_address": types.StringValue(resp.Network.GetRouterAddress()),
|
||||||
|
|
||||||
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),
|
|
||||||
},
|
},
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,32 +3,24 @@ package postgresflexalpha
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
|
||||||
"strings"
|
"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/path"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/resource"
|
"github.com/hashicorp/terraform-plugin-framework/resource"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
|
"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/planmodifier"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
|
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
"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"
|
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -53,12 +45,9 @@ type instanceResource struct {
|
||||||
providerData core.ProviderData
|
providerData core.ProviderData
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *instanceResource) ValidateConfig(
|
func (r *instanceResource) ValidateConfig(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) {
|
||||||
ctx context.Context,
|
var data postgresflexalpha.InstanceModel
|
||||||
req resource.ValidateConfigRequest,
|
// var data Model
|
||||||
resp *resource.ValidateConfigResponse,
|
|
||||||
) {
|
|
||||||
var data Model
|
|
||||||
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
|
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
|
||||||
|
|
||||||
if resp.Diagnostics.HasError() {
|
if resp.Diagnostics.HasError() {
|
||||||
|
|
@ -77,12 +66,9 @@ func (r *instanceResource) ValidateConfig(
|
||||||
|
|
||||||
// ModifyPlan implements resource.ResourceWithModifyPlan.
|
// ModifyPlan implements resource.ResourceWithModifyPlan.
|
||||||
// Use the modifier to set the effective region in the current plan.
|
// Use the modifier to set the effective region in the current plan.
|
||||||
func (r *instanceResource) ModifyPlan(
|
func (r *instanceResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { // nolint:gocritic // function signature required by Terraform
|
||||||
ctx context.Context,
|
var configModel postgresflexalpha.InstanceModel
|
||||||
req resource.ModifyPlanRequest,
|
// var configModel Model
|
||||||
resp *resource.ModifyPlanResponse,
|
|
||||||
) { // nolint:gocritic // function signature required by Terraform
|
|
||||||
var configModel Model
|
|
||||||
// skip initial empty configuration to avoid follow-up errors
|
// skip initial empty configuration to avoid follow-up errors
|
||||||
if req.Config.Raw.IsNull() {
|
if req.Config.Raw.IsNull() {
|
||||||
return
|
return
|
||||||
|
|
@ -92,7 +78,8 @@ func (r *instanceResource) ModifyPlan(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var planModel Model
|
var planModel postgresflexalpha.InstanceModel
|
||||||
|
// var planModel Model
|
||||||
resp.Diagnostics.Append(req.Plan.Get(ctx, &planModel)...)
|
resp.Diagnostics.Append(req.Plan.Get(ctx, &planModel)...)
|
||||||
if resp.Diagnostics.HasError() {
|
if resp.Diagnostics.HasError() {
|
||||||
return
|
return
|
||||||
|
|
@ -135,243 +122,19 @@ func (r *instanceResource) Configure(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Schema defines the schema for the resource.
|
// Schema defines the schema for the resource.
|
||||||
func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
|
func (r *instanceResource) Schema(ctx context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
|
||||||
descriptions := map[string]string{
|
resp.Schema = postgresflexalpha.InstanceResourceSchema(ctx)
|
||||||
"main": "Postgres Flex instance resource schema. Must have a `region` specified in the provider configuration.",
|
resp.Schema = addPlanModifiers(resp.Schema)
|
||||||
"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) IdentitySchema(_ context.Context, _ resource.IdentitySchemaRequest, resp *resource.IdentitySchemaResponse) {
|
func addPlanModifiers(s schema.Schema) schema.Schema {
|
||||||
// resp.IdentitySchema = identityschema.Schema{
|
attr := s.Attributes["backup_schedule"].(schema.StringAttribute)
|
||||||
// Attributes: map[string]identityschema.Attribute{
|
attr.PlanModifiers = []planmodifier.String{
|
||||||
// "project_id": identityschema.StringAttribute{
|
stringplanmodifier.UseStateForUnknown(),
|
||||||
// RequiredForImport: true, // must be set during import by the practitioner
|
}
|
||||||
// },
|
s.Attributes["backup_schedule"] = attr
|
||||||
// "region": identityschema.StringAttribute{
|
return s
|
||||||
// RequiredForImport: true, // must be set during import by the practitioner
|
}
|
||||||
// },
|
|
||||||
// "instance_id": identityschema.StringAttribute{
|
|
||||||
// RequiredForImport: true, // must be set during import by the practitioner
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
// Create creates the resource and sets the initial Terraform state.
|
// Create creates the resource and sets the initial Terraform state.
|
||||||
func (r *instanceResource) Create(
|
func (r *instanceResource) Create(
|
||||||
|
|
@ -379,7 +142,8 @@ func (r *instanceResource) Create(
|
||||||
req resource.CreateRequest,
|
req resource.CreateRequest,
|
||||||
resp *resource.CreateResponse,
|
resp *resource.CreateResponse,
|
||||||
) { // nolint:gocritic // function signature required by Terraform
|
) { // nolint:gocritic // function signature required by Terraform
|
||||||
var model Model
|
var model postgresflexalpha.InstanceModel
|
||||||
|
//var model Model
|
||||||
diags := req.Plan.Get(ctx, &model)
|
diags := req.Plan.Get(ctx, &model)
|
||||||
resp.Diagnostics.Append(diags...)
|
resp.Diagnostics.Append(diags...)
|
||||||
if resp.Diagnostics.HasError() {
|
if resp.Diagnostics.HasError() {
|
||||||
|
|
@ -393,59 +157,22 @@ func (r *instanceResource) Create(
|
||||||
ctx = tflog.SetField(ctx, "project_id", projectId)
|
ctx = tflog.SetField(ctx, "project_id", projectId)
|
||||||
ctx = tflog.SetField(ctx, "region", region)
|
ctx = tflog.SetField(ctx, "region", region)
|
||||||
|
|
||||||
var storage = &storageModel{}
|
var netAcl []string
|
||||||
if !model.Storage.IsNull() && !model.Storage.IsUnknown() {
|
diag := model.Network.Acl.ElementsAs(ctx, &netAcl, false)
|
||||||
diags = model.Storage.As(ctx, storage, basetypes.ObjectAsOptions{})
|
resp.Diagnostics.Append(diags...)
|
||||||
resp.Diagnostics.Append(diags...)
|
if diag.HasError() {
|
||||||
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),
|
|
||||||
)
|
|
||||||
return
|
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
|
// Create new instance
|
||||||
createResp, err := r.client.CreateInstanceRequest(
|
createResp, err := r.client.CreateInstanceRequest(ctx, projectId, region).CreateInstanceRequestPayload(payload).Execute()
|
||||||
ctx,
|
|
||||||
projectId,
|
|
||||||
region,
|
|
||||||
).CreateInstanceRequestPayload(*payload).Execute()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Calling API: %v", err))
|
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Calling API: %v", err))
|
||||||
return
|
return
|
||||||
|
|
@ -463,26 +190,16 @@ func (r *instanceResource) Create(
|
||||||
|
|
||||||
waitResp, err := wait.CreateInstanceWaitHandler(ctx, r.client, projectId, region, instanceId).WaitWithContext(ctx)
|
waitResp, err := wait.CreateInstanceWaitHandler(ctx, r.client, projectId, region, instanceId).WaitWithContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
core.LogAndAddError(
|
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Wait handler error: %v", err))
|
||||||
ctx,
|
|
||||||
&resp.Diagnostics,
|
|
||||||
"Error creating instance",
|
|
||||||
fmt.Sprintf("Wait handler error: %v", err),
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map response body to schema
|
err = mapGetInstanceResponseToModel(ctx, &model, waitResp)
|
||||||
err = mapFields(ctx, waitResp, &model, storage, encryption, network, region)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
core.LogAndAddError(
|
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Error creating model: %v", err))
|
||||||
ctx,
|
|
||||||
&resp.Diagnostics,
|
|
||||||
"Error creating instance",
|
|
||||||
fmt.Sprintf("Processing API payload: %v", err),
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set state to fully populated data
|
// Set state to fully populated data
|
||||||
diags = resp.State.Set(ctx, model)
|
diags = resp.State.Set(ctx, model)
|
||||||
resp.Diagnostics.Append(diags...)
|
resp.Diagnostics.Append(diags...)
|
||||||
|
|
@ -492,13 +209,41 @@ func (r *instanceResource) Create(
|
||||||
tflog.Info(ctx, "Postgres Flex instance created")
|
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.
|
// Read refreshes the Terraform state with the latest data.
|
||||||
func (r *instanceResource) Read(
|
func (r *instanceResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform
|
||||||
ctx context.Context,
|
var model postgresflexalpha.InstanceModel
|
||||||
req resource.ReadRequest,
|
//var model Model
|
||||||
resp *resource.ReadResponse,
|
|
||||||
) { // nolint:gocritic // function signature required by Terraform
|
|
||||||
var model Model
|
|
||||||
diags := req.State.Get(ctx, &model)
|
diags := req.State.Get(ctx, &model)
|
||||||
resp.Diagnostics.Append(diags...)
|
resp.Diagnostics.Append(diags...)
|
||||||
if resp.Diagnostics.HasError() {
|
if resp.Diagnostics.HasError() {
|
||||||
|
|
@ -514,33 +259,6 @@ func (r *instanceResource) Read(
|
||||||
ctx = tflog.SetField(ctx, "instance_id", instanceId)
|
ctx = tflog.SetField(ctx, "instance_id", instanceId)
|
||||||
ctx = tflog.SetField(ctx, "region", region)
|
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()
|
instanceResp, err := r.client.GetInstanceRequest(ctx, projectId, region, instanceId).Execute()
|
||||||
if err != nil {
|
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
|
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)
|
ctx = core.LogResponse(ctx)
|
||||||
|
|
||||||
// Map response body to schema
|
err = mapGetInstanceResponseToModel(ctx, &model, instanceResp)
|
||||||
err = mapFields(ctx, instanceResp, &model, &storage, &encryption, &network, region)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
core.LogAndAddError(
|
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Processing API payload: %v", err))
|
||||||
ctx,
|
|
||||||
&resp.Diagnostics,
|
|
||||||
"Error reading instance",
|
|
||||||
fmt.Sprintf("Processing API payload: %v", err),
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -576,12 +288,9 @@ func (r *instanceResource) Read(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update updates the resource and sets the updated Terraform state on success.
|
// Update updates the resource and sets the updated Terraform state on success.
|
||||||
func (r *instanceResource) Update(
|
func (r *instanceResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform
|
||||||
ctx context.Context,
|
var model postgresflexalpha.InstanceModel
|
||||||
req resource.UpdateRequest,
|
//var model Model
|
||||||
resp *resource.UpdateResponse,
|
|
||||||
) { // nolint:gocritic // function signature required by Terraform
|
|
||||||
var model Model
|
|
||||||
diags := req.Plan.Get(ctx, &model)
|
diags := req.Plan.Get(ctx, &model)
|
||||||
resp.Diagnostics.Append(diags...)
|
resp.Diagnostics.Append(diags...)
|
||||||
if resp.Diagnostics.HasError() {
|
if resp.Diagnostics.HasError() {
|
||||||
|
|
@ -597,61 +306,38 @@ func (r *instanceResource) Update(
|
||||||
ctx = tflog.SetField(ctx, "instance_id", instanceId)
|
ctx = tflog.SetField(ctx, "instance_id", instanceId)
|
||||||
ctx = tflog.SetField(ctx, "region", region)
|
ctx = tflog.SetField(ctx, "region", region)
|
||||||
|
|
||||||
// nolint:gocritic // need that code later
|
var netAcl []string
|
||||||
// var acl []string
|
diag := model.Network.Acl.ElementsAs(ctx, &netAcl, false)
|
||||||
// if !(model.ACL.IsNull() || model.ACL.IsUnknown()) {
|
resp.Diagnostics.Append(diags...)
|
||||||
// diags = model.ACL.ElementsAs(ctx, &acl, false)
|
if diag.HasError() {
|
||||||
// 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),
|
|
||||||
)
|
|
||||||
return
|
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
|
// Update existing instance
|
||||||
err = r.client.UpdateInstancePartiallyRequest(
|
err := r.client.UpdateInstancePartiallyRequest(
|
||||||
ctx,
|
ctx,
|
||||||
projectId,
|
projectId,
|
||||||
region,
|
region,
|
||||||
instanceId,
|
instanceId,
|
||||||
).UpdateInstancePartiallyRequestPayload(*payload).Execute()
|
).UpdateInstancePartiallyRequestPayload(payload).Execute()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", err.Error())
|
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", err.Error())
|
||||||
return
|
return
|
||||||
|
|
@ -659,34 +345,18 @@ func (r *instanceResource) Update(
|
||||||
|
|
||||||
ctx = core.LogResponse(ctx)
|
ctx = core.LogResponse(ctx)
|
||||||
|
|
||||||
waitResp, err := wait.PartialUpdateInstanceWaitHandler(
|
waitResp, err := wait.PartialUpdateInstanceWaitHandler(ctx, r.client, projectId, region, instanceId).WaitWithContext(ctx)
|
||||||
ctx,
|
|
||||||
r.client,
|
|
||||||
projectId,
|
|
||||||
region,
|
|
||||||
instanceId,
|
|
||||||
).WaitWithContext(ctx)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
core.LogAndAddError(
|
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Instance update waiting: %v", err))
|
||||||
ctx,
|
|
||||||
&resp.Diagnostics,
|
|
||||||
"Error updating instance",
|
|
||||||
fmt.Sprintf("Instance update waiting: %v", err),
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map response body to schema
|
err = mapGetInstanceResponseToModel(ctx, &model, waitResp)
|
||||||
err = mapFields(ctx, waitResp, &model, storage, encryption, network, region)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
core.LogAndAddError(
|
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Processing API payload: %v", err))
|
||||||
ctx,
|
|
||||||
&resp.Diagnostics,
|
|
||||||
"Error updating instance",
|
|
||||||
fmt.Sprintf("Processing API payload: %v", err),
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
diags = resp.State.Set(ctx, model)
|
diags = resp.State.Set(ctx, model)
|
||||||
resp.Diagnostics.Append(diags...)
|
resp.Diagnostics.Append(diags...)
|
||||||
if resp.Diagnostics.HasError() {
|
if resp.Diagnostics.HasError() {
|
||||||
|
|
@ -696,12 +366,9 @@ func (r *instanceResource) Update(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete deletes the resource and removes the Terraform state on success.
|
// Delete deletes the resource and removes the Terraform state on success.
|
||||||
func (r *instanceResource) Delete(
|
func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform
|
||||||
ctx context.Context,
|
var model postgresflexalpha.InstanceModel
|
||||||
req resource.DeleteRequest,
|
//var model Model
|
||||||
resp *resource.DeleteResponse,
|
|
||||||
) { // nolint:gocritic // function signature required by Terraform
|
|
||||||
var model Model
|
|
||||||
diags := req.State.Get(ctx, &model)
|
diags := req.State.Get(ctx, &model)
|
||||||
resp.Diagnostics.Append(diags...)
|
resp.Diagnostics.Append(diags...)
|
||||||
if resp.Diagnostics.HasError() {
|
if resp.Diagnostics.HasError() {
|
||||||
|
|
@ -741,16 +408,11 @@ func (r *instanceResource) Delete(
|
||||||
|
|
||||||
// ImportState imports a resource into the Terraform state on success.
|
// ImportState imports a resource into the Terraform state on success.
|
||||||
// The expected format of the resource import identifier is: project_id,instance_id
|
// The expected format of the resource import identifier is: project_id,instance_id
|
||||||
func (r *instanceResource) ImportState(
|
func (r *instanceResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
|
||||||
ctx context.Context,
|
|
||||||
req resource.ImportStateRequest,
|
|
||||||
resp *resource.ImportStateResponse,
|
|
||||||
) {
|
|
||||||
idParts := strings.Split(req.ID, core.Separator)
|
idParts := strings.Split(req.ID, core.Separator)
|
||||||
|
|
||||||
if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" {
|
if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" {
|
||||||
core.LogAndAddError(
|
core.LogAndAddError(ctx, &resp.Diagnostics,
|
||||||
ctx, &resp.Diagnostics,
|
|
||||||
"Error importing instance",
|
"Error importing instance",
|
||||||
fmt.Sprintf("Expected import identifier with format: [project_id],[region],[instance_id] Got: %q", req.ID),
|
fmt.Sprintf("Expected import identifier with format: [project_id],[region],[instance_id] Got: %q", req.ID),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,10 @@
|
||||||
package postgresflexalpha
|
package postgresflexalpha
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"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/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 {
|
// type postgresFlexClientMocked struct {
|
||||||
|
|
@ -26,608 +20,6 @@ import (
|
||||||
// return c.getFlavorsResp, nil
|
// 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) {
|
func TestNewInstanceResource(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
|
@ -639,12 +31,10 @@ func TestNewInstanceResource(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
tt.name, func(t *testing.T) {
|
if got := NewInstanceResource(); !reflect.DeepEqual(got, tt.want) {
|
||||||
if got := NewInstanceResource(); !reflect.DeepEqual(got, tt.want) {
|
t.Errorf("NewInstanceResource() = %v, want %v", got, tt.want)
|
||||||
t.Errorf("NewInstanceResource() = %v, want %v", got, tt.want)
|
}
|
||||||
}
|
})
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue