From a08dbd892651fae841a18e1321d04818f5fb0507 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Palet?= Date: Mon, 1 Jul 2024 12:09:26 +0100 Subject: [PATCH] Extend LogMe instance parameters (#438) * Extend LogMe instance parameters * Update acc test * Add more field descriptions * Improve code and tests * Add more fields to acc test * Fix linter * Add float parameter --- docs/data-sources/logme_instance.md | 24 +- docs/data-sources/rabbitmq_instance.md | 26 +- docs/data-sources/redis_instance.md | 44 +-- docs/resources/logme_instance.md | 24 +- stackit/internal/conversion/conversion.go | 10 + .../services/logme/instance/datasource.go | 112 ++++++- .../services/logme/instance/resource.go | 305 ++++++++++++++++-- .../services/logme/instance/resource_test.go | 226 +++++++++---- .../internal/services/logme/logme_acc_test.go | 101 +++++- .../services/rabbitmq/instance/datasource.go | 47 ++- .../services/rabbitmq/instance/resource.go | 5 +- .../rabbitmq/instance/resource_test.go | 18 +- .../services/redis/instance/datasource.go | 102 ++++-- .../services/redis/instance/resource.go | 6 +- .../services/redis/instance/resource_test.go | 18 +- 15 files changed, 868 insertions(+), 200 deletions(-) diff --git a/docs/data-sources/logme_instance.md b/docs/data-sources/logme_instance.md index b4680337..9133c239 100644 --- a/docs/data-sources/logme_instance.md +++ b/docs/data-sources/logme_instance.md @@ -46,4 +46,26 @@ data "stackit_logme_instance" "example" { Read-Only: -- `sgw_acl` (String) +- `enable_monitoring` (Boolean) Enable monitoring. +- `fluentd_tcp` (Number) +- `fluentd_tls` (Number) +- `fluentd_tls_ciphers` (String) +- `fluentd_tls_max_version` (String) +- `fluentd_tls_min_version` (String) +- `fluentd_tls_version` (String) +- `fluentd_udp` (Number) +- `graphite` (String) If set, monitoring with Graphite will be enabled. Expects the host and port where the Graphite metrics should be sent to (host:port). +- `ism_deletion_after` (String) Combination of an integer and a timerange when an index will be considered "old" and can be deleted. Possible values for the timerange are `s`, `m`, `h` and `d`. +- `ism_jitter` (Number) +- `ism_job_interval` (Number) Jitter of the execution time. +- `java_heapspace` (Number) The amount of memory (in MB) allocated as heap by the JVM for OpenSearch. +- `java_maxmetaspace` (Number) The amount of memory (in MB) used by the JVM to store metadata for OpenSearch. +- `max_disk_threshold` (Number) The maximum disk threshold in MB. If the disk usage exceeds this threshold, the instance will be stopped. +- `metrics_frequency` (Number) The frequency in seconds at which metrics are emitted (in seconds). +- `metrics_prefix` (String) The prefix for the metrics. Could be useful when using Graphite monitoring to prefix the metrics with a certain value, like an API key. +- `monitoring_instance_id` (String) The monitoring instance ID. +- `opensearch_tls_ciphers` (List of String) +- `opensearch_tls_protocols` (List of String) +- `sgw_acl` (String) Comma separated list of IP networks in CIDR notation which are allowed to access this instance. +- `syslog` (List of String) List of syslog servers to send logs to. +- `syslog_use_udp` (String) diff --git a/docs/data-sources/rabbitmq_instance.md b/docs/data-sources/rabbitmq_instance.md index 7881ba9d..05fc6f46 100644 --- a/docs/data-sources/rabbitmq_instance.md +++ b/docs/data-sources/rabbitmq_instance.md @@ -46,16 +46,16 @@ data "stackit_rabbitmq_instance" "example" { Read-Only: -- `consumer_timeout` (Number) -- `enable_monitoring` (Boolean) -- `graphite` (String) -- `max_disk_threshold` (Number) -- `metrics_frequency` (Number) -- `metrics_prefix` (String) -- `monitoring_instance_id` (String) -- `plugins` (List of String) -- `roles` (List of String) -- `sgw_acl` (String) -- `syslog` (List of String) -- `tls_ciphers` (List of String) -- `tls_protocols` (String) +- `consumer_timeout` (Number) The timeout in milliseconds for the consumer. +- `enable_monitoring` (Boolean) Enable monitoring. +- `graphite` (String) Graphite server URL (host and port). If set, monitoring with Graphite will be enabled. +- `max_disk_threshold` (Number) The maximum disk threshold in MB. If the disk usage exceeds this threshold, the instance will be stopped. +- `metrics_frequency` (Number) The frequency in seconds at which metrics are emitted. +- `metrics_prefix` (String) The prefix for the metrics. Could be useful when using Graphite monitoring to prefix the metrics with a certain value, like an API key +- `monitoring_instance_id` (String) The monitoring instance ID. +- `plugins` (List of String) List of plugins to install. Must be a supported plugin name. +- `roles` (List of String) List of roles to assign to the instance. +- `sgw_acl` (String) Comma separated list of IP networks in CIDR notation which are allowed to access this instance. +- `syslog` (List of String) List of syslog servers to send logs to. +- `tls_ciphers` (List of String) List of TLS ciphers to use. +- `tls_protocols` (String) TLS protocol to use. diff --git a/docs/data-sources/redis_instance.md b/docs/data-sources/redis_instance.md index 2e65f240..244ef30b 100644 --- a/docs/data-sources/redis_instance.md +++ b/docs/data-sources/redis_instance.md @@ -46,25 +46,25 @@ data "stackit_redis_instance" "example" { Read-Only: -- `down_after_milliseconds` (Number) -- `enable_monitoring` (Boolean) -- `failover_timeout` (Number) -- `graphite` (String) -- `lazyfree_lazy_eviction` (String) -- `lazyfree_lazy_expire` (String) -- `lua_time_limit` (Number) -- `max_disk_threshold` (Number) -- `maxclients` (Number) -- `maxmemory_policy` (String) -- `maxmemory_samples` (Number) -- `metrics_frequency` (Number) -- `metrics_prefix` (String) -- `min_replicas_max_lag` (Number) -- `monitoring_instance_id` (String) -- `notify_keyspace_events` (String) -- `sgw_acl` (String) -- `snapshot` (String) -- `syslog` (List of String) -- `tls_ciphers` (List of String) -- `tls_ciphersuites` (String) -- `tls_protocols` (String) +- `down_after_milliseconds` (Number) The number of milliseconds after which the instance is considered down. +- `enable_monitoring` (Boolean) Enable monitoring. +- `failover_timeout` (Number) The failover timeout in milliseconds. +- `graphite` (String) Graphite server URL (host and port). If set, monitoring with Graphite will be enabled. +- `lazyfree_lazy_eviction` (String) The lazy eviction enablement (yes or no). +- `lazyfree_lazy_expire` (String) The lazy expire enablement (yes or no). +- `lua_time_limit` (Number) The Lua time limit. +- `max_disk_threshold` (Number) The maximum disk threshold in MB. If the disk usage exceeds this threshold, the instance will be stopped. +- `maxclients` (Number) The maximum number of clients. +- `maxmemory_policy` (String) The policy to handle the maximum memory (volatile-lru, noeviction, etc). +- `maxmemory_samples` (Number) The maximum memory samples. +- `metrics_frequency` (Number) The frequency in seconds at which metrics are emitted. +- `metrics_prefix` (String) The prefix for the metrics. Could be useful when using Graphite monitoring to prefix the metrics with a certain value, like an API key +- `min_replicas_max_lag` (Number) The minimum replicas maximum lag. +- `monitoring_instance_id` (String) The monitoring instance ID. +- `notify_keyspace_events` (String) The notify keyspace events. +- `sgw_acl` (String) Comma separated list of IP networks in CIDR notation which are allowed to access this instance. +- `snapshot` (String) The snapshot configuration. +- `syslog` (List of String) List of syslog servers to send logs to. +- `tls_ciphers` (List of String) List of TLS ciphers to use. +- `tls_ciphersuites` (String) TLS cipher suites to use. +- `tls_protocols` (String) TLS protocol to use. diff --git a/docs/resources/logme_instance.md b/docs/resources/logme_instance.md index 1141763d..43200f76 100644 --- a/docs/resources/logme_instance.md +++ b/docs/resources/logme_instance.md @@ -54,4 +54,26 @@ resource "stackit_logme_instance" "example" { Optional: -- `sgw_acl` (String) +- `enable_monitoring` (Boolean) Enable monitoring. +- `fluentd_tcp` (Number) +- `fluentd_tls` (Number) +- `fluentd_tls_ciphers` (String) +- `fluentd_tls_max_version` (String) +- `fluentd_tls_min_version` (String) +- `fluentd_tls_version` (String) +- `fluentd_udp` (Number) +- `graphite` (String) If set, monitoring with Graphite will be enabled. Expects the host and port where the Graphite metrics should be sent to (host:port). +- `ism_deletion_after` (String) Combination of an integer and a timerange when an index will be considered "old" and can be deleted. Possible values for the timerange are `s`, `m`, `h` and `d`. +- `ism_jitter` (Number) +- `ism_job_interval` (Number) Jitter of the execution time. +- `java_heapspace` (Number) The amount of memory (in MB) allocated as heap by the JVM for OpenSearch. +- `java_maxmetaspace` (Number) The amount of memory (in MB) used by the JVM to store metadata for OpenSearch. +- `max_disk_threshold` (Number) The maximum disk threshold in MB. If the disk usage exceeds this threshold, the instance will be stopped. +- `metrics_frequency` (Number) The frequency in seconds at which metrics are emitted (in seconds). +- `metrics_prefix` (String) The prefix for the metrics. Could be useful when using Graphite monitoring to prefix the metrics with a certain value, like an API key. +- `monitoring_instance_id` (String) The monitoring instance ID. +- `opensearch_tls_ciphers` (List of String) +- `opensearch_tls_protocols` (List of String) +- `sgw_acl` (String) Comma separated list of IP networks in CIDR notation which are allowed to access this instance. +- `syslog` (List of String) List of syslog servers to send logs to. +- `syslog_use_udp` (String) diff --git a/stackit/internal/conversion/conversion.go b/stackit/internal/conversion/conversion.go index 47450338..56df3c77 100644 --- a/stackit/internal/conversion/conversion.go +++ b/stackit/internal/conversion/conversion.go @@ -78,6 +78,16 @@ func Int64ValueToPointer(s basetypes.Int64Value) *int64 { return &value } +// Float64ValueToPointer converts basetypes.Float64Value to a pointer to float64. +// It returns nil if the value is null or unknown. +func Float64ValueToPointer(s basetypes.Float64Value) *float64 { + if s.IsNull() || s.IsUnknown() { + return nil + } + value := s.ValueFloat64() + return &value +} + // BoolValueToPointer converts basetypes.BoolValue to a pointer to bool. // It returns nil if the value is null or unknown. func BoolValueToPointer(s basetypes.BoolValue) *bool { diff --git a/stackit/internal/services/logme/instance/datasource.go b/stackit/internal/services/logme/instance/datasource.go index 4a307906..0c53d1c4 100644 --- a/stackit/internal/services/logme/instance/datasource.go +++ b/stackit/internal/services/logme/instance/datasource.go @@ -7,6 +7,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" @@ -86,6 +87,23 @@ func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaReques "plan_id": "The selected plan ID.", } + parametersDescriptions := map[string]string{ + "sgw_acl": "Comma separated list of IP networks in CIDR notation which are allowed to access this instance.", + "enable_monitoring": "Enable monitoring.", + "graphite": "If set, monitoring with Graphite will be enabled. Expects the host and port where the Graphite metrics should be sent to (host:port).", + "max_disk_threshold": "The maximum disk threshold in MB. If the disk usage exceeds this threshold, the instance will be stopped.", + "metrics_frequency": "The frequency in seconds at which metrics are emitted (in seconds).", + "metrics_prefix": "The prefix for the metrics. Could be useful when using Graphite monitoring to prefix the metrics with a certain value, like an API key.", + "monitoring_instance_id": "The monitoring instance ID.", + "java_heapspace": "The amount of memory (in MB) allocated as heap by the JVM for OpenSearch.", + "java_maxmetaspace": "The amount of memory (in MB) used by the JVM to store metadata for OpenSearch.", + "ism_deletion_after": "Combination of an integer and a timerange when an index will be considered \"old\" and can be deleted. Possible values for the timerange are `s`, `m`, `h` and `d`.", + "ism_job_interval": "Jitter of the execution time.", + "syslog": "List of syslog servers to send logs to.", + "syslog-use-udp": "Defines if syslog will use UDP. Possible values: `yes`, `no`.", + "opensearch-tls-ciphers": "List of ciphers to use for TLS.", + } + resp.Schema = schema.Schema{ Description: descriptions["main"], Attributes: map[string]schema.Attribute{ @@ -128,7 +146,99 @@ func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaReques "parameters": schema.SingleNestedAttribute{ Attributes: map[string]schema.Attribute{ "sgw_acl": schema.StringAttribute{ - Computed: true, + Description: parametersDescriptions["sgw_acl"], + Computed: true, + }, + "enable_monitoring": schema.BoolAttribute{ + Description: parametersDescriptions["enable_monitoring"], + Computed: true, + }, + "fluentd_tcp": schema.Int64Attribute{ + Description: parametersDescriptions["fluentd_tcp"], + Computed: true, + }, + "fluentd_tls": schema.Int64Attribute{ + Description: parametersDescriptions["fluentd_tls"], + Computed: true, + }, + "fluentd_tls_ciphers": schema.StringAttribute{ + Description: parametersDescriptions["fluentd_tls_ciphers"], + Computed: true, + }, + "fluentd_tls_max_version": schema.StringAttribute{ + Description: parametersDescriptions["fluentd_tls_max_version"], + Computed: true, + }, + "fluentd_tls_min_version": schema.StringAttribute{ + Description: parametersDescriptions["fluentd_tls_min_version"], + Computed: true, + }, + "fluentd_tls_version": schema.StringAttribute{ + Description: parametersDescriptions["fluentd_tls_version"], + Computed: true, + }, + "fluentd_udp": schema.Int64Attribute{ + Description: parametersDescriptions["fluentd_udp"], + Computed: true, + }, + "graphite": schema.StringAttribute{ + Description: parametersDescriptions["graphite"], + Computed: true, + }, + "ism_deletion_after": schema.StringAttribute{ + Description: parametersDescriptions["ism_deletion_after"], + Computed: true, + }, + "ism_jitter": schema.Float64Attribute{ + Description: parametersDescriptions["ism_jitter"], + Computed: true, + }, + "ism_job_interval": schema.Int64Attribute{ + Description: parametersDescriptions["ism_job_interval"], + Computed: true, + }, + "java_heapspace": schema.Int64Attribute{ + Description: parametersDescriptions["java_heapspace"], + Computed: true, + }, + "java_maxmetaspace": schema.Int64Attribute{ + Description: parametersDescriptions["java_maxmetaspace"], + Computed: true, + }, + "max_disk_threshold": schema.Int64Attribute{ + Description: parametersDescriptions["max_disk_threshold"], + Computed: true, + }, + "metrics_frequency": schema.Int64Attribute{ + Description: parametersDescriptions["metrics_frequency"], + Computed: true, + }, + "metrics_prefix": schema.StringAttribute{ + Description: parametersDescriptions["metrics_prefix"], + Computed: true, + }, + "monitoring_instance_id": schema.StringAttribute{ + Description: parametersDescriptions["monitoring_instance_id"], + Computed: true, + }, + "opensearch_tls_ciphers": schema.ListAttribute{ + Description: parametersDescriptions["opensearch_tls_ciphers"], + ElementType: types.StringType, + Computed: true, + }, + "opensearch_tls_protocols": schema.ListAttribute{ + Description: parametersDescriptions["opensearch_tls_protocols"], + ElementType: types.StringType, + Computed: true, + }, + "syslog": schema.ListAttribute{ + Description: parametersDescriptions["syslog"], + ElementType: types.StringType, + Computed: true, + }, + "syslog_use_udp": schema.StringAttribute{ + Description: parametersDescriptions["syslog_use_udp"], + Computed: true, }, }, Computed: true, diff --git a/stackit/internal/services/logme/instance/resource.go b/stackit/internal/services/logme/instance/resource.go index dccf84a7..9c4ee0c2 100644 --- a/stackit/internal/services/logme/instance/resource.go +++ b/stackit/internal/services/logme/instance/resource.go @@ -4,7 +4,9 @@ import ( "context" "fmt" "net/http" + "slices" "strings" + "time" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/attr" @@ -52,12 +54,56 @@ type Model struct { // Struct corresponding to DataSourceModel.Parameters type parametersModel struct { - SgwAcl types.String `tfsdk:"sgw_acl"` + SgwAcl types.String `tfsdk:"sgw_acl"` + EnableMonitoring types.Bool `tfsdk:"enable_monitoring"` + FluentdTcp types.Int64 `tfsdk:"fluentd_tcp"` + FluentdTls types.Int64 `tfsdk:"fluentd_tls"` + FluentdTlsCiphers types.String `tfsdk:"fluentd_tls_ciphers"` + FluentdTlsMaxVersion types.String `tfsdk:"fluentd_tls_max_version"` + FluentdTlsMinVersion types.String `tfsdk:"fluentd_tls_min_version"` + FluentdTlsVersion types.String `tfsdk:"fluentd_tls_version"` + FluentdUdp types.Int64 `tfsdk:"fluentd_udp"` + Graphite types.String `tfsdk:"graphite"` + IsmDeletionAfter types.String `tfsdk:"ism_deletion_after"` + IsmJitter types.Float64 `tfsdk:"ism_jitter"` + IsmJobInterval types.Int64 `tfsdk:"ism_job_interval"` + JavaHeapspace types.Int64 `tfsdk:"java_heapspace"` + JavaMaxmetaspace types.Int64 `tfsdk:"java_maxmetaspace"` + MaxDiskThreshold types.Int64 `tfsdk:"max_disk_threshold"` + MetricsFrequency types.Int64 `tfsdk:"metrics_frequency"` + MetricsPrefix types.String `tfsdk:"metrics_prefix"` + MonitoringInstanceId types.String `tfsdk:"monitoring_instance_id"` + OpensearchTlsCiphers types.List `tfsdk:"opensearch_tls_ciphers"` + OpensearchTlsProtocols types.List `tfsdk:"opensearch_tls_protocols"` + Syslog types.List `tfsdk:"syslog"` + SyslogUseUdp types.String `tfsdk:"syslog_use_udp"` } // Types corresponding to parametersModel var parametersTypes = map[string]attr.Type{ - "sgw_acl": basetypes.StringType{}, + "sgw_acl": basetypes.StringType{}, + "enable_monitoring": basetypes.BoolType{}, + "fluentd_tcp": basetypes.Int64Type{}, + "fluentd_tls": basetypes.Int64Type{}, + "fluentd_tls_ciphers": basetypes.StringType{}, + "fluentd_tls_max_version": basetypes.StringType{}, + "fluentd_tls_min_version": basetypes.StringType{}, + "fluentd_tls_version": basetypes.StringType{}, + "fluentd_udp": basetypes.Int64Type{}, + "graphite": basetypes.StringType{}, + "ism_deletion_after": basetypes.StringType{}, + "ism_jitter": basetypes.Float64Type{}, + "ism_job_interval": basetypes.Int64Type{}, + "java_heapspace": basetypes.Int64Type{}, + "java_maxmetaspace": basetypes.Int64Type{}, + "max_disk_threshold": basetypes.Int64Type{}, + "metrics_frequency": basetypes.Int64Type{}, + "metrics_prefix": basetypes.StringType{}, + "monitoring_instance_id": basetypes.StringType{}, + "opensearch_tls_ciphers": basetypes.ListType{ElemType: types.StringType}, + "opensearch_tls_protocols": basetypes.ListType{ElemType: types.StringType}, + "syslog": basetypes.ListType{ElemType: types.StringType}, + "syslog_use_udp": basetypes.StringType{}, } // NewInstanceResource is a helper function to simplify the provider implementation. @@ -124,6 +170,23 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r "plan_id": "The selected plan ID.", } + parametersDescriptions := map[string]string{ + "sgw_acl": "Comma separated list of IP networks in CIDR notation which are allowed to access this instance.", + "enable_monitoring": "Enable monitoring.", + "graphite": "If set, monitoring with Graphite will be enabled. Expects the host and port where the Graphite metrics should be sent to (host:port).", + "max_disk_threshold": "The maximum disk threshold in MB. If the disk usage exceeds this threshold, the instance will be stopped.", + "metrics_frequency": "The frequency in seconds at which metrics are emitted (in seconds).", + "metrics_prefix": "The prefix for the metrics. Could be useful when using Graphite monitoring to prefix the metrics with a certain value, like an API key.", + "monitoring_instance_id": "The monitoring instance ID.", + "java_heapspace": "The amount of memory (in MB) allocated as heap by the JVM for OpenSearch.", + "java_maxmetaspace": "The amount of memory (in MB) used by the JVM to store metadata for OpenSearch.", + "ism_deletion_after": "Combination of an integer and a timerange when an index will be considered \"old\" and can be deleted. Possible values for the timerange are `s`, `m`, `h` and `d`.", + "ism_job_interval": "Jitter of the execution time.", + "syslog": "List of syslog servers to send logs to.", + "syslog-use-udp": "Defines if syslog will use UDP. Possible values: `yes`, `no`.", + "opensearch-tls-ciphers": "List of ciphers to use for TLS.", + } + resp.Schema = schema.Schema{ Description: descriptions["main"], Attributes: map[string]schema.Attribute{ @@ -183,8 +246,122 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r "parameters": schema.SingleNestedAttribute{ Attributes: map[string]schema.Attribute{ "sgw_acl": schema.StringAttribute{ - Optional: true, - Computed: true, + Description: parametersDescriptions["sgw_acl"], + Optional: true, + Computed: true, + }, + "enable_monitoring": schema.BoolAttribute{ + Description: parametersDescriptions["enable_monitoring"], + Optional: true, + Computed: true, + }, + "fluentd_tcp": schema.Int64Attribute{ + Description: parametersDescriptions["fluentd_tcp"], + Optional: true, + Computed: true, + }, + "fluentd_tls": schema.Int64Attribute{ + Description: parametersDescriptions["fluentd_tls"], + Optional: true, + Computed: true, + }, + "fluentd_tls_ciphers": schema.StringAttribute{ + Description: parametersDescriptions["fluentd_tls_ciphers"], + Optional: true, + Computed: true, + }, + "fluentd_tls_max_version": schema.StringAttribute{ + Description: parametersDescriptions["fluentd_tls_max_version"], + Optional: true, + Computed: true, + }, + "fluentd_tls_min_version": schema.StringAttribute{ + Description: parametersDescriptions["fluentd_tls_min_version"], + Optional: true, + Computed: true, + }, + "fluentd_tls_version": schema.StringAttribute{ + Description: parametersDescriptions["fluentd_tls_version"], + Optional: true, + Computed: true, + }, + "fluentd_udp": schema.Int64Attribute{ + Description: parametersDescriptions["fluentd_udp"], + Optional: true, + Computed: true, + }, + "graphite": schema.StringAttribute{ + Description: parametersDescriptions["graphite"], + Optional: true, + Computed: true, + }, + "ism_deletion_after": schema.StringAttribute{ + Description: parametersDescriptions["ism_deletion_after"], + Optional: true, + Computed: true, + }, + "ism_jitter": schema.Float64Attribute{ + Description: parametersDescriptions["ism_jitter"], + Optional: true, + Computed: true, + }, + "ism_job_interval": schema.Int64Attribute{ + Description: parametersDescriptions["ism_job_interval"], + Optional: true, + Computed: true, + }, + "java_heapspace": schema.Int64Attribute{ + Description: parametersDescriptions["java_heapspace"], + Optional: true, + Computed: true, + }, + "java_maxmetaspace": schema.Int64Attribute{ + Description: parametersDescriptions["java_maxmetaspace"], + Optional: true, + Computed: true, + }, + "max_disk_threshold": schema.Int64Attribute{ + Description: parametersDescriptions["max_disk_threshold"], + Optional: true, + Computed: true, + }, + "metrics_frequency": schema.Int64Attribute{ + Description: parametersDescriptions["metrics_frequency"], + Optional: true, + Computed: true, + }, + "metrics_prefix": schema.StringAttribute{ + Description: parametersDescriptions["metrics_prefix"], + Optional: true, + Computed: true, + }, + "monitoring_instance_id": schema.StringAttribute{ + Description: parametersDescriptions["monitoring_instance_id"], + Optional: true, + Computed: true, + }, + "opensearch_tls_ciphers": schema.ListAttribute{ + Description: parametersDescriptions["opensearch_tls_ciphers"], + ElementType: types.StringType, + Optional: true, + Computed: true, + }, + "opensearch_tls_protocols": schema.ListAttribute{ + Description: parametersDescriptions["opensearch_tls_protocols"], + ElementType: types.StringType, + Optional: true, + Computed: true, + }, + "syslog": schema.ListAttribute{ + Description: parametersDescriptions["syslog"], + ElementType: types.StringType, + Optional: true, + Computed: true, + }, + "syslog_use_udp": schema.StringAttribute{ + Description: parametersDescriptions["syslog_use_udp"], + Optional: true, + Computed: true, }, }, Optional: true, @@ -235,8 +412,9 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques projectId := model.ProjectId.ValueString() ctx = tflog.SetField(ctx, "project_id", projectId) - var parameters = ¶metersModel{} + var parameters *parametersModel if !(model.Parameters.IsNull() || model.Parameters.IsUnknown()) { + parameters = ¶metersModel{} diags = model.Parameters.As(ctx, parameters, basetypes.ObjectAsOptions{}) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { @@ -264,7 +442,7 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques } instanceId := *createResp.InstanceId ctx = tflog.SetField(ctx, "instance_id", instanceId) - waitResp, err := wait.CreateInstanceWaitHandler(ctx, r.client, projectId, instanceId).WaitWithContext(ctx) + waitResp, err := wait.CreateInstanceWaitHandler(ctx, r.client, projectId, instanceId).SetTimeout(90 * time.Minute).WaitWithContext(ctx) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Instance creation waiting: %v", err)) return @@ -346,8 +524,9 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "instance_id", instanceId) - var parameters = ¶metersModel{} + var parameters *parametersModel if !(model.Parameters.IsNull() || model.Parameters.IsUnknown()) { + parameters = ¶metersModel{} diags = model.Parameters.As(ctx, parameters, basetypes.ObjectAsOptions{}) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { @@ -488,7 +667,30 @@ func mapFields(instance *logme.Instance, model *Model) error { func mapParameters(params map[string]interface{}) (types.Object, error) { attributes := map[string]attr.Value{} for attribute := range parametersTypes { - valueInterface, ok := params[attribute] + var valueInterface interface{} + var ok bool + + // This replacement is necessary because Terraform does not allow hyphens in attribute names + // And the API uses hyphens in some of the attribute names, which would cause a mismatch + // The following attributes have hyphens in the API but underscores in the schema + hyphenAttributes := []string{ + "fluentd_tcp", + "fluentd_tls", + "fluentd_tls_ciphers", + "fluentd_tls_max_version", + "fluentd_tls_min_version", + "fluentd_tls_version", + "fluentd_udp", + "opensearch_tls_ciphers", + "opensearch_tls_protocols", + "syslog_use_udp", + } + if slices.Contains(hyphenAttributes, attribute) { + alteredAttribute := strings.ReplaceAll(attribute, "_", "-") + valueInterface, ok = params[alteredAttribute] + } else { + valueInterface, ok = params[attribute] + } if !ok { // All fields are optional, so this is ok // Set the value as nil, will be handled accordingly @@ -540,6 +742,19 @@ func mapParameters(params map[string]interface{}) (types.Object, error) { } value = types.Int64Value(valueInt64) } + case basetypes.Float64Type: + if valueInterface == nil { + value = types.Float64Null() + } else { + var valueFloat64 float64 + switch temp := valueInterface.(type) { + default: + return types.ObjectNull(parametersTypes), fmt.Errorf("found attribute '%s' of type %T, failed to assert as int", attribute, valueInterface) + case float64: + valueFloat64 = float64(temp) + } + value = types.Float64Value(valueFloat64) + } case basetypes.ListType: // Assumed to be a list of strings if valueInterface == nil { value = types.ListNull(types.StringType) @@ -584,16 +799,12 @@ func toCreatePayload(model *Model, parameters *parametersModel) (*logme.CreateIn if model == nil { return nil, fmt.Errorf("nil model") } - if parameters == nil { - return &logme.CreateInstancePayload{ - InstanceName: conversion.StringValueToPointer(model.Name), - PlanId: conversion.StringValueToPointer(model.PlanId), - }, nil - } - payloadParams := &logme.InstanceParameters{} - if parameters.SgwAcl.ValueString() != "" { - payloadParams.SgwAcl = conversion.StringValueToPointer(parameters.SgwAcl) + + payloadParams, err := toInstanceParams(parameters) + if err != nil { + return nil, fmt.Errorf("convert parameters: %w", err) } + return &logme.CreateInstancePayload{ InstanceName: conversion.StringValueToPointer(model.Name), Parameters: payloadParams, @@ -606,19 +817,63 @@ func toUpdatePayload(model *Model, parameters *parametersModel) (*logme.PartialU return nil, fmt.Errorf("nil model") } - if parameters == nil { - return &logme.PartialUpdateInstancePayload{ - PlanId: conversion.StringValueToPointer(model.PlanId), - }, nil + payloadParams, err := toInstanceParams(parameters) + if err != nil { + return nil, fmt.Errorf("convert parameters: %w", err) } + return &logme.PartialUpdateInstancePayload{ - Parameters: &logme.InstanceParameters{ - SgwAcl: conversion.StringValueToPointer(parameters.SgwAcl), - }, - PlanId: conversion.StringValueToPointer(model.PlanId), + Parameters: payloadParams, + PlanId: conversion.StringValueToPointer(model.PlanId), }, nil } +func toInstanceParams(parameters *parametersModel) (*logme.InstanceParameters, error) { + if parameters == nil { + return nil, nil + } + payloadParams := &logme.InstanceParameters{} + + payloadParams.SgwAcl = conversion.StringValueToPointer(parameters.SgwAcl) + payloadParams.EnableMonitoring = conversion.BoolValueToPointer(parameters.EnableMonitoring) + payloadParams.FluentdTcp = conversion.Int64ValueToPointer(parameters.FluentdTcp) + payloadParams.FluentdTls = conversion.Int64ValueToPointer(parameters.FluentdTls) + payloadParams.FluentdTlsCiphers = conversion.StringValueToPointer(parameters.FluentdTlsCiphers) + payloadParams.FluentdTlsMaxVersion = conversion.StringValueToPointer(parameters.FluentdTlsMaxVersion) + payloadParams.FluentdTlsMinVersion = conversion.StringValueToPointer(parameters.FluentdTlsMinVersion) + payloadParams.FluentdTlsVersion = conversion.StringValueToPointer(parameters.FluentdTlsVersion) + payloadParams.FluentdUdp = conversion.Int64ValueToPointer(parameters.FluentdUdp) + payloadParams.Graphite = conversion.StringValueToPointer(parameters.Graphite) + payloadParams.IsmDeletionAfter = conversion.StringValueToPointer(parameters.IsmDeletionAfter) + payloadParams.IsmJitter = conversion.Float64ValueToPointer(parameters.IsmJitter) + payloadParams.IsmJobInterval = conversion.Int64ValueToPointer(parameters.IsmJobInterval) + payloadParams.JavaHeapspace = conversion.Int64ValueToPointer(parameters.JavaHeapspace) + payloadParams.JavaMaxmetaspace = conversion.Int64ValueToPointer(parameters.JavaMaxmetaspace) + payloadParams.MaxDiskThreshold = conversion.Int64ValueToPointer(parameters.MaxDiskThreshold) + payloadParams.MetricsFrequency = conversion.Int64ValueToPointer(parameters.MetricsFrequency) + payloadParams.MetricsPrefix = conversion.StringValueToPointer(parameters.MetricsPrefix) + payloadParams.MonitoringInstanceId = conversion.StringValueToPointer(parameters.MonitoringInstanceId) + payloadParams.SyslogUseUdp = conversion.StringValueToPointer(parameters.SyslogUseUdp) + + var err error + payloadParams.OpensearchTlsCiphers, err = conversion.StringListToPointer(parameters.OpensearchTlsCiphers) + if err != nil { + return nil, fmt.Errorf("convert opensearch_tls_ciphers: %w", err) + } + + payloadParams.OpensearchTlsProtocols, err = conversion.StringListToPointer(parameters.OpensearchTlsProtocols) + if err != nil { + return nil, fmt.Errorf("convert opensearch_tls_protocols: %w", err) + } + + payloadParams.Syslog, err = conversion.StringListToPointer(parameters.Syslog) + if err != nil { + return nil, fmt.Errorf("convert syslog: %w", err) + } + + return payloadParams, nil +} + func (r *instanceResource) loadPlanId(ctx context.Context, model *Model) error { projectId := model.ProjectId.ValueString() res, err := r.client.ListOfferings(ctx, projectId).Execute() diff --git a/stackit/internal/services/logme/instance/resource_test.go b/stackit/internal/services/logme/instance/resource_test.go index af204fb5..2d7535c0 100644 --- a/stackit/internal/services/logme/instance/resource_test.go +++ b/stackit/internal/services/logme/instance/resource_test.go @@ -1,15 +1,104 @@ package logme import ( + "context" "testing" "github.com/google/go-cmp/cmp" "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" "github.com/stackitcloud/stackit-sdk-go/core/utils" "github.com/stackitcloud/stackit-sdk-go/services/logme" ) +var fixtureModelParameters = types.ObjectValueMust(parametersTypes, map[string]attr.Value{ + "sgw_acl": types.StringValue("acl"), + "enable_monitoring": types.BoolValue(true), + "fluentd_tcp": types.Int64Value(10), + "fluentd_tls": types.Int64Value(10), + "fluentd_tls_ciphers": types.StringValue("ciphers"), + "fluentd_tls_max_version": types.StringValue("max_version"), + "fluentd_tls_min_version": types.StringValue("min_version"), + "fluentd_tls_version": types.StringValue("version"), + "fluentd_udp": types.Int64Value(10), + "graphite": types.StringValue("graphite"), + "ism_deletion_after": types.StringValue("deletion_after"), + "ism_jitter": types.Float64Value(10.1), + "ism_job_interval": types.Int64Value(10), + "java_heapspace": types.Int64Value(10), + "java_maxmetaspace": types.Int64Value(10), + "max_disk_threshold": types.Int64Value(10), + "metrics_frequency": types.Int64Value(10), + "metrics_prefix": types.StringValue("prefix"), + "monitoring_instance_id": types.StringValue("mid"), + "opensearch_tls_ciphers": types.ListValueMust(types.StringType, []attr.Value{ + types.StringValue("ciphers"), + types.StringValue("ciphers2"), + }), + "opensearch_tls_protocols": types.ListValueMust(types.StringType, []attr.Value{ + types.StringValue("protocols"), + types.StringValue("protocols2"), + }), + "syslog": types.ListValueMust(types.StringType, []attr.Value{ + types.StringValue("syslog"), + types.StringValue("syslog2"), + }), + "syslog_use_udp": types.StringValue("udp"), +}) + +var fixtureNullModelParameters = types.ObjectValueMust(parametersTypes, map[string]attr.Value{ + "sgw_acl": types.StringNull(), + "enable_monitoring": types.BoolNull(), + "fluentd_tcp": types.Int64Null(), + "fluentd_tls": types.Int64Null(), + "fluentd_tls_ciphers": types.StringNull(), + "fluentd_tls_max_version": types.StringNull(), + "fluentd_tls_min_version": types.StringNull(), + "fluentd_tls_version": types.StringNull(), + "fluentd_udp": types.Int64Null(), + "graphite": types.StringNull(), + "ism_deletion_after": types.StringNull(), + "ism_jitter": types.Float64Null(), + "ism_job_interval": types.Int64Null(), + "java_heapspace": types.Int64Null(), + "java_maxmetaspace": types.Int64Null(), + "max_disk_threshold": types.Int64Null(), + "metrics_frequency": types.Int64Null(), + "metrics_prefix": types.StringNull(), + "monitoring_instance_id": types.StringNull(), + "opensearch_tls_ciphers": types.ListNull(types.StringType), + "opensearch_tls_protocols": types.ListNull(types.StringType), + "syslog": types.ListNull(types.StringType), + "syslog_use_udp": types.StringNull(), +}) + +var fixtureInstanceParameters = logme.InstanceParameters{ + SgwAcl: utils.Ptr("acl"), + EnableMonitoring: utils.Ptr(true), + FluentdTcp: utils.Ptr(int64(10)), + FluentdTls: utils.Ptr(int64(10)), + FluentdTlsCiphers: utils.Ptr("ciphers"), + FluentdTlsMaxVersion: utils.Ptr("max_version"), + FluentdTlsMinVersion: utils.Ptr("min_version"), + FluentdTlsVersion: utils.Ptr("version"), + FluentdUdp: utils.Ptr(int64(10)), + Graphite: utils.Ptr("graphite"), + IsmDeletionAfter: utils.Ptr("deletion_after"), + IsmJitter: utils.Ptr(10.1), + IsmJobInterval: utils.Ptr(int64(10)), + JavaHeapspace: utils.Ptr(int64(10)), + JavaMaxmetaspace: utils.Ptr(int64(10)), + MaxDiskThreshold: utils.Ptr(int64(10)), + MetricsFrequency: utils.Ptr(int64(10)), + MetricsPrefix: utils.Ptr("prefix"), + MonitoringInstanceId: utils.Ptr("mid"), + OpensearchTlsCiphers: &[]string{"ciphers", "ciphers2"}, + OpensearchTlsProtocols: &[]string{"protocols", "protocols2"}, + Syslog: &[]string{"syslog", "syslog2"}, + SyslogUseUdp: utils.Ptr("udp"), +} + func TestMapFields(t *testing.T) { tests := []struct { description string @@ -47,7 +136,30 @@ func TestMapFields(t *testing.T) { Name: utils.Ptr("name"), CfOrganizationGuid: utils.Ptr("org"), Parameters: &map[string]interface{}{ - "sgw_acl": "acl", + // Using "-" on purpose on some fields because that is the API response + "sgw_acl": "acl", + "enable_monitoring": true, + "fluentd-tcp": 10, + "fluentd-tls": 10, + "fluentd-tls-ciphers": "ciphers", + "fluentd-tls-max-version": "max_version", + "fluentd-tls-min-version": "min_version", + "fluentd-tls-version": "version", + "fluentd-udp": 10, + "graphite": "graphite", + "ism_deletion_after": "deletion_after", + "ism_jitter": 10.1, + "ism_job_interval": 10, + "java_heapspace": 10, + "java_maxmetaspace": 10, + "max_disk_threshold": 10, + "metrics_frequency": 10, + "metrics_prefix": "prefix", + "monitoring_instance_id": "mid", + "opensearch-tls-ciphers": []string{"ciphers", "ciphers2"}, + "opensearch-tls-protocols": []string{"protocols", "protocols2"}, + "syslog": []string{"syslog", "syslog2"}, + "syslog-use-udp": "udp", }, }, Model{ @@ -61,9 +173,7 @@ func TestMapFields(t *testing.T) { DashboardUrl: types.StringValue("dashboard"), ImageUrl: types.StringValue("image"), CfOrganizationGuid: types.StringValue("org"), - Parameters: types.ObjectValueMust(parametersTypes, map[string]attr.Value{ - "sgw_acl": types.StringValue("acl"), - }), + Parameters: fixtureModelParameters, }, true, }, @@ -125,61 +235,48 @@ func TestMapFields(t *testing.T) { func TestToCreatePayload(t *testing.T) { tests := []struct { - description string - input *Model - inputParameters *parametersModel - expected *logme.CreateInstancePayload - isValid bool + description string + input *Model + expected *logme.CreateInstancePayload + isValid bool }{ { "default_values", &Model{}, - ¶metersModel{}, - &logme.CreateInstancePayload{ - Parameters: &logme.InstanceParameters{}, - }, + &logme.CreateInstancePayload{}, true, }, { "simple_values", &Model{ - Name: types.StringValue("name"), - PlanId: types.StringValue("plan"), - }, - ¶metersModel{ - SgwAcl: types.StringValue("sgw"), + Name: types.StringValue("name"), + PlanId: types.StringValue("plan"), + Parameters: fixtureModelParameters, }, &logme.CreateInstancePayload{ InstanceName: utils.Ptr("name"), - Parameters: &logme.InstanceParameters{ - SgwAcl: utils.Ptr("sgw"), - }, - PlanId: utils.Ptr("plan"), + PlanId: utils.Ptr("plan"), + Parameters: &fixtureInstanceParameters, }, true, }, { "null_fields_and_int_conversions", &Model{ - Name: types.StringValue(""), - PlanId: types.StringValue(""), - }, - ¶metersModel{ - SgwAcl: types.StringNull(), + Name: types.StringValue(""), + PlanId: types.StringValue(""), + Parameters: fixtureNullModelParameters, }, &logme.CreateInstancePayload{ InstanceName: utils.Ptr(""), - Parameters: &logme.InstanceParameters{ - SgwAcl: nil, - }, - PlanId: utils.Ptr(""), + PlanId: utils.Ptr(""), + Parameters: &logme.InstanceParameters{}, }, true, }, { "nil_model", nil, - ¶metersModel{}, nil, false, }, @@ -189,7 +286,6 @@ func TestToCreatePayload(t *testing.T) { Name: types.StringValue("name"), PlanId: types.StringValue("plan"), }, - nil, &logme.CreateInstancePayload{ InstanceName: utils.Ptr("name"), PlanId: utils.Ptr("plan"), @@ -199,7 +295,17 @@ func TestToCreatePayload(t *testing.T) { } for _, tt := range tests { t.Run(tt.description, func(t *testing.T) { - output, err := toCreatePayload(tt.input, tt.inputParameters) + var parameters *parametersModel + if tt.input != nil { + if !(tt.input.Parameters.IsNull() || tt.input.Parameters.IsUnknown()) { + parameters = ¶metersModel{} + diags := tt.input.Parameters.As(context.Background(), parameters, basetypes.ObjectAsOptions{}) + if diags.HasError() { + t.Fatalf("Error converting parameters: %v", diags.Errors()) + } + } + } + output, err := toCreatePayload(tt.input, parameters) if !tt.isValid && err == nil { t.Fatalf("Should have failed") } @@ -218,57 +324,44 @@ func TestToCreatePayload(t *testing.T) { func TestToUpdatePayload(t *testing.T) { tests := []struct { - description string - input *Model - inputParameters *parametersModel - expected *logme.PartialUpdateInstancePayload - isValid bool + description string + input *Model + expected *logme.PartialUpdateInstancePayload + isValid bool }{ { "default_values", &Model{}, - ¶metersModel{}, - &logme.PartialUpdateInstancePayload{ - Parameters: &logme.InstanceParameters{}, - }, + &logme.PartialUpdateInstancePayload{}, true, }, { "simple_values", &Model{ - PlanId: types.StringValue("plan"), - }, - ¶metersModel{ - SgwAcl: types.StringValue("sgw"), + PlanId: types.StringValue("plan"), + Parameters: fixtureModelParameters, }, &logme.PartialUpdateInstancePayload{ - Parameters: &logme.InstanceParameters{ - SgwAcl: utils.Ptr("sgw"), - }, - PlanId: utils.Ptr("plan"), + Parameters: &fixtureInstanceParameters, + PlanId: utils.Ptr("plan"), }, true, }, { "null_fields_and_int_conversions", &Model{ - PlanId: types.StringValue(""), - }, - ¶metersModel{ - SgwAcl: types.StringNull(), + PlanId: types.StringValue(""), + Parameters: fixtureNullModelParameters, }, &logme.PartialUpdateInstancePayload{ - Parameters: &logme.InstanceParameters{ - SgwAcl: nil, - }, - PlanId: utils.Ptr(""), + Parameters: &logme.InstanceParameters{}, + PlanId: utils.Ptr(""), }, true, }, { "nil_model", nil, - ¶metersModel{}, nil, false, }, @@ -277,7 +370,6 @@ func TestToUpdatePayload(t *testing.T) { &Model{ PlanId: types.StringValue("plan"), }, - nil, &logme.PartialUpdateInstancePayload{ PlanId: utils.Ptr("plan"), }, @@ -286,7 +378,17 @@ func TestToUpdatePayload(t *testing.T) { } for _, tt := range tests { t.Run(tt.description, func(t *testing.T) { - output, err := toUpdatePayload(tt.input, tt.inputParameters) + var parameters *parametersModel + if tt.input != nil { + if !(tt.input.Parameters.IsNull() || tt.input.Parameters.IsUnknown()) { + parameters = ¶metersModel{} + diags := tt.input.Parameters.As(context.Background(), parameters, basetypes.ObjectAsOptions{}) + if diags.HasError() { + t.Fatalf("Error converting parameters: %v", diags.Errors()) + } + } + } + output, err := toUpdatePayload(tt.input, parameters) if !tt.isValid && err == nil { t.Fatalf("Should have failed") } diff --git a/stackit/internal/services/logme/logme_acc_test.go b/stackit/internal/services/logme/logme_acc_test.go index 8783b6e5..aac3b261 100644 --- a/stackit/internal/services/logme/logme_acc_test.go +++ b/stackit/internal/services/logme/logme_acc_test.go @@ -18,16 +18,49 @@ import ( // Instance resource data var instanceResource = map[string]string{ - "project_id": testutil.ProjectId, - "name": testutil.ResourceNameWithDateTime("logme"), - "plan_id": "201d743c-0f06-4af2-8f20-649baf4819ae", - "plan_name": "stackit-logme2-1.2.50-replica", - "version": "2", - "sgw_acl-1": "192.168.0.0/16", - "sgw_acl-2": "192.168.0.0/24", + "project_id": testutil.ProjectId, + "name": testutil.ResourceNameWithDateTime("logme"), + "plan_id": "201d743c-0f06-4af2-8f20-649baf4819ae", + "plan_name": "stackit-logme2-1.2.50-replica", + "version": "2", + "sgw_acl-1": "192.168.0.0/16", + "sgw_acl-2": "192.168.0.0/24", + "fluent_tcp": "4", + "max_disk_threshold": "80", + "enable_monitoring": "false", + "syslog-0": "syslog.example.com:514", + "ism_jitter": "0.6", } -func resourceConfig(acls string) string { +func parametersConfig(params map[string]string) string { + nonStringParams := []string{ + "enable_monitoring", + "fluentd_tcp", + "fluentd_tls", + "fluentd_udp", + "ism_jitter", + "ism_job_interval", + "java_heapspace", + "java_maxmetaspace", + "max_disk_threshold", + "metrics_frequency", + "opensearch_tls_ciphers", + "opensearch_tls_protocols", + "syslog", + } + parameters := "parameters = {" + for k, v := range params { + if utils.Contains(nonStringParams, k) { + parameters += fmt.Sprintf("%s = %s\n", k, v) + } else { + parameters += fmt.Sprintf("%s = %q\n", k, v) + } + } + parameters += "\n}" + return parameters +} + +func resourceConfig(params map[string]string) string { return fmt.Sprintf(` %s @@ -36,9 +69,7 @@ func resourceConfig(acls string) string { name = "%s" plan_name = "%s" version = "%s" - parameters = { - sgw_acl = "%s" - } + %s } resource "stackit_logme_credential" "credential" { @@ -51,7 +82,7 @@ func resourceConfig(acls string) string { instanceResource["name"], instanceResource["plan_name"], instanceResource["version"], - acls, + parametersConfig(params), ) } func TestAccLogMeResource(t *testing.T) { @@ -62,7 +93,15 @@ func TestAccLogMeResource(t *testing.T) { // Creation { - Config: resourceConfig(instanceResource["sgw_acl-1"]), + Config: resourceConfig( + map[string]string{ + "sgw_acl": instanceResource["sgw_acl-1"], + "fluentd_tcp": instanceResource["fluent_tcp"], + "max_disk_threshold": instanceResource["max_disk_threshold"], + "enable_monitoring": instanceResource["enable_monitoring"], + "syslog": fmt.Sprintf(`[%q]`, instanceResource["syslog-0"]), + "ism_jitter": instanceResource["ism_jitter"], + }), Check: resource.ComposeAggregateTestCheckFunc( // Instance data resource.TestCheckResourceAttr("stackit_logme_instance.instance", "project_id", instanceResource["project_id"]), @@ -72,6 +111,12 @@ func TestAccLogMeResource(t *testing.T) { resource.TestCheckResourceAttr("stackit_logme_instance.instance", "version", instanceResource["version"]), resource.TestCheckResourceAttr("stackit_logme_instance.instance", "name", instanceResource["name"]), resource.TestCheckResourceAttr("stackit_logme_instance.instance", "parameters.sgw_acl", instanceResource["sgw_acl-1"]), + resource.TestCheckResourceAttr("stackit_logme_instance.instance", "parameters.fluentd_tcp", instanceResource["fluent_tcp"]), + resource.TestCheckResourceAttr("stackit_logme_instance.instance", "parameters.max_disk_threshold", instanceResource["max_disk_threshold"]), + resource.TestCheckResourceAttr("stackit_logme_instance.instance", "parameters.enable_monitoring", instanceResource["enable_monitoring"]), + resource.TestCheckResourceAttr("stackit_logme_instance.instance", "parameters.syslog.#", "1"), + resource.TestCheckResourceAttr("stackit_logme_instance.instance", "parameters.syslog.0", instanceResource["syslog-0"]), + resource.TestCheckResourceAttr("stackit_logme_instance.instance", "parameters.ism_jitter", instanceResource["ism_jitter"]), // Credential data resource.TestCheckResourceAttrPair( @@ -101,7 +146,14 @@ func TestAccLogMeResource(t *testing.T) { instance_id = stackit_logme_credential.credential.instance_id credential_id = stackit_logme_credential.credential.credential_id }`, - resourceConfig(instanceResource["sgw_acl-1"]), + resourceConfig(map[string]string{ + "sgw_acl": instanceResource["sgw_acl-1"], + "fluentd_tcp": instanceResource["fluent_tcp"], + "max_disk_threshold": instanceResource["max_disk_threshold"], + "enable_monitoring": instanceResource["enable_monitoring"], + "syslog": fmt.Sprintf(`[%q]`, instanceResource["syslog-0"]), + "ism_jitter": instanceResource["ism_jitter"], + }), ), Check: resource.ComposeAggregateTestCheckFunc( // Instance data @@ -114,6 +166,12 @@ func TestAccLogMeResource(t *testing.T) { resource.TestCheckResourceAttr("data.stackit_logme_instance.instance", "plan_id", instanceResource["plan_id"]), resource.TestCheckResourceAttr("data.stackit_logme_instance.instance", "name", instanceResource["name"]), resource.TestCheckResourceAttr("data.stackit_logme_instance.instance", "parameters.sgw_acl", instanceResource["sgw_acl-1"]), + resource.TestCheckResourceAttr("data.stackit_logme_instance.instance", "parameters.fluentd_tcp", instanceResource["fluent_tcp"]), + resource.TestCheckResourceAttr("data.stackit_logme_instance.instance", "parameters.max_disk_threshold", instanceResource["max_disk_threshold"]), + resource.TestCheckResourceAttr("data.stackit_logme_instance.instance", "parameters.enable_monitoring", instanceResource["enable_monitoring"]), + resource.TestCheckResourceAttr("data.stackit_logme_instance.instance", "parameters.syslog.#", "1"), + resource.TestCheckResourceAttr("data.stackit_logme_instance.instance", "parameters.syslog.0", instanceResource["syslog-0"]), + resource.TestCheckResourceAttr("data.stackit_logme_instance.instance", "parameters.ism_jitter", instanceResource["ism_jitter"]), // Credential data resource.TestCheckResourceAttr("data.stackit_logme_credential.credential", "project_id", instanceResource["project_id"]), @@ -162,7 +220,14 @@ func TestAccLogMeResource(t *testing.T) { }, // Update { - Config: resourceConfig(instanceResource["sgw_acl-2"]), + Config: resourceConfig(map[string]string{ + "sgw_acl": instanceResource["sgw_acl-2"], + "fluentd_tcp": instanceResource["fluent_tcp"], + "max_disk_threshold": instanceResource["max_disk_threshold"], + "enable_monitoring": instanceResource["enable_monitoring"], + "syslog": fmt.Sprintf(`[%q]`, instanceResource["syslog-0"]), + "ism_jitter": instanceResource["ism_jitter"], + }), Check: resource.ComposeAggregateTestCheckFunc( // Instance data resource.TestCheckResourceAttr("stackit_logme_instance.instance", "project_id", instanceResource["project_id"]), @@ -172,6 +237,12 @@ func TestAccLogMeResource(t *testing.T) { resource.TestCheckResourceAttr("stackit_logme_instance.instance", "version", instanceResource["version"]), resource.TestCheckResourceAttr("stackit_logme_instance.instance", "name", instanceResource["name"]), resource.TestCheckResourceAttr("stackit_logme_instance.instance", "parameters.sgw_acl", instanceResource["sgw_acl-2"]), + resource.TestCheckResourceAttr("stackit_logme_instance.instance", "parameters.fluentd_tcp", instanceResource["fluent_tcp"]), + resource.TestCheckResourceAttr("stackit_logme_instance.instance", "parameters.max_disk_threshold", instanceResource["max_disk_threshold"]), + resource.TestCheckResourceAttr("stackit_logme_instance.instance", "parameters.enable_monitoring", instanceResource["enable_monitoring"]), + resource.TestCheckResourceAttr("stackit_logme_instance.instance", "parameters.syslog.#", "1"), + resource.TestCheckResourceAttr("stackit_logme_instance.instance", "parameters.syslog.0", instanceResource["syslog-0"]), + resource.TestCheckResourceAttr("stackit_logme_instance.instance", "parameters.ism_jitter", instanceResource["ism_jitter"]), ), }, // Deletion is done by the framework implicitly diff --git a/stackit/internal/services/rabbitmq/instance/datasource.go b/stackit/internal/services/rabbitmq/instance/datasource.go index b6a96012..90826308 100644 --- a/stackit/internal/services/rabbitmq/instance/datasource.go +++ b/stackit/internal/services/rabbitmq/instance/datasource.go @@ -87,6 +87,22 @@ func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaReques "plan_id": "The selected plan ID.", } + parametersDescriptions := map[string]string{ + "sgw_acl": "Comma separated list of IP networks in CIDR notation which are allowed to access this instance.", + "consumer_timeout": "The timeout in milliseconds for the consumer.", + "enable_monitoring": "Enable monitoring.", + "graphite": "Graphite server URL (host and port). If set, monitoring with Graphite will be enabled.", + "max_disk_threshold": "The maximum disk threshold in MB. If the disk usage exceeds this threshold, the instance will be stopped.", + "metrics_frequency": "The frequency in seconds at which metrics are emitted.", + "metrics_prefix": "The prefix for the metrics. Could be useful when using Graphite monitoring to prefix the metrics with a certain value, like an API key", + "monitoring_instance_id": "The monitoring instance ID.", + "plugins": "List of plugins to install. Must be a supported plugin name.", + "roles": "List of roles to assign to the instance.", + "syslog": "List of syslog servers to send logs to.", + "tls_ciphers": "List of TLS ciphers to use.", + "tls_protocols": "TLS protocol to use.", + } + resp.Schema = schema.Schema{ Description: descriptions["main"], Attributes: map[string]schema.Attribute{ @@ -129,47 +145,60 @@ func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaReques "parameters": schema.SingleNestedAttribute{ Attributes: map[string]schema.Attribute{ "sgw_acl": schema.StringAttribute{ - Computed: true, + Description: parametersDescriptions["sgw_acl"], + Computed: true, }, "consumer_timeout": schema.Int64Attribute{ - Computed: true, + Description: parametersDescriptions["consumer_timeout"], + Computed: true, }, "enable_monitoring": schema.BoolAttribute{ - Computed: true, + Description: parametersDescriptions["enable_monitoring"], + Computed: true, }, "graphite": schema.StringAttribute{ - Computed: true, + Description: parametersDescriptions["graphite"], + Computed: true, }, "max_disk_threshold": schema.Int64Attribute{ - Computed: true, + Description: parametersDescriptions["max_disk_threshold"], + Computed: true, }, "metrics_frequency": schema.Int64Attribute{ - Computed: true, + Description: parametersDescriptions["metrics_frequency"], + Computed: true, }, "metrics_prefix": schema.StringAttribute{ - Computed: true, + Description: parametersDescriptions["metrics_prefix"], + Computed: true, }, "monitoring_instance_id": schema.StringAttribute{ - Computed: true, + Description: parametersDescriptions["monitoring_instance_id"], + Computed: true, }, "plugins": schema.ListAttribute{ + Description: parametersDescriptions["plugins"], ElementType: types.StringType, Computed: true, }, "roles": schema.ListAttribute{ + Description: parametersDescriptions["roles"], ElementType: types.StringType, Computed: true, }, "syslog": schema.ListAttribute{ + Description: parametersDescriptions["syslog"], ElementType: types.StringType, Computed: true, }, "tls_ciphers": schema.ListAttribute{ + Description: parametersDescriptions["tls_ciphers"], ElementType: types.StringType, Computed: true, }, "tls_protocols": schema.StringAttribute{ - Computed: true, + Description: parametersDescriptions["tls_protocols"], + Computed: true, }, }, Computed: true, diff --git a/stackit/internal/services/rabbitmq/instance/resource.go b/stackit/internal/services/rabbitmq/instance/resource.go index c58b0621..c69a53da 100644 --- a/stackit/internal/services/rabbitmq/instance/resource.go +++ b/stackit/internal/services/rabbitmq/instance/resource.go @@ -340,7 +340,7 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques projectId := model.ProjectId.ValueString() ctx = tflog.SetField(ctx, "project_id", projectId) - var parameters = ¶metersModel{} + var parameters *parametersModel if !(model.Parameters.IsNull() || model.Parameters.IsUnknown()) { diags = model.Parameters.As(ctx, parameters, basetypes.ObjectAsOptions{}) resp.Diagnostics.Append(diags...) @@ -451,8 +451,9 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "instance_id", instanceId) - var parameters = ¶metersModel{} + var parameters *parametersModel if !(model.Parameters.IsNull() || model.Parameters.IsUnknown()) { + parameters = ¶metersModel{} diags = model.Parameters.As(ctx, parameters, basetypes.ObjectAsOptions{}) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { diff --git a/stackit/internal/services/rabbitmq/instance/resource_test.go b/stackit/internal/services/rabbitmq/instance/resource_test.go index 2eac739e..6a17ceaa 100644 --- a/stackit/internal/services/rabbitmq/instance/resource_test.go +++ b/stackit/internal/services/rabbitmq/instance/resource_test.go @@ -190,9 +190,7 @@ func TestToCreatePayload(t *testing.T) { { "default_values", &Model{}, - &rabbitmq.CreateInstancePayload{ - Parameters: &rabbitmq.InstanceParameters{}, - }, + &rabbitmq.CreateInstancePayload{}, true, }, { @@ -238,16 +236,16 @@ func TestToCreatePayload(t *testing.T) { &rabbitmq.CreateInstancePayload{ InstanceName: utils.Ptr("name"), PlanId: utils.Ptr("plan"), - Parameters: &rabbitmq.InstanceParameters{}, }, true, }, } for _, tt := range tests { t.Run(tt.description, func(t *testing.T) { - var parameters = ¶metersModel{} + var parameters *parametersModel if tt.input != nil { if !(tt.input.Parameters.IsNull() || tt.input.Parameters.IsUnknown()) { + parameters = ¶metersModel{} diags := tt.input.Parameters.As(context.Background(), parameters, basetypes.ObjectAsOptions{}) if diags.HasError() { t.Fatalf("Error converting parameters: %v", diags.Errors()) @@ -281,9 +279,7 @@ func TestToUpdatePayload(t *testing.T) { { "default_values", &Model{}, - &rabbitmq.PartialUpdateInstancePayload{ - Parameters: &rabbitmq.InstanceParameters{}, - }, + &rabbitmq.PartialUpdateInstancePayload{}, true, }, { @@ -323,17 +319,17 @@ func TestToUpdatePayload(t *testing.T) { PlanId: types.StringValue("plan"), }, &rabbitmq.PartialUpdateInstancePayload{ - PlanId: utils.Ptr("plan"), - Parameters: &rabbitmq.InstanceParameters{}, + PlanId: utils.Ptr("plan"), }, true, }, } for _, tt := range tests { t.Run(tt.description, func(t *testing.T) { - var parameters = ¶metersModel{} + var parameters *parametersModel if tt.input != nil { if !(tt.input.Parameters.IsNull() || tt.input.Parameters.IsUnknown()) { + parameters = ¶metersModel{} diags := tt.input.Parameters.As(context.Background(), parameters, basetypes.ObjectAsOptions{}) if diags.HasError() { t.Fatalf("Error converting parameters: %v", diags.Errors()) diff --git a/stackit/internal/services/redis/instance/datasource.go b/stackit/internal/services/redis/instance/datasource.go index f7f5eb23..59792dad 100644 --- a/stackit/internal/services/redis/instance/datasource.go +++ b/stackit/internal/services/redis/instance/datasource.go @@ -87,6 +87,31 @@ func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaReques "plan_id": "The selected plan ID.", } + parametersDescriptions := map[string]string{ + "sgw_acl": "Comma separated list of IP networks in CIDR notation which are allowed to access this instance.", + "down_after_milliseconds": "The number of milliseconds after which the instance is considered down.", + "enable_monitoring": "Enable monitoring.", + "failover_timeout": "The failover timeout in milliseconds.", + "graphite": "Graphite server URL (host and port). If set, monitoring with Graphite will be enabled.", + "lazyfree_lazy_eviction": "The lazy eviction enablement (yes or no).", + "lazyfree_lazy_expire": "The lazy expire enablement (yes or no).", + "lua_time_limit": "The Lua time limit.", + "max_disk_threshold": "The maximum disk threshold in MB. If the disk usage exceeds this threshold, the instance will be stopped.", + "maxclients": "The maximum number of clients.", + "maxmemory_policy": "The policy to handle the maximum memory (volatile-lru, noeviction, etc).", + "maxmemory_samples": "The maximum memory samples.", + "metrics_frequency": "The frequency in seconds at which metrics are emitted.", + "metrics_prefix": "The prefix for the metrics. Could be useful when using Graphite monitoring to prefix the metrics with a certain value, like an API key", + "min_replicas_max_lag": "The minimum replicas maximum lag.", + "monitoring_instance_id": "The monitoring instance ID.", + "notify_keyspace_events": "The notify keyspace events.", + "snapshot": "The snapshot configuration.", + "syslog": "List of syslog servers to send logs to.", + "tls_ciphers": "List of TLS ciphers to use.", + "tls_ciphersuites": "TLS cipher suites to use.", + "tls_protocols": "TLS protocol to use.", + } + resp.Schema = schema.Schema{ Description: descriptions["main"], Attributes: map[string]schema.Attribute{ @@ -129,90 +154,117 @@ func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaReques "parameters": schema.SingleNestedAttribute{ Attributes: map[string]schema.Attribute{ "sgw_acl": schema.StringAttribute{ - Computed: true, + Description: parametersDescriptions["sgw_acl"], + Computed: true, }, "down_after_milliseconds": schema.Int64Attribute{ - Computed: true, + Description: parametersDescriptions["down_after_milliseconds"], + Computed: true, }, "enable_monitoring": schema.BoolAttribute{ - Computed: true, + Description: parametersDescriptions["enable_monitoring"], + Computed: true, }, "failover_timeout": schema.Int64Attribute{ - Computed: true, + Description: parametersDescriptions["failover_timeout"], + Computed: true, }, "graphite": schema.StringAttribute{ - Computed: true, + Description: parametersDescriptions["graphite"], + Computed: true, }, "lazyfree_lazy_eviction": schema.StringAttribute{ - Computed: true, + Description: parametersDescriptions["lazyfree_lazy_eviction"], + Computed: true, }, "lazyfree_lazy_expire": schema.StringAttribute{ - Computed: true, + Description: parametersDescriptions["lazyfree_lazy_expire"], + Computed: true, }, "lua_time_limit": schema.Int64Attribute{ - Computed: true, + Description: parametersDescriptions["lua_time_limit"], + Computed: true, }, "max_disk_threshold": schema.Int64Attribute{ - Computed: true, + Description: parametersDescriptions["max_disk_threshold"], + Computed: true, }, "maxclients": schema.Int64Attribute{ - Computed: true, + Description: parametersDescriptions["maxclients"], + Computed: true, }, "maxmemory_policy": schema.StringAttribute{ - Computed: true, + Description: parametersDescriptions["maxmemory_policy"], + Computed: true, }, "maxmemory_samples": schema.Int64Attribute{ - Computed: true, + Description: parametersDescriptions["maxmemory_samples"], + Computed: true, }, "metrics_frequency": schema.Int64Attribute{ - Computed: true, + Description: parametersDescriptions["metrics_frequency"], + Computed: true, }, "metrics_prefix": schema.StringAttribute{ - Computed: true, + Description: parametersDescriptions["metrics_prefix"], + Computed: true, }, "min_replicas_max_lag": schema.Int64Attribute{ - Computed: true, + Description: parametersDescriptions["min_replicas_max_lag"], + Computed: true, }, "monitoring_instance_id": schema.StringAttribute{ - Computed: true, + Description: parametersDescriptions["monitoring_instance_id"], + Computed: true, }, "notify_keyspace_events": schema.StringAttribute{ - Computed: true, + Description: parametersDescriptions["notify_keyspace_events"], + Computed: true, }, "snapshot": schema.StringAttribute{ - Computed: true, + Description: parametersDescriptions["snapshot"], + Computed: true, }, "syslog": schema.ListAttribute{ ElementType: types.StringType, + Description: parametersDescriptions["syslog"], Computed: true, }, "tls_ciphers": schema.ListAttribute{ ElementType: types.StringType, + Description: parametersDescriptions["tls_ciphers"], Computed: true, }, "tls_ciphersuites": schema.StringAttribute{ - Computed: true, + Description: parametersDescriptions["tls_ciphersuites"], + Computed: true, }, "tls_protocols": schema.StringAttribute{ - Computed: true, + Description: parametersDescriptions["tls_protocols"], + Computed: true, }, }, Computed: true, }, "cf_guid": schema.StringAttribute{ - Computed: true, + Description: descriptions["cf_guid"], + Computed: true, }, "cf_space_guid": schema.StringAttribute{ - Computed: true, + Description: descriptions["cf_space_guid"], + Computed: true, }, "dashboard_url": schema.StringAttribute{ - Computed: true, + Description: descriptions["dashboard_url"], + Computed: true, }, "image_url": schema.StringAttribute{ - Computed: true, + Description: descriptions["image_url"], + Computed: true, }, "cf_organization_guid": schema.StringAttribute{ - Computed: true, + Description: descriptions["cf_organization_guid"], + Computed: true, }, }, } diff --git a/stackit/internal/services/redis/instance/resource.go b/stackit/internal/services/redis/instance/resource.go index 1b290627..d90a9bb8 100644 --- a/stackit/internal/services/redis/instance/resource.go +++ b/stackit/internal/services/redis/instance/resource.go @@ -411,8 +411,9 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques projectId := model.ProjectId.ValueString() ctx = tflog.SetField(ctx, "project_id", projectId) - var parameters = ¶metersModel{} + var parameters *parametersModel if !(model.Parameters.IsNull() || model.Parameters.IsUnknown()) { + parameters = ¶metersModel{} diags = model.Parameters.As(ctx, parameters, basetypes.ObjectAsOptions{}) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { @@ -522,8 +523,9 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "instance_id", instanceId) - var parameters = ¶metersModel{} + var parameters *parametersModel if !(model.Parameters.IsNull() || model.Parameters.IsUnknown()) { + parameters = ¶metersModel{} diags = model.Parameters.As(ctx, parameters, basetypes.ObjectAsOptions{}) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { diff --git a/stackit/internal/services/redis/instance/resource_test.go b/stackit/internal/services/redis/instance/resource_test.go index c5c91919..38551dca 100644 --- a/stackit/internal/services/redis/instance/resource_test.go +++ b/stackit/internal/services/redis/instance/resource_test.go @@ -210,9 +210,7 @@ func TestToCreatePayload(t *testing.T) { { "default_values", &Model{}, - &redis.CreateInstancePayload{ - Parameters: &redis.InstanceParameters{}, - }, + &redis.CreateInstancePayload{}, true, }, { @@ -258,16 +256,16 @@ func TestToCreatePayload(t *testing.T) { &redis.CreateInstancePayload{ InstanceName: utils.Ptr("name"), PlanId: utils.Ptr("plan"), - Parameters: &redis.InstanceParameters{}, }, true, }, } for _, tt := range tests { t.Run(tt.description, func(t *testing.T) { - var parameters = ¶metersModel{} + var parameters *parametersModel if tt.input != nil { if !(tt.input.Parameters.IsNull() || tt.input.Parameters.IsUnknown()) { + parameters = ¶metersModel{} diags := tt.input.Parameters.As(context.Background(), parameters, basetypes.ObjectAsOptions{}) if diags.HasError() { t.Fatalf("Error converting parameters: %v", diags.Errors()) @@ -301,9 +299,7 @@ func TestToUpdatePayload(t *testing.T) { { "default_values", &Model{}, - &redis.PartialUpdateInstancePayload{ - Parameters: &redis.InstanceParameters{}, - }, + &redis.PartialUpdateInstancePayload{}, true, }, { @@ -342,17 +338,17 @@ func TestToUpdatePayload(t *testing.T) { PlanId: types.StringValue("plan"), }, &redis.PartialUpdateInstancePayload{ - PlanId: utils.Ptr("plan"), - Parameters: &redis.InstanceParameters{}, + PlanId: utils.Ptr("plan"), }, true, }, } for _, tt := range tests { t.Run(tt.description, func(t *testing.T) { - var parameters = ¶metersModel{} + var parameters *parametersModel if tt.input != nil { if !(tt.input.Parameters.IsNull() || tt.input.Parameters.IsUnknown()) { + parameters = ¶metersModel{} diags := tt.input.Parameters.As(context.Background(), parameters, basetypes.ObjectAsOptions{}) if diags.HasError() { t.Fatalf("Error converting parameters: %v", diags.Errors())