Skip to content

Commit 4b46119

Browse files
authored
feat(observability): add send_resolved field (#935)
relates to STACKITTPR-283
1 parent b1e97e9 commit 4b46119

File tree

7 files changed

+110
-52
lines changed

7 files changed

+110
-52
lines changed

docs/data-sources/observability_instance.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ Read-Only:
9999
- `auth_password` (String, Sensitive) SMTP authentication password.
100100
- `auth_username` (String) SMTP authentication username.
101101
- `from` (String) The sender email address. Must be a valid email address
102+
- `send_resolved` (Boolean) Whether to notify about resolved alerts.
102103
- `smart_host` (String) The SMTP host through which emails are sent.
103104
- `to` (String) The email address to send notifications to. Must be a valid email address
104105

@@ -111,6 +112,7 @@ Read-Only:
111112
- `api_key` (String) The API key for OpsGenie.
112113
- `api_url` (String) The host to send OpsGenie API requests to. Must be a valid URL
113114
- `priority` (String) Priority of the alert. Possible values are: `P1`, `P2`, `P3`, `P4`, `P5`.
115+
- `send_resolved` (Boolean) Whether to notify about resolved alerts.
114116
- `tags` (String) Comma separated list of tags attached to the notifications.
115117

116118

@@ -121,6 +123,7 @@ Read-Only:
121123

122124
- `google_chat` (Boolean) Google Chat webhooks require special handling, set this to true if the webhook is for Google Chat.
123125
- `ms_teams` (Boolean) Microsoft Teams webhooks require special handling, set this to true if the webhook is for Microsoft Teams.
126+
- `send_resolved` (Boolean) Whether to notify about resolved alerts.
124127
- `url` (String, Sensitive) The endpoint to send HTTP POST requests to. Must be a valid URL
125128

126129

docs/resources/observability_instance.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ Optional:
104104
- `auth_password` (String, Sensitive) SMTP authentication password.
105105
- `auth_username` (String) SMTP authentication username.
106106
- `from` (String) The sender email address. Must be a valid email address
107+
- `send_resolved` (Boolean) Whether to notify about resolved alerts.
107108
- `smart_host` (String) The SMTP host through which emails are sent.
108109
- `to` (String) The email address to send notifications to. Must be a valid email address
109110

@@ -116,6 +117,7 @@ Optional:
116117
- `api_key` (String) The API key for OpsGenie.
117118
- `api_url` (String) The host to send OpsGenie API requests to. Must be a valid URL
118119
- `priority` (String) Priority of the alert. Possible values are: `P1`, `P2`, `P3`, `P4`, `P5`.
120+
- `send_resolved` (Boolean) Whether to notify about resolved alerts.
119121
- `tags` (String) Comma separated list of tags attached to the notifications.
120122

121123

@@ -126,6 +128,7 @@ Optional:
126128

127129
- `google_chat` (Boolean) Google Chat webhooks require special handling, set this to true if the webhook is for Google Chat.
128130
- `ms_teams` (Boolean) Microsoft Teams webhooks require special handling, set this to true if the webhook is for Microsoft Teams.
131+
- `send_resolved` (Boolean) Whether to notify about resolved alerts.
129132
- `url` (String, Sensitive) The endpoint to send HTTP POST requests to. Must be a valid URL
130133

131134

stackit/internal/services/observability/instance/datasource.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,10 @@ func (d *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaReques
220220
Description: "The sender email address. Must be a valid email address",
221221
Computed: true,
222222
},
223+
"send_resolved": schema.BoolAttribute{
224+
Description: "Whether to notify about resolved alerts.",
225+
Computed: true,
226+
},
223227
"smart_host": schema.StringAttribute{
224228
Description: "The SMTP host through which emails are sent.",
225229
Computed: true,
@@ -252,6 +256,10 @@ func (d *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaReques
252256
Description: "Priority of the alert. " + utils.FormatPossibleValues([]string{"P1", "P2", "P3", "P4", "P5"}...),
253257
Computed: true,
254258
},
259+
"send_resolved": schema.BoolAttribute{
260+
Description: "Whether to notify about resolved alerts.",
261+
Computed: true,
262+
},
255263
},
256264
},
257265
},
@@ -273,6 +281,10 @@ func (d *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaReques
273281
Description: "Google Chat webhooks require special handling, set this to true if the webhook is for Google Chat.",
274282
Computed: true,
275283
},
284+
"send_resolved": schema.BoolAttribute{
285+
Description: "Whether to notify about resolved alerts.",
286+
Computed: true,
287+
},
276288
},
277289
},
278290
},

stackit/internal/services/observability/instance/resource.go

Lines changed: 53 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ type emailConfigsModel struct {
188188
AuthPassword types.String `tfsdk:"auth_password"`
189189
AuthUsername types.String `tfsdk:"auth_username"`
190190
From types.String `tfsdk:"from"`
191+
SendResolved types.Bool `tfsdk:"send_resolved"`
191192
Smarthost types.String `tfsdk:"smart_host"`
192193
To types.String `tfsdk:"to"`
193194
}
@@ -197,36 +198,41 @@ var emailConfigsTypes = map[string]attr.Type{
197198
"auth_password": types.StringType,
198199
"auth_username": types.StringType,
199200
"from": types.StringType,
201+
"send_resolved": types.BoolType,
200202
"smart_host": types.StringType,
201203
"to": types.StringType,
202204
}
203205

204206
// Struct corresponding to Model.AlertConfig.receivers.opsGenieConfigs
205207
type opsgenieConfigsModel struct {
206-
ApiKey types.String `tfsdk:"api_key"`
207-
ApiUrl types.String `tfsdk:"api_url"`
208-
Tags types.String `tfsdk:"tags"`
209-
Priority types.String `tfsdk:"priority"`
208+
ApiKey types.String `tfsdk:"api_key"`
209+
ApiUrl types.String `tfsdk:"api_url"`
210+
Tags types.String `tfsdk:"tags"`
211+
Priority types.String `tfsdk:"priority"`
212+
SendResolved types.Bool `tfsdk:"send_resolved"`
210213
}
211214

212215
var opsgenieConfigsTypes = map[string]attr.Type{
213-
"api_key": types.StringType,
214-
"api_url": types.StringType,
215-
"tags": types.StringType,
216-
"priority": types.StringType,
216+
"api_key": types.StringType,
217+
"api_url": types.StringType,
218+
"tags": types.StringType,
219+
"priority": types.StringType,
220+
"send_resolved": types.BoolType,
217221
}
218222

219223
// Struct corresponding to Model.AlertConfig.receivers.webHooksConfigs
220224
type webHooksConfigsModel struct {
221-
Url types.String `tfsdk:"url"`
222-
MsTeams types.Bool `tfsdk:"ms_teams"`
223-
GoogleChat types.Bool `tfsdk:"google_chat"`
225+
Url types.String `tfsdk:"url"`
226+
MsTeams types.Bool `tfsdk:"ms_teams"`
227+
GoogleChat types.Bool `tfsdk:"google_chat"`
228+
SendResolved types.Bool `tfsdk:"send_resolved"`
224229
}
225230

226231
var webHooksConfigsTypes = map[string]attr.Type{
227-
"url": types.StringType,
228-
"ms_teams": types.BoolType,
229-
"google_chat": types.BoolType,
232+
"url": types.StringType,
233+
"ms_teams": types.BoolType,
234+
"google_chat": types.BoolType,
235+
"send_resolved": types.BoolType,
230236
}
231237

232238
var routeDescriptions = map[string]string{
@@ -629,6 +635,10 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r
629635
Description: "The sender email address. Must be a valid email address",
630636
Optional: true,
631637
},
638+
"send_resolved": schema.BoolAttribute{
639+
Description: "Whether to notify about resolved alerts.",
640+
Optional: true,
641+
},
632642
"smart_host": schema.StringAttribute{
633643
Description: "The SMTP host through which emails are sent.",
634644
Optional: true,
@@ -664,6 +674,10 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r
664674
Description: "Priority of the alert. " + utils.FormatPossibleValues("P1", "P2", "P3", "P4", "P5"),
665675
Optional: true,
666676
},
677+
"send_resolved": schema.BoolAttribute{
678+
Description: "Whether to notify about resolved alerts.",
679+
Optional: true,
680+
},
667681
},
668682
},
669683
},
@@ -695,6 +709,10 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r
695709
Computed: true,
696710
Default: booldefault.StaticBool(false),
697711
},
712+
"send_resolved": schema.BoolAttribute{
713+
Description: "Whether to notify about resolved alerts.",
714+
Optional: true,
715+
},
698716
},
699717
},
700718
},
@@ -1490,6 +1508,7 @@ func getMockAlertConfig(ctx context.Context) (alertConfigModel, error) {
14901508
mockEmailConfig, diags := types.ObjectValue(emailConfigsTypes, map[string]attr.Value{
14911509
"to": types.StringValue("[email protected]"),
14921510
"smart_host": types.StringValue("smtp.gmail.com:587"),
1511+
"send_resolved": types.BoolValue(false),
14931512
"from": types.StringValue("[email protected]"),
14941513
"auth_username": types.StringValue("[email protected]"),
14951514
"auth_password": types.StringValue("xxxxxxxxx"),
@@ -1635,6 +1654,7 @@ func mapReceiversToAttributes(ctx context.Context, respReceivers *[]observabilit
16351654
"auth_password": types.StringPointerValue(emailConfig.AuthPassword),
16361655
"auth_username": types.StringPointerValue(emailConfig.AuthUsername),
16371656
"from": types.StringPointerValue(emailConfig.From),
1657+
"send_resolved": types.BoolPointerValue(emailConfig.SendResolved),
16381658
"smart_host": types.StringPointerValue(emailConfig.Smarthost),
16391659
"to": types.StringPointerValue(emailConfig.To),
16401660
}
@@ -1650,10 +1670,11 @@ func mapReceiversToAttributes(ctx context.Context, respReceivers *[]observabilit
16501670
if receiver.OpsgenieConfigs != nil {
16511671
for _, opsgenieConfig := range *receiver.OpsgenieConfigs {
16521672
opsGenieConfigMap := map[string]attr.Value{
1653-
"api_key": types.StringPointerValue(opsgenieConfig.ApiKey),
1654-
"api_url": types.StringPointerValue(opsgenieConfig.ApiUrl),
1655-
"tags": types.StringPointerValue(opsgenieConfig.Tags),
1656-
"priority": types.StringPointerValue(opsgenieConfig.Priority),
1673+
"api_key": types.StringPointerValue(opsgenieConfig.ApiKey),
1674+
"api_url": types.StringPointerValue(opsgenieConfig.ApiUrl),
1675+
"tags": types.StringPointerValue(opsgenieConfig.Tags),
1676+
"priority": types.StringPointerValue(opsgenieConfig.Priority),
1677+
"send_resolved": types.BoolPointerValue(opsgenieConfig.SendResolved),
16571678
}
16581679
opsGenieConfigModel, diags := types.ObjectValue(opsgenieConfigsTypes, opsGenieConfigMap)
16591680
if diags.HasError() {
@@ -1666,13 +1687,11 @@ func mapReceiversToAttributes(ctx context.Context, respReceivers *[]observabilit
16661687
webhooksConfigList := []attr.Value{}
16671688
if receiver.WebHookConfigs != nil {
16681689
for _, webhookConfig := range *receiver.WebHookConfigs {
1669-
msTeamsValue := types.BoolPointerValue(webhookConfig.MsTeams)
1670-
googleChatValue := types.BoolPointerValue(webhookConfig.GoogleChat)
1671-
16721690
webHookConfigsMap := map[string]attr.Value{
1673-
"url": types.StringPointerValue(webhookConfig.Url),
1674-
"ms_teams": msTeamsValue,
1675-
"google_chat": googleChatValue,
1691+
"url": types.StringPointerValue(webhookConfig.Url),
1692+
"ms_teams": types.BoolPointerValue(webhookConfig.MsTeams),
1693+
"google_chat": types.BoolPointerValue(webhookConfig.GoogleChat),
1694+
"send_resolved": types.BoolPointerValue(webhookConfig.SendResolved),
16761695
}
16771696
webHookConfigsModel, diags := types.ObjectValue(webHooksConfigsTypes, webHookConfigsMap)
16781697
if diags.HasError() {
@@ -1981,6 +2000,7 @@ func toReceiverPayload(ctx context.Context, model *alertConfigModel) (*[]observa
19812000
AuthPassword: conversion.StringValueToPointer(emailConfig.AuthPassword),
19822001
AuthUsername: conversion.StringValueToPointer(emailConfig.AuthUsername),
19832002
From: conversion.StringValueToPointer(emailConfig.From),
2003+
SendResolved: conversion.BoolValueToPointer(emailConfig.SendResolved),
19842004
Smarthost: conversion.StringValueToPointer(emailConfig.Smarthost),
19852005
To: conversion.StringValueToPointer(emailConfig.To),
19862006
})
@@ -1998,10 +2018,11 @@ func toReceiverPayload(ctx context.Context, model *alertConfigModel) (*[]observa
19982018
for i := range opsgenieConfigs {
19992019
opsgenieConfig := opsgenieConfigs[i]
20002020
payloadOpsGenieConfigs = append(payloadOpsGenieConfigs, observability.CreateAlertConfigReceiverPayloadOpsgenieConfigsInner{
2001-
ApiKey: conversion.StringValueToPointer(opsgenieConfig.ApiKey),
2002-
ApiUrl: conversion.StringValueToPointer(opsgenieConfig.ApiUrl),
2003-
Tags: conversion.StringValueToPointer(opsgenieConfig.Tags),
2004-
Priority: conversion.StringValueToPointer(opsgenieConfig.Priority),
2021+
ApiKey: conversion.StringValueToPointer(opsgenieConfig.ApiKey),
2022+
ApiUrl: conversion.StringValueToPointer(opsgenieConfig.ApiUrl),
2023+
Tags: conversion.StringValueToPointer(opsgenieConfig.Tags),
2024+
Priority: conversion.StringValueToPointer(opsgenieConfig.Priority),
2025+
SendResolved: conversion.BoolValueToPointer(opsgenieConfig.SendResolved),
20052026
})
20062027
}
20072028
receiverPayload.OpsgenieConfigs = &payloadOpsGenieConfigs
@@ -2017,9 +2038,10 @@ func toReceiverPayload(ctx context.Context, model *alertConfigModel) (*[]observa
20172038
for i := range receiverWebHooksConfigs {
20182039
webHooksConfig := receiverWebHooksConfigs[i]
20192040
payloadWebHooksConfigs = append(payloadWebHooksConfigs, observability.CreateAlertConfigReceiverPayloadWebHookConfigsInner{
2020-
Url: conversion.StringValueToPointer(webHooksConfig.Url),
2021-
MsTeams: conversion.BoolValueToPointer(webHooksConfig.MsTeams),
2022-
GoogleChat: conversion.BoolValueToPointer(webHooksConfig.GoogleChat),
2041+
Url: conversion.StringValueToPointer(webHooksConfig.Url),
2042+
MsTeams: conversion.BoolValueToPointer(webHooksConfig.MsTeams),
2043+
GoogleChat: conversion.BoolValueToPointer(webHooksConfig.GoogleChat),
2044+
SendResolved: conversion.BoolValueToPointer(webHooksConfig.SendResolved),
20232045
})
20242046
}
20252047
receiverPayload.WebHookConfigs = &payloadWebHooksConfigs

stackit/internal/services/observability/instance/resource_test.go

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ func fixtureEmailConfigsModel() basetypes.ListValue {
2424
"auth_password": types.StringValue("password"),
2525
"auth_username": types.StringValue("username"),
2626
"from": types.StringValue("[email protected]"),
27+
"send_resolved": types.BoolValue(true),
2728
"smart_host": types.StringValue("smtp.example.com"),
2829
"to": types.StringValue("[email protected]"),
2930
}),
@@ -33,20 +34,22 @@ func fixtureEmailConfigsModel() basetypes.ListValue {
3334
func fixtureOpsGenieConfigsModel() basetypes.ListValue {
3435
return types.ListValueMust(types.ObjectType{AttrTypes: opsgenieConfigsTypes}, []attr.Value{
3536
types.ObjectValueMust(opsgenieConfigsTypes, map[string]attr.Value{
36-
"api_key": types.StringValue("key"),
37-
"tags": types.StringValue("tag"),
38-
"api_url": types.StringValue("ops.example.com"),
39-
"priority": types.StringValue("P3"),
37+
"api_key": types.StringValue("key"),
38+
"tags": types.StringValue("tag"),
39+
"api_url": types.StringValue("ops.example.com"),
40+
"priority": types.StringValue("P3"),
41+
"send_resolved": types.BoolValue(true),
4042
}),
4143
})
4244
}
4345

4446
func fixtureWebHooksConfigsModel() basetypes.ListValue {
4547
return types.ListValueMust(types.ObjectType{AttrTypes: webHooksConfigsTypes}, []attr.Value{
4648
types.ObjectValueMust(webHooksConfigsTypes, map[string]attr.Value{
47-
"url": types.StringValue("http://example.com"),
48-
"ms_teams": types.BoolValue(true),
49-
"google_chat": types.BoolValue(true),
49+
"url": types.StringValue("http://example.com"),
50+
"ms_teams": types.BoolValue(true),
51+
"google_chat": types.BoolValue(true),
52+
"send_resolved": types.BoolValue(true),
5053
}),
5154
})
5255
}
@@ -135,25 +138,28 @@ func fixtureEmailConfigsPayload() observability.CreateAlertConfigReceiverPayload
135138
AuthPassword: utils.Ptr("password"),
136139
AuthUsername: utils.Ptr("username"),
137140
From: utils.Ptr("[email protected]"),
141+
SendResolved: utils.Ptr(true),
138142
Smarthost: utils.Ptr("smtp.example.com"),
139143
To: utils.Ptr("[email protected]"),
140144
}
141145
}
142146

143147
func fixtureOpsGenieConfigsPayload() observability.CreateAlertConfigReceiverPayloadOpsgenieConfigsInner {
144148
return observability.CreateAlertConfigReceiverPayloadOpsgenieConfigsInner{
145-
ApiKey: utils.Ptr("key"),
146-
Tags: utils.Ptr("tag"),
147-
ApiUrl: utils.Ptr("ops.example.com"),
148-
Priority: utils.Ptr("P3"),
149+
ApiKey: utils.Ptr("key"),
150+
Tags: utils.Ptr("tag"),
151+
ApiUrl: utils.Ptr("ops.example.com"),
152+
Priority: utils.Ptr("P3"),
153+
SendResolved: utils.Ptr(true),
149154
}
150155
}
151156

152157
func fixtureWebHooksConfigsPayload() observability.CreateAlertConfigReceiverPayloadWebHookConfigsInner {
153158
return observability.CreateAlertConfigReceiverPayloadWebHookConfigsInner{
154-
Url: utils.Ptr("http://example.com"),
155-
MsTeams: utils.Ptr(true),
156-
GoogleChat: utils.Ptr(true),
159+
Url: utils.Ptr("http://example.com"),
160+
MsTeams: utils.Ptr(true),
161+
GoogleChat: utils.Ptr(true),
162+
SendResolved: utils.Ptr(true),
157163
}
158164
}
159165

@@ -216,25 +222,28 @@ func fixtureEmailConfigsResponse() observability.EmailConfig {
216222
AuthPassword: utils.Ptr("password"),
217223
AuthUsername: utils.Ptr("username"),
218224
From: utils.Ptr("[email protected]"),
225+
SendResolved: utils.Ptr(true),
219226
Smarthost: utils.Ptr("smtp.example.com"),
220227
To: utils.Ptr("[email protected]"),
221228
}
222229
}
223230

224231
func fixtureOpsGenieConfigsResponse() observability.OpsgenieConfig {
225232
return observability.OpsgenieConfig{
226-
ApiKey: utils.Ptr("key"),
227-
Tags: utils.Ptr("tag"),
228-
ApiUrl: utils.Ptr("ops.example.com"),
229-
Priority: utils.Ptr("P3"),
233+
ApiKey: utils.Ptr("key"),
234+
Tags: utils.Ptr("tag"),
235+
ApiUrl: utils.Ptr("ops.example.com"),
236+
Priority: utils.Ptr("P3"),
237+
SendResolved: utils.Ptr(true),
230238
}
231239
}
232240

233241
func fixtureWebHooksConfigsResponse() observability.WebHook {
234242
return observability.WebHook{
235-
Url: utils.Ptr("http://example.com"),
236-
MsTeams: utils.Ptr(true),
237-
GoogleChat: utils.Ptr(true),
243+
Url: utils.Ptr("http://example.com"),
244+
MsTeams: utils.Ptr(true),
245+
GoogleChat: utils.Ptr(true),
246+
SendResolved: utils.Ptr(true),
238247
}
239248
}
240249

stackit/internal/services/observability/observability_acc_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,15 +79,18 @@ var testConfigVarsMax = config.Variables{
7979
"auth_password": config.StringVariable("password"),
8080
"auth_username": config.StringVariable("username"),
8181
"email_from": config.StringVariable("[email protected]"),
82+
"email_send_resolved": config.StringVariable("true"),
8283
"smart_host": config.StringVariable("smtp.gmail.com:587"),
8384
"email_to": config.StringVariable("[email protected]"),
8485
"opsgenie_api_key": config.StringVariable("example-api-key"),
8586
"opsgenie_api_tags": config.StringVariable("observability-alert"),
8687
"opsgenie_api_url": config.StringVariable("https://api.eu.opsgenie.com"),
8788
"opsgenie_priority": config.StringVariable("P3"),
89+
"opsgenie_send_resolved": config.StringVariable("false"),
8890
"webhook_configs_url": config.StringVariable("https://example.com"),
8991
"ms_teams": config.StringVariable("true"),
9092
"google_chat": config.StringVariable("false"),
93+
"webhook_configs_send_resolved": config.StringVariable("false"),
9194
"group_by": config.StringVariable("alertname"),
9295
"group_interval": config.StringVariable("10m"),
9396
"group_wait": config.StringVariable("1m"),

0 commit comments

Comments
 (0)