From c909309881b7a0304fa8ea3dc4d04cb28324140f Mon Sep 17 00:00:00 2001 From: mitterle-sit <195103606+mitterle-sit@users.noreply.github.com> Date: Thu, 9 Oct 2025 14:32:41 +0200 Subject: [PATCH 1/5] feat(observability/instance): add PlanModifiers Computed and Opsgenie nil handler --- .../observability/instance/resource.go | 55 ++++++++++++++++++- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/stackit/internal/services/observability/instance/resource.go b/stackit/internal/services/observability/instance/resource.go index ee89a5a95..102686bee 100644 --- a/stackit/internal/services/observability/instance/resource.go +++ b/stackit/internal/services/observability/instance/resource.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils" observabilityUtils "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/observability/utils" @@ -461,6 +462,9 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r Validators: []validator.String{ validate.UUID(), }, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "parameters": schema.MapAttribute{ Description: "Additional parameters.", @@ -528,16 +532,25 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r Description: "Specifies for how many days the raw metrics are kept. Default is set to `90`.", Optional: true, Computed: true, + PlanModifiers: []planmodifier.Int64{ + int64planmodifier.UseStateForUnknown(), + }, }, "metrics_retention_days_5m_downsampling": schema.Int64Attribute{ Description: "Specifies for how many days the 5m downsampled metrics are kept. must be less than the value of the general retention. Default is set to `90`.", Optional: true, Computed: true, + PlanModifiers: []planmodifier.Int64{ + int64planmodifier.UseStateForUnknown(), + }, }, "metrics_retention_days_1h_downsampling": schema.Int64Attribute{ Description: "Specifies for how many days the 1h downsampled metrics are kept. must be less than the value of the 5m downsampling retention. Default is set to `90`.", Optional: true, Computed: true, + PlanModifiers: []planmodifier.Int64{ + int64planmodifier.UseStateForUnknown(), + }, }, "metrics_url": schema.StringAttribute{ Description: "Specifies metrics URL.", @@ -789,10 +802,18 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r Description: "The API key for OpsGenie.", Optional: true, Sensitive: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "opsgenie_api_url": schema.StringAttribute{ Description: "The host to send OpsGenie API requests to. Must be a valid URL", Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "resolve_timeout": schema.StringAttribute{ Description: "The default value used by alertmanager if the alert does not include EndsAt. After this time passes, it can declare the alert as resolved if it has not been updated. This has no impact on alerts from Prometheus, as they always include EndsAt.", @@ -805,24 +826,43 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r "smtp_auth_identity": schema.StringAttribute{ Description: "SMTP authentication information. Must be a valid email address", Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "smtp_auth_password": schema.StringAttribute{ Description: "SMTP Auth using LOGIN and PLAIN.", Optional: true, Sensitive: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "smtp_auth_username": schema.StringAttribute{ Description: "SMTP Auth using CRAM-MD5, LOGIN and PLAIN. If empty, Alertmanager doesn't authenticate to the SMTP server.", Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "smtp_from": schema.StringAttribute{ Description: "The default SMTP From header field. Must be a valid email address", Optional: true, Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "smtp_smart_host": schema.StringAttribute{ Description: "The default SMTP smarthost used for sending emails, including port number in format `host:port` (eg. `smtp.example.com:587`). Port number usually is 25, or 587 for SMTP over TLS (sometimes referred to as STARTTLS).", Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, }, }, @@ -1816,10 +1856,21 @@ func mapGlobalConfigToAttributes(respGlobalConfigs *observability.Global, global smtpAuthUsername = sdkUtils.Ptr(globalConfigsTF.SmtpAuthUsername.ValueString()) } } + //handle nil value from api + opsgenieApiKey := respGlobalConfigs.OpsgenieApiKey + opsgenieApiUrl := respGlobalConfigs.OpsgenieApiUrl + if globalConfigsTF != nil { + if respGlobalConfigs.OpsgenieApiKey == nil { + opsgenieApiKey = sdkUtils.Ptr(globalConfigsTF.OpsgenieApiKey.ValueString()) + } + if respGlobalConfigs.OpsgenieApiUrl == nil { + opsgenieApiUrl = sdkUtils.Ptr(globalConfigsTF.OpsgenieApiUrl.ValueString()) + } + } globalConfigObject, diags := types.ObjectValue(globalConfigurationTypes, map[string]attr.Value{ - "opsgenie_api_key": types.StringPointerValue(respGlobalConfigs.OpsgenieApiKey), - "opsgenie_api_url": types.StringPointerValue(respGlobalConfigs.OpsgenieApiUrl), + "opsgenie_api_key": types.StringPointerValue(opsgenieApiKey), + "opsgenie_api_url": types.StringPointerValue(opsgenieApiUrl), "resolve_timeout": types.StringPointerValue(respGlobalConfigs.ResolveTimeout), "smtp_from": types.StringPointerValue(respGlobalConfigs.SmtpFrom), "smtp_auth_identity": types.StringPointerValue(smtpAuthIdentity), From 2ae77221841f8e1415e467ac8066b4d5bccf407d Mon Sep 17 00:00:00 2001 From: mitterle-sit <195103606+mitterle-sit@users.noreply.github.com> Date: Wed, 29 Oct 2025 16:09:42 +0100 Subject: [PATCH 2/5] fix: lint issue --- stackit/internal/services/observability/instance/resource.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stackit/internal/services/observability/instance/resource.go b/stackit/internal/services/observability/instance/resource.go index 102686bee..8f7a57e63 100644 --- a/stackit/internal/services/observability/instance/resource.go +++ b/stackit/internal/services/observability/instance/resource.go @@ -1856,7 +1856,7 @@ func mapGlobalConfigToAttributes(respGlobalConfigs *observability.Global, global smtpAuthUsername = sdkUtils.Ptr(globalConfigsTF.SmtpAuthUsername.ValueString()) } } - //handle nil value from api + // handle nil value from api opsgenieApiKey := respGlobalConfigs.OpsgenieApiKey opsgenieApiUrl := respGlobalConfigs.OpsgenieApiUrl if globalConfigsTF != nil { From 2c7995b86663c400129c187fb30edab4fae80eb1 Mon Sep 17 00:00:00 2001 From: mitterle-sit <195103606+mitterle-sit@users.noreply.github.com> Date: Mon, 10 Nov 2025 08:19:43 +0100 Subject: [PATCH 3/5] feat: add send_resolved values --- .../internal/services/observability/instance/resource.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/stackit/internal/services/observability/instance/resource.go b/stackit/internal/services/observability/instance/resource.go index 8f7a57e63..2b5226d15 100644 --- a/stackit/internal/services/observability/instance/resource.go +++ b/stackit/internal/services/observability/instance/resource.go @@ -672,6 +672,8 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r "send_resolved": schema.BoolAttribute{ Description: "Whether to notify about resolved alerts.", Optional: true, + Computed: true, + Default: booldefault.StaticBool(true), }, "smart_host": schema.StringAttribute{ Description: "The SMTP host through which emails are sent.", @@ -711,6 +713,8 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r "send_resolved": schema.BoolAttribute{ Description: "Whether to notify about resolved alerts.", Optional: true, + Computed: true, + Default: booldefault.StaticBool(true), }, }, }, @@ -746,6 +750,8 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r "send_resolved": schema.BoolAttribute{ Description: "Whether to notify about resolved alerts.", Optional: true, + Computed: true, + Default: booldefault.StaticBool(true), }, }, }, From f726b86d2feaac04ec8ddbbc870553f29a693f68 Mon Sep 17 00:00:00 2001 From: mitterle-sit <195103606+mitterle-sit@users.noreply.github.com> Date: Fri, 14 Nov 2025 11:03:31 +0100 Subject: [PATCH 4/5] fix: remove PlanModifiers from plan_id --- stackit/internal/services/observability/instance/resource.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/stackit/internal/services/observability/instance/resource.go b/stackit/internal/services/observability/instance/resource.go index 2b5226d15..a3eb1a082 100644 --- a/stackit/internal/services/observability/instance/resource.go +++ b/stackit/internal/services/observability/instance/resource.go @@ -462,9 +462,6 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r Validators: []validator.String{ validate.UUID(), }, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, }, "parameters": schema.MapAttribute{ Description: "Additional parameters.", From bd25932616e273dc486c9b3287dffc4f9d45a791 Mon Sep 17 00:00:00 2001 From: mitterle-sit <195103606+mitterle-sit@users.noreply.github.com> Date: Mon, 24 Nov 2025 10:08:42 +0100 Subject: [PATCH 5/5] fix: integrate to globalConfigsTF check --- .../internal/services/observability/instance/resource.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/stackit/internal/services/observability/instance/resource.go b/stackit/internal/services/observability/instance/resource.go index a3eb1a082..3db875f14 100644 --- a/stackit/internal/services/observability/instance/resource.go +++ b/stackit/internal/services/observability/instance/resource.go @@ -1841,6 +1841,8 @@ func mapGlobalConfigToAttributes(respGlobalConfigs *observability.Global, global smtpAuthIdentity := respGlobalConfigs.SmtpAuthIdentity smtpAuthPassword := respGlobalConfigs.SmtpAuthPassword smtpAuthUsername := respGlobalConfigs.SmtpAuthUsername + opsgenieApiKey := respGlobalConfigs.OpsgenieApiKey + opsgenieApiUrl := respGlobalConfigs.OpsgenieApiUrl if globalConfigsTF != nil { if respGlobalConfigs.SmtpSmarthost == nil && !globalConfigsTF.SmtpSmartHost.IsNull() && !globalConfigsTF.SmtpSmartHost.IsUnknown() { @@ -1858,11 +1860,6 @@ func mapGlobalConfigToAttributes(respGlobalConfigs *observability.Global, global !globalConfigsTF.SmtpAuthUsername.IsNull() && !globalConfigsTF.SmtpAuthUsername.IsUnknown() { smtpAuthUsername = sdkUtils.Ptr(globalConfigsTF.SmtpAuthUsername.ValueString()) } - } - // handle nil value from api - opsgenieApiKey := respGlobalConfigs.OpsgenieApiKey - opsgenieApiUrl := respGlobalConfigs.OpsgenieApiUrl - if globalConfigsTF != nil { if respGlobalConfigs.OpsgenieApiKey == nil { opsgenieApiKey = sdkUtils.Ptr(globalConfigsTF.OpsgenieApiKey.ValueString()) }