Skip to content

Commit

Permalink
feat(monitor): resource for silence rule
Browse files Browse the repository at this point in the history
  • Loading branch information
dbonf committed Aug 7, 2023
1 parent 0bab7f1 commit b81bd9f
Show file tree
Hide file tree
Showing 7 changed files with 549 additions and 0 deletions.
13 changes: 13 additions & 0 deletions sysdig/internal/client/v2/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -708,3 +708,16 @@ type IdentityContext struct {
ServiceAccountID int `json:"serviceAccountId"`
ServiceAccountName string `json:"serviceAccountName"`
}

type SilenceRule struct {
Name string `json:"name"`
Enabled bool `json:"enabled"`
StartTs int64 `json:"startTs"`
DurationInSec int `json:"durationInSec"`
Scope string `json:"scope,omitempty"`
AlertIds []int `json:"alertIds,omitempty"`
NotificationChannelIds []int `json:"notificationChannelIds,omitempty"`

Version int `json:"version,omitempty"`
ID int `json:"id,omitempty"`
}
99 changes: 99 additions & 0 deletions sysdig/internal/client/v2/silence_rule.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package v2

import (
"context"
"fmt"
"net/http"
)

const (
silenceRulesPath = "%s/api/v1/silencingRules"
silenceRulePath = "%s/api/v1/silencingRules/%d"
)

type SilenceRuleInterface interface {
Base
GetSilenceRule(ctx context.Context, id int) (SilenceRule, error)
CreateSilenceRule(ctx context.Context, silenceRule SilenceRule) (SilenceRule, error)
UpdateSilenceRule(ctx context.Context, silenceRule SilenceRule) (SilenceRule, error)
DeleteSilenceRule(ctx context.Context, id int) error
}

func (client *Client) GetSilenceRule(ctx context.Context, id int) (SilenceRule, error) {
response, err := client.requester.Request(ctx, http.MethodGet, client.getSilenceRuleURL(id), nil)
if err != nil {
return SilenceRule{}, err
}
defer response.Body.Close()

if response.StatusCode != http.StatusOK {
return SilenceRule{}, client.ErrorFromResponse(response)
}

silenceRule, err := Unmarshal[SilenceRule](response.Body)
if err != nil {
return SilenceRule{}, err
}

return silenceRule, nil
}

func (client *Client) CreateSilenceRule(ctx context.Context, silenceRule SilenceRule) (SilenceRule, error) {
payload, err := Marshal(silenceRule)
if err != nil {
return SilenceRule{}, err
}

response, err := client.requester.Request(ctx, http.MethodPost, client.getSilenceRulesURL(), payload)
if err != nil {
return SilenceRule{}, err
}
defer response.Body.Close()

if response.StatusCode != http.StatusOK && response.StatusCode != http.StatusCreated {
return SilenceRule{}, client.ErrorFromResponse(response)
}

return Unmarshal[SilenceRule](response.Body)
}

func (client *Client) UpdateSilenceRule(ctx context.Context, silenceRule SilenceRule) (SilenceRule, error) {
payload, err := Marshal(silenceRule)
if err != nil {
return SilenceRule{}, err
}

response, err := client.requester.Request(ctx, http.MethodPut, client.getSilenceRuleURL(silenceRule.ID), payload)
if err != nil {
return SilenceRule{}, err
}
defer response.Body.Close()

if response.StatusCode != http.StatusOK {
return SilenceRule{}, client.ErrorFromResponse(response)
}

return Unmarshal[SilenceRule](response.Body)
}

func (client *Client) DeleteSilenceRule(ctx context.Context, id int) error {
response, err := client.requester.Request(ctx, http.MethodDelete, client.getSilenceRuleURL(id), nil)
if err != nil {
return err
}
defer response.Body.Close()

if response.StatusCode != http.StatusNoContent && response.StatusCode != http.StatusOK && response.StatusCode != http.StatusNotFound {
return client.ErrorFromResponse(response)
}

return nil
}

func (client *Client) getSilenceRulesURL() string {
return fmt.Sprintf(silenceRulesPath, client.config.url)
}

func (client *Client) getSilenceRuleURL(id int) string {
return fmt.Sprintf(silenceRulePath, client.config.url, id)
}
1 change: 1 addition & 0 deletions sysdig/internal/client/v2/sysdig.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type SysdigMonitor interface {
SysdigCommon
MonitorCommon
DashboardInterface
SilenceRuleInterface
CloudAccountMonitorInterface
AlertV2Interface
}
Expand Down
1 change: 1 addition & 0 deletions sysdig/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ func Provider() *schema.Provider {
"sysdig_secure_scanning_policy": resourceSysdigSecureScanningPolicy(),
"sysdig_secure_scanning_policy_assignment": resourceSysdigSecureScanningPolicyAssignment(),

"sysdig_monitor_silence_rule": resourceSysdigMonitorSilenceRule(),
"sysdig_monitor_alert_downtime": resourceSysdigMonitorAlertDowntime(),
"sysdig_monitor_alert_metric": resourceSysdigMonitorAlertMetric(),
"sysdig_monitor_alert_event": resourceSysdigMonitorAlertEvent(),
Expand Down
218 changes: 218 additions & 0 deletions sysdig/resource_sysdig_monitor_silence_rule.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
package sysdig

import (
"context"
"strconv"
"time"

v2 "github.com/draios/terraform-provider-sysdig/sysdig/internal/client/v2"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)

func resourceSysdigMonitorSilenceRule() *schema.Resource {
timeout := 5 * time.Minute

return &schema.Resource{
CreateContext: resourceSysdigMonitorSilenceRuleCreate,
UpdateContext: resourceSysdigMonitorSilenceRuleUpdate,
ReadContext: resourceSysdigMonitorSilenceRuleRead,
DeleteContext: resourceSysdigMonitorSilenceRuleDelete,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},

Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(timeout),
Update: schema.DefaultTimeout(timeout),
Read: schema.DefaultTimeout(timeout),
Delete: schema.DefaultTimeout(timeout),
},

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
},
"enabled": {
Type: schema.TypeBool,
Optional: true,
Default: true,
},
"start_ts": {
Type: schema.TypeString,
Required: true,
},
"duration_seconds": {
Type: schema.TypeInt,
Required: true,
ValidateFunc: validation.IntAtLeast(60),
},
"alert_ids": {
Type: schema.TypeSet,
Elem: &schema.Schema{
Type: schema.TypeInt,
},
Optional: true,
},
"scope": {
Type: schema.TypeString,
Optional: true,
},
"notification_channel_ids": {
Type: schema.TypeSet,
Elem: &schema.Schema{
Type: schema.TypeInt,
},
Optional: true,
},
"version": {
Type: schema.TypeInt,
Computed: true,
},
},
}
}

func getMonitorSilenceRuleClient(c SysdigClients) (v2.SilenceRuleInterface, error) {
return c.sysdigMonitorClientV2()
}

func resourceSysdigMonitorSilenceRuleCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client, err := getMonitorSilenceRuleClient(meta.(SysdigClients))
if err != nil {
return diag.FromErr(err)
}

silenceRule, err := monitorSilenceRuleFromResourceData(d)
if err != nil {
return diag.FromErr(err)
}

silenceRule, err = client.CreateSilenceRule(ctx, silenceRule)
if err != nil {
return diag.FromErr(err)
}

d.SetId(strconv.Itoa(silenceRule.ID))

return resourceSysdigMonitorSilenceRuleRead(ctx, d, meta)
}

func resourceSysdigMonitorSilenceRuleRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client, err := getMonitorSilenceRuleClient(meta.(SysdigClients))
if err != nil {
return diag.FromErr(err)
}

id, err := strconv.Atoi(d.Id())
if err != nil {
return diag.FromErr(err)
}

silenceRule, err := client.GetSilenceRule(ctx, id)

if err != nil {
d.SetId("")
return diag.FromErr(err)
}

// suppress diff of "enabled" field if the silence interval is over: it will always be false from the api
// any update of an ended silence rule results in a 422 Unprocessable Entity error from the api
silenceRuleEnd := time.Unix(silenceRule.StartTs/1000+int64(silenceRule.DurationInSec), 0)
if time.Now().After(silenceRuleEnd) {
silenceRule.Enabled = d.Get("enabled").(bool)
}

err = monitorSilenceRuleToResourceData(silenceRule, d)
if err != nil {
return diag.FromErr(err)
}

return nil
}

func resourceSysdigMonitorSilenceRuleUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client, err := getMonitorSilenceRuleClient(meta.(SysdigClients))
if err != nil {
return diag.FromErr(err)
}

silenceRule, err := monitorSilenceRuleFromResourceData(d)
if err != nil {
return diag.FromErr(err)
}

silenceRule.Version = d.Get("version").(int)
silenceRule.ID, err = strconv.Atoi(d.Id())
if err != nil {
return diag.FromErr(err)
}

_, err = client.UpdateSilenceRule(ctx, silenceRule)
if err != nil {
return diag.FromErr(err)
}

return nil
}

func resourceSysdigMonitorSilenceRuleDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client, err := getMonitorSilenceRuleClient(meta.(SysdigClients))
if err != nil {
return diag.FromErr(err)
}

id, err := strconv.Atoi(d.Id())
if err != nil {
return diag.FromErr(err)
}

err = client.DeleteSilenceRule(ctx, id)
if err != nil {
return diag.FromErr(err)
}

return nil
}

func monitorSilenceRuleFromResourceData(d *schema.ResourceData) (v2.SilenceRule, error) {
silenceRule := v2.SilenceRule{}

silenceRule.Name = d.Get("name").(string)
silenceRule.Enabled = d.Get("enabled").(bool)
startTs, err := strconv.ParseInt(d.Get("start_ts").(string), 10, 64)
if err != nil {
return silenceRule, err
}
silenceRule.StartTs = startTs
silenceRule.DurationInSec = d.Get("duration_seconds").(int)
silenceRule.Scope = d.Get("scope").(string)
alertIds := d.Get("alert_ids").(*schema.Set)
for _, rawAlertId := range alertIds.List() {
if alertId, ok := rawAlertId.(int); ok {
silenceRule.AlertIds = append(silenceRule.AlertIds, alertId)
}
}
notificationChannelIds := d.Get("notification_channel_ids").(*schema.Set)
for _, rawNotificationChannelId := range notificationChannelIds.List() {
if notificationChannelId, ok := rawNotificationChannelId.(int); ok {
silenceRule.NotificationChannelIds = append(silenceRule.NotificationChannelIds, notificationChannelId)
}
}
return silenceRule, nil
}

func monitorSilenceRuleToResourceData(silenceRule v2.SilenceRule, d *schema.ResourceData) (err error) {
_ = d.Set("name", silenceRule.Name)
_ = d.Set("enabled", silenceRule.Enabled)
_ = d.Set("start_ts", strconv.FormatInt(silenceRule.StartTs, 10))
_ = d.Set("duration_seconds", silenceRule.DurationInSec)
_ = d.Set("alert_ids", silenceRule.AlertIds)
_ = d.Set("scope", silenceRule.Scope)
_ = d.Set("notification_channel_ids", silenceRule.NotificationChannelIds)
_ = d.Set("version", silenceRule.Version)
return nil
}
Loading

0 comments on commit b81bd9f

Please sign in to comment.