Skip to content

Commit 2158560

Browse files
authored
feat(alerts): introduce duration attribute (#525)
* chore(alerts): use new duration fields for v1 alerts * feat(alerts): introduce duration attribute
1 parent 663d0d1 commit 2158560

24 files changed

+358
-98
lines changed

sysdig/internal/client/v2/model.go

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,8 @@ type Alert struct {
189189
NotificationChannelIds []int `json:"notificationChannelIds"`
190190
Filter string `json:"filter"`
191191
Severity int `json:"severity"`
192-
Timespan int `json:"timespan"`
192+
Timespan *int `json:"timespan,omitempty"`
193+
Duration *int `json:"duration,omitempty"`
193194
CustomNotification *CustomNotification `json:"customNotification"`
194195
TeamID int `json:"teamId,omitempty"`
195196
AutoCreated bool `json:"autoCreated"`
@@ -712,12 +713,13 @@ type AlertV2Common struct {
712713
type AlertV2ConfigPrometheus struct {
713714
Query string `json:"query"`
714715
KeepFiringForSec *int `json:"keepFiringForSec,omitempty"`
716+
717+
Duration int `json:"duration"`
715718
}
716719

717720
type AlertV2Prometheus struct {
718721
AlertV2Common
719-
DurationSec int `json:"durationSec"`
720-
Config AlertV2ConfigPrometheus `json:"config"`
722+
Config AlertV2ConfigPrometheus `json:"config"`
721723
}
722724

723725
type alertV2PrometheusWrapper struct {
@@ -755,12 +757,13 @@ type AlertV2ConfigEvent struct {
755757

756758
Filter string `json:"filter"`
757759
Tags []string `json:"tags"`
760+
761+
Range int `json:"range"`
758762
}
759763

760764
type AlertV2Event struct {
761765
AlertV2Common
762-
DurationSec int `json:"durationSec"`
763-
Config AlertV2ConfigEvent `json:"config"`
766+
Config AlertV2ConfigEvent `json:"config"`
764767
}
765768

766769
type alertV2EventWrapper struct {
@@ -796,11 +799,13 @@ type AlertV2ConfigMetric struct {
796799
TimeAggregation string `json:"timeAggregation"`
797800
Metric AlertMetricDescriptorV2 `json:"metric"`
798801
NoDataBehaviour string `json:"noDataBehaviour"`
802+
803+
Range int `json:"range"`
804+
Duration int `json:"duration"`
799805
}
800806

801807
type AlertV2Metric struct {
802808
AlertV2Common
803-
DurationSec int `json:"durationSec"`
804809
Config AlertV2ConfigMetric `json:"config"`
805810
UnreportedAlertNotificationsRetentionSec *int `json:"unreportedAlertNotificationsRetentionSec"`
806811
}
@@ -818,11 +823,12 @@ type AlertV2ConfigDowntime struct {
818823
GroupAggregation string `json:"groupAggregation"`
819824
TimeAggregation string `json:"timeAggregation"`
820825
Metric AlertMetricDescriptorV2 `json:"metric"`
826+
827+
Range int `json:"range"`
821828
}
822829

823830
type AlertV2Downtime struct {
824831
AlertV2Common
825-
DurationSec int `json:"durationSec"`
826832
Config AlertV2ConfigDowntime `json:"config"`
827833
UnreportedAlertNotificationsRetentionSec *int `json:"unreportedAlertNotificationsRetentionSec"`
828834
}
@@ -856,11 +862,12 @@ type AlertV2ConfigFormBasedPrometheus struct {
856862
WarningConditionOperator string `json:"warningConditionOperator,omitempty"`
857863
WarningThreshold *float64 `json:"warningThreshold,omitempty"`
858864
NoDataBehaviour string `json:"noDataBehaviour"`
865+
866+
Duration int `json:"duration"`
859867
}
860868

861869
type AlertV2FormBasedPrometheus struct {
862870
AlertV2Common
863-
DurationSec int `json:"durationSec"` // not really used but the api wants it set to 0 in POST/PUT
864871
Config AlertV2ConfigFormBasedPrometheus `json:"config"`
865872
UnreportedAlertNotificationsRetentionSec *int `json:"unreportedAlertNotificationsRetentionSec"`
866873
}
@@ -881,11 +888,12 @@ type AlertV2ConfigGroupOutlier struct {
881888
TimeAggregation string `json:"timeAggregation"`
882889
Metric AlertMetricDescriptorV2 `json:"metric"`
883890
NoDataBehaviour string `json:"noDataBehaviour"`
891+
892+
ObservationWindow int `json:"observationWindow"`
884893
}
885894

886895
type AlertV2GroupOutlier struct {
887896
AlertV2Common
888-
DurationSec int `json:"durationSec"` // Observation window should be greater than or equal to 10 minutes
889897
Config AlertV2ConfigGroupOutlier `json:"config"`
890898
UnreportedAlertNotificationsRetentionSec *int `json:"unreportedAlertNotificationsRetentionSec"`
891899
}
@@ -896,7 +904,6 @@ type alertV2GroupOutlierWrapper struct {
896904

897905
type AlertV2Change struct {
898906
AlertV2Common
899-
DurationSec int `json:"durationSec"` // not really used but the api wants it set to 0 in POST/PUT
900907
Config AlertV2ConfigChange `json:"config"`
901908
UnreportedAlertNotificationsRetentionSec *int `json:"unreportedAlertNotificationsRetentionSec"`
902909
}

sysdig/resource_sysdig_monitor_alert_common.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,11 @@ func createAlertSchema(original map[string]*schema.Schema) map[string]*schema.Sc
125125

126126
func alertFromResourceData(d *schema.ResourceData) (alert *v2.Alert, err error) {
127127
trigger_after_minutes := time.Duration(d.Get("trigger_after_minutes").(int)) * time.Minute
128+
timespan := int(trigger_after_minutes.Microseconds())
128129
alert = &v2.Alert{
129130
Name: d.Get("name").(string),
130131
Type: "MANUAL",
131-
Timespan: int(trigger_after_minutes.Microseconds()),
132+
Timespan: &timespan,
132133
SegmentBy: []string{},
133134
NotificationChannelIds: []int{},
134135
CustomNotification: &v2.CustomNotification{
@@ -202,13 +203,16 @@ func alertFromResourceData(d *schema.ResourceData) (alert *v2.Alert, err error)
202203
}
203204

204205
func alertToResourceData(alert *v2.Alert, data *schema.ResourceData) (err error) {
205-
trigger_after_minutes := time.Duration(alert.Timespan) * time.Microsecond
206+
var trigger_after_minutes int
207+
if alert.Timespan != nil {
208+
trigger_after_minutes = int((time.Duration(*alert.Timespan) * time.Microsecond).Minutes())
209+
}
206210

207211
_ = data.Set("version", alert.Version)
208212
_ = data.Set("name", alert.Name)
209213
_ = data.Set("description", alert.Description)
210214
_ = data.Set("scope", alert.Filter)
211-
_ = data.Set("trigger_after_minutes", int(trigger_after_minutes.Minutes()))
215+
_ = data.Set("trigger_after_minutes", trigger_after_minutes)
212216
_ = data.Set("group_name", alert.GroupName)
213217
_ = data.Set("team", alert.TeamID)
214218
_ = data.Set("enabled", alert.Enabled)

sysdig/resource_sysdig_monitor_alert_promql.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@ func promqlAlertFromResourceData(data *schema.ResourceData) (alert *v2.Alert, er
131131
if err != nil {
132132
return
133133
}
134+
duration := int((time.Duration(*alert.Timespan) * time.Microsecond).Seconds())
135+
alert.Duration = &duration
136+
alert.Timespan = nil
134137

135138
alert.Type = "PROMETHEUS"
136139

@@ -145,6 +148,11 @@ func promqlAlertToResourceData(alert *v2.Alert, data *schema.ResourceData) (err
145148
return
146149
}
147150

151+
if alert.Duration != nil {
152+
trigger_after_minutes := int((time.Duration(*alert.Duration) * time.Second).Minutes())
153+
_ = data.Set("trigger_after_minutes", trigger_after_minutes)
154+
}
155+
148156
_ = data.Set("promql", alert.Condition)
149157

150158
return

sysdig/resource_sysdig_monitor_alert_v2_change.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,6 @@ func buildAlertV2ChangeStruct(d *schema.ResourceData) (*v2.AlertV2Change, error)
312312

313313
alert := &v2.AlertV2Change{
314314
AlertV2Common: *alertV2Common,
315-
DurationSec: 0,
316315
Config: config,
317316
UnreportedAlertNotificationsRetentionSec: unreportedAlertNotificationsRetentionSec,
318317
}

sysdig/resource_sysdig_monitor_alert_v2_downtime.go

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,18 @@ func resourceSysdigMonitorAlertV2Downtime() *schema.Resource {
3333

3434
Schema: createScopedSegmentedAlertV2Schema(createAlertV2Schema(map[string]*schema.Schema{
3535
"trigger_after_minutes": {
36-
Type: schema.TypeInt,
37-
Required: true,
36+
Type: schema.TypeInt,
37+
Optional: true,
38+
Computed: true, // computed if range_seconds is defined
39+
Deprecated: "Use range_seconds instead",
40+
ValidateFunc: validation.IntAtLeast(1),
41+
},
42+
"range_seconds": {
43+
Type: schema.TypeInt,
44+
Optional: true,
45+
Computed: true, // computed if trigger_after_minutes is defined
46+
ExactlyOneOf: []string{"trigger_after_minutes"},
47+
ValidateFunc: validation.IntAtLeast(60),
3848
},
3949
"threshold": {
4050
Type: schema.TypeFloat,
@@ -175,6 +185,19 @@ func buildAlertV2DowntimeStruct(d *schema.ResourceData) *v2.AlertV2Downtime {
175185
metric := d.Get("metric").(string)
176186
config.Metric.ID = metric
177187

188+
if attr, ok := d.GetOk("range_seconds"); ok && attr != nil {
189+
config.Range = d.Get("range_seconds").(int)
190+
}
191+
192+
if d.HasChange("trigger_after_minutes") {
193+
// GetOk returns true even if the value is stored only in the state and not in the user config:
194+
// to avoid applying a trigger_after_minutes old value from the state even if the user removed it from the config
195+
// we use HasChange that is true only if the use has changed (or created) it - and so it must be in the config
196+
if attr, ok := d.GetOk("trigger_after_minutes"); ok && attr != nil {
197+
config.Range = minutesToSeconds(d.Get("trigger_after_minutes").(int))
198+
}
199+
}
200+
178201
var unreportedAlertNotificationsRetentionSec *int
179202
if unreportedAlertNotificationsRetentionSecInterface, ok := d.GetOk("unreported_alert_notifications_retention_seconds"); ok {
180203
u := unreportedAlertNotificationsRetentionSecInterface.(int)
@@ -183,7 +206,6 @@ func buildAlertV2DowntimeStruct(d *schema.ResourceData) *v2.AlertV2Downtime {
183206

184207
alert := &v2.AlertV2Downtime{
185208
AlertV2Common: *alertV2Common,
186-
DurationSec: minutesToSeconds(d.Get("trigger_after_minutes").(int)),
187209
Config: config,
188210
UnreportedAlertNotificationsRetentionSec: unreportedAlertNotificationsRetentionSec,
189211
}
@@ -201,7 +223,8 @@ func updateAlertV2DowntimeState(d *schema.ResourceData, alert *v2.AlertV2Downtim
201223
return err
202224
}
203225

204-
_ = d.Set("trigger_after_minutes", secondsToMinutes(alert.DurationSec))
226+
_ = d.Set("trigger_after_minutes", secondsToMinutes(alert.Config.Range))
227+
_ = d.Set("range_seconds", alert.Config.Range)
205228

206229
_ = d.Set("threshold", (1-alert.Config.Threshold)*100)
207230

sysdig/resource_sysdig_monitor_alert_v2_downtime_test.go

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ func TestAccAlertV2Downtime(t *testing.T) {
2727
{
2828
Config: alertV2DowntimeWithName(rText()),
2929
},
30+
{
31+
Config: alertV2DowntimeWithTriggerAfterMinutes(rText()),
32+
},
3033
{
3134
Config: alertV2DowntimeWithWithUnreportedAlertNotificationsRetentionSec(rText()),
3235
},
@@ -56,6 +59,27 @@ resource "sysdig_monitor_alert_v2_downtime" "sample" {
5659
values = ["thom-cluster1", "demo-env-prom"]
5760
}
5861
62+
range_seconds = 600
63+
64+
}
65+
66+
`, name)
67+
}
68+
69+
func alertV2DowntimeWithTriggerAfterMinutes(name string) string {
70+
return fmt.Sprintf(`
71+
resource "sysdig_monitor_alert_v2_downtime" "sample" {
72+
73+
name = "TERRAFORM TEST - DOWNTIMEV2 %s"
74+
metric = "sysdig_container_up"
75+
threshold = 75
76+
77+
scope {
78+
label = "kube_cluster_name"
79+
operator = "in"
80+
values = ["thom-cluster1", "demo-env-prom"]
81+
}
82+
5983
trigger_after_minutes = 15
6084
6185
}
@@ -77,7 +101,7 @@ resource "sysdig_monitor_alert_v2_downtime" "sample" {
77101
values = ["thom-cluster1", "demo-env-prom"]
78102
}
79103
80-
trigger_after_minutes = 15
104+
range_seconds = 600
81105
unreported_alert_notifications_retention_seconds = 60 * 60 * 24 * 30
82106
83107
}
@@ -100,7 +124,7 @@ func alertV2DowntimeWithGroupBy(name string) string {
100124
values = ["thom-cluster1", "demo-env-prom"]
101125
}
102126
103-
trigger_after_minutes = 15
127+
range_seconds = 600
104128
105129
}
106130

sysdig/resource_sysdig_monitor_alert_v2_event.go

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,18 @@ func resourceSysdigMonitorAlertV2Event() *schema.Resource {
3434

3535
Schema: createScopedSegmentedAlertV2Schema(createAlertV2Schema(map[string]*schema.Schema{
3636
"trigger_after_minutes": {
37-
Type: schema.TypeInt,
38-
Required: true,
37+
Type: schema.TypeInt,
38+
Optional: true,
39+
Computed: true, // computed if range_seconds is defined
40+
Deprecated: "Use range_seconds instead",
41+
ValidateFunc: validation.IntAtLeast(1),
42+
},
43+
"range_seconds": {
44+
Type: schema.TypeInt,
45+
Optional: true,
46+
Computed: true, // computed if trigger_after_minutes is defined
47+
ExactlyOneOf: []string{"trigger_after_minutes"},
48+
ValidateFunc: validation.IntAtLeast(60),
3949
},
4050
"operator": {
4151
Type: schema.TypeString,
@@ -203,9 +213,21 @@ func buildAlertV2EventStruct(d *schema.ResourceData) (*v2.AlertV2Event, error) {
203213
}
204214
config.Tags = tags
205215

216+
if attr, ok := d.GetOk("range_seconds"); ok && attr != nil {
217+
config.Range = d.Get("range_seconds").(int)
218+
}
219+
220+
if d.HasChange("trigger_after_minutes") {
221+
// GetOk returns true even if the value is stored only in the state and not in the user config:
222+
// to avoid applying a trigger_after_minutes old value from the state even if the user removed it from the config
223+
// we use HasChange that is true only if the use has changed (or created) it - and so it must be in the config
224+
if attr, ok := d.GetOk("trigger_after_minutes"); ok && attr != nil {
225+
config.Range = minutesToSeconds(d.Get("trigger_after_minutes").(int))
226+
}
227+
}
228+
206229
alert := &v2.AlertV2Event{
207230
AlertV2Common: *alertV2Common,
208-
DurationSec: minutesToSeconds(d.Get("trigger_after_minutes").(int)),
209231
Config: config,
210232
}
211233
return alert, nil
@@ -222,7 +244,8 @@ func updateAlertV2EventState(d *schema.ResourceData, alert *v2.AlertV2Event) err
222244
return err
223245
}
224246

225-
_ = d.Set("trigger_after_minutes", secondsToMinutes(alert.DurationSec))
247+
_ = d.Set("trigger_after_minutes", secondsToMinutes(alert.Config.Range))
248+
_ = d.Set("range_seconds", alert.Config.Range)
226249

227250
_ = d.Set("operator", alert.Config.ConditionOperator)
228251

0 commit comments

Comments
 (0)