Skip to content

Commit daf27af

Browse files
authored
feat(monitor): add resource to manage Inhibition rules (#535)
* feat(monitor): add resource to manage inhibition rules * feat(monitor): add labels attribute to alerts
1 parent e5fa378 commit daf27af

18 files changed

+747
-1
lines changed

CODEOWNERS

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
*monitor*providers* @jwsarna1
1111
*monitor*groupmapping* @shadow649
1212
*notification_channel* @michelevergnano @dkutsanov @antonio-cuomo @dbonf
13+
*inhibition_rule* @michelevergnano @dkutsanov @antonio-cuomo @dbonf
14+
*silence_rule* @michelevergnano @dkutsanov @antonio-cuomo @dbonf
1315

1416
# policies/rules
1517
*secure*policy* @kmvachhani @rosenbloomb-sysdig @ombellare @miguelgordo @ivanlysiuk-sysdig @daniel-almeida @jbainbridgesysdig @IvanNik @hila1608 @yaminSapir @chen-shmilovich-sysdig @zohar-arad

sysdig/internal/client/v2/client.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ type MonitorCommon interface {
5151
AlertV2Interface
5252
DashboardInterface
5353
SilenceRuleInterface
54+
InhibitionRuleInterface
5455
}
5556

5657
type SecureCommon interface {
@@ -75,7 +76,7 @@ func (client *Client) ErrorFromResponse(response *http.Response) error {
7576
return errors.New(response.Status)
7677
}
7778

78-
search, err := jmespath.Search("[message, error, errors[].[reason, message]][][] | join(', ', @)", data)
79+
search, err := jmespath.Search("[message, error, details[], errors[].[reason, message]][][] | join(', ', @)", data)
7980
if err != nil {
8081
return errors.New(response.Status)
8182
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package v2
2+
3+
import (
4+
"context"
5+
"errors"
6+
"fmt"
7+
"net/http"
8+
)
9+
10+
const (
11+
inhibitionRulesPath = "%s/monitor/alerts/v1/inhibition-rules"
12+
inhibitionRulePath = "%s/monitor/alerts/v1/inhibition-rules/%d"
13+
)
14+
15+
var ErrInhibitionRuleNotFound = errors.New("inhibition rule not found")
16+
17+
type InhibitionRuleInterface interface {
18+
Base
19+
GetInhibitionRule(ctx context.Context, id int) (InhibitionRule, error)
20+
CreateInhibitionRule(ctx context.Context, inhibitionRule InhibitionRule) (InhibitionRule, error)
21+
UpdateInhibitionRule(ctx context.Context, inhibitionRule InhibitionRule) (InhibitionRule, error)
22+
DeleteInhibitionRule(ctx context.Context, id int) error
23+
}
24+
25+
func (client *Client) GetInhibitionRule(ctx context.Context, id int) (InhibitionRule, error) {
26+
response, err := client.requester.Request(ctx, http.MethodGet, client.getInhibitionRuleURL(id), nil)
27+
if err != nil {
28+
return InhibitionRule{}, err
29+
}
30+
defer response.Body.Close()
31+
32+
if response.StatusCode == http.StatusNotFound {
33+
return InhibitionRule{}, ErrInhibitionRuleNotFound
34+
}
35+
if response.StatusCode != http.StatusOK {
36+
return InhibitionRule{}, client.ErrorFromResponse(response)
37+
}
38+
39+
inhibitionRule, err := Unmarshal[InhibitionRule](response.Body)
40+
if err != nil {
41+
return InhibitionRule{}, err
42+
}
43+
44+
return inhibitionRule, nil
45+
}
46+
47+
func (client *Client) CreateInhibitionRule(ctx context.Context, inhibitionRule InhibitionRule) (InhibitionRule, error) {
48+
payload, err := Marshal(inhibitionRule)
49+
if err != nil {
50+
return InhibitionRule{}, err
51+
}
52+
53+
response, err := client.requester.Request(ctx, http.MethodPost, client.getInhibitionRulesURL(), payload)
54+
if err != nil {
55+
return InhibitionRule{}, err
56+
}
57+
defer response.Body.Close()
58+
59+
if response.StatusCode != http.StatusOK && response.StatusCode != http.StatusCreated {
60+
return InhibitionRule{}, client.ErrorFromResponse(response)
61+
}
62+
63+
return Unmarshal[InhibitionRule](response.Body)
64+
}
65+
66+
func (client *Client) UpdateInhibitionRule(ctx context.Context, inhibitionRule InhibitionRule) (InhibitionRule, error) {
67+
payload, err := Marshal(inhibitionRule)
68+
if err != nil {
69+
return InhibitionRule{}, err
70+
}
71+
72+
response, err := client.requester.Request(ctx, http.MethodPut, client.getInhibitionRuleURL(inhibitionRule.ID), payload)
73+
if err != nil {
74+
return InhibitionRule{}, err
75+
}
76+
defer response.Body.Close()
77+
78+
if response.StatusCode != http.StatusOK {
79+
return InhibitionRule{}, client.ErrorFromResponse(response)
80+
}
81+
82+
return Unmarshal[InhibitionRule](response.Body)
83+
}
84+
85+
func (client *Client) DeleteInhibitionRule(ctx context.Context, id int) error {
86+
response, err := client.requester.Request(ctx, http.MethodDelete, client.getInhibitionRuleURL(id), nil)
87+
if err != nil {
88+
return err
89+
}
90+
defer response.Body.Close()
91+
92+
if response.StatusCode != http.StatusNoContent && response.StatusCode != http.StatusOK && response.StatusCode != http.StatusNotFound {
93+
return client.ErrorFromResponse(response)
94+
}
95+
96+
return nil
97+
}
98+
99+
func (client *Client) getInhibitionRulesURL() string {
100+
return fmt.Sprintf(inhibitionRulesPath, client.config.url)
101+
}
102+
103+
func (client *Client) getInhibitionRuleURL(id int) string {
104+
return fmt.Sprintf(inhibitionRulePath, client.config.url, id)
105+
}

sysdig/internal/client/v2/model.go

+19
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,7 @@ type AlertV2Common struct {
706706
CustomNotificationTemplate *CustomNotificationTemplateV2 `json:"customNotificationTemplate,omitempty"`
707707
CaptureConfig *CaptureConfigV2 `json:"captureConfig,omitempty"`
708708
Links []AlertLinkV2 `json:"links"`
709+
Labels map[string]interface{} `json:"labels,omitempty"`
709710
}
710711

711712
type AlertV2ConfigPrometheus struct {
@@ -1088,6 +1089,24 @@ type SilenceRule struct {
10881089
ID int `json:"id,omitempty"`
10891090
}
10901091

1092+
type InhibitionRule struct {
1093+
Name string `json:"name,omitempty"`
1094+
Description string `json:"description,omitempty"`
1095+
Enabled bool `json:"isEnabled"`
1096+
SourceMatchers []LabelMatchers `json:"sourceMatchers"`
1097+
TargetMatchers []LabelMatchers `json:"targetMatchers"`
1098+
Equal []string `json:"equal,omitempty"`
1099+
1100+
Version int `json:"version,omitempty"`
1101+
ID int `json:"id,omitempty"`
1102+
}
1103+
1104+
type LabelMatchers struct {
1105+
LabelName string `json:"labelName"`
1106+
Operator string `json:"operator"`
1107+
Value string `json:"value"`
1108+
}
1109+
10911110
type AgentAccessKey struct {
10921111
ID int `json:"id,omitempty"`
10931112
Reservation int `json:"agentReservation,omitempty"`

sysdig/provider.go

+1
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ func (p *SysdigProvider) Provider() *schema.Provider {
159159
"sysdig_secure_cloud_auth_account_feature": resourceSysdigSecureCloudauthAccountFeature(),
160160

161161
"sysdig_monitor_silence_rule": resourceSysdigMonitorSilenceRule(),
162+
"sysdig_monitor_inhibition_rule": resourceSysdigMonitorInhibitionRule(),
162163
"sysdig_monitor_alert_downtime": resourceSysdigMonitorAlertDowntime(),
163164
"sysdig_monitor_alert_metric": resourceSysdigMonitorAlertMetric(),
164165
"sysdig_monitor_alert_event": resourceSysdigMonitorAlertEvent(),

sysdig/resource_sysdig_monitor_alert_v2_common.go

+8
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,10 @@ func createAlertV2Schema(original map[string]*schema.Schema) map[string]*schema.
177177
},
178178
},
179179
},
180+
"labels": {
181+
Type: schema.TypeMap,
182+
Optional: true,
183+
},
180184
}
181185

182186
for k, v := range original {
@@ -307,6 +311,8 @@ func buildAlertV2CommonStruct(d *schema.ResourceData) *v2.AlertV2Common {
307311
}
308312
}
309313

314+
alert.Labels = d.Get("labels").(map[string]interface{})
315+
310316
return alert
311317
}
312318

@@ -395,6 +401,8 @@ func updateAlertV2CommonState(d *schema.ResourceData, alert *v2.AlertV2Common) (
395401
_ = d.Set("link", links)
396402
}
397403

404+
_ = d.Set("labels", alert.Labels)
405+
398406
return nil
399407
}
400408

sysdig/resource_sysdig_monitor_alert_v2_metric_test.go

+23
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ func TestAccAlertV2Metric(t *testing.T) {
6666
{
6767
Config: alertV2MetricWithUnreportedAlertNotificationsRetentionSec(rText()),
6868
},
69+
{
70+
Config: alertV2MetricWithLabels(rText()),
71+
},
6972
{
7073
Config: alertV2MetricWithWarningThreshold(rText()),
7174
},
@@ -383,6 +386,26 @@ resource "sysdig_monitor_alert_v2_metric" "sample" {
383386
`, name)
384387
}
385388

389+
func alertV2MetricWithLabels(name string) string {
390+
return fmt.Sprintf(`
391+
392+
resource "sysdig_monitor_alert_v2_metric" "sample" {
393+
394+
name = "TERRAFORM TEST - METRICV2 %s"
395+
metric = "sysdig_container_cpu_used_percent"
396+
group_aggregation = "avg"
397+
time_aggregation = "avg"
398+
operator = ">="
399+
threshold = 50
400+
trigger_after_minutes = 15
401+
labels = {
402+
application = "app1"
403+
maturity = "high"
404+
}
405+
}
406+
`, name)
407+
}
408+
386409
func alertV2MetricWithWarningThreshold(name string) string {
387410
return fmt.Sprintf(`
388411
resource "sysdig_monitor_notification_channel_email" "nc_email1" {

0 commit comments

Comments
 (0)