Skip to content

Commit 6a3e1d3

Browse files
committed
fix(monitor-alert): handle legacy alerts with metricId fallback
Legacy metric alerts (pre-2024 schema) store the metric identifier in the flat `metricId` field instead of the nested `metric.id` object. When importing these alerts, the provider now falls back to `metricId` if `metric.id` is empty, making them manageable via Terraform. Also adds StringIsNotEmpty validation on the metric field to surface a clear error at plan time instead of a cryptic API 422. Closes #708
1 parent 16d361c commit 6a3e1d3

3 files changed

Lines changed: 90 additions & 1 deletion

File tree

sysdig/internal/client/v2/model.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,7 @@ type AlertV2ConfigMetric struct {
773773
GroupAggregation string `json:"groupAggregation"`
774774
TimeAggregation string `json:"timeAggregation"`
775775
Metric AlertMetricDescriptorV2 `json:"metric"`
776+
MetricID string `json:"metricId,omitempty"` // Legacy API field, used as fallback when Metric.ID is empty
776777
NoDataBehaviour string `json:"noDataBehaviour"`
777778

778779
Range int `json:"range"`
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package v2
2+
3+
import (
4+
"encoding/json"
5+
"testing"
6+
)
7+
8+
func TestAlertV2MetricUnmarshalLegacyMetricID(t *testing.T) {
9+
// Legacy API response: has "metricId" but no "metric.id"
10+
legacyJSON := `{
11+
"alert": {
12+
"id": 1553848,
13+
"name": "MysqlMateo",
14+
"type": "MANUAL",
15+
"config": {
16+
"metricId": "mysql_global_status_threads_connected",
17+
"groupAggregation": "avg",
18+
"timeAggregation": "avg",
19+
"threshold": 125.0,
20+
"conditionOperator": ">",
21+
"noDataBehaviour": "DO_NOTHING",
22+
"range": 60,
23+
"duration": 0
24+
}
25+
}
26+
}`
27+
28+
var wrapper alertV2MetricWrapper
29+
err := json.Unmarshal([]byte(legacyJSON), &wrapper)
30+
if err != nil {
31+
t.Fatalf("failed to unmarshal legacy alert JSON: %v", err)
32+
}
33+
34+
alert := wrapper.Alert
35+
36+
if alert.Config.MetricID != "mysql_global_status_threads_connected" {
37+
t.Errorf("expected MetricID to be %q, got %q", "mysql_global_status_threads_connected", alert.Config.MetricID)
38+
}
39+
40+
// metric.id should be empty since the legacy response doesn't include it
41+
if alert.Config.Metric.ID != "" {
42+
t.Errorf("expected Metric.ID to be empty for legacy alert, got %q", alert.Config.Metric.ID)
43+
}
44+
}
45+
46+
func TestAlertV2MetricUnmarshalCurrentMetricID(t *testing.T) {
47+
// Current API response: has both "metric.id" and "metricId"
48+
currentJSON := `{
49+
"alert": {
50+
"id": 1760356,
51+
"name": "cpu usage spike alert",
52+
"type": "MANUAL",
53+
"config": {
54+
"metric": {
55+
"id": "sysdig_container_cpu_quota_used_percent"
56+
},
57+
"metricId": "sysdig_container_cpu_quota_used_percent",
58+
"groupAggregation": "sum",
59+
"timeAggregation": "avg",
60+
"threshold": 90.0,
61+
"conditionOperator": ">",
62+
"noDataBehaviour": "DO_NOTHING",
63+
"range": 60,
64+
"duration": 0
65+
}
66+
}
67+
}`
68+
69+
var wrapper alertV2MetricWrapper
70+
err := json.Unmarshal([]byte(currentJSON), &wrapper)
71+
if err != nil {
72+
t.Fatalf("failed to unmarshal current alert JSON: %v", err)
73+
}
74+
75+
alert := wrapper.Alert
76+
77+
if alert.Config.Metric.ID != "sysdig_container_cpu_quota_used_percent" {
78+
t.Errorf("expected Metric.ID to be %q, got %q", "sysdig_container_cpu_quota_used_percent", alert.Config.Metric.ID)
79+
}
80+
81+
if alert.Config.MetricID != "sysdig_container_cpu_quota_used_percent" {
82+
t.Errorf("expected MetricID to be %q, got %q", "sysdig_container_cpu_quota_used_percent", alert.Config.MetricID)
83+
}
84+
}

sysdig/resource_sysdig_monitor_alert_v2_metric.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,11 @@ func updateAlertV2MetricState(d *schema.ResourceData, alert *v2.AlertV2Metric) e
275275

276276
_ = d.Set("group_aggregation", alert.Config.GroupAggregation)
277277

278-
_ = d.Set("metric", alert.Config.Metric.ID)
278+
metricID := alert.Config.Metric.ID
279+
if metricID == "" {
280+
metricID = alert.Config.MetricID
281+
}
282+
_ = d.Set("metric", metricID)
279283

280284
_ = d.Set("no_data_behaviour", alert.Config.NoDataBehaviour)
281285

0 commit comments

Comments
 (0)