From 5cdbd93b25e8139f3280639d9b826dcacae57a71 Mon Sep 17 00:00:00 2001 From: Yuri Tseretyan Date: Wed, 18 Oct 2023 17:29:15 -0400 Subject: [PATCH 1/2] add on-call --- docs/resources/contact_point.md | 26 ++++ .../_acc_receiver_types_10_2.tf | 13 ++ .../resource_alerting_contact_point.go | 1 + ...source_alerting_contact_point_notifiers.go | 133 ++++++++++++++++++ .../resource_alerting_contact_point_test.go | 31 ++++ 5 files changed, 204 insertions(+) create mode 100644 examples/resources/grafana_contact_point/_acc_receiver_types_10_2.tf diff --git a/docs/resources/contact_point.md b/docs/resources/contact_point.md index ace2517ce..9285c9335 100644 --- a/docs/resources/contact_point.md +++ b/docs/resources/contact_point.md @@ -49,6 +49,7 @@ resource "grafana_contact_point" "my_contact_point" { - `googlechat` (Block List) A contact point that sends notifications to Google Chat. (see [below for nested schema](#nestedblock--googlechat)) - `kafka` (Block List) A contact point that publishes notifications to Apache Kafka topics. (see [below for nested schema](#nestedblock--kafka)) - `line` (Block List) A contact point that sends notifications to LINE.me. (see [below for nested schema](#nestedblock--line)) +- `oncall` (Block List) A contact point that sends notifications to Grafana On-Call. (see [below for nested schema](#nestedblock--oncall)) - `opsgenie` (Block List) A contact point that sends notifications to OpsGenie. (see [below for nested schema](#nestedblock--opsgenie)) - `pagerduty` (Block List) A contact point that sends notifications to PagerDuty. (see [below for nested schema](#nestedblock--pagerduty)) - `pushover` (Block List) A contact point that sends notifications to Pushover. (see [below for nested schema](#nestedblock--pushover)) @@ -208,6 +209,31 @@ Read-Only: - `uid` (String) The UID of the contact point. + +### Nested Schema for `oncall` + +Required: + +- `url` (String) The URL to send webhook requests to. + +Optional: + +- `authorization_credentials` (String, Sensitive) Allows a custom authorization scheme - attaches an auth header with this value. Do not use in conjunction with basic auth parameters. +- `authorization_scheme` (String) Allows a custom authorization scheme - attaches an auth header with this name. Do not use in conjunction with basic auth parameters. +- `basic_auth_password` (String, Sensitive) The username to use in basic auth headers attached to the request. If omitted, basic auth will not be used. +- `basic_auth_user` (String) The username to use in basic auth headers attached to the request. If omitted, basic auth will not be used. +- `disable_resolve_message` (Boolean) Whether to disable sending resolve messages. Defaults to `false`. +- `http_method` (String) The HTTP method to use in the request. Defaults to `POST`. +- `max_alerts` (Number) The maximum number of alerts to send in a single request. This can be helpful in limiting the size of the request body. The default is 0, which indicates no limit. +- `message` (String) Custom message. You can use template variables. +- `settings` (Map of String, Sensitive) Additional custom properties to attach to the notifier. Defaults to `map[]`. +- `title` (String) Templated title of the message. + +Read-Only: + +- `uid` (String) The UID of the contact point. + + ### Nested Schema for `opsgenie` diff --git a/examples/resources/grafana_contact_point/_acc_receiver_types_10_2.tf b/examples/resources/grafana_contact_point/_acc_receiver_types_10_2.tf new file mode 100644 index 000000000..f7ad7aa63 --- /dev/null +++ b/examples/resources/grafana_contact_point/_acc_receiver_types_10_2.tf @@ -0,0 +1,13 @@ +resource "grafana_contact_point" "receiver_types" { + name = "Receiver Types since v10.2" + + oncall { + url = "http://my-url" + http_method = "POST" + basic_auth_user = "user" + basic_auth_password = "password" + max_alerts = 100 + message = "Custom message" + title = "Custom title" + } +} diff --git a/internal/resources/grafana/resource_alerting_contact_point.go b/internal/resources/grafana/resource_alerting_contact_point.go index 609bfa285..05d82db1e 100644 --- a/internal/resources/grafana/resource_alerting_contact_point.go +++ b/internal/resources/grafana/resource_alerting_contact_point.go @@ -21,6 +21,7 @@ var notifiers = []notifier{ googleChatNotifier{}, kafkaNotifier{}, lineNotifier{}, + oncallNotifier{}, opsGenieNotifier{}, pagerDutyNotifier{}, pushoverNotifier{}, diff --git a/internal/resources/grafana/resource_alerting_contact_point_notifiers.go b/internal/resources/grafana/resource_alerting_contact_point_notifiers.go index c4714b39d..601424d4c 100644 --- a/internal/resources/grafana/resource_alerting_contact_point_notifiers.go +++ b/internal/resources/grafana/resource_alerting_contact_point_notifiers.go @@ -612,6 +612,139 @@ func (o lineNotifier) unpack(raw interface{}, name string) gapi.ContactPoint { } } +type oncallNotifier struct { +} + +var _ notifier = (*oncallNotifier)(nil) + +func (w oncallNotifier) meta() notifierMeta { + return notifierMeta{ + field: "oncall", + typeStr: "oncall", + desc: "A contact point that sends notifications to Grafana On-Call.", + secureFields: []string{"basic_auth_password", "authorization_credentials"}, + } +} + +func (w oncallNotifier) schema() *schema.Resource { + r := commonNotifierResource() + r.Schema["url"] = &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The URL to send webhook requests to.", + } + r.Schema["http_method"] = &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The HTTP method to use in the request. Defaults to `POST`.", + } + r.Schema["basic_auth_user"] = &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The username to use in basic auth headers attached to the request. If omitted, basic auth will not be used.", + } + r.Schema["basic_auth_password"] = &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Sensitive: true, + Description: "The username to use in basic auth headers attached to the request. If omitted, basic auth will not be used.", + } + r.Schema["authorization_scheme"] = &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Allows a custom authorization scheme - attaches an auth header with this name. Do not use in conjunction with basic auth parameters.", + } + r.Schema["authorization_credentials"] = &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Sensitive: true, + Description: "Allows a custom authorization scheme - attaches an auth header with this value. Do not use in conjunction with basic auth parameters.", + } + r.Schema["max_alerts"] = &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "The maximum number of alerts to send in a single request. This can be helpful in limiting the size of the request body. The default is 0, which indicates no limit.", + } + r.Schema["message"] = &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Custom message. You can use template variables.", + } + r.Schema["title"] = &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Templated title of the message.", + } + return r +} + +func (w oncallNotifier) pack(p gapi.ContactPoint, data *schema.ResourceData) (interface{}, error) { + notifier := packCommonNotifierFields(&p) + + packNotifierStringField(&p.Settings, ¬ifier, "url", "url") + packNotifierStringField(&p.Settings, ¬ifier, "httpMethod", "http_method") + packNotifierStringField(&p.Settings, ¬ifier, "username", "basic_auth_user") + packNotifierStringField(&p.Settings, ¬ifier, "password", "basic_auth_password") + packNotifierStringField(&p.Settings, ¬ifier, "authorization_scheme", "authorization_scheme") + packNotifierStringField(&p.Settings, ¬ifier, "authorization_credentials", "authorization_credentials") + packNotifierStringField(&p.Settings, ¬ifier, "message", "message") + packNotifierStringField(&p.Settings, ¬ifier, "title", "title") + if v, ok := p.Settings["maxAlerts"]; ok && v != nil { + switch typ := v.(type) { + case int: + notifier["max_alerts"] = v.(int) + case float64: + notifier["max_alerts"] = int(v.(float64)) + case string: + val, err := strconv.Atoi(typ) + if err != nil { + panic(fmt.Errorf("failed to parse value of 'maxAlerts' to integer: %w", err)) + } + notifier["max_alerts"] = val + default: + panic(fmt.Sprintf("unexpected type %T for 'maxAlerts': %v", typ, typ)) + } + delete(p.Settings, "maxAlerts") + } + + packSecureFields(notifier, getNotifierConfigFromStateWithUID(data, w, p.UID), w.meta().secureFields) + + notifier["settings"] = packSettings(&p) + return notifier, nil +} + +func (w oncallNotifier) unpack(raw interface{}, name string) gapi.ContactPoint { + json := raw.(map[string]interface{}) + uid, disableResolve, settings := unpackCommonNotifierFields(json) + + unpackNotifierStringField(&json, &settings, "url", "url") + unpackNotifierStringField(&json, &settings, "http_method", "httpMethod") + unpackNotifierStringField(&json, &settings, "basic_auth_user", "username") + unpackNotifierStringField(&json, &settings, "basic_auth_password", "password") + unpackNotifierStringField(&json, &settings, "authorization_scheme", "authorization_scheme") + unpackNotifierStringField(&json, &settings, "authorization_credentials", "authorization_credentials") + unpackNotifierStringField(&json, &settings, "message", "message") + unpackNotifierStringField(&json, &settings, "title", "title") + if v, ok := json["max_alerts"]; ok && v != nil { + switch typ := v.(type) { + case int: + settings["maxAlerts"] = v.(int) + case float64: + settings["maxAlerts"] = int(v.(float64)) + default: + panic(fmt.Sprintf("unexpected type for maxAlerts: %v", typ)) + } + } + + return gapi.ContactPoint{ + UID: uid, + Name: name, + Type: w.meta().typeStr, + DisableResolveMessage: disableResolve, + Settings: settings, + } +} + type opsGenieNotifier struct{} var _ notifier = (*opsGenieNotifier)(nil) diff --git a/internal/resources/grafana/resource_alerting_contact_point_test.go b/internal/resources/grafana/resource_alerting_contact_point_test.go index e9fc264f4..715fe0dc0 100644 --- a/internal/resources/grafana/resource_alerting_contact_point_test.go +++ b/internal/resources/grafana/resource_alerting_contact_point_test.go @@ -340,6 +340,37 @@ func TestAccContactPoint_notifiers(t *testing.T) { }) } +func TestAccContactPoint_notifiers10_2(t *testing.T) { + testutils.CheckOSSTestsEnabled(t) + testutils.CheckOSSTestsSemver(t, ">=10.2.0") + + var points []gapi.ContactPoint + + resource.ParallelTest(t, resource.TestCase{ + ProviderFactories: testutils.ProviderFactories, + // Implicitly tests deletion. + CheckDestroy: testContactPointCheckDestroy(points), + Steps: []resource.TestStep{ + // Test creation. + { + Config: testutils.TestAccExample(t, "resources/grafana_contact_point/_acc_receiver_types_10_2.tf"), + Check: resource.ComposeTestCheckFunc( + testContactPointCheckExists("grafana_contact_point.receiver_types", &points, 1), + // oncall + resource.TestCheckResourceAttr("grafana_contact_point.receiver_types", "oncall.#", "1"), + resource.TestCheckResourceAttr("grafana_contact_point.receiver_types", "oncall.0.url", "http://my-url"), + resource.TestCheckResourceAttr("grafana_contact_point.receiver_types", "oncall.0.http_method", "POST"), + resource.TestCheckResourceAttr("grafana_contact_point.receiver_types", "oncall.0.basic_auth_user", "user"), + resource.TestCheckResourceAttr("grafana_contact_point.receiver_types", "oncall.0.basic_auth_password", "password"), + resource.TestCheckResourceAttr("grafana_contact_point.receiver_types", "oncall.0.max_alerts", "100"), + resource.TestCheckResourceAttr("grafana_contact_point.receiver_types", "oncall.0.message", "Custom message"), + resource.TestCheckResourceAttr("grafana_contact_point.receiver_types", "oncall.0.title", "Custom title"), + ), + }, + }, + }) +} + func TestAccContactPoint_empty(t *testing.T) { testutils.CheckOSSTestsEnabled(t, ">=9.1.0") From 35a6914d8d1315352e6e49aec94bd2a56f514af5 Mon Sep 17 00:00:00 2001 From: Julien Duchesne Date: Wed, 1 Nov 2023 13:39:35 -0400 Subject: [PATCH 2/2] Fix test util --- .../resources/grafana/resource_alerting_contact_point_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/resources/grafana/resource_alerting_contact_point_test.go b/internal/resources/grafana/resource_alerting_contact_point_test.go index 715fe0dc0..76c6a90b2 100644 --- a/internal/resources/grafana/resource_alerting_contact_point_test.go +++ b/internal/resources/grafana/resource_alerting_contact_point_test.go @@ -341,8 +341,7 @@ func TestAccContactPoint_notifiers(t *testing.T) { } func TestAccContactPoint_notifiers10_2(t *testing.T) { - testutils.CheckOSSTestsEnabled(t) - testutils.CheckOSSTestsSemver(t, ">=10.2.0") + testutils.CheckOSSTestsEnabled(t, ">=10.2.0") var points []gapi.ContactPoint