Skip to content

Commit 12bfa00

Browse files
committed
feat(observability): add send_resolved field
relates to STACKITTPR-283
1 parent 64787ff commit 12bfa00

7 files changed

Lines changed: 124 additions & 52 deletions

File tree

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
@@ -173,6 +173,7 @@ type emailConfigsModel struct {
173173
AuthPassword types.String `tfsdk:"auth_password"`
174174
AuthUsername types.String `tfsdk:"auth_username"`
175175
From types.String `tfsdk:"from"`
176+
SendResolved types.Bool `tfsdk:"send_resolved"`
176177
Smarthost types.String `tfsdk:"smart_host"`
177178
To types.String `tfsdk:"to"`
178179
}
@@ -182,36 +183,41 @@ var emailConfigsTypes = map[string]attr.Type{
182183
"auth_password": types.StringType,
183184
"auth_username": types.StringType,
184185
"from": types.StringType,
186+
"send_resolved": types.BoolType,
185187
"smart_host": types.StringType,
186188
"to": types.StringType,
187189
}
188190

189191
// Struct corresponding to Model.AlertConfig.receivers.opsGenieConfigs
190192
type opsgenieConfigsModel struct {
191-
ApiKey types.String `tfsdk:"api_key"`
192-
ApiUrl types.String `tfsdk:"api_url"`
193-
Tags types.String `tfsdk:"tags"`
194-
Priority types.String `tfsdk:"priority"`
193+
ApiKey types.String `tfsdk:"api_key"`
194+
ApiUrl types.String `tfsdk:"api_url"`
195+
Tags types.String `tfsdk:"tags"`
196+
Priority types.String `tfsdk:"priority"`
197+
SendResolved types.Bool `tfsdk:"send_resolved"`
195198
}
196199

197200
var opsgenieConfigsTypes = map[string]attr.Type{
198-
"api_key": types.StringType,
199-
"api_url": types.StringType,
200-
"tags": types.StringType,
201-
"priority": types.StringType,
201+
"api_key": types.StringType,
202+
"api_url": types.StringType,
203+
"tags": types.StringType,
204+
"priority": types.StringType,
205+
"send_resolved": types.BoolType,
202206
}
203207

204208
// Struct corresponding to Model.AlertConfig.receivers.webHooksConfigs
205209
type webHooksConfigsModel struct {
206-
Url types.String `tfsdk:"url"`
207-
MsTeams types.Bool `tfsdk:"ms_teams"`
208-
GoogleChat types.Bool `tfsdk:"google_chat"`
210+
Url types.String `tfsdk:"url"`
211+
MsTeams types.Bool `tfsdk:"ms_teams"`
212+
GoogleChat types.Bool `tfsdk:"google_chat"`
213+
SendResolved types.Bool `tfsdk:"send_resolved"`
209214
}
210215

211216
var webHooksConfigsTypes = map[string]attr.Type{
212-
"url": types.StringType,
213-
"ms_teams": types.BoolType,
214-
"google_chat": types.BoolType,
217+
"url": types.StringType,
218+
"ms_teams": types.BoolType,
219+
"google_chat": types.BoolType,
220+
"send_resolved": types.BoolType,
215221
}
216222

217223
var routeDescriptions = map[string]string{
@@ -604,6 +610,10 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r
604610
Description: "The sender email address. Must be a valid email address",
605611
Optional: true,
606612
},
613+
"send_resolved": schema.BoolAttribute{
614+
Description: "Whether to notify about resolved alerts.",
615+
Optional: true,
616+
},
607617
"smart_host": schema.StringAttribute{
608618
Description: "The SMTP host through which emails are sent.",
609619
Optional: true,
@@ -639,6 +649,10 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r
639649
Description: "Priority of the alert. " + utils.FormatPossibleValues("P1", "P2", "P3", "P4", "P5"),
640650
Optional: true,
641651
},
652+
"send_resolved": schema.BoolAttribute{
653+
Description: "Whether to notify about resolved alerts.",
654+
Optional: true,
655+
},
642656
},
643657
},
644658
},
@@ -670,6 +684,10 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r
670684
Computed: true,
671685
Default: booldefault.StaticBool(false),
672686
},
687+
"send_resolved": schema.BoolAttribute{
688+
Description: "Whether to notify about resolved alerts.",
689+
Optional: true,
690+
},
673691
},
674692
},
675693
},
@@ -1525,6 +1543,7 @@ func getMockAlertConfig(ctx context.Context) (alertConfigModel, error) {
15251543
mockEmailConfig, diags := types.ObjectValue(emailConfigsTypes, map[string]attr.Value{
15261544
"to": types.StringValue("123@gmail.com"),
15271545
"smart_host": types.StringValue("smtp.gmail.com:587"),
1546+
"send_resolved": types.BoolValue(false),
15281547
"from": types.StringValue("xxxx@gmail.com"),
15291548
"auth_username": types.StringValue("xxxx@gmail.com"),
15301549
"auth_password": types.StringValue("xxxxxxxxx"),
@@ -1672,6 +1691,7 @@ func mapReceiversToAttributes(ctx context.Context, respReceivers *[]observabilit
16721691
"auth_password": types.StringPointerValue(emailConfig.AuthPassword),
16731692
"auth_username": types.StringPointerValue(emailConfig.AuthUsername),
16741693
"from": types.StringPointerValue(emailConfig.From),
1694+
"send_resolved": types.BoolPointerValue(emailConfig.SendResolved),
16751695
"smart_host": types.StringPointerValue(emailConfig.Smarthost),
16761696
"to": types.StringPointerValue(emailConfig.To),
16771697
}
@@ -1687,10 +1707,11 @@ func mapReceiversToAttributes(ctx context.Context, respReceivers *[]observabilit
16871707
if receiver.OpsgenieConfigs != nil {
16881708
for _, opsgenieConfig := range *receiver.OpsgenieConfigs {
16891709
opsGenieConfigMap := map[string]attr.Value{
1690-
"api_key": types.StringPointerValue(opsgenieConfig.ApiKey),
1691-
"api_url": types.StringPointerValue(opsgenieConfig.ApiUrl),
1692-
"tags": types.StringPointerValue(opsgenieConfig.Tags),
1693-
"priority": types.StringPointerValue(opsgenieConfig.Priority),
1710+
"api_key": types.StringPointerValue(opsgenieConfig.ApiKey),
1711+
"api_url": types.StringPointerValue(opsgenieConfig.ApiUrl),
1712+
"tags": types.StringPointerValue(opsgenieConfig.Tags),
1713+
"priority": types.StringPointerValue(opsgenieConfig.Priority),
1714+
"send_resolved": types.BoolPointerValue(opsgenieConfig.SendResolved),
16941715
}
16951716
opsGenieConfigModel, diags := types.ObjectValue(opsgenieConfigsTypes, opsGenieConfigMap)
16961717
if diags.HasError() {
@@ -1703,13 +1724,11 @@ func mapReceiversToAttributes(ctx context.Context, respReceivers *[]observabilit
17031724
webhooksConfigList := []attr.Value{}
17041725
if receiver.WebHookConfigs != nil {
17051726
for _, webhookConfig := range *receiver.WebHookConfigs {
1706-
msTeamsValue := types.BoolPointerValue(webhookConfig.MsTeams)
1707-
googleChatValue := types.BoolPointerValue(webhookConfig.GoogleChat)
1708-
17091727
webHookConfigsMap := map[string]attr.Value{
1710-
"url": types.StringPointerValue(webhookConfig.Url),
1711-
"ms_teams": msTeamsValue,
1712-
"google_chat": googleChatValue,
1728+
"url": types.StringPointerValue(webhookConfig.Url),
1729+
"ms_teams": types.BoolPointerValue(webhookConfig.MsTeams),
1730+
"google_chat": types.BoolPointerValue(webhookConfig.GoogleChat),
1731+
"send_resolved": types.BoolPointerValue(webhookConfig.SendResolved),
17131732
}
17141733
webHookConfigsModel, diags := types.ObjectValue(webHooksConfigsTypes, webHookConfigsMap)
17151734
if diags.HasError() {
@@ -2024,6 +2043,7 @@ func toReceiverPayload(ctx context.Context, model *alertConfigModel) (*[]observa
20242043
AuthPassword: conversion.StringValueToPointer(emailConfig.AuthPassword),
20252044
AuthUsername: conversion.StringValueToPointer(emailConfig.AuthUsername),
20262045
From: conversion.StringValueToPointer(emailConfig.From),
2046+
SendResolved: conversion.BoolValueToPointer(emailConfig.SendResolved),
20272047
Smarthost: conversion.StringValueToPointer(emailConfig.Smarthost),
20282048
To: conversion.StringValueToPointer(emailConfig.To),
20292049
})
@@ -2041,10 +2061,11 @@ func toReceiverPayload(ctx context.Context, model *alertConfigModel) (*[]observa
20412061
for i := range opsgenieConfigs {
20422062
opsgenieConfig := opsgenieConfigs[i]
20432063
payloadOpsGenieConfigs = append(payloadOpsGenieConfigs, observability.CreateAlertConfigReceiverPayloadOpsgenieConfigsInner{
2044-
ApiKey: conversion.StringValueToPointer(opsgenieConfig.ApiKey),
2045-
ApiUrl: conversion.StringValueToPointer(opsgenieConfig.ApiUrl),
2046-
Tags: conversion.StringValueToPointer(opsgenieConfig.Tags),
2047-
Priority: conversion.StringValueToPointer(opsgenieConfig.Priority),
2064+
ApiKey: conversion.StringValueToPointer(opsgenieConfig.ApiKey),
2065+
ApiUrl: conversion.StringValueToPointer(opsgenieConfig.ApiUrl),
2066+
Tags: conversion.StringValueToPointer(opsgenieConfig.Tags),
2067+
Priority: conversion.StringValueToPointer(opsgenieConfig.Priority),
2068+
SendResolved: conversion.BoolValueToPointer(opsgenieConfig.SendResolved),
20482069
})
20492070
}
20502071
receiverPayload.OpsgenieConfigs = &payloadOpsGenieConfigs
@@ -2060,9 +2081,10 @@ func toReceiverPayload(ctx context.Context, model *alertConfigModel) (*[]observa
20602081
for i := range receiverWebHooksConfigs {
20612082
webHooksConfig := receiverWebHooksConfigs[i]
20622083
payloadWebHooksConfigs = append(payloadWebHooksConfigs, observability.CreateAlertConfigReceiverPayloadWebHookConfigsInner{
2063-
Url: conversion.StringValueToPointer(webHooksConfig.Url),
2064-
MsTeams: conversion.BoolValueToPointer(webHooksConfig.MsTeams),
2065-
GoogleChat: conversion.BoolValueToPointer(webHooksConfig.GoogleChat),
2084+
Url: conversion.StringValueToPointer(webHooksConfig.Url),
2085+
MsTeams: conversion.BoolValueToPointer(webHooksConfig.MsTeams),
2086+
GoogleChat: conversion.BoolValueToPointer(webHooksConfig.GoogleChat),
2087+
SendResolved: conversion.BoolValueToPointer(webHooksConfig.SendResolved),
20662088
})
20672089
}
20682090
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("notification@example.com"),
27+
"send_resolved": types.BoolValue(true),
2728
"smart_host": types.StringValue("smtp.example.com"),
2829
"to": types.StringValue("me@example.com"),
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("notification@example.com"),
141+
SendResolved: utils.Ptr(true),
138142
Smarthost: utils.Ptr("smtp.example.com"),
139143
To: utils.Ptr("me@example.com"),
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

@@ -217,25 +223,28 @@ func fixtureEmailConfigsResponse() observability.EmailConfig {
217223
AuthPassword: utils.Ptr("password"),
218224
AuthUsername: utils.Ptr("username"),
219225
From: utils.Ptr("notification@example.com"),
226+
SendResolved: utils.Ptr(true),
220227
Smarthost: utils.Ptr("smtp.example.com"),
221228
To: utils.Ptr("me@example.com"),
222229
}
223230
}
224231

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

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

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("aa@bb.ccc"),
82+
"email_send_resolved": config.StringVariable("true"),
8283
"smart_host": config.StringVariable("smtp.gmail.com:587"),
8384
"email_to": config.StringVariable("bb@bb.ccc"),
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)