From 1b27c646880d2a30ec639727ee2e3b4ed0785c29 Mon Sep 17 00:00:00 2001 From: Marko Simon Date: Thu, 22 Aug 2024 12:53:44 +0200 Subject: [PATCH 01/16] add slack webhook type for alert action --- ilert/resource_alert_action.go | 32 ++++++++++++++++++++++++++++++++ ilert/resource_connector.go | 2 +- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/ilert/resource_alert_action.go b/ilert/resource_alert_action.go index f6e4f16..74c73ec 100644 --- a/ilert/resource_alert_action.go +++ b/ilert/resource_alert_action.go @@ -480,6 +480,22 @@ func resourceAlertAction() *schema.Resource { }, }, }, + "slack_webhook": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + MinItems: 1, + ForceNew: true, + ConflictsWith: removeStringsFromSlice(alertActionTypesAll, ilert.ConnectorTypes.SlackWebhook), + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, "created_at": { Type: schema.TypeString, Computed: true, @@ -843,6 +859,16 @@ func buildAlertAction(d *schema.ResourceData) (*ilert.AlertAction, error) { } } + if val, ok := d.GetOk("slack_webhook"); ok { + vL := val.([]interface{}) + if len(vL) > 0 { + v := vL[0].(map[string]interface{}) + alertAction.Params = &ilert.AlertActionParamsSlackWebhook{ + URL: v["url"].(string), + } + } + } + if val, ok := d.GetOk("alert_filter"); ok { vL := val.([]interface{}) if len(vL) > 0 { @@ -1130,6 +1156,12 @@ func resourceAlertActionRead(ctx context.Context, d *schema.ResourceData, m inte "url": result.AlertAction.Params.URL, }, }) + case ilert.ConnectorTypes.SlackWebhook: + d.Set("slack_webhook", []interface{}{ + map[string]interface{}{ + "url": result.AlertAction.Params.URL, + }, + }) } alertFilter, err := flattenAlertActionAlertFilter(result.AlertAction.AlertFilter) diff --git a/ilert/resource_connector.go b/ilert/resource_connector.go index 5a04cbb..9637704 100644 --- a/ilert/resource_connector.go +++ b/ilert/resource_connector.go @@ -15,7 +15,7 @@ import ( func resourceConnector() *schema.Resource { // remove types with no or one specific standalone connector - connectorTypesAll := removeStringsFromSlice(ilert.ConnectorTypesAll, ilert.ConnectorTypes.Email, ilert.ConnectorTypes.MicrosoftTeamsBot, ilert.ConnectorTypes.Slack, ilert.ConnectorTypes.Webhook, ilert.ConnectorTypes.AutomationRule, ilert.ConnectorTypes.Telegram, ilert.ConnectorTypes.DingTalkAction, ilert.ConnectorTypes.MicrosoftTeamsWebhook) + connectorTypesAll := removeStringsFromSlice(ilert.ConnectorTypesAll, ilert.ConnectorTypes.Email, ilert.ConnectorTypes.MicrosoftTeamsBot, ilert.ConnectorTypes.Slack, ilert.ConnectorTypes.Webhook, ilert.ConnectorTypes.AutomationRule, ilert.ConnectorTypes.Telegram, ilert.ConnectorTypes.DingTalkAction, ilert.ConnectorTypes.MicrosoftTeamsWebhook, ilert.ConnectorTypes.SlackWebhook) return &schema.Resource{ Schema: map[string]*schema.Schema{ "name": { From 7cda1f30159f7a62263896ab1b0388960fc6bd55 Mon Sep 17 00:00:00 2001 From: Marko Simon Date: Thu, 22 Aug 2024 12:54:06 +0200 Subject: [PATCH 02/16] add metrics to status page resource --- go.mod | 2 ++ ilert/resource_status_page.go | 64 +++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/go.mod b/go.mod index a0f9186..ce7f037 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,8 @@ module github.com/iLert/terraform-provider-ilert go 1.19 +replace github.com/iLert/ilert-go/v3 => /Users/markosimon/Documents/workspace/ilert-go + require ( github.com/hashicorp/terraform-plugin-sdk/v2 v2.25.0 github.com/iLert/ilert-go/v3 v3.8.3 diff --git a/ilert/resource_status_page.go b/ilert/resource_status_page.go index 4587fe9..46f8303 100644 --- a/ilert/resource_status_page.go +++ b/ilert/resource_status_page.go @@ -209,6 +209,24 @@ func resourceStatusPage() *schema.Resource { ValidateFunc: validation.StringInSlice(ilert.StatusPageAppearanceAll, false), ConflictsWith: []string{"theme_mode"}, }, + "metric": { + Type: schema.TypeList, + Optional: true, + MinItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeInt, + Required: true, + }, + "name": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 255), + }, + }, + }, + }, }, CreateContext: resourceStatusPageCreate, ReadContext: resourceStatusPageRead, @@ -414,6 +432,22 @@ func buildStatusPage(d *schema.ResourceData) (*ilert.StatusPage, error) { statusPage.Appearance = val.(string) } + if val, ok := d.GetOk("metric"); ok { + vL := val.([]interface{}) + mts := make([]ilert.Metric, 0) + for _, m := range vL { + v := m.(map[string]interface{}) + mt := ilert.Metric{ + ID: int64(v["id"].(int)), + } + if v["name"] != nil && v["name"].(string) != "" { + mt.Name = v["name"].(string) + } + mts = append(mts, mt) + } + statusPage.Metrics = mts + } + return statusPage, nil } @@ -558,6 +592,14 @@ func resourceStatusPageRead(ctx context.Context, d *schema.ResourceData, m inter d.Set("appearance", result.StatusPage.Appearance) } + metrics, err := flattenMetricsList(result.StatusPage.Metrics, d) + if err != nil { + return diag.FromErr(err) + } + if err := d.Set("metric", metrics); err != nil { + return diag.Errorf("error setting metrics: %s", err) + } + return nil } @@ -684,6 +726,28 @@ func flattenServicesList(list []ilert.Service, d *schema.ResourceData) ([]interf return results, nil } +func flattenMetricsList(list []ilert.Metric, d *schema.ResourceData) ([]interface{}, error) { + if list == nil { + return make([]interface{}, 0), nil + } + results := make([]interface{}, 0) + if val, ok := d.GetOk("metric"); ok && val != nil { + vL := val.([]interface{}) + for i, item := range list { + if vL != nil && i < len(vL) && vL[i] != nil { + result := make(map[string]interface{}) + v := vL[i].(map[string]interface{}) + result["id"] = item.ID + if item.Name != "" && v["name"] != nil && v["name"].(string) != "" { + result["name"] = item.Name + } + results = append(results, result) + } + } + } + return results, nil +} + func flattenStatusPageStructure(structure *ilert.StatusPageStructure) ([]interface{}, error) { if structure == nil { return make([]interface{}, 0), nil From 8412a190f9e0b2940797b03a05099fcf0e93f7c5 Mon Sep 17 00:00:00 2001 From: Marko Simon Date: Thu, 22 Aug 2024 13:02:14 +0200 Subject: [PATCH 03/16] fix provider crash when metric is created without metadata or data source --- ilert/resource_metric.go | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/ilert/resource_metric.go b/ilert/resource_metric.go index c9e77a4..a37df56 100644 --- a/ilert/resource_metric.go +++ b/ilert/resource_metric.go @@ -301,12 +301,18 @@ func resourceMetricRead(ctx context.Context, d *schema.ResourceData, m interface } d.Set("unit_label", result.Metric.UnitLabel) - d.Set("metadata", []interface{}{map[string]interface{}{ - "query": result.Metric.Metadata.Query, - }}) - d.Set("data_source", []interface{}{map[string]interface{}{ - "id": int(result.Metric.DataSource.ID), - }}) + + if result.Metric.Metadata != nil { + d.Set("metadata", []interface{}{map[string]interface{}{ + "query": result.Metric.Metadata.Query, + }}) + } + + if result.Metric.DataSource != nil { + d.Set("data_source", []interface{}{map[string]interface{}{ + "id": int(result.Metric.DataSource.ID), + }}) + } return nil } From 7d294fb46e13aa2af29e2d0318b53b95d284b56d Mon Sep 17 00:00:00 2001 From: Marko Simon Date: Thu, 22 Aug 2024 13:10:51 +0200 Subject: [PATCH 04/16] update docs --- website/docs/r/alert_action.html.markdown | 7 +++++-- website/docs/r/connector.html.markdown | 2 +- website/docs/r/status_page.html.markdown | 6 ++++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/website/docs/r/alert_action.html.markdown b/website/docs/r/alert_action.html.markdown index dcaf840..5563761 100644 --- a/website/docs/r/alert_action.html.markdown +++ b/website/docs/r/alert_action.html.markdown @@ -87,6 +87,7 @@ The following arguments are supported: - `telegram` - (Optional) An [telegram](#telegram-arguments) block. - `microsoft_teams_bot` - (Optional) A [microsoft_teams_bot](#microsoft-teams-bot-arguments) block. - `microsoft_teams_webhook` - (Optional) A [microsoft_teams_webhook](#microsoft-teams-webhook-arguments) block. +- `slack_webhook` - (Optional) A [slack_webhook](#slack-webhook-arguments) block. - `alert_filter` - (Optional) An [alert_filter](#alert-filter-arguments) block. - `team` - (Optional) One or more [team](#team-arguments) blocks. @@ -219,7 +220,9 @@ The following arguments are supported: #### Microsoft teams webhook Arguments -> See [the Microsoft teams bot integration documentation](https://docs.ilert.com/chatops/microsoft-teams/chat/workflows) for more details. +- `url` - (Required) The workflow URL for the channel. + +#### Slack webhook Arguments - `url` - (Required) The workflow URL for the channel. @@ -250,7 +253,7 @@ The following attributes are exported: ## Import -Services can be imported using the `id`, e.g. +Alert actions can be imported using the `id`, e.g. ```sh $ terraform import ilert_alert_action.main 123456789 diff --git a/website/docs/r/connector.html.markdown b/website/docs/r/connector.html.markdown index e1aeadb..cadf3c3 100644 --- a/website/docs/r/connector.html.markdown +++ b/website/docs/r/connector.html.markdown @@ -131,7 +131,7 @@ The following attributes are exported: ## Import -Services can be imported using the `id`, e.g. +Connectors can be imported using the `id`, e.g. ```sh $ terraform import ilert_connector.main 123456789 diff --git a/website/docs/r/status_page.html.markdown b/website/docs/r/status_page.html.markdown index b8be2f4..ab1b093 100644 --- a/website/docs/r/status_page.html.markdown +++ b/website/docs/r/status_page.html.markdown @@ -66,6 +66,7 @@ The following arguments are supported: - `account_wide_view` - (Optional) Indicates whether or not the status page should be shown account wide. - `structure` - (Optional) A [structure](#structure-arguments) block. - `appearance` - (Optional) The appearance of the status page. Allowed values are `LIGHT` and `DARK`. +- `metric` - (Required) One or more [metric](#metric-arguments) blocks. #### Service Arguments @@ -94,6 +95,11 @@ The following arguments are supported: - `type` - (Required) The type of the child. Allowed values are `SERVICE`. - `options` - (Optional) One or more options to provide for the child. Allowed values are `no-graph`. +#### Metric Arguments + +- `id` - (Required) The ID of the metric. +- `name` - (Optional) The name of the metric. + ## Attributes Reference The following attributes are exported: From 574f83cafc03854d5f042cb5efe2b2178bb4ea0c Mon Sep 17 00:00:00 2001 From: Marko Simon Date: Thu, 22 Aug 2024 13:25:08 +0200 Subject: [PATCH 05/16] add email whitelist and announcement to status page resource --- ilert/resource_status_page.go | 57 +++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/ilert/resource_status_page.go b/ilert/resource_status_page.go index 46f8303..ae6fff0 100644 --- a/ilert/resource_status_page.go +++ b/ilert/resource_status_page.go @@ -209,6 +209,25 @@ func resourceStatusPage() *schema.Resource { ValidateFunc: validation.StringInSlice(ilert.StatusPageAppearanceAll, false), ConflictsWith: []string{"theme_mode"}, }, + "email_whitelist": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "announcement": { + Type: schema.TypeString, + Optional: true, + }, + "announcement_on_page": { + Type: schema.TypeBool, + Optional: true, + }, + "announcement_in_widget": { + Type: schema.TypeBool, + Optional: true, + }, "metric": { Type: schema.TypeList, Optional: true, @@ -432,6 +451,28 @@ func buildStatusPage(d *schema.ResourceData) (*ilert.StatusPage, error) { statusPage.Appearance = val.(string) } + if val, ok := d.GetOk("email_whitelist"); ok { + vL := val.([]interface{}) + sL := make([]string, 0) + for _, m := range vL { + v := m.(string) + sL = append(sL, v) + } + statusPage.EmailWhitelist = sL + } + + if val, ok := d.GetOk("announcement"); ok { + statusPage.Announcement = val.(string) + } + + if val, ok := d.GetOk("announcement_on_page"); ok { + statusPage.AnnouncementOnPage = val.(bool) + } + + if val, ok := d.GetOk("announcement_in_widget"); ok { + statusPage.AnnouncementInWidget = val.(bool) + } + if val, ok := d.GetOk("metric"); ok { vL := val.([]interface{}) mts := make([]ilert.Metric, 0) @@ -592,6 +633,22 @@ func resourceStatusPageRead(ctx context.Context, d *schema.ResourceData, m inter d.Set("appearance", result.StatusPage.Appearance) } + if val, ok := d.GetOk("email_whitelist"); ok && val.([]interface{}) != nil && len(val.([]interface{})) > 0 { + d.Set("email_whitelist", result.StatusPage.EmailWhitelist) + } + + if _, ok := d.GetOk("announcement"); ok { + d.Set("announcement", result.StatusPage.Announcement) + } + + if _, ok := d.GetOk("announcement_on_page"); ok { + d.Set("announcement_on_page", result.StatusPage.AnnouncementOnPage) + } + + if _, ok := d.GetOk("announcement_in_widget"); ok { + d.Set("announcement_in_widget", result.StatusPage.AnnouncementInWidget) + } + metrics, err := flattenMetricsList(result.StatusPage.Metrics, d) if err != nil { return diag.FromErr(err) From c7acb84df9b558c0accbbafa1cf6229e45c0ceb7 Mon Sep 17 00:00:00 2001 From: Marko Simon Date: Thu, 22 Aug 2024 13:25:14 +0200 Subject: [PATCH 06/16] update docs for status page --- website/docs/r/status_page.html.markdown | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/website/docs/r/status_page.html.markdown b/website/docs/r/status_page.html.markdown index ab1b093..70bab4a 100644 --- a/website/docs/r/status_page.html.markdown +++ b/website/docs/r/status_page.html.markdown @@ -66,6 +66,10 @@ The following arguments are supported: - `account_wide_view` - (Optional) Indicates whether or not the status page should be shown account wide. - `structure` - (Optional) A [structure](#structure-arguments) block. - `appearance` - (Optional) The appearance of the status page. Allowed values are `LIGHT` and `DARK`. +- `email_whitelist` - (Optional) One or more emails to whitelist. Enables login via email only. +- `announcement` - (Optional) Sets the text for an announcement shown at the top of the status page and/or in a widget. +- `announcement_on_page`- (Optional) Indicates whether the announcement is show at the top of the status page or not. +- `announcement_in_widget`- (Optional) Indicates whether the announcement is also shown in the status widget. - `metric` - (Required) One or more [metric](#metric-arguments) blocks. #### Service Arguments From d70eaf6e9adf0d62612f24dc473885444a2e7c60 Mon Sep 17 00:00:00 2001 From: Marko Simon Date: Thu, 22 Aug 2024 14:34:53 +0200 Subject: [PATCH 07/16] add check for private status page on email whitelist --- ilert/resource_status_page.go | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/ilert/resource_status_page.go b/ilert/resource_status_page.go index ae6fff0..27d7dad 100644 --- a/ilert/resource_status_page.go +++ b/ilert/resource_status_page.go @@ -452,13 +452,17 @@ func buildStatusPage(d *schema.ResourceData) (*ilert.StatusPage, error) { } if val, ok := d.GetOk("email_whitelist"); ok { - vL := val.([]interface{}) - sL := make([]string, 0) - for _, m := range vL { - v := m.(string) - sL = append(sL, v) + if statusPage.Visibility == ilert.StatusPageVisibility.Private { + vL := val.([]interface{}) + sL := make([]string, 0) + for _, m := range vL { + v := m.(string) + sL = append(sL, v) + } + statusPage.EmailWhitelist = sL + } else { + return nil, fmt.Errorf("[ERROR] Can't set email whitelist, as it is only allowed on private status pages") } - statusPage.EmailWhitelist = sL } if val, ok := d.GetOk("announcement"); ok { From a950758c4c350545ad056c55a9a616e20080c707 Mon Sep 17 00:00:00 2001 From: Marko Simon Date: Thu, 22 Aug 2024 14:38:56 +0200 Subject: [PATCH 08/16] add intelligent grouping to alert source alert creation types and related fields --- ilert/resource_alert_source.go | 36 +++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/ilert/resource_alert_source.go b/ilert/resource_alert_source.go index 10a7c8d..30adce4 100644 --- a/ilert/resource_alert_source.go +++ b/ilert/resource_alert_source.go @@ -562,6 +562,14 @@ func resourceAlertSource() *schema.Resource { Optional: true, ValidateFunc: validation.StringInSlice(ilert.AlertSourceAlertGroupingWindowsAll, false), }, + "score_threshold": { + Type: schema.TypeFloat, + Optional: true, + }, + "event_filter": { + Type: schema.TypeString, + Optional: true, + }, }, CreateContext: resourceAlertSourceCreate, ReadContext: resourceAlertSourceRead, @@ -610,8 +618,8 @@ func buildAlertSource(d *schema.ResourceData) (*ilert.AlertSource, error) { } if val, ok := d.GetOk("alert_creation"); ok { alertCreation := val.(string) - if _, ok := d.GetOk("alert_grouping_window"); !ok && alertCreation == ilert.AlertSourceAlertCreations.OneAlertGroupedPerWindow { - return nil, fmt.Errorf("[ERROR] Can't set alert creation type 'ONE_ALERT_GROUPED_PER_WINDOW' when alert grouping window is not set") + if _, ok := d.GetOk("alert_grouping_window"); !ok && (alertCreation == ilert.AlertSourceAlertCreations.OneAlertGroupedPerWindow || alertCreation == ilert.AlertSourceAlertCreations.IntelligentGrouping) { + return nil, fmt.Errorf("[ERROR] Can't set alert creation type 'ONE_ALERT_GROUPED_PER_WINDOW' or 'INTELLIGENT_GROUPING' when alert grouping window is not set") } alertSource.AlertCreation = alertCreation } @@ -901,13 +909,21 @@ func buildAlertSource(d *schema.ResourceData) (*ilert.AlertSource, error) { } } if val, ok := d.GetOk("alert_grouping_window"); ok { - if alert_creation, ok := d.GetOk("alert_creation"); !ok || alert_creation.(string) != ilert.AlertSourceAlertCreations.OneAlertGroupedPerWindow { - return nil, fmt.Errorf("[ERROR] Can't set alert grouping window when alert creation is not set or not of type 'ONE_ALERT_GROUPED_PER_WINDOW'") + if alert_creation, ok := d.GetOk("alert_creation"); !ok || (alert_creation.(string) != ilert.AlertSourceAlertCreations.OneAlertGroupedPerWindow && alert_creation.(string) != ilert.AlertSourceAlertCreations.IntelligentGrouping) { + return nil, fmt.Errorf("[ERROR] Can't set alert grouping window when alert creation is not set or not of type 'ONE_ALERT_GROUPED_PER_WINDOW' or 'INTELLIGENT_GROUPING'") } alertGroupingWindow := val.(string) alertSource.AlertGroupingWindow = alertGroupingWindow } + if val, ok := d.GetOk("score_threshold"); ok { + alertSource.ScoreThreshold = val.(float64) + } + + if val, ok := d.GetOk("event_filter"); ok { + alertSource.EventFilter = val.(string) + } + return alertSource, nil } @@ -923,7 +939,9 @@ func resourceAlertSourceCreate(ctx context.Context, d *schema.ResourceData, m in log.Printf("[DEBUG] Creating ilert alert source %s\n", alertSource.Name) result := &ilert.CreateAlertSourceOutput{} err = resource.RetryContext(ctx, d.Timeout(schema.TimeoutCreate), func() *resource.RetryError { - r, err := client.CreateAlertSource(&ilert.CreateAlertSourceInput{AlertSource: alertSource}) + includes := make([]*string, 0) + includes = append(includes, ilert.String("summaryTemplate"), ilert.String("detailsTemplate"), ilert.String("routingTemplate"), ilert.String("textTemplate"), ilert.String("linkTemplates"), ilert.String("priorityTemplate"), ilert.String("eventFilter")) + r, err := client.CreateAlertSource(&ilert.CreateAlertSourceInput{AlertSource: alertSource, Include: includes}) if err != nil { if _, ok := err.(*ilert.RetryableAPIError); ok { log.Printf("[ERROR] Creating ilert alert source error '%s', so retry again", err.Error()) @@ -958,7 +976,7 @@ func resourceAlertSourceRead(ctx context.Context, d *schema.ResourceData, m inte result := &ilert.GetAlertSourceOutput{} err = resource.RetryContext(ctx, d.Timeout(schema.TimeoutRead), func() *resource.RetryError { includes := make([]*string, 0) - includes = append(includes, ilert.String("summaryTemplate"), ilert.String("detailsTemplate"), ilert.String("routingTemplate"), ilert.String("textTemplate"), ilert.String("linkTemplates"), ilert.String("priorityTemplate")) + includes = append(includes, ilert.String("summaryTemplate"), ilert.String("detailsTemplate"), ilert.String("routingTemplate"), ilert.String("textTemplate"), ilert.String("linkTemplates"), ilert.String("priorityTemplate"), ilert.String("eventFilter")) r, err := client.GetAlertSource(&ilert.GetAlertSourceInput{AlertSourceID: ilert.Int64(alertSourceID), Include: includes}) if err != nil { if _, ok := err.(*ilert.NotFoundAPIError); ok { @@ -1006,6 +1024,8 @@ func resourceAlertSourceRead(ctx context.Context, d *schema.ResourceData, m inte d.Set("email", result.AlertSource.IntegrationKey) } d.Set("alert_grouping_window", result.AlertSource.AlertGroupingWindow) + d.Set("score_threshold", result.AlertSource.ScoreThreshold) + d.Set("event_filter", result.AlertSource.EventFilter) if result.AlertSource.Heartbeat != nil { d.Set("heartbeat", []interface{}{ @@ -1173,7 +1193,9 @@ func resourceAlertSourceUpdate(ctx context.Context, d *schema.ResourceData, m in } log.Printf("[DEBUG] Updating alert source: %s", d.Id()) err = resource.RetryContext(ctx, d.Timeout(schema.TimeoutUpdate), func() *resource.RetryError { - _, err = client.UpdateAlertSource(&ilert.UpdateAlertSourceInput{AlertSource: alertSource, AlertSourceID: ilert.Int64(alertSourceID)}) + includes := make([]*string, 0) + includes = append(includes, ilert.String("summaryTemplate"), ilert.String("detailsTemplate"), ilert.String("routingTemplate"), ilert.String("textTemplate"), ilert.String("linkTemplates"), ilert.String("priorityTemplate"), ilert.String("eventFilter")) + _, err = client.UpdateAlertSource(&ilert.UpdateAlertSourceInput{AlertSource: alertSource, AlertSourceID: ilert.Int64(alertSourceID), Include: includes}) if err != nil { if _, ok := err.(*ilert.RetryableAPIError); ok { time.Sleep(2 * time.Second) From bdfec1ca6dc165d6660299ba23d03b85ea7f2059 Mon Sep 17 00:00:00 2001 From: Marko Simon Date: Thu, 22 Aug 2024 14:39:04 +0200 Subject: [PATCH 09/16] update docs for alert source --- website/docs/r/alert_source.html.markdown | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/website/docs/r/alert_source.html.markdown b/website/docs/r/alert_source.html.markdown index 175bdc6..d47d10f 100644 --- a/website/docs/r/alert_source.html.markdown +++ b/website/docs/r/alert_source.html.markdown @@ -42,7 +42,7 @@ The following arguments are supported: - `name` - (Required) The name of the alert source. - `integration_type` - (Required) The integration type of the alert source. Allowed values are `NAGIOS`, `ICINGA`, `EMAIL`, `SMS`, `API`, `CRN`, `HEARTBEAT`, `PRTG`, `PINGDOM`, `CLOUDWATCH`, `AWSPHD`, `STACKDRIVER`, `INSTANA`, `ZABBIX`, `SOLARWINDS`, `PROMETHEUS`, `NEWRELIC`, `GRAFANA`, `GITHUB`, `DATADOG`, `UPTIMEROBOT`, `APPDYNAMICS`, `DYNATRACE`, `TOPDESK`, `STATUSCAKE`, `MONITOR`, `TOOL`, `CHECKMK`, `AUTOTASK`, `AWSBUDGET`, `KENTIXAM`, `JIRA`, `CONSUL`, `ZAMMAD`, `SIGNALFX`, `SPLUNK`, `KUBERNETES`, `SEMATEXT`, `SENTRY`, `SUMOLOGIC`, `RAYGUN`, `MXTOOLBOX`, `ESWATCHER`, `AMAZONSNS`, `KAPACITOR`, `CORTEXXSOAR`, `SYSDIG`, `SERVERDENSITY`, `ZAPIER`, `SERVICENOW`, `SEARCHGUARD`, `AZUREALERTS`, `TERRAFORMCLOUD`, `ZENDESK`, `AUVIK`, `SENSU`, `NCENTRAL`, `JUMPCLOUD`, `SALESFORCE`, `GUARDDUTY`, `STATUSHUB`, `IXON`, `APIFORTRESS`, `FRESHSERVICE`, `APPSIGNAL`, `LIGHTSTEP`, `IBMCLOUDFUNCTIONS`, `CROWDSTRIKE`, `HUMIO`, `OHDEAR`, `MONGODBATLAS`, `GITLAB`. - `escalation_policy` - (Required) The escalation policy id used by this alert source. -- `alert_creation` - (Optional) ilert receives events from your monitoring systems and can then create alerts in different ways. This option is recommended. Allowed values are `ONE_ALERT_PER_EMAIL`, `ONE_ALERT_PER_EMAIL_SUBJECT`, `ONE_PENDING_ALERT_ALLOWED`, `ONE_OPEN_ALERT_ALLOWED`, `OPEN_RESOLVE_ON_EXTRACTION`, `ONE_ALERT_GROUPED_PER_WINDOW`. `alert_grouping_window` must be defined when this field is set to `ONE_ALERT_GROUPED_PER_WINDOW`. +- `alert_creation` - (Optional) ilert receives events from your monitoring systems and can then create alerts in different ways. This option is recommended. Allowed values are `ONE_ALERT_PER_EMAIL`, `ONE_ALERT_PER_EMAIL_SUBJECT`, `ONE_PENDING_ALERT_ALLOWED`, `ONE_OPEN_ALERT_ALLOWED`, `OPEN_RESOLVE_ON_EXTRACTION`, `ONE_ALERT_GROUPED_PER_WINDOW`, `INTELLIGENT_GROUPING`. `alert_grouping_window` must be defined when this field is set to `ONE_ALERT_GROUPED_PER_WINDOW` or `INTELLIGENT_GROUPING`. - `active` - (Optional) The state of the alert source. Default: `true`. - `alert_priority_rule` - (Optional) The alert priority rule. This option is recommended. Allowed values are `HIGH`, `LOW`, `HIGH_DURING_SUPPORT_HOURS`, `LOW_DURING_SUPPORT_HOURS`. - `auto_resolution_timeout` - (Optional) The auto resolution timeout. Allowed values are `PT10M`, `PT20M`, `PT30M`, `PT40M`, `PT50M`, `PT60M`, `PT90M`, `PT2H`, `PT3H`, `PT4H`, `PT5H`, `PT6H`, `PT12H`, `PT24H` (`H` means hour and `M` means minute). @@ -62,7 +62,9 @@ The following arguments are supported: - `routing_template` - (Optional) A routing [template](#template-arguments) block. - `link_template` - (Optional) One or more [link template](#link-template-arguments) block. - `priority_template` - (Optional) A [priority template](#priority-template-arguments) block. -- `alert_grouping_window` - (Optional) The alert grouping time frame. Any alerts triggered within this time frame will be grouped together. This field has to be defined when `alert_creation` is set to `ONE_ALERT_GROUPED_PER_WINDOW`. +- `alert_grouping_window` - (Optional) The alert grouping time frame. Any alerts triggered within this time frame will be grouped together. This field has to be defined when `alert_creation` is set to `ONE_ALERT_GROUPED_PER_WINDOW` or `INTELLIGENT_GROUPING`. +- `score_threshold` - (Optional) Sets the score threshold. Indicates how similar alerts are to be grouped together. This field has to be defined when `alert_creation` is set to `INTELLIGENT_GROUPING`. Should be a floating point number between `0` and `1` (inclusive). +- `event_filter` - (Optional) Defines event filter condition in ICL language. This is a code based implementation, more info on syntax: https://docs.ilert.com/rest-api/icl-ilert-condition-language. For block based configuration please use the web UI. #### Heartbeat Arguments From 2d26d2952a72d5cb0626e1f5cef034796817d121 Mon Sep 17 00:00:00 2001 From: Marko Simon Date: Thu, 22 Aug 2024 14:42:18 +0200 Subject: [PATCH 10/16] update docs to add new trigger type for alert action --- website/docs/r/alert_action.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/alert_action.html.markdown b/website/docs/r/alert_action.html.markdown index 5563761..3d975cf 100644 --- a/website/docs/r/alert_action.html.markdown +++ b/website/docs/r/alert_action.html.markdown @@ -70,7 +70,7 @@ The following arguments are supported: - `connector` - (Required) A [connector](#connector-arguments) block. - `trigger_mode` - (Optional) The trigger mode of the alert action. Allowed values are `AUTOMATIC` or `MANUAL`. Default: `AUTOMATIC`. - `delay_sec` - (Optional) The number of seconds the alert action will be delayed when reaching end of escalation. Can only be set when one of `trigger_types` is set to `alert-escalation-ended`. Must be either `0` or a value between `30` and `7200`. -- `trigger_types` - (Optional if the `MANUAL` trigger mode and required if the `AUTOMATIC` trigger mode) A list of the trigger types. Allowed values are `alert-created`, `alert-assigned`, `alert-auto-escalated`, `alert-acknowledged`, `alert-raised`, `alert-comment-added`, `alert-escalation-ended`, `alert-resolved`, `alert-auto-resolved`, `alert-responder-added`, `alert-responder-removed`, `alert-channel-attached`, `alert-channel-detached`. +- `trigger_types` - (Optional if the `MANUAL` trigger mode and required if the `AUTOMATIC` trigger mode) A list of the trigger types. Allowed values are `alert-created`, `alert-assigned`, `alert-auto-escalated`, `alert-acknowledged`, `alert-raised`, `alert-comment-added`, `alert-escalation-ended`, `alert-resolved`, `alert-auto-resolved`, `alert-responder-added`, `alert-responder-removed`, `alert-channel-attached`, `alert-channel-detached`, `v-alert-not-resolved`. - `jira` - (Optional) A [jira](#jira-arguments) block. - `servicenow` - (Optional) A [servicenow](#servicenow-arguments) block. - `slack` - (Optional) A [slack](#slack-arguments) block. From 630e22c53762be331fb6925304be27fa7fee467b Mon Sep 17 00:00:00 2001 From: Marko Simon Date: Thu, 22 Aug 2024 14:56:20 +0200 Subject: [PATCH 11/16] deprecate delaySec in favor of more specific fields in alert action resource --- ilert/resource_alert_action.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/ilert/resource_alert_action.go b/ilert/resource_alert_action.go index 74c73ec..730dd43 100644 --- a/ilert/resource_alert_action.go +++ b/ilert/resource_alert_action.go @@ -561,6 +561,15 @@ func resourceAlertAction() *schema.Resource { }, }, "delay_sec": { + Type: schema.TypeInt, + Optional: true, + Deprecated: "The field delay_sec is deprecated! Please use escalation_ended_delay_sec instead for trigger_type 'alert_escalation_ended' or not_resolved_delay_sec for trigger_type 'alert_not_resolved'.", + }, + "escalation_ended_delay_sec": { + Type: schema.TypeInt, + Optional: true, + }, + "not_resolved_delay_sec": { Type: schema.TypeInt, Optional: true, }, @@ -916,6 +925,22 @@ func buildAlertAction(d *schema.ResourceData) (*ilert.AlertAction, error) { alertAction.DelaySec = val.(int) } + if val, ok := d.GetOk("escalation_ended_delay_sec"); ok { + escalationEndedDelaySec := val.(int) + if escalationEndedDelaySec != 0 && (escalationEndedDelaySec < 30 || escalationEndedDelaySec > 7200) { + return nil, fmt.Errorf("[ERROR] Can't set 'escalation_ended_delay_sec', value must be either 0 or between 30 and 7200") + } + alertAction.EscalationEndedDelaySec = val.(int) + } + + if val, ok := d.GetOk("not_resolved_delay_sec"); ok { + notResolvedDelaySec := val.(int) + if notResolvedDelaySec != 0 && (notResolvedDelaySec < 60 || notResolvedDelaySec > 7200) { + return nil, fmt.Errorf("[ERROR] Can't set 'not_resolved_delay_sec', value must be either 0 or between 60 and 7200") + } + alertAction.NotResolvedDelaySec = val.(int) + } + return alertAction, nil } @@ -1199,6 +1224,8 @@ func resourceAlertActionRead(ctx context.Context, d *schema.ResourceData, m inte } d.Set("delay_sec", result.AlertAction.DelaySec) + d.Set("escalation_ended_delay_sec", result.AlertAction.EscalationEndedDelaySec) + d.Set("not_resolved_delay_sec", result.AlertAction.NotResolvedDelaySec) if val, ok := d.GetOk("alert_source"); ok && len(val.([]interface{})) == 1 { if v, ok := d.GetOk("team"); !ok || len(v.([]interface{})) == 0 { From 6f736fa6fa3a0855d34b4579bad93457e72d08fc Mon Sep 17 00:00:00 2001 From: Marko Simon Date: Thu, 22 Aug 2024 14:56:32 +0200 Subject: [PATCH 12/16] update delaySec related fields in docs --- website/docs/r/alert_action.html.markdown | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/website/docs/r/alert_action.html.markdown b/website/docs/r/alert_action.html.markdown index 3d975cf..6bd170f 100644 --- a/website/docs/r/alert_action.html.markdown +++ b/website/docs/r/alert_action.html.markdown @@ -69,7 +69,8 @@ The following arguments are supported: - `alert_source` - (Required) One or more [alert source](#alert-source-arguments) blocks. - `connector` - (Required) A [connector](#connector-arguments) block. - `trigger_mode` - (Optional) The trigger mode of the alert action. Allowed values are `AUTOMATIC` or `MANUAL`. Default: `AUTOMATIC`. -- `delay_sec` - (Optional) The number of seconds the alert action will be delayed when reaching end of escalation. Can only be set when one of `trigger_types` is set to `alert-escalation-ended`. Must be either `0` or a value between `30` and `7200`. +- `escalation_ended_delay_sec` - (Optional) The number of seconds the alert action will be delayed when reaching end of escalation. Should only be set when one of `trigger_types` is set to `alert-escalation-ended`. Must be either `0` or a value between `30` and `7200`. +- `not_resolved_delay_sec` - (Optional) The number of seconds the alert action will be delayed when the alert is not resolved yet. Should only be set when one of `trigger_types` is set to `v-alert-not-resolved`. Must be either `0` or a value between `60` and `7200`. - `trigger_types` - (Optional if the `MANUAL` trigger mode and required if the `AUTOMATIC` trigger mode) A list of the trigger types. Allowed values are `alert-created`, `alert-assigned`, `alert-auto-escalated`, `alert-acknowledged`, `alert-raised`, `alert-comment-added`, `alert-escalation-ended`, `alert-resolved`, `alert-auto-resolved`, `alert-responder-added`, `alert-responder-removed`, `alert-channel-attached`, `alert-channel-detached`, `v-alert-not-resolved`. - `jira` - (Optional) A [jira](#jira-arguments) block. - `servicenow` - (Optional) A [servicenow](#servicenow-arguments) block. From a1891a8ba1164a61d402ffa52b4fa8d8e444747b Mon Sep 17 00:00:00 2001 From: Marko Simon Date: Thu, 22 Aug 2024 15:02:27 +0200 Subject: [PATCH 13/16] update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 73469e9..7c7291f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 22.08.2024, Version 2.9.0 + +- feature/new-api-resources in [#92](https://github.com/iLert/terraform-provider-ilert/pull/92) + ## 24.07.2024, Version 2.8.6 - fix/microsoft-teams-webhook-validation [#90](https://github.com/iLert/terraform-provider-ilert/pull/90) From 5009b82d450b5aa8b4220db71cc280a2f18fd4e0 Mon Sep 17 00:00:00 2001 From: Marko Simon Date: Thu, 22 Aug 2024 15:02:36 +0200 Subject: [PATCH 14/16] remove local dev path --- go.mod | 2 -- 1 file changed, 2 deletions(-) diff --git a/go.mod b/go.mod index ce7f037..a0f9186 100644 --- a/go.mod +++ b/go.mod @@ -2,8 +2,6 @@ module github.com/iLert/terraform-provider-ilert go 1.19 -replace github.com/iLert/ilert-go/v3 => /Users/markosimon/Documents/workspace/ilert-go - require ( github.com/hashicorp/terraform-plugin-sdk/v2 v2.25.0 github.com/iLert/ilert-go/v3 v3.8.3 From 679457869ba2dba2b05ee7eebb8dccc01c0c526e Mon Sep 17 00:00:00 2001 From: Marko Simon Date: Thu, 22 Aug 2024 15:03:58 +0200 Subject: [PATCH 15/16] edit changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c7291f..73c3d0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## 22.08.2024, Version 2.9.0 -- feature/new-api-resources in [#92](https://github.com/iLert/terraform-provider-ilert/pull/92) +- feature/new-api-resources pt.1 in [#92](https://github.com/iLert/terraform-provider-ilert/pull/92) ## 24.07.2024, Version 2.8.6 From b99a24201cfa930a7b31e6a5d12796436f58e678 Mon Sep 17 00:00:00 2001 From: Marko Simon Date: Thu, 22 Aug 2024 15:13:06 +0200 Subject: [PATCH 16/16] update to newest go sdk --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index a0f9186..bbd80c8 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.19 require ( github.com/hashicorp/terraform-plugin-sdk/v2 v2.25.0 - github.com/iLert/ilert-go/v3 v3.8.3 + github.com/iLert/ilert-go/v3 v3.9.0 ) require ( diff --git a/go.sum b/go.sum index 8df5a72..c9eb538 100644 --- a/go.sum +++ b/go.sum @@ -103,8 +103,8 @@ github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/iLert/ilert-go/v3 v3.8.3 h1:QY3aYHzQ4JDCP/36TMxwDKtsvMU1Rd7cPrVBN8VeVEA= -github.com/iLert/ilert-go/v3 v3.8.3/go.mod h1:xHJ8qdmthK4HExcQOd3V5JARed/EBKTdX86MqrJ1yJ0= +github.com/iLert/ilert-go/v3 v3.9.0 h1:i13Yv3JeK9ZEJYysR6hcHCDvMxx5xetuafVrdiJb6Ts= +github.com/iLert/ilert-go/v3 v3.9.0/go.mod h1:xHJ8qdmthK4HExcQOd3V5JARed/EBKTdX86MqrJ1yJ0= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=