Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions docs/resources/notification_silencing_rule.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "netdata_notification_silencing_rule Resource - terraform-provider-netdata"
subcategory: ""
description: |-
Provides a Netdata Cloud Notification Silencing Rule resource. Use this resource to manage notification silencing rules in Netdata Cloud.
A notification silencing rule allows you to silence notifications for specific alerts, nodes, rooms, or spaces based on various criteria.
---

# netdata_notification_silencing_rule (Resource)

Provides a Netdata Cloud Notification Silencing Rule resource. Use this resource to manage notification silencing rules in Netdata Cloud.
A notification silencing rule allows you to silence notifications for specific alerts, nodes, rooms, or spaces based on various criteria.

## Example Usage

```terraform
resource "netdata_notification_silencing_rule" "test" {
space_id = "<space_id>"
name = "testing"
starts_at = "2025-09-01T00:00:00Z"
lasts_until = "2025-12-31T23:59:59Z"
notification_options = ["CRITICAL", "WARNING"]
alert_names = ["disk.space"]
alert_contexts = ["disk_space_usage"]
timezone = "America/New_York"
rrule = "RRULE:FREQ=WEEKLY;INTERVAL=1;COUNT=5;BYDAY=MO"
delete_on_expiry = false
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `name` (String) The name of the silencing rule.
- `space_id` (String) The ID of the space.
- `starts_at` (String) The start time of the silencing rule in RFC3339 format. Must be expressed in UTC, e.g. "2026-09-01T00:00:00Z". A value carrying a non-UTC offset such as "+02:00" is rejected at plan time, because the API stores and returns timestamps in UTC. Use `timezone` to control the schedule's local time.

### Optional

- `alert_contexts` (List of String) List of alert contexts to silence. When empty it applies to all alert contexts. Example ["disk_space_usage"].
- `alert_instances` (List of String) List of alert instances to silence. When empty it applies to all alert instances. Example ["disk_space./"].
- `alert_names` (List of String) List of alert names to silence. When empty it applies to all alert names. Example ["disk.space"].
- `alert_roles` (List of String) List of alert roles to silence. When empty it applies to all alert roles. Example ["webmaster"].
- `delete_on_expiry` (Boolean) Whether to delete the silencing rule when it expires. If enabled, then it requires setting lasts_until. It is not compatible with an RRule.. then Defaults to false.
- `disabled` (Boolean) Whether the silencing rule is disabled. Defaults to false.
- `host_labels` (Map of String) Host labels to filter nodes the silencing rule applies to. When empty it applies to any label. Example { os = "linux" }.
- `integration_ids` (List of String) List of integration (notification methods) IDs to apply the silencing rule to. When empty it applies to all integrations in the space.
- `lasts_until` (String) The end time of the silencing rule in RFC3339 format. Must be expressed in UTC, e.g. "2026-12-31T23:59:59Z". A value carrying a non-UTC offset such as "+02:00" is rejected at plan time, because the API stores and returns timestamps in UTC. If not set, the rule does not expire.
- `node_ids` (List of String) List of node IDs to apply the silencing rule to. When empty it applies to all nodes in the space.
- `notification_options` (List of String) List of notification options to silence. Valid values: CRITICAL, WARNING, CLEAR, REACHABLE, UNREACHABLE.
- `room_ids` (List of String) List of room IDs to apply the silencing rule to. When empty it applies to all rooms in the space.
- `rrule` (String) The recurrence rule (RRULE) for the silencing rule. The format orignates from the iCalendar specification (RFC 5545). Must not include a DTSTART line - the recurrence start is taken from starts_at. Example: "RRULE:FREQ=MONTHLY;INTERVAL=1;COUNT=10;BYMONTHDAY=1".
- `timezone` (String) The timezone for the silencing rule schedule. Must be a valid IANA timezone (e.g. "America/New_York", "UTC"). Defaults to "UTC".

### Read-Only

- `id` (String) The ID of the silencing rule.

## Import

Import is supported using the following syntax:

The [`terraform import` command](https://developer.hashicorp.com/terraform/cli/commands/import) can be used, for example:

```shell
#!/bin/sh

terraform import netdata_notification_silencing_rule.test space_id,notification_silencing_rule_id
```
13 changes: 13 additions & 0 deletions examples/complete/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,19 @@ resource "netdata_notification_pagerduty_channel" "test" {
integration_key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}

resource "netdata_notification_silencing_rule" "test" {
space_id = netdata_space.test.id
name = "Testing Rule"
starts_at = "2026-09-01T00:00:00Z"
lasts_until = "2030-12-31T23:59:59Z"
notification_options = ["CRITICAL", "WARNING"]
alert_names = ["disk.space"]
alert_contexts = ["disk_space_usage"]
timezone = "America/New_York"
rrule = "RRULE:FREQ=WEEKLY;INTERVAL=1;COUNT=5;BYDAY=MO"
delete_on_expiry = false
}

data "netdata_space" "test" {
id = netdata_space.test.id
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/sh

terraform import netdata_notification_silencing_rule.test space_id,notification_silencing_rule_id
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
resource "netdata_notification_silencing_rule" "test" {
space_id = "<space_id>"
name = "testing"
starts_at = "2025-09-01T00:00:00Z"
lasts_until = "2025-12-31T23:59:59Z"
notification_options = ["CRITICAL", "WARNING"]
alert_names = ["disk.space"]
alert_contexts = ["disk_space_usage"]
timezone = "America/New_York"
rrule = "RRULE:FREQ=WEEKLY;INTERVAL=1;COUNT=5;BYDAY=MO"
delete_on_expiry = false
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ require (
github.com/hashicorp/logutils v1.0.0 // indirect
github.com/hashicorp/terraform-exec v0.25.1 // indirect
github.com/hashicorp/terraform-json v0.27.3-0.20260213134036-298b8f6b673a // indirect
github.com/hashicorp/terraform-plugin-framework-timetypes v0.5.0 // indirect
github.com/hashicorp/terraform-plugin-sdk/v2 v2.40.0 // indirect
github.com/hashicorp/terraform-registry-address v0.4.0 // indirect
github.com/hashicorp/terraform-svchost v0.2.1 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ github.com/hashicorp/terraform-plugin-docs v0.25.0 h1:qHs1V257NxVe8tv6HS4UQfNqja
github.com/hashicorp/terraform-plugin-docs v0.25.0/go.mod h1:MQggCmY8zgP7R7E/cC0b0cmTvA9hSj3ZKyrrsDjRbLo=
github.com/hashicorp/terraform-plugin-framework v1.19.0 h1:q0bwyhxAOR3vfdgbk9iplv3MlTv/dhBHTXjQOtQDoBA=
github.com/hashicorp/terraform-plugin-framework v1.19.0/go.mod h1:YRXOBu0jvs7xp4AThBbX4mAzYaMJ1JgtFH//oGKxwLc=
github.com/hashicorp/terraform-plugin-framework-timetypes v0.5.0 h1:v3DapR8gsp3EM8fKMh6up9cJUFQ2iRaFsYLP8UJnCco=
github.com/hashicorp/terraform-plugin-framework-timetypes v0.5.0/go.mod h1:c3PnGE9pHBDfdEVG9t1S1C9ia5LW+gkFR0CygXlM8ak=
github.com/hashicorp/terraform-plugin-framework-validators v0.19.0 h1:Zz3iGgzxe/1XBkooZCewS0nJAaCFPFPHdNJd8FgE4Ow=
github.com/hashicorp/terraform-plugin-framework-validators v0.19.0/go.mod h1:GBKTNGbGVJohU03dZ7U8wHqc2zYnMUawgCN+gC0itLc=
github.com/hashicorp/terraform-plugin-go v0.31.0 h1:0Fz2r9DQ+kNNl6bx8HRxFd1TfMKUvnrOtvJPmp3Z0q8=
Expand Down
2 changes: 2 additions & 0 deletions internal/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ var (
ErrNodeID = errors.New("nodeID is required")
ErrNodeMembershipIDRequired = errors.New("nodeMembershipID is required")
ErrNodeMembershipActionRequired = errors.New("nodeMembershipAction is required")
ErrSilencingRuleIDRequired = errors.New("silencingRuleID is required")
ErrInvalidSilencingRuleID = errors.New("silencingRuleID is invalid, must be a valid UUID")
)

type Client struct {
Expand Down
21 changes: 21 additions & 0 deletions internal/client/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package client

import (
"encoding/json"
"time"

"github.com/google/uuid"
)
Expand Down Expand Up @@ -102,3 +103,23 @@ type NodeMembershipClause struct {
Value string `json:"value"`
Negate bool `json:"negate"`
}

type SilencingRule struct {
ID uuid.UUID `json:"id"`
Name string `json:"name"`
RoomIDs []uuid.UUID `json:"room_ids,omitempty"`
NodeIDs []uuid.UUID `json:"node_ids,omitempty"`
HostLabels map[string]string `json:"host_labels,omitempty"`
AlertNames []string `json:"alert_names,omitempty"`
AlertContexts []string `json:"alert_contexts,omitempty"`
AlertInstances []string `json:"alert_instances,omitempty"`
AlertRoles []string `json:"alert_roles,omitempty"`
NotificationOptions []string `json:"notification_options,omitempty"`
IntegrationIDs []uuid.UUID `json:"integration_ids,omitempty"`
StartsAt time.Time `json:"starts_at"`
LastsUntil *time.Time `json:"lasts_until,omitempty"`
DeleteOnExpiry bool `json:"delete_on_expiry"`
Disabled bool `json:"disabled"`
RRule *string `json:"rrule,omitempty"`
Timezone *string `json:"timezone,omitempty"`
}
133 changes: 133 additions & 0 deletions internal/client/notification_silencing_rule.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package client

import (
"bytes"
"encoding/json"
"fmt"
"net/http"

"github.com/google/uuid"
)

func (c *Client) CreateSilencingRule(spaceID string, silencingRule SilencingRule) (*SilencingRule, error) {

if spaceID == "" {
return nil, ErrSpaceIDRequired
}

silencingRuleJson, err := json.Marshal(silencingRule)
if err != nil {
return nil, err
}

req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s/api/v2/spaces/%s/notifications/silencing/rule", c.HostURL, spaceID), bytes.NewReader(silencingRuleJson))
if err != nil {
return nil, err
}

var silencingRuleResponse SilencingRule

err = c.doRequestUnmarshal(req, &silencingRuleResponse)
if err != nil {
return nil, err
}

return &silencingRuleResponse, nil

}

func (c *Client) GetSilencingRule(silencingRuleID, spaceID string) (*SilencingRule, error) {

if silencingRuleID == "" {
return nil, ErrSilencingRuleIDRequired
}

parsedSilencingRuleID, err := uuid.Parse(silencingRuleID)
if err != nil {
return nil, ErrInvalidSilencingRuleID
}

if spaceID == "" {
return nil, ErrSpaceIDRequired
}

req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/api/v2/spaces/%s/notifications/silencing/rules", c.HostURL, spaceID), nil)
if err != nil {
return nil, err
}

var silencingRules []SilencingRule

err = c.doRequestUnmarshal(req, &silencingRules)
if err != nil {
return nil, err
}

for _, rule := range silencingRules {
if rule.ID == parsedSilencingRuleID {
return &rule, nil
}
}

return nil, ErrNotFound
}

func (c *Client) DeleteSilencingRule(silencingRuleID, spaceID string) error {

if silencingRuleID == "" {
return ErrSilencingRuleIDRequired
}

if spaceID == "" {
return ErrSpaceIDRequired
}

reqBody, err := json.Marshal([]string{silencingRuleID})
if err != nil {
return err
}

req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s/api/v2/spaces/%s/notifications/silencing/rules/delete", c.HostURL, spaceID), bytes.NewReader(reqBody))
if err != nil {
return err
}

_, err = c.doRequest(req)
if err != nil {
return err
}

return nil

}

func (c *Client) UpdateSilencingRule(silencingRuleID, spaceID string, silencingRule SilencingRule) (*SilencingRule, error) {

if silencingRuleID == "" {
return nil, ErrSilencingRuleIDRequired
}

if spaceID == "" {
return nil, ErrSpaceIDRequired
}

silencingRuleJson, err := json.Marshal(silencingRule)
if err != nil {
return nil, err
}

req, err := http.NewRequest(http.MethodPut, fmt.Sprintf("%s/api/v2/spaces/%s/notifications/silencing/rule/%s", c.HostURL, spaceID, silencingRuleID), bytes.NewReader(silencingRuleJson))
if err != nil {
return nil, err
}

var silencingRuleResponse SilencingRule

err = c.doRequestUnmarshal(req, &silencingRuleResponse)
if err != nil {
return nil, err
}

return &silencingRuleResponse, nil

}
6 changes: 6 additions & 0 deletions internal/provider/node_room_member.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,19 @@ There are two options to add nodes to the room:
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
Validators: []validator.String{
UUID(),
},
},
"space_id": schema.StringAttribute{
Description: "Space ID of the member.",
Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
Validators: []validator.String{
UUID(),
},
},
"node_names": schema.ListAttribute{
Description: "List of node names to add to the room. At least one node name is required.",
Expand Down
Loading
Loading