Skip to content

Commit c56e349

Browse files
Feat: support for alertV2 (#194)
* AlertV2 model and client methods, AlertV2Prometheus resource * fix linting * COEOWNERS for monitor * fix notification_channels.type to be required * update AlertV2Prometheus docs
1 parent 9e886ee commit c56e349

File tree

10 files changed

+913
-0
lines changed

10 files changed

+913
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,4 @@ website/vendor
4141
# Binaries
4242
terraform-provider-sysdig
4343
oanc
44+
.vscode/settings.json

CODEOWNERS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,6 @@
33

44
# compliance
55
*benchmark* @haresh-suresh @nkraemer-sysdig
6+
7+
# monitor
8+
*monitor*alert* @arturodilecce
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package monitor
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"io"
7+
"net/http"
8+
)
9+
10+
func (c *sysdigMonitorClient) alertsV2URL() string {
11+
return fmt.Sprintf("%s/api/v2/alerts", c.URL)
12+
}
13+
14+
func (c *sysdigMonitorClient) alertV2URL(alertID int) string {
15+
return fmt.Sprintf("%s/api/v2/alerts/%d", c.URL, alertID)
16+
}
17+
18+
func (c *sysdigMonitorClient) CreateAlertV2Prometheus(ctx context.Context, alert AlertV2Prometheus) (createdAlert AlertV2Prometheus, err error) {
19+
body, err := c.createAlertV2(ctx, alert.ToJSON())
20+
if err != nil {
21+
return
22+
}
23+
createdAlert = AlertV2PrometheusFromJSON(body)
24+
25+
// this fixes the APIs bug of not setting the default group on the response of the create method
26+
if createdAlert.Group == "" {
27+
createdAlert.Group = "default"
28+
}
29+
return
30+
}
31+
32+
func (c *sysdigMonitorClient) UpdateAlertV2Prometheus(ctx context.Context, alert AlertV2Prometheus) (updatedAlert AlertV2Prometheus, err error) {
33+
body, err := c.updateAlertV2(ctx, alert.ID, alert.ToJSON())
34+
if err != nil {
35+
return
36+
}
37+
38+
updatedAlert = AlertV2PrometheusFromJSON(body)
39+
return
40+
}
41+
42+
func (c *sysdigMonitorClient) GetAlertV2PrometheusById(ctx context.Context, alertID int) (alert AlertV2Prometheus, err error) {
43+
body, err := c.getAlertV2ById(ctx, alertID)
44+
if err != nil {
45+
return
46+
}
47+
48+
alert = AlertV2PrometheusFromJSON(body)
49+
return
50+
}
51+
52+
func (c *sysdigMonitorClient) DeleteAlertV2Prometheus(ctx context.Context, alertID int) (err error) {
53+
return c.deleteAlertV2(ctx, alertID)
54+
}
55+
56+
// helpers
57+
58+
func (c *sysdigMonitorClient) createAlertV2(ctx context.Context, alertJson io.Reader) (responseBody []byte, err error) {
59+
response, err := c.doSysdigMonitorRequest(ctx, http.MethodPost, fmt.Sprintf("%s/create", c.alertsV2URL()), alertJson)
60+
if err != nil {
61+
return
62+
}
63+
defer response.Body.Close()
64+
65+
if response.StatusCode != http.StatusOK {
66+
err = errorFromResponse(response)
67+
return
68+
}
69+
70+
body, err := io.ReadAll(response.Body)
71+
return body, err
72+
}
73+
74+
func (c *sysdigMonitorClient) deleteAlertV2(ctx context.Context, alertID int) error {
75+
response, err := c.doSysdigMonitorRequest(ctx, http.MethodDelete, c.alertV2URL(alertID), nil)
76+
if err != nil {
77+
return err
78+
}
79+
defer response.Body.Close()
80+
81+
if response.StatusCode != http.StatusNoContent && response.StatusCode != http.StatusOK && response.StatusCode != http.StatusNotFound {
82+
return errorFromResponse(response)
83+
}
84+
85+
return err
86+
}
87+
88+
func (c *sysdigMonitorClient) updateAlertV2(ctx context.Context, alertID int, alertJson io.Reader) (responseBody []byte, err error) {
89+
response, err := c.doSysdigMonitorRequest(ctx, http.MethodPut, c.alertV2URL(alertID), alertJson)
90+
if err != nil {
91+
return
92+
}
93+
defer response.Body.Close()
94+
95+
if response.StatusCode != http.StatusOK {
96+
err = errorFromResponse(response)
97+
return
98+
}
99+
100+
body, err := io.ReadAll(response.Body)
101+
return body, err
102+
}
103+
104+
func (c *sysdigMonitorClient) getAlertV2ById(ctx context.Context, alertID int) (respBody []byte, err error) {
105+
response, err := c.doSysdigMonitorRequest(ctx, http.MethodGet, c.alertV2URL(alertID), nil)
106+
if err != nil {
107+
return
108+
}
109+
defer response.Body.Close()
110+
111+
if response.StatusCode != http.StatusOK {
112+
err = errorFromResponse(response)
113+
return
114+
}
115+
116+
body, err := io.ReadAll(response.Body)
117+
return body, err
118+
}

sysdig/internal/client/monitor/client.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ type SysdigMonitorClient interface {
1919
UpdateAlert(context.Context, Alert) (Alert, error)
2020
GetAlertById(context.Context, int) (Alert, error)
2121

22+
CreateAlertV2Prometheus(context.Context, AlertV2Prometheus) (AlertV2Prometheus, error)
23+
DeleteAlertV2Prometheus(context.Context, int) error
24+
UpdateAlertV2Prometheus(context.Context, AlertV2Prometheus) (AlertV2Prometheus, error)
25+
GetAlertV2PrometheusById(context.Context, int) (AlertV2Prometheus, error)
26+
2227
CreateTeam(context.Context, Team) (Team, error)
2328
GetTeamById(context.Context, int) (Team, error)
2429
UpdateTeam(context.Context, Team) (Team, error)
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
package monitor
2+
3+
import (
4+
"bytes"
5+
"encoding/json"
6+
"io"
7+
)
8+
9+
// --- Constants --
10+
const (
11+
// alert types enum
12+
AlertV2AlertType_AdvancedManual = "ADVANCED_MANUAL"
13+
AlertV2AlertType_AnomalyDetection = "ANOMALY_DETECTION"
14+
AlertV2AlertType_Dowtime = "DOWNTIME"
15+
AlertV2AlertType_Event = "EVENT"
16+
AlertV2AlertType_GroupOutlier = "GROUP_OUTLIER"
17+
AlertV2AlertType_Manual = "MANUAL"
18+
AlertV2AlertType_Prometheus = "PROMETHEUS"
19+
20+
// severities enum
21+
AlertV2Severity_High = "high"
22+
AlertV2Severity_Medium = "medium"
23+
AlertV2Severity_Low = "low"
24+
AlertV2Severity_Info = "info"
25+
26+
// alert link type
27+
AlertLinkV2Type_Dashboard = "dashboard"
28+
AlertLinkV2Type_Runbook = "runbook"
29+
30+
// others
31+
AlertV2CaptureFilenameRegexp = `.*?\.scap`
32+
)
33+
34+
// enums severity values
35+
func AlertV2Severity_Values() []string {
36+
return []string{
37+
AlertV2Severity_High,
38+
AlertV2Severity_Medium,
39+
AlertV2Severity_Low,
40+
AlertV2Severity_Info,
41+
}
42+
}
43+
44+
// AlertV2
45+
type AlertV2Common struct {
46+
ID int `json:"id,omitempty"`
47+
Version int `json:"version,omitempty"`
48+
Name string `json:"name"`
49+
Description string `json:"description,omitempty"`
50+
DurationSec int `json:"durationSec"`
51+
Type string `json:"type"`
52+
Group string `json:"group,omitempty"`
53+
Severity string `json:"severity"`
54+
TeamID int `json:"teamId,omitempty"`
55+
Enabled bool `json:"enabled"`
56+
NotificationChannelConfigList *[]NotificationChannelConfigV2 `json:"notificationChannelConfigList,omitempty"`
57+
CustomNotificationTemplate *CustomNotificationTemplateV2 `json:"customNotificationTemplate,omitempty"`
58+
CaptureConfig *CaptureConfigV2 `json:"captureConfig,omitempty"`
59+
Links *[]AlertLinkV2 `json:"links,omitempty"`
60+
}
61+
62+
type AlertV2ConfigPrometheus struct {
63+
Query string `json:"query"`
64+
}
65+
66+
type AlertV2Prometheus struct {
67+
AlertV2Common
68+
Config *AlertV2ConfigPrometheus `json:"config"`
69+
}
70+
71+
func (a *AlertV2Prometheus) ToJSON() io.Reader {
72+
data := struct {
73+
Alert AlertV2Prometheus `json:"alert"`
74+
}{Alert: *a}
75+
payload, _ := json.Marshal(data)
76+
return bytes.NewBuffer(payload)
77+
}
78+
79+
func AlertV2PrometheusFromJSON(body []byte) AlertV2Prometheus {
80+
var result struct {
81+
Alert AlertV2Prometheus
82+
}
83+
_ = json.Unmarshal(body, &result)
84+
return result.Alert
85+
}
86+
87+
// AlertScopeV2
88+
type AlertScopeV2 struct {
89+
Expressions []ScopeExpressionV2 `json:"expressions"`
90+
}
91+
92+
type AlertLabelDescriptorV2 struct {
93+
ID string `json:"id"`
94+
PublicID string `json:"publicId"`
95+
}
96+
97+
type NotificationGroupingConditionV2 struct {
98+
Type string `json:"type"`
99+
Value float64 `json:"value"`
100+
}
101+
102+
type AlertMetricDescriptorV2 struct {
103+
ID string `json:"id"`
104+
PublicID string `json:"publicId"`
105+
MetricType string `json:"metricType"`
106+
Type string `json:"type"`
107+
Scale float64 `json:"scale"`
108+
GroupAggregations []Aggregation `json:"groupAggregations"`
109+
TimeAggregations []Aggregation `json:"timeAggregations"`
110+
}
111+
112+
type Aggregation struct {
113+
ID int `json:"id"`
114+
Percentile bool `json:"percentile"`
115+
AggregationValue interface{} `json:"aggregationValue"`
116+
}
117+
118+
type ScopeExpressionV2 struct {
119+
Operand string `json:"operand"`
120+
Descriptor AlertLabelDescriptorV2 `json:"descriptor"`
121+
Operator ScopeExpressionOperator `json:"operator"`
122+
Value []string `json:"value"`
123+
}
124+
125+
type ScopeExpressionOperator struct {
126+
}
127+
128+
type NotificationChannelConfigV2 struct {
129+
// Type can be one of EMAIL, SNS, SLACK, PAGER_DUTY, VICTOROPS, OPSGENIE, WEBHOOK, IBM_FUNCTION, MS_TEAMS, TEAM_EMAIL, IBM_EVENT_NOTIFICATIONS, PROMETHEUS_ALERT_MANAGER
130+
ChannelID int `json:"channelId,omitempty"`
131+
Type string `json:"type,omitempty"`
132+
Name string `json:"nam,omitempty"`
133+
Enabled bool `json:"enabled,omitempty"`
134+
Options *NotificationChannelOptionsV2 `json:"options,omitempty"`
135+
}
136+
137+
type NotificationChannelOptionsV2 struct {
138+
// commons
139+
NotifyOnAcknowledge bool `json:"notifyOnAcknowledge,omitempty"`
140+
NotifyOnResolve bool `json:"notifyOnResolve,omitempty"`
141+
ReNotifyEverySec int `json:"reNotifyEverySec,omitempty"`
142+
CustomNotificationTemplate *CustomNotificationTemplateV2 `json:"customNotificationTemplate,omitempty"`
143+
Thresholds []string `json:"thresholds,omitempty"`
144+
}
145+
146+
type CustomNotificationTemplateV2 struct {
147+
Subject string `json:"subject,omitempty"`
148+
PrependText string `json:"prependText,omitempty"`
149+
AppendText string `json:"appendText,omitempty"`
150+
}
151+
152+
type CaptureConfigV2 struct {
153+
DurationSec int `json:"durationSec"`
154+
Storage string `json:"storage"`
155+
Filter string `json:"filter,omitempty"`
156+
FileName string `json:"fileName"`
157+
Enabled bool `json:"enabled"`
158+
}
159+
160+
// enums link types values
161+
func AlertLinkV2Type_Values() []string {
162+
return []string{
163+
AlertLinkV2Type_Dashboard,
164+
AlertLinkV2Type_Runbook,
165+
}
166+
}
167+
168+
type AlertLinkV2 struct {
169+
Name string `json:"name"`
170+
Type string `json:"type"`
171+
ID string `json:"id"`
172+
Href string `json:"href"`
173+
}

sysdig/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ func Provider() *schema.Provider {
7979
"sysdig_monitor_alert_anomaly": resourceSysdigMonitorAlertAnomaly(),
8080
"sysdig_monitor_alert_group_outlier": resourceSysdigMonitorAlertGroupOutlier(),
8181
"sysdig_monitor_alert_promql": resourceSysdigMonitorAlertPromql(),
82+
"sysdig_monitor_alert_v2_prometheus": resourceSysdigMonitorAlertV2Prometheus(),
8283
"sysdig_monitor_dashboard": resourceSysdigMonitorDashboard(),
8384
"sysdig_monitor_notification_channel_email": resourceSysdigMonitorNotificationChannelEmail(),
8485
"sysdig_monitor_notification_channel_opsgenie": resourceSysdigMonitorNotificationChannelOpsGenie(),

0 commit comments

Comments
 (0)