From cbc2c388145401e526c9d02134e828b68bb00da1 Mon Sep 17 00:00:00 2001 From: "Robert Barnes (DevOps Rob)" Date: Mon, 7 Feb 2022 15:22:37 +0000 Subject: [PATCH 01/63] Adding custom_headers to delivery_method in webhook_subscription resource. --- pagerduty/resource_pagerduty_webhook_subscription.go | 6 ++++++ .../heimweh/go-pagerduty/pagerduty/webhook_subscription.go | 1 + website/docs/r/webhook_subscription.html.markdown | 1 + 3 files changed, 8 insertions(+) diff --git a/pagerduty/resource_pagerduty_webhook_subscription.go b/pagerduty/resource_pagerduty_webhook_subscription.go index 0e7b0a8f7..f4f96d0b9 100644 --- a/pagerduty/resource_pagerduty_webhook_subscription.go +++ b/pagerduty/resource_pagerduty_webhook_subscription.go @@ -41,6 +41,10 @@ func resourcePagerDutyWebhookSubscription() *schema.Resource { Type: schema.TypeString, Optional: true, }, + "custom_headers": { + Type: schema.TypeMap, + Optional: true, + }, }, }, }, @@ -196,6 +200,7 @@ func expandDeliveryMethod(v interface{}) pagerduty.DeliveryMethod { TemporarilyDisabled: dmMap["temporarily_disabled"].(bool), Type: dmMap["type"].(string), URL: dmMap["url"].(string), + CustomHeaders: dmMap["custom_headers"].(map[string]string), } return method } @@ -217,6 +222,7 @@ func flattenDeliveryMethod(method pagerduty.DeliveryMethod) []map[string]interfa "temporarily_disabled": method.TemporarilyDisabled, "type": method.Type, "url": method.URL, + "custom_headers": method.CustomHeaders, } methods = append(methods, methodMap) return methods diff --git a/vendor/github.com/heimweh/go-pagerduty/pagerduty/webhook_subscription.go b/vendor/github.com/heimweh/go-pagerduty/pagerduty/webhook_subscription.go index 2f17c17af..a2d76f777 100644 --- a/vendor/github.com/heimweh/go-pagerduty/pagerduty/webhook_subscription.go +++ b/vendor/github.com/heimweh/go-pagerduty/pagerduty/webhook_subscription.go @@ -21,6 +21,7 @@ type DeliveryMethod struct { TemporarilyDisabled bool `json:"temporarily_disabled,omitempty"` Type string `json:"type,omitempty"` URL string `json:"url,omitempty"` + CustomHeaders map[string]string `json:"custom_headers,omitempty"` } // Filter represents a webhook subscription filter diff --git a/website/docs/r/webhook_subscription.html.markdown b/website/docs/r/webhook_subscription.html.markdown index e193563b5..195284dfc 100644 --- a/website/docs/r/webhook_subscription.html.markdown +++ b/website/docs/r/webhook_subscription.html.markdown @@ -77,6 +77,7 @@ The following arguments are supported: * `temporarily_disabled` - (Required) Whether this webhook subscription is temporarily disabled. Becomes true if the delivery method URL is repeatedly rejected by the server. * `type` - (Required) Indicates the type of the delivery method. Allowed and default value: `http_delivery_method`. * `url` - (Required) The destination URL for webhook delivery. +* `custom_headers` - (Optional) The custom_headers of a webhook subscription define any optional headers that will be passed along with the payload to the destination URL. ### Webhook filter (`filter`) supports the following: From d873d62f383200585792a8cf553c92f31c88650c Mon Sep 17 00:00:00 2001 From: "Robert Barnes (DevOps Rob)" Date: Tue, 8 Feb 2022 18:57:28 +0000 Subject: [PATCH 02/63] fixing type error --- ...resource_pagerduty_webhook_subscription.go | 27 +++++++++++++++++-- .../pagerduty/webhook_subscription.go | 7 ++++- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/pagerduty/resource_pagerduty_webhook_subscription.go b/pagerduty/resource_pagerduty_webhook_subscription.go index f4f96d0b9..e61ec85bd 100644 --- a/pagerduty/resource_pagerduty_webhook_subscription.go +++ b/pagerduty/resource_pagerduty_webhook_subscription.go @@ -42,8 +42,21 @@ func resourcePagerDutyWebhookSubscription() *schema.Resource { Optional: true, }, "custom_headers": { - Type: schema.TypeMap, + Type: schema.TypeList, Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + + "value": { + Type: schema.TypeString, + Required: true, + }, + }, + }, }, }, }, @@ -196,11 +209,21 @@ func expandDeliveryMethod(v interface{}) pagerduty.DeliveryMethod { var method pagerduty.DeliveryMethod + // convert interface to []*pagerduty.CustomHeaders + var list []*pagerduty.CustomHeaders + for _, raw := range dmMap["custom_headers"].([]interface{}) { + list = append(list, &pagerduty.CustomHeaders{ + Name: raw.(map[string]interface{})["name"].(string), + Value: raw.(map[string]interface{})["value"].(string), + }) + } + + method = pagerduty.DeliveryMethod{ TemporarilyDisabled: dmMap["temporarily_disabled"].(bool), Type: dmMap["type"].(string), URL: dmMap["url"].(string), - CustomHeaders: dmMap["custom_headers"].(map[string]string), + CustomHeaders: list, } return method } diff --git a/vendor/github.com/heimweh/go-pagerduty/pagerduty/webhook_subscription.go b/vendor/github.com/heimweh/go-pagerduty/pagerduty/webhook_subscription.go index a2d76f777..192af2a6f 100644 --- a/vendor/github.com/heimweh/go-pagerduty/pagerduty/webhook_subscription.go +++ b/vendor/github.com/heimweh/go-pagerduty/pagerduty/webhook_subscription.go @@ -21,7 +21,12 @@ type DeliveryMethod struct { TemporarilyDisabled bool `json:"temporarily_disabled,omitempty"` Type string `json:"type,omitempty"` URL string `json:"url,omitempty"` - CustomHeaders map[string]string `json:"custom_headers,omitempty"` + CustomHeaders []*CustomHeaders `json:"custom_headers,omitempty"` +} + +type CustomHeaders struct { + Name string `json:"name,omitempty"` + Value string `json:"value,omitempty"` } // Filter represents a webhook subscription filter From 620023697e8a914065ab5167909835820efa6d8c Mon Sep 17 00:00:00 2001 From: DevOps Rob Date: Wed, 9 Feb 2022 11:02:53 +0000 Subject: [PATCH 03/63] Update pagerduty/resource_pagerduty_webhook_subscription.go Co-authored-by: Shohei Maeda <11495867+smaeda-ks@users.noreply.github.com> --- pagerduty/resource_pagerduty_webhook_subscription.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pagerduty/resource_pagerduty_webhook_subscription.go b/pagerduty/resource_pagerduty_webhook_subscription.go index e61ec85bd..ade6894f2 100644 --- a/pagerduty/resource_pagerduty_webhook_subscription.go +++ b/pagerduty/resource_pagerduty_webhook_subscription.go @@ -223,7 +223,7 @@ func expandDeliveryMethod(v interface{}) pagerduty.DeliveryMethod { TemporarilyDisabled: dmMap["temporarily_disabled"].(bool), Type: dmMap["type"].(string), URL: dmMap["url"].(string), - CustomHeaders: list, + CustomHeaders: headers, } return method } From 9caccf893ce254a127edf213a0008fe346a93d91 Mon Sep 17 00:00:00 2001 From: DevOps Rob Date: Wed, 9 Feb 2022 11:03:06 +0000 Subject: [PATCH 04/63] Update pagerduty/resource_pagerduty_webhook_subscription.go Co-authored-by: Shohei Maeda <11495867+smaeda-ks@users.noreply.github.com> --- pagerduty/resource_pagerduty_webhook_subscription.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pagerduty/resource_pagerduty_webhook_subscription.go b/pagerduty/resource_pagerduty_webhook_subscription.go index ade6894f2..8ad2f0728 100644 --- a/pagerduty/resource_pagerduty_webhook_subscription.go +++ b/pagerduty/resource_pagerduty_webhook_subscription.go @@ -210,9 +210,9 @@ func expandDeliveryMethod(v interface{}) pagerduty.DeliveryMethod { var method pagerduty.DeliveryMethod // convert interface to []*pagerduty.CustomHeaders - var list []*pagerduty.CustomHeaders + var headers []*pagerduty.CustomHeaders for _, raw := range dmMap["custom_headers"].([]interface{}) { - list = append(list, &pagerduty.CustomHeaders{ + headers = append(headers, &pagerduty.CustomHeaders{ Name: raw.(map[string]interface{})["name"].(string), Value: raw.(map[string]interface{})["value"].(string), }) From a246bf76f5f26b8c222b6b5b34065261ad1088ea Mon Sep 17 00:00:00 2001 From: "Robert Barnes (DevOps Rob)" Date: Wed, 9 Feb 2022 11:14:05 +0000 Subject: [PATCH 05/63] Updated the dependancy hash and example usage --- go.mod | 2 +- go.sum | 2 ++ .../heimweh/go-pagerduty/pagerduty/user.go | 31 ++++++++++++++++++- .../pagerduty/webhook_subscription.go | 8 ++--- vendor/modules.txt | 2 +- .../docs/r/webhook_subscription.html.markdown | 3 ++ 6 files changed, 41 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 77b3d5d19..13bd6813c 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.16 require ( cloud.google.com/go v0.71.0 // indirect github.com/hashicorp/terraform-plugin-sdk/v2 v2.10.1 - github.com/heimweh/go-pagerduty v0.0.0-20211210233744-b65de43109c1 + github.com/heimweh/go-pagerduty v0.0.0-20220208022815-41d374b4d21b golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd // indirect google.golang.org/api v0.35.0 // indirect google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb // indirect diff --git a/go.sum b/go.sum index f8b73d3b8..61c19462f 100644 --- a/go.sum +++ b/go.sum @@ -282,6 +282,8 @@ github.com/heimweh/go-pagerduty v0.0.0-20211119212911-31ef1eea0d0f h1:/sgh3L7adJ github.com/heimweh/go-pagerduty v0.0.0-20211119212911-31ef1eea0d0f/go.mod h1:JtJGtgN0y9KOCaqFMZFaBCWskpO/KK3Ro9TwjP9ss6w= github.com/heimweh/go-pagerduty v0.0.0-20211210233744-b65de43109c1 h1:49zl3n/g+ff/7/CpxiuqnenyxId5iAjbhgoE9iDHULc= github.com/heimweh/go-pagerduty v0.0.0-20211210233744-b65de43109c1/go.mod h1:JtJGtgN0y9KOCaqFMZFaBCWskpO/KK3Ro9TwjP9ss6w= +github.com/heimweh/go-pagerduty v0.0.0-20220208022815-41d374b4d21b h1:RoRPj+MZHLCb3DDepeGOJcJPpZD2TUzgPR//JWA5n+Y= +github.com/heimweh/go-pagerduty v0.0.0-20220208022815-41d374b4d21b/go.mod h1:JtJGtgN0y9KOCaqFMZFaBCWskpO/KK3Ro9TwjP9ss6w= github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= diff --git a/vendor/github.com/heimweh/go-pagerduty/pagerduty/user.go b/vendor/github.com/heimweh/go-pagerduty/pagerduty/user.go index a50971588..b6314510a 100644 --- a/vendor/github.com/heimweh/go-pagerduty/pagerduty/user.go +++ b/vendor/github.com/heimweh/go-pagerduty/pagerduty/user.go @@ -3,6 +3,7 @@ package pagerduty import ( "fmt" "log" + "strings" ) // UserService handles the communication with user @@ -289,13 +290,31 @@ func (s *UserService) ListContactMethods(userID string) (*ListContactMethodsResp } // CreateContactMethod creates a new contact method for a user. +// If the same contact method already exists, it will fetch the existing one, return a 200 instead of fail. This feature is useful in terraform +// provider, as when the desired user contact method already exists, terraform will be able to sync it to the state automatically. Otherwise, +// we need to manually fix the conflicts. func (s *UserService) CreateContactMethod(userID string, contactMethod *ContactMethod) (*ContactMethod, *Response, error) { u := fmt.Sprintf("/users/%s/contact_methods", userID) v := new(ContactMethodPayload) resp, err := s.client.newRequestDo("POST", u, nil, &ContactMethodPayload{ContactMethod: contactMethod}, &v) if err != nil { - return nil, nil, err + if e, ok := err.(*Error); ok && strings.Compare(fmt.Sprintf("%v", e.Errors), "[User Contact method must be unique]") == 0 { + resp, _, lErr := s.ListContactMethods(userID) + if lErr != nil { + return nil, nil, fmt.Errorf("user contact method is not unique and failed to fetch existing ones: %w", lErr) + } + + for _, contact := range resp.ContactMethods { + if isSameContactMethod(contact, contactMethod) { + return s.GetContactMethod(userID, contact.ID) + } + } + + return nil, nil, fmt.Errorf("user contact method address is used with different attributes (possibly label)") + } else { + return nil, nil, err + } } if err = cachePutContactMethod(v.ContactMethod); err != nil { @@ -307,6 +326,16 @@ func (s *UserService) CreateContactMethod(userID string, contactMethod *ContactM return v.ContactMethod, resp, nil } +// isSameContactMethod checks if an existing contact method should be taken as the same as a new one users want to create. +// note new contact method misses some fields like Self, HTMLURL. +func isSameContactMethod(existingContact, newContact *ContactMethod) bool { + return existingContact.Type == newContact.Type && + existingContact.Address == newContact.Address && + existingContact.Label == newContact.Label && + existingContact.CountryCode == newContact.CountryCode && + existingContact.Summary == newContact.Summary +} + // GetContactMethod retrieves a contact method for a user. func (s *UserService) GetContactMethod(userID string, contactMethodID string) (*ContactMethod, *Response, error) { u := fmt.Sprintf("/users/%s/contact_methods/%s", userID, contactMethodID) diff --git a/vendor/github.com/heimweh/go-pagerduty/pagerduty/webhook_subscription.go b/vendor/github.com/heimweh/go-pagerduty/pagerduty/webhook_subscription.go index 192af2a6f..8390be7db 100644 --- a/vendor/github.com/heimweh/go-pagerduty/pagerduty/webhook_subscription.go +++ b/vendor/github.com/heimweh/go-pagerduty/pagerduty/webhook_subscription.go @@ -18,10 +18,10 @@ type WebhookSubscription struct { // DeliveryMethod represents a webhook delivery method type DeliveryMethod struct { - TemporarilyDisabled bool `json:"temporarily_disabled,omitempty"` - Type string `json:"type,omitempty"` - URL string `json:"url,omitempty"` - CustomHeaders []*CustomHeaders `json:"custom_headers,omitempty"` + TemporarilyDisabled bool `json:"temporarily_disabled,omitempty"` + Type string `json:"type,omitempty"` + URL string `json:"url,omitempty"` + CustomHeaders []*CustomHeaders `json:"custom_headers,omitempty"` } type CustomHeaders struct { diff --git a/vendor/modules.txt b/vendor/modules.txt index e28f13ce8..2297a0d65 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -124,7 +124,7 @@ github.com/hashicorp/terraform-registry-address github.com/hashicorp/terraform-svchost # github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d github.com/hashicorp/yamux -# github.com/heimweh/go-pagerduty v0.0.0-20211210233744-b65de43109c1 +# github.com/heimweh/go-pagerduty v0.0.0-20220208022815-41d374b4d21b ## explicit github.com/heimweh/go-pagerduty/pagerduty # github.com/klauspost/compress v1.11.2 diff --git a/website/docs/r/webhook_subscription.html.markdown b/website/docs/r/webhook_subscription.html.markdown index 195284dfc..b7c2edb91 100644 --- a/website/docs/r/webhook_subscription.html.markdown +++ b/website/docs/r/webhook_subscription.html.markdown @@ -21,6 +21,9 @@ resource "pagerduty_webhook_subscription" "foo" { delivery_method { type = "http_delivery_method" url = "https://example.com/receive_a_pagerduty_webhook" + custom_headers = { + example_key = "example_value" + } } description = "%s" events = [ From 609d956724cd1346634a080cf912aca4c9fdbbaa Mon Sep 17 00:00:00 2001 From: DevOps Rob Date: Fri, 11 Feb 2022 10:39:12 +0000 Subject: [PATCH 06/63] Update website/docs/r/webhook_subscription.html.markdown Co-authored-by: Shohei Maeda <11495867+smaeda-ks@users.noreply.github.com> --- website/docs/r/webhook_subscription.html.markdown | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/website/docs/r/webhook_subscription.html.markdown b/website/docs/r/webhook_subscription.html.markdown index b7c2edb91..42dbaccf0 100644 --- a/website/docs/r/webhook_subscription.html.markdown +++ b/website/docs/r/webhook_subscription.html.markdown @@ -21,8 +21,13 @@ resource "pagerduty_webhook_subscription" "foo" { delivery_method { type = "http_delivery_method" url = "https://example.com/receive_a_pagerduty_webhook" - custom_headers = { - example_key = "example_value" + custom_headers { + name = "X-Foo" + value = "foo" + } + custom_headers { + name = "X-Bar" + value = "bar" } } description = "%s" From 5d8b3afb69c68491cea9d0fbe3ec443db109149c Mon Sep 17 00:00:00 2001 From: Bohdan Borovskyi <51109105+bohdanborovskyi-ma@users.noreply.github.com> Date: Thu, 7 Apr 2022 15:37:09 +0300 Subject: [PATCH 07/63] Fix flattened valueExtractor to preserve regex field Current flattening logic not aligned with expandEmailParsers function logic --- .../resource_pagerduty_service_integration.go | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/pagerduty/resource_pagerduty_service_integration.go b/pagerduty/resource_pagerduty_service_integration.go index dfb6e81dc..d3c8ca00a 100644 --- a/pagerduty/resource_pagerduty_service_integration.go +++ b/pagerduty/resource_pagerduty_service_integration.go @@ -519,12 +519,21 @@ func flattenEmailParsers(v []*pagerduty.EmailParser) []map[string]interface{} { var valueExtractors []map[string]interface{} for _, ve := range ef.ValueExtractors { - extractor := map[string]interface{}{ - "type": ve.Type, - "value_name": ve.ValueName, - "part": ve.Part, - "starts_after": ve.StartsAfter, - "ends_before": ve.EndsBefore, + if ve.Type == "regex" { + extractor := map[string]interface{}{ + "type": ve.Type, + "value_name": ve.ValueName, + "part": ve.Part, + "regex": ve.Regex, + } + } else { + extractor := map[string]interface{}{ + "type": ve.Type, + "value_name": ve.ValueName, + "part": ve.Part, + "starts_after": ve.StartsAfter, + "ends_before": ve.EndsBefore, + } } valueExtractors = append(valueExtractors, extractor) From 886e62743c06775324d345647250238f1ff2bf5f Mon Sep 17 00:00:00 2001 From: Bohdan Borovskyi <51109105+bohdanborovskyi-ma@users.noreply.github.com> Date: Thu, 7 Apr 2022 15:53:56 +0300 Subject: [PATCH 08/63] Change one of tests to verify email parser with regex type --- ...source_pagerduty_service_integration_test.go | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/pagerduty/resource_pagerduty_service_integration_test.go b/pagerduty/resource_pagerduty_service_integration_test.go index 61b533387..1ca874a6b 100644 --- a/pagerduty/resource_pagerduty_service_integration_test.go +++ b/pagerduty/resource_pagerduty_service_integration_test.go @@ -356,14 +356,12 @@ func TestAccPagerDutyServiceIntegrationEmail_Filters(t *testing.T) { "pagerduty_service_integration.foo", "email_parser.1.value_extractor.1.type", "between"), resource.TestCheckResourceAttr( "pagerduty_service_integration.foo", "email_parser.1.value_extractor.1.value_name", "FieldName11"), - resource.TestCheckResourceAttr( - "pagerduty_service_integration.foo", "email_parser.1.value_extractor.2.ends_before", "end"), resource.TestCheckResourceAttr( "pagerduty_service_integration.foo", "email_parser.1.value_extractor.2.part", "subject"), resource.TestCheckResourceAttr( - "pagerduty_service_integration.foo", "email_parser.1.value_extractor.2.starts_after", "start"), + "pagerduty_service_integration.foo", "email_parser.1.value_extractor.2.regex", "(bar*)"), resource.TestCheckResourceAttr( - "pagerduty_service_integration.foo", "email_parser.1.value_extractor.2.type", "between"), + "pagerduty_service_integration.foo", "email_parser.1.value_extractor.2.type", "regex"), resource.TestCheckResourceAttr( "pagerduty_service_integration.foo", "email_parser.1.value_extractor.2.value_name", "FieldName2"), ), @@ -949,12 +947,11 @@ resource "pagerduty_service_integration" "foo" { type = "between" value_name = "FieldName11" } - value_extractor { - ends_before = "end" - part = "subject" - starts_after = "start" - type = "between" - value_name = "FieldName2" + value_extractor { + part = "subject" + regex = "(bar*)" + type = "regex" + value_name = "FieldName2" } } email_parsing_fallback = "open_new_incident" From 90de4b5b1afd770ca515e9aac020d859089e5bc6 Mon Sep 17 00:00:00 2001 From: Bohdan Borovskyi <51109105+bohdanborovskyi-ma@users.noreply.github.com> Date: Thu, 7 Apr 2022 16:07:48 +0300 Subject: [PATCH 09/63] Update docs for params related to Email Management --- website/docs/r/service_integration.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/r/service_integration.html.markdown b/website/docs/r/service_integration.html.markdown index e50b0e999..7688451c3 100644 --- a/website/docs/r/service_integration.html.markdown +++ b/website/docs/r/service_integration.html.markdown @@ -169,8 +169,8 @@ The following arguments are supported: * `integration_key` - (Optional) This is the unique key used to route events to this integration when received via the PagerDuty Events API. * `integration_email` - (Optional) This is the unique fully-qualified email address used for routing emails to this integration for processing. - * `email_incident_creation` - (Optional) This is the unique fully-qualified email address used for routing emails to this integration for processing. - * `email_filter_mode` - (Optional) This is the unique fully-qualified email address used for routing emails to this integration for processing. + * `email_incident_creation` - (Optional) Behaviour of Email Management feature ([explained in PD docs](https://support.pagerduty.com/docs/email-management-filters-and-rules#control-when-a-new-incident-or-alert-is-triggered)). Can be `on_new_email`, `on_new_email_subject`, `only_if_no_open_incidents` or `use_rules`. + * `email_filter_mode` - (Optional) Mode of Emails Filters feature ([explained in PD docs](https://support.pagerduty.com/docs/email-management-filters-and-rules#configure-a-regex-filter)). Can be `all-email`, `or-rules-email` or `and-rules-email`. * `email_parsing_fallback` - (Optional) Can be `open_new_incident` or `discard`. Email filters (`email_filter`) supports the following: From 8290ab1d0db7fb45b67c649c9790f3f297c9711a Mon Sep 17 00:00:00 2001 From: Bohdan Borovskyi <51109105+bohdanborovskyi-ma@users.noreply.github.com> Date: Tue, 26 Apr 2022 23:42:19 +0300 Subject: [PATCH 10/63] [HF] Fix variable assignment --- .../resource_pagerduty_service_integration.go | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/pagerduty/resource_pagerduty_service_integration.go b/pagerduty/resource_pagerduty_service_integration.go index d3c8ca00a..4c8556782 100644 --- a/pagerduty/resource_pagerduty_service_integration.go +++ b/pagerduty/resource_pagerduty_service_integration.go @@ -519,21 +519,17 @@ func flattenEmailParsers(v []*pagerduty.EmailParser) []map[string]interface{} { var valueExtractors []map[string]interface{} for _, ve := range ef.ValueExtractors { - if ve.Type == "regex" { - extractor := map[string]interface{}{ + extractor := map[string]interface{}{ "type": ve.Type, "value_name": ve.ValueName, "part": ve.Part, - "regex": ve.Regex, - } + } + + if ve.Type == "regex" { + extractor["regex"] = ve.Regex } else { - extractor := map[string]interface{}{ - "type": ve.Type, - "value_name": ve.ValueName, - "part": ve.Part, - "starts_after": ve.StartsAfter, - "ends_before": ve.EndsBefore, - } + extractor["starts_after"] = ve.StartsAfter + extractor["ends_before"] = ve.EndsBefore } valueExtractors = append(valueExtractors, extractor) From 2d3c4897f3f9c7c717263f6b57d50821f89f8c16 Mon Sep 17 00:00:00 2001 From: Bohdan Borovskyi <51109105+bohdanborovskyi-ma@users.noreply.github.com> Date: Tue, 26 Apr 2022 23:44:48 +0300 Subject: [PATCH 11/63] Format the code --- pagerduty/resource_pagerduty_service_integration.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pagerduty/resource_pagerduty_service_integration.go b/pagerduty/resource_pagerduty_service_integration.go index 4c8556782..6845646fa 100644 --- a/pagerduty/resource_pagerduty_service_integration.go +++ b/pagerduty/resource_pagerduty_service_integration.go @@ -520,9 +520,9 @@ func flattenEmailParsers(v []*pagerduty.EmailParser) []map[string]interface{} { for _, ve := range ef.ValueExtractors { extractor := map[string]interface{}{ - "type": ve.Type, - "value_name": ve.ValueName, - "part": ve.Part, + "type": ve.Type, + "value_name": ve.ValueName, + "part": ve.Part, } if ve.Type == "regex" { From 64e8ebe429c39e7206eb848ef8dfd5b621db99f7 Mon Sep 17 00:00:00 2001 From: Sysfcuk Date: Thu, 28 Apr 2022 17:36:13 +0100 Subject: [PATCH 12/63] Wrong Extension Schema MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Had been struggling to get this working, eventually figured out the documentation was specifying the wrong extension schema, working great now 👍 --- website/docs/r/extension_servicenow.html.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/docs/r/extension_servicenow.html.markdown b/website/docs/r/extension_servicenow.html.markdown index 4e7bb18dc..d42b5d2ef 100644 --- a/website/docs/r/extension_servicenow.html.markdown +++ b/website/docs/r/extension_servicenow.html.markdown @@ -13,8 +13,8 @@ A special case for [extension](https://developer.pagerduty.com/api-reference/b3A ## Example Usage ```hcl -data "pagerduty_extension_schema" "webhook" { - name = "Generic V2 Webhook" +data "pagerduty_extension_schema" "servicenow" { + name = "ServiceNow (v7)" } resource "pagerduty_user" "example" { @@ -45,7 +45,7 @@ resource "pagerduty_service" "example" { resource "pagerduty_extension_servicenow" "snow" { name = "My Web App Extension" - extension_schema = data.pagerduty_extension_schema.webhook.id + extension_schema = data.pagerduty_extension_schema.servicenow.id extension_objects = [pagerduty_service.example.id] snow_user = "meeps" snow_password = "zorz" From 2dec4615aa4b790a209c5b238e0396ee01e90924 Mon Sep 17 00:00:00 2001 From: Dominik Rastawicki Date: Wed, 4 May 2022 12:56:23 +0800 Subject: [PATCH 13/63] Include timezdata build tag into the goreleaser config --- .goreleaser.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.goreleaser.yml b/.goreleaser.yml index eee11e81d..8097aab79 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -6,6 +6,8 @@ builds: - -trimpath ldflags: - '-s -w -X main.version={{.Version}} -X main.commit={{.Commit}}' + tags: + - timetzdata goos: - freebsd - windows From f6e18565a590ffd23192a08c40091b3f60c4bbbd Mon Sep 17 00:00:00 2001 From: Marcos Wright-Kuhns Date: Fri, 6 May 2022 09:59:15 -0700 Subject: [PATCH 14/63] Switch to always use @foo.test TLD in our tests & documentation ...because [he test TLD[1] will never be publicly addressable & therefore we'll be certain to never send real email to a random domain when the acceptance tests run. [1]:https://en.wikipedia.org/wiki/.test --- CHANGELOG.md | 21 ++++++----- ...source_pagerduty_escalation_policy_test.go | 2 +- .../data_source_pagerduty_schedule_test.go | 2 +- ...urce_pagerduty_service_integration_test.go | 2 +- .../data_source_pagerduty_service_test.go | 2 +- pagerduty/data_source_pagerduty_user_test.go | 2 +- ...import_pagerduty_escalation_policy_test.go | 2 +- pagerduty/import_pagerduty_schedule_test.go | 2 +- ...mport_pagerduty_service_dependency_test.go | 2 +- ...mport_pagerduty_service_event_rule_test.go | 2 +- ...port_pagerduty_service_integration_test.go | 2 +- pagerduty/import_pagerduty_service_test.go | 4 +-- .../import_pagerduty_slack_connection_test.go | 2 +- ...port_pagerduty_user_contact_method_test.go | 2 +- ...t_pagerduty_user_notification_rule_test.go | 2 +- pagerduty/import_pagerduty_user_test.go | 2 +- ...ort_pagerduty_webhook_subscription_test.go | 2 +- pagerduty/resource_pagerduty_addon_test.go | 4 +-- ...erduty_business_service_subscriber_test.go | 4 +-- ...source_pagerduty_escalation_policy_test.go | 4 +-- ...rce_pagerduty_extension_servicenow_test.go | 2 +- .../resource_pagerduty_extension_test.go | 2 +- ...ource_pagerduty_maintenance_window_test.go | 4 +-- .../resource_pagerduty_response_play_test.go | 18 +++++----- pagerduty/resource_pagerduty_schedule_test.go | 14 ++++---- ...ource_pagerduty_service_dependency_test.go | 4 +-- ...ource_pagerduty_service_event_rule_test.go | 4 +-- ...urce_pagerduty_service_integration_test.go | 14 ++++---- pagerduty/resource_pagerduty_service_test.go | 16 ++++----- ...esource_pagerduty_slack_connection_test.go | 36 +++++++++---------- .../resource_pagerduty_tag_assignment_test.go | 10 +++--- ...resource_pagerduty_team_membership_test.go | 4 +-- ...urce_pagerduty_user_contact_method_test.go | 12 +++---- ...e_pagerduty_user_notification_rule_test.go | 10 +++--- pagerduty/resource_pagerduty_user_test.go | 6 ++-- ...rce_pagerduty_webhook_subscription_test.go | 16 ++++----- .../mongo/options/datakeyoptions.go | 2 +- .../docs/r/service_integration.html.markdown | 4 +-- 38 files changed, 125 insertions(+), 120 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36b460c67..2b0725948 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 2.4.2 (Unreleased) + +IMPROVEMENTS: +* Use "@foo.test" email addresses in tests + ## 2.4.1 (April 22, 2022) IMPROVEMENTS: * `resource/pagerduty_user_notification`: Create user/notification rule: allow using existing ones ([#482](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/482)) @@ -19,7 +24,7 @@ IMPROVEMENTS: * `resource/maintenance_window`: Ignore error code 405 on delete ([#466](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/466)) -## 2.3.0 (February 10, 2022) +## 2.3.0 (February 10, 2022) IMPROVEMENTS: * Updated TF SDK to v2.10.1 and added `depends_on` to eventrule tests ([#446](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/446)) * `resource/pagerduty_schedule`: Added validation to `duration_seconds` ([#433](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/433)) @@ -198,11 +203,11 @@ IMPROVEMENTS: * `data_source_pagerduty_ruleset`: Added `routing_keys` field to the `ruleset` object ([#305](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/305)) ## 1.9.3 (February 11, 2021) -BUG FIXES: +BUG FIXES: * `resource/pagerduty_service_event_rule`,`resource/pagerduty_ruleset_rule`: Fixed Bug with Event Rule Suppress Action ([#302](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/302)) ## 1.9.2 (February 10, 2021) -BUG FIXES: +BUG FIXES: * `resource/pagerduty_service_event_rule`,`resource/pagerduty_ruleset_rule`: Fixed Bug with Event Rule Positioning ([#301](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/301)) ## 1.9.1 (February 8, 2021) @@ -268,7 +273,7 @@ FEATURES * Implement retry logic on all reads ([#208](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/208)) * Bump golang to v1.14.1 ([#193](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/193)) -BUG FIXES: +BUG FIXES: * data_source_ruleset: add example of Default Global Ruleset in Docs ([#239](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/239)) ## 1.7.2 (June 01, 2020) @@ -276,7 +281,7 @@ FEATURES * **New Data Source:** `pagerduty_ruleset` ([#237](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/237)) * Update docs/tests to TF 0.12 syntax ([#223](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/223)) -BUG FIXES: +BUG FIXES: * testing: update sweepers ([#220](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/220)) * data_source_priority: adding doc to sidebar nav ([#221](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/221)) @@ -363,7 +368,7 @@ BUG FIXES: IMPROVEMENTS: * Switch to standalone Terraform Plugin SDK: ([#158](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/158)) -* Add html_url read-only attribute to resource_pagerduty_service, resource_pagerduty_extension, resource_pagerduty_team ([#162](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/162)) +* Add html_url read-only attribute to resource_pagerduty_service, resource_pagerduty_extension, resource_pagerduty_team ([#162](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/162)) * resource/pagerduty_event_rule: Documentation for `depends_on` field ([#152](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/152)). @@ -397,9 +402,9 @@ BUG FIXES: BUG FIXES: -* data-source/pagerduty_team: Fix team search issue [[#110](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/110)] +* data-source/pagerduty_team: Fix team search issue [[#110](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/110)] * resource/pagerduty_maintenance_window: Suppress spurious diff in `start_time` & `end_time` ([#116](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/116)) -* resource/pagerduty_service: Set invitation_sent [[#127](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/127)] +* resource/pagerduty_service: Set invitation_sent [[#127](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/127)] * resource/pagerduty_escalation_policy: Correctly set teams ([#129](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/129)) IMPROVEMENTS: diff --git a/pagerduty/data_source_pagerduty_escalation_policy_test.go b/pagerduty/data_source_pagerduty_escalation_policy_test.go index b509bb214..442791df6 100644 --- a/pagerduty/data_source_pagerduty_escalation_policy_test.go +++ b/pagerduty/data_source_pagerduty_escalation_policy_test.go @@ -11,7 +11,7 @@ import ( func TestAccDataSourcePagerDutyEscalationPolicy_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) resource.Test(t, resource.TestCase{ diff --git a/pagerduty/data_source_pagerduty_schedule_test.go b/pagerduty/data_source_pagerduty_schedule_test.go index 06f17dc3e..87be61eef 100644 --- a/pagerduty/data_source_pagerduty_schedule_test.go +++ b/pagerduty/data_source_pagerduty_schedule_test.go @@ -12,7 +12,7 @@ import ( func TestAccDataSourcePagerDutySchedule_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) schedule := fmt.Sprintf("tf-%s", acctest.RandString(5)) location := "Europe/Berlin" start := timeNowInLoc(location).Add(24 * time.Hour).Round(1 * time.Hour).Format(time.RFC3339) diff --git a/pagerduty/data_source_pagerduty_service_integration_test.go b/pagerduty/data_source_pagerduty_service_integration_test.go index 708483d9a..546f11062 100644 --- a/pagerduty/data_source_pagerduty_service_integration_test.go +++ b/pagerduty/data_source_pagerduty_service_integration_test.go @@ -11,7 +11,7 @@ import ( func TestAccDataSourcePagerDutyIntegration_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) serviceIntegration := "Datadog" diff --git a/pagerduty/data_source_pagerduty_service_test.go b/pagerduty/data_source_pagerduty_service_test.go index de4f60ddb..549b7dd65 100644 --- a/pagerduty/data_source_pagerduty_service_test.go +++ b/pagerduty/data_source_pagerduty_service_test.go @@ -11,7 +11,7 @@ import ( func TestAccDataSourcePagerDutyService_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) diff --git a/pagerduty/data_source_pagerduty_user_test.go b/pagerduty/data_source_pagerduty_user_test.go index 8724ffbcf..5f900a2cd 100644 --- a/pagerduty/data_source_pagerduty_user_test.go +++ b/pagerduty/data_source_pagerduty_user_test.go @@ -11,7 +11,7 @@ import ( func TestAccDataSourcePagerDutyUser_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, diff --git a/pagerduty/import_pagerduty_escalation_policy_test.go b/pagerduty/import_pagerduty_escalation_policy_test.go index 872e8ccd4..d6e8820ed 100644 --- a/pagerduty/import_pagerduty_escalation_policy_test.go +++ b/pagerduty/import_pagerduty_escalation_policy_test.go @@ -10,7 +10,7 @@ import ( func TestAccPagerDutyEscalationPolicy_import(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) resource.Test(t, resource.TestCase{ diff --git a/pagerduty/import_pagerduty_schedule_test.go b/pagerduty/import_pagerduty_schedule_test.go index 840be3d26..40338bd9d 100644 --- a/pagerduty/import_pagerduty_schedule_test.go +++ b/pagerduty/import_pagerduty_schedule_test.go @@ -11,7 +11,7 @@ import ( func TestAccPagerDutySchedule_import(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) schedule := fmt.Sprintf("tf-%s", acctest.RandString(5)) location := "Europe/Berlin" start := timeNowInLoc(location).Add(24 * time.Hour).Round(1 * time.Hour).Format(time.RFC3339) diff --git a/pagerduty/import_pagerduty_service_dependency_test.go b/pagerduty/import_pagerduty_service_dependency_test.go index b343d3d6b..5f502090e 100644 --- a/pagerduty/import_pagerduty_service_dependency_test.go +++ b/pagerduty/import_pagerduty_service_dependency_test.go @@ -13,7 +13,7 @@ func TestAccPagerDutyServiceDependency_import(t *testing.T) { service := fmt.Sprintf("tf-%s", acctest.RandString(5)) businessService := fmt.Sprintf("tf-%s", acctest.RandString(5)) username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) resource.Test(t, resource.TestCase{ diff --git a/pagerduty/import_pagerduty_service_event_rule_test.go b/pagerduty/import_pagerduty_service_event_rule_test.go index 904f11e89..fda2e4a95 100644 --- a/pagerduty/import_pagerduty_service_event_rule_test.go +++ b/pagerduty/import_pagerduty_service_event_rule_test.go @@ -11,7 +11,7 @@ import ( func TestAccPagerDutyServiceEventRule_import(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) rule := fmt.Sprintf("tf-%s", acctest.RandString(5)) diff --git a/pagerduty/import_pagerduty_service_integration_test.go b/pagerduty/import_pagerduty_service_integration_test.go index 7376af4f8..e42d4d9e1 100644 --- a/pagerduty/import_pagerduty_service_integration_test.go +++ b/pagerduty/import_pagerduty_service_integration_test.go @@ -11,7 +11,7 @@ import ( func TestAccPagerDutyServiceIntegration_import(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) serviceIntegration := fmt.Sprintf("tf-%s", acctest.RandString(5)) diff --git a/pagerduty/import_pagerduty_service_test.go b/pagerduty/import_pagerduty_service_test.go index 29995809f..458acca0f 100644 --- a/pagerduty/import_pagerduty_service_test.go +++ b/pagerduty/import_pagerduty_service_test.go @@ -10,7 +10,7 @@ import ( func TestAccPagerDutyService_import(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) @@ -34,7 +34,7 @@ func TestAccPagerDutyService_import(t *testing.T) { func TestAccPagerDutyServiceWithIncidentUrgency_import(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) diff --git a/pagerduty/import_pagerduty_slack_connection_test.go b/pagerduty/import_pagerduty_slack_connection_test.go index 1f798566c..2b363081d 100644 --- a/pagerduty/import_pagerduty_slack_connection_test.go +++ b/pagerduty/import_pagerduty_slack_connection_test.go @@ -11,7 +11,7 @@ import ( func TestAccPagerDutySlackConnection_import(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) diff --git a/pagerduty/import_pagerduty_user_contact_method_test.go b/pagerduty/import_pagerduty_user_contact_method_test.go index d3e0a44c2..fa33a19a7 100644 --- a/pagerduty/import_pagerduty_user_contact_method_test.go +++ b/pagerduty/import_pagerduty_user_contact_method_test.go @@ -11,7 +11,7 @@ import ( func TestAccPagerDutyUserContactMethod_import(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, diff --git a/pagerduty/import_pagerduty_user_notification_rule_test.go b/pagerduty/import_pagerduty_user_notification_rule_test.go index 66456d0a1..74b7206c9 100644 --- a/pagerduty/import_pagerduty_user_notification_rule_test.go +++ b/pagerduty/import_pagerduty_user_notification_rule_test.go @@ -11,7 +11,7 @@ import ( func TestAccPagerDutyUserNotificationRule_import(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) contactMethodType := "phone_contact_method" resource.Test(t, resource.TestCase{ diff --git a/pagerduty/import_pagerduty_user_test.go b/pagerduty/import_pagerduty_user_test.go index aeeea8bab..527ebf884 100644 --- a/pagerduty/import_pagerduty_user_test.go +++ b/pagerduty/import_pagerduty_user_test.go @@ -10,7 +10,7 @@ import ( func TestAccPagerDutyUser_import(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, diff --git a/pagerduty/import_pagerduty_webhook_subscription_test.go b/pagerduty/import_pagerduty_webhook_subscription_test.go index f93867a5a..7bf88092a 100644 --- a/pagerduty/import_pagerduty_webhook_subscription_test.go +++ b/pagerduty/import_pagerduty_webhook_subscription_test.go @@ -11,7 +11,7 @@ import ( func TestAccPagerDutyWebhookSubscription_import(t *testing.T) { description := fmt.Sprintf("tf-test-%s", acctest.RandString(5)) username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) diff --git a/pagerduty/resource_pagerduty_addon_test.go b/pagerduty/resource_pagerduty_addon_test.go index e8c76a49a..eb777f6f3 100644 --- a/pagerduty/resource_pagerduty_addon_test.go +++ b/pagerduty/resource_pagerduty_addon_test.go @@ -63,7 +63,7 @@ func TestAccPagerDutyAddon_Basic(t *testing.T) { resource.TestCheckResourceAttr( "pagerduty_addon.foo", "name", addon), resource.TestCheckResourceAttr( - "pagerduty_addon.foo", "src", "https://intranet.foo.com/status"), + "pagerduty_addon.foo", "src", "https://intranet.foo.test/status"), ), }, { @@ -125,7 +125,7 @@ func testAccCheckPagerDutyAddonConfig(addon string) string { return fmt.Sprintf(` resource "pagerduty_addon" "foo" { name = "%s" - src = "https://intranet.foo.com/status" + src = "https://intranet.foo.test/status" } `, addon) } diff --git a/pagerduty/resource_pagerduty_business_service_subscriber_test.go b/pagerduty/resource_pagerduty_business_service_subscriber_test.go index 5fa864943..edeaaa0bb 100644 --- a/pagerduty/resource_pagerduty_business_service_subscriber_test.go +++ b/pagerduty/resource_pagerduty_business_service_subscriber_test.go @@ -13,7 +13,7 @@ import ( func TestAccPagerDutyBusinessServiceSubscriber_User(t *testing.T) { businessServiceName := fmt.Sprintf("tf-%s", acctest.RandString(5)) username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -57,7 +57,7 @@ func TestAccPagerDutyBusinessServiceSubscriber_TeamUser(t *testing.T) { businessServiceName := fmt.Sprintf("tf-%s", acctest.RandString(5)) team := fmt.Sprintf("tf-%s", acctest.RandString(5)) username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, diff --git a/pagerduty/resource_pagerduty_escalation_policy_test.go b/pagerduty/resource_pagerduty_escalation_policy_test.go index a1de0b0c2..431959568 100644 --- a/pagerduty/resource_pagerduty_escalation_policy_test.go +++ b/pagerduty/resource_pagerduty_escalation_policy_test.go @@ -52,7 +52,7 @@ func testSweepEscalationPolicy(region string) error { func TestAccPagerDutyEscalationPolicy_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) escalationPolicyUpdated := fmt.Sprintf("tf-%s", acctest.RandString(5)) @@ -102,7 +102,7 @@ func TestAccPagerDutyEscalationPolicy_Basic(t *testing.T) { func TestAccPagerDutyEscalationPolicyWithTeams_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) team := fmt.Sprintf("tf-%s", acctest.RandString(5)) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) escalationPolicyUpdated := fmt.Sprintf("tf-%s", acctest.RandString(5)) diff --git a/pagerduty/resource_pagerduty_extension_servicenow_test.go b/pagerduty/resource_pagerduty_extension_servicenow_test.go index 54d0af74e..792dc4755 100644 --- a/pagerduty/resource_pagerduty_extension_servicenow_test.go +++ b/pagerduty/resource_pagerduty_extension_servicenow_test.go @@ -159,7 +159,7 @@ func testAccCheckPagerDutyExtensionServiceNowConfig(name string, extension_name return fmt.Sprintf(` resource "pagerduty_user" "foo" { name = "%[1]v" - email = "%[1]v@foo.com" + email = "%[1]v@foo.test" color = "green" role = "user" job_title = "foo" diff --git a/pagerduty/resource_pagerduty_extension_test.go b/pagerduty/resource_pagerduty_extension_test.go index cb6442a5a..1b3e822d3 100644 --- a/pagerduty/resource_pagerduty_extension_test.go +++ b/pagerduty/resource_pagerduty_extension_test.go @@ -137,7 +137,7 @@ func testAccCheckPagerDutyExtensionConfig(name string, extension_name string, ur return fmt.Sprintf(` resource "pagerduty_user" "foo" { name = "%[1]v" - email = "%[1]v@foo.com" + email = "%[1]v@foo.test" color = "green" role = "user" job_title = "foo" diff --git a/pagerduty/resource_pagerduty_maintenance_window_test.go b/pagerduty/resource_pagerduty_maintenance_window_test.go index 79e3d23b0..b11c94608 100644 --- a/pagerduty/resource_pagerduty_maintenance_window_test.go +++ b/pagerduty/resource_pagerduty_maintenance_window_test.go @@ -115,7 +115,7 @@ func testAccCheckPagerDutyMaintenanceWindowConfig(desc, start, end string) strin return fmt.Sprintf(` resource "pagerduty_user" "foo" { name = "%[1]v" - email = "%[1]v@foo.com" + email = "%[1]v@foo.test" color = "green" role = "user" job_title = "foo" @@ -163,7 +163,7 @@ func testAccCheckPagerDutyMaintenanceWindowConfigUpdated(desc, start, end string return fmt.Sprintf(` resource "pagerduty_user" "foo" { name = "%[1]v" - email = "%[1]v@foo.com" + email = "%[1]v@foo.test" color = "green" role = "user" job_title = "foo" diff --git a/pagerduty/resource_pagerduty_response_play_test.go b/pagerduty/resource_pagerduty_response_play_test.go index 003a32c77..bf450fb6f 100644 --- a/pagerduty/resource_pagerduty_response_play_test.go +++ b/pagerduty/resource_pagerduty_response_play_test.go @@ -24,7 +24,7 @@ func TestAccPagerDutyResponsePlay_Basic(t *testing.T) { resource.TestCheckResourceAttr( "pagerduty_response_play.foo", "name", name), resource.TestCheckResourceAttr( - "pagerduty_response_play.foo", "from", name+"@foo.com"), + "pagerduty_response_play.foo", "from", name+"@foo.test"), resource.TestCheckResourceAttr( "pagerduty_response_play.foo", "responder.#", "2"), ), @@ -36,7 +36,7 @@ func TestAccPagerDutyResponsePlay_Basic(t *testing.T) { resource.TestCheckResourceAttr( "pagerduty_response_play.foo", "name", name), resource.TestCheckResourceAttr( - "pagerduty_response_play.foo", "from", name+"@foo.com"), + "pagerduty_response_play.foo", "from", name+"@foo.test"), resource.TestCheckResourceAttr( "pagerduty_response_play.foo", "responder.#", "1"), resource.TestCheckResourceAttr( @@ -96,7 +96,7 @@ func testAccCheckPagerDutyResponsePlayConfig(name string) string { return fmt.Sprintf(` resource "pagerduty_user" "foo" { name = "%[1]v" - email = "%[1]v@foo.com" + email = "%[1]v@foo.test" color = "green" role = "user" job_title = "foo" @@ -133,7 +133,7 @@ resource "pagerduty_response_play" "foo" { type = "user_reference" id = pagerduty_user.foo.id } -runnability = "services" +runnability = "services" } `, name) } @@ -142,28 +142,28 @@ func testAccCheckPagerDutyResponsePlayConfigUpdated(name string) string { return fmt.Sprintf(` resource "pagerduty_user" "foo" { name = "%[1]v" - email = "%[1]v@foo.com" + email = "%[1]v@foo.test" color = "green" role = "user" job_title = "foo" description = "foo" } - + resource "pagerduty_escalation_policy" "foo" { name = "%[1]v" description = "bar" num_loops = 2 - + rule { escalation_delay_in_minutes = 10 - + target { type = "user_reference" id = pagerduty_user.foo.id } } } - + resource "pagerduty_response_play" "foo" { name = "%[1]v" from = pagerduty_user.foo.email diff --git a/pagerduty/resource_pagerduty_schedule_test.go b/pagerduty/resource_pagerduty_schedule_test.go index 4ed90a954..f02b29795 100644 --- a/pagerduty/resource_pagerduty_schedule_test.go +++ b/pagerduty/resource_pagerduty_schedule_test.go @@ -51,7 +51,7 @@ func testSweepSchedule(region string) error { func TestAccPagerDutySchedule_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) schedule := fmt.Sprintf("tf-%s", acctest.RandString(5)) scheduleUpdated := fmt.Sprintf("tf-%s", acctest.RandString(5)) location := "America/New_York" @@ -113,7 +113,7 @@ func TestAccPagerDutySchedule_Basic(t *testing.T) { func TestAccPagerDutyScheduleWithTeams_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) schedule := fmt.Sprintf("tf-%s", acctest.RandString(5)) scheduleUpdated := fmt.Sprintf("tf-%s", acctest.RandString(5)) location := "America/New_York" @@ -176,7 +176,7 @@ func TestAccPagerDutyScheduleWithTeams_Basic(t *testing.T) { } func TestAccPagerDutyScheduleOverflow_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) schedule := fmt.Sprintf("tf-%s", acctest.RandString(5)) scheduleUpdated := fmt.Sprintf("tf-%s", acctest.RandString(5)) location := "America/New_York" @@ -206,7 +206,7 @@ func TestAccPagerDutyScheduleOverflow_Basic(t *testing.T) { func TestAccPagerDutySchedule_BasicWeek(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) schedule := fmt.Sprintf("tf-%s", acctest.RandString(5)) scheduleUpdated := fmt.Sprintf("tf-%s", acctest.RandString(5)) location := "Australia/Melbourne" @@ -268,7 +268,7 @@ func TestAccPagerDutySchedule_BasicWeek(t *testing.T) { func TestAccPagerDutySchedule_Multi(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) schedule := fmt.Sprintf("tf-%s", acctest.RandString(5)) location := "Europe/Berlin" start := timeNowInLoc(location).Add(24 * time.Hour).Round(1 * time.Hour).Format(time.RFC3339) @@ -745,7 +745,7 @@ resource "pagerduty_schedule" "foo" { time_zone = "%s" description = "foo" - + teams = [pagerduty_team.foo.id] layer { @@ -781,7 +781,7 @@ resource "pagerduty_schedule" "foo" { time_zone = "%s" description = "Managed by Terraform" - + teams = [pagerduty_team.foo.id] layer { diff --git a/pagerduty/resource_pagerduty_service_dependency_test.go b/pagerduty/resource_pagerduty_service_dependency_test.go index ae5e6b69c..11a02ec08 100644 --- a/pagerduty/resource_pagerduty_service_dependency_test.go +++ b/pagerduty/resource_pagerduty_service_dependency_test.go @@ -15,7 +15,7 @@ func TestAccPagerDutyBusinessServiceDependency_Basic(t *testing.T) { service := fmt.Sprintf("tf-%s", acctest.RandString(5)) businessService := fmt.Sprintf("tf-%s", acctest.RandString(5)) username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) resource.Test(t, resource.TestCase{ @@ -152,7 +152,7 @@ func TestAccPagerDutyTechnicalServiceDependency_Basic(t *testing.T) { dependentService := fmt.Sprintf("tf-%s", acctest.RandString(5)) supportingService := fmt.Sprintf("tf-%s", acctest.RandString(5)) username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) resource.Test(t, resource.TestCase{ diff --git a/pagerduty/resource_pagerduty_service_event_rule_test.go b/pagerduty/resource_pagerduty_service_event_rule_test.go index f4e593fe2..199c457f3 100644 --- a/pagerduty/resource_pagerduty_service_event_rule_test.go +++ b/pagerduty/resource_pagerduty_service_event_rule_test.go @@ -11,7 +11,7 @@ import ( func TestAccPagerDutyServiceEventRule_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) rule := fmt.Sprintf("tf-%s", acctest.RandString(5)) @@ -74,7 +74,7 @@ func TestAccPagerDutyServiceEventRule_Basic(t *testing.T) { func TestAccPagerDutyServiceEventRule_MultipleRules(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) rule1 := fmt.Sprintf("tf-%s", acctest.RandString(5)) diff --git a/pagerduty/resource_pagerduty_service_integration_test.go b/pagerduty/resource_pagerduty_service_integration_test.go index 61b533387..2c7481c33 100644 --- a/pagerduty/resource_pagerduty_service_integration_test.go +++ b/pagerduty/resource_pagerduty_service_integration_test.go @@ -13,7 +13,7 @@ import ( func TestAccPagerDutyServiceIntegration_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) serviceIntegration := fmt.Sprintf("tf-%s", acctest.RandString(5)) @@ -56,7 +56,7 @@ func TestAccPagerDutyServiceIntegration_Basic(t *testing.T) { func TestAccPagerDutyServiceIntegrationGeneric_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) serviceIntegration := fmt.Sprintf("tf-%s", acctest.RandString(5)) @@ -115,7 +115,7 @@ func TestAccPagerDutyServiceIntegrationGeneric_Basic(t *testing.T) { } func TestAccPagerDutyServiceIntegrationEmail_Filters(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) serviceIntegration := fmt.Sprintf("tf-%s", acctest.RandString(5)) @@ -146,7 +146,7 @@ func TestAccPagerDutyServiceIntegrationEmail_Filters(t *testing.T) { resource.TestCheckResourceAttr( "pagerduty_service_integration.foo", "email_filter.0.from_email_mode", "match"), resource.TestCheckResourceAttr( - "pagerduty_service_integration.foo", "email_filter.0.from_email_regex", "(@foo.com*)"), + "pagerduty_service_integration.foo", "email_filter.0.from_email_regex", "(@foo.test*)"), resource.TestCheckResourceAttr( "pagerduty_service_integration.foo", "email_filter.0.subject_mode", "match"), resource.TestCheckResourceAttr( @@ -262,7 +262,7 @@ func TestAccPagerDutyServiceIntegrationEmail_Filters(t *testing.T) { resource.TestCheckResourceAttr( "pagerduty_service_integration.foo", "email_filter.0.from_email_mode", "match"), resource.TestCheckResourceAttr( - "pagerduty_service_integration.foo", "email_filter.0.from_email_regex", "(@foo.com*)"), + "pagerduty_service_integration.foo", "email_filter.0.from_email_regex", "(@foo.test*)"), resource.TestCheckResourceAttr( "pagerduty_service_integration.foo", "email_filter.0.subject_mode", "match"), resource.TestCheckResourceAttr( @@ -746,7 +746,7 @@ resource "pagerduty_service_integration" "foo" { body_mode = "always" body_regex = null from_email_mode = "match" - from_email_regex = "(@foo.com*)" + from_email_regex = "(@foo.test*)" subject_mode = "match" subject_regex = "(CRITICAL*)" } @@ -872,7 +872,7 @@ resource "pagerduty_service_integration" "foo" { body_mode = "always" body_regex = null from_email_mode = "match" - from_email_regex = "(@foo.com*)" + from_email_regex = "(@foo.test*)" subject_mode = "match" subject_regex = "(CRITICAL*)" } diff --git a/pagerduty/resource_pagerduty_service_test.go b/pagerduty/resource_pagerduty_service_test.go index 9db9a8608..56de1270e 100644 --- a/pagerduty/resource_pagerduty_service_test.go +++ b/pagerduty/resource_pagerduty_service_test.go @@ -50,7 +50,7 @@ func testSweepService(region string) error { func TestAccPagerDutyService_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) serviceUpdated := fmt.Sprintf("tf-%s", acctest.RandString(5)) @@ -132,7 +132,7 @@ func TestAccPagerDutyService_Basic(t *testing.T) { func TestAccPagerDutyService_AlertGrouping(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) @@ -199,7 +199,7 @@ func TestAccPagerDutyService_AlertGrouping(t *testing.T) { func TestAccPagerDutyService_AlertContentGrouping(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) @@ -244,7 +244,7 @@ func TestAccPagerDutyService_AlertContentGrouping(t *testing.T) { func TestAccPagerDutyService_BasicWithIncidentUrgencyRules(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) serviceUpdated := fmt.Sprintf("tf-%s", acctest.RandString(5)) @@ -446,7 +446,7 @@ func TestAccPagerDutyService_BasicWithIncidentUrgencyRules(t *testing.T) { func TestAccPagerDutyService_FromBasicToCustomIncidentUrgencyRules(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) serviceUpdated := fmt.Sprintf("tf-%s", acctest.RandString(5)) @@ -548,7 +548,7 @@ func TestAccPagerDutyService_FromBasicToCustomIncidentUrgencyRules(t *testing.T) func TestAccPagerDutyService_SupportHoursChange(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) service_id := "" @@ -759,9 +759,9 @@ resource "pagerduty_service" "foo" { acknowledgement_timeout = 1800 escalation_policy = pagerduty_escalation_policy.foo.id alert_creation = "create_alerts_and_incidents" - alert_grouping_parameters { + alert_grouping_parameters { type = "content_based" - config { + config { aggregate = "all" fields = ["custom_details.field1"] } diff --git a/pagerduty/resource_pagerduty_slack_connection_test.go b/pagerduty/resource_pagerduty_slack_connection_test.go index af9133252..147ca848c 100644 --- a/pagerduty/resource_pagerduty_slack_connection_test.go +++ b/pagerduty/resource_pagerduty_slack_connection_test.go @@ -22,7 +22,7 @@ var ( func TestAccPagerDutySlackConnection_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) @@ -165,32 +165,32 @@ func testAccCheckPagerDutySlackConnectionExists(n string) resource.TestCheckFunc func testAccCheckPagerDutySlackConnectionConfig(username, useremail, escalationPolicy, service, workspaceID, channelID string) string { return fmt.Sprintf(` resource "pagerduty_user" "foo" { - name = "%s" + name = "%s" email = "%s" } - + resource "pagerduty_escalation_policy" "foo" { name = "%s" description = "foo" num_loops = 1 - + rule { escalation_delay_in_minutes = 10 - + target { type = "user_reference" id = pagerduty_user.foo.id } } } - + resource "pagerduty_service" "foo" { name = "%s" description = "foo" auto_resolve_timeout = 1800 acknowledgement_timeout = 1800 escalation_policy = pagerduty_escalation_policy.foo.id - + incident_urgency_rule { type = "constant" urgency = "high" @@ -219,7 +219,7 @@ func testAccCheckPagerDutySlackConnectionConfig(username, useremail, escalationP "incident.responder.added", "incident.responder.replied", "incident.status_update_published", - "incident.reopened" + "incident.reopened" ] priorities = [data.pagerduty_priority.p1.id] urgency = "high" @@ -231,32 +231,32 @@ func testAccCheckPagerDutySlackConnectionConfig(username, useremail, escalationP func testAccCheckPagerDutySlackConnectionConfigUpdated(username, email, escalationPolicy, service, workspaceID, channelID string) string { return fmt.Sprintf(` resource "pagerduty_user" "foo" { - name = "%s" + name = "%s" email = "%s" } - + resource "pagerduty_escalation_policy" "foo" { name = "%s" description = "foo" num_loops = 1 - + rule { escalation_delay_in_minutes = 10 - + target { type = "user_reference" id = pagerduty_user.foo.id } } } - + resource "pagerduty_service" "foo" { name = "%s" description = "foo" auto_resolve_timeout = 1800 acknowledgement_timeout = 1800 escalation_policy = pagerduty_escalation_policy.foo.id - + incident_urgency_rule { type = "constant" urgency = "high" @@ -285,7 +285,7 @@ func testAccCheckPagerDutySlackConnectionConfigUpdated(username, email, escalati "incident.responder.added", "incident.responder.replied", "incident.status_update_published", - "incident.reopened" + "incident.reopened" ] priorities = [data.pagerduty_priority.p1.id] } @@ -318,7 +318,7 @@ func testAccCheckPagerDutySlackConnectionConfigTeam(team, workspaceID, channelID "incident.responder.added", "incident.responder.replied", "incident.status_update_published", - "incident.reopened" + "incident.reopened" ] } } @@ -349,7 +349,7 @@ func testAccCheckPagerDutySlackConnectionConfigTeamUpdated(team, workspaceID, ch "incident.responder.added", "incident.responder.replied", "incident.status_update_published", - "incident.reopened" + "incident.reopened" ] urgency = "low" } @@ -381,7 +381,7 @@ func testAccCheckPagerDutySlackConnectionConfigEnvar(team, channelID string) str "incident.responder.added", "incident.responder.replied", "incident.status_update_published", - "incident.reopened" + "incident.reopened" ] urgency = "low" } diff --git a/pagerduty/resource_pagerduty_tag_assignment_test.go b/pagerduty/resource_pagerduty_tag_assignment_test.go index 893463dc4..e6a7cfc82 100644 --- a/pagerduty/resource_pagerduty_tag_assignment_test.go +++ b/pagerduty/resource_pagerduty_tag_assignment_test.go @@ -13,7 +13,7 @@ import ( func TestAccPagerDutyTagAssignment_User(t *testing.T) { tagLabel := fmt.Sprintf("tf-%s", acctest.RandString(5)) username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -61,7 +61,7 @@ func TestAccPagerDutyTagAssignment_EP(t *testing.T) { tagLabel := fmt.Sprintf("tf-%s", acctest.RandString(5)) ep := fmt.Sprintf("tf-%s", acctest.RandString(5)) username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -184,15 +184,15 @@ resource "pagerduty_user" "foo" { name = "%s" email = "%s" } - + resource "pagerduty_escalation_policy" "foo" { name = "%s" description = "foo" num_loops = 1 - + rule { escalation_delay_in_minutes = 10 - + target { type = "user_reference" id = pagerduty_user.foo.id diff --git a/pagerduty/resource_pagerduty_team_membership_test.go b/pagerduty/resource_pagerduty_team_membership_test.go index ffcc6cff2..a6f0aacbf 100644 --- a/pagerduty/resource_pagerduty_team_membership_test.go +++ b/pagerduty/resource_pagerduty_team_membership_test.go @@ -114,7 +114,7 @@ func testAccCheckPagerDutyTeamMembershipConfig(user, team string) string { return fmt.Sprintf(` resource "pagerduty_user" "foo" { name = "%[1]v" - email = "%[1]v@foo.com" + email = "%[1]v@foo.test" } resource "pagerduty_team" "foo" { @@ -133,7 +133,7 @@ func testAccCheckPagerDutyTeamMembershipWithRoleConfig(user, team, role string) return fmt.Sprintf(` resource "pagerduty_user" "foo" { name = "%[1]v" - email = "%[1]v@foo.com" + email = "%[1]v@foo.test" } resource "pagerduty_team" "foo" { diff --git a/pagerduty/resource_pagerduty_user_contact_method_test.go b/pagerduty/resource_pagerduty_user_contact_method_test.go index 1b173113a..2eb819a79 100644 --- a/pagerduty/resource_pagerduty_user_contact_method_test.go +++ b/pagerduty/resource_pagerduty_user_contact_method_test.go @@ -13,8 +13,8 @@ import ( func TestAccPagerDutyUserContactMethodEmail_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) usernameUpdated := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) - emailUpdated := fmt.Sprintf("%s@foo.com", usernameUpdated) + email := fmt.Sprintf("%s@foo.test", username) + emailUpdated := fmt.Sprintf("%s@foo.test", usernameUpdated) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -40,8 +40,8 @@ func TestAccPagerDutyUserContactMethodEmail_Basic(t *testing.T) { func TestAccPagerDutyUserContactMethodPhone_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) usernameUpdated := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) - emailUpdated := fmt.Sprintf("%s@foo.com", usernameUpdated) + email := fmt.Sprintf("%s@foo.test", username) + emailUpdated := fmt.Sprintf("%s@foo.test", usernameUpdated) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -71,8 +71,8 @@ func TestAccPagerDutyUserContactMethodPhone_Basic(t *testing.T) { func TestAccPagerDutyUserContactMethodSMS_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) usernameUpdated := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) - emailUpdated := fmt.Sprintf("%s@foo.com", usernameUpdated) + email := fmt.Sprintf("%s@foo.test", username) + emailUpdated := fmt.Sprintf("%s@foo.test", usernameUpdated) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, diff --git a/pagerduty/resource_pagerduty_user_notification_rule_test.go b/pagerduty/resource_pagerduty_user_notification_rule_test.go index 6e80e3f6f..59ef06337 100644 --- a/pagerduty/resource_pagerduty_user_notification_rule_test.go +++ b/pagerduty/resource_pagerduty_user_notification_rule_test.go @@ -12,7 +12,7 @@ import ( func TestAccPagerDutyUserNotificationRuleContactMethod_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) contactMethodType1 := "email_contact_method" contactMethodType2 := "phone_contact_method" contactMethodType3 := "sms_contact_method" @@ -46,7 +46,7 @@ func TestAccPagerDutyUserNotificationRuleContactMethod_Basic(t *testing.T) { func TestAccPagerDutyUserNotificationRuleContactMethod_Invalid(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -63,7 +63,7 @@ func TestAccPagerDutyUserNotificationRuleContactMethod_Invalid(t *testing.T) { func TestAccPagerDutyUserNotificationRuleContactMethod_Missing_id(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -80,7 +80,7 @@ func TestAccPagerDutyUserNotificationRuleContactMethod_Missing_id(t *testing.T) func TestAccPagerDutyUserNotificationRuleContactMethod_Missing_type(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -97,7 +97,7 @@ func TestAccPagerDutyUserNotificationRuleContactMethod_Missing_type(t *testing.T func TestAccPagerDutyUserNotificationRuleContactMethod_Unknown_key(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, diff --git a/pagerduty/resource_pagerduty_user_test.go b/pagerduty/resource_pagerduty_user_test.go index 89bd18759..b16d60103 100644 --- a/pagerduty/resource_pagerduty_user_test.go +++ b/pagerduty/resource_pagerduty_user_test.go @@ -56,8 +56,8 @@ func TestAccPagerDutyUser_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) usernameSpaces := " " + username + " " usernameUpdated := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@Foo.com", username) - emailUpdated := fmt.Sprintf("%s@foo.com", usernameUpdated) + email := fmt.Sprintf("%s@foo.test", username) + emailUpdated := fmt.Sprintf("%s@foo.test", usernameUpdated) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -108,7 +108,7 @@ func TestAccPagerDutyUser_Basic(t *testing.T) { func TestAccPagerDutyUserWithTeams_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) team1 := fmt.Sprintf("tf-%s", acctest.RandString(5)) team2 := fmt.Sprintf("tf-%s", acctest.RandString(5)) diff --git a/pagerduty/resource_pagerduty_webhook_subscription_test.go b/pagerduty/resource_pagerduty_webhook_subscription_test.go index 6ea02f17f..dbddad061 100644 --- a/pagerduty/resource_pagerduty_webhook_subscription_test.go +++ b/pagerduty/resource_pagerduty_webhook_subscription_test.go @@ -48,7 +48,7 @@ func testSweepWebhookSubscription(region string) error { func TestAccPagerDutyWebhookSubscription_Basic(t *testing.T) { description := fmt.Sprintf("tf-test-%s", acctest.RandString(5)) username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) @@ -109,38 +109,38 @@ func testAccCheckPagerDutyWebhookSubscriptionExists(n string) resource.TestCheck func testAccCheckPagerDutyWebhookSubscriptionConfig(username, useremail, escalationPolicy, service, description string) string { return fmt.Sprintf(` resource "pagerduty_user" "foo" { - name = "%s" + name = "%s" email = "%s" } - + resource "pagerduty_escalation_policy" "foo" { name = "%s" description = "foo" num_loops = 1 - + rule { escalation_delay_in_minutes = 10 - + target { type = "user_reference" id = pagerduty_user.foo.id } } } - + resource "pagerduty_service" "foo" { name = "%s" description = "foo" auto_resolve_timeout = 1800 acknowledgement_timeout = 1800 escalation_policy = pagerduty_escalation_policy.foo.id - + incident_urgency_rule { type = "constant" urgency = "high" } } - + resource "pagerduty_webhook_subscription" "foo" { delivery_method { type = "http_delivery_method" diff --git a/vendor/go.mongodb.org/mongo-driver/mongo/options/datakeyoptions.go b/vendor/go.mongodb.org/mongo-driver/mongo/options/datakeyoptions.go index c6a17f9e0..3da8f652a 100644 --- a/vendor/go.mongodb.org/mongo-driver/mongo/options/datakeyoptions.go +++ b/vendor/go.mongodb.org/mongo-driver/mongo/options/datakeyoptions.go @@ -22,7 +22,7 @@ func DataKey() *DataKeyOptions { // If being used with a local KMS provider, this option is not applicable and should not be specified. // // For the AWS, Azure, and GCP KMS providers, this option is required and must be a document. For each, the value of the -// "endpoint" or "keyVaultEndpoint" must be a host name with an optional port number (e.g. "foo.com" or "foo.com:443"). +// "endpoint" or "keyVaultEndpoint" must be a host name with an optional port number (e.g. "foo.test" or "foo.test:443"). // // When using AWS, the document must have the format: // { diff --git a/website/docs/r/service_integration.html.markdown b/website/docs/r/service_integration.html.markdown index e50b0e999..c10318699 100644 --- a/website/docs/r/service_integration.html.markdown +++ b/website/docs/r/service_integration.html.markdown @@ -96,7 +96,7 @@ resource "pagerduty_service_integration" "email" { body_mode = "always" body_regex = null from_email_mode = "match" - from_email_regex = "(@foo.com*)" + from_email_regex = "(@foo.test*)" subject_mode = "match" subject_regex = "(CRITICAL*)" } @@ -201,7 +201,7 @@ The following arguments are supported: * `type` - (Required) Can be `between`, `entire` or `regex`. * `part` - (Required) Can be `subject` or `body`. * `value_name` - (Required) First value extractor should have name `incident_key` other value extractors should contain custom names. - * `ends_before` - (Optional) + * `ends_before` - (Optional) * `starts_after` - (Optional) * `regex` - (Optional) If `type` has value `regex` this value should contain valid regex. From 802e4e411b0c91eecfc0c8d2e8d45ffba9d1abc3 Mon Sep 17 00:00:00 2001 From: Marcos Wright-Kuhns Date: Fri, 6 May 2022 10:01:39 -0700 Subject: [PATCH 15/63] Add instructions about running an individual test to the README --- README.md | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index ee79b47a2..808fabf77 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -Terraform Provider for PagerDuty -================================ +# Terraform Provider for PagerDuty - Website: https://registry.terraform.io/providers/PagerDuty/pagerduty/latest - Documentation: https://registry.terraform.io/providers/PagerDuty/pagerduty/latest/docs @@ -8,14 +7,12 @@ Terraform Provider for PagerDuty [PagerDuty](https://www.pagerduty.com/) is an alarm aggregation and dispatching service for system administrators and support teams. It collects alerts from your monitoring tools, gives you an overall view of all of your monitoring alarms, and alerts an on duty engineer if there’s a problem. The Terraform Pagerduty provider is a plugin for Terraform that allows for the management of PagerDuty resources using HCL (HashiCorp Configuration Language). -Requirements ------------- +## Requirements - [Terraform](https://www.terraform.io/downloads.html) 0.12.x - [Go](https://golang.org/doc/install) 1.11 (to build the provider plugin) -Building The Provider ---------------------- +## Building The Provider Clone repository to: `$GOPATH/src/github.com/terraform-providers/terraform-provider-pagerduty` @@ -31,14 +28,13 @@ $ cd $GOPATH/src/github.com/PagerDuty/terraform-provider-pagerduty $ make build ``` -Using the provider ----------------------- +## Using the provider + Please refer to https://registry.terraform.io/providers/PagerDuty/pagerduty/latest/docs for examples on how to use the provider and detailed documentation about the Resources and Data Sources the provider has. -Developing the Provider ---------------------------- +## Developing the Provider If you wish to work on the provider, you'll first need [Go](http://www.golang.org) installed on your machine (version 1.11+ is *required*). You'll also need to correctly setup a [GOPATH](http://golang.org/doc/code.html#GOPATH), as well as adding `$GOPATH/bin` to your `$PATH`. @@ -51,6 +47,8 @@ $ $GOPATH/bin/terraform-provider-pagerduty ... ``` +### Testing + In order to test the provider, you can simply run `make test`. ```sh @@ -65,4 +63,10 @@ In order to run the full suite of Acceptance tests, run `make testacc`. $ make testacc ``` -*Additional Note:* In order for the tests on the Slack Connection resources to pass you will need valid Slack workspace and channel IDs from a [Slack workspace connected to your PagerDuty account](https://support.pagerduty.com/docs/slack-integration-guide#integration-walkthrough). \ No newline at end of file +*Additional Note:* In order for the tests on the Slack Connection resources to pass you will need valid Slack workspace and channel IDs from a [Slack workspace connected to your PagerDuty account](https://support.pagerduty.com/docs/slack-integration-guide#integration-walkthrough). + +Run a specific subset of tests by name use the `TESTARGS="-run TestName"` option which will run all test functions with "TestName" in their name. + +```sh +$ make testacc TESTARGS="-run TestAccPagerDutyTeam" +``` From e9f106d61bf62e239b2d3048255372cdb8abe9ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Antonio=20Reyes?= Date: Thu, 12 May 2022 17:57:45 -0400 Subject: [PATCH 16/63] update slack integration docs --- website/docs/r/slack_connection.html.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/r/slack_connection.html.markdown b/website/docs/r/slack_connection.html.markdown index 8cfcbbc54..a7a2702b0 100644 --- a/website/docs/r/slack_connection.html.markdown +++ b/website/docs/r/slack_connection.html.markdown @@ -13,6 +13,7 @@ A [slack connection](https://developer.pagerduty.com/api-reference/YXBpOjExMjA5N **NOTES for using this resource:** * To first use this resource you will need to [map your PagerDuty account to a valid Slack Workspace](https://support.pagerduty.com/docs/slack-integration-guide#integration-walkthrough). *This can only be done through the PagerDuty UI.* * This resource requires a PagerDuty [user-level API key](https://support.pagerduty.com/docs/generating-api-keys#section-generating-a-personal-rest-api-key). This can be set as the `user_token` on the provider tag or as the `PAGERDUTY_USER_TOKEN` environment variable. +* If you configured your Slack integration (V1 or V2) prior to August 10, 2021, you may migrate to the Slack V2 Next Generation update using this [migration instructions](https://support.pagerduty.com/docs/slack-integration-guide#migrate-to-slack-v2-next-generation), but if you configured your Slack integration after that date, you will have access to the update out of the box. ## Example Usage ```hcl From c33688e5e7673547d20430e0fef04d9fd30d7e9f Mon Sep 17 00:00:00 2001 From: Peter Mescalchin Date: Fri, 13 May 2022 17:09:13 +1000 Subject: [PATCH 17/63] Fix Terraform `user` -> `user_reference` example typo for `pagerduty_escalation_policy` resource --- website/docs/r/escalation_policy.html.markdown | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/website/docs/r/escalation_policy.html.markdown b/website/docs/r/escalation_policy.html.markdown index cf31d3198..9dcab3324 100644 --- a/website/docs/r/escalation_policy.html.markdown +++ b/website/docs/r/escalation_policy.html.markdown @@ -33,11 +33,11 @@ resource "pagerduty_escalation_policy" "example" { rule { escalation_delay_in_minutes = 10 target { - type = "user" + type = "user_reference" id = pagerduty_user.example.id } target { - type = "user" + type = "user_reference" id = pagerduty_user.example2.id } } @@ -55,13 +55,11 @@ The following arguments are supported: * `num_loops` - (Optional) The number of times the escalation policy will repeat after reaching the end of its escalation. * `rule` - (Required) An Escalation rule block. Escalation rules documented below. - Escalation rules (`rule`) supports the following: * `escalation_delay_in_minutes` - (Required) The number of minutes before an unacknowledged incident escalates away from this rule. * `targets` - (Required) A target block. Target blocks documented below. - Targets (`target`) supports the following: * `type` - (Optional) Can be `user_reference` or `schedule_reference`. Defaults to `user_reference`. For multiple users as example, repeat the target. From 2cf936efb976b66e81ba2430cb8e7819502d1fcd Mon Sep 17 00:00:00 2001 From: Scott McAllister Date: Fri, 13 May 2022 17:15:02 -0700 Subject: [PATCH 18/63] Update slack_connection.html.markdown Small tweak to the message added to the docs. --- website/docs/r/slack_connection.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/slack_connection.html.markdown b/website/docs/r/slack_connection.html.markdown index a7a2702b0..94fa09194 100644 --- a/website/docs/r/slack_connection.html.markdown +++ b/website/docs/r/slack_connection.html.markdown @@ -13,7 +13,7 @@ A [slack connection](https://developer.pagerduty.com/api-reference/YXBpOjExMjA5N **NOTES for using this resource:** * To first use this resource you will need to [map your PagerDuty account to a valid Slack Workspace](https://support.pagerduty.com/docs/slack-integration-guide#integration-walkthrough). *This can only be done through the PagerDuty UI.* * This resource requires a PagerDuty [user-level API key](https://support.pagerduty.com/docs/generating-api-keys#section-generating-a-personal-rest-api-key). This can be set as the `user_token` on the provider tag or as the `PAGERDUTY_USER_TOKEN` environment variable. -* If you configured your Slack integration (V1 or V2) prior to August 10, 2021, you may migrate to the Slack V2 Next Generation update using this [migration instructions](https://support.pagerduty.com/docs/slack-integration-guide#migrate-to-slack-v2-next-generation), but if you configured your Slack integration after that date, you will have access to the update out of the box. +* This resource is for configuring Slack V2 Next Generation connections. If you configured your Slack integration (V1 or V2) prior to August 10, 2021, you may migrate to the Slack V2 Next Generation update using this [migration instructions](https://support.pagerduty.com/docs/slack-integration-guide#migrate-to-slack-v2-next-generation), but if you configured your Slack integration after that date, you will have access to the update out of the box. ## Example Usage ```hcl From 1aa5336733e00c73654e509a73942421a4fea0a3 Mon Sep 17 00:00:00 2001 From: jedelson-pagerduty <103767938+jedelson-pagerduty@users.noreply.github.com> Date: Thu, 19 May 2022 14:23:02 -0400 Subject: [PATCH 19/63] Add some additional requirements for running acceptance tests --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 808fabf77..9f3e72e14 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,11 @@ In order to test the provider, you can simply run `make test`. $ make test ``` -In order to run the full suite of Acceptance tests, run `make testacc`. +In order to run the full suite of Acceptance tests, run `make testacc`. Running the acceptance tests requires +that the `PAGERDUTY_TOKEN` environment variable be set to a valid API Token and that the +`PAGERDUTY_USER_TOKEN` environment variable be set to a valid API User Token. Many tests also +require that the [Email Domain Restriction](https://support.pagerduty.com/docs/account-settings#email-domain-restriction) feature +either be disabled *or* be configured to include `foo.test` as an allowed domain. *Note:* Acceptance tests create real resources, and often cost money to run. From 20ddd9c9c70c9207875f0d4af811bc2d7594dd44 Mon Sep 17 00:00:00 2001 From: Scott McAllister Date: Fri, 20 May 2022 12:13:08 -0700 Subject: [PATCH 20/63] removing 429 check on ep and ruleset data --- pagerduty/data_source_pagerduty_escalation_policy.go | 12 ++++-------- pagerduty/data_source_pagerduty_ruleset.go | 12 ++++-------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/pagerduty/data_source_pagerduty_escalation_policy.go b/pagerduty/data_source_pagerduty_escalation_policy.go index 4a68de007..4c27ace8d 100644 --- a/pagerduty/data_source_pagerduty_escalation_policy.go +++ b/pagerduty/data_source_pagerduty_escalation_policy.go @@ -40,14 +40,10 @@ func dataSourcePagerDutyEscalationPolicyRead(d *schema.ResourceData, meta interf return resource.Retry(5*time.Minute, func() *resource.RetryError { resp, _, err := client.EscalationPolicies.List(o) if err != nil { - if isErrCode(err, 429) { - // Delaying retry by 30s as recommended by PagerDuty - // https://developer.pagerduty.com/docs/rest-api-v2/rate-limiting/#what-are-possible-workarounds-to-the-events-api-rate-limit - time.Sleep(30 * time.Second) - return resource.RetryableError(err) - } - - return resource.NonRetryableError(err) + // Delaying retry by 30s as recommended by PagerDuty + // https://developer.pagerduty.com/docs/rest-api-v2/rate-limiting/#what-are-possible-workarounds-to-the-events-api-rate-limit + time.Sleep(30 * time.Second) + return resource.RetryableError(err) } var found *pagerduty.EscalationPolicy diff --git a/pagerduty/data_source_pagerduty_ruleset.go b/pagerduty/data_source_pagerduty_ruleset.go index f4df0d6ed..5e902274e 100644 --- a/pagerduty/data_source_pagerduty_ruleset.go +++ b/pagerduty/data_source_pagerduty_ruleset.go @@ -43,14 +43,10 @@ func dataSourcePagerDutyRulesetRead(d *schema.ResourceData, meta interface{}) er return resource.Retry(5*time.Minute, func() *resource.RetryError { resp, _, err := client.Rulesets.List() if err != nil { - if isErrCode(err, 429) { - // Delaying retry by 30s as recommended by PagerDuty - // https://developer.pagerduty.com/docs/rest-api-v2/rate-limiting/#what-are-possible-workarounds-to-the-events-api-rate-limit - time.Sleep(30 * time.Second) - return resource.RetryableError(err) - } - - return resource.NonRetryableError(err) + // Delaying retry by 30s as recommended by PagerDuty + // https://developer.pagerduty.com/docs/rest-api-v2/rate-limiting/#what-are-possible-workarounds-to-the-events-api-rate-limit + time.Sleep(30 * time.Second) + return resource.RetryableError(err) } var found *pagerduty.Ruleset From 9ddf6cecfd1b995da94f3861a4f59093c09fa674 Mon Sep 17 00:00:00 2001 From: Scott McAllister Date: Fri, 20 May 2022 14:12:40 -0700 Subject: [PATCH 21/63] Update CHANGELOG.md --- CHANGELOG.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b0725948..ab8225a49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,16 @@ -## 2.4.2 (Unreleased) +## 2.4.2 (May 20, 2022) IMPROVEMENTS: -* Use "@foo.test" email addresses in tests +* Acceptance Test Improvements: Use "@foo.test" email addresses in tests. ([#491](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/491)) +* Acceptance Test Improvements: Adding better notes to README on running ACC ([#503](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/503)) +* `resource/pagerduty_ruleset_rule`: Introduce support for `catch_all` rules. ([#481](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/481)) +* Docs: `resource/pagerduty_slack_connection`: Improved notes on resource supporting Slack V2 Next Generation ([#496](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/496)) + +BUG FIXES: +* Documentation: Fixed all broken links to the PagerDuty API documentation ([#464](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/464)) +* Docs: `resource/pagerduty_escalation_policy`: Fixed `user` -> `user_reference` in samples ([#497](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/497)) +* Build Process: Include `timezdata` build tag in goreleaser config ([#488](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/488)) +* `data_source/pagerduty_escalation_policy`,`data_source/pagerduty_ruleset`: Changed logic to retry on all errors returned by PD API. Remedies GOAWAY error. ([#507](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/507)) ## 2.4.1 (April 22, 2022) IMPROVEMENTS: From 2b63b8a2c55a243b04c843e81577035e019e6738 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Antonio=20Reyes?= Date: Mon, 23 May 2022 20:16:58 -0400 Subject: [PATCH 22/63] change users paginated listing by list all --- pagerduty/data_source_pagerduty_user.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pagerduty/data_source_pagerduty_user.go b/pagerduty/data_source_pagerduty_user.go index fbea4c541..cb94a7661 100644 --- a/pagerduty/data_source_pagerduty_user.go +++ b/pagerduty/data_source_pagerduty_user.go @@ -42,7 +42,7 @@ func dataSourcePagerDutyUserRead(d *schema.ResourceData, meta interface{}) error } return resource.Retry(5*time.Minute, func() *resource.RetryError { - resp, _, err := client.Users.List(o) + resp, err := client.Users.ListAll(o) if err != nil { if isErrCode(err, 429) { // Delaying retry by 30s as recommended by PagerDuty @@ -54,9 +54,9 @@ func dataSourcePagerDutyUserRead(d *schema.ResourceData, meta interface{}) error return resource.NonRetryableError(err) } - var found *pagerduty.User + var found *pagerduty.FullUser - for _, user := range resp.Users { + for _, user := range resp { if user.Email == searchEmail { found = user break From d1c22c1c10dd050311a2280e79b9c7c832693d75 Mon Sep 17 00:00:00 2001 From: alenapan <47909261+alenapan@users.noreply.github.com> Date: Wed, 1 Jun 2022 16:29:28 -0400 Subject: [PATCH 23/63] [ORCA-3444] Add support for Event Orchestrations (#512) * ORCA-3459 - event orchestration resource * reformat * [REVERT LATER] Temporarily pointing to the local copy of go-pagerduty * rename Orchestration references to EventOrchestration * add more properties, mapping logic; add tests * more tests to event_orchestration_resource * add datasource event orchestration * [REVERT LATER]-local testing * fix create logic (set integrations), remove description and routes from orchestration data source * fix data source, add data source tests * reformat * Add import tests * update to latest alenapan/go-pagerduty * add team checks to the tests * [ORCA-3475] Allow deleting event orchestration team from an orchestration (#494) * support unsetting orch team * add retry logic to the event orchestration update method * [ORCA-3463] Orchestration Path Router Resource (#493) * router path * Add support for parent * refactor * update handler and actions support * support conditions * move conditions to util * move parent to util * test for multiple rules and conditions * actions and catchall * refactor tests * validateFunc * refactor * undo local vendor module path change * rules schema change and test * PR comments addressed * Event orchestration unrouted resource (#495) * Init commit for unrouted * Added tests for unrouted * Added catch_all to unrouted schema * Tweaked catch_all * Merge event-orchestrations * Add testacc for unrouted * Added full config test for unrouted * Add test for number of extractions and variables * Cleaned router and added new test checks to unrouted * Change escalation_policy from snake case to camel case * make type computed and set it on read/update * Orca 3486 refactor (#500) * Clean sweeper function for router/unrouted * Clean sweeper function * [ORCA-3465] - Event Orchestration Service path resource (#499) * ORCA-3465 - Event Orchestration Service Path resource * add resource file * fix read/update, add test * more tests * more service path tests, add conditions * more tests * more tests * add more service path props * fix orch path PUT payload, add tests * fix Suspend * ToDos * add catch_all support, fix tests * add support for regex extractions, add mor tests, add service path import test * update client * PR feedback * Flatten teams block (#506) * Flatten teams block * Fixed naming for the test orchestration * ORCA-3486 - remove team attribute from service path * flatten/rename parent to 'service' for service path * remove type attribute from unrouted * remove type attribute from router * flatten/rename parent to 'event_orchestration' for router * set event_orchestration attr on router import * flatten/rename parent to 'event_orchestration' for unrouted * Clean teams block * revert changes on web file * [ORCA-3486] - Reuse shared Event Orchestration Path logic, add import tests (#509) * ORCA-3486 - add import tests for router/unrouted * ORCA-3486 - add import tests for router, unrouted * reuse severity/event_action validation functions in unrouted/service * reuse variables and extractions schema in router/unrouted * reuse shared conditions schema and mapping functions in router/unrouted/service * [ORCA-3486] Extend unrouted tests, add CustomizeDiff, clean shared functions (#510) * Extend unrouted tests, add CustomizeDiff, clean shared functions * Move shared functions for unrouted and service paths to utils file * orchestration and path resource documentation * datasource documentation * refactor * update comment * update type field documentation * update documentation * cleanup * Remove mention of the suppress action from event_orchestration_unrouted docs * Add "Optional" info to 1 attribute in event_orchestration_service docs * give a better datasource example * cleanup * Add Event Orchestration info to the CHANGELOG (release date TBD) (#514) * update go-pagerduty package * Router - make sets, rules, conditions singular * Unrouted, Service - make sets, rules, conditions, variables, extractions, pd_automation_actions, automations_action (headers, params) singular * Event Orchestration - make integrations singular * update Event Orchestration documentation * EO data source - retry on any error * EO data source - retry on any error Co-authored-by: Pari Dhanakoti Co-authored-by: Alex Zakabluk Co-authored-by: Marcos Wright-Kuhns Co-authored-by: Scott McAllister --- CHANGELOG.md | 9 + go.mod | 2 +- go.sum | 4 + ...ta_source_pagerduty_event_orchestration.go | 102 +++ ...urce_pagerduty_event_orchestration_test.go | 64 ++ pagerduty/event_orchestration_path_util.go | 225 ++++++ ...ty_event_orchestration_path_router_test.go | 38 + ...y_event_orchestration_path_service_test.go | 36 + ..._event_orchestration_path_unrouted_test.go | 38 + ...port_pagerduty_event_orchestration_test.go | 53 ++ pagerduty/provider.go | 55 +- .../resource_pagerduty_event_orchestration.go | 240 ++++++ ...gerduty_event_orchestration_path_router.go | 335 ++++++++ ...ty_event_orchestration_path_router_test.go | 428 ++++++++++ ...erduty_event_orchestration_path_service.go | 555 +++++++++++++ ...y_event_orchestration_path_service_test.go | 733 ++++++++++++++++++ ...rduty_event_orchestration_path_unrouted.go | 445 +++++++++++ ..._event_orchestration_path_unrouted_test.go | 549 +++++++++++++ ...urce_pagerduty_event_orchestration_test.go | 245 ++++++ pagerduty/util.go | 7 + .../pagerduty/event_orchestration.go | 127 +++ .../pagerduty/event_orchestration_path.go | 147 ++++ .../go-pagerduty/pagerduty/pagerduty.go | 4 + .../mongo/options/datakeyoptions.go | 2 +- vendor/modules.txt | 2 +- .../docs/d/event_orchestration.html.markdown | 60 ++ .../docs/r/event_orchestration.html.markdown | 52 ++ .../event_orchestration_router.html.markdown | 93 +++ .../event_orchestration_service.html.markdown | 215 +++++ ...event_orchestration_unrouted.html.markdown | 102 +++ 30 files changed, 4939 insertions(+), 28 deletions(-) create mode 100644 pagerduty/data_source_pagerduty_event_orchestration.go create mode 100644 pagerduty/data_source_pagerduty_event_orchestration_test.go create mode 100644 pagerduty/event_orchestration_path_util.go create mode 100644 pagerduty/import_pagerduty_event_orchestration_path_router_test.go create mode 100644 pagerduty/import_pagerduty_event_orchestration_path_service_test.go create mode 100644 pagerduty/import_pagerduty_event_orchestration_path_unrouted_test.go create mode 100644 pagerduty/import_pagerduty_event_orchestration_test.go create mode 100644 pagerduty/resource_pagerduty_event_orchestration.go create mode 100644 pagerduty/resource_pagerduty_event_orchestration_path_router.go create mode 100644 pagerduty/resource_pagerduty_event_orchestration_path_router_test.go create mode 100644 pagerduty/resource_pagerduty_event_orchestration_path_service.go create mode 100644 pagerduty/resource_pagerduty_event_orchestration_path_service_test.go create mode 100644 pagerduty/resource_pagerduty_event_orchestration_path_unrouted.go create mode 100644 pagerduty/resource_pagerduty_event_orchestration_path_unrouted_test.go create mode 100644 pagerduty/resource_pagerduty_event_orchestration_test.go create mode 100644 vendor/github.com/heimweh/go-pagerduty/pagerduty/event_orchestration.go create mode 100644 vendor/github.com/heimweh/go-pagerduty/pagerduty/event_orchestration_path.go create mode 100644 website/docs/d/event_orchestration.html.markdown create mode 100644 website/docs/r/event_orchestration.html.markdown create mode 100644 website/docs/r/event_orchestration_router.html.markdown create mode 100644 website/docs/r/event_orchestration_service.html.markdown create mode 100644 website/docs/r/event_orchestration_unrouted.html.markdown diff --git a/CHANGELOG.md b/CHANGELOG.md index ab8225a49..b5dfe244f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +## 2.5.0 (June 1, 2022) + +FEATURES: +* Support for Event Orchestration via several new resources. ([#512](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/512)) + * `resource/pagerduty_event_orchestration` + * `resource/pagerduty_event_orchestration_router` + * `resource/pagerduty_event_orchestration_unrouted` + * `resource/pagerduty_event_orchestration_service` + ## 2.4.2 (May 20, 2022) IMPROVEMENTS: diff --git a/go.mod b/go.mod index b3380923d..c5f0bc0d2 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.16 require ( cloud.google.com/go v0.71.0 // indirect github.com/hashicorp/terraform-plugin-sdk/v2 v2.10.1 - github.com/heimweh/go-pagerduty v0.0.0-20220422231448-43095fe5ba3f + github.com/heimweh/go-pagerduty v0.0.0-20220527195341-4e587aa9b58e golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd // indirect google.golang.org/api v0.35.0 // indirect google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb // indirect diff --git a/go.sum b/go.sum index 9c893f216..dd09ff741 100644 --- a/go.sum +++ b/go.sum @@ -286,6 +286,10 @@ github.com/heimweh/go-pagerduty v0.0.0-20220208023456-83fe435832fb h1:p3faOVCU8L github.com/heimweh/go-pagerduty v0.0.0-20220208023456-83fe435832fb/go.mod h1:JtJGtgN0y9KOCaqFMZFaBCWskpO/KK3Ro9TwjP9ss6w= github.com/heimweh/go-pagerduty v0.0.0-20220422231448-43095fe5ba3f h1:NLk7iDq85F2lz0q1gY32vZR506aYiNcgvV+Us1rX1q4= github.com/heimweh/go-pagerduty v0.0.0-20220422231448-43095fe5ba3f/go.mod h1:JtJGtgN0y9KOCaqFMZFaBCWskpO/KK3Ro9TwjP9ss6w= +github.com/heimweh/go-pagerduty v0.0.0-20220428180718-5a69bb821163 h1:ETKxW+KSjOPaRzZU9f+QrjCkrL7hQqtMPKDv8DnLDO4= +github.com/heimweh/go-pagerduty v0.0.0-20220428180718-5a69bb821163/go.mod h1:JtJGtgN0y9KOCaqFMZFaBCWskpO/KK3Ro9TwjP9ss6w= +github.com/heimweh/go-pagerduty v0.0.0-20220527195341-4e587aa9b58e h1:xit0rQWTVlM9ohz4IzrddDKglC7jey+m3GSI/bz3TIw= +github.com/heimweh/go-pagerduty v0.0.0-20220527195341-4e587aa9b58e/go.mod h1:JtJGtgN0y9KOCaqFMZFaBCWskpO/KK3Ro9TwjP9ss6w= github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= diff --git a/pagerduty/data_source_pagerduty_event_orchestration.go b/pagerduty/data_source_pagerduty_event_orchestration.go new file mode 100644 index 000000000..0e42d5a80 --- /dev/null +++ b/pagerduty/data_source_pagerduty_event_orchestration.go @@ -0,0 +1,102 @@ +package pagerduty + +import ( + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/heimweh/go-pagerduty/pagerduty" +) + +func dataSourcePagerDutyEventOrchestration() *schema.Resource { + return &schema.Resource{ + Read: dataSourcePagerDutyEventOrchestrationRead, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "integration": { + Type: schema.TypeList, + Computed: true, + Optional: true, // Tests keep failing if "Optional: true" is not provided + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + "parameters": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "routing_key": { + Type: schema.TypeString, + Computed: true, + }, + "type": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourcePagerDutyEventOrchestrationRead(d *schema.ResourceData, meta interface{}) error { + client, err := meta.(*Config).Client() + if err != nil { + return err + } + + log.Printf("[INFO] Reading PagerDuty Event Orchestration") + + searchName := d.Get("name").(string) + + return resource.Retry(5*time.Minute, func() *resource.RetryError { + resp, _, err := client.EventOrchestrations.List() + if err != nil { + return resource.RetryableError(err) + } + + var found *pagerduty.EventOrchestration + + for _, orchestration := range resp.Orchestrations { + if orchestration.Name == searchName { + found = orchestration + break + } + } + + if found == nil { + return resource.NonRetryableError( + fmt.Errorf("Unable to locate any Event Orchestration with the name: %s", searchName), + ) + } + + // Get the found orchestration by ID so we can set the integrations property + // since the list ndpoint does not return it + orch, _, err := client.EventOrchestrations.Get(found.ID) + if err != nil { + return resource.RetryableError(err) + } + + d.SetId(orch.ID) + d.Set("name", orch.Name) + + if len(orch.Integrations) > 0 { + d.Set("integration", flattenEventOrchestrationIntegrations(orch.Integrations)) + } + + return nil + }) +} diff --git a/pagerduty/data_source_pagerduty_event_orchestration_test.go b/pagerduty/data_source_pagerduty_event_orchestration_test.go new file mode 100644 index 000000000..554c19037 --- /dev/null +++ b/pagerduty/data_source_pagerduty_event_orchestration_test.go @@ -0,0 +1,64 @@ +package pagerduty + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccDataSourcePagerDutyEventOrchestration_Basic(t *testing.T) { + name := fmt.Sprintf("tf-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourcePagerDutyEventOrchestrationConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccDataSourcePagerDutyEventOrchestration("pagerduty_event_orchestration.test", "data.pagerduty_event_orchestration.by_name"), + ), + }, + }, + }) +} + +func testAccDataSourcePagerDutyEventOrchestration(src, n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + + srcR := s.RootModule().Resources[src] + srcA := srcR.Primary.Attributes + + r := s.RootModule().Resources[n] + a := r.Primary.Attributes + + if a["id"] == "" { + return fmt.Errorf("Expected to get an Event Orchestration ID from PagerDuty") + } + + testAtts := []string{"id", "name", "integration"} + + for _, att := range testAtts { + if a[att] != srcA[att] { + return fmt.Errorf("Expected the Event Orchestration %s to be: %s, but got: %s", att, srcA[att], a[att]) + } + } + + return nil + } +} + +func testAccDataSourcePagerDutyEventOrchestrationConfig(name string) string { + return fmt.Sprintf(` +resource "pagerduty_event_orchestration" "test" { + name = "%s" +} + +data "pagerduty_event_orchestration" "by_name" { + name = pagerduty_event_orchestration.test.name +} +`, name) +} diff --git a/pagerduty/event_orchestration_path_util.go b/pagerduty/event_orchestration_path_util.go new file mode 100644 index 000000000..7f5bc6f65 --- /dev/null +++ b/pagerduty/event_orchestration_path_util.go @@ -0,0 +1,225 @@ +package pagerduty + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/heimweh/go-pagerduty/pagerduty" +) + +var eventOrchestrationPathConditionsSchema = map[string]*schema.Schema{ + "expression": { + Type: schema.TypeString, + Required: true, + }, +} + +var eventOrchestrationPathVariablesSchema = map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "path": { + Type: schema.TypeString, + Required: true, + }, + "type": { + Type: schema.TypeString, + Required: true, + }, + "value": { + Type: schema.TypeString, + Required: true, + }, +} + +var eventOrchestrationPathExtractionsSchema = map[string]*schema.Schema{ + "regex": { + Type: schema.TypeString, + Optional: true, + }, + "source": { + Type: schema.TypeString, + Optional: true, + }, + "target": { + Type: schema.TypeString, + Required: true, + }, + "template": { + Type: schema.TypeString, + Optional: true, + }, +} + +func invalidExtractionRegexTemplateNilConfig() string { + return ` + extraction { + target = "event.summary" + }` +} + +func invalidExtractionRegexTemplateValConfig() string { + return ` + extraction { + regex = ".*" + template = "hi" + target = "event.summary" + }` +} + +func invalidExtractionRegexNilSourceConfig() string { + return ` + extraction { + regex = ".*" + target = "event.summary" + }` +} + +func validateEventOrchestrationPathSeverity() schema.SchemaValidateFunc { + return validateValueFunc([]string{ + "info", + "error", + "warning", + "critical", + }) +} + +func validateEventOrchestrationPathEventAction() schema.SchemaValidateFunc { + return validateValueFunc([]string{ + "trigger", + "resolve", + }) +} + +func checkExtractions(context context.Context, diff *schema.ResourceDiff, i interface{}) error { + sn := diff.Get("set.#").(int) + + for si := 0; si < sn; si++ { + rn := diff.Get(fmt.Sprintf("set.%d.rule.#", si)).(int) + for ri := 0; ri < rn; ri++ { + res := checkExtractionAttributes(diff, fmt.Sprintf("set.%d.rule.%d.actions.0.extraction", si, ri)) + if res != nil { + return res + } + } + } + return checkExtractionAttributes(diff, "catch_all.0.actions.0.extraction") +} + +func checkExtractionAttributes(diff *schema.ResourceDiff, loc string) error { + num := diff.Get(fmt.Sprintf("%s.#", loc)).(int) + for i := 0; i < num; i++ { + prefix := fmt.Sprintf("%s.%d", loc, i) + r := diff.Get(fmt.Sprintf("%s.regex", prefix)).(string) + t := diff.Get(fmt.Sprintf("%s.template", prefix)).(string) + + if r == "" && t == "" { + return fmt.Errorf("Invalid configuration in %s: regex and template cannot both be null", prefix) + } + if r != "" && t != "" { + return fmt.Errorf("Invalid configuration in %s: regex and template cannot both have values", prefix) + } + + s := diff.Get(fmt.Sprintf("%s.source", prefix)).(string) + if r != "" && s == "" { + return fmt.Errorf("Invalid configuration in %s: source can't be blank", prefix) + } + } + return nil +} + +func expandEventOrchestrationPathConditions(v interface{}) []*pagerduty.EventOrchestrationPathRuleCondition { + conditions := []*pagerduty.EventOrchestrationPathRuleCondition{} + + for _, cond := range v.([]interface{}) { + c := cond.(map[string]interface{}) + + cx := &pagerduty.EventOrchestrationPathRuleCondition{ + Expression: c["expression"].(string), + } + + conditions = append(conditions, cx) + } + + return conditions +} + +func flattenEventOrchestrationPathConditions(conditions []*pagerduty.EventOrchestrationPathRuleCondition) []interface{} { + var flattendConditions []interface{} + + for _, condition := range conditions { + flattendCondition := map[string]interface{}{ + "expression": condition.Expression, + } + flattendConditions = append(flattendConditions, flattendCondition) + } + + return flattendConditions +} + +func expandEventOrchestrationPathVariables(v interface{}) []*pagerduty.EventOrchestrationPathActionVariables { + res := []*pagerduty.EventOrchestrationPathActionVariables{} + + for _, er := range v.([]interface{}) { + rer := er.(map[string]interface{}) + + av := &pagerduty.EventOrchestrationPathActionVariables{ + Name: rer["name"].(string), + Path: rer["path"].(string), + Type: rer["type"].(string), + Value: rer["value"].(string), + } + + res = append(res, av) + } + + return res +} + +func flattenEventOrchestrationPathVariables(v []*pagerduty.EventOrchestrationPathActionVariables) []interface{} { + var res []interface{} + + for _, s := range v { + fv := map[string]interface{}{ + "name": s.Name, + "path": s.Path, + "type": s.Type, + "value": s.Value, + } + res = append(res, fv) + } + return res +} + +func expandEventOrchestrationPathExtractions(v interface{}) []*pagerduty.EventOrchestrationPathActionExtractions { + res := []*pagerduty.EventOrchestrationPathActionExtractions{} + + for _, eai := range v.([]interface{}) { + ea := eai.(map[string]interface{}) + ext := &pagerduty.EventOrchestrationPathActionExtractions{ + Target: ea["target"].(string), + Regex: ea["regex"].(string), + Template: ea["template"].(string), + Source: ea["source"].(string), + } + res = append(res, ext) + } + return res +} + +func flattenEventOrchestrationPathExtractions(e []*pagerduty.EventOrchestrationPathActionExtractions) []interface{} { + var res []interface{} + + for _, s := range e { + e := map[string]interface{}{ + "target": s.Target, + "regex": s.Regex, + "template": s.Template, + "source": s.Source, + } + res = append(res, e) + } + return res +} diff --git a/pagerduty/import_pagerduty_event_orchestration_path_router_test.go b/pagerduty/import_pagerduty_event_orchestration_path_router_test.go new file mode 100644 index 000000000..976e80057 --- /dev/null +++ b/pagerduty/import_pagerduty_event_orchestration_path_router_test.go @@ -0,0 +1,38 @@ +package pagerduty + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccPagerDutyEventOrchestrationPathRouter_import(t *testing.T) { + team := fmt.Sprintf("tf-name-%s", acctest.RandString(5)) + escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) + service := fmt.Sprintf("tf-%s", acctest.RandString(5)) + orchestration := fmt.Sprintf("tf-orchestration-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckPagerDutyEventOrchestrationRouterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckPagerDutyEventOrchestrationRouterConfigWithMultipleRules(team, escalationPolicy, service, orchestration), + }, + { + ResourceName: "pagerduty_event_orchestration_router.router", + ImportStateIdFunc: testAccCheckPagerDutyEventOrchestrationPathRouterID, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckPagerDutyEventOrchestrationPathRouterID(s *terraform.State) (string, error) { + return s.RootModule().Resources["pagerduty_event_orchestration.orch"].Primary.ID, nil +} diff --git a/pagerduty/import_pagerduty_event_orchestration_path_service_test.go b/pagerduty/import_pagerduty_event_orchestration_path_service_test.go new file mode 100644 index 000000000..579d2c957 --- /dev/null +++ b/pagerduty/import_pagerduty_event_orchestration_path_service_test.go @@ -0,0 +1,36 @@ +package pagerduty + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccPagerDutyEventOrchestrationPathService_import(t *testing.T) { + escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) + service := fmt.Sprintf("tf-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckPagerDutyEventOrchestrationServicePathDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckPagerDutyEventOrchestrationPathServiceAllActionsConfig(escalationPolicy, service), + }, + { + ResourceName: "pagerduty_event_orchestration_service.serviceA", + ImportStateIdFunc: testAccCheckPagerDutyEventOrchestrationPathServiceID, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckPagerDutyEventOrchestrationPathServiceID(s *terraform.State) (string, error) { + return s.RootModule().Resources["pagerduty_service.bar"].Primary.ID, nil +} diff --git a/pagerduty/import_pagerduty_event_orchestration_path_unrouted_test.go b/pagerduty/import_pagerduty_event_orchestration_path_unrouted_test.go new file mode 100644 index 000000000..9ab539ba4 --- /dev/null +++ b/pagerduty/import_pagerduty_event_orchestration_path_unrouted_test.go @@ -0,0 +1,38 @@ +package pagerduty + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccPagerDutyEventOrchestrationPathUnrouted_import(t *testing.T) { + team := fmt.Sprintf("tf-name-%s", acctest.RandString(5)) + escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) + service := fmt.Sprintf("tf-%s", acctest.RandString(5)) + orchestration := fmt.Sprintf("tf-orchestration-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckPagerDutyEventOrchestrationPathUnroutedDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckPagerDutyEventOrchestrationPathUnroutedWithAllConfig(team, escalationPolicy, service, orchestration), + }, + { + ResourceName: "pagerduty_event_orchestration_unrouted.unrouted", + ImportStateIdFunc: testAccCheckPagerDutyEventOrchestrationPathUnroutedID, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckPagerDutyEventOrchestrationPathUnroutedID(s *terraform.State) (string, error) { + return s.RootModule().Resources["pagerduty_event_orchestration.orch"].Primary.ID, nil +} diff --git a/pagerduty/import_pagerduty_event_orchestration_test.go b/pagerduty/import_pagerduty_event_orchestration_test.go new file mode 100644 index 000000000..d6b7c8d14 --- /dev/null +++ b/pagerduty/import_pagerduty_event_orchestration_test.go @@ -0,0 +1,53 @@ +package pagerduty + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccPagerDutyEventOrchestration_import(t *testing.T) { + name := fmt.Sprintf("tf-name-%s", acctest.RandString(5)) + description := fmt.Sprintf("tf-description-%s", acctest.RandString(5)) + team1 := fmt.Sprintf("tf-team1-%s", acctest.RandString(5)) + team2 := fmt.Sprintf("tf-team2-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckPagerDutyEventOrchestrationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckPagerDutyEventOrchestrationConfig(name, description, team1, team2), + }, + { + ResourceName: "pagerduty_event_orchestration.foo", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccPagerDutyEventOrchestrationNameOnly_import(t *testing.T) { + name := fmt.Sprintf("tf-name-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckPagerDutyEventOrchestrationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckPagerDutyEventOrchestrationConfigNameOnly(name), + }, + + { + ResourceName: "pagerduty_event_orchestration.foo", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} diff --git a/pagerduty/provider.go b/pagerduty/provider.go index 4af8626dc..92e478397 100644 --- a/pagerduty/provider.go +++ b/pagerduty/provider.go @@ -59,34 +59,39 @@ func Provider() *schema.Provider { "pagerduty_priority": dataSourcePagerDutyPriority(), "pagerduty_ruleset": dataSourcePagerDutyRuleset(), "pagerduty_tag": dataSourcePagerDutyTag(), + "pagerduty_event_orchestration": dataSourcePagerDutyEventOrchestration(), }, ResourcesMap: map[string]*schema.Resource{ - "pagerduty_addon": resourcePagerDutyAddon(), - "pagerduty_escalation_policy": resourcePagerDutyEscalationPolicy(), - "pagerduty_maintenance_window": resourcePagerDutyMaintenanceWindow(), - "pagerduty_schedule": resourcePagerDutySchedule(), - "pagerduty_service": resourcePagerDutyService(), - "pagerduty_service_integration": resourcePagerDutyServiceIntegration(), - "pagerduty_team": resourcePagerDutyTeam(), - "pagerduty_team_membership": resourcePagerDutyTeamMembership(), - "pagerduty_user": resourcePagerDutyUser(), - "pagerduty_user_contact_method": resourcePagerDutyUserContactMethod(), - "pagerduty_user_notification_rule": resourcePagerDutyUserNotificationRule(), - "pagerduty_extension": resourcePagerDutyExtension(), - "pagerduty_extension_servicenow": resourcePagerDutyExtensionServiceNow(), - "pagerduty_event_rule": resourcePagerDutyEventRule(), - "pagerduty_ruleset": resourcePagerDutyRuleset(), - "pagerduty_ruleset_rule": resourcePagerDutyRulesetRule(), - "pagerduty_business_service": resourcePagerDutyBusinessService(), - "pagerduty_service_dependency": resourcePagerDutyServiceDependency(), - "pagerduty_response_play": resourcePagerDutyResponsePlay(), - "pagerduty_tag": resourcePagerDutyTag(), - "pagerduty_tag_assignment": resourcePagerDutyTagAssignment(), - "pagerduty_service_event_rule": resourcePagerDutyServiceEventRule(), - "pagerduty_slack_connection": resourcePagerDutySlackConnection(), - "pagerduty_business_service_subscriber": resourcePagerDutyBusinessServiceSubscriber(), - "pagerduty_webhook_subscription": resourcePagerDutyWebhookSubscription(), + "pagerduty_addon": resourcePagerDutyAddon(), + "pagerduty_escalation_policy": resourcePagerDutyEscalationPolicy(), + "pagerduty_maintenance_window": resourcePagerDutyMaintenanceWindow(), + "pagerduty_schedule": resourcePagerDutySchedule(), + "pagerduty_service": resourcePagerDutyService(), + "pagerduty_service_integration": resourcePagerDutyServiceIntegration(), + "pagerduty_team": resourcePagerDutyTeam(), + "pagerduty_team_membership": resourcePagerDutyTeamMembership(), + "pagerduty_user": resourcePagerDutyUser(), + "pagerduty_user_contact_method": resourcePagerDutyUserContactMethod(), + "pagerduty_user_notification_rule": resourcePagerDutyUserNotificationRule(), + "pagerduty_extension": resourcePagerDutyExtension(), + "pagerduty_extension_servicenow": resourcePagerDutyExtensionServiceNow(), + "pagerduty_event_rule": resourcePagerDutyEventRule(), + "pagerduty_ruleset": resourcePagerDutyRuleset(), + "pagerduty_ruleset_rule": resourcePagerDutyRulesetRule(), + "pagerduty_business_service": resourcePagerDutyBusinessService(), + "pagerduty_service_dependency": resourcePagerDutyServiceDependency(), + "pagerduty_response_play": resourcePagerDutyResponsePlay(), + "pagerduty_tag": resourcePagerDutyTag(), + "pagerduty_tag_assignment": resourcePagerDutyTagAssignment(), + "pagerduty_service_event_rule": resourcePagerDutyServiceEventRule(), + "pagerduty_slack_connection": resourcePagerDutySlackConnection(), + "pagerduty_business_service_subscriber": resourcePagerDutyBusinessServiceSubscriber(), + "pagerduty_webhook_subscription": resourcePagerDutyWebhookSubscription(), + "pagerduty_event_orchestration": resourcePagerDutyEventOrchestration(), + "pagerduty_event_orchestration_router": resourcePagerDutyEventOrchestrationPathRouter(), + "pagerduty_event_orchestration_unrouted": resourcePagerDutyEventOrchestrationPathUnrouted(), + "pagerduty_event_orchestration_service": resourcePagerDutyEventOrchestrationPathService(), }, } diff --git a/pagerduty/resource_pagerduty_event_orchestration.go b/pagerduty/resource_pagerduty_event_orchestration.go new file mode 100644 index 000000000..8e876c1cb --- /dev/null +++ b/pagerduty/resource_pagerduty_event_orchestration.go @@ -0,0 +1,240 @@ +package pagerduty + +import ( + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/heimweh/go-pagerduty/pagerduty" +) + +func resourcePagerDutyEventOrchestration() *schema.Resource { + return &schema.Resource{ + Create: resourcePagerDutyEventOrchestrationCreate, + Read: resourcePagerDutyEventOrchestrationRead, + Update: resourcePagerDutyEventOrchestrationUpdate, + Delete: resourcePagerDutyEventOrchestrationDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "description": { + Type: schema.TypeString, + Optional: true, + }, + "team": { + Type: schema.TypeString, + Optional: true, + }, + "routes": { + Type: schema.TypeInt, + Computed: true, + }, + "integration": { + Type: schema.TypeList, + Computed: true, + Optional: true, // Tests keep failing if "Optional: true" is not provided + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + "parameters": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "routing_key": { + Type: schema.TypeString, + Computed: true, + }, + "type": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func buildEventOrchestrationStruct(d *schema.ResourceData) *pagerduty.EventOrchestration { + orchestration := &pagerduty.EventOrchestration{ + Name: d.Get("name").(string), + } + + if attr, ok := d.GetOk("description"); ok { + orchestration.Description = attr.(string) + } + + if attr, ok := d.GetOk("team"); ok { + orchestration.Team = &pagerduty.EventOrchestrationObject{ + ID: stringTypeToStringPtr(attr.(string)), + } + } else { + var tId *string + orchestration.Team = &pagerduty.EventOrchestrationObject{ + ID: tId, + } + } + + return orchestration +} + +func resourcePagerDutyEventOrchestrationCreate(d *schema.ResourceData, meta interface{}) error { + client, err := meta.(*Config).Client() + if err != nil { + return err + } + + payload := buildEventOrchestrationStruct(d) + var orchestration *pagerduty.EventOrchestration + + log.Printf("[INFO] Creating PagerDuty Event Orchestration: %s", payload.Name) + + retryErr := resource.Retry(10*time.Second, func() *resource.RetryError { + if orch, _, err := client.EventOrchestrations.Create(payload); err != nil { + if isErrCode(err, 400) || isErrCode(err, 429) { + return resource.RetryableError(err) + } + + return resource.NonRetryableError(err) + } else if orch != nil { + d.SetId(orch.ID) + orchestration = orch + } + return nil + }) + + if retryErr != nil { + return retryErr + } + + setEventOrchestrationProps(d, orchestration) + + return nil +} + +func resourcePagerDutyEventOrchestrationRead(d *schema.ResourceData, meta interface{}) error { + client, err := meta.(*Config).Client() + if err != nil { + return err + } + + return resource.Retry(2*time.Minute, func() *resource.RetryError { + orch, _, err := client.EventOrchestrations.Get(d.Id()) + if err != nil { + errResp := handleNotFoundError(err, d) + if errResp != nil { + time.Sleep(2 * time.Second) + return resource.RetryableError(errResp) + } + + return nil + } + + setEventOrchestrationProps(d, orch) + + return nil + }) +} + +func resourcePagerDutyEventOrchestrationUpdate(d *schema.ResourceData, meta interface{}) error { + client, err := meta.(*Config).Client() + if err != nil { + return err + } + + orchestration := buildEventOrchestrationStruct(d) + + log.Printf("[INFO] Updating PagerDuty Event Orchestration: %s", d.Id()) + + retryErr := resource.Retry(10*time.Second, func() *resource.RetryError { + if _, _, err := client.EventOrchestrations.Update(d.Id(), orchestration); err != nil { + if isErrCode(err, 400) || isErrCode(err, 429) { + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + + return nil + }) + + if retryErr != nil { + return retryErr + } + + return nil +} + +func resourcePagerDutyEventOrchestrationDelete(d *schema.ResourceData, meta interface{}) error { + client, err := meta.(*Config).Client() + if err != nil { + return err + } + + log.Printf("[INFO] Deleting PagerDuty Event Orchestration: %s", d.Id()) + if _, err := client.EventOrchestrations.Delete(d.Id()); err != nil { + return err + } + + d.SetId("") + + return nil +} + +func flattenEventOrchestrationTeam(v *pagerduty.EventOrchestrationObject) []interface{} { + team := map[string]interface{}{ + "id": v.ID, + } + + return []interface{}{team} +} + +func flattenEventOrchestrationIntegrations(eoi []*pagerduty.EventOrchestrationIntegration) []interface{} { + var result []interface{} + + for _, i := range eoi { + integration := map[string]interface{}{ + "id": i.ID, + "parameters": flattenEventOrchestrationIntegrationParameters(i.Parameters), + } + result = append(result, integration) + } + return result +} + +func flattenEventOrchestrationIntegrationParameters(p *pagerduty.EventOrchestrationIntegrationParameters) []interface{} { + result := map[string]interface{}{ + "routing_key": p.RoutingKey, + "type": p.Type, + } + + return []interface{}{result} +} + +func setEventOrchestrationProps(d *schema.ResourceData, o *pagerduty.EventOrchestration) error { + d.Set("name", o.Name) + d.Set("description", o.Description) + d.Set("routes", o.Routes) + + if o.Team != nil { + d.Set("team", o.Team.ID) + } + + if len(o.Integrations) > 0 { + d.Set("integration", flattenEventOrchestrationIntegrations(o.Integrations)) + } + + return nil +} diff --git a/pagerduty/resource_pagerduty_event_orchestration_path_router.go b/pagerduty/resource_pagerduty_event_orchestration_path_router.go new file mode 100644 index 000000000..d535e14a2 --- /dev/null +++ b/pagerduty/resource_pagerduty_event_orchestration_path_router.go @@ -0,0 +1,335 @@ +package pagerduty + +import ( + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/heimweh/go-pagerduty/pagerduty" +) + +func resourcePagerDutyEventOrchestrationPathRouter() *schema.Resource { + return &schema.Resource{ + Read: resourcePagerDutyEventOrchestrationPathRouterRead, + Create: resourcePagerDutyEventOrchestrationPathRouterCreate, + Update: resourcePagerDutyEventOrchestrationPathRouterUpdate, + Delete: resourcePagerDutyEventOrchestrationPathRouterDelete, + Importer: &schema.ResourceImporter{ + State: resourcePagerDutyEventOrchestrationPathRouterImport, + }, + Schema: map[string]*schema.Schema{ + "event_orchestration": { + Type: schema.TypeString, + Required: true, + }, + "set": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, // Router can only have 'start' set + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Required: true, + }, + "rule": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + "label": { + Type: schema.TypeString, + Optional: true, + }, + "condition": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: eventOrchestrationPathConditionsSchema, + }, + }, + "actions": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, //there can only be one action for router + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "route_to": { + Type: schema.TypeString, + Required: true, + ValidateFunc: func(v interface{}, key string) (warns []string, errs []error) { + value := v.(string) + if value == "unrouted" { + errs = append(errs, fmt.Errorf("route_to within a set's rule has to be a Service ID. Got: %q", v)) + } + return + }, + }, + }, + }, + }, + "disabled": { + Type: schema.TypeBool, + Optional: true, + }, + }, + }, + }, + }, + }, + }, + "catch_all": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "actions": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "route_to": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func resourcePagerDutyEventOrchestrationPathRouterRead(d *schema.ResourceData, meta interface{}) error { + client, err := meta.(*Config).Client() + if err != nil { + return err + } + + return resource.Retry(2*time.Minute, func() *resource.RetryError { + log.Printf("[INFO] Reading PagerDuty Event Orchestration Path of type %s for orchestration: %s", "router", d.Id()) + + if routerPath, _, err := client.EventOrchestrationPaths.Get(d.Id(), "router"); err != nil { + time.Sleep(2 * time.Second) + return resource.RetryableError(err) + } else if routerPath != nil { + d.Set("event_orchestration", routerPath.Parent.ID) + + if routerPath.Sets != nil { + d.Set("set", flattenSets(routerPath.Sets)) + } + + if routerPath.CatchAll != nil { + d.Set("catch_all", flattenCatchAll(routerPath.CatchAll)) + } + } + return nil + }) + +} + +// EventOrchestrationPath cannot be created, use update to add / edit / remove rules and sets +func resourcePagerDutyEventOrchestrationPathRouterCreate(d *schema.ResourceData, meta interface{}) error { + return resourcePagerDutyEventOrchestrationPathRouterUpdate(d, meta) +} + +func resourcePagerDutyEventOrchestrationPathRouterDelete(d *schema.ResourceData, meta interface{}) error { + d.SetId("") + return nil +} + +func resourcePagerDutyEventOrchestrationPathRouterUpdate(d *schema.ResourceData, meta interface{}) error { + client, err := meta.(*Config).Client() + if err != nil { + return err + } + + updatePath := buildRouterPathStructForUpdate(d) + + log.Printf("[INFO] Updating PagerDuty Event Orchestration Path of type %s for orchestration: %s", "router", updatePath.Parent.ID) + + return performRouterPathUpdate(d, updatePath, client) +} + +func performRouterPathUpdate(d *schema.ResourceData, routerPath *pagerduty.EventOrchestrationPath, client *pagerduty.Client) error { + retryErr := resource.Retry(30*time.Second, func() *resource.RetryError { + updatedPath, _, err := client.EventOrchestrationPaths.Update(routerPath.Parent.ID, "router", routerPath) + if err != nil { + return resource.RetryableError(err) + } + if updatedPath == nil { + return resource.NonRetryableError(fmt.Errorf("No Event Orchestration Router found.")) + } + d.SetId(routerPath.Parent.ID) + d.Set("event_orchestration", routerPath.Parent.ID) + + if routerPath.Sets != nil { + d.Set("set", flattenSets(routerPath.Sets)) + } + if updatedPath.CatchAll != nil { + d.Set("catch_all", flattenCatchAll(updatedPath.CatchAll)) + } + return nil + }) + if retryErr != nil { + time.Sleep(2 * time.Second) + return retryErr + } + return nil +} + +func buildRouterPathStructForUpdate(d *schema.ResourceData) *pagerduty.EventOrchestrationPath { + + orchPath := &pagerduty.EventOrchestrationPath{ + Parent: &pagerduty.EventOrchestrationPathReference{ + ID: d.Get("event_orchestration").(string), + }, + } + + if attr, ok := d.GetOk("set"); ok { + orchPath.Sets = expandSets(attr) + } + + if attr, ok := d.GetOk("catch_all"); ok { + orchPath.CatchAll = expandCatchAll(attr) + } + + return orchPath +} + +func expandSets(v interface{}) []*pagerduty.EventOrchestrationPathSet { + var sets []*pagerduty.EventOrchestrationPathSet + + for _, set := range v.([]interface{}) { + s := set.(map[string]interface{}) + + orchPathSet := &pagerduty.EventOrchestrationPathSet{ + ID: s["id"].(string), + Rules: expandRules(s["rule"]), + } + + sets = append(sets, orchPathSet) + } + + return sets +} + +func expandRules(v interface{}) []*pagerduty.EventOrchestrationPathRule { + items := v.([]interface{}) + rules := []*pagerduty.EventOrchestrationPathRule{} + + for _, rule := range items { + r := rule.(map[string]interface{}) + + ruleInSet := &pagerduty.EventOrchestrationPathRule{ + ID: r["id"].(string), + Label: r["label"].(string), + Disabled: r["disabled"].(bool), + Conditions: expandEventOrchestrationPathConditions(r["condition"]), + Actions: expandRouterActions(r["actions"]), + } + + rules = append(rules, ruleInSet) + } + return rules +} + +func expandRouterActions(v interface{}) *pagerduty.EventOrchestrationPathRuleActions { + var actions = new(pagerduty.EventOrchestrationPathRuleActions) + for _, ai := range v.([]interface{}) { + am := ai.(map[string]interface{}) + actions.RouteTo = am["route_to"].(string) + } + + return actions +} + +func expandCatchAll(v interface{}) *pagerduty.EventOrchestrationPathCatchAll { + var catchAll = new(pagerduty.EventOrchestrationPathCatchAll) + + for _, ca := range v.([]interface{}) { + am := ca.(map[string]interface{}) + catchAll.Actions = expandRouterActions(am["actions"]) + } + + return catchAll +} + +func flattenSets(orchPathSets []*pagerduty.EventOrchestrationPathSet) []interface{} { + var flattenedSets []interface{} + for _, set := range orchPathSets { + flattenedSet := map[string]interface{}{ + "id": set.ID, + "rule": flattenRules(set.Rules), + } + flattenedSets = append(flattenedSets, flattenedSet) + } + return flattenedSets +} + +func flattenRules(rules []*pagerduty.EventOrchestrationPathRule) []interface{} { + var flattenedRules []interface{} + + for _, rule := range rules { + flattenedRule := map[string]interface{}{ + "id": rule.ID, + "label": rule.Label, + "disabled": rule.Disabled, + "condition": flattenEventOrchestrationPathConditions(rule.Conditions), + "actions": flattenRouterActions(rule.Actions), + } + flattenedRules = append(flattenedRules, flattenedRule) + } + + return flattenedRules +} + +func flattenRouterActions(actions *pagerduty.EventOrchestrationPathRuleActions) []map[string]interface{} { + var actionsMap []map[string]interface{} + + am := make(map[string]interface{}) + am["route_to"] = actions.RouteTo + actionsMap = append(actionsMap, am) + return actionsMap +} + +func flattenCatchAll(catchAll *pagerduty.EventOrchestrationPathCatchAll) []map[string]interface{} { + var caMap []map[string]interface{} + + c := make(map[string]interface{}) + + c["actions"] = flattenRouterActions(catchAll.Actions) + caMap = append(caMap, c) + + return caMap +} + +func resourcePagerDutyEventOrchestrationPathRouterImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + client, err := meta.(*Config).Client() + if err != nil { + return []*schema.ResourceData{}, err + } + // given an orchestration ID import the router orchestration path + orchestrationID := d.Id() + pathType := "router" + _, _, err = client.EventOrchestrationPaths.Get(orchestrationID, pathType) + + if err != nil { + return []*schema.ResourceData{}, err + } + + d.SetId(orchestrationID) + d.Set("event_orchestration", orchestrationID) + + return []*schema.ResourceData{d}, nil +} diff --git a/pagerduty/resource_pagerduty_event_orchestration_path_router_test.go b/pagerduty/resource_pagerduty_event_orchestration_path_router_test.go new file mode 100644 index 000000000..3e03a1428 --- /dev/null +++ b/pagerduty/resource_pagerduty_event_orchestration_path_router_test.go @@ -0,0 +1,428 @@ +package pagerduty + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func init() { + resource.AddTestSweepers("pagerduty_event_orchestration_router", &resource.Sweeper{ + Name: "pagerduty_event_orchestration_router", + F: testSweepEventOrchestration, + }) +} + +func TestAccPagerDutyEventOrchestrationPathRouter_Basic(t *testing.T) { + team := fmt.Sprintf("tf-name-%s", acctest.RandString(5)) + escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) + service := fmt.Sprintf("tf-%s", acctest.RandString(5)) + orchestration := fmt.Sprintf("tf-orchestration-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckPagerDutyEventOrchestrationRouterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckPagerDutyEventOrchestrationRouterConfigNoRules(team, escalationPolicy, service, orchestration), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationRouterExists("pagerduty_event_orchestration_router.router"), + testAccCheckPagerDutyEventOrchestrationRouterPathRouteToMatch( + "pagerduty_event_orchestration_router.router", "unrouted", true), //test for catch_all route_to prop, by default it should be unrouted + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_router.router", "set.0.rule.#", "0"), + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationRouterConfig(team, escalationPolicy, service, orchestration), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationRouterExists("pagerduty_event_orchestration_router.router"), + testAccCheckPagerDutyEventOrchestrationRouterPathRouteToMatch( + "pagerduty_event_orchestration_router.router", "pagerduty_service.bar", false), // test for rule action route_to + testAccCheckPagerDutyEventOrchestrationRouterPathRouteToMatch( + "pagerduty_event_orchestration_router.router", "unrouted", true), //test for catch_all route_to prop, by default it should be unrouted + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationRouterConfigWithConditions(team, escalationPolicy, service, orchestration), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationRouterExists("pagerduty_event_orchestration_router.router"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_router.router", "set.0.rule.0.condition.0.expression", "event.summary matches part 'database'"), + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationRouterConfigWithMultipleRules(team, escalationPolicy, service, orchestration), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationRouterExists("pagerduty_event_orchestration_router.router"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_router.router", "set.0.rule.#", "2"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_router.router", "set.0.rule.0.condition.0.expression", "event.summary matches part 'database'"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_router.router", "set.0.rule.1.condition.0.expression", "event.severity matches part 'critical'"), + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationRouterConfigWithCatchAllToService(team, escalationPolicy, service, orchestration), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationRouterExists("pagerduty_event_orchestration_router.router"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_router.router", "set.0.rule.#", "1"), + testAccCheckPagerDutyEventOrchestrationRouterPathRouteToMatch( + "pagerduty_event_orchestration_router.router", "pagerduty_service.bar", true), //test for catch_all routing to service if provided + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationRouterConfigNoConditions(team, escalationPolicy, service, orchestration), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationRouterExists("pagerduty_event_orchestration_router.router"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_router.router", "set.0.rule.#", "1"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_router.router", "set.0.rule.0.condition.#", "0"), + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationRouterConfigDeleteAllRulesInSet(team, escalationPolicy, service, orchestration), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationRouterExists("pagerduty_event_orchestration_router.router"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_router.router", "set.0.rule.#", "0"), + testAccCheckPagerDutyEventOrchestrationRouterPathRouteToMatch( + "pagerduty_event_orchestration_router.router", "pagerduty_service.bar", true), + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationRouterConfigDelete(team, escalationPolicy, service, orchestration), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationRouterNotExists("pagerduty_event_orchestration_router.router"), + ), + }, + }, + }) +} + +func testAccCheckPagerDutyEventOrchestrationRouterDestroy(s *terraform.State) error { + client, _ := testAccProvider.Meta().(*Config).Client() + for _, r := range s.RootModule().Resources { + if r.Type != "pagerduty_event_orchestration_path_router" { + continue + } + + orch, _ := s.RootModule().Resources["pagerduty_event_orchestration.orch"] + + if _, _, err := client.EventOrchestrationPaths.Get(orch.Primary.ID, "router"); err == nil { + return fmt.Errorf("Event Orchestration Path still exists") + } + } + return nil +} + +func testAccCheckPagerDutyEventOrchestrationRouterExists(rn string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[rn] + if !ok { + return fmt.Errorf("Not found: %s", rn) + } + if rs.Primary.ID == "" { + return fmt.Errorf("No Event Orchestration Router is set") + } + + orch, _ := s.RootModule().Resources["pagerduty_event_orchestration.orch"] + client, _ := testAccProvider.Meta().(*Config).Client() + _, _, err := client.EventOrchestrationPaths.Get(orch.Primary.ID, "router") + + if err != nil { + return fmt.Errorf("Orchestration Path type not found: %v for orchestration %v", "router", orch.Primary.ID) + } + + return nil + } +} + +func testAccCheckPagerDutyEventOrchestrationRouterNotExists(rn string) resource.TestCheckFunc { + return func(s *terraform.State) error { + _, ok := s.RootModule().Resources[rn] + if ok { + return fmt.Errorf("Event Orchestration Router Path is not deleted: %s", rn) + } + + return nil + } +} + +func createBaseConfig(t, ep, s, o string) string { + return fmt.Sprintf(` + resource "pagerduty_team" "foo" { + name = "%s" + } + + resource "pagerduty_user" "foo" { + name = "tf-user" + email = "user@pagerduty.com" + color = "green" + role = "user" + job_title = "foo" + description = "foo" + } + + resource "pagerduty_escalation_policy" "foo" { + name = "%s" + description = "bar" + num_loops = 2 + + rule { + escalation_delay_in_minutes = 10 + target { + type = "user_reference" + id = pagerduty_user.foo.id + } + } + } + + resource "pagerduty_service" "bar" { + name = "%s" + escalation_policy = pagerduty_escalation_policy.foo.id + + incident_urgency_rule { + type = "constant" + urgency = "high" + } + } + + resource "pagerduty_event_orchestration" "orch" { + name = "%s" + team = pagerduty_team.foo.id + } + `, t, ep, s, o) +} + +func testAccCheckPagerDutyEventOrchestrationRouterConfigNoRules(t, ep, s, o string) string { + return fmt.Sprintf("%s%s", createBaseConfig(t, ep, s, o), + `resource "pagerduty_event_orchestration_router" "router" { + event_orchestration = pagerduty_event_orchestration.orch.id + + catch_all { + actions { + route_to = "unrouted" + } + } + set { + id = "start" + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationRouterConfig(t, ep, s, o string) string { + return fmt.Sprintf("%s%s", createBaseConfig(t, ep, s, o), + `resource "pagerduty_event_orchestration_router" "router" { + event_orchestration = pagerduty_event_orchestration.orch.id + + catch_all { + actions { + route_to = "unrouted" + } + } + set { + id = "start" + rule { + disabled = false + label = "rule1 label" + actions { + route_to = pagerduty_service.bar.id + } + } + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationRouterConfigWithConditions(t, ep, s, o string) string { + return fmt.Sprintf("%s%s", createBaseConfig(t, ep, s, o), + `resource "pagerduty_event_orchestration_router" "router" { + event_orchestration = pagerduty_event_orchestration.orch.id + + catch_all { + actions { + route_to = "unrouted" + } + } + set { + id = "start" + rule { + disabled = false + label = "rule1 label" + actions { + route_to = pagerduty_service.bar.id + } + condition { + expression = "event.summary matches part 'database'" + } + } + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationRouterConfigWithMultipleRules(t, ep, s, o string) string { + return fmt.Sprintf( + "%s%s", createBaseConfig(t, ep, s, o), + `resource "pagerduty_service" "bar2" { + name = "tf-barService2" + escalation_policy = pagerduty_escalation_policy.foo.id + + incident_urgency_rule { + type = "constant" + urgency = "high" + } + } + + resource "pagerduty_event_orchestration_router" "router" { + event_orchestration = pagerduty_event_orchestration.orch.id + + catch_all { + actions { + route_to = "unrouted" + } + } + set { + id = "start" + rule { + disabled = false + label = "rule1 label" + actions { + route_to = pagerduty_service.bar.id + } + condition { + expression = "event.summary matches part 'database'" + } + condition { + expression = "event.severity matches part 'critical'" + } + } + + rule { + disabled = false + label = "rule2 label" + actions { + route_to = pagerduty_service.bar2.id + } + condition { + expression = "event.severity matches part 'critical'" + } + } + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationRouterConfigNoConditions(t, ep, s, o string) string { + return fmt.Sprintf("%s%s", createBaseConfig(t, ep, s, o), + `resource "pagerduty_event_orchestration_router" "router" { + event_orchestration = pagerduty_event_orchestration.orch.id + + catch_all { + actions { + route_to = pagerduty_service.bar.id + } + } + set { + id = "start" + rule { + disabled = false + label = "rule1 label" + actions { + route_to = pagerduty_service.bar.id + } + } + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationRouterConfigWithCatchAllToService(t, ep, s, o string) string { + return fmt.Sprintf("%s%s", createBaseConfig(t, ep, s, o), + `resource "pagerduty_event_orchestration_router" "router" { + event_orchestration = pagerduty_event_orchestration.orch.id + + catch_all { + actions { + route_to = pagerduty_service.bar.id + } + } + set { + id = "start" + rule { + disabled = false + label = "rule1 label" + actions { + route_to = pagerduty_service.bar.id + } + condition { + expression = "event.severity matches part 'critical'" + } + } + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationRouterConfigDeleteAllRulesInSet(t, ep, s, o string) string { + return fmt.Sprintf("%s%s", createBaseConfig(t, ep, s, o), + `resource "pagerduty_event_orchestration_router" "router" { + event_orchestration = pagerduty_event_orchestration.orch.id + + catch_all { + actions { + route_to = pagerduty_service.bar.id + } + } + set { + id = "start" + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationRouterConfigDelete(t, ep, s, o string) string { + return createBaseConfig(t, ep, s, o) +} + +func testAccCheckPagerDutyEventOrchestrationRouterPathRouteToMatch(router, service string, catchAll bool) resource.TestCheckFunc { + return func(s *terraform.State) error { + r, rOk := s.RootModule().Resources[router] + if !rOk { + return fmt.Errorf("Not found: %s", router) + } + + var rRouteToId = "" + if catchAll == true { + rRouteToId = r.Primary.Attributes["catch_all.0.actions.0.route_to"] + } else { + rRouteToId = r.Primary.Attributes["set.0.rule.0.actions.0.route_to"] + } + + var sId = "" + if service == "unrouted" { + sId = "unrouted" + } else { + svc, sOk := s.RootModule().Resources[service] + if !sOk { + return fmt.Errorf("Not found: %s", service) + } + sId = svc.Primary.Attributes["id"] + } + + if rRouteToId != sId { + return fmt.Errorf("Event Orchestration Router Route to Service ID (%v) not matching provided service ID: %v", rRouteToId, sId) + } + + return nil + } +} diff --git a/pagerduty/resource_pagerduty_event_orchestration_path_service.go b/pagerduty/resource_pagerduty_event_orchestration_path_service.go new file mode 100644 index 000000000..a956bb8f4 --- /dev/null +++ b/pagerduty/resource_pagerduty_event_orchestration_path_service.go @@ -0,0 +1,555 @@ +package pagerduty + +import ( + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/heimweh/go-pagerduty/pagerduty" +) + +var eventOrchestrationAutomationActionObjectSchema = map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Required: true, + }, + "value": { + Type: schema.TypeString, + Required: true, + }, +} + +var eventOrchestrationPathServiceCatchAllActionsSchema = map[string]*schema.Schema{ + "suppress": { + Type: schema.TypeBool, + Optional: true, + }, + "suspend": { + Type: schema.TypeInt, + Optional: true, + }, + "priority": { + Type: schema.TypeString, + Optional: true, + }, + "annotate": { + Type: schema.TypeString, + Optional: true, + }, + "pagerduty_automation_action": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "action_id": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "automation_action": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "url": { + Type: schema.TypeString, + Required: true, + }, + "auto_send": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "header": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: eventOrchestrationAutomationActionObjectSchema, + }, + }, + "parameter": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: eventOrchestrationAutomationActionObjectSchema, + }, + }, + }, + }, + }, + "severity": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateEventOrchestrationPathSeverity(), + }, + "event_action": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateEventOrchestrationPathEventAction(), + }, + "variable": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: eventOrchestrationPathVariablesSchema, + }, + }, + "extraction": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: eventOrchestrationPathExtractionsSchema, + }, + }, +} + +var eventOrchestrationPathServiceRuleActionsSchema = buildEventOrchestrationPathServiceRuleActionsSchema() + +func buildEventOrchestrationPathServiceRuleActionsSchema() map[string]*schema.Schema { + a := eventOrchestrationPathServiceCatchAllActionsSchema + a["route_to"] = &schema.Schema{ + Type: schema.TypeString, + Optional: true, + } + + return a +} + +func resourcePagerDutyEventOrchestrationPathService() *schema.Resource { + return &schema.Resource{ + Read: resourcePagerDutyEventOrchestrationPathServiceRead, + Create: resourcePagerDutyEventOrchestrationPathServiceCreate, + Update: resourcePagerDutyEventOrchestrationPathServiceUpdate, + Delete: resourcePagerDutyEventOrchestrationPathServiceDelete, + Importer: &schema.ResourceImporter{ + State: resourcePagerDutyEventOrchestrationPathServiceImport, + }, + CustomizeDiff: checkExtractions, + Schema: map[string]*schema.Schema{ + "service": { + Type: schema.TypeString, + Required: true, + }, + "set": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Required: true, + }, + "rule": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + "label": { + Type: schema.TypeString, + Optional: true, + }, + "condition": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: eventOrchestrationPathConditionsSchema, + }, + }, + "actions": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: eventOrchestrationPathServiceRuleActionsSchema, + }, + }, + "disabled": { + Type: schema.TypeBool, + Optional: true, + }, + }, + }, + }, + }, + }, + }, + "catch_all": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "actions": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: eventOrchestrationPathServiceRuleActionsSchema, + }, + }, + }, + }, + }, + }, + } +} + +func resourcePagerDutyEventOrchestrationPathServiceRead(d *schema.ResourceData, meta interface{}) error { + client, err := meta.(*Config).Client() + if err != nil { + return err + } + + return resource.Retry(2*time.Minute, func() *resource.RetryError { + id := d.Id() + t := "service" + log.Printf("[INFO] Reading PagerDuty Event Orchestration Path of type %s for orchestration: %s", t, id) + + if path, _, err := client.EventOrchestrationPaths.Get(d.Id(), t); err != nil { + time.Sleep(2 * time.Second) + return resource.RetryableError(err) + } else if path != nil { + setEventOrchestrationPathServiceProps(d, path) + } + return nil + }) + +} + +func resourcePagerDutyEventOrchestrationPathServiceCreate(d *schema.ResourceData, meta interface{}) error { + return resourcePagerDutyEventOrchestrationPathServiceUpdate(d, meta) +} + +func resourcePagerDutyEventOrchestrationPathServiceUpdate(d *schema.ResourceData, meta interface{}) error { + client, err := meta.(*Config).Client() + if err != nil { + return err + } + + payload := buildServicePathStruct(d) + var servicePath *pagerduty.EventOrchestrationPath + + log.Printf("[INFO] Creating PagerDuty Event Orchestration Service Path: %s", payload.Parent.ID) + + retryErr := resource.Retry(30*time.Second, func() *resource.RetryError { + if path, _, err := client.EventOrchestrationPaths.Update(payload.Parent.ID, "service", payload); err != nil { + return resource.RetryableError(err) + } else if path != nil { + d.SetId(path.Parent.ID) + servicePath = path + } + return nil + }) + + if retryErr != nil { + return retryErr + } + + setEventOrchestrationPathServiceProps(d, servicePath) + + return nil +} + +func resourcePagerDutyEventOrchestrationPathServiceDelete(d *schema.ResourceData, meta interface{}) error { + d.SetId("") + return nil +} + +func resourcePagerDutyEventOrchestrationPathServiceImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + client, err := meta.(*Config).Client() + if err != nil { + return []*schema.ResourceData{}, err + } + + id := d.Id() + + _, _, pErr := client.EventOrchestrationPaths.Get(id, "service") + if pErr != nil { + return []*schema.ResourceData{}, pErr + } + + d.SetId(id) + d.Set("service", id) + + return []*schema.ResourceData{d}, nil +} + +func buildServicePathStruct(d *schema.ResourceData) *pagerduty.EventOrchestrationPath { + return &pagerduty.EventOrchestrationPath{ + Parent: &pagerduty.EventOrchestrationPathReference{ + ID: d.Get("service").(string), + }, + Sets: expandServicePathSets(d.Get("set")), + CatchAll: expandServicePathCatchAll(d.Get("catch_all")), + } +} + +func expandServicePathSets(v interface{}) []*pagerduty.EventOrchestrationPathSet { + var sets []*pagerduty.EventOrchestrationPathSet + + for _, set := range v.([]interface{}) { + s := set.(map[string]interface{}) + + orchPathSet := &pagerduty.EventOrchestrationPathSet{ + ID: s["id"].(string), + Rules: expandServicePathRules(s["rule"].(interface{})), + } + + sets = append(sets, orchPathSet) + } + + return sets +} + +func expandServicePathRules(v interface{}) []*pagerduty.EventOrchestrationPathRule { + items := v.([]interface{}) + rules := []*pagerduty.EventOrchestrationPathRule{} + + for _, rule := range items { + r := rule.(map[string]interface{}) + + ruleInSet := &pagerduty.EventOrchestrationPathRule{ + ID: r["id"].(string), + Label: r["label"].(string), + Disabled: r["disabled"].(bool), + Conditions: expandEventOrchestrationPathConditions(r["condition"]), + Actions: expandServicePathActions(r["actions"]), + } + + rules = append(rules, ruleInSet) + } + return rules +} + +func expandServicePathCatchAll(v interface{}) *pagerduty.EventOrchestrationPathCatchAll { + var catchAll = new(pagerduty.EventOrchestrationPathCatchAll) + + for _, ca := range v.([]interface{}) { + if ca != nil { + am := ca.(map[string]interface{}) + catchAll.Actions = expandServicePathActions(am["actions"]) + } + } + + return catchAll +} + +func expandServicePathActions(v interface{}) *pagerduty.EventOrchestrationPathRuleActions { + var actions = &pagerduty.EventOrchestrationPathRuleActions{ + AutomationActions: []*pagerduty.EventOrchestrationPathAutomationAction{}, + PagerdutyAutomationActions: []*pagerduty.EventOrchestrationPathPagerdutyAutomationAction{}, + Variables: []*pagerduty.EventOrchestrationPathActionVariables{}, + Extractions: []*pagerduty.EventOrchestrationPathActionExtractions{}, + } + + for _, i := range v.([]interface{}) { + if i == nil { + continue + } + a := i.(map[string]interface{}) + + actions.RouteTo = a["route_to"].(string) + actions.Suppress = a["suppress"].(bool) + actions.Suspend = intTypeToIntPtr(a["suspend"].(int)) + actions.Priority = a["priority"].(string) + actions.Annotate = a["annotate"].(string) + actions.Severity = a["severity"].(string) + actions.EventAction = a["event_action"].(string) + actions.PagerdutyAutomationActions = expandServicePathPagerDutyAutomationActions(a["pagerduty_automation_action"]) + actions.AutomationActions = expandServicePathAutomationActions(a["automation_action"]) + actions.Variables = expandEventOrchestrationPathVariables(a["variable"]) + actions.Extractions = expandEventOrchestrationPathExtractions(a["extraction"]) + } + + return actions +} + +func expandServicePathPagerDutyAutomationActions(v interface{}) []*pagerduty.EventOrchestrationPathPagerdutyAutomationAction { + result := []*pagerduty.EventOrchestrationPathPagerdutyAutomationAction{} + + for _, i := range v.([]interface{}) { + a := i.(map[string]interface{}) + pdaa := &pagerduty.EventOrchestrationPathPagerdutyAutomationAction{ + ActionId: a["action_id"].(string), + } + + result = append(result, pdaa) + } + + return result +} + +func expandServicePathAutomationActions(v interface{}) []*pagerduty.EventOrchestrationPathAutomationAction { + result := []*pagerduty.EventOrchestrationPathAutomationAction{} + + for _, i := range v.([]interface{}) { + a := i.(map[string]interface{}) + aa := &pagerduty.EventOrchestrationPathAutomationAction{ + Name: a["name"].(string), + Url: a["url"].(string), + AutoSend: a["auto_send"].(bool), + Headers: expandEventOrchestrationAutomationActionObjects(a["header"]), + Parameters: expandEventOrchestrationAutomationActionObjects(a["parameter"]), + } + + result = append(result, aa) + } + + return result +} + +func expandEventOrchestrationAutomationActionObjects(v interface{}) []*pagerduty.EventOrchestrationPathAutomationActionObject { + result := []*pagerduty.EventOrchestrationPathAutomationActionObject{} + + for _, i := range v.([]interface{}) { + o := i.(map[string]interface{}) + obj := &pagerduty.EventOrchestrationPathAutomationActionObject{ + Key: o["key"].(string), + Value: o["value"].(string), + } + + result = append(result, obj) + } + + return result +} + +func setEventOrchestrationPathServiceProps(d *schema.ResourceData, p *pagerduty.EventOrchestrationPath) error { + d.SetId(p.Parent.ID) + d.Set("service", p.Parent.ID) + d.Set("set", flattenServicePathSets(p.Sets)) + d.Set("catch_all", flattenServicePathCatchAll(p.CatchAll)) + return nil +} + +func flattenServicePathSets(orchPathSets []*pagerduty.EventOrchestrationPathSet) []interface{} { + var flattenedSets []interface{} + + for _, set := range orchPathSets { + flattenedSet := map[string]interface{}{ + "id": set.ID, + "rule": flattenServicePathRules(set.Rules), + } + flattenedSets = append(flattenedSets, flattenedSet) + } + return flattenedSets +} + +func flattenServicePathCatchAll(catchAll *pagerduty.EventOrchestrationPathCatchAll) []map[string]interface{} { + var caMap []map[string]interface{} + + c := make(map[string]interface{}) + + c["actions"] = flattenServicePathActions(catchAll.Actions) + caMap = append(caMap, c) + + return caMap +} + +func flattenServicePathRules(rules []*pagerduty.EventOrchestrationPathRule) []interface{} { + var flattenedRules []interface{} + + for _, rule := range rules { + flattenedRule := map[string]interface{}{ + "id": rule.ID, + "label": rule.Label, + "disabled": rule.Disabled, + "condition": flattenEventOrchestrationPathConditions(rule.Conditions), + "actions": flattenServicePathActions(rule.Actions), + } + flattenedRules = append(flattenedRules, flattenedRule) + } + + return flattenedRules +} + +func flattenServicePathActions(actions *pagerduty.EventOrchestrationPathRuleActions) []map[string]interface{} { + var actionsMap []map[string]interface{} + + flattenedAction := map[string]interface{}{ + "route_to": actions.RouteTo, + "severity": actions.Severity, + "event_action": actions.EventAction, + "suppress": actions.Suppress, + "suspend": actions.Suspend, + "priority": actions.Priority, + "annotate": actions.Annotate, + } + + if actions.Variables != nil { + flattenedAction["variable"] = flattenEventOrchestrationPathVariables(actions.Variables) + } + if actions.Extractions != nil { + flattenedAction["extraction"] = flattenEventOrchestrationPathExtractions(actions.Extractions) + } + if actions.PagerdutyAutomationActions != nil { + flattenedAction["pagerduty_automation_action"] = flattenServicePathPagerDutyAutomationActions(actions.PagerdutyAutomationActions) + } + if actions.AutomationActions != nil { + flattenedAction["automation_action"] = flattenServicePathAutomationActions(actions.AutomationActions) + } + + actionsMap = append(actionsMap, flattenedAction) + + return actionsMap +} + +func flattenServicePathPagerDutyAutomationActions(v []*pagerduty.EventOrchestrationPathPagerdutyAutomationAction) []interface{} { + var result []interface{} + + for _, i := range v { + pdaa := map[string]string{ + "action_id": i.ActionId, + } + + result = append(result, pdaa) + } + + return result +} + +func flattenServicePathAutomationActions(v []*pagerduty.EventOrchestrationPathAutomationAction) []interface{} { + var result []interface{} + + for _, i := range v { + pdaa := map[string]interface{}{ + "name": i.Name, + "url": i.Url, + "auto_send": i.AutoSend, + "header": flattenServicePathAutomationActionObjects(i.Headers), + "parameter": flattenServicePathAutomationActionObjects(i.Parameters), + } + + result = append(result, pdaa) + } + + return result +} + +func flattenServicePathAutomationActionObjects(v []*pagerduty.EventOrchestrationPathAutomationActionObject) []interface{} { + var result []interface{} + + for _, i := range v { + pdaa := map[string]interface{}{ + "key": i.Key, + "value": i.Value, + } + + result = append(result, pdaa) + } + + return result +} diff --git a/pagerduty/resource_pagerduty_event_orchestration_path_service_test.go b/pagerduty/resource_pagerduty_event_orchestration_path_service_test.go new file mode 100644 index 000000000..700bf32ea --- /dev/null +++ b/pagerduty/resource_pagerduty_event_orchestration_path_service_test.go @@ -0,0 +1,733 @@ +package pagerduty + +import ( + "fmt" + "regexp" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func init() { + resource.AddTestSweepers("pagerduty_event_orchestration_service", &resource.Sweeper{ + Name: "pagerduty_event_orchestration_service", + F: testSweepEventOrchestration, + }) +} + +func TestAccPagerDutyEventOrchestrationPathService_Basic(t *testing.T) { + escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) + service := fmt.Sprintf("tf-%s", acctest.RandString(5)) + + resourceName := "pagerduty_event_orchestration_service.serviceA" + serviceResourceName := "pagerduty_service.bar" + + // Checks that run on every step except the last one. These checks that verify the existance of the resource + // and computed/default attributes. We're not checking individual resource attributes because + // according to the official docs (https://pkg.go.dev/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource#TestCheckResourceAttr) + // "State value checking is only recommended for testing Computed attributes and attribute defaults." + baseChecks := []resource.TestCheckFunc{ + testAccCheckPagerDutyEventOrchestrationPathServiceExists(resourceName), + testAccCheckPagerDutyEventOrchestrationPathServiceServiceID(resourceName, serviceResourceName), + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckPagerDutyEventOrchestrationServicePathDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckPagerDutyEventOrchestrationPathServiceDefaultConfig(escalationPolicy, service), + Check: resource.ComposeTestCheckFunc(baseChecks...), + }, + // Adding/updating/deleting automation_action properties + { + Config: testAccCheckPagerDutyEventOrchestrationPathServiceAutomationActionsConfig(escalationPolicy, service), + Check: resource.ComposeTestCheckFunc( + append( + baseChecks, + resource.TestCheckResourceAttrSet(resourceName, "set.0.rule.0.id"), + )..., + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathServiceAutomationActionsParamsUpdateConfig(escalationPolicy, service), + Check: resource.ComposeTestCheckFunc( + append( + baseChecks, + resource.TestCheckResourceAttr( + resourceName, "set.0.rule.0.actions.0.automation_action.0.auto_send", "false", + ), + )..., + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathServiceAutomationActionsParamsDeleteConfig(escalationPolicy, service), + Check: resource.ComposeTestCheckFunc(baseChecks...), + }, + // Providing invalid extractions attributes for set rules + { + Config: testAccCheckPagerDutyEventOrchestrationPathServiceInvalidExtractionsConfig( + escalationPolicy, service, invalidExtractionRegexTemplateNilConfig(), "", + ), + PlanOnly: true, + ExpectError: regexp.MustCompile("Invalid configuration in set.0.rule.0.actions.0.extraction.0: regex and template cannot both be null"), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathServiceInvalidExtractionsConfig( + escalationPolicy, service, invalidExtractionRegexTemplateValConfig(), "", + ), + PlanOnly: true, + ExpectError: regexp.MustCompile("Invalid configuration in set.0.rule.0.actions.0.extraction.0: regex and template cannot both have values"), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathServiceInvalidExtractionsConfig( + escalationPolicy, service, invalidExtractionRegexNilSourceConfig(), "", + ), + PlanOnly: true, + ExpectError: regexp.MustCompile("Invalid configuration in set.0.rule.0.actions.0.extraction.0: source can't be blank"), + }, + // Providing invalid extractions attributes for the catch_all rule + { + Config: testAccCheckPagerDutyEventOrchestrationPathServiceInvalidExtractionsConfig( + escalationPolicy, service, "", invalidExtractionRegexTemplateNilConfig(), + ), + PlanOnly: true, + ExpectError: regexp.MustCompile("Invalid configuration in catch_all.0.actions.0.extraction.0: regex and template cannot both be null"), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathServiceInvalidExtractionsConfig( + escalationPolicy, service, "", invalidExtractionRegexTemplateValConfig(), + ), + PlanOnly: true, + ExpectError: regexp.MustCompile("Invalid configuration in catch_all.0.actions.0.extraction.0: regex and template cannot both have values"), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathServiceInvalidExtractionsConfig( + escalationPolicy, service, "", invalidExtractionRegexNilSourceConfig(), + ), + PlanOnly: true, + ExpectError: regexp.MustCompile("Invalid configuration in catch_all.0.actions.0.extraction.0: source can't be blank"), + }, + // Adding/updating/deleting all actions + { + Config: testAccCheckPagerDutyEventOrchestrationPathServiceAllActionsConfig(escalationPolicy, service), + Check: resource.ComposeTestCheckFunc( + append( + baseChecks, + []resource.TestCheckFunc{ + resource.TestCheckResourceAttrSet(resourceName, "set.0.rule.0.id"), + resource.TestCheckResourceAttrSet(resourceName, "set.1.rule.0.id"), + resource.TestCheckResourceAttrSet(resourceName, "set.1.rule.1.id"), + }..., + )..., + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathServiceAllActionsUpdateConfig(escalationPolicy, service), + Check: resource.ComposeTestCheckFunc( + append( + baseChecks, + []resource.TestCheckFunc{ + resource.TestCheckResourceAttrSet(resourceName, "set.0.rule.0.id"), + resource.TestCheckResourceAttrSet(resourceName, "set.1.rule.0.id"), + resource.TestCheckResourceAttrSet(resourceName, "set.1.rule.1.id"), + }..., + )..., + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathServiceAllActionsDeleteConfig(escalationPolicy, service), + Check: resource.ComposeTestCheckFunc( + append( + baseChecks, + []resource.TestCheckFunc{ + resource.TestCheckResourceAttrSet(resourceName, "set.0.rule.0.id"), + resource.TestCheckResourceAttrSet(resourceName, "set.1.rule.0.id"), + resource.TestCheckResourceAttrSet(resourceName, "set.1.rule.1.id"), + }..., + )..., + ), + }, + // Deleting sets and the service path resource + { + Config: testAccCheckPagerDutyEventOrchestrationPathServiceOneSetNoActionsConfig(escalationPolicy, service), + Check: resource.ComposeTestCheckFunc( + append( + baseChecks, + resource.TestCheckResourceAttrSet(resourceName, "set.0.rule.0.id"), + )..., + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathServiceResourceDeleteConfig(escalationPolicy, service), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationServicePathNotExists(resourceName), + ), + }, + }, + }) +} + +func testAccCheckPagerDutyEventOrchestrationServicePathDestroy(s *terraform.State) error { + client, _ := testAccProvider.Meta().(*Config).Client() + for _, r := range s.RootModule().Resources { + if r.Type != "pagerduty_event_orchestration_path_service" { + continue + } + + srv := s.RootModule().Resources["pagerduty_service.bar"] + + if _, _, err := client.EventOrchestrationPaths.Get(srv.Primary.ID, "service"); err == nil { + return fmt.Errorf("Event Orchestration Service Path still exists") + } + } + return nil +} + +func testAccCheckPagerDutyEventOrchestrationPathServiceExists(rn string) resource.TestCheckFunc { + return func(s *terraform.State) error { + orch, ok := s.RootModule().Resources[rn] + if !ok { + return fmt.Errorf("Not found: %s", rn) + } + if orch.Primary.ID == "" { + return fmt.Errorf("No Event Orchestration Service ID is set") + } + + client, _ := testAccProvider.Meta().(*Config).Client() + found, _, err := client.EventOrchestrationPaths.Get(orch.Primary.ID, "service") + if err != nil { + return err + } + if found.Parent.ID != orch.Primary.ID { + return fmt.Errorf("Event Orchrestration Service not found: %v - %v", orch.Primary.ID, found) + } + + return nil + } +} + +func testAccCheckPagerDutyEventOrchestrationServicePathNotExists(rn string) resource.TestCheckFunc { + return func(s *terraform.State) error { + _, ok := s.RootModule().Resources[rn] + if ok { + return fmt.Errorf("Event Orchestration Service Path is not deleted from the state: %s", rn) + } + + return nil + } +} + +func testAccCheckPagerDutyEventOrchestrationPathServiceServiceID(rn, sn string) resource.TestCheckFunc { + return func(s *terraform.State) error { + p, _ := s.RootModule().Resources[rn] + srv, ok := s.RootModule().Resources[sn] + + if !ok { + return fmt.Errorf("Service not found: %s", sn) + } + + var pId = p.Primary.Attributes["service"] + var sId = srv.Primary.Attributes["id"] + if pId != sId { + return fmt.Errorf("Event Orchestration Service path service ID (%v) not matching provided service ID: %v", pId, sId) + } + + return nil + } +} + +func createBaseServicePathConfig(ep, s string) string { + return fmt.Sprintf(` + resource "pagerduty_user" "foo" { + name = "tf-user" + email = "user@pagerduty.com" + color = "green" + role = "user" + job_title = "foo" + description = "foo" + } + + resource "pagerduty_escalation_policy" "foo" { + name = "%s" + description = "bar" + num_loops = 2 + + rule { + escalation_delay_in_minutes = 10 + target { + type = "user_reference" + id = pagerduty_user.foo.id + } + } + } + + resource "pagerduty_service" "bar" { + name = "%s" + escalation_policy = pagerduty_escalation_policy.foo.id + + incident_urgency_rule { + type = "constant" + urgency = "high" + } + } + `, ep, s) +} + +func testAccCheckPagerDutyEventOrchestrationPathServiceDefaultConfig(ep, s string) string { + return fmt.Sprintf("%s%s", createBaseServicePathConfig(ep, s), + `resource "pagerduty_event_orchestration_service" "serviceA" { + service = pagerduty_service.bar.id + + set { + id = "start" + } + + catch_all { + actions { } + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationPathServiceAutomationActionsConfig(ep, s string) string { + return fmt.Sprintf("%s%s", createBaseServicePathConfig(ep, s), + `resource "pagerduty_event_orchestration_service" "serviceA" { + service = pagerduty_service.bar.id + + set { + id = "start" + rule { + label = "rule 1" + actions { + automation_action { + name = "test" + url = "https://test.com" + auto_send = true + + header { + key = "foo" + value = "bar" + } + header { + key = "baz" + value = "buz" + } + + parameter { + key = "source" + value = "orch" + } + parameter { + key = "region" + value = "us" + } + } + } + } + } + + catch_all { + actions { + automation_action { + name = "catch-all test" + url = "https://catch-all-test.com" + auto_send = true + + header { + key = "foo1" + value = "bar1" + } + header { + key = "baz1" + value = "buz1" + } + + parameter { + key = "source1" + value = "orch1" + } + parameter { + key = "region1" + value = "us1" + } + } + } + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationPathServiceAutomationActionsParamsUpdateConfig(ep, s string) string { + return fmt.Sprintf("%s%s", createBaseServicePathConfig(ep, s), + `resource "pagerduty_event_orchestration_service" "serviceA" { + service = pagerduty_service.bar.id + + set { + id = "start" + rule { + label = "rule 1" + actions { + automation_action { + name = "test1" + url = "https://test1.com" + + header { + key = "foo1" + value = "bar1" + } + parameter { + key = "source_region" + value = "eu" + } + } + } + } + } + + catch_all { + actions { + automation_action { + name = "catch-all test upd" + url = "https://catch-all-test-upd.com" + + header { + key = "baz2" + value = "buz2" + } + + parameter { + key = "source2" + value = "orch2" + } + } + } + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationPathServiceAutomationActionsParamsDeleteConfig(ep, s string) string { + return fmt.Sprintf("%s%s", createBaseServicePathConfig(ep, s), + `resource "pagerduty_event_orchestration_service" "serviceA" { + service = pagerduty_service.bar.id + + set { + id = "start" + rule { + label = "rule 1" + actions { + automation_action { + name = "test" + url = "https://test.com" + } + } + } + } + + catch_all { + actions { + automation_action { + name = "catch-all test upd" + url = "https://catch-all-test-upd.com" + } + } + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationPathServiceInvalidExtractionsConfig(ep, s, re, cae string) string { + return fmt.Sprintf( + "%s%s", + createBaseServicePathConfig(ep, s), + fmt.Sprintf(`resource "pagerduty_event_orchestration_service" "serviceA" { + service = pagerduty_service.bar.id + + set { + id = "start" + rule { + actions { + %s + } + } + } + catch_all { + actions { + %s + } + } + } + `, re, cae), + ) +} + +func testAccCheckPagerDutyEventOrchestrationPathServiceAllActionsConfig(ep, s string) string { + return fmt.Sprintf("%s%s", createBaseServicePathConfig(ep, s), + `resource "pagerduty_event_orchestration_service" "serviceA" { + service = pagerduty_service.bar.id + + set { + id = "start" + rule { + label = "rule 1" + condition { + expression = "event.summary matches part 'timeout'" + } + condition { + expression = "event.custom_details.timeout_err exists" + } + actions { + route_to = "set-1" + priority = "P0IN2KQ" + annotate = "Routed through an event orchestration" + pagerduty_automation_action { + action_id = "01CSB5SMOKCKVRI5GN0LJG7SMB" + } + severity = "critical" + event_action = "trigger" + variable { + name = "hostname" + path = "event.source" + type = "regex" + value = "Source host: (.*)" + } + variable { + name = "cpu_val" + path = "event.custom_details.cpu" + type = "regex" + value = "(.*)" + } + extraction { + target = "event.summary" + template = "High CPU usage on {{variables.hostname}}" + } + extraction { + regex = ".*" + source = "event.group" + target = "event.custom_details.message" + } + } + } + } + set { + id = "set-1" + rule { + label = "set-1 rule 1" + actions { + suspend = 300 + } + } + rule { + label = "set-1 rule 2" + condition { + expression = "event.source matches part 'stg-'" + } + actions { + suppress = true + } + } + } + + catch_all { + actions { + suspend = 120 + priority = "P0IN2KW" + annotate = "Routed through an event orchestration - catch-all rule" + pagerduty_automation_action { + action_id = "01CSB5SMOKCKVRI5GN0LJG7SMC" + } + severity = "warning" + event_action = "trigger" + variable { + name = "user_id" + path = "event.custom_details.user_id" + type = "regex" + value = "Source host: (.*)" + } + variable { + name = "updated_at" + path = "event.custom_details.updated_at" + type = "regex" + value = "(.*)" + } + extraction { + target = "event.custom_details.message" + template = "Last modified by {{variables.user_id}} on {{variables.updated_at}}" + } + extraction { + regex = ".*" + source = "event.custom_details.region" + target = "event.group" + } + } + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationPathServiceAllActionsUpdateConfig(ep, s string) string { + return fmt.Sprintf("%s%s", createBaseServicePathConfig(ep, s), + `resource "pagerduty_event_orchestration_service" "serviceA" { + service = pagerduty_service.bar.id + + set { + id = "start" + rule { + label = "rule 1 updated" + condition { + expression = "event.custom_details.timeout_err matches part 'timeout'" + } + actions { + route_to = "set-2" + priority = "P0IN2KR" + annotate = "Routed through a service orchestration!" + pagerduty_automation_action { + action_id = "01CSB5SMOKCKVRI5GN0LJG7SMBUPDATED" + } + severity = "warning" + event_action = "resolve" + variable { + name = "cpu_val_upd" + path = "event.custom_details.cpu_upd" + type = "regex" + value = "CPU:(.*)" + } + extraction { + regex = ".*" + source = "event.custom_details.region_upd" + target = "event.source" + } + extraction { + target = "event.custom_details.message_upd" + template = "[UPD] High CPU usage on {{variables.hostname}}: {{variables.cpu_val}}" + } + } + } + } + set { + id = "set-2" + rule { + label = "set-2 rule 1" + actions { + suspend = 15 + } + } + rule { + label = "set-2 rule 2" + condition { + expression = "event.source matches part 'test-'" + } + actions { + annotate = "Matched set-2 rule 2" + variable { + name = "host_name" + path = "event.custom_details.memory" + type = "regex" + value = "High memory usage on (.*) server" + } + extraction { + target = "event.summary" + template = "High memory usage on {{variables.hostname}} server: {{event.custom_details.max_memory}}" + } + extraction { + regex = ".*" + source = "event.custom_details.region" + target = "event.group" + } + extraction { + regex = ".*" + source = "event.custom_details.hostname" + target = "event.source" + } + } + } + } + + catch_all { + actions { + suspend = 360 + suppress = true + priority = "P0IN2KX" + annotate = "[UPD] Routed through an event orchestration - catch-all rule" + pagerduty_automation_action { + action_id = "01CSB5SMOKCKVRI5GN0LJG7SMD" + } + severity = "info" + event_action = "resolve" + variable { + name = "updated_at_upd" + path = "event.custom_details.updated_at" + type = "regex" + value = "UPD (.*)" + } + extraction { + regex = ".*" + source = "event.custom_details.region_upd" + target = "event.class" + } + } + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationPathServiceAllActionsDeleteConfig(ep, s string) string { + return fmt.Sprintf("%s%s", createBaseServicePathConfig(ep, s), + `resource "pagerduty_event_orchestration_service" "serviceA" { + service = pagerduty_service.bar.id + + set { + id = "start" + rule { + label = "rule 1 updated" + actions { + route_to = "set-2" + } + } + } + set { + id = "set-2" + rule { + label = "set-2 rule 1" + actions { } + } + rule { + label = "set-2 rule 2" + actions { } + } + } + + catch_all { + actions { } + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationPathServiceOneSetNoActionsConfig(ep, s string) string { + return fmt.Sprintf("%s%s", createBaseServicePathConfig(ep, s), + `resource "pagerduty_event_orchestration_service" "serviceA" { + service = pagerduty_service.bar.id + + set { + id = "start" + rule { + label = "rule 1 updated" + actions {} + } + } + + catch_all { + actions { } + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationPathServiceResourceDeleteConfig(ep, s string) string { + return createBaseServicePathConfig(ep, s) +} diff --git a/pagerduty/resource_pagerduty_event_orchestration_path_unrouted.go b/pagerduty/resource_pagerduty_event_orchestration_path_unrouted.go new file mode 100644 index 000000000..2fc4cc787 --- /dev/null +++ b/pagerduty/resource_pagerduty_event_orchestration_path_unrouted.go @@ -0,0 +1,445 @@ +package pagerduty + +import ( + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/heimweh/go-pagerduty/pagerduty" +) + +func resourcePagerDutyEventOrchestrationPathUnrouted() *schema.Resource { + return &schema.Resource{ + Read: resourcePagerDutyEventOrchestrationPathUnroutedRead, + Create: resourcePagerDutyEventOrchestrationPathUnroutedCreate, + Update: resourcePagerDutyEventOrchestrationPathUnroutedUpdate, + Delete: resourcePagerDutyEventOrchestrationPathUnroutedDelete, + Importer: &schema.ResourceImporter{ + State: resourcePagerDutyEventOrchestrationPathUnroutedImport, + }, + CustomizeDiff: checkExtractions, + Schema: map[string]*schema.Schema{ + "event_orchestration": { + Type: schema.TypeString, + Required: true, + }, + "set": { + Type: schema.TypeList, + Required: true, + MinItems: 1, // An Unrouted Orchestration must contain at least a "start" set + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Required: true, + }, + "rule": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + "label": { + Type: schema.TypeString, + Optional: true, + }, + "condition": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: eventOrchestrationPathConditionsSchema, + }, + }, + "actions": { + Type: schema.TypeList, + Required: true, // even if there are no actions, API returns actions as an empty list + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "route_to": { + Type: schema.TypeString, + Optional: true, // If there is only start set we don't need route_to + }, + "severity": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateEventOrchestrationPathSeverity(), + }, + "event_action": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateEventOrchestrationPathEventAction(), + }, + "variable": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: eventOrchestrationPathVariablesSchema, + }, + }, + "extraction": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: eventOrchestrationPathExtractionsSchema, + }, + }, + }, + }, + }, + "disabled": { + Type: schema.TypeBool, + Optional: true, + }, + }, + }, + }, + }, + }, + }, + "catch_all": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "actions": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "suppress": { + Type: schema.TypeBool, + Computed: true, + }, + "severity": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateValueFunc([]string{ + "info", + "error", + "warning", + "critical", + }), + }, + "event_action": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateValueFunc([]string{ + "trigger", + "resolve", + }), + }, + "variable": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: eventOrchestrationPathVariablesSchema, + }, + }, + "extraction": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: eventOrchestrationPathExtractionsSchema, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func resourcePagerDutyEventOrchestrationPathUnroutedRead(d *schema.ResourceData, meta interface{}) error { + client, err := meta.(*Config).Client() + if err != nil { + return err + } + + return resource.Retry(2*time.Minute, func() *resource.RetryError { + + log.Printf("[INFO] Reading PagerDuty Event Orchestration Path of type: %s for orchestration: %s", "unrouted", d.Id()) + + if unroutedPath, _, err := client.EventOrchestrationPaths.Get(d.Id(), "unrouted"); err != nil { + time.Sleep(2 * time.Second) + return resource.RetryableError(err) + } else if unroutedPath != nil { + if unroutedPath.Sets != nil { + d.Set("set", flattenUnroutedSets(unroutedPath.Sets)) + } + + if unroutedPath.CatchAll != nil { + d.Set("catch_all", flattenUnroutedCatchAll(unroutedPath.CatchAll)) + } + } + return nil + }) + +} + +// EventOrchestrationPath cannot be created, use update to add / edit / remove rules and sets +func resourcePagerDutyEventOrchestrationPathUnroutedCreate(d *schema.ResourceData, meta interface{}) error { + return resourcePagerDutyEventOrchestrationPathUnroutedUpdate(d, meta) +} + +// EventOrchestrationPath cannot be deleted, use update to add / edit / remove rules and sets +func resourcePagerDutyEventOrchestrationPathUnroutedDelete(d *schema.ResourceData, meta interface{}) error { + d.SetId("") + return nil +} + +func resourcePagerDutyEventOrchestrationPathUnroutedUpdate(d *schema.ResourceData, meta interface{}) error { + client, err := meta.(*Config).Client() + if err != nil { + return err + } + + updatePath := buildUnroutedPathStructForUpdate(d) + + log.Printf("[INFO] Updating PagerDuty EventOrchestrationPath of type: %s for orchestration: %s", "unrouted", updatePath.Parent.ID) + + return performUnroutedPathUpdate(d, updatePath, client) +} + +func performUnroutedPathUpdate(d *schema.ResourceData, unroutedPath *pagerduty.EventOrchestrationPath, client *pagerduty.Client) error { + retryErr := resource.Retry(30*time.Second, func() *resource.RetryError { + updatedPath, _, err := client.EventOrchestrationPaths.Update(unroutedPath.Parent.ID, "unrouted", unroutedPath) + if err != nil { + return resource.RetryableError(err) + } + if updatedPath == nil { + return resource.NonRetryableError(fmt.Errorf("no event orchestration unrouted found")) + } + d.SetId(unroutedPath.Parent.ID) + d.Set("event_orchestration", unroutedPath.Parent.ID) + if unroutedPath.Sets != nil { + d.Set("set", flattenUnroutedSets(unroutedPath.Sets)) + } + if updatedPath.CatchAll != nil { + d.Set("catch_all", flattenUnroutedCatchAll(updatedPath.CatchAll)) + } + return nil + }) + if retryErr != nil { + time.Sleep(2 * time.Second) + return retryErr + } + return nil +} + +func buildUnroutedPathStructForUpdate(d *schema.ResourceData) *pagerduty.EventOrchestrationPath { + + orchPath := &pagerduty.EventOrchestrationPath{ + Parent: &pagerduty.EventOrchestrationPathReference{ + ID: d.Get("event_orchestration").(string), + }, + } + + if attr, ok := d.GetOk("set"); ok { + orchPath.Sets = expandUnroutedSets(attr.([]interface{})) + } + + if attr, ok := d.GetOk("catch_all"); ok { + orchPath.CatchAll = expandUnroutedCatchAll(attr.([]interface{})) + } + + return orchPath +} + +func expandUnroutedSets(v interface{}) []*pagerduty.EventOrchestrationPathSet { + var sets []*pagerduty.EventOrchestrationPathSet + + for _, set := range v.([]interface{}) { + s := set.(map[string]interface{}) + + orchPathSet := &pagerduty.EventOrchestrationPathSet{ + ID: s["id"].(string), + Rules: expandUnroutedRules(s["rule"]), + } + + sets = append(sets, orchPathSet) + } + + return sets +} + +func expandUnroutedRules(v interface{}) []*pagerduty.EventOrchestrationPathRule { + items := v.([]interface{}) + rules := []*pagerduty.EventOrchestrationPathRule{} + + for _, rule := range items { + r := rule.(map[string]interface{}) + + ruleInSet := &pagerduty.EventOrchestrationPathRule{ + ID: r["id"].(string), + Label: r["label"].(string), + Disabled: r["disabled"].(bool), + Conditions: expandEventOrchestrationPathConditions(r["condition"]), + Actions: expandUnroutedActions(r["actions"]), + } + + rules = append(rules, ruleInSet) + } + return rules +} + +func expandUnroutedActions(v interface{}) *pagerduty.EventOrchestrationPathRuleActions { + var actions = &pagerduty.EventOrchestrationPathRuleActions{ + Variables: []*pagerduty.EventOrchestrationPathActionVariables{}, + Extractions: []*pagerduty.EventOrchestrationPathActionExtractions{}, + } + + for _, ai := range v.([]interface{}) { + if ai != nil { + am := ai.(map[string]interface{}) + actions.RouteTo = am["route_to"].(string) + actions.Severity = am["severity"].(string) + actions.EventAction = am["event_action"].(string) + actions.Variables = expandEventOrchestrationPathVariables(am["variable"]) + actions.Extractions = expandEventOrchestrationPathExtractions(am["extraction"]) + } + } + + return actions +} + +func expandUnroutedCatchAll(v interface{}) *pagerduty.EventOrchestrationPathCatchAll { + var catchAll = new(pagerduty.EventOrchestrationPathCatchAll) + + for _, ca := range v.([]interface{}) { + if ca != nil { + am := ca.(map[string]interface{}) + catchAll.Actions = expandUnroutedCatchAllActions(am["actions"]) + } + } + + return catchAll +} + +func expandUnroutedCatchAllActions(v interface{}) *pagerduty.EventOrchestrationPathRuleActions { + var actions = new(pagerduty.EventOrchestrationPathRuleActions) + for _, ai := range v.([]interface{}) { + if ai != nil { + am := ai.(map[string]interface{}) + actions.Severity = am["severity"].(string) + actions.EventAction = am["event_action"].(string) + actions.Variables = expandEventOrchestrationPathVariables(am["variable"]) + actions.Extractions = expandEventOrchestrationPathExtractions(am["extraction"]) + } + } + + return actions +} + +func flattenUnroutedSets(orchPathSets []*pagerduty.EventOrchestrationPathSet) []interface{} { + var flattenedSets []interface{} + + for _, set := range orchPathSets { + flattenedSet := map[string]interface{}{ + "id": set.ID, + "rule": flattenUnroutedRules(set.Rules), + } + flattenedSets = append(flattenedSets, flattenedSet) + } + return flattenedSets +} + +func flattenUnroutedRules(rules []*pagerduty.EventOrchestrationPathRule) []interface{} { + var flattenedRules []interface{} + + for _, rule := range rules { + flattenedRule := map[string]interface{}{ + "id": rule.ID, + "label": rule.Label, + "disabled": rule.Disabled, + "condition": flattenEventOrchestrationPathConditions(rule.Conditions), + "actions": flattenUnroutedActions(rule.Actions), + } + flattenedRules = append(flattenedRules, flattenedRule) + } + + return flattenedRules +} + +func flattenUnroutedActions(actions *pagerduty.EventOrchestrationPathRuleActions) []map[string]interface{} { + var actionsMap []map[string]interface{} + + flattenedAction := map[string]interface{}{ + "route_to": actions.RouteTo, + "severity": actions.Severity, + "event_action": actions.EventAction, + } + + if actions.Variables != nil { + flattenedAction["variable"] = flattenEventOrchestrationPathVariables(actions.Variables) + } + if actions.Extractions != nil { + flattenedAction["extraction"] = flattenEventOrchestrationPathExtractions(actions.Extractions) + } + + actionsMap = append(actionsMap, flattenedAction) + + return actionsMap +} + +func flattenUnroutedCatchAll(catchAll *pagerduty.EventOrchestrationPathCatchAll) []map[string]interface{} { + var caMap []map[string]interface{} + + c := make(map[string]interface{}) + + c["actions"] = flattenUnroutedCatchAllActions(catchAll.Actions) + caMap = append(caMap, c) + + return caMap +} + +func flattenUnroutedCatchAllActions(actions *pagerduty.EventOrchestrationPathRuleActions) []map[string]interface{} { + var actionsMap []map[string]interface{} + + flattenedAction := map[string]interface{}{ + "severity": actions.Severity, + "event_action": actions.EventAction, + "suppress": actions.Suppress, // By default suppress is set to "true" by API for unrouted + } + + if actions.Variables != nil { + flattenedAction["variable"] = flattenEventOrchestrationPathVariables(actions.Variables) + } + if actions.Variables != nil { + flattenedAction["extraction"] = flattenEventOrchestrationPathExtractions(actions.Extractions) + } + + actionsMap = append(actionsMap, flattenedAction) + + return actionsMap +} + +func resourcePagerDutyEventOrchestrationPathUnroutedImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + client, err := meta.(*Config).Client() + if err != nil { + return []*schema.ResourceData{}, err + } + // given an orchestration ID import the unrouted orchestration path + orchestrationID := d.Id() + pathType := "unrouted" + _, _, err = client.EventOrchestrationPaths.Get(orchestrationID, pathType) + + if err != nil { + return []*schema.ResourceData{}, err + } + + d.SetId(orchestrationID) + d.Set("event_orchestration", orchestrationID) + + return []*schema.ResourceData{d}, nil +} diff --git a/pagerduty/resource_pagerduty_event_orchestration_path_unrouted_test.go b/pagerduty/resource_pagerduty_event_orchestration_path_unrouted_test.go new file mode 100644 index 000000000..4d2180ec0 --- /dev/null +++ b/pagerduty/resource_pagerduty_event_orchestration_path_unrouted_test.go @@ -0,0 +1,549 @@ +package pagerduty + +import ( + "fmt" + "regexp" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func init() { + resource.AddTestSweepers("pagerduty_event_orchestration_unrouted", &resource.Sweeper{ + Name: "pagerduty_event_orchestration_unrouted", + F: testSweepEventOrchestration, + }) +} + +func TestAccPagerDutyEventOrchestrationPathUnrouted_Basic(t *testing.T) { + team := fmt.Sprintf("tf-team-%s", acctest.RandString(5)) + escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) + service := fmt.Sprintf("tf-%s", acctest.RandString(5)) + orchestration := fmt.Sprintf("tf-orchestration-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckPagerDutyEventOrchestrationPathUnroutedDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckPagerDutyEventOrchestrationPathUnroutedConfigNoRules(team, escalationPolicy, service, orchestration), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationPathUnroutedExists("pagerduty_event_orchestration_unrouted.unrouted"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.0.rule.#", "0"), + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathUnroutedConfigWithConditions(team, escalationPolicy, service, orchestration), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationPathUnroutedExists("pagerduty_event_orchestration_unrouted.unrouted"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.0.rule.0.condition.0.expression", "event.summary matches part 'rds'"), + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathUnroutedConfigWithMultipleRules(team, escalationPolicy, service, orchestration), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationPathUnroutedExists("pagerduty_event_orchestration_unrouted.unrouted"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.0.rule.#", "2"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.0.rule.0.condition.0.expression", "event.summary matches part 'rds'"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.0.rule.0.condition.1.expression", "event.severity matches part 'warning'"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.0.rule.1.condition.0.expression", "event.severity matches part 'info'"), + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathUnroutedWithAllConfig(team, escalationPolicy, service, orchestration), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationPathUnroutedExists("pagerduty_event_orchestration_unrouted.unrouted"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.#", "2"), + //Set #1 + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.0.id", "start"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.0.rule.0.condition.#", "2"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.0.rule.0.actions.0.route_to", "child-1"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.0.rule.0.condition.0.expression", "event.severity matches part 'info'"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.0.rule.0.condition.1.expression", "event.severity matches part 'warning'"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.0.rule.0.actions.0.severity", "info"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.0.rule.0.actions.0.event_action", "trigger"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.0.rule.0.actions.0.variable.#", "2"), + resource.TestCheckTypeSetElemNestedAttrs( + "pagerduty_event_orchestration_unrouted.unrouted", + "set.0.rule.0.actions.0.variable.*", + map[string]string{ + "name": "server_name_cpu", + "path": "event.summary", + "type": "regex", + "value": "High CPU on (.*) server", + }, + ), + resource.TestCheckTypeSetElemNestedAttrs( + "pagerduty_event_orchestration_unrouted.unrouted", + "set.0.rule.0.actions.0.variable.*", + map[string]string{ + "name": "server_name_memory", + "path": "event.custom_details", + "type": "regex", + "value": "High memory usage on (.*) server", + }, + ), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.0.rule.0.actions.0.extraction.#", "2"), + + resource.TestCheckTypeSetElemNestedAttrs( + "pagerduty_event_orchestration_unrouted.unrouted", + "set.0.rule.0.actions.0.extraction.*", + map[string]string{ + "target": "event.summary", + "template": "High memory usage on {{variables.hostname}} server", + }, + ), + resource.TestCheckTypeSetElemNestedAttrs( + "pagerduty_event_orchestration_unrouted.unrouted", + "set.0.rule.0.actions.0.extraction.*", + map[string]string{ + "target": "event.custom_details", + "template": "High memory usage on {{variables.hostname}} server", + }, + ), + //Set #2 + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.1.id", "child-1"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.1.rule.0.condition.0.expression", "event.severity matches part 'warning'"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.1.rule.0.actions.0.event_action", "resolve"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.1.rule.1.condition.0.expression", "event.severity matches part 'critical'"), + // Catch All + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "catch_all.0.actions.0.severity", "critical"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "catch_all.0.actions.0.event_action", "trigger"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "catch_all.0.actions.0.variable.#", "2"), + resource.TestCheckTypeSetElemNestedAttrs( + "pagerduty_event_orchestration_unrouted.unrouted", + "catch_all.0.actions.0.variable.*", + map[string]string{ + "name": "server_name_cpu", + "path": "event.summary", + "type": "regex", + "value": "High CPU on (.*) server", + }, + ), + resource.TestCheckTypeSetElemNestedAttrs( + "pagerduty_event_orchestration_unrouted.unrouted", + "catch_all.0.actions.0.variable.*", + map[string]string{ + "name": "server_name_memory", + "path": "event.custom_details", + "type": "regex", + "value": "High memory usage on (.*) server", + }, + ), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "catch_all.0.actions.0.extraction.#", "2"), + + resource.TestCheckTypeSetElemNestedAttrs( + "pagerduty_event_orchestration_unrouted.unrouted", + "catch_all.0.actions.0.extraction.*", + map[string]string{ + "target": "event.summary", + "template": "High memory usage on {{variables.hostname}} server", + }, + ), + resource.TestCheckTypeSetElemNestedAttrs( + "pagerduty_event_orchestration_unrouted.unrouted", + "catch_all.0.actions.0.extraction.*", + map[string]string{ + "target": "event.custom_details", + "template": "High memory usage on {{variables.hostname}} server", + }, + ), + ), + }, + // Providing invalid extractions attributes for set rules + { + Config: testAccCheckPagerDutyEventOrchestrationPathUnroutedInvalidExtractionsConfig( + team, escalationPolicy, service, orchestration, invalidExtractionRegexTemplateValConfig(), "", + ), + PlanOnly: true, + ExpectError: regexp.MustCompile("Invalid configuration in set.0.rule.0.actions.0.extraction.0: regex and template cannot both have values"), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathUnroutedInvalidExtractionsConfig( + team, escalationPolicy, service, orchestration, invalidExtractionRegexTemplateValConfig(), "", + ), + PlanOnly: true, + ExpectError: regexp.MustCompile("Invalid configuration in set.0.rule.0.actions.0.extraction.0: regex and template cannot both have values"), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathUnroutedInvalidExtractionsConfig( + team, escalationPolicy, service, orchestration, invalidExtractionRegexNilSourceConfig(), "", + ), + PlanOnly: true, + ExpectError: regexp.MustCompile("Invalid configuration in set.0.rule.0.actions.0.extraction.0: source can't be blank"), + }, + // Providing invalid extractions attributes for the catch_all rule + { + Config: testAccCheckPagerDutyEventOrchestrationPathUnroutedInvalidExtractionsConfig( + team, escalationPolicy, service, orchestration, "", invalidExtractionRegexTemplateNilConfig(), + ), + PlanOnly: true, + ExpectError: regexp.MustCompile("Invalid configuration in catch_all.0.actions.0.extraction.0: regex and template cannot both be null"), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathUnroutedInvalidExtractionsConfig( + team, escalationPolicy, service, orchestration, "", invalidExtractionRegexTemplateValConfig(), + ), + PlanOnly: true, + ExpectError: regexp.MustCompile("Invalid configuration in catch_all.0.actions.0.extraction.0: regex and template cannot both have values"), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathUnroutedInvalidExtractionsConfig( + team, escalationPolicy, service, orchestration, "", invalidExtractionRegexNilSourceConfig(), + ), + PlanOnly: true, + ExpectError: regexp.MustCompile("Invalid configuration in catch_all.0.actions.0.extraction.0: source can't be blank"), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathUnroutedConfigNoRules(team, escalationPolicy, service, orchestration), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationPathUnroutedExists("pagerduty_event_orchestration_unrouted.unrouted"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.0.rule.#", "0"), + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathUnroutedConfigDelete(team, escalationPolicy, service, orchestration), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationPathUnroutedNotExists("pagerduty_event_orchestration_unrouted.unrouted"), + ), + }, + }, + }) +} + +func testAccCheckPagerDutyEventOrchestrationPathUnroutedDestroy(s *terraform.State) error { + client, _ := testAccProvider.Meta().(*Config).Client() + for _, r := range s.RootModule().Resources { + if r.Type != "pagerduty_event_orchestration_path_unrouted" { + continue + } + + orch := s.RootModule().Resources["pagerduty_event_orchestration.orch"] + + if _, _, err := client.EventOrchestrationPaths.Get(orch.Primary.ID, "unrouted"); err == nil { + return fmt.Errorf("Event Orchestration Path still exists") + } + } + return nil +} + +func testAccCheckPagerDutyEventOrchestrationPathUnroutedExists(rn string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[rn] + if !ok { + return fmt.Errorf("Not found: %s", rn) + } + if rs.Primary.ID == "" { + return fmt.Errorf("No Event Orchestration Unrouted Path is set") + } + + orch := s.RootModule().Resources["pagerduty_event_orchestration.orch"] + client, _ := testAccProvider.Meta().(*Config).Client() + _, _, err := client.EventOrchestrationPaths.Get(orch.Primary.ID, "unrouted") + + if err != nil { + return fmt.Errorf("Event Orchestration Unrouted Path not found: %v for orchestration %v", "unrouted", orch.Primary.ID) + } + + return nil + } +} + +func testAccCheckPagerDutyEventOrchestrationPathUnroutedNotExists(rn string) resource.TestCheckFunc { + return func(s *terraform.State) error { + _, ok := s.RootModule().Resources[rn] + if ok { + return fmt.Errorf("Event Orchestration Unrouted Path is not deleted: %s", rn) + } + + return nil + } +} + +func testAccCheckPagerDutyEventOrchestrationPathUnroutedConfigDelete(t, ep, s, o string) string { + return createUnroutedBaseConfig(t, ep, s, o) +} + +func createUnroutedBaseConfig(t, ep, s, o string) string { + return fmt.Sprintf(` + resource "pagerduty_team" "foo" { + name = "%s" + } + resource "pagerduty_user" "foo" { + name = "tf-user" + email = "user@pagerduty.com" + color = "green" + role = "user" + job_title = "foo" + description = "foo" + } + resource "pagerduty_escalation_policy" "foo" { + name = "%s" + description = "bar" + num_loops = 2 + rule { + escalation_delay_in_minutes = 10 + target { + type = "user_reference" + id = pagerduty_user.foo.id + } + } + } + resource "pagerduty_service" "bar" { + name = "%s" + escalation_policy = pagerduty_escalation_policy.foo.id + incident_urgency_rule { + type = "constant" + urgency = "high" + } + } + resource "pagerduty_event_orchestration" "orch" { + name = "%s" + team = pagerduty_team.foo.id + } + `, t, ep, s, o) +} + +func testAccCheckPagerDutyEventOrchestrationPathUnroutedConfigNoRules(t, ep, s, o string) string { + return fmt.Sprintf("%s%s", createUnroutedBaseConfig(t, ep, s, o), + `resource "pagerduty_event_orchestration_unrouted" "unrouted" { + event_orchestration = pagerduty_event_orchestration.orch.id + + set { + id = "start" + } + catch_all { + actions { } + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationPathUnroutedConfigWithConditions(t, ep, s, o string) string { + return fmt.Sprintf("%s%s", createUnroutedBaseConfig(t, ep, s, o), + `resource "pagerduty_event_orchestration_unrouted" "unrouted" { + event_orchestration = pagerduty_event_orchestration.orch.id + + set { + id = "start" + rule { + disabled = false + label = "rule1 label" + actions { } + condition { + expression = "event.summary matches part 'rds'" + } + } + } + catch_all { + actions { } + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationPathUnroutedConfigWithMultipleRules(t, ep, s, o string) string { + return fmt.Sprintf("%s%s", createUnroutedBaseConfig(t, ep, s, o), + `resource "pagerduty_event_orchestration_unrouted" "unrouted" { + event_orchestration = pagerduty_event_orchestration.orch.id + + set { + id = "start" + rule { + disabled = false + label = "rule1 label" + actions { } + condition { + expression = "event.summary matches part 'rds'" + } + condition { + expression = "event.severity matches part 'warning'" + } + } + + rule { + disabled = false + label = "rule2 label" + actions { } + condition { + expression = "event.severity matches part 'info'" + } + } + } + catch_all { + actions { } + } + } +`) +} + +func testAccCheckPagerDutyEventOrchestrationPathUnroutedWithAllConfig(t, ep, s, o string) string { + return fmt.Sprintf("%s%s", createUnroutedBaseConfig(t, ep, s, o), + `resource "pagerduty_event_orchestration_unrouted" "unrouted" { + event_orchestration = pagerduty_event_orchestration.orch.id + + set { + id = "start" + rule { + disabled = false + label = "rule1 label" + condition { + expression = "event.severity matches part 'info'" + } + condition { + expression = "event.severity matches part 'warning'" + } + actions { + route_to = "child-1" + severity = "info" + event_action = "trigger" + variable { + name = "server_name_cpu" + path = "event.summary" + type = "regex" + value = "High CPU on (.*) server" + } + variable { + name = "server_name_memory" + path = "event.custom_details" + type = "regex" + value = "High memory usage on (.*) server" + } + extraction { + target = "event.summary" + template = "High memory usage on {{variables.hostname}} server" + } + extraction { + target = "event.custom_details" + template = "High memory usage on {{variables.hostname}} server" + } + } + } + } + set { + id = "child-1" + rule { + disabled = false + label = "rule2 label1" + condition { + expression = "event.severity matches part 'warning'" + } + actions { + severity = "warning" + event_action = "resolve" + variable { + name = "server_name_cpu" + path = "event.summary" + type = "regex" + value = "High CPU on (.*) server" + } + extraction { + target = "event.summary" + template = "High CPU on {{event.custom_details.hostname}} server" + } + } + } + rule { + disabled = false + label = "rule2 label2" + condition { + expression = "event.severity matches part 'critical'" + } + actions { + severity = "warning" + event_action = "trigger" + variable { + name = "server_name_cpu" + path = "event.summary" + type = "regex" + value = "High CPU on (.*) server" + } + extraction { + target = "event.summary" + template = "High CPU on {{event.custom_details.hostname}} server" + } + } + } + } + catch_all { + actions { + severity = "critical" + event_action = "trigger" + variable { + name = "server_name_cpu" + path = "event.summary" + type = "regex" + value = "High CPU on (.*) server" + } + variable { + name = "server_name_memory" + path = "event.custom_details" + type = "regex" + value = "High memory usage on (.*) server" + } + extraction { + target = "event.summary" + template = "High memory usage on {{variables.hostname}} server" + } + extraction { + target = "event.custom_details" + template = "High memory usage on {{variables.hostname}} server" + } + } + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationPathUnroutedInvalidExtractionsConfig(t, ep, s, o, re, cae string) string { + return fmt.Sprintf( + "%s%s", + createUnroutedBaseConfig(t, ep, s, o), + fmt.Sprintf(`resource "pagerduty_event_orchestration_unrouted" "unrouted" { + event_orchestration = pagerduty_event_orchestration.orch.id + + set { + id = "start" + rule { + actions { + %s + } + } + } + catch_all { + actions { + %s + } + } + } + `, re, cae), + ) +} diff --git a/pagerduty/resource_pagerduty_event_orchestration_test.go b/pagerduty/resource_pagerduty_event_orchestration_test.go new file mode 100644 index 000000000..6e39fa640 --- /dev/null +++ b/pagerduty/resource_pagerduty_event_orchestration_test.go @@ -0,0 +1,245 @@ +package pagerduty + +import ( + "fmt" + "log" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func init() { + resource.AddTestSweepers("pagerduty_event_orchestration", &resource.Sweeper{ + Name: "pagerduty_event_orchestration", + F: testSweepEventOrchestration, + Dependencies: []string{ + "pagerduty_schedule", + "pagerduty_team", + "pagerduty_user", + "pagerduty_escalation_policy", + "pagerduty_service", + }, + }) +} + +func testSweepEventOrchestration(region string) error { + config, err := sharedConfigForRegion(region) + if err != nil { + return err + } + + client, err := config.Client() + if err != nil { + return err + } + + resp, _, err := client.EventOrchestrations.List() + if err != nil { + return err + } + + for _, orchestration := range resp.Orchestrations { + if strings.HasPrefix(orchestration.Name, "tf-orchestration-") { + log.Printf("Destroying Event Orchestration %s (%s)", orchestration.Name, orchestration.ID) + if _, err := client.EventOrchestrations.Delete(orchestration.ID); err != nil { + return err + } + } + } + + return nil +} + +func TestAccPagerDutyEventOrchestration_Basic(t *testing.T) { + name := fmt.Sprintf("tf-orchestration-%s", acctest.RandString(5)) + description := fmt.Sprintf("tf-description-%s", acctest.RandString(5)) + nameUpdated := fmt.Sprintf("tf-name-%s", acctest.RandString(5)) + descriptionUpdated := fmt.Sprintf("tf-description-%s", acctest.RandString(5)) + team1 := fmt.Sprintf("tf-team-%s", acctest.RandString(5)) + team2 := fmt.Sprintf("tf-team-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckPagerDutyEventOrchestrationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckPagerDutyEventOrchestrationConfigNameOnly(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationExists("pagerduty_event_orchestration.foo"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration.foo", "name", name, + ), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration.foo", "description", "", + ), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration.foo", "team.#", "0", + ), + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationConfig(name, description, team1, team2), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationExists("pagerduty_event_orchestration.foo"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration.foo", "name", name, + ), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration.foo", "description", description, + ), + testAccCheckPagerDutyEventOrchestrationTeamMatch("pagerduty_event_orchestration.foo", "pagerduty_team.foo"), + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationConfigUpdated(nameUpdated, descriptionUpdated, team1, team2), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationExists("pagerduty_event_orchestration.foo"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration.foo", "name", nameUpdated, + ), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration.foo", "description", descriptionUpdated, + ), + testAccCheckPagerDutyEventOrchestrationTeamMatch("pagerduty_event_orchestration.foo", "pagerduty_team.bar"), + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationConfigDescriptionTeamDeleted(nameUpdated, team1, team2), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationExists("pagerduty_event_orchestration.foo"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration.foo", "name", nameUpdated, + ), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration.foo", "description", "", + ), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration.foo", "team.#", "0", + ), + ), + }, + }, + }) +} + +func testAccCheckPagerDutyEventOrchestrationDestroy(s *terraform.State) error { + client, _ := testAccProvider.Meta().(*Config).Client() + for _, r := range s.RootModule().Resources { + if r.Type != "pagerduty_event_orchestration" { + continue + } + if _, _, err := client.EventOrchestrations.Get(r.Primary.ID); err == nil { + return fmt.Errorf("Event Orchestration still exists") + } + } + return nil +} + +func testAccCheckPagerDutyEventOrchestrationExists(rn string) resource.TestCheckFunc { + return func(s *terraform.State) error { + orch, ok := s.RootModule().Resources[rn] + if !ok { + return fmt.Errorf("Not found: %s", rn) + } + if orch.Primary.ID == "" { + return fmt.Errorf("No Event Orchestration ID is set") + } + + client, _ := testAccProvider.Meta().(*Config).Client() + found, _, err := client.EventOrchestrations.Get(orch.Primary.ID) + if err != nil { + return err + } + if found.ID != orch.Primary.ID { + return fmt.Errorf("Event Orchrestration not found: %v - %v", orch.Primary.ID, found) + } + + return nil + } +} + +func testAccCheckPagerDutyEventOrchestrationTeamMatch(orchName, teamName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + o, orchOk := s.RootModule().Resources[orchName] + + if !orchOk { + return fmt.Errorf("Not found: %s", orchName) + } + + t, tOk := s.RootModule().Resources[teamName] + if !tOk { + return fmt.Errorf("Not found: %s", teamName) + } + + var otId = o.Primary.Attributes["team"] + var tId = t.Primary.Attributes["id"] + + if otId != tId { + return fmt.Errorf("Event Orchestration team ID (%v) not matching provided team ID: %v", otId, tId) + } + + return nil + } +} + +func testAccCheckPagerDutyEventOrchestrationConfigNameOnly(n string) string { + return fmt.Sprintf(` + +resource "pagerduty_event_orchestration" "foo" { + name = "%s" +} +`, n) +} + +func testAccCheckPagerDutyEventOrchestrationConfig(name, description, team1, team2 string) string { + return fmt.Sprintf(` + +resource "pagerduty_team" "foo" { + name = "%s" +} +resource "pagerduty_team" "bar" { + name = "%s" +} +resource "pagerduty_event_orchestration" "foo" { + name = "%s" + description = "%s" + team = pagerduty_team.foo.id +} +`, team1, team2, name, description) +} + +func testAccCheckPagerDutyEventOrchestrationConfigUpdated(name, description, team1, team2 string) string { + return fmt.Sprintf(` + +resource "pagerduty_team" "foo" { + name = "%s" +} +resource "pagerduty_team" "bar" { + name = "%s" +} +resource "pagerduty_event_orchestration" "foo" { + name = "%s" + description = "%s" + team = pagerduty_team.bar.id +} +`, team1, team2, name, description) +} + +func testAccCheckPagerDutyEventOrchestrationConfigDescriptionTeamDeleted(name, team1, team2 string) string { + return fmt.Sprintf(` + +resource "pagerduty_team" "foo" { + name = "%s" +} +resource "pagerduty_team" "bar" { + name = "%s" +} +resource "pagerduty_event_orchestration" "foo" { + name = "%s" +} +`, team1, team2, name) +} diff --git a/pagerduty/util.go b/pagerduty/util.go index ea256a931..7689b8c45 100644 --- a/pagerduty/util.go +++ b/pagerduty/util.go @@ -145,3 +145,10 @@ func stringPtrToStringType(v *string) string { } return *v } + +func intTypeToIntPtr(v int) *int { + if v == 0 { + return nil + } + return &v +} diff --git a/vendor/github.com/heimweh/go-pagerduty/pagerduty/event_orchestration.go b/vendor/github.com/heimweh/go-pagerduty/pagerduty/event_orchestration.go new file mode 100644 index 000000000..0eeedbd5f --- /dev/null +++ b/vendor/github.com/heimweh/go-pagerduty/pagerduty/event_orchestration.go @@ -0,0 +1,127 @@ +package pagerduty + +import ( + "fmt" +) + +type EventOrchestrationService service + +type EventOrchestration struct { + ID string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Description string `json:"description"` + Team *EventOrchestrationObject `json:"team"` + Routes int `json:"routes,omitempty"` + Integrations []*EventOrchestrationIntegration `json:"integrations,omitempty"` +} + +type EventOrchestrationObject struct { + Type string `json:"type,omitempty"` + ID *string `json:"id"` +} + +type EventOrchestrationIntegrationParameters struct { + RoutingKey string `json:"routing_key,omitempty"` + Type string `json:"type,omitempty"` +} + +type EventOrchestrationIntegration struct { + ID string `json:"id,omitempty"` + Parameters *EventOrchestrationIntegrationParameters `json:"parameters,omitempty"` +} + +type EventOrchestrationPayload struct { + Orchestration *EventOrchestration `json:"orchestration,omitempty"` +} + +type ListEventOrchestrationsResponse struct { + Total int `json:"total,omitempty"` + Offset int `json:"offset,omitempty"` + More bool `json:"more,omitempty"` + Limit int `json:"limit,omitempty"` + Orchestrations []*EventOrchestration `json:"orchestrations,omitempty"` +} + +var eventOrchestrationBaseUrl = "/event_orchestrations" + +func (s *EventOrchestrationService) List() (*ListEventOrchestrationsResponse, *Response, error) { + v := new(ListEventOrchestrationsResponse) + v.Total = 0 + + orchestrations := make([]*EventOrchestration, 0) + + // Create a handler closure capable of parsing data from the event orchestrations endpoint + // and appending resultant orchestrations to the return slice. + responseHandler := func(response *Response) (ListResp, *Response, error) { + var result ListEventOrchestrationsResponse + + if err := s.client.DecodeJSON(response, &result); err != nil { + return ListResp{}, response, err + } + + v.Total += result.Total + v.Offset = result.Offset + v.More = result.More + v.Limit = result.Limit + orchestrations = append(orchestrations, result.Orchestrations...) + + // Return stats on the current page. Caller can use this information to + // adjust for requesting additional pages. + return ListResp{ + More: result.More, + Offset: result.Offset, + Limit: result.Limit, + }, response, nil + } + err := s.client.newRequestPagedGetDo(eventOrchestrationBaseUrl, responseHandler) + if err != nil { + return nil, nil, err + } + v.Orchestrations = orchestrations + + return v, nil, nil +} + +func (s *EventOrchestrationService) Create(orchestration *EventOrchestration) (*EventOrchestration, *Response, error) { + v := new(EventOrchestrationPayload) + p := &EventOrchestrationPayload{Orchestration: orchestration} + + resp, err := s.client.newRequestDo("POST", eventOrchestrationBaseUrl, nil, p, v) + + if err != nil { + return nil, nil, err + } + + return v.Orchestration, resp, nil +} + +func (s *EventOrchestrationService) Get(ID string) (*EventOrchestration, *Response, error) { + u := fmt.Sprintf("%s/%s", eventOrchestrationBaseUrl, ID) + v := new(EventOrchestrationPayload) + p := &EventOrchestrationPayload{} + + resp, err := s.client.newRequestDo("GET", u, nil, p, v) + if err != nil { + return nil, nil, err + } + + return v.Orchestration, resp, nil +} + +func (s *EventOrchestrationService) Update(ID string, orchestration *EventOrchestration) (*EventOrchestration, *Response, error) { + u := fmt.Sprintf("%s/%s", eventOrchestrationBaseUrl, ID) + v := new(EventOrchestrationPayload) + p := &EventOrchestrationPayload{Orchestration: orchestration} + + resp, err := s.client.newRequestDo("PUT", u, nil, p, v) + if err != nil { + return nil, nil, err + } + + return v.Orchestration, resp, nil +} + +func (s *EventOrchestrationService) Delete(ID string) (*Response, error) { + u := fmt.Sprintf("%s/%s", eventOrchestrationBaseUrl, ID) + return s.client.newRequestDo("DELETE", u, nil, nil, nil) +} diff --git a/vendor/github.com/heimweh/go-pagerduty/pagerduty/event_orchestration_path.go b/vendor/github.com/heimweh/go-pagerduty/pagerduty/event_orchestration_path.go new file mode 100644 index 000000000..ddc7e0091 --- /dev/null +++ b/vendor/github.com/heimweh/go-pagerduty/pagerduty/event_orchestration_path.go @@ -0,0 +1,147 @@ +package pagerduty + +import ( + "fmt" +) + +type EventOrchestrationPathService service + +type EventOrchestrationPath struct { + Type string `json:"type,omitempty"` + Self string `json:"self,omitempty"` + Parent *EventOrchestrationPathReference `json:"parent,omitempty"` + Sets []*EventOrchestrationPathSet `json:"sets,omitempty"` + CatchAll *EventOrchestrationPathCatchAll `json:"catch_all,omitempty"` + CreatedAt string `json:"created_at,omitempty"` + CreatedBy *EventOrchestrationPathReference `json:"created_by,omitempty"` + UpdatedAt string `json:"updated_at,omitempty"` + UpdatedBy *EventOrchestrationPathReference `json:"updated_by,omitempty"` + Version string `json:"version,omitempty"` +} + +// A reference to a related object (e.g. an EventOrchestration, User, Team, etc) +type EventOrchestrationPathReference struct { + ID string `json:"id,omitempty"` + Type string `json:"type,omitempty"` + Self string `json:"self,omitempty"` +} + +type EventOrchestrationPathSet struct { + ID string `json:"id,omitempty"` + Rules []*EventOrchestrationPathRule `json:"rules"` +} + +type EventOrchestrationPathRule struct { + ID string `json:"id,omitempty"` + Label string `json:"label,omitempty"` + Conditions []*EventOrchestrationPathRuleCondition `json:"conditions"` + Actions *EventOrchestrationPathRuleActions `json:"actions,omitempty"` + Disabled bool `json:"disabled,omitempty"` +} + +type EventOrchestrationPathRuleCondition struct { + // A PCL string: https://developer.pagerduty.com/docs/ZG9jOjM1NTE0MDc0-pcl-overview + Expression string `json:"expression,omitempty"` +} + +// See the full list of supported actions for path types: +// Router: https://developer.pagerduty.com/api-reference/f0fae270c70b3-get-the-router-for-a-global-event-orchestration +// Service: https://developer.pagerduty.com/api-reference/179537b835e2d-get-the-service-orchestration-for-a-service +// Unrouted: https://developer.pagerduty.com/api-reference/70aa1139e1013-get-the-unrouted-orchestration-for-a-global-event-orchestration +type EventOrchestrationPathRuleActions struct { + RouteTo string `json:"route_to"` + Suppress bool `json:"suppress"` + Suspend *int `json:"suspend"` + Priority string `json:"priority"` + Annotate string `json:"annotate"` + PagerdutyAutomationActions []*EventOrchestrationPathPagerdutyAutomationAction `json:"pagerduty_automation_actions"` + AutomationActions []*EventOrchestrationPathAutomationAction `json:"automation_actions"` + Severity string `json:"severity"` + EventAction string `json:"event_action"` + Variables []*EventOrchestrationPathActionVariables `json:"variables"` + Extractions []*EventOrchestrationPathActionExtractions `json:"extractions"` +} + +type EventOrchestrationPathPagerdutyAutomationAction struct { + ActionId string `json:"action_id,omitempty"` +} + +type EventOrchestrationPathAutomationAction struct { + Name string `json:"name,omitempty"` + Url string `json:"url,omitempty"` + AutoSend bool `json:"auto_send,omitempty"` + Headers []*EventOrchestrationPathAutomationActionObject `json:"headers"` + Parameters []*EventOrchestrationPathAutomationActionObject `json:"parameters"` +} + +type EventOrchestrationPathAutomationActionObject struct { + Key string `json:"key,omitempty"` + Value string `json:"value,omitempty"` +} + +type EventOrchestrationPathActionVariables struct { + Name string `json:"name,omitempty"` + Path string `json:"path,omitempty"` + Type string `json:"type,omitempty"` + Value string `json:"value,omitempty"` +} + +type EventOrchestrationPathActionExtractions struct { + Target string `json:"target,omitempty"` + Regex string `json:"regex,omitempty"` + Template string `json:"template,omitempty"` + Source string `json:"source,omitempty"` +} + +type EventOrchestrationPathCatchAll struct { + Actions *EventOrchestrationPathRuleActions `json:"actions,omitempty"` +} + +type EventOrchestrationPathPayload struct { + OrchestrationPath *EventOrchestrationPath `json:"orchestration_path,omitempty"` +} + +const PathTypeRouter string = "router" +const PathTypeService string = "service" +const PathTypeUnrouted string = "unrouted" + +func orchestrationPathUrlBuilder(id string, pathType string) string { + switch { + case pathType == PathTypeService: + return fmt.Sprintf("%s/services/%s", eventOrchestrationBaseUrl, id) + case pathType == PathTypeUnrouted: + return fmt.Sprintf("%s/%s/unrouted", eventOrchestrationBaseUrl, id) + case pathType == PathTypeRouter: + return fmt.Sprintf("%s/%s/router", eventOrchestrationBaseUrl, id) + default: + return "" + } +} + +// Get for EventOrchestrationPath +func (s *EventOrchestrationPathService) Get(id string, pathType string) (*EventOrchestrationPath, *Response, error) { + u := orchestrationPathUrlBuilder(id, pathType) + v := new(EventOrchestrationPathPayload) + + resp, err := s.client.newRequestDo("GET", u, nil, nil, &v) + + if err != nil { + return nil, nil, err + } + + return v.OrchestrationPath, resp, nil +} + +// Update for EventOrchestrationPath +func (s *EventOrchestrationPathService) Update(id string, pathType string, orchestration_path *EventOrchestrationPath) (*EventOrchestrationPath, *Response, error) { + u := orchestrationPathUrlBuilder(id, pathType) + v := new(EventOrchestrationPathPayload) + p := EventOrchestrationPathPayload{OrchestrationPath: orchestration_path} + + resp, err := s.client.newRequestDo("PUT", u, nil, p, &v) + if err != nil { + return nil, nil, err + } + + return v.OrchestrationPath, resp, nil +} diff --git a/vendor/github.com/heimweh/go-pagerduty/pagerduty/pagerduty.go b/vendor/github.com/heimweh/go-pagerduty/pagerduty/pagerduty.go index e3dbbaf8f..f25b916d7 100644 --- a/vendor/github.com/heimweh/go-pagerduty/pagerduty/pagerduty.go +++ b/vendor/github.com/heimweh/go-pagerduty/pagerduty/pagerduty.go @@ -41,6 +41,8 @@ type Client struct { Extensions *ExtensionService MaintenanceWindows *MaintenanceWindowService Rulesets *RulesetService + EventOrchestrations *EventOrchestrationService + EventOrchestrationPaths *EventOrchestrationPathService Schedules *ScheduleService Services *ServicesService Teams *TeamService @@ -99,6 +101,8 @@ func NewClient(config *Config) (*Client, error) { c.EscalationPolicies = &EscalationPolicyService{c} c.MaintenanceWindows = &MaintenanceWindowService{c} c.Rulesets = &RulesetService{c} + c.EventOrchestrations = &EventOrchestrationService{c} + c.EventOrchestrationPaths = &EventOrchestrationPathService{c} c.Schedules = &ScheduleService{c} c.Services = &ServicesService{c} c.Teams = &TeamService{c} diff --git a/vendor/go.mongodb.org/mongo-driver/mongo/options/datakeyoptions.go b/vendor/go.mongodb.org/mongo-driver/mongo/options/datakeyoptions.go index 3da8f652a..c6a17f9e0 100644 --- a/vendor/go.mongodb.org/mongo-driver/mongo/options/datakeyoptions.go +++ b/vendor/go.mongodb.org/mongo-driver/mongo/options/datakeyoptions.go @@ -22,7 +22,7 @@ func DataKey() *DataKeyOptions { // If being used with a local KMS provider, this option is not applicable and should not be specified. // // For the AWS, Azure, and GCP KMS providers, this option is required and must be a document. For each, the value of the -// "endpoint" or "keyVaultEndpoint" must be a host name with an optional port number (e.g. "foo.test" or "foo.test:443"). +// "endpoint" or "keyVaultEndpoint" must be a host name with an optional port number (e.g. "foo.com" or "foo.com:443"). // // When using AWS, the document must have the format: // { diff --git a/vendor/modules.txt b/vendor/modules.txt index 8f52ef197..0fd9953e9 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -124,7 +124,7 @@ github.com/hashicorp/terraform-registry-address github.com/hashicorp/terraform-svchost # github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d github.com/hashicorp/yamux -# github.com/heimweh/go-pagerduty v0.0.0-20220422231448-43095fe5ba3f +# github.com/heimweh/go-pagerduty v0.0.0-20220527195341-4e587aa9b58e ## explicit github.com/heimweh/go-pagerduty/pagerduty # github.com/klauspost/compress v1.11.2 diff --git a/website/docs/d/event_orchestration.html.markdown b/website/docs/d/event_orchestration.html.markdown new file mode 100644 index 000000000..e9cb650ca --- /dev/null +++ b/website/docs/d/event_orchestration.html.markdown @@ -0,0 +1,60 @@ +--- +layout: "pagerduty" +page_title: "PagerDuty: pagerduty_event_orchestration" +sidebar_current: "docs-pagerduty-datasource-event-orchestration" +description: |- + Get information about a Global Event Orchestration that you have created. +--- + +# pagerduty\_event_orchestration + +Use this data source to get information about a specific Global [Event Orchestration][1] + +## Example Usage +```hcl +resource "pagerduty_event_orchestration" "tf_orch_a" { + name = "Test Event Orchestration" +} + +data "pagerduty_event_orchestration" "tf_my_monitor" { + name = pagerduty_event_orchestration.tf_orch_a.name +} + +resource "pagerduty_event_orchestration_router" "router" { + parent { + id = data.pagerduty_event_orchestration.tf_my_monitor.id + } + catch_all { + actions { + route_to = "unrouted" + } + } + set { + id = "start" + rule { + actions { + route_to = pagerduty_service.db.id + } + } + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the Global Event orchestration to find in the PagerDuty API. + +## Attributes Reference + +* `id` - The ID of the found Event Orchestration. +* `name` - The name of the found Event Orchestration. +* `integration` - An integration for the Event Orchestration. + * `id` - ID of the integration + * `parameters` + * `routing_key` - Routing key that routes to this Orchestration. + * `type` - Type of the routing key. `global` is the default type. + + +[1]: https://developer.pagerduty.com/api-reference/7ba0fe7bdb26a-list-event-orchestrations diff --git a/website/docs/r/event_orchestration.html.markdown b/website/docs/r/event_orchestration.html.markdown new file mode 100644 index 000000000..1fcb07d33 --- /dev/null +++ b/website/docs/r/event_orchestration.html.markdown @@ -0,0 +1,52 @@ +--- +layout: "pagerduty" +page_title: "PagerDuty: pagerduty_event_orchestration" +sidebar_current: "docs-pagerduty-resource-event-orchestration" +description: |- + Creates and manages a Global Event Orchestration in PagerDuty. +--- + +# pagerduty_event_orchestration + +[Global Event Orchestrations](https://support.pagerduty.com/docs/event-orchestration#global-orchestrations) allow you define a set of Event Rules, so that when you ingest events using the Orchestration's Routing Key your events will be routed to the correct Service, based on the event's content. + +## Example of configuring a Global Event Orchestration + +```hcl +resource "pagerduty_team" "engineering" { + name = "Engineering" +} + +resource "pagerduty_event_orchestration" "my_monitor" { + name = "My Monitoring Orchestration" + description = "Send events to a pair of services" + team = pagerduty_team.engineering.id +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) Name of the Event Orchestration. +* `description` - (Optional) A human-friendly description of the Event Orchestration. +* `team` - (Optional) ID of the team that owns the Event Orchestration. If none is specified, only admins have access. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The ID of the Event Orchestration. +* `integration` - An integration for the Event Orchestration. + * `id` - ID of the integration + * `parameters` + * `routing_key` - Routing key that routes to this Orchestration. + * `type` - Type of the routing key. `global` is the default type. + +## Import + +EventOrchestrations can be imported using the `id`, e.g. + +``` +$ terraform import pagerduty_event_orchestration.main 19acac92-027a-4ea0-b06c-bbf516519601 +``` diff --git a/website/docs/r/event_orchestration_router.html.markdown b/website/docs/r/event_orchestration_router.html.markdown new file mode 100644 index 000000000..822588006 --- /dev/null +++ b/website/docs/r/event_orchestration_router.html.markdown @@ -0,0 +1,93 @@ +--- +layout: "pagerduty" +page_title: "PagerDuty: pagerduty_event_orchestration_router" +sidebar_current: "docs-pagerduty-resource-event-orchestration-router" +description: |- + Creates and manages a Router for Global Event Orchestration in PagerDuty. +--- + +# pagerduty_event_orchestration_router + +An Orchestration Router allows users to create a set of Event Rules. The Router evaluates events sent to this Orchestration against each of its rules, one at a time, and routes the event to a specific Service based on the first rule that matches. If an event doesn't match any rules, it'll be sent to service specified in the `catch_all` or to the "Unrouted" Orchestration if no service is specified. + +## Example of configuring Router rules for an Orchestration + +In this example the user has defined the Router with two rules, each routing to a different service. + +This example assumes services used in the `route_to` configuration already exists. So it does not show creation of service resource. + +```hcl +resource "pagerduty_event_orchestration_router" "router" { + event_orchestration = pagerduty_event_orchestration.my_monitor.id + set { + rule { + label = "Events relating to our relational database" + condition { + expression = "event.summary matches part 'database'" + } + condition { + expression = "event.source matches regex 'db[0-9]+-server'" + } + actions { + route_to = pageduty_service.database.id + } + } + rule { + condition { + expression = "event.summary matches part 'www'" + } + actions { + route_to = pagerduty_service.www.id + } + } + } + catch_all { + actions { + route_to = "unrouted" + } + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `event_orchestration` - (Required) ID of the Event Orchestration to which the Router belongs. +* `set` - (Required) The Router contains a single set of rules (the "start" set). +* `catch_all` - (Required) When none of the rules match an event, the event will be routed according to the catch_all settings. + +### Set (`set`) supports the following: +* `id` - (Required) ID of the `start` set. Router supports only one set and it's id has to be `start` +* `rule` - (Optional) The Router evaluates Events against these Rules, one at a time, and routes each Event to a specific Service based on the first rule that matches. If no rules are provided as part of Terraform configuration, the API returns empty list of rules. + +### Rule (`rule`) supports the following: +* `label` - (Optional) A description of this rule's purpose. +* `condition` - (Optional) Each of these conditions is evaluated to check if an event matches this rule. The rule is considered a match if any of these conditions match. If none are provided, the event will _always_ match against the rule. +* `actions` - (Required) Actions that will be taken to change the resulting alert and incident, when an event matches this rule. +* `disabled` - (Optional) Indicates whether the rule is disabled and would therefore not be evaluated. + +### Condition (`condition`) supports the following: +* `expression`- (Required) A [PCL condition](https://developer.pagerduty.com/docs/ZG9jOjM1NTE0MDc0-pcl-overview) string. + +### Actions (`actions`) supports the following: +* `route_to` - (Required) The ID of the target Service for the resulting alert. + +### Catch All (`catch_all`) supports the following: +* `actions` - (Required) These are the actions that will be taken to change the resulting alert and incident. + * `route_to` - (Required) Defines where an alert will be sent if doesn't match any rules. Can either be the ID of a Service _or_ the string `"unrouted"` to send events to the Unrouted Orchestration. + +## Attributes Reference + +The following attributes are exported: +* `self` - The URL at which the Router Orchestration is accessible. +* `rule` + * `id` - The ID of the rule within the `start` set. + +## Import + +Router can be imported using the `id` of the Event Orchestration, e.g. + +``` +$ terraform import pagerduty_event_orchestration_router 1b49abe7-26db-4439-a715-c6d883acfb3e +``` diff --git a/website/docs/r/event_orchestration_service.html.markdown b/website/docs/r/event_orchestration_service.html.markdown new file mode 100644 index 000000000..cda7a031d --- /dev/null +++ b/website/docs/r/event_orchestration_service.html.markdown @@ -0,0 +1,215 @@ +--- +layout: "pagerduty" +page_title: "PagerDuty: pagerduty_event_orchestration_service" +sidebar_current: "docs-pagerduty-resource-event-orchestration-service" +description: |- + Creates and manages a Service Orchestration for a Service. +--- + +# pagerduty_event_orchestration_service + +A [Service Orchestration](https://support.pagerduty.com/docs/event-orchestration#service-orchestrations) allows you to create a set of Event Rules. The Service Orchestration evaluates Events sent to this Service against each of its rules, beginning with the rules in the "start" set. When a matching rule is found, it can modify and enhance the event and can route the event to another set of rules within this Service Orchestration for further processing. + +**Note:** If you have a Service that uses [Service Event Rules](https://support.pagerduty.com/docs/rulesets#service-event-rules), you can switch to [Service Orchestrations](https://support.pagerduty.com/docs/event-orchestration#service-orchestrations) at any time. Please read the [Switch to Service Orchestrations](https://support.pagerduty.com/docs/event-orchestration#switch-to-service-orchestrations) instructions for more information. + +## Example of configuring a Service Orchestration + +This example shows creating `Team`, `User`, `Escalation Policy`, and `Service` resources followed by creating a Service Orchestration to handle Events sent to that Service. + +This example also shows using `priority` [data source](https://registry.terraform.io/providers/PagerDuty/pagerduty/latest/docs/data-sources/priority) to configure `priority` action for a rule. If the Event matches the first rule in set "step-two" the resulting incident will have the Priority `P1`. + +This example shows a Service Orchestration that has nested sets: a rule in the "start" set has a `route_to` action pointing at the "step-two" set. + +The `catch_all` actions will be applied if an Event reaches the end of any set without matching any rules in that set. In this example the `catch_all` doesn't have any `actions` so it'll leave events as-is. + + +```hcl +resource "pagerduty_team" "engineering" { + name = "Engineering" +} + +resource "pagerduty_user" "example" { + name = "Earline Greenholt" + email = "125.greenholt.earline@graham.name" + teams = [pagerduty_team.engineering.id] +} + +resource "pagerduty_escalation_policy" "foo" { + name = "Engineering Escalation Policy" + num_loops = 2 + + rule { + escalation_delay_in_minutes = 10 + target { + type = "user" + id = pagerduty_user.example.id + } + } +} + +resource "pagerduty_service" "example" { + name = "My Web App" + auto_resolve_timeout = 14400 + acknowledgement_timeout = 600 + escalation_policy = pagerduty_escalation_policy.example.id + alert_creation = "create_alerts_and_incidents" +} + +data "pagerduty_priority" "p1" { + name = "P1" +} + +resource "pagerduty_event_orchestration_service" "www" { + service = pagerduty_service.example.id + set { + id = "start" + rule { + label = "Always apply some consistent event transformations to all events" + actions { + variable { + name = "hostname" + path = "event.component" + value = "hostname: (.*)" + type = "regex" + } + extraction { + # Demonstrating a template-style extraction + template = "{{variables.hostname}}" + target = "event.custom_details.hostname" + } + extraction { + # Demonstrating a regex-style extraction + source = "event.source" + regex = "www (.*) service" + target = "event.source" + } + # Id of the next set + route_to = "step-two" + } + } + } + set { + id = "step-two" + rule { + label = "All critical alerts should be treated as P1 incident" + condition { + expression = "event.severity matches 'critical'" + } + actions { + annotate = "Please use our P1 runbook: https://docs.test/p1-runbook" + priority = data.pagerduty_priority.p1.id + } + } + rule { + label = "If there's something wrong on the canary let the team know about it in our deployments Slack channel" + condition { + expression = "event.custom_details.hostname matches part 'canary'" + } + # create webhook action with parameters and headers + actions { + automation_action { + name = "Canary Slack Notification" + url = "https://our-slack-listerner.test/canary-notification" + auto_send = true + parameter { + key = "channel" + value = "#my-team-channel" + } + parameter { + key = "message" + value = "something is wrong with the canary deployment" + } + header { + key = "X-Notification-Source" + value = "PagerDuty Incident Webhook" + } + } + } + } + rule { + label = "Never bother the on-call for info-level events outside of work hours" + condition { + expression = "event.severity matches 'info' and not (now in Mon,Tue,Wed,Thu,Fri 09:00:00 to 17:00:00 America/Los_Angeles)" + } + actions { + suppress = true + } + } + } + catch_all { + actions { } + } +} +``` +## Argument Reference + +The following arguments are supported: + +* `service` - (Required) ID of the Service to which this Service Orchestration belongs to. +* `set` - (Required) A Service Orchestration must contain at least a "start" set, but can contain any number of additional sets that are routed to by other rules to form a directional graph. +* `catch_all` - (Required) the `catch_all` actions will be applied if an Event reaches the end of any set without matching any rules in that set. + +### Set (`set`) supports the following: +* `id` - (Required) The ID of this set of rules. Rules in other sets can route events into this set using the rule's `route_to` property. +* `rule` - (Optional) The service orchestration evaluates Events against these Rules, one at a time, and applies all the actions for first rule it finds where the event matches the rule's conditions. If no rules are provided as part of Terraform configuration, the API returns empty list of rules. + +### Rule (`rule`) supports the following: +* `label` - (Optional) A description of this rule's purpose. +* `condition` - (Optional) Each of these conditions is evaluated to check if an event matches this rule. The rule is considered a match if any of these conditions match. If none are provided, the event will `always` match against the rule. +* `actions` - (Required) Actions that will be taken to change the resulting alert and incident, when an event matches this rule. +* `disabled` - (Optional) Indicates whether the rule is disabled and would therefore not be evaluated. + +### Condition (`condition`) supports the following: +* `expression`- (Required) A [PCL condition](https://developer.pagerduty.com/docs/ZG9jOjM1NTE0MDc0-pcl-overview) string. + +### Actions (`actions`) supports the following: +* `route_to` - (Optional) The ID of a Set from this Service Orchestration whose rules you also want to use with event that match this rule. +* `suppress` - (Optional) Set whether the resulting alert is suppressed. Suppressed alerts will not trigger an incident. +* `suspend` - (Optional) The number of seconds to suspend the resulting alert before triggering. This effectively pauses incident notifications. If a `resolve` event arrives before the alert triggers then PagerDuty won't create an incident for this the resulting alert. +* `priority` - (Optional) The ID of the priority you want to set on resulting incident. Consider using the [`pagerduty_priority`](https://registry.terraform.io/providers/PagerDuty/pagerduty/latest/docs/data-sources/priority) data source. +* `annotate` - (Optional) Add this text as a note on the resulting incident. +* `pagerduty_automation_action` - (Optional) Configure a [Process Automation](https://support.pagerduty.com/docs/event-orchestration#process-automation) associated with the resulting incident. + * `action_id` - (Required) Id of the Process Automation action to be triggered. +* `automation_action` - (Optional) Create a [Webhook](https://support.pagerduty.com/docs/event-orchestration#webhooks) associated with the resulting incident. + * `name` - (Required) Name of this Webhook. + * `url` - (Required) The API endpoint where PagerDuty's servers will send the webhook request. + * `auto_send` - (Optional) When true, PagerDuty's servers will automatically send this webhook request as soon as the resulting incident is created. When false, your incident responder will be able to manually trigger the Webhook via the PagerDuty website and mobile app. + * `header` - (Optional) Specify custom key/value pairs that'll be sent with the webhook request as request headers. + * `key` - (Required) Name to identify the header + * `value` - (Required) Value of this header + * `parameter` - (Optional) Specify custom key/value pairs that'll be included in the webhook request's JSON payload. + * `key` - (Required) Name to identify the parameter + * `value` - (Required) Value of this parameter +* `severity` - (Optional) sets Severity of the resulting alert. Allowed values are: `info`, `error`, `warning`, `critical` +* `event_action` - (Optional) sets whether the resulting alert status is trigger or resolve. Allowed values are: `trigger`, `resolve` +* `variable` - (Optional) Populate variables from event payloads and use those variables in other event actions. + * `name` - (Required) The name of the variable + * `path` - (Required) Path to a field in an event, in dot-notation. This supports both PagerDuty Common Event Format [PD-CEF](https://support.pagerduty.com/docs/pd-cef) and non-CEF fields. Eg: Use `event.summary` for the `summary` CEF field. Use `raw_event.fieldname` to read from the original event `fieldname` data. You can use any valid [PCL path](https://developer.pagerduty.com/docs/ZG9jOjM1NTE0MDc0-pcl-overview#paths). + * `type` - (Required) Only `regex` is supported + * `value` - (Required) The Regex expression to match against. Must use valid [RE2 regular expression](https://github.com/google/re2/wiki/Syntax) syntax. +* `extraction` - (Optional) Replace any CEF field or Custom Details object field using custom variables. + * `target` - (Required) The PagerDuty Common Event Format [PD-CEF](https://support.pagerduty.com/docs/pd-cef) field that will be set with the value from the `template` or based on `regex` and `source` fields. + * `template` - (Optional) A string that will be used to populate the `target` field. You can reference variables or event data within your template using double curly braces. For example: + * Use variables named `ip` and `subnet` with a template like: `{{variables.ip}}/{{variables.subnet}}` + * Combine the event severity & summary with template like: `{{event.severity}}:{{event.summary}}` + * `regex` - (Optional) A [RE2 regular expression](https://github.com/google/re2/wiki/Syntax) that will be matched against field specified via the `source` argument. If the regex contains one or more capture groups, their values will be extracted and appended together. If it contains no capture groups, the whole match is used. This field can be ignored for `template` based extractions. + * `source` - (Optional) The path to the event field where the `regex` will be applied to extract a value. You can use any valid [PCL path](https://developer.pagerduty.com/docs/ZG9jOjM1NTE0MDc0-pcl-overview#paths) like `event.summary` and you can reference previously-defined variables using a path like `variables.hostname`. This field can be ignored for `template` based extractions. + +### Catch All (`catch_all`) supports the following: +* `actions` - (Required) These are the actions that will be taken to change the resulting alert and incident. `catch_all` supports all actions described above for `rule` _except_ `route_to` action. + + +## Attributes Reference + +The following attributes are exported: +* `self` - The URL at which the Service Orchestration is accessible. +* `rule` + * `id` - The ID of the rule within the set. + +## Import + +Service Orchestration can be imported using the `id` of the Service, e.g. + +``` +$ terraform import pagerduty_event_orchestration_service PFEODA7 +``` diff --git a/website/docs/r/event_orchestration_unrouted.html.markdown b/website/docs/r/event_orchestration_unrouted.html.markdown new file mode 100644 index 000000000..0ae8f084d --- /dev/null +++ b/website/docs/r/event_orchestration_unrouted.html.markdown @@ -0,0 +1,102 @@ +--- +layout: "pagerduty" +page_title: "PagerDuty: pagerduty_event_orchestration_unrouted" +sidebar_current: "docs-pagerduty-resource-event-orchestration-unrouted" +description: |- + Creates and manages an Unrouted Orchestration for a Global Event Orchestration in PagerDuty. +--- + +# pagerduty_event_orchestration_unrouted + +An Unrouted Orchestration allows users to create a set of Event Rules that will be evaluated against all events that don't match any rules in the Orchestration's Router. + +The Unrouted Orchestration evaluates events sent to it against each of its rules, beginning with the rules in the "start" set. When a matching rule is found, it can modify and enhance the event and can route the event to another set of rules within this Unrouted Orchestration for further processing. + +## Example of configuring Unrouted Rules for an Orchestration + +In this example of an Unrouted Orchestration, the rule matches only if the condition is matched. +Alerts created for events that do not match the rule will have severity level set to `info` as defined in `catch_all` block. + +```hcl +resource "pagerduty_event_orchestration_unrouted" "unrouted" { + event_orchestration = pagerduty_event_orchestration.my_monitor.id + set { + id = "start" + rule { + label = "Update the summary of un-matched Critical alerts so they're easier to spot" + condition { + expression = "event.severity matches 'critical'" + } + actions { + severity = "critical" + extraction { + target = "event.summary" + template = "[Critical Unrouted] {{event.summary}}" + } + } + } + } + catch_all { + actions { + severity = "info" + } + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `event_orchestration` - (Required) The Event Orchestration to which this Unrouted Orchestration belongs to. +* `set` - (Required) An Unrouted Orchestration must contain at least a "start" set, but can contain any number of additional sets that are routed to by other rules to form a directional graph. +* `catch_all` - (Required) the `catch_all` actions will be applied if an Event reaches the end of any set without matching any rules in that set. + +### Set (`set`) supports the following: +* `id` - (Required) The ID of this set of rules. Rules in other sets can route events into this set using the rule's `route_to` property. +* `rule` - (Optional) The Unrouted Orchestration evaluates Events against these Rules, one at a time, and applies all the actions for first rule it finds where the event matches the rule's conditions. If no rules are provided as part of Terraform configuration, the API returns empty list of rules. + +### Rule (`rule`) supports the following: +* `label` - (Optional) A description of this rule's purpose. +* `condition` - (Optional) Each of these conditions is evaluated to check if an event matches this rule. The rule is considered a match if any of these conditions match. If none are provided, the event will `always` match against the rule. +* `actions` - (Required) Actions that will be taken to change the resulting alert and incident, when an event matches this rule. +* `disabled` - (Optional) Indicates whether the rule is disabled and would therefore not be evaluated. + +### Condition (`condition`) supports the following: +* `expression`- (Required) A [PCL condition](https://developer.pagerduty.com/docs/ZG9jOjM1NTE0MDc0-pcl-overview) string. + +### Actions (`actions`) supports the following: +* `route_to` - (Optional) The ID of a Set from this Unrouted Orchestration whose rules you also want to use with event that match this rule. +* `severity` - (Optional) sets Severity of the resulting alert. Allowed values are: `info`, `error`, `warning`, `critical` +* `event_action` - (Optional) sets whether the resulting alert status is trigger or resolve. Allowed values are: `trigger`, `resolve` +* `variable` - (Optional) Populate variables from event payloads and use those variables in other event actions. + * `name` - (Required) The name of the variable + * `path` - (Required) Path to a field in an event, in dot-notation. This supports both [PD-CEF](https://support.pagerduty.com/docs/pd-cef) and non-CEF fields. Eg: Use `event.summary` for the `summary` CEF field. Use `raw_event.fieldname` to read from the original event `fieldname` data. + * `type` - (Required) Only `regex` is supported + * `value` - (Required) The Regex expression to match against. Must use valid [RE2 regular expression](https://github.com/google/re2/wiki/Syntax) syntax. +* `extraction` - (Optional) Replace any CEF field or Custom Details object field using custom variables. + * `target` - (Required) The PagerDuty Common Event Format [PD-CEF](https://support.pagerduty.com/docs/pd-cef) field that will be set with the value from the `template` or based on `regex` and `source` fields. + * `template` - (Optional) A string that will be used to populate the `target` field. You can reference variables or event data within your template using double curly braces. For example: + * Use variables named `ip` and `subnet` with a template like: `{{variables.ip}}/{{variables.subnet}}` + * Combine the event severity & summary with template like: `{{event.severity}}:{{event.summary}}` + * `target` - (Required) The PagerDuty Common Event Format [PD-CEF](https://support.pagerduty.com/docs/pd-cef) field that will be set with the value from the `template` or based on `regex` and `source` fields. + * `regex` - (Optional) A [RE2 regular expression](https://github.com/google/re2/wiki/Syntax) that will be matched against field specified via the `source` argument. If the regex contains one or more capture groups, their values will be extracted and appended together. If it contains no capture groups, the whole match is used. This field can be ignored for `template` based extractions. + * `source` - (Optional) The path to the event field where the `regex` will be applied to extract a value. You can use any valid [PCL path](https://developer.pagerduty.com/docs/ZG9jOjM1NTE0MDc0-pcl-overview#paths) like `event.summary` and you can reference previously-defined variables using a path like `variables.hostname`. This field can be ignored for `template` based extractions. + +### Catch All (`catch_all`) supports the following: +* `actions` - (Required) These are the actions that will be taken to change the resulting alert and incident. `catch_all` supports all actions described above for `rule` _except_ `route_to` action. + +## Attributes Reference + +The following attributes are exported: +* `self` - The URL at which the Unrouted Event Orchestration is accessible. +* `rule` + * `id` - The ID of the rule within the set. + +## Import + +Unrouted Orchestration can be imported using the `id` of the Event Orchestration, e.g. + +``` +$ terraform import pagerduty_event_orchestration_unrouted 1b49abe7-26db-4439-a715-c6d883acfb3e +``` From 32781812f70b8609c728247deef30279fd30421b Mon Sep 17 00:00:00 2001 From: Scott McAllister Date: Wed, 1 Jun 2022 13:37:02 -0700 Subject: [PATCH 24/63] Update CHANGELOG for v2.5.0 Release --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5dfe244f..c84e5e959 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,13 @@ FEATURES: * `resource/pagerduty_event_orchestration_router` * `resource/pagerduty_event_orchestration_unrouted` * `resource/pagerduty_event_orchestration_service` + * `data_source/pagerduty_event_orchestration` + +IMPROVEMENTS: +* `data_source/pagerduty_user`: Add support for pagination. Gets all users. ([#511](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/511)) + +BUG FIXES: +* `resource/pagerduty_service_integration`: Fix permadiff in email_parser with type regex & minor docs update ([#479](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/479)) ## 2.4.2 (May 20, 2022) From 5c7d632d507b54e0fe7ac6619d50156a882e8bda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Antonio=20Reyes?= Date: Wed, 1 Jun 2022 19:24:00 -0400 Subject: [PATCH 25/63] add star wildcard config for setting `Any Priority` to slack_connection resource --- .../resource_pagerduty_slack_connection.go | 30 +++++++++++++++++-- website/docs/r/slack_connection.html.markdown | 2 ++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/pagerduty/resource_pagerduty_slack_connection.go b/pagerduty/resource_pagerduty_slack_connection.go index 58165934c..4557dcfb8 100644 --- a/pagerduty/resource_pagerduty_slack_connection.go +++ b/pagerduty/resource_pagerduty_slack_connection.go @@ -12,6 +12,7 @@ import ( ) const AppBaseUrl = "https://app.pagerduty.com" +const StarWildcardConfig = "*" func resourcePagerDutySlackConnection() *schema.Resource { return &schema.Resource{ @@ -215,7 +216,7 @@ func expandConnectionConfig(v interface{}) pagerduty.ConnectionConfig { config = pagerduty.ConnectionConfig{ Events: expandConfigList(c["events"].([]interface{})), - Priorities: expandConfigList(c["priorities"].([]interface{})), + Priorities: expandStarWildcardConfig(expandConfigList(c["priorities"].([]interface{}))), Urgency: nil, } if val, ok := c["urgency"]; ok { @@ -228,18 +229,30 @@ func expandConnectionConfig(v interface{}) pagerduty.ConnectionConfig { } func expandConfigList(v interface{}) []string { - var items []string + items := []string{} for _, i := range v.([]interface{}) { items = append(items, i.(string)) } return items } +//Expands the use of star wildcard ("*") configuration for an attribute to its +//matching expected value by PagerDuty's API, which is nil. This is necessary +//when the API accepts and interprets nil and empty configurations as valid +//settings. The state produced by this kind of config can be reverted to the API +//expected values with sibbling function `flattenStarWildcardConfig`. +func expandStarWildcardConfig(c []string) []string { + if isUsingStarWildcardConfig := len(c) == 1 && c[0] == StarWildcardConfig; isUsingStarWildcardConfig { + c = nil + } + return c +} + func flattenConnectionConfig(config pagerduty.ConnectionConfig) []map[string]interface{} { var configs []map[string]interface{} configMap := map[string]interface{}{ "events": flattenConfigList(config.Events), - "priorities": flattenConfigList(config.Priorities), + "priorities": flattenConfigList(flattenStarWildcardConfig(config.Priorities)), } if config.Urgency != nil { configMap["urgency"] = *config.Urgency @@ -258,6 +271,17 @@ func flattenConfigList(list []string) interface{} { return items } +// Flattens a `nil` configuration to its corresponding star wildcard ("*") +// configuration value for an attribute which is meant to be accepting this kind +// of configuration, with the only purpose to match the config stored in the +// Terraform's state. +func flattenStarWildcardConfig(c []string) []string { + if hasStarWildcardConfigSet := c[:] == nil; hasStarWildcardConfigSet { + c = append(c, StarWildcardConfig) + } + return c +} + func resourcePagerDutySlackConnectionImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { client, err := meta.(*Config).SlackClient() if err != nil { diff --git a/website/docs/r/slack_connection.html.markdown b/website/docs/r/slack_connection.html.markdown index 94fa09194..7c63d56e5 100644 --- a/website/docs/r/slack_connection.html.markdown +++ b/website/docs/r/slack_connection.html.markdown @@ -80,6 +80,8 @@ The following arguments are supported: - `incident.status_update_published` - `incident.reopened` * `priorities` - (Optional) Allows you to filter events by priority. Needs to be an array of PagerDuty priority IDs. Available through [pagerduty_priority](https://registry.terraform.io/providers/PagerDuty/pagerduty/latest/docs/data-sources/priority) data source. + - When omitted or set to an empty array (`[]`) in the configuration for a Slack Connection, its default behaviour is to set `priorities` to `No Priority` value. + - When set to `["*"]` its corresponding value for `priorities` in Slack Connection's configuration will be `Any Priority`. * `urgency` - (Optional) Allows you to filter events by urgency. Either `high` or `low`. ## Attributes Reference From 2f5e02f42fb8f2b1271c8f87888db7234b3a5b5a Mon Sep 17 00:00:00 2001 From: Rucheli Berry <7971632+cmrberry@users.noreply.github.com> Date: Tue, 7 Jun 2022 11:27:56 -0700 Subject: [PATCH 26/63] remove 429 check on user, vendor, schedule --- pagerduty/data_source_pagerduty_schedule.go | 12 ++++-------- pagerduty/data_source_pagerduty_user.go | 12 ++++-------- pagerduty/data_source_pagerduty_vendor.go | 12 ++++-------- 3 files changed, 12 insertions(+), 24 deletions(-) diff --git a/pagerduty/data_source_pagerduty_schedule.go b/pagerduty/data_source_pagerduty_schedule.go index ef6dafedc..2d6615b7f 100644 --- a/pagerduty/data_source_pagerduty_schedule.go +++ b/pagerduty/data_source_pagerduty_schedule.go @@ -40,14 +40,10 @@ func dataSourcePagerDutyScheduleRead(d *schema.ResourceData, meta interface{}) e return resource.Retry(5*time.Minute, func() *resource.RetryError { resp, _, err := client.Schedules.List(o) if err != nil { - if isErrCode(err, 429) { - // Delaying retry by 30s as recommended by PagerDuty - // https://developer.pagerduty.com/docs/rest-api-v2/rate-limiting/#what-are-possible-workarounds-to-the-events-api-rate-limit - time.Sleep(30 * time.Second) - return resource.RetryableError(err) - } - - return resource.NonRetryableError(err) + // Delaying retry by 30s as recommended by PagerDuty + // https://developer.pagerduty.com/docs/rest-api-v2/rate-limiting/#what-are-possible-workarounds-to-the-events-api-rate-limit + time.Sleep(30 * time.Second) + return resource.RetryableError(err) } var found *pagerduty.Schedule diff --git a/pagerduty/data_source_pagerduty_user.go b/pagerduty/data_source_pagerduty_user.go index cb94a7661..d32b8fd94 100644 --- a/pagerduty/data_source_pagerduty_user.go +++ b/pagerduty/data_source_pagerduty_user.go @@ -44,14 +44,10 @@ func dataSourcePagerDutyUserRead(d *schema.ResourceData, meta interface{}) error return resource.Retry(5*time.Minute, func() *resource.RetryError { resp, err := client.Users.ListAll(o) if err != nil { - if isErrCode(err, 429) { - // Delaying retry by 30s as recommended by PagerDuty - // https://developer.pagerduty.com/docs/rest-api-v2/rate-limiting/#what-are-possible-workarounds-to-the-events-api-rate-limit - time.Sleep(30 * time.Second) - return resource.RetryableError(err) - } - - return resource.NonRetryableError(err) + // Delaying retry by 30s as recommended by PagerDuty + // https://developer.pagerduty.com/docs/rest-api-v2/rate-limiting/#what-are-possible-workarounds-to-the-events-api-rate-limit + time.Sleep(30 * time.Second) + return resource.RetryableError(err) } var found *pagerduty.FullUser diff --git a/pagerduty/data_source_pagerduty_vendor.go b/pagerduty/data_source_pagerduty_vendor.go index 8b6dae810..1d3d6804c 100644 --- a/pagerduty/data_source_pagerduty_vendor.go +++ b/pagerduty/data_source_pagerduty_vendor.go @@ -45,14 +45,10 @@ func dataSourcePagerDutyVendorRead(d *schema.ResourceData, meta interface{}) err return resource.Retry(5*time.Minute, func() *resource.RetryError { resp, _, err := client.Vendors.List(o) if err != nil { - if isErrCode(err, 429) { - // Delaying retry by 30s as recommended by PagerDuty - // https://developer.pagerduty.com/docs/rest-api-v2/rate-limiting/#what-are-possible-workarounds-to-the-events-api-rate-limit - time.Sleep(30 * time.Second) - return resource.RetryableError(err) - } - - return resource.NonRetryableError(err) + // Delaying retry by 30s as recommended by PagerDuty + // https://developer.pagerduty.com/docs/rest-api-v2/rate-limiting/#what-are-possible-workarounds-to-the-events-api-rate-limit + time.Sleep(30 * time.Second) + return resource.RetryableError(err) } var found *pagerduty.Vendor From bb3008fd1721e295273c76ef966e01a92d5b5283 Mon Sep 17 00:00:00 2001 From: DevOps Rob Date: Wed, 8 Jun 2022 11:05:32 +0100 Subject: [PATCH 27/63] refactor: customer_headers => custom_header --- pagerduty/resource_pagerduty_webhook_subscription.go | 9 ++++----- .../go-pagerduty/pagerduty/webhook_subscription.go | 2 +- website/docs/r/webhook_subscription.html.markdown | 6 +++--- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/pagerduty/resource_pagerduty_webhook_subscription.go b/pagerduty/resource_pagerduty_webhook_subscription.go index e66792ada..6b9d73e72 100644 --- a/pagerduty/resource_pagerduty_webhook_subscription.go +++ b/pagerduty/resource_pagerduty_webhook_subscription.go @@ -41,7 +41,7 @@ func resourcePagerDutyWebhookSubscription() *schema.Resource { Type: schema.TypeString, Optional: true, }, - "custom_headers": { + "custom_header": { Type: schema.TypeList, Optional: true, Elem: &schema.Resource{ @@ -223,19 +223,18 @@ func expandDeliveryMethod(v interface{}) pagerduty.DeliveryMethod { // convert interface to []*pagerduty.CustomHeaders var headers []*pagerduty.CustomHeaders - for _, raw := range dmMap["custom_headers"].([]interface{}) { + for _, raw := range dmMap["custom_header"].([]interface{}) { headers = append(headers, &pagerduty.CustomHeaders{ Name: raw.(map[string]interface{})["name"].(string), Value: raw.(map[string]interface{})["value"].(string), }) } - method = pagerduty.DeliveryMethod{ TemporarilyDisabled: dmMap["temporarily_disabled"].(bool), Type: dmMap["type"].(string), URL: dmMap["url"].(string), - CustomHeaders: headers, + CustomHeaders: headers, } return method } @@ -257,7 +256,7 @@ func flattenDeliveryMethod(method pagerduty.DeliveryMethod) []map[string]interfa "temporarily_disabled": method.TemporarilyDisabled, "type": method.Type, "url": method.URL, - "custom_headers": method.CustomHeaders, + "custom_header": method.CustomHeaders, } methods = append(methods, methodMap) return methods diff --git a/vendor/github.com/heimweh/go-pagerduty/pagerduty/webhook_subscription.go b/vendor/github.com/heimweh/go-pagerduty/pagerduty/webhook_subscription.go index 19f06ddbd..b799dbbaf 100644 --- a/vendor/github.com/heimweh/go-pagerduty/pagerduty/webhook_subscription.go +++ b/vendor/github.com/heimweh/go-pagerduty/pagerduty/webhook_subscription.go @@ -21,7 +21,7 @@ type DeliveryMethod struct { TemporarilyDisabled bool `json:"temporarily_disabled,omitempty"` Type string `json:"type,omitempty"` URL string `json:"url,omitempty"` - CustomHeaders []*CustomHeaders `json:"custom_headers"` + CustomHeaders []*CustomHeaders `json:"custom_header"` } type CustomHeaders struct { diff --git a/website/docs/r/webhook_subscription.html.markdown b/website/docs/r/webhook_subscription.html.markdown index 42dbaccf0..a1ed7ec51 100644 --- a/website/docs/r/webhook_subscription.html.markdown +++ b/website/docs/r/webhook_subscription.html.markdown @@ -21,11 +21,11 @@ resource "pagerduty_webhook_subscription" "foo" { delivery_method { type = "http_delivery_method" url = "https://example.com/receive_a_pagerduty_webhook" - custom_headers { + custom_header { name = "X-Foo" value = "foo" } - custom_headers { + custom_header { name = "X-Bar" value = "bar" } @@ -85,7 +85,7 @@ The following arguments are supported: * `temporarily_disabled` - (Required) Whether this webhook subscription is temporarily disabled. Becomes true if the delivery method URL is repeatedly rejected by the server. * `type` - (Required) Indicates the type of the delivery method. Allowed and default value: `http_delivery_method`. * `url` - (Required) The destination URL for webhook delivery. -* `custom_headers` - (Optional) The custom_headers of a webhook subscription define any optional headers that will be passed along with the payload to the destination URL. +* `custom_header` - (Optional) The custom_header of a webhook subscription define any optional headers that will be passed along with the payload to the destination URL. ### Webhook filter (`filter`) supports the following: From 3037c29943d069d4b19102907a1a9a770a1fe320 Mon Sep 17 00:00:00 2001 From: Marcos Wright-Kuhns Date: Fri, 6 May 2022 09:59:15 -0700 Subject: [PATCH 28/63] Switch to always use @foo.test TLD in our tests & documentation ...because [he test TLD[1] will never be publicly addressable & therefore we'll be certain to never send real email to a random domain when the acceptance tests run. [1]:https://en.wikipedia.org/wiki/.test --- CHANGELOG.md | 21 ++++++----- ...source_pagerduty_escalation_policy_test.go | 2 +- .../data_source_pagerduty_schedule_test.go | 2 +- ...urce_pagerduty_service_integration_test.go | 2 +- .../data_source_pagerduty_service_test.go | 2 +- pagerduty/data_source_pagerduty_user_test.go | 2 +- ...import_pagerduty_escalation_policy_test.go | 2 +- pagerduty/import_pagerduty_schedule_test.go | 2 +- ...mport_pagerduty_service_dependency_test.go | 2 +- ...mport_pagerduty_service_event_rule_test.go | 2 +- ...port_pagerduty_service_integration_test.go | 2 +- pagerduty/import_pagerduty_service_test.go | 4 +-- .../import_pagerduty_slack_connection_test.go | 2 +- ...port_pagerduty_user_contact_method_test.go | 2 +- ...t_pagerduty_user_notification_rule_test.go | 2 +- pagerduty/import_pagerduty_user_test.go | 2 +- ...ort_pagerduty_webhook_subscription_test.go | 2 +- pagerduty/resource_pagerduty_addon_test.go | 4 +-- ...erduty_business_service_subscriber_test.go | 4 +-- ...source_pagerduty_escalation_policy_test.go | 4 +-- ...rce_pagerduty_extension_servicenow_test.go | 2 +- .../resource_pagerduty_extension_test.go | 2 +- ...ource_pagerduty_maintenance_window_test.go | 4 +-- .../resource_pagerduty_response_play_test.go | 18 +++++----- pagerduty/resource_pagerduty_schedule_test.go | 14 ++++---- ...ource_pagerduty_service_dependency_test.go | 4 +-- ...ource_pagerduty_service_event_rule_test.go | 4 +-- ...urce_pagerduty_service_integration_test.go | 14 ++++---- pagerduty/resource_pagerduty_service_test.go | 16 ++++----- ...esource_pagerduty_slack_connection_test.go | 36 +++++++++---------- .../resource_pagerduty_tag_assignment_test.go | 10 +++--- ...resource_pagerduty_team_membership_test.go | 4 +-- ...urce_pagerduty_user_contact_method_test.go | 12 +++---- ...e_pagerduty_user_notification_rule_test.go | 10 +++--- pagerduty/resource_pagerduty_user_test.go | 6 ++-- ...rce_pagerduty_webhook_subscription_test.go | 16 ++++----- .../mongo/options/datakeyoptions.go | 2 +- .../docs/r/service_integration.html.markdown | 4 +-- 38 files changed, 125 insertions(+), 120 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36b460c67..2b0725948 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 2.4.2 (Unreleased) + +IMPROVEMENTS: +* Use "@foo.test" email addresses in tests + ## 2.4.1 (April 22, 2022) IMPROVEMENTS: * `resource/pagerduty_user_notification`: Create user/notification rule: allow using existing ones ([#482](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/482)) @@ -19,7 +24,7 @@ IMPROVEMENTS: * `resource/maintenance_window`: Ignore error code 405 on delete ([#466](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/466)) -## 2.3.0 (February 10, 2022) +## 2.3.0 (February 10, 2022) IMPROVEMENTS: * Updated TF SDK to v2.10.1 and added `depends_on` to eventrule tests ([#446](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/446)) * `resource/pagerduty_schedule`: Added validation to `duration_seconds` ([#433](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/433)) @@ -198,11 +203,11 @@ IMPROVEMENTS: * `data_source_pagerduty_ruleset`: Added `routing_keys` field to the `ruleset` object ([#305](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/305)) ## 1.9.3 (February 11, 2021) -BUG FIXES: +BUG FIXES: * `resource/pagerduty_service_event_rule`,`resource/pagerduty_ruleset_rule`: Fixed Bug with Event Rule Suppress Action ([#302](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/302)) ## 1.9.2 (February 10, 2021) -BUG FIXES: +BUG FIXES: * `resource/pagerduty_service_event_rule`,`resource/pagerduty_ruleset_rule`: Fixed Bug with Event Rule Positioning ([#301](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/301)) ## 1.9.1 (February 8, 2021) @@ -268,7 +273,7 @@ FEATURES * Implement retry logic on all reads ([#208](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/208)) * Bump golang to v1.14.1 ([#193](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/193)) -BUG FIXES: +BUG FIXES: * data_source_ruleset: add example of Default Global Ruleset in Docs ([#239](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/239)) ## 1.7.2 (June 01, 2020) @@ -276,7 +281,7 @@ FEATURES * **New Data Source:** `pagerduty_ruleset` ([#237](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/237)) * Update docs/tests to TF 0.12 syntax ([#223](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/223)) -BUG FIXES: +BUG FIXES: * testing: update sweepers ([#220](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/220)) * data_source_priority: adding doc to sidebar nav ([#221](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/221)) @@ -363,7 +368,7 @@ BUG FIXES: IMPROVEMENTS: * Switch to standalone Terraform Plugin SDK: ([#158](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/158)) -* Add html_url read-only attribute to resource_pagerduty_service, resource_pagerduty_extension, resource_pagerduty_team ([#162](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/162)) +* Add html_url read-only attribute to resource_pagerduty_service, resource_pagerduty_extension, resource_pagerduty_team ([#162](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/162)) * resource/pagerduty_event_rule: Documentation for `depends_on` field ([#152](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/152)). @@ -397,9 +402,9 @@ BUG FIXES: BUG FIXES: -* data-source/pagerduty_team: Fix team search issue [[#110](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/110)] +* data-source/pagerduty_team: Fix team search issue [[#110](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/110)] * resource/pagerduty_maintenance_window: Suppress spurious diff in `start_time` & `end_time` ([#116](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/116)) -* resource/pagerduty_service: Set invitation_sent [[#127](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/127)] +* resource/pagerduty_service: Set invitation_sent [[#127](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/127)] * resource/pagerduty_escalation_policy: Correctly set teams ([#129](https://github.com/PagerDuty/terraform-provider-pagerduty/issues/129)) IMPROVEMENTS: diff --git a/pagerduty/data_source_pagerduty_escalation_policy_test.go b/pagerduty/data_source_pagerduty_escalation_policy_test.go index b509bb214..442791df6 100644 --- a/pagerduty/data_source_pagerduty_escalation_policy_test.go +++ b/pagerduty/data_source_pagerduty_escalation_policy_test.go @@ -11,7 +11,7 @@ import ( func TestAccDataSourcePagerDutyEscalationPolicy_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) resource.Test(t, resource.TestCase{ diff --git a/pagerduty/data_source_pagerduty_schedule_test.go b/pagerduty/data_source_pagerduty_schedule_test.go index 06f17dc3e..87be61eef 100644 --- a/pagerduty/data_source_pagerduty_schedule_test.go +++ b/pagerduty/data_source_pagerduty_schedule_test.go @@ -12,7 +12,7 @@ import ( func TestAccDataSourcePagerDutySchedule_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) schedule := fmt.Sprintf("tf-%s", acctest.RandString(5)) location := "Europe/Berlin" start := timeNowInLoc(location).Add(24 * time.Hour).Round(1 * time.Hour).Format(time.RFC3339) diff --git a/pagerduty/data_source_pagerduty_service_integration_test.go b/pagerduty/data_source_pagerduty_service_integration_test.go index 708483d9a..546f11062 100644 --- a/pagerduty/data_source_pagerduty_service_integration_test.go +++ b/pagerduty/data_source_pagerduty_service_integration_test.go @@ -11,7 +11,7 @@ import ( func TestAccDataSourcePagerDutyIntegration_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) serviceIntegration := "Datadog" diff --git a/pagerduty/data_source_pagerduty_service_test.go b/pagerduty/data_source_pagerduty_service_test.go index de4f60ddb..549b7dd65 100644 --- a/pagerduty/data_source_pagerduty_service_test.go +++ b/pagerduty/data_source_pagerduty_service_test.go @@ -11,7 +11,7 @@ import ( func TestAccDataSourcePagerDutyService_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) diff --git a/pagerduty/data_source_pagerduty_user_test.go b/pagerduty/data_source_pagerduty_user_test.go index 8724ffbcf..5f900a2cd 100644 --- a/pagerduty/data_source_pagerduty_user_test.go +++ b/pagerduty/data_source_pagerduty_user_test.go @@ -11,7 +11,7 @@ import ( func TestAccDataSourcePagerDutyUser_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, diff --git a/pagerduty/import_pagerduty_escalation_policy_test.go b/pagerduty/import_pagerduty_escalation_policy_test.go index 872e8ccd4..d6e8820ed 100644 --- a/pagerduty/import_pagerduty_escalation_policy_test.go +++ b/pagerduty/import_pagerduty_escalation_policy_test.go @@ -10,7 +10,7 @@ import ( func TestAccPagerDutyEscalationPolicy_import(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) resource.Test(t, resource.TestCase{ diff --git a/pagerduty/import_pagerduty_schedule_test.go b/pagerduty/import_pagerduty_schedule_test.go index 840be3d26..40338bd9d 100644 --- a/pagerduty/import_pagerduty_schedule_test.go +++ b/pagerduty/import_pagerduty_schedule_test.go @@ -11,7 +11,7 @@ import ( func TestAccPagerDutySchedule_import(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) schedule := fmt.Sprintf("tf-%s", acctest.RandString(5)) location := "Europe/Berlin" start := timeNowInLoc(location).Add(24 * time.Hour).Round(1 * time.Hour).Format(time.RFC3339) diff --git a/pagerduty/import_pagerduty_service_dependency_test.go b/pagerduty/import_pagerduty_service_dependency_test.go index b343d3d6b..5f502090e 100644 --- a/pagerduty/import_pagerduty_service_dependency_test.go +++ b/pagerduty/import_pagerduty_service_dependency_test.go @@ -13,7 +13,7 @@ func TestAccPagerDutyServiceDependency_import(t *testing.T) { service := fmt.Sprintf("tf-%s", acctest.RandString(5)) businessService := fmt.Sprintf("tf-%s", acctest.RandString(5)) username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) resource.Test(t, resource.TestCase{ diff --git a/pagerduty/import_pagerduty_service_event_rule_test.go b/pagerduty/import_pagerduty_service_event_rule_test.go index 904f11e89..fda2e4a95 100644 --- a/pagerduty/import_pagerduty_service_event_rule_test.go +++ b/pagerduty/import_pagerduty_service_event_rule_test.go @@ -11,7 +11,7 @@ import ( func TestAccPagerDutyServiceEventRule_import(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) rule := fmt.Sprintf("tf-%s", acctest.RandString(5)) diff --git a/pagerduty/import_pagerduty_service_integration_test.go b/pagerduty/import_pagerduty_service_integration_test.go index 7376af4f8..e42d4d9e1 100644 --- a/pagerduty/import_pagerduty_service_integration_test.go +++ b/pagerduty/import_pagerduty_service_integration_test.go @@ -11,7 +11,7 @@ import ( func TestAccPagerDutyServiceIntegration_import(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) serviceIntegration := fmt.Sprintf("tf-%s", acctest.RandString(5)) diff --git a/pagerduty/import_pagerduty_service_test.go b/pagerduty/import_pagerduty_service_test.go index 29995809f..458acca0f 100644 --- a/pagerduty/import_pagerduty_service_test.go +++ b/pagerduty/import_pagerduty_service_test.go @@ -10,7 +10,7 @@ import ( func TestAccPagerDutyService_import(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) @@ -34,7 +34,7 @@ func TestAccPagerDutyService_import(t *testing.T) { func TestAccPagerDutyServiceWithIncidentUrgency_import(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) diff --git a/pagerduty/import_pagerduty_slack_connection_test.go b/pagerduty/import_pagerduty_slack_connection_test.go index 1f798566c..2b363081d 100644 --- a/pagerduty/import_pagerduty_slack_connection_test.go +++ b/pagerduty/import_pagerduty_slack_connection_test.go @@ -11,7 +11,7 @@ import ( func TestAccPagerDutySlackConnection_import(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) diff --git a/pagerduty/import_pagerduty_user_contact_method_test.go b/pagerduty/import_pagerduty_user_contact_method_test.go index d3e0a44c2..fa33a19a7 100644 --- a/pagerduty/import_pagerduty_user_contact_method_test.go +++ b/pagerduty/import_pagerduty_user_contact_method_test.go @@ -11,7 +11,7 @@ import ( func TestAccPagerDutyUserContactMethod_import(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, diff --git a/pagerduty/import_pagerduty_user_notification_rule_test.go b/pagerduty/import_pagerduty_user_notification_rule_test.go index 66456d0a1..74b7206c9 100644 --- a/pagerduty/import_pagerduty_user_notification_rule_test.go +++ b/pagerduty/import_pagerduty_user_notification_rule_test.go @@ -11,7 +11,7 @@ import ( func TestAccPagerDutyUserNotificationRule_import(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) contactMethodType := "phone_contact_method" resource.Test(t, resource.TestCase{ diff --git a/pagerduty/import_pagerduty_user_test.go b/pagerduty/import_pagerduty_user_test.go index aeeea8bab..527ebf884 100644 --- a/pagerduty/import_pagerduty_user_test.go +++ b/pagerduty/import_pagerduty_user_test.go @@ -10,7 +10,7 @@ import ( func TestAccPagerDutyUser_import(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, diff --git a/pagerduty/import_pagerduty_webhook_subscription_test.go b/pagerduty/import_pagerduty_webhook_subscription_test.go index f93867a5a..7bf88092a 100644 --- a/pagerduty/import_pagerduty_webhook_subscription_test.go +++ b/pagerduty/import_pagerduty_webhook_subscription_test.go @@ -11,7 +11,7 @@ import ( func TestAccPagerDutyWebhookSubscription_import(t *testing.T) { description := fmt.Sprintf("tf-test-%s", acctest.RandString(5)) username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) diff --git a/pagerduty/resource_pagerduty_addon_test.go b/pagerduty/resource_pagerduty_addon_test.go index e8c76a49a..eb777f6f3 100644 --- a/pagerduty/resource_pagerduty_addon_test.go +++ b/pagerduty/resource_pagerduty_addon_test.go @@ -63,7 +63,7 @@ func TestAccPagerDutyAddon_Basic(t *testing.T) { resource.TestCheckResourceAttr( "pagerduty_addon.foo", "name", addon), resource.TestCheckResourceAttr( - "pagerduty_addon.foo", "src", "https://intranet.foo.com/status"), + "pagerduty_addon.foo", "src", "https://intranet.foo.test/status"), ), }, { @@ -125,7 +125,7 @@ func testAccCheckPagerDutyAddonConfig(addon string) string { return fmt.Sprintf(` resource "pagerduty_addon" "foo" { name = "%s" - src = "https://intranet.foo.com/status" + src = "https://intranet.foo.test/status" } `, addon) } diff --git a/pagerduty/resource_pagerduty_business_service_subscriber_test.go b/pagerduty/resource_pagerduty_business_service_subscriber_test.go index 5fa864943..edeaaa0bb 100644 --- a/pagerduty/resource_pagerduty_business_service_subscriber_test.go +++ b/pagerduty/resource_pagerduty_business_service_subscriber_test.go @@ -13,7 +13,7 @@ import ( func TestAccPagerDutyBusinessServiceSubscriber_User(t *testing.T) { businessServiceName := fmt.Sprintf("tf-%s", acctest.RandString(5)) username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -57,7 +57,7 @@ func TestAccPagerDutyBusinessServiceSubscriber_TeamUser(t *testing.T) { businessServiceName := fmt.Sprintf("tf-%s", acctest.RandString(5)) team := fmt.Sprintf("tf-%s", acctest.RandString(5)) username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, diff --git a/pagerduty/resource_pagerduty_escalation_policy_test.go b/pagerduty/resource_pagerduty_escalation_policy_test.go index a1de0b0c2..431959568 100644 --- a/pagerduty/resource_pagerduty_escalation_policy_test.go +++ b/pagerduty/resource_pagerduty_escalation_policy_test.go @@ -52,7 +52,7 @@ func testSweepEscalationPolicy(region string) error { func TestAccPagerDutyEscalationPolicy_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) escalationPolicyUpdated := fmt.Sprintf("tf-%s", acctest.RandString(5)) @@ -102,7 +102,7 @@ func TestAccPagerDutyEscalationPolicy_Basic(t *testing.T) { func TestAccPagerDutyEscalationPolicyWithTeams_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) team := fmt.Sprintf("tf-%s", acctest.RandString(5)) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) escalationPolicyUpdated := fmt.Sprintf("tf-%s", acctest.RandString(5)) diff --git a/pagerduty/resource_pagerduty_extension_servicenow_test.go b/pagerduty/resource_pagerduty_extension_servicenow_test.go index 54d0af74e..792dc4755 100644 --- a/pagerduty/resource_pagerduty_extension_servicenow_test.go +++ b/pagerduty/resource_pagerduty_extension_servicenow_test.go @@ -159,7 +159,7 @@ func testAccCheckPagerDutyExtensionServiceNowConfig(name string, extension_name return fmt.Sprintf(` resource "pagerduty_user" "foo" { name = "%[1]v" - email = "%[1]v@foo.com" + email = "%[1]v@foo.test" color = "green" role = "user" job_title = "foo" diff --git a/pagerduty/resource_pagerduty_extension_test.go b/pagerduty/resource_pagerduty_extension_test.go index cb6442a5a..1b3e822d3 100644 --- a/pagerduty/resource_pagerduty_extension_test.go +++ b/pagerduty/resource_pagerduty_extension_test.go @@ -137,7 +137,7 @@ func testAccCheckPagerDutyExtensionConfig(name string, extension_name string, ur return fmt.Sprintf(` resource "pagerduty_user" "foo" { name = "%[1]v" - email = "%[1]v@foo.com" + email = "%[1]v@foo.test" color = "green" role = "user" job_title = "foo" diff --git a/pagerduty/resource_pagerduty_maintenance_window_test.go b/pagerduty/resource_pagerduty_maintenance_window_test.go index 79e3d23b0..b11c94608 100644 --- a/pagerduty/resource_pagerduty_maintenance_window_test.go +++ b/pagerduty/resource_pagerduty_maintenance_window_test.go @@ -115,7 +115,7 @@ func testAccCheckPagerDutyMaintenanceWindowConfig(desc, start, end string) strin return fmt.Sprintf(` resource "pagerduty_user" "foo" { name = "%[1]v" - email = "%[1]v@foo.com" + email = "%[1]v@foo.test" color = "green" role = "user" job_title = "foo" @@ -163,7 +163,7 @@ func testAccCheckPagerDutyMaintenanceWindowConfigUpdated(desc, start, end string return fmt.Sprintf(` resource "pagerduty_user" "foo" { name = "%[1]v" - email = "%[1]v@foo.com" + email = "%[1]v@foo.test" color = "green" role = "user" job_title = "foo" diff --git a/pagerduty/resource_pagerduty_response_play_test.go b/pagerduty/resource_pagerduty_response_play_test.go index 003a32c77..bf450fb6f 100644 --- a/pagerduty/resource_pagerduty_response_play_test.go +++ b/pagerduty/resource_pagerduty_response_play_test.go @@ -24,7 +24,7 @@ func TestAccPagerDutyResponsePlay_Basic(t *testing.T) { resource.TestCheckResourceAttr( "pagerduty_response_play.foo", "name", name), resource.TestCheckResourceAttr( - "pagerduty_response_play.foo", "from", name+"@foo.com"), + "pagerduty_response_play.foo", "from", name+"@foo.test"), resource.TestCheckResourceAttr( "pagerduty_response_play.foo", "responder.#", "2"), ), @@ -36,7 +36,7 @@ func TestAccPagerDutyResponsePlay_Basic(t *testing.T) { resource.TestCheckResourceAttr( "pagerduty_response_play.foo", "name", name), resource.TestCheckResourceAttr( - "pagerduty_response_play.foo", "from", name+"@foo.com"), + "pagerduty_response_play.foo", "from", name+"@foo.test"), resource.TestCheckResourceAttr( "pagerduty_response_play.foo", "responder.#", "1"), resource.TestCheckResourceAttr( @@ -96,7 +96,7 @@ func testAccCheckPagerDutyResponsePlayConfig(name string) string { return fmt.Sprintf(` resource "pagerduty_user" "foo" { name = "%[1]v" - email = "%[1]v@foo.com" + email = "%[1]v@foo.test" color = "green" role = "user" job_title = "foo" @@ -133,7 +133,7 @@ resource "pagerduty_response_play" "foo" { type = "user_reference" id = pagerduty_user.foo.id } -runnability = "services" +runnability = "services" } `, name) } @@ -142,28 +142,28 @@ func testAccCheckPagerDutyResponsePlayConfigUpdated(name string) string { return fmt.Sprintf(` resource "pagerduty_user" "foo" { name = "%[1]v" - email = "%[1]v@foo.com" + email = "%[1]v@foo.test" color = "green" role = "user" job_title = "foo" description = "foo" } - + resource "pagerduty_escalation_policy" "foo" { name = "%[1]v" description = "bar" num_loops = 2 - + rule { escalation_delay_in_minutes = 10 - + target { type = "user_reference" id = pagerduty_user.foo.id } } } - + resource "pagerduty_response_play" "foo" { name = "%[1]v" from = pagerduty_user.foo.email diff --git a/pagerduty/resource_pagerduty_schedule_test.go b/pagerduty/resource_pagerduty_schedule_test.go index 4ed90a954..f02b29795 100644 --- a/pagerduty/resource_pagerduty_schedule_test.go +++ b/pagerduty/resource_pagerduty_schedule_test.go @@ -51,7 +51,7 @@ func testSweepSchedule(region string) error { func TestAccPagerDutySchedule_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) schedule := fmt.Sprintf("tf-%s", acctest.RandString(5)) scheduleUpdated := fmt.Sprintf("tf-%s", acctest.RandString(5)) location := "America/New_York" @@ -113,7 +113,7 @@ func TestAccPagerDutySchedule_Basic(t *testing.T) { func TestAccPagerDutyScheduleWithTeams_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) schedule := fmt.Sprintf("tf-%s", acctest.RandString(5)) scheduleUpdated := fmt.Sprintf("tf-%s", acctest.RandString(5)) location := "America/New_York" @@ -176,7 +176,7 @@ func TestAccPagerDutyScheduleWithTeams_Basic(t *testing.T) { } func TestAccPagerDutyScheduleOverflow_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) schedule := fmt.Sprintf("tf-%s", acctest.RandString(5)) scheduleUpdated := fmt.Sprintf("tf-%s", acctest.RandString(5)) location := "America/New_York" @@ -206,7 +206,7 @@ func TestAccPagerDutyScheduleOverflow_Basic(t *testing.T) { func TestAccPagerDutySchedule_BasicWeek(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) schedule := fmt.Sprintf("tf-%s", acctest.RandString(5)) scheduleUpdated := fmt.Sprintf("tf-%s", acctest.RandString(5)) location := "Australia/Melbourne" @@ -268,7 +268,7 @@ func TestAccPagerDutySchedule_BasicWeek(t *testing.T) { func TestAccPagerDutySchedule_Multi(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) schedule := fmt.Sprintf("tf-%s", acctest.RandString(5)) location := "Europe/Berlin" start := timeNowInLoc(location).Add(24 * time.Hour).Round(1 * time.Hour).Format(time.RFC3339) @@ -745,7 +745,7 @@ resource "pagerduty_schedule" "foo" { time_zone = "%s" description = "foo" - + teams = [pagerduty_team.foo.id] layer { @@ -781,7 +781,7 @@ resource "pagerduty_schedule" "foo" { time_zone = "%s" description = "Managed by Terraform" - + teams = [pagerduty_team.foo.id] layer { diff --git a/pagerduty/resource_pagerduty_service_dependency_test.go b/pagerduty/resource_pagerduty_service_dependency_test.go index ae5e6b69c..11a02ec08 100644 --- a/pagerduty/resource_pagerduty_service_dependency_test.go +++ b/pagerduty/resource_pagerduty_service_dependency_test.go @@ -15,7 +15,7 @@ func TestAccPagerDutyBusinessServiceDependency_Basic(t *testing.T) { service := fmt.Sprintf("tf-%s", acctest.RandString(5)) businessService := fmt.Sprintf("tf-%s", acctest.RandString(5)) username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) resource.Test(t, resource.TestCase{ @@ -152,7 +152,7 @@ func TestAccPagerDutyTechnicalServiceDependency_Basic(t *testing.T) { dependentService := fmt.Sprintf("tf-%s", acctest.RandString(5)) supportingService := fmt.Sprintf("tf-%s", acctest.RandString(5)) username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) resource.Test(t, resource.TestCase{ diff --git a/pagerduty/resource_pagerduty_service_event_rule_test.go b/pagerduty/resource_pagerduty_service_event_rule_test.go index f4e593fe2..199c457f3 100644 --- a/pagerduty/resource_pagerduty_service_event_rule_test.go +++ b/pagerduty/resource_pagerduty_service_event_rule_test.go @@ -11,7 +11,7 @@ import ( func TestAccPagerDutyServiceEventRule_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) rule := fmt.Sprintf("tf-%s", acctest.RandString(5)) @@ -74,7 +74,7 @@ func TestAccPagerDutyServiceEventRule_Basic(t *testing.T) { func TestAccPagerDutyServiceEventRule_MultipleRules(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) rule1 := fmt.Sprintf("tf-%s", acctest.RandString(5)) diff --git a/pagerduty/resource_pagerduty_service_integration_test.go b/pagerduty/resource_pagerduty_service_integration_test.go index 61b533387..2c7481c33 100644 --- a/pagerduty/resource_pagerduty_service_integration_test.go +++ b/pagerduty/resource_pagerduty_service_integration_test.go @@ -13,7 +13,7 @@ import ( func TestAccPagerDutyServiceIntegration_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) serviceIntegration := fmt.Sprintf("tf-%s", acctest.RandString(5)) @@ -56,7 +56,7 @@ func TestAccPagerDutyServiceIntegration_Basic(t *testing.T) { func TestAccPagerDutyServiceIntegrationGeneric_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) serviceIntegration := fmt.Sprintf("tf-%s", acctest.RandString(5)) @@ -115,7 +115,7 @@ func TestAccPagerDutyServiceIntegrationGeneric_Basic(t *testing.T) { } func TestAccPagerDutyServiceIntegrationEmail_Filters(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) serviceIntegration := fmt.Sprintf("tf-%s", acctest.RandString(5)) @@ -146,7 +146,7 @@ func TestAccPagerDutyServiceIntegrationEmail_Filters(t *testing.T) { resource.TestCheckResourceAttr( "pagerduty_service_integration.foo", "email_filter.0.from_email_mode", "match"), resource.TestCheckResourceAttr( - "pagerduty_service_integration.foo", "email_filter.0.from_email_regex", "(@foo.com*)"), + "pagerduty_service_integration.foo", "email_filter.0.from_email_regex", "(@foo.test*)"), resource.TestCheckResourceAttr( "pagerduty_service_integration.foo", "email_filter.0.subject_mode", "match"), resource.TestCheckResourceAttr( @@ -262,7 +262,7 @@ func TestAccPagerDutyServiceIntegrationEmail_Filters(t *testing.T) { resource.TestCheckResourceAttr( "pagerduty_service_integration.foo", "email_filter.0.from_email_mode", "match"), resource.TestCheckResourceAttr( - "pagerduty_service_integration.foo", "email_filter.0.from_email_regex", "(@foo.com*)"), + "pagerduty_service_integration.foo", "email_filter.0.from_email_regex", "(@foo.test*)"), resource.TestCheckResourceAttr( "pagerduty_service_integration.foo", "email_filter.0.subject_mode", "match"), resource.TestCheckResourceAttr( @@ -746,7 +746,7 @@ resource "pagerduty_service_integration" "foo" { body_mode = "always" body_regex = null from_email_mode = "match" - from_email_regex = "(@foo.com*)" + from_email_regex = "(@foo.test*)" subject_mode = "match" subject_regex = "(CRITICAL*)" } @@ -872,7 +872,7 @@ resource "pagerduty_service_integration" "foo" { body_mode = "always" body_regex = null from_email_mode = "match" - from_email_regex = "(@foo.com*)" + from_email_regex = "(@foo.test*)" subject_mode = "match" subject_regex = "(CRITICAL*)" } diff --git a/pagerduty/resource_pagerduty_service_test.go b/pagerduty/resource_pagerduty_service_test.go index 9db9a8608..56de1270e 100644 --- a/pagerduty/resource_pagerduty_service_test.go +++ b/pagerduty/resource_pagerduty_service_test.go @@ -50,7 +50,7 @@ func testSweepService(region string) error { func TestAccPagerDutyService_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) serviceUpdated := fmt.Sprintf("tf-%s", acctest.RandString(5)) @@ -132,7 +132,7 @@ func TestAccPagerDutyService_Basic(t *testing.T) { func TestAccPagerDutyService_AlertGrouping(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) @@ -199,7 +199,7 @@ func TestAccPagerDutyService_AlertGrouping(t *testing.T) { func TestAccPagerDutyService_AlertContentGrouping(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) @@ -244,7 +244,7 @@ func TestAccPagerDutyService_AlertContentGrouping(t *testing.T) { func TestAccPagerDutyService_BasicWithIncidentUrgencyRules(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) serviceUpdated := fmt.Sprintf("tf-%s", acctest.RandString(5)) @@ -446,7 +446,7 @@ func TestAccPagerDutyService_BasicWithIncidentUrgencyRules(t *testing.T) { func TestAccPagerDutyService_FromBasicToCustomIncidentUrgencyRules(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) serviceUpdated := fmt.Sprintf("tf-%s", acctest.RandString(5)) @@ -548,7 +548,7 @@ func TestAccPagerDutyService_FromBasicToCustomIncidentUrgencyRules(t *testing.T) func TestAccPagerDutyService_SupportHoursChange(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) service_id := "" @@ -759,9 +759,9 @@ resource "pagerduty_service" "foo" { acknowledgement_timeout = 1800 escalation_policy = pagerduty_escalation_policy.foo.id alert_creation = "create_alerts_and_incidents" - alert_grouping_parameters { + alert_grouping_parameters { type = "content_based" - config { + config { aggregate = "all" fields = ["custom_details.field1"] } diff --git a/pagerduty/resource_pagerduty_slack_connection_test.go b/pagerduty/resource_pagerduty_slack_connection_test.go index af9133252..147ca848c 100644 --- a/pagerduty/resource_pagerduty_slack_connection_test.go +++ b/pagerduty/resource_pagerduty_slack_connection_test.go @@ -22,7 +22,7 @@ var ( func TestAccPagerDutySlackConnection_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) @@ -165,32 +165,32 @@ func testAccCheckPagerDutySlackConnectionExists(n string) resource.TestCheckFunc func testAccCheckPagerDutySlackConnectionConfig(username, useremail, escalationPolicy, service, workspaceID, channelID string) string { return fmt.Sprintf(` resource "pagerduty_user" "foo" { - name = "%s" + name = "%s" email = "%s" } - + resource "pagerduty_escalation_policy" "foo" { name = "%s" description = "foo" num_loops = 1 - + rule { escalation_delay_in_minutes = 10 - + target { type = "user_reference" id = pagerduty_user.foo.id } } } - + resource "pagerduty_service" "foo" { name = "%s" description = "foo" auto_resolve_timeout = 1800 acknowledgement_timeout = 1800 escalation_policy = pagerduty_escalation_policy.foo.id - + incident_urgency_rule { type = "constant" urgency = "high" @@ -219,7 +219,7 @@ func testAccCheckPagerDutySlackConnectionConfig(username, useremail, escalationP "incident.responder.added", "incident.responder.replied", "incident.status_update_published", - "incident.reopened" + "incident.reopened" ] priorities = [data.pagerduty_priority.p1.id] urgency = "high" @@ -231,32 +231,32 @@ func testAccCheckPagerDutySlackConnectionConfig(username, useremail, escalationP func testAccCheckPagerDutySlackConnectionConfigUpdated(username, email, escalationPolicy, service, workspaceID, channelID string) string { return fmt.Sprintf(` resource "pagerduty_user" "foo" { - name = "%s" + name = "%s" email = "%s" } - + resource "pagerduty_escalation_policy" "foo" { name = "%s" description = "foo" num_loops = 1 - + rule { escalation_delay_in_minutes = 10 - + target { type = "user_reference" id = pagerduty_user.foo.id } } } - + resource "pagerduty_service" "foo" { name = "%s" description = "foo" auto_resolve_timeout = 1800 acknowledgement_timeout = 1800 escalation_policy = pagerduty_escalation_policy.foo.id - + incident_urgency_rule { type = "constant" urgency = "high" @@ -285,7 +285,7 @@ func testAccCheckPagerDutySlackConnectionConfigUpdated(username, email, escalati "incident.responder.added", "incident.responder.replied", "incident.status_update_published", - "incident.reopened" + "incident.reopened" ] priorities = [data.pagerduty_priority.p1.id] } @@ -318,7 +318,7 @@ func testAccCheckPagerDutySlackConnectionConfigTeam(team, workspaceID, channelID "incident.responder.added", "incident.responder.replied", "incident.status_update_published", - "incident.reopened" + "incident.reopened" ] } } @@ -349,7 +349,7 @@ func testAccCheckPagerDutySlackConnectionConfigTeamUpdated(team, workspaceID, ch "incident.responder.added", "incident.responder.replied", "incident.status_update_published", - "incident.reopened" + "incident.reopened" ] urgency = "low" } @@ -381,7 +381,7 @@ func testAccCheckPagerDutySlackConnectionConfigEnvar(team, channelID string) str "incident.responder.added", "incident.responder.replied", "incident.status_update_published", - "incident.reopened" + "incident.reopened" ] urgency = "low" } diff --git a/pagerduty/resource_pagerduty_tag_assignment_test.go b/pagerduty/resource_pagerduty_tag_assignment_test.go index 893463dc4..e6a7cfc82 100644 --- a/pagerduty/resource_pagerduty_tag_assignment_test.go +++ b/pagerduty/resource_pagerduty_tag_assignment_test.go @@ -13,7 +13,7 @@ import ( func TestAccPagerDutyTagAssignment_User(t *testing.T) { tagLabel := fmt.Sprintf("tf-%s", acctest.RandString(5)) username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -61,7 +61,7 @@ func TestAccPagerDutyTagAssignment_EP(t *testing.T) { tagLabel := fmt.Sprintf("tf-%s", acctest.RandString(5)) ep := fmt.Sprintf("tf-%s", acctest.RandString(5)) username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -184,15 +184,15 @@ resource "pagerduty_user" "foo" { name = "%s" email = "%s" } - + resource "pagerduty_escalation_policy" "foo" { name = "%s" description = "foo" num_loops = 1 - + rule { escalation_delay_in_minutes = 10 - + target { type = "user_reference" id = pagerduty_user.foo.id diff --git a/pagerduty/resource_pagerduty_team_membership_test.go b/pagerduty/resource_pagerduty_team_membership_test.go index ffcc6cff2..a6f0aacbf 100644 --- a/pagerduty/resource_pagerduty_team_membership_test.go +++ b/pagerduty/resource_pagerduty_team_membership_test.go @@ -114,7 +114,7 @@ func testAccCheckPagerDutyTeamMembershipConfig(user, team string) string { return fmt.Sprintf(` resource "pagerduty_user" "foo" { name = "%[1]v" - email = "%[1]v@foo.com" + email = "%[1]v@foo.test" } resource "pagerduty_team" "foo" { @@ -133,7 +133,7 @@ func testAccCheckPagerDutyTeamMembershipWithRoleConfig(user, team, role string) return fmt.Sprintf(` resource "pagerduty_user" "foo" { name = "%[1]v" - email = "%[1]v@foo.com" + email = "%[1]v@foo.test" } resource "pagerduty_team" "foo" { diff --git a/pagerduty/resource_pagerduty_user_contact_method_test.go b/pagerduty/resource_pagerduty_user_contact_method_test.go index 1b173113a..2eb819a79 100644 --- a/pagerduty/resource_pagerduty_user_contact_method_test.go +++ b/pagerduty/resource_pagerduty_user_contact_method_test.go @@ -13,8 +13,8 @@ import ( func TestAccPagerDutyUserContactMethodEmail_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) usernameUpdated := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) - emailUpdated := fmt.Sprintf("%s@foo.com", usernameUpdated) + email := fmt.Sprintf("%s@foo.test", username) + emailUpdated := fmt.Sprintf("%s@foo.test", usernameUpdated) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -40,8 +40,8 @@ func TestAccPagerDutyUserContactMethodEmail_Basic(t *testing.T) { func TestAccPagerDutyUserContactMethodPhone_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) usernameUpdated := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) - emailUpdated := fmt.Sprintf("%s@foo.com", usernameUpdated) + email := fmt.Sprintf("%s@foo.test", username) + emailUpdated := fmt.Sprintf("%s@foo.test", usernameUpdated) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -71,8 +71,8 @@ func TestAccPagerDutyUserContactMethodPhone_Basic(t *testing.T) { func TestAccPagerDutyUserContactMethodSMS_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) usernameUpdated := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) - emailUpdated := fmt.Sprintf("%s@foo.com", usernameUpdated) + email := fmt.Sprintf("%s@foo.test", username) + emailUpdated := fmt.Sprintf("%s@foo.test", usernameUpdated) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, diff --git a/pagerduty/resource_pagerduty_user_notification_rule_test.go b/pagerduty/resource_pagerduty_user_notification_rule_test.go index 6e80e3f6f..59ef06337 100644 --- a/pagerduty/resource_pagerduty_user_notification_rule_test.go +++ b/pagerduty/resource_pagerduty_user_notification_rule_test.go @@ -12,7 +12,7 @@ import ( func TestAccPagerDutyUserNotificationRuleContactMethod_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) contactMethodType1 := "email_contact_method" contactMethodType2 := "phone_contact_method" contactMethodType3 := "sms_contact_method" @@ -46,7 +46,7 @@ func TestAccPagerDutyUserNotificationRuleContactMethod_Basic(t *testing.T) { func TestAccPagerDutyUserNotificationRuleContactMethod_Invalid(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -63,7 +63,7 @@ func TestAccPagerDutyUserNotificationRuleContactMethod_Invalid(t *testing.T) { func TestAccPagerDutyUserNotificationRuleContactMethod_Missing_id(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -80,7 +80,7 @@ func TestAccPagerDutyUserNotificationRuleContactMethod_Missing_id(t *testing.T) func TestAccPagerDutyUserNotificationRuleContactMethod_Missing_type(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -97,7 +97,7 @@ func TestAccPagerDutyUserNotificationRuleContactMethod_Missing_type(t *testing.T func TestAccPagerDutyUserNotificationRuleContactMethod_Unknown_key(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, diff --git a/pagerduty/resource_pagerduty_user_test.go b/pagerduty/resource_pagerduty_user_test.go index 89bd18759..b16d60103 100644 --- a/pagerduty/resource_pagerduty_user_test.go +++ b/pagerduty/resource_pagerduty_user_test.go @@ -56,8 +56,8 @@ func TestAccPagerDutyUser_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) usernameSpaces := " " + username + " " usernameUpdated := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@Foo.com", username) - emailUpdated := fmt.Sprintf("%s@foo.com", usernameUpdated) + email := fmt.Sprintf("%s@foo.test", username) + emailUpdated := fmt.Sprintf("%s@foo.test", usernameUpdated) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -108,7 +108,7 @@ func TestAccPagerDutyUser_Basic(t *testing.T) { func TestAccPagerDutyUserWithTeams_Basic(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) team1 := fmt.Sprintf("tf-%s", acctest.RandString(5)) team2 := fmt.Sprintf("tf-%s", acctest.RandString(5)) diff --git a/pagerduty/resource_pagerduty_webhook_subscription_test.go b/pagerduty/resource_pagerduty_webhook_subscription_test.go index 6ea02f17f..dbddad061 100644 --- a/pagerduty/resource_pagerduty_webhook_subscription_test.go +++ b/pagerduty/resource_pagerduty_webhook_subscription_test.go @@ -48,7 +48,7 @@ func testSweepWebhookSubscription(region string) error { func TestAccPagerDutyWebhookSubscription_Basic(t *testing.T) { description := fmt.Sprintf("tf-test-%s", acctest.RandString(5)) username := fmt.Sprintf("tf-%s", acctest.RandString(5)) - email := fmt.Sprintf("%s@foo.com", username) + email := fmt.Sprintf("%s@foo.test", username) escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) service := fmt.Sprintf("tf-%s", acctest.RandString(5)) @@ -109,38 +109,38 @@ func testAccCheckPagerDutyWebhookSubscriptionExists(n string) resource.TestCheck func testAccCheckPagerDutyWebhookSubscriptionConfig(username, useremail, escalationPolicy, service, description string) string { return fmt.Sprintf(` resource "pagerduty_user" "foo" { - name = "%s" + name = "%s" email = "%s" } - + resource "pagerduty_escalation_policy" "foo" { name = "%s" description = "foo" num_loops = 1 - + rule { escalation_delay_in_minutes = 10 - + target { type = "user_reference" id = pagerduty_user.foo.id } } } - + resource "pagerduty_service" "foo" { name = "%s" description = "foo" auto_resolve_timeout = 1800 acknowledgement_timeout = 1800 escalation_policy = pagerduty_escalation_policy.foo.id - + incident_urgency_rule { type = "constant" urgency = "high" } } - + resource "pagerduty_webhook_subscription" "foo" { delivery_method { type = "http_delivery_method" diff --git a/vendor/go.mongodb.org/mongo-driver/mongo/options/datakeyoptions.go b/vendor/go.mongodb.org/mongo-driver/mongo/options/datakeyoptions.go index c6a17f9e0..3da8f652a 100644 --- a/vendor/go.mongodb.org/mongo-driver/mongo/options/datakeyoptions.go +++ b/vendor/go.mongodb.org/mongo-driver/mongo/options/datakeyoptions.go @@ -22,7 +22,7 @@ func DataKey() *DataKeyOptions { // If being used with a local KMS provider, this option is not applicable and should not be specified. // // For the AWS, Azure, and GCP KMS providers, this option is required and must be a document. For each, the value of the -// "endpoint" or "keyVaultEndpoint" must be a host name with an optional port number (e.g. "foo.com" or "foo.com:443"). +// "endpoint" or "keyVaultEndpoint" must be a host name with an optional port number (e.g. "foo.test" or "foo.test:443"). // // When using AWS, the document must have the format: // { diff --git a/website/docs/r/service_integration.html.markdown b/website/docs/r/service_integration.html.markdown index e50b0e999..c10318699 100644 --- a/website/docs/r/service_integration.html.markdown +++ b/website/docs/r/service_integration.html.markdown @@ -96,7 +96,7 @@ resource "pagerduty_service_integration" "email" { body_mode = "always" body_regex = null from_email_mode = "match" - from_email_regex = "(@foo.com*)" + from_email_regex = "(@foo.test*)" subject_mode = "match" subject_regex = "(CRITICAL*)" } @@ -201,7 +201,7 @@ The following arguments are supported: * `type` - (Required) Can be `between`, `entire` or `regex`. * `part` - (Required) Can be `subject` or `body`. * `value_name` - (Required) First value extractor should have name `incident_key` other value extractors should contain custom names. - * `ends_before` - (Optional) + * `ends_before` - (Optional) * `starts_after` - (Optional) * `regex` - (Optional) If `type` has value `regex` this value should contain valid regex. From 77cb971ba2d73c62aeeeb7c2455fb4b1e5cc9340 Mon Sep 17 00:00:00 2001 From: Marcos Wright-Kuhns Date: Fri, 6 May 2022 10:01:39 -0700 Subject: [PATCH 29/63] Add instructions about running an individual test to the README --- README.md | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index ee79b47a2..808fabf77 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -Terraform Provider for PagerDuty -================================ +# Terraform Provider for PagerDuty - Website: https://registry.terraform.io/providers/PagerDuty/pagerduty/latest - Documentation: https://registry.terraform.io/providers/PagerDuty/pagerduty/latest/docs @@ -8,14 +7,12 @@ Terraform Provider for PagerDuty [PagerDuty](https://www.pagerduty.com/) is an alarm aggregation and dispatching service for system administrators and support teams. It collects alerts from your monitoring tools, gives you an overall view of all of your monitoring alarms, and alerts an on duty engineer if there’s a problem. The Terraform Pagerduty provider is a plugin for Terraform that allows for the management of PagerDuty resources using HCL (HashiCorp Configuration Language). -Requirements ------------- +## Requirements - [Terraform](https://www.terraform.io/downloads.html) 0.12.x - [Go](https://golang.org/doc/install) 1.11 (to build the provider plugin) -Building The Provider ---------------------- +## Building The Provider Clone repository to: `$GOPATH/src/github.com/terraform-providers/terraform-provider-pagerduty` @@ -31,14 +28,13 @@ $ cd $GOPATH/src/github.com/PagerDuty/terraform-provider-pagerduty $ make build ``` -Using the provider ----------------------- +## Using the provider + Please refer to https://registry.terraform.io/providers/PagerDuty/pagerduty/latest/docs for examples on how to use the provider and detailed documentation about the Resources and Data Sources the provider has. -Developing the Provider ---------------------------- +## Developing the Provider If you wish to work on the provider, you'll first need [Go](http://www.golang.org) installed on your machine (version 1.11+ is *required*). You'll also need to correctly setup a [GOPATH](http://golang.org/doc/code.html#GOPATH), as well as adding `$GOPATH/bin` to your `$PATH`. @@ -51,6 +47,8 @@ $ $GOPATH/bin/terraform-provider-pagerduty ... ``` +### Testing + In order to test the provider, you can simply run `make test`. ```sh @@ -65,4 +63,10 @@ In order to run the full suite of Acceptance tests, run `make testacc`. $ make testacc ``` -*Additional Note:* In order for the tests on the Slack Connection resources to pass you will need valid Slack workspace and channel IDs from a [Slack workspace connected to your PagerDuty account](https://support.pagerduty.com/docs/slack-integration-guide#integration-walkthrough). \ No newline at end of file +*Additional Note:* In order for the tests on the Slack Connection resources to pass you will need valid Slack workspace and channel IDs from a [Slack workspace connected to your PagerDuty account](https://support.pagerduty.com/docs/slack-integration-guide#integration-walkthrough). + +Run a specific subset of tests by name use the `TESTARGS="-run TestName"` option which will run all test functions with "TestName" in their name. + +```sh +$ make testacc TESTARGS="-run TestAccPagerDutyTeam" +``` From 934463567548d5ed91348d3bd1ad5e82b71a41f9 Mon Sep 17 00:00:00 2001 From: Dominik Rastawicki Date: Wed, 4 May 2022 12:56:23 +0800 Subject: [PATCH 30/63] Include timezdata build tag into the goreleaser config --- .goreleaser.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.goreleaser.yml b/.goreleaser.yml index eee11e81d..8097aab79 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -6,6 +6,8 @@ builds: - -trimpath ldflags: - '-s -w -X main.version={{.Version}} -X main.commit={{.Commit}}' + tags: + - timetzdata goos: - freebsd - windows From 7c3edd8a7019b09927041323fce1681e2ba81dcb Mon Sep 17 00:00:00 2001 From: Peter Mescalchin Date: Fri, 13 May 2022 17:09:13 +1000 Subject: [PATCH 31/63] Fix Terraform `user` -> `user_reference` example typo for `pagerduty_escalation_policy` resource --- website/docs/r/escalation_policy.html.markdown | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/website/docs/r/escalation_policy.html.markdown b/website/docs/r/escalation_policy.html.markdown index cf31d3198..9dcab3324 100644 --- a/website/docs/r/escalation_policy.html.markdown +++ b/website/docs/r/escalation_policy.html.markdown @@ -33,11 +33,11 @@ resource "pagerduty_escalation_policy" "example" { rule { escalation_delay_in_minutes = 10 target { - type = "user" + type = "user_reference" id = pagerduty_user.example.id } target { - type = "user" + type = "user_reference" id = pagerduty_user.example2.id } } @@ -55,13 +55,11 @@ The following arguments are supported: * `num_loops` - (Optional) The number of times the escalation policy will repeat after reaching the end of its escalation. * `rule` - (Required) An Escalation rule block. Escalation rules documented below. - Escalation rules (`rule`) supports the following: * `escalation_delay_in_minutes` - (Required) The number of minutes before an unacknowledged incident escalates away from this rule. * `targets` - (Required) A target block. Target blocks documented below. - Targets (`target`) supports the following: * `type` - (Optional) Can be `user_reference` or `schedule_reference`. Defaults to `user_reference`. For multiple users as example, repeat the target. From fb0c0149cce0fe1a3fd0e2455a5350f77b26f816 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Antonio=20Reyes?= Date: Thu, 12 May 2022 17:57:45 -0400 Subject: [PATCH 32/63] update slack integration docs --- website/docs/r/slack_connection.html.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/r/slack_connection.html.markdown b/website/docs/r/slack_connection.html.markdown index 8cfcbbc54..a7a2702b0 100644 --- a/website/docs/r/slack_connection.html.markdown +++ b/website/docs/r/slack_connection.html.markdown @@ -13,6 +13,7 @@ A [slack connection](https://developer.pagerduty.com/api-reference/YXBpOjExMjA5N **NOTES for using this resource:** * To first use this resource you will need to [map your PagerDuty account to a valid Slack Workspace](https://support.pagerduty.com/docs/slack-integration-guide#integration-walkthrough). *This can only be done through the PagerDuty UI.* * This resource requires a PagerDuty [user-level API key](https://support.pagerduty.com/docs/generating-api-keys#section-generating-a-personal-rest-api-key). This can be set as the `user_token` on the provider tag or as the `PAGERDUTY_USER_TOKEN` environment variable. +* If you configured your Slack integration (V1 or V2) prior to August 10, 2021, you may migrate to the Slack V2 Next Generation update using this [migration instructions](https://support.pagerduty.com/docs/slack-integration-guide#migrate-to-slack-v2-next-generation), but if you configured your Slack integration after that date, you will have access to the update out of the box. ## Example Usage ```hcl From d740e9b77eb134cc7ea8d9f2c63dc0d184d1c655 Mon Sep 17 00:00:00 2001 From: Scott McAllister Date: Fri, 13 May 2022 17:15:02 -0700 Subject: [PATCH 33/63] Update slack_connection.html.markdown Small tweak to the message added to the docs. --- website/docs/r/slack_connection.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/slack_connection.html.markdown b/website/docs/r/slack_connection.html.markdown index a7a2702b0..94fa09194 100644 --- a/website/docs/r/slack_connection.html.markdown +++ b/website/docs/r/slack_connection.html.markdown @@ -13,7 +13,7 @@ A [slack connection](https://developer.pagerduty.com/api-reference/YXBpOjExMjA5N **NOTES for using this resource:** * To first use this resource you will need to [map your PagerDuty account to a valid Slack Workspace](https://support.pagerduty.com/docs/slack-integration-guide#integration-walkthrough). *This can only be done through the PagerDuty UI.* * This resource requires a PagerDuty [user-level API key](https://support.pagerduty.com/docs/generating-api-keys#section-generating-a-personal-rest-api-key). This can be set as the `user_token` on the provider tag or as the `PAGERDUTY_USER_TOKEN` environment variable. -* If you configured your Slack integration (V1 or V2) prior to August 10, 2021, you may migrate to the Slack V2 Next Generation update using this [migration instructions](https://support.pagerduty.com/docs/slack-integration-guide#migrate-to-slack-v2-next-generation), but if you configured your Slack integration after that date, you will have access to the update out of the box. +* This resource is for configuring Slack V2 Next Generation connections. If you configured your Slack integration (V1 or V2) prior to August 10, 2021, you may migrate to the Slack V2 Next Generation update using this [migration instructions](https://support.pagerduty.com/docs/slack-integration-guide#migrate-to-slack-v2-next-generation), but if you configured your Slack integration after that date, you will have access to the update out of the box. ## Example Usage ```hcl From ab9a88581148e78041bdde5906d22a22a801c3fb Mon Sep 17 00:00:00 2001 From: jedelson-pagerduty <103767938+jedelson-pagerduty@users.noreply.github.com> Date: Thu, 19 May 2022 14:23:02 -0400 Subject: [PATCH 34/63] Add some additional requirements for running acceptance tests --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 808fabf77..9f3e72e14 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,11 @@ In order to test the provider, you can simply run `make test`. $ make test ``` -In order to run the full suite of Acceptance tests, run `make testacc`. +In order to run the full suite of Acceptance tests, run `make testacc`. Running the acceptance tests requires +that the `PAGERDUTY_TOKEN` environment variable be set to a valid API Token and that the +`PAGERDUTY_USER_TOKEN` environment variable be set to a valid API User Token. Many tests also +require that the [Email Domain Restriction](https://support.pagerduty.com/docs/account-settings#email-domain-restriction) feature +either be disabled *or* be configured to include `foo.test` as an allowed domain. *Note:* Acceptance tests create real resources, and often cost money to run. From ec87a0651b8c74dfc322e9be0d751e307d84b728 Mon Sep 17 00:00:00 2001 From: Scott McAllister Date: Fri, 20 May 2022 14:12:40 -0700 Subject: [PATCH 35/63] Update CHANGELOG.md --- CHANGELOG.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b0725948..ab8225a49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,16 @@ -## 2.4.2 (Unreleased) +## 2.4.2 (May 20, 2022) IMPROVEMENTS: -* Use "@foo.test" email addresses in tests +* Acceptance Test Improvements: Use "@foo.test" email addresses in tests. ([#491](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/491)) +* Acceptance Test Improvements: Adding better notes to README on running ACC ([#503](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/503)) +* `resource/pagerduty_ruleset_rule`: Introduce support for `catch_all` rules. ([#481](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/481)) +* Docs: `resource/pagerduty_slack_connection`: Improved notes on resource supporting Slack V2 Next Generation ([#496](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/496)) + +BUG FIXES: +* Documentation: Fixed all broken links to the PagerDuty API documentation ([#464](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/464)) +* Docs: `resource/pagerduty_escalation_policy`: Fixed `user` -> `user_reference` in samples ([#497](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/497)) +* Build Process: Include `timezdata` build tag in goreleaser config ([#488](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/488)) +* `data_source/pagerduty_escalation_policy`,`data_source/pagerduty_ruleset`: Changed logic to retry on all errors returned by PD API. Remedies GOAWAY error. ([#507](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/507)) ## 2.4.1 (April 22, 2022) IMPROVEMENTS: From e993179c80003ed8c9770aa276d78eea58845769 Mon Sep 17 00:00:00 2001 From: Scott McAllister Date: Fri, 20 May 2022 12:13:08 -0700 Subject: [PATCH 36/63] removing 429 check on ep and ruleset data --- pagerduty/data_source_pagerduty_escalation_policy.go | 12 ++++-------- pagerduty/data_source_pagerduty_ruleset.go | 12 ++++-------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/pagerduty/data_source_pagerduty_escalation_policy.go b/pagerduty/data_source_pagerduty_escalation_policy.go index 4a68de007..4c27ace8d 100644 --- a/pagerduty/data_source_pagerduty_escalation_policy.go +++ b/pagerduty/data_source_pagerduty_escalation_policy.go @@ -40,14 +40,10 @@ func dataSourcePagerDutyEscalationPolicyRead(d *schema.ResourceData, meta interf return resource.Retry(5*time.Minute, func() *resource.RetryError { resp, _, err := client.EscalationPolicies.List(o) if err != nil { - if isErrCode(err, 429) { - // Delaying retry by 30s as recommended by PagerDuty - // https://developer.pagerduty.com/docs/rest-api-v2/rate-limiting/#what-are-possible-workarounds-to-the-events-api-rate-limit - time.Sleep(30 * time.Second) - return resource.RetryableError(err) - } - - return resource.NonRetryableError(err) + // Delaying retry by 30s as recommended by PagerDuty + // https://developer.pagerduty.com/docs/rest-api-v2/rate-limiting/#what-are-possible-workarounds-to-the-events-api-rate-limit + time.Sleep(30 * time.Second) + return resource.RetryableError(err) } var found *pagerduty.EscalationPolicy diff --git a/pagerduty/data_source_pagerduty_ruleset.go b/pagerduty/data_source_pagerduty_ruleset.go index f4df0d6ed..5e902274e 100644 --- a/pagerduty/data_source_pagerduty_ruleset.go +++ b/pagerduty/data_source_pagerduty_ruleset.go @@ -43,14 +43,10 @@ func dataSourcePagerDutyRulesetRead(d *schema.ResourceData, meta interface{}) er return resource.Retry(5*time.Minute, func() *resource.RetryError { resp, _, err := client.Rulesets.List() if err != nil { - if isErrCode(err, 429) { - // Delaying retry by 30s as recommended by PagerDuty - // https://developer.pagerduty.com/docs/rest-api-v2/rate-limiting/#what-are-possible-workarounds-to-the-events-api-rate-limit - time.Sleep(30 * time.Second) - return resource.RetryableError(err) - } - - return resource.NonRetryableError(err) + // Delaying retry by 30s as recommended by PagerDuty + // https://developer.pagerduty.com/docs/rest-api-v2/rate-limiting/#what-are-possible-workarounds-to-the-events-api-rate-limit + time.Sleep(30 * time.Second) + return resource.RetryableError(err) } var found *pagerduty.Ruleset From ce2cedbc0de7c0532225ae1f8f8c26bc9e040a42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Antonio=20Reyes?= Date: Mon, 23 May 2022 20:16:58 -0400 Subject: [PATCH 37/63] change users paginated listing by list all --- pagerduty/data_source_pagerduty_user.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pagerduty/data_source_pagerduty_user.go b/pagerduty/data_source_pagerduty_user.go index fbea4c541..cb94a7661 100644 --- a/pagerduty/data_source_pagerduty_user.go +++ b/pagerduty/data_source_pagerduty_user.go @@ -42,7 +42,7 @@ func dataSourcePagerDutyUserRead(d *schema.ResourceData, meta interface{}) error } return resource.Retry(5*time.Minute, func() *resource.RetryError { - resp, _, err := client.Users.List(o) + resp, err := client.Users.ListAll(o) if err != nil { if isErrCode(err, 429) { // Delaying retry by 30s as recommended by PagerDuty @@ -54,9 +54,9 @@ func dataSourcePagerDutyUserRead(d *schema.ResourceData, meta interface{}) error return resource.NonRetryableError(err) } - var found *pagerduty.User + var found *pagerduty.FullUser - for _, user := range resp.Users { + for _, user := range resp { if user.Email == searchEmail { found = user break From 18cdab72b39f451ad8c6740723e9424a95b3e62a Mon Sep 17 00:00:00 2001 From: Bohdan Borovskyi <51109105+bohdanborovskyi-ma@users.noreply.github.com> Date: Thu, 7 Apr 2022 15:37:09 +0300 Subject: [PATCH 38/63] Fix flattened valueExtractor to preserve regex field Current flattening logic not aligned with expandEmailParsers function logic --- .../resource_pagerduty_service_integration.go | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/pagerduty/resource_pagerduty_service_integration.go b/pagerduty/resource_pagerduty_service_integration.go index dfb6e81dc..d3c8ca00a 100644 --- a/pagerduty/resource_pagerduty_service_integration.go +++ b/pagerduty/resource_pagerduty_service_integration.go @@ -519,12 +519,21 @@ func flattenEmailParsers(v []*pagerduty.EmailParser) []map[string]interface{} { var valueExtractors []map[string]interface{} for _, ve := range ef.ValueExtractors { - extractor := map[string]interface{}{ - "type": ve.Type, - "value_name": ve.ValueName, - "part": ve.Part, - "starts_after": ve.StartsAfter, - "ends_before": ve.EndsBefore, + if ve.Type == "regex" { + extractor := map[string]interface{}{ + "type": ve.Type, + "value_name": ve.ValueName, + "part": ve.Part, + "regex": ve.Regex, + } + } else { + extractor := map[string]interface{}{ + "type": ve.Type, + "value_name": ve.ValueName, + "part": ve.Part, + "starts_after": ve.StartsAfter, + "ends_before": ve.EndsBefore, + } } valueExtractors = append(valueExtractors, extractor) From 90ca174905ed1f4477fccb2e6337edff0c3ab5c7 Mon Sep 17 00:00:00 2001 From: Bohdan Borovskyi <51109105+bohdanborovskyi-ma@users.noreply.github.com> Date: Thu, 7 Apr 2022 15:53:56 +0300 Subject: [PATCH 39/63] Change one of tests to verify email parser with regex type --- ...source_pagerduty_service_integration_test.go | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/pagerduty/resource_pagerduty_service_integration_test.go b/pagerduty/resource_pagerduty_service_integration_test.go index 2c7481c33..a9b4072d4 100644 --- a/pagerduty/resource_pagerduty_service_integration_test.go +++ b/pagerduty/resource_pagerduty_service_integration_test.go @@ -356,14 +356,12 @@ func TestAccPagerDutyServiceIntegrationEmail_Filters(t *testing.T) { "pagerduty_service_integration.foo", "email_parser.1.value_extractor.1.type", "between"), resource.TestCheckResourceAttr( "pagerduty_service_integration.foo", "email_parser.1.value_extractor.1.value_name", "FieldName11"), - resource.TestCheckResourceAttr( - "pagerduty_service_integration.foo", "email_parser.1.value_extractor.2.ends_before", "end"), resource.TestCheckResourceAttr( "pagerduty_service_integration.foo", "email_parser.1.value_extractor.2.part", "subject"), resource.TestCheckResourceAttr( - "pagerduty_service_integration.foo", "email_parser.1.value_extractor.2.starts_after", "start"), + "pagerduty_service_integration.foo", "email_parser.1.value_extractor.2.regex", "(bar*)"), resource.TestCheckResourceAttr( - "pagerduty_service_integration.foo", "email_parser.1.value_extractor.2.type", "between"), + "pagerduty_service_integration.foo", "email_parser.1.value_extractor.2.type", "regex"), resource.TestCheckResourceAttr( "pagerduty_service_integration.foo", "email_parser.1.value_extractor.2.value_name", "FieldName2"), ), @@ -949,12 +947,11 @@ resource "pagerduty_service_integration" "foo" { type = "between" value_name = "FieldName11" } - value_extractor { - ends_before = "end" - part = "subject" - starts_after = "start" - type = "between" - value_name = "FieldName2" + value_extractor { + part = "subject" + regex = "(bar*)" + type = "regex" + value_name = "FieldName2" } } email_parsing_fallback = "open_new_incident" From 0b5ac0f4bd03e33e068ab1eaf7d21f985607872b Mon Sep 17 00:00:00 2001 From: Bohdan Borovskyi <51109105+bohdanborovskyi-ma@users.noreply.github.com> Date: Thu, 7 Apr 2022 16:07:48 +0300 Subject: [PATCH 40/63] Update docs for params related to Email Management --- website/docs/r/service_integration.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/r/service_integration.html.markdown b/website/docs/r/service_integration.html.markdown index c10318699..c2fa60d03 100644 --- a/website/docs/r/service_integration.html.markdown +++ b/website/docs/r/service_integration.html.markdown @@ -169,8 +169,8 @@ The following arguments are supported: * `integration_key` - (Optional) This is the unique key used to route events to this integration when received via the PagerDuty Events API. * `integration_email` - (Optional) This is the unique fully-qualified email address used for routing emails to this integration for processing. - * `email_incident_creation` - (Optional) This is the unique fully-qualified email address used for routing emails to this integration for processing. - * `email_filter_mode` - (Optional) This is the unique fully-qualified email address used for routing emails to this integration for processing. + * `email_incident_creation` - (Optional) Behaviour of Email Management feature ([explained in PD docs](https://support.pagerduty.com/docs/email-management-filters-and-rules#control-when-a-new-incident-or-alert-is-triggered)). Can be `on_new_email`, `on_new_email_subject`, `only_if_no_open_incidents` or `use_rules`. + * `email_filter_mode` - (Optional) Mode of Emails Filters feature ([explained in PD docs](https://support.pagerduty.com/docs/email-management-filters-and-rules#configure-a-regex-filter)). Can be `all-email`, `or-rules-email` or `and-rules-email`. * `email_parsing_fallback` - (Optional) Can be `open_new_incident` or `discard`. Email filters (`email_filter`) supports the following: From 2d3b28ecb185fa345d95178a5dd7add62a8448a9 Mon Sep 17 00:00:00 2001 From: Bohdan Borovskyi <51109105+bohdanborovskyi-ma@users.noreply.github.com> Date: Tue, 26 Apr 2022 23:42:19 +0300 Subject: [PATCH 41/63] [HF] Fix variable assignment --- .../resource_pagerduty_service_integration.go | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/pagerduty/resource_pagerduty_service_integration.go b/pagerduty/resource_pagerduty_service_integration.go index d3c8ca00a..4c8556782 100644 --- a/pagerduty/resource_pagerduty_service_integration.go +++ b/pagerduty/resource_pagerduty_service_integration.go @@ -519,21 +519,17 @@ func flattenEmailParsers(v []*pagerduty.EmailParser) []map[string]interface{} { var valueExtractors []map[string]interface{} for _, ve := range ef.ValueExtractors { - if ve.Type == "regex" { - extractor := map[string]interface{}{ + extractor := map[string]interface{}{ "type": ve.Type, "value_name": ve.ValueName, "part": ve.Part, - "regex": ve.Regex, - } + } + + if ve.Type == "regex" { + extractor["regex"] = ve.Regex } else { - extractor := map[string]interface{}{ - "type": ve.Type, - "value_name": ve.ValueName, - "part": ve.Part, - "starts_after": ve.StartsAfter, - "ends_before": ve.EndsBefore, - } + extractor["starts_after"] = ve.StartsAfter + extractor["ends_before"] = ve.EndsBefore } valueExtractors = append(valueExtractors, extractor) From 9175f2c8fe865052db6085da8a04bdeeaa754a9b Mon Sep 17 00:00:00 2001 From: Bohdan Borovskyi <51109105+bohdanborovskyi-ma@users.noreply.github.com> Date: Tue, 26 Apr 2022 23:44:48 +0300 Subject: [PATCH 42/63] Format the code --- pagerduty/resource_pagerduty_service_integration.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pagerduty/resource_pagerduty_service_integration.go b/pagerduty/resource_pagerduty_service_integration.go index 4c8556782..6845646fa 100644 --- a/pagerduty/resource_pagerduty_service_integration.go +++ b/pagerduty/resource_pagerduty_service_integration.go @@ -520,9 +520,9 @@ func flattenEmailParsers(v []*pagerduty.EmailParser) []map[string]interface{} { for _, ve := range ef.ValueExtractors { extractor := map[string]interface{}{ - "type": ve.Type, - "value_name": ve.ValueName, - "part": ve.Part, + "type": ve.Type, + "value_name": ve.ValueName, + "part": ve.Part, } if ve.Type == "regex" { From d223aac8561a27fb66360a3e65015318777ce1b4 Mon Sep 17 00:00:00 2001 From: alenapan <47909261+alenapan@users.noreply.github.com> Date: Wed, 1 Jun 2022 16:29:28 -0400 Subject: [PATCH 43/63] [ORCA-3444] Add support for Event Orchestrations (#512) * ORCA-3459 - event orchestration resource * reformat * [REVERT LATER] Temporarily pointing to the local copy of go-pagerduty * rename Orchestration references to EventOrchestration * add more properties, mapping logic; add tests * more tests to event_orchestration_resource * add datasource event orchestration * [REVERT LATER]-local testing * fix create logic (set integrations), remove description and routes from orchestration data source * fix data source, add data source tests * reformat * Add import tests * update to latest alenapan/go-pagerduty * add team checks to the tests * [ORCA-3475] Allow deleting event orchestration team from an orchestration (#494) * support unsetting orch team * add retry logic to the event orchestration update method * [ORCA-3463] Orchestration Path Router Resource (#493) * router path * Add support for parent * refactor * update handler and actions support * support conditions * move conditions to util * move parent to util * test for multiple rules and conditions * actions and catchall * refactor tests * validateFunc * refactor * undo local vendor module path change * rules schema change and test * PR comments addressed * Event orchestration unrouted resource (#495) * Init commit for unrouted * Added tests for unrouted * Added catch_all to unrouted schema * Tweaked catch_all * Merge event-orchestrations * Add testacc for unrouted * Added full config test for unrouted * Add test for number of extractions and variables * Cleaned router and added new test checks to unrouted * Change escalation_policy from snake case to camel case * make type computed and set it on read/update * Orca 3486 refactor (#500) * Clean sweeper function for router/unrouted * Clean sweeper function * [ORCA-3465] - Event Orchestration Service path resource (#499) * ORCA-3465 - Event Orchestration Service Path resource * add resource file * fix read/update, add test * more tests * more service path tests, add conditions * more tests * more tests * add more service path props * fix orch path PUT payload, add tests * fix Suspend * ToDos * add catch_all support, fix tests * add support for regex extractions, add mor tests, add service path import test * update client * PR feedback * Flatten teams block (#506) * Flatten teams block * Fixed naming for the test orchestration * ORCA-3486 - remove team attribute from service path * flatten/rename parent to 'service' for service path * remove type attribute from unrouted * remove type attribute from router * flatten/rename parent to 'event_orchestration' for router * set event_orchestration attr on router import * flatten/rename parent to 'event_orchestration' for unrouted * Clean teams block * revert changes on web file * [ORCA-3486] - Reuse shared Event Orchestration Path logic, add import tests (#509) * ORCA-3486 - add import tests for router/unrouted * ORCA-3486 - add import tests for router, unrouted * reuse severity/event_action validation functions in unrouted/service * reuse variables and extractions schema in router/unrouted * reuse shared conditions schema and mapping functions in router/unrouted/service * [ORCA-3486] Extend unrouted tests, add CustomizeDiff, clean shared functions (#510) * Extend unrouted tests, add CustomizeDiff, clean shared functions * Move shared functions for unrouted and service paths to utils file * orchestration and path resource documentation * datasource documentation * refactor * update comment * update type field documentation * update documentation * cleanup * Remove mention of the suppress action from event_orchestration_unrouted docs * Add "Optional" info to 1 attribute in event_orchestration_service docs * give a better datasource example * cleanup * Add Event Orchestration info to the CHANGELOG (release date TBD) (#514) * update go-pagerduty package * Router - make sets, rules, conditions singular * Unrouted, Service - make sets, rules, conditions, variables, extractions, pd_automation_actions, automations_action (headers, params) singular * Event Orchestration - make integrations singular * update Event Orchestration documentation * EO data source - retry on any error * EO data source - retry on any error Co-authored-by: Pari Dhanakoti Co-authored-by: Alex Zakabluk Co-authored-by: Marcos Wright-Kuhns Co-authored-by: Scott McAllister --- CHANGELOG.md | 9 + go.mod | 2 +- go.sum | 4 + ...ta_source_pagerduty_event_orchestration.go | 102 +++ ...urce_pagerduty_event_orchestration_test.go | 64 ++ pagerduty/event_orchestration_path_util.go | 225 ++++++ ...ty_event_orchestration_path_router_test.go | 38 + ...y_event_orchestration_path_service_test.go | 36 + ..._event_orchestration_path_unrouted_test.go | 38 + ...port_pagerduty_event_orchestration_test.go | 53 ++ pagerduty/provider.go | 55 +- .../resource_pagerduty_event_orchestration.go | 240 ++++++ ...gerduty_event_orchestration_path_router.go | 335 ++++++++ ...ty_event_orchestration_path_router_test.go | 428 ++++++++++ ...erduty_event_orchestration_path_service.go | 555 +++++++++++++ ...y_event_orchestration_path_service_test.go | 733 ++++++++++++++++++ ...rduty_event_orchestration_path_unrouted.go | 445 +++++++++++ ..._event_orchestration_path_unrouted_test.go | 549 +++++++++++++ ...urce_pagerduty_event_orchestration_test.go | 245 ++++++ pagerduty/util.go | 7 + .../pagerduty/event_orchestration.go | 127 +++ .../pagerduty/event_orchestration_path.go | 147 ++++ .../go-pagerduty/pagerduty/pagerduty.go | 4 + .../mongo/options/datakeyoptions.go | 2 +- vendor/modules.txt | 2 +- .../docs/d/event_orchestration.html.markdown | 60 ++ .../docs/r/event_orchestration.html.markdown | 52 ++ .../event_orchestration_router.html.markdown | 93 +++ .../event_orchestration_service.html.markdown | 215 +++++ ...event_orchestration_unrouted.html.markdown | 102 +++ 30 files changed, 4939 insertions(+), 28 deletions(-) create mode 100644 pagerduty/data_source_pagerduty_event_orchestration.go create mode 100644 pagerduty/data_source_pagerduty_event_orchestration_test.go create mode 100644 pagerduty/event_orchestration_path_util.go create mode 100644 pagerduty/import_pagerduty_event_orchestration_path_router_test.go create mode 100644 pagerduty/import_pagerduty_event_orchestration_path_service_test.go create mode 100644 pagerduty/import_pagerduty_event_orchestration_path_unrouted_test.go create mode 100644 pagerduty/import_pagerduty_event_orchestration_test.go create mode 100644 pagerduty/resource_pagerduty_event_orchestration.go create mode 100644 pagerduty/resource_pagerduty_event_orchestration_path_router.go create mode 100644 pagerduty/resource_pagerduty_event_orchestration_path_router_test.go create mode 100644 pagerduty/resource_pagerduty_event_orchestration_path_service.go create mode 100644 pagerduty/resource_pagerduty_event_orchestration_path_service_test.go create mode 100644 pagerduty/resource_pagerduty_event_orchestration_path_unrouted.go create mode 100644 pagerduty/resource_pagerduty_event_orchestration_path_unrouted_test.go create mode 100644 pagerduty/resource_pagerduty_event_orchestration_test.go create mode 100644 vendor/github.com/heimweh/go-pagerduty/pagerduty/event_orchestration.go create mode 100644 vendor/github.com/heimweh/go-pagerduty/pagerduty/event_orchestration_path.go create mode 100644 website/docs/d/event_orchestration.html.markdown create mode 100644 website/docs/r/event_orchestration.html.markdown create mode 100644 website/docs/r/event_orchestration_router.html.markdown create mode 100644 website/docs/r/event_orchestration_service.html.markdown create mode 100644 website/docs/r/event_orchestration_unrouted.html.markdown diff --git a/CHANGELOG.md b/CHANGELOG.md index ab8225a49..b5dfe244f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +## 2.5.0 (June 1, 2022) + +FEATURES: +* Support for Event Orchestration via several new resources. ([#512](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/512)) + * `resource/pagerduty_event_orchestration` + * `resource/pagerduty_event_orchestration_router` + * `resource/pagerduty_event_orchestration_unrouted` + * `resource/pagerduty_event_orchestration_service` + ## 2.4.2 (May 20, 2022) IMPROVEMENTS: diff --git a/go.mod b/go.mod index b3380923d..c5f0bc0d2 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.16 require ( cloud.google.com/go v0.71.0 // indirect github.com/hashicorp/terraform-plugin-sdk/v2 v2.10.1 - github.com/heimweh/go-pagerduty v0.0.0-20220422231448-43095fe5ba3f + github.com/heimweh/go-pagerduty v0.0.0-20220527195341-4e587aa9b58e golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd // indirect google.golang.org/api v0.35.0 // indirect google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb // indirect diff --git a/go.sum b/go.sum index 9c893f216..dd09ff741 100644 --- a/go.sum +++ b/go.sum @@ -286,6 +286,10 @@ github.com/heimweh/go-pagerduty v0.0.0-20220208023456-83fe435832fb h1:p3faOVCU8L github.com/heimweh/go-pagerduty v0.0.0-20220208023456-83fe435832fb/go.mod h1:JtJGtgN0y9KOCaqFMZFaBCWskpO/KK3Ro9TwjP9ss6w= github.com/heimweh/go-pagerduty v0.0.0-20220422231448-43095fe5ba3f h1:NLk7iDq85F2lz0q1gY32vZR506aYiNcgvV+Us1rX1q4= github.com/heimweh/go-pagerduty v0.0.0-20220422231448-43095fe5ba3f/go.mod h1:JtJGtgN0y9KOCaqFMZFaBCWskpO/KK3Ro9TwjP9ss6w= +github.com/heimweh/go-pagerduty v0.0.0-20220428180718-5a69bb821163 h1:ETKxW+KSjOPaRzZU9f+QrjCkrL7hQqtMPKDv8DnLDO4= +github.com/heimweh/go-pagerduty v0.0.0-20220428180718-5a69bb821163/go.mod h1:JtJGtgN0y9KOCaqFMZFaBCWskpO/KK3Ro9TwjP9ss6w= +github.com/heimweh/go-pagerduty v0.0.0-20220527195341-4e587aa9b58e h1:xit0rQWTVlM9ohz4IzrddDKglC7jey+m3GSI/bz3TIw= +github.com/heimweh/go-pagerduty v0.0.0-20220527195341-4e587aa9b58e/go.mod h1:JtJGtgN0y9KOCaqFMZFaBCWskpO/KK3Ro9TwjP9ss6w= github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= diff --git a/pagerduty/data_source_pagerduty_event_orchestration.go b/pagerduty/data_source_pagerduty_event_orchestration.go new file mode 100644 index 000000000..0e42d5a80 --- /dev/null +++ b/pagerduty/data_source_pagerduty_event_orchestration.go @@ -0,0 +1,102 @@ +package pagerduty + +import ( + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/heimweh/go-pagerduty/pagerduty" +) + +func dataSourcePagerDutyEventOrchestration() *schema.Resource { + return &schema.Resource{ + Read: dataSourcePagerDutyEventOrchestrationRead, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "integration": { + Type: schema.TypeList, + Computed: true, + Optional: true, // Tests keep failing if "Optional: true" is not provided + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + "parameters": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "routing_key": { + Type: schema.TypeString, + Computed: true, + }, + "type": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourcePagerDutyEventOrchestrationRead(d *schema.ResourceData, meta interface{}) error { + client, err := meta.(*Config).Client() + if err != nil { + return err + } + + log.Printf("[INFO] Reading PagerDuty Event Orchestration") + + searchName := d.Get("name").(string) + + return resource.Retry(5*time.Minute, func() *resource.RetryError { + resp, _, err := client.EventOrchestrations.List() + if err != nil { + return resource.RetryableError(err) + } + + var found *pagerduty.EventOrchestration + + for _, orchestration := range resp.Orchestrations { + if orchestration.Name == searchName { + found = orchestration + break + } + } + + if found == nil { + return resource.NonRetryableError( + fmt.Errorf("Unable to locate any Event Orchestration with the name: %s", searchName), + ) + } + + // Get the found orchestration by ID so we can set the integrations property + // since the list ndpoint does not return it + orch, _, err := client.EventOrchestrations.Get(found.ID) + if err != nil { + return resource.RetryableError(err) + } + + d.SetId(orch.ID) + d.Set("name", orch.Name) + + if len(orch.Integrations) > 0 { + d.Set("integration", flattenEventOrchestrationIntegrations(orch.Integrations)) + } + + return nil + }) +} diff --git a/pagerduty/data_source_pagerduty_event_orchestration_test.go b/pagerduty/data_source_pagerduty_event_orchestration_test.go new file mode 100644 index 000000000..554c19037 --- /dev/null +++ b/pagerduty/data_source_pagerduty_event_orchestration_test.go @@ -0,0 +1,64 @@ +package pagerduty + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccDataSourcePagerDutyEventOrchestration_Basic(t *testing.T) { + name := fmt.Sprintf("tf-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourcePagerDutyEventOrchestrationConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccDataSourcePagerDutyEventOrchestration("pagerduty_event_orchestration.test", "data.pagerduty_event_orchestration.by_name"), + ), + }, + }, + }) +} + +func testAccDataSourcePagerDutyEventOrchestration(src, n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + + srcR := s.RootModule().Resources[src] + srcA := srcR.Primary.Attributes + + r := s.RootModule().Resources[n] + a := r.Primary.Attributes + + if a["id"] == "" { + return fmt.Errorf("Expected to get an Event Orchestration ID from PagerDuty") + } + + testAtts := []string{"id", "name", "integration"} + + for _, att := range testAtts { + if a[att] != srcA[att] { + return fmt.Errorf("Expected the Event Orchestration %s to be: %s, but got: %s", att, srcA[att], a[att]) + } + } + + return nil + } +} + +func testAccDataSourcePagerDutyEventOrchestrationConfig(name string) string { + return fmt.Sprintf(` +resource "pagerduty_event_orchestration" "test" { + name = "%s" +} + +data "pagerduty_event_orchestration" "by_name" { + name = pagerduty_event_orchestration.test.name +} +`, name) +} diff --git a/pagerduty/event_orchestration_path_util.go b/pagerduty/event_orchestration_path_util.go new file mode 100644 index 000000000..7f5bc6f65 --- /dev/null +++ b/pagerduty/event_orchestration_path_util.go @@ -0,0 +1,225 @@ +package pagerduty + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/heimweh/go-pagerduty/pagerduty" +) + +var eventOrchestrationPathConditionsSchema = map[string]*schema.Schema{ + "expression": { + Type: schema.TypeString, + Required: true, + }, +} + +var eventOrchestrationPathVariablesSchema = map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "path": { + Type: schema.TypeString, + Required: true, + }, + "type": { + Type: schema.TypeString, + Required: true, + }, + "value": { + Type: schema.TypeString, + Required: true, + }, +} + +var eventOrchestrationPathExtractionsSchema = map[string]*schema.Schema{ + "regex": { + Type: schema.TypeString, + Optional: true, + }, + "source": { + Type: schema.TypeString, + Optional: true, + }, + "target": { + Type: schema.TypeString, + Required: true, + }, + "template": { + Type: schema.TypeString, + Optional: true, + }, +} + +func invalidExtractionRegexTemplateNilConfig() string { + return ` + extraction { + target = "event.summary" + }` +} + +func invalidExtractionRegexTemplateValConfig() string { + return ` + extraction { + regex = ".*" + template = "hi" + target = "event.summary" + }` +} + +func invalidExtractionRegexNilSourceConfig() string { + return ` + extraction { + regex = ".*" + target = "event.summary" + }` +} + +func validateEventOrchestrationPathSeverity() schema.SchemaValidateFunc { + return validateValueFunc([]string{ + "info", + "error", + "warning", + "critical", + }) +} + +func validateEventOrchestrationPathEventAction() schema.SchemaValidateFunc { + return validateValueFunc([]string{ + "trigger", + "resolve", + }) +} + +func checkExtractions(context context.Context, diff *schema.ResourceDiff, i interface{}) error { + sn := diff.Get("set.#").(int) + + for si := 0; si < sn; si++ { + rn := diff.Get(fmt.Sprintf("set.%d.rule.#", si)).(int) + for ri := 0; ri < rn; ri++ { + res := checkExtractionAttributes(diff, fmt.Sprintf("set.%d.rule.%d.actions.0.extraction", si, ri)) + if res != nil { + return res + } + } + } + return checkExtractionAttributes(diff, "catch_all.0.actions.0.extraction") +} + +func checkExtractionAttributes(diff *schema.ResourceDiff, loc string) error { + num := diff.Get(fmt.Sprintf("%s.#", loc)).(int) + for i := 0; i < num; i++ { + prefix := fmt.Sprintf("%s.%d", loc, i) + r := diff.Get(fmt.Sprintf("%s.regex", prefix)).(string) + t := diff.Get(fmt.Sprintf("%s.template", prefix)).(string) + + if r == "" && t == "" { + return fmt.Errorf("Invalid configuration in %s: regex and template cannot both be null", prefix) + } + if r != "" && t != "" { + return fmt.Errorf("Invalid configuration in %s: regex and template cannot both have values", prefix) + } + + s := diff.Get(fmt.Sprintf("%s.source", prefix)).(string) + if r != "" && s == "" { + return fmt.Errorf("Invalid configuration in %s: source can't be blank", prefix) + } + } + return nil +} + +func expandEventOrchestrationPathConditions(v interface{}) []*pagerduty.EventOrchestrationPathRuleCondition { + conditions := []*pagerduty.EventOrchestrationPathRuleCondition{} + + for _, cond := range v.([]interface{}) { + c := cond.(map[string]interface{}) + + cx := &pagerduty.EventOrchestrationPathRuleCondition{ + Expression: c["expression"].(string), + } + + conditions = append(conditions, cx) + } + + return conditions +} + +func flattenEventOrchestrationPathConditions(conditions []*pagerduty.EventOrchestrationPathRuleCondition) []interface{} { + var flattendConditions []interface{} + + for _, condition := range conditions { + flattendCondition := map[string]interface{}{ + "expression": condition.Expression, + } + flattendConditions = append(flattendConditions, flattendCondition) + } + + return flattendConditions +} + +func expandEventOrchestrationPathVariables(v interface{}) []*pagerduty.EventOrchestrationPathActionVariables { + res := []*pagerduty.EventOrchestrationPathActionVariables{} + + for _, er := range v.([]interface{}) { + rer := er.(map[string]interface{}) + + av := &pagerduty.EventOrchestrationPathActionVariables{ + Name: rer["name"].(string), + Path: rer["path"].(string), + Type: rer["type"].(string), + Value: rer["value"].(string), + } + + res = append(res, av) + } + + return res +} + +func flattenEventOrchestrationPathVariables(v []*pagerduty.EventOrchestrationPathActionVariables) []interface{} { + var res []interface{} + + for _, s := range v { + fv := map[string]interface{}{ + "name": s.Name, + "path": s.Path, + "type": s.Type, + "value": s.Value, + } + res = append(res, fv) + } + return res +} + +func expandEventOrchestrationPathExtractions(v interface{}) []*pagerduty.EventOrchestrationPathActionExtractions { + res := []*pagerduty.EventOrchestrationPathActionExtractions{} + + for _, eai := range v.([]interface{}) { + ea := eai.(map[string]interface{}) + ext := &pagerduty.EventOrchestrationPathActionExtractions{ + Target: ea["target"].(string), + Regex: ea["regex"].(string), + Template: ea["template"].(string), + Source: ea["source"].(string), + } + res = append(res, ext) + } + return res +} + +func flattenEventOrchestrationPathExtractions(e []*pagerduty.EventOrchestrationPathActionExtractions) []interface{} { + var res []interface{} + + for _, s := range e { + e := map[string]interface{}{ + "target": s.Target, + "regex": s.Regex, + "template": s.Template, + "source": s.Source, + } + res = append(res, e) + } + return res +} diff --git a/pagerduty/import_pagerduty_event_orchestration_path_router_test.go b/pagerduty/import_pagerduty_event_orchestration_path_router_test.go new file mode 100644 index 000000000..976e80057 --- /dev/null +++ b/pagerduty/import_pagerduty_event_orchestration_path_router_test.go @@ -0,0 +1,38 @@ +package pagerduty + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccPagerDutyEventOrchestrationPathRouter_import(t *testing.T) { + team := fmt.Sprintf("tf-name-%s", acctest.RandString(5)) + escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) + service := fmt.Sprintf("tf-%s", acctest.RandString(5)) + orchestration := fmt.Sprintf("tf-orchestration-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckPagerDutyEventOrchestrationRouterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckPagerDutyEventOrchestrationRouterConfigWithMultipleRules(team, escalationPolicy, service, orchestration), + }, + { + ResourceName: "pagerduty_event_orchestration_router.router", + ImportStateIdFunc: testAccCheckPagerDutyEventOrchestrationPathRouterID, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckPagerDutyEventOrchestrationPathRouterID(s *terraform.State) (string, error) { + return s.RootModule().Resources["pagerduty_event_orchestration.orch"].Primary.ID, nil +} diff --git a/pagerduty/import_pagerduty_event_orchestration_path_service_test.go b/pagerduty/import_pagerduty_event_orchestration_path_service_test.go new file mode 100644 index 000000000..579d2c957 --- /dev/null +++ b/pagerduty/import_pagerduty_event_orchestration_path_service_test.go @@ -0,0 +1,36 @@ +package pagerduty + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccPagerDutyEventOrchestrationPathService_import(t *testing.T) { + escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) + service := fmt.Sprintf("tf-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckPagerDutyEventOrchestrationServicePathDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckPagerDutyEventOrchestrationPathServiceAllActionsConfig(escalationPolicy, service), + }, + { + ResourceName: "pagerduty_event_orchestration_service.serviceA", + ImportStateIdFunc: testAccCheckPagerDutyEventOrchestrationPathServiceID, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckPagerDutyEventOrchestrationPathServiceID(s *terraform.State) (string, error) { + return s.RootModule().Resources["pagerduty_service.bar"].Primary.ID, nil +} diff --git a/pagerduty/import_pagerduty_event_orchestration_path_unrouted_test.go b/pagerduty/import_pagerduty_event_orchestration_path_unrouted_test.go new file mode 100644 index 000000000..9ab539ba4 --- /dev/null +++ b/pagerduty/import_pagerduty_event_orchestration_path_unrouted_test.go @@ -0,0 +1,38 @@ +package pagerduty + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccPagerDutyEventOrchestrationPathUnrouted_import(t *testing.T) { + team := fmt.Sprintf("tf-name-%s", acctest.RandString(5)) + escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) + service := fmt.Sprintf("tf-%s", acctest.RandString(5)) + orchestration := fmt.Sprintf("tf-orchestration-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckPagerDutyEventOrchestrationPathUnroutedDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckPagerDutyEventOrchestrationPathUnroutedWithAllConfig(team, escalationPolicy, service, orchestration), + }, + { + ResourceName: "pagerduty_event_orchestration_unrouted.unrouted", + ImportStateIdFunc: testAccCheckPagerDutyEventOrchestrationPathUnroutedID, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckPagerDutyEventOrchestrationPathUnroutedID(s *terraform.State) (string, error) { + return s.RootModule().Resources["pagerduty_event_orchestration.orch"].Primary.ID, nil +} diff --git a/pagerduty/import_pagerduty_event_orchestration_test.go b/pagerduty/import_pagerduty_event_orchestration_test.go new file mode 100644 index 000000000..d6b7c8d14 --- /dev/null +++ b/pagerduty/import_pagerduty_event_orchestration_test.go @@ -0,0 +1,53 @@ +package pagerduty + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccPagerDutyEventOrchestration_import(t *testing.T) { + name := fmt.Sprintf("tf-name-%s", acctest.RandString(5)) + description := fmt.Sprintf("tf-description-%s", acctest.RandString(5)) + team1 := fmt.Sprintf("tf-team1-%s", acctest.RandString(5)) + team2 := fmt.Sprintf("tf-team2-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckPagerDutyEventOrchestrationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckPagerDutyEventOrchestrationConfig(name, description, team1, team2), + }, + { + ResourceName: "pagerduty_event_orchestration.foo", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccPagerDutyEventOrchestrationNameOnly_import(t *testing.T) { + name := fmt.Sprintf("tf-name-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckPagerDutyEventOrchestrationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckPagerDutyEventOrchestrationConfigNameOnly(name), + }, + + { + ResourceName: "pagerduty_event_orchestration.foo", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} diff --git a/pagerduty/provider.go b/pagerduty/provider.go index 4af8626dc..92e478397 100644 --- a/pagerduty/provider.go +++ b/pagerduty/provider.go @@ -59,34 +59,39 @@ func Provider() *schema.Provider { "pagerduty_priority": dataSourcePagerDutyPriority(), "pagerduty_ruleset": dataSourcePagerDutyRuleset(), "pagerduty_tag": dataSourcePagerDutyTag(), + "pagerduty_event_orchestration": dataSourcePagerDutyEventOrchestration(), }, ResourcesMap: map[string]*schema.Resource{ - "pagerduty_addon": resourcePagerDutyAddon(), - "pagerduty_escalation_policy": resourcePagerDutyEscalationPolicy(), - "pagerduty_maintenance_window": resourcePagerDutyMaintenanceWindow(), - "pagerduty_schedule": resourcePagerDutySchedule(), - "pagerduty_service": resourcePagerDutyService(), - "pagerduty_service_integration": resourcePagerDutyServiceIntegration(), - "pagerduty_team": resourcePagerDutyTeam(), - "pagerduty_team_membership": resourcePagerDutyTeamMembership(), - "pagerduty_user": resourcePagerDutyUser(), - "pagerduty_user_contact_method": resourcePagerDutyUserContactMethod(), - "pagerduty_user_notification_rule": resourcePagerDutyUserNotificationRule(), - "pagerduty_extension": resourcePagerDutyExtension(), - "pagerduty_extension_servicenow": resourcePagerDutyExtensionServiceNow(), - "pagerduty_event_rule": resourcePagerDutyEventRule(), - "pagerduty_ruleset": resourcePagerDutyRuleset(), - "pagerduty_ruleset_rule": resourcePagerDutyRulesetRule(), - "pagerduty_business_service": resourcePagerDutyBusinessService(), - "pagerduty_service_dependency": resourcePagerDutyServiceDependency(), - "pagerduty_response_play": resourcePagerDutyResponsePlay(), - "pagerduty_tag": resourcePagerDutyTag(), - "pagerduty_tag_assignment": resourcePagerDutyTagAssignment(), - "pagerduty_service_event_rule": resourcePagerDutyServiceEventRule(), - "pagerduty_slack_connection": resourcePagerDutySlackConnection(), - "pagerduty_business_service_subscriber": resourcePagerDutyBusinessServiceSubscriber(), - "pagerduty_webhook_subscription": resourcePagerDutyWebhookSubscription(), + "pagerduty_addon": resourcePagerDutyAddon(), + "pagerduty_escalation_policy": resourcePagerDutyEscalationPolicy(), + "pagerduty_maintenance_window": resourcePagerDutyMaintenanceWindow(), + "pagerduty_schedule": resourcePagerDutySchedule(), + "pagerduty_service": resourcePagerDutyService(), + "pagerduty_service_integration": resourcePagerDutyServiceIntegration(), + "pagerduty_team": resourcePagerDutyTeam(), + "pagerduty_team_membership": resourcePagerDutyTeamMembership(), + "pagerduty_user": resourcePagerDutyUser(), + "pagerduty_user_contact_method": resourcePagerDutyUserContactMethod(), + "pagerduty_user_notification_rule": resourcePagerDutyUserNotificationRule(), + "pagerduty_extension": resourcePagerDutyExtension(), + "pagerduty_extension_servicenow": resourcePagerDutyExtensionServiceNow(), + "pagerduty_event_rule": resourcePagerDutyEventRule(), + "pagerduty_ruleset": resourcePagerDutyRuleset(), + "pagerduty_ruleset_rule": resourcePagerDutyRulesetRule(), + "pagerduty_business_service": resourcePagerDutyBusinessService(), + "pagerduty_service_dependency": resourcePagerDutyServiceDependency(), + "pagerduty_response_play": resourcePagerDutyResponsePlay(), + "pagerduty_tag": resourcePagerDutyTag(), + "pagerduty_tag_assignment": resourcePagerDutyTagAssignment(), + "pagerduty_service_event_rule": resourcePagerDutyServiceEventRule(), + "pagerduty_slack_connection": resourcePagerDutySlackConnection(), + "pagerduty_business_service_subscriber": resourcePagerDutyBusinessServiceSubscriber(), + "pagerduty_webhook_subscription": resourcePagerDutyWebhookSubscription(), + "pagerduty_event_orchestration": resourcePagerDutyEventOrchestration(), + "pagerduty_event_orchestration_router": resourcePagerDutyEventOrchestrationPathRouter(), + "pagerduty_event_orchestration_unrouted": resourcePagerDutyEventOrchestrationPathUnrouted(), + "pagerduty_event_orchestration_service": resourcePagerDutyEventOrchestrationPathService(), }, } diff --git a/pagerduty/resource_pagerduty_event_orchestration.go b/pagerduty/resource_pagerduty_event_orchestration.go new file mode 100644 index 000000000..8e876c1cb --- /dev/null +++ b/pagerduty/resource_pagerduty_event_orchestration.go @@ -0,0 +1,240 @@ +package pagerduty + +import ( + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/heimweh/go-pagerduty/pagerduty" +) + +func resourcePagerDutyEventOrchestration() *schema.Resource { + return &schema.Resource{ + Create: resourcePagerDutyEventOrchestrationCreate, + Read: resourcePagerDutyEventOrchestrationRead, + Update: resourcePagerDutyEventOrchestrationUpdate, + Delete: resourcePagerDutyEventOrchestrationDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "description": { + Type: schema.TypeString, + Optional: true, + }, + "team": { + Type: schema.TypeString, + Optional: true, + }, + "routes": { + Type: schema.TypeInt, + Computed: true, + }, + "integration": { + Type: schema.TypeList, + Computed: true, + Optional: true, // Tests keep failing if "Optional: true" is not provided + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + "parameters": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "routing_key": { + Type: schema.TypeString, + Computed: true, + }, + "type": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func buildEventOrchestrationStruct(d *schema.ResourceData) *pagerduty.EventOrchestration { + orchestration := &pagerduty.EventOrchestration{ + Name: d.Get("name").(string), + } + + if attr, ok := d.GetOk("description"); ok { + orchestration.Description = attr.(string) + } + + if attr, ok := d.GetOk("team"); ok { + orchestration.Team = &pagerduty.EventOrchestrationObject{ + ID: stringTypeToStringPtr(attr.(string)), + } + } else { + var tId *string + orchestration.Team = &pagerduty.EventOrchestrationObject{ + ID: tId, + } + } + + return orchestration +} + +func resourcePagerDutyEventOrchestrationCreate(d *schema.ResourceData, meta interface{}) error { + client, err := meta.(*Config).Client() + if err != nil { + return err + } + + payload := buildEventOrchestrationStruct(d) + var orchestration *pagerduty.EventOrchestration + + log.Printf("[INFO] Creating PagerDuty Event Orchestration: %s", payload.Name) + + retryErr := resource.Retry(10*time.Second, func() *resource.RetryError { + if orch, _, err := client.EventOrchestrations.Create(payload); err != nil { + if isErrCode(err, 400) || isErrCode(err, 429) { + return resource.RetryableError(err) + } + + return resource.NonRetryableError(err) + } else if orch != nil { + d.SetId(orch.ID) + orchestration = orch + } + return nil + }) + + if retryErr != nil { + return retryErr + } + + setEventOrchestrationProps(d, orchestration) + + return nil +} + +func resourcePagerDutyEventOrchestrationRead(d *schema.ResourceData, meta interface{}) error { + client, err := meta.(*Config).Client() + if err != nil { + return err + } + + return resource.Retry(2*time.Minute, func() *resource.RetryError { + orch, _, err := client.EventOrchestrations.Get(d.Id()) + if err != nil { + errResp := handleNotFoundError(err, d) + if errResp != nil { + time.Sleep(2 * time.Second) + return resource.RetryableError(errResp) + } + + return nil + } + + setEventOrchestrationProps(d, orch) + + return nil + }) +} + +func resourcePagerDutyEventOrchestrationUpdate(d *schema.ResourceData, meta interface{}) error { + client, err := meta.(*Config).Client() + if err != nil { + return err + } + + orchestration := buildEventOrchestrationStruct(d) + + log.Printf("[INFO] Updating PagerDuty Event Orchestration: %s", d.Id()) + + retryErr := resource.Retry(10*time.Second, func() *resource.RetryError { + if _, _, err := client.EventOrchestrations.Update(d.Id(), orchestration); err != nil { + if isErrCode(err, 400) || isErrCode(err, 429) { + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + + return nil + }) + + if retryErr != nil { + return retryErr + } + + return nil +} + +func resourcePagerDutyEventOrchestrationDelete(d *schema.ResourceData, meta interface{}) error { + client, err := meta.(*Config).Client() + if err != nil { + return err + } + + log.Printf("[INFO] Deleting PagerDuty Event Orchestration: %s", d.Id()) + if _, err := client.EventOrchestrations.Delete(d.Id()); err != nil { + return err + } + + d.SetId("") + + return nil +} + +func flattenEventOrchestrationTeam(v *pagerduty.EventOrchestrationObject) []interface{} { + team := map[string]interface{}{ + "id": v.ID, + } + + return []interface{}{team} +} + +func flattenEventOrchestrationIntegrations(eoi []*pagerduty.EventOrchestrationIntegration) []interface{} { + var result []interface{} + + for _, i := range eoi { + integration := map[string]interface{}{ + "id": i.ID, + "parameters": flattenEventOrchestrationIntegrationParameters(i.Parameters), + } + result = append(result, integration) + } + return result +} + +func flattenEventOrchestrationIntegrationParameters(p *pagerduty.EventOrchestrationIntegrationParameters) []interface{} { + result := map[string]interface{}{ + "routing_key": p.RoutingKey, + "type": p.Type, + } + + return []interface{}{result} +} + +func setEventOrchestrationProps(d *schema.ResourceData, o *pagerduty.EventOrchestration) error { + d.Set("name", o.Name) + d.Set("description", o.Description) + d.Set("routes", o.Routes) + + if o.Team != nil { + d.Set("team", o.Team.ID) + } + + if len(o.Integrations) > 0 { + d.Set("integration", flattenEventOrchestrationIntegrations(o.Integrations)) + } + + return nil +} diff --git a/pagerduty/resource_pagerduty_event_orchestration_path_router.go b/pagerduty/resource_pagerduty_event_orchestration_path_router.go new file mode 100644 index 000000000..d535e14a2 --- /dev/null +++ b/pagerduty/resource_pagerduty_event_orchestration_path_router.go @@ -0,0 +1,335 @@ +package pagerduty + +import ( + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/heimweh/go-pagerduty/pagerduty" +) + +func resourcePagerDutyEventOrchestrationPathRouter() *schema.Resource { + return &schema.Resource{ + Read: resourcePagerDutyEventOrchestrationPathRouterRead, + Create: resourcePagerDutyEventOrchestrationPathRouterCreate, + Update: resourcePagerDutyEventOrchestrationPathRouterUpdate, + Delete: resourcePagerDutyEventOrchestrationPathRouterDelete, + Importer: &schema.ResourceImporter{ + State: resourcePagerDutyEventOrchestrationPathRouterImport, + }, + Schema: map[string]*schema.Schema{ + "event_orchestration": { + Type: schema.TypeString, + Required: true, + }, + "set": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, // Router can only have 'start' set + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Required: true, + }, + "rule": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + "label": { + Type: schema.TypeString, + Optional: true, + }, + "condition": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: eventOrchestrationPathConditionsSchema, + }, + }, + "actions": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, //there can only be one action for router + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "route_to": { + Type: schema.TypeString, + Required: true, + ValidateFunc: func(v interface{}, key string) (warns []string, errs []error) { + value := v.(string) + if value == "unrouted" { + errs = append(errs, fmt.Errorf("route_to within a set's rule has to be a Service ID. Got: %q", v)) + } + return + }, + }, + }, + }, + }, + "disabled": { + Type: schema.TypeBool, + Optional: true, + }, + }, + }, + }, + }, + }, + }, + "catch_all": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "actions": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "route_to": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func resourcePagerDutyEventOrchestrationPathRouterRead(d *schema.ResourceData, meta interface{}) error { + client, err := meta.(*Config).Client() + if err != nil { + return err + } + + return resource.Retry(2*time.Minute, func() *resource.RetryError { + log.Printf("[INFO] Reading PagerDuty Event Orchestration Path of type %s for orchestration: %s", "router", d.Id()) + + if routerPath, _, err := client.EventOrchestrationPaths.Get(d.Id(), "router"); err != nil { + time.Sleep(2 * time.Second) + return resource.RetryableError(err) + } else if routerPath != nil { + d.Set("event_orchestration", routerPath.Parent.ID) + + if routerPath.Sets != nil { + d.Set("set", flattenSets(routerPath.Sets)) + } + + if routerPath.CatchAll != nil { + d.Set("catch_all", flattenCatchAll(routerPath.CatchAll)) + } + } + return nil + }) + +} + +// EventOrchestrationPath cannot be created, use update to add / edit / remove rules and sets +func resourcePagerDutyEventOrchestrationPathRouterCreate(d *schema.ResourceData, meta interface{}) error { + return resourcePagerDutyEventOrchestrationPathRouterUpdate(d, meta) +} + +func resourcePagerDutyEventOrchestrationPathRouterDelete(d *schema.ResourceData, meta interface{}) error { + d.SetId("") + return nil +} + +func resourcePagerDutyEventOrchestrationPathRouterUpdate(d *schema.ResourceData, meta interface{}) error { + client, err := meta.(*Config).Client() + if err != nil { + return err + } + + updatePath := buildRouterPathStructForUpdate(d) + + log.Printf("[INFO] Updating PagerDuty Event Orchestration Path of type %s for orchestration: %s", "router", updatePath.Parent.ID) + + return performRouterPathUpdate(d, updatePath, client) +} + +func performRouterPathUpdate(d *schema.ResourceData, routerPath *pagerduty.EventOrchestrationPath, client *pagerduty.Client) error { + retryErr := resource.Retry(30*time.Second, func() *resource.RetryError { + updatedPath, _, err := client.EventOrchestrationPaths.Update(routerPath.Parent.ID, "router", routerPath) + if err != nil { + return resource.RetryableError(err) + } + if updatedPath == nil { + return resource.NonRetryableError(fmt.Errorf("No Event Orchestration Router found.")) + } + d.SetId(routerPath.Parent.ID) + d.Set("event_orchestration", routerPath.Parent.ID) + + if routerPath.Sets != nil { + d.Set("set", flattenSets(routerPath.Sets)) + } + if updatedPath.CatchAll != nil { + d.Set("catch_all", flattenCatchAll(updatedPath.CatchAll)) + } + return nil + }) + if retryErr != nil { + time.Sleep(2 * time.Second) + return retryErr + } + return nil +} + +func buildRouterPathStructForUpdate(d *schema.ResourceData) *pagerduty.EventOrchestrationPath { + + orchPath := &pagerduty.EventOrchestrationPath{ + Parent: &pagerduty.EventOrchestrationPathReference{ + ID: d.Get("event_orchestration").(string), + }, + } + + if attr, ok := d.GetOk("set"); ok { + orchPath.Sets = expandSets(attr) + } + + if attr, ok := d.GetOk("catch_all"); ok { + orchPath.CatchAll = expandCatchAll(attr) + } + + return orchPath +} + +func expandSets(v interface{}) []*pagerduty.EventOrchestrationPathSet { + var sets []*pagerduty.EventOrchestrationPathSet + + for _, set := range v.([]interface{}) { + s := set.(map[string]interface{}) + + orchPathSet := &pagerduty.EventOrchestrationPathSet{ + ID: s["id"].(string), + Rules: expandRules(s["rule"]), + } + + sets = append(sets, orchPathSet) + } + + return sets +} + +func expandRules(v interface{}) []*pagerduty.EventOrchestrationPathRule { + items := v.([]interface{}) + rules := []*pagerduty.EventOrchestrationPathRule{} + + for _, rule := range items { + r := rule.(map[string]interface{}) + + ruleInSet := &pagerduty.EventOrchestrationPathRule{ + ID: r["id"].(string), + Label: r["label"].(string), + Disabled: r["disabled"].(bool), + Conditions: expandEventOrchestrationPathConditions(r["condition"]), + Actions: expandRouterActions(r["actions"]), + } + + rules = append(rules, ruleInSet) + } + return rules +} + +func expandRouterActions(v interface{}) *pagerduty.EventOrchestrationPathRuleActions { + var actions = new(pagerduty.EventOrchestrationPathRuleActions) + for _, ai := range v.([]interface{}) { + am := ai.(map[string]interface{}) + actions.RouteTo = am["route_to"].(string) + } + + return actions +} + +func expandCatchAll(v interface{}) *pagerduty.EventOrchestrationPathCatchAll { + var catchAll = new(pagerduty.EventOrchestrationPathCatchAll) + + for _, ca := range v.([]interface{}) { + am := ca.(map[string]interface{}) + catchAll.Actions = expandRouterActions(am["actions"]) + } + + return catchAll +} + +func flattenSets(orchPathSets []*pagerduty.EventOrchestrationPathSet) []interface{} { + var flattenedSets []interface{} + for _, set := range orchPathSets { + flattenedSet := map[string]interface{}{ + "id": set.ID, + "rule": flattenRules(set.Rules), + } + flattenedSets = append(flattenedSets, flattenedSet) + } + return flattenedSets +} + +func flattenRules(rules []*pagerduty.EventOrchestrationPathRule) []interface{} { + var flattenedRules []interface{} + + for _, rule := range rules { + flattenedRule := map[string]interface{}{ + "id": rule.ID, + "label": rule.Label, + "disabled": rule.Disabled, + "condition": flattenEventOrchestrationPathConditions(rule.Conditions), + "actions": flattenRouterActions(rule.Actions), + } + flattenedRules = append(flattenedRules, flattenedRule) + } + + return flattenedRules +} + +func flattenRouterActions(actions *pagerduty.EventOrchestrationPathRuleActions) []map[string]interface{} { + var actionsMap []map[string]interface{} + + am := make(map[string]interface{}) + am["route_to"] = actions.RouteTo + actionsMap = append(actionsMap, am) + return actionsMap +} + +func flattenCatchAll(catchAll *pagerduty.EventOrchestrationPathCatchAll) []map[string]interface{} { + var caMap []map[string]interface{} + + c := make(map[string]interface{}) + + c["actions"] = flattenRouterActions(catchAll.Actions) + caMap = append(caMap, c) + + return caMap +} + +func resourcePagerDutyEventOrchestrationPathRouterImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + client, err := meta.(*Config).Client() + if err != nil { + return []*schema.ResourceData{}, err + } + // given an orchestration ID import the router orchestration path + orchestrationID := d.Id() + pathType := "router" + _, _, err = client.EventOrchestrationPaths.Get(orchestrationID, pathType) + + if err != nil { + return []*schema.ResourceData{}, err + } + + d.SetId(orchestrationID) + d.Set("event_orchestration", orchestrationID) + + return []*schema.ResourceData{d}, nil +} diff --git a/pagerduty/resource_pagerduty_event_orchestration_path_router_test.go b/pagerduty/resource_pagerduty_event_orchestration_path_router_test.go new file mode 100644 index 000000000..3e03a1428 --- /dev/null +++ b/pagerduty/resource_pagerduty_event_orchestration_path_router_test.go @@ -0,0 +1,428 @@ +package pagerduty + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func init() { + resource.AddTestSweepers("pagerduty_event_orchestration_router", &resource.Sweeper{ + Name: "pagerduty_event_orchestration_router", + F: testSweepEventOrchestration, + }) +} + +func TestAccPagerDutyEventOrchestrationPathRouter_Basic(t *testing.T) { + team := fmt.Sprintf("tf-name-%s", acctest.RandString(5)) + escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) + service := fmt.Sprintf("tf-%s", acctest.RandString(5)) + orchestration := fmt.Sprintf("tf-orchestration-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckPagerDutyEventOrchestrationRouterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckPagerDutyEventOrchestrationRouterConfigNoRules(team, escalationPolicy, service, orchestration), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationRouterExists("pagerduty_event_orchestration_router.router"), + testAccCheckPagerDutyEventOrchestrationRouterPathRouteToMatch( + "pagerduty_event_orchestration_router.router", "unrouted", true), //test for catch_all route_to prop, by default it should be unrouted + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_router.router", "set.0.rule.#", "0"), + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationRouterConfig(team, escalationPolicy, service, orchestration), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationRouterExists("pagerduty_event_orchestration_router.router"), + testAccCheckPagerDutyEventOrchestrationRouterPathRouteToMatch( + "pagerduty_event_orchestration_router.router", "pagerduty_service.bar", false), // test for rule action route_to + testAccCheckPagerDutyEventOrchestrationRouterPathRouteToMatch( + "pagerduty_event_orchestration_router.router", "unrouted", true), //test for catch_all route_to prop, by default it should be unrouted + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationRouterConfigWithConditions(team, escalationPolicy, service, orchestration), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationRouterExists("pagerduty_event_orchestration_router.router"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_router.router", "set.0.rule.0.condition.0.expression", "event.summary matches part 'database'"), + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationRouterConfigWithMultipleRules(team, escalationPolicy, service, orchestration), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationRouterExists("pagerduty_event_orchestration_router.router"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_router.router", "set.0.rule.#", "2"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_router.router", "set.0.rule.0.condition.0.expression", "event.summary matches part 'database'"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_router.router", "set.0.rule.1.condition.0.expression", "event.severity matches part 'critical'"), + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationRouterConfigWithCatchAllToService(team, escalationPolicy, service, orchestration), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationRouterExists("pagerduty_event_orchestration_router.router"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_router.router", "set.0.rule.#", "1"), + testAccCheckPagerDutyEventOrchestrationRouterPathRouteToMatch( + "pagerduty_event_orchestration_router.router", "pagerduty_service.bar", true), //test for catch_all routing to service if provided + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationRouterConfigNoConditions(team, escalationPolicy, service, orchestration), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationRouterExists("pagerduty_event_orchestration_router.router"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_router.router", "set.0.rule.#", "1"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_router.router", "set.0.rule.0.condition.#", "0"), + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationRouterConfigDeleteAllRulesInSet(team, escalationPolicy, service, orchestration), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationRouterExists("pagerduty_event_orchestration_router.router"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_router.router", "set.0.rule.#", "0"), + testAccCheckPagerDutyEventOrchestrationRouterPathRouteToMatch( + "pagerduty_event_orchestration_router.router", "pagerduty_service.bar", true), + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationRouterConfigDelete(team, escalationPolicy, service, orchestration), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationRouterNotExists("pagerduty_event_orchestration_router.router"), + ), + }, + }, + }) +} + +func testAccCheckPagerDutyEventOrchestrationRouterDestroy(s *terraform.State) error { + client, _ := testAccProvider.Meta().(*Config).Client() + for _, r := range s.RootModule().Resources { + if r.Type != "pagerduty_event_orchestration_path_router" { + continue + } + + orch, _ := s.RootModule().Resources["pagerduty_event_orchestration.orch"] + + if _, _, err := client.EventOrchestrationPaths.Get(orch.Primary.ID, "router"); err == nil { + return fmt.Errorf("Event Orchestration Path still exists") + } + } + return nil +} + +func testAccCheckPagerDutyEventOrchestrationRouterExists(rn string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[rn] + if !ok { + return fmt.Errorf("Not found: %s", rn) + } + if rs.Primary.ID == "" { + return fmt.Errorf("No Event Orchestration Router is set") + } + + orch, _ := s.RootModule().Resources["pagerduty_event_orchestration.orch"] + client, _ := testAccProvider.Meta().(*Config).Client() + _, _, err := client.EventOrchestrationPaths.Get(orch.Primary.ID, "router") + + if err != nil { + return fmt.Errorf("Orchestration Path type not found: %v for orchestration %v", "router", orch.Primary.ID) + } + + return nil + } +} + +func testAccCheckPagerDutyEventOrchestrationRouterNotExists(rn string) resource.TestCheckFunc { + return func(s *terraform.State) error { + _, ok := s.RootModule().Resources[rn] + if ok { + return fmt.Errorf("Event Orchestration Router Path is not deleted: %s", rn) + } + + return nil + } +} + +func createBaseConfig(t, ep, s, o string) string { + return fmt.Sprintf(` + resource "pagerduty_team" "foo" { + name = "%s" + } + + resource "pagerduty_user" "foo" { + name = "tf-user" + email = "user@pagerduty.com" + color = "green" + role = "user" + job_title = "foo" + description = "foo" + } + + resource "pagerduty_escalation_policy" "foo" { + name = "%s" + description = "bar" + num_loops = 2 + + rule { + escalation_delay_in_minutes = 10 + target { + type = "user_reference" + id = pagerduty_user.foo.id + } + } + } + + resource "pagerduty_service" "bar" { + name = "%s" + escalation_policy = pagerduty_escalation_policy.foo.id + + incident_urgency_rule { + type = "constant" + urgency = "high" + } + } + + resource "pagerduty_event_orchestration" "orch" { + name = "%s" + team = pagerduty_team.foo.id + } + `, t, ep, s, o) +} + +func testAccCheckPagerDutyEventOrchestrationRouterConfigNoRules(t, ep, s, o string) string { + return fmt.Sprintf("%s%s", createBaseConfig(t, ep, s, o), + `resource "pagerduty_event_orchestration_router" "router" { + event_orchestration = pagerduty_event_orchestration.orch.id + + catch_all { + actions { + route_to = "unrouted" + } + } + set { + id = "start" + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationRouterConfig(t, ep, s, o string) string { + return fmt.Sprintf("%s%s", createBaseConfig(t, ep, s, o), + `resource "pagerduty_event_orchestration_router" "router" { + event_orchestration = pagerduty_event_orchestration.orch.id + + catch_all { + actions { + route_to = "unrouted" + } + } + set { + id = "start" + rule { + disabled = false + label = "rule1 label" + actions { + route_to = pagerduty_service.bar.id + } + } + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationRouterConfigWithConditions(t, ep, s, o string) string { + return fmt.Sprintf("%s%s", createBaseConfig(t, ep, s, o), + `resource "pagerduty_event_orchestration_router" "router" { + event_orchestration = pagerduty_event_orchestration.orch.id + + catch_all { + actions { + route_to = "unrouted" + } + } + set { + id = "start" + rule { + disabled = false + label = "rule1 label" + actions { + route_to = pagerduty_service.bar.id + } + condition { + expression = "event.summary matches part 'database'" + } + } + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationRouterConfigWithMultipleRules(t, ep, s, o string) string { + return fmt.Sprintf( + "%s%s", createBaseConfig(t, ep, s, o), + `resource "pagerduty_service" "bar2" { + name = "tf-barService2" + escalation_policy = pagerduty_escalation_policy.foo.id + + incident_urgency_rule { + type = "constant" + urgency = "high" + } + } + + resource "pagerduty_event_orchestration_router" "router" { + event_orchestration = pagerduty_event_orchestration.orch.id + + catch_all { + actions { + route_to = "unrouted" + } + } + set { + id = "start" + rule { + disabled = false + label = "rule1 label" + actions { + route_to = pagerduty_service.bar.id + } + condition { + expression = "event.summary matches part 'database'" + } + condition { + expression = "event.severity matches part 'critical'" + } + } + + rule { + disabled = false + label = "rule2 label" + actions { + route_to = pagerduty_service.bar2.id + } + condition { + expression = "event.severity matches part 'critical'" + } + } + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationRouterConfigNoConditions(t, ep, s, o string) string { + return fmt.Sprintf("%s%s", createBaseConfig(t, ep, s, o), + `resource "pagerduty_event_orchestration_router" "router" { + event_orchestration = pagerduty_event_orchestration.orch.id + + catch_all { + actions { + route_to = pagerduty_service.bar.id + } + } + set { + id = "start" + rule { + disabled = false + label = "rule1 label" + actions { + route_to = pagerduty_service.bar.id + } + } + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationRouterConfigWithCatchAllToService(t, ep, s, o string) string { + return fmt.Sprintf("%s%s", createBaseConfig(t, ep, s, o), + `resource "pagerduty_event_orchestration_router" "router" { + event_orchestration = pagerduty_event_orchestration.orch.id + + catch_all { + actions { + route_to = pagerduty_service.bar.id + } + } + set { + id = "start" + rule { + disabled = false + label = "rule1 label" + actions { + route_to = pagerduty_service.bar.id + } + condition { + expression = "event.severity matches part 'critical'" + } + } + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationRouterConfigDeleteAllRulesInSet(t, ep, s, o string) string { + return fmt.Sprintf("%s%s", createBaseConfig(t, ep, s, o), + `resource "pagerduty_event_orchestration_router" "router" { + event_orchestration = pagerduty_event_orchestration.orch.id + + catch_all { + actions { + route_to = pagerduty_service.bar.id + } + } + set { + id = "start" + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationRouterConfigDelete(t, ep, s, o string) string { + return createBaseConfig(t, ep, s, o) +} + +func testAccCheckPagerDutyEventOrchestrationRouterPathRouteToMatch(router, service string, catchAll bool) resource.TestCheckFunc { + return func(s *terraform.State) error { + r, rOk := s.RootModule().Resources[router] + if !rOk { + return fmt.Errorf("Not found: %s", router) + } + + var rRouteToId = "" + if catchAll == true { + rRouteToId = r.Primary.Attributes["catch_all.0.actions.0.route_to"] + } else { + rRouteToId = r.Primary.Attributes["set.0.rule.0.actions.0.route_to"] + } + + var sId = "" + if service == "unrouted" { + sId = "unrouted" + } else { + svc, sOk := s.RootModule().Resources[service] + if !sOk { + return fmt.Errorf("Not found: %s", service) + } + sId = svc.Primary.Attributes["id"] + } + + if rRouteToId != sId { + return fmt.Errorf("Event Orchestration Router Route to Service ID (%v) not matching provided service ID: %v", rRouteToId, sId) + } + + return nil + } +} diff --git a/pagerduty/resource_pagerduty_event_orchestration_path_service.go b/pagerduty/resource_pagerduty_event_orchestration_path_service.go new file mode 100644 index 000000000..a956bb8f4 --- /dev/null +++ b/pagerduty/resource_pagerduty_event_orchestration_path_service.go @@ -0,0 +1,555 @@ +package pagerduty + +import ( + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/heimweh/go-pagerduty/pagerduty" +) + +var eventOrchestrationAutomationActionObjectSchema = map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Required: true, + }, + "value": { + Type: schema.TypeString, + Required: true, + }, +} + +var eventOrchestrationPathServiceCatchAllActionsSchema = map[string]*schema.Schema{ + "suppress": { + Type: schema.TypeBool, + Optional: true, + }, + "suspend": { + Type: schema.TypeInt, + Optional: true, + }, + "priority": { + Type: schema.TypeString, + Optional: true, + }, + "annotate": { + Type: schema.TypeString, + Optional: true, + }, + "pagerduty_automation_action": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "action_id": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "automation_action": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "url": { + Type: schema.TypeString, + Required: true, + }, + "auto_send": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "header": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: eventOrchestrationAutomationActionObjectSchema, + }, + }, + "parameter": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: eventOrchestrationAutomationActionObjectSchema, + }, + }, + }, + }, + }, + "severity": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateEventOrchestrationPathSeverity(), + }, + "event_action": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateEventOrchestrationPathEventAction(), + }, + "variable": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: eventOrchestrationPathVariablesSchema, + }, + }, + "extraction": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: eventOrchestrationPathExtractionsSchema, + }, + }, +} + +var eventOrchestrationPathServiceRuleActionsSchema = buildEventOrchestrationPathServiceRuleActionsSchema() + +func buildEventOrchestrationPathServiceRuleActionsSchema() map[string]*schema.Schema { + a := eventOrchestrationPathServiceCatchAllActionsSchema + a["route_to"] = &schema.Schema{ + Type: schema.TypeString, + Optional: true, + } + + return a +} + +func resourcePagerDutyEventOrchestrationPathService() *schema.Resource { + return &schema.Resource{ + Read: resourcePagerDutyEventOrchestrationPathServiceRead, + Create: resourcePagerDutyEventOrchestrationPathServiceCreate, + Update: resourcePagerDutyEventOrchestrationPathServiceUpdate, + Delete: resourcePagerDutyEventOrchestrationPathServiceDelete, + Importer: &schema.ResourceImporter{ + State: resourcePagerDutyEventOrchestrationPathServiceImport, + }, + CustomizeDiff: checkExtractions, + Schema: map[string]*schema.Schema{ + "service": { + Type: schema.TypeString, + Required: true, + }, + "set": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Required: true, + }, + "rule": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + "label": { + Type: schema.TypeString, + Optional: true, + }, + "condition": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: eventOrchestrationPathConditionsSchema, + }, + }, + "actions": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: eventOrchestrationPathServiceRuleActionsSchema, + }, + }, + "disabled": { + Type: schema.TypeBool, + Optional: true, + }, + }, + }, + }, + }, + }, + }, + "catch_all": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "actions": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: eventOrchestrationPathServiceRuleActionsSchema, + }, + }, + }, + }, + }, + }, + } +} + +func resourcePagerDutyEventOrchestrationPathServiceRead(d *schema.ResourceData, meta interface{}) error { + client, err := meta.(*Config).Client() + if err != nil { + return err + } + + return resource.Retry(2*time.Minute, func() *resource.RetryError { + id := d.Id() + t := "service" + log.Printf("[INFO] Reading PagerDuty Event Orchestration Path of type %s for orchestration: %s", t, id) + + if path, _, err := client.EventOrchestrationPaths.Get(d.Id(), t); err != nil { + time.Sleep(2 * time.Second) + return resource.RetryableError(err) + } else if path != nil { + setEventOrchestrationPathServiceProps(d, path) + } + return nil + }) + +} + +func resourcePagerDutyEventOrchestrationPathServiceCreate(d *schema.ResourceData, meta interface{}) error { + return resourcePagerDutyEventOrchestrationPathServiceUpdate(d, meta) +} + +func resourcePagerDutyEventOrchestrationPathServiceUpdate(d *schema.ResourceData, meta interface{}) error { + client, err := meta.(*Config).Client() + if err != nil { + return err + } + + payload := buildServicePathStruct(d) + var servicePath *pagerduty.EventOrchestrationPath + + log.Printf("[INFO] Creating PagerDuty Event Orchestration Service Path: %s", payload.Parent.ID) + + retryErr := resource.Retry(30*time.Second, func() *resource.RetryError { + if path, _, err := client.EventOrchestrationPaths.Update(payload.Parent.ID, "service", payload); err != nil { + return resource.RetryableError(err) + } else if path != nil { + d.SetId(path.Parent.ID) + servicePath = path + } + return nil + }) + + if retryErr != nil { + return retryErr + } + + setEventOrchestrationPathServiceProps(d, servicePath) + + return nil +} + +func resourcePagerDutyEventOrchestrationPathServiceDelete(d *schema.ResourceData, meta interface{}) error { + d.SetId("") + return nil +} + +func resourcePagerDutyEventOrchestrationPathServiceImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + client, err := meta.(*Config).Client() + if err != nil { + return []*schema.ResourceData{}, err + } + + id := d.Id() + + _, _, pErr := client.EventOrchestrationPaths.Get(id, "service") + if pErr != nil { + return []*schema.ResourceData{}, pErr + } + + d.SetId(id) + d.Set("service", id) + + return []*schema.ResourceData{d}, nil +} + +func buildServicePathStruct(d *schema.ResourceData) *pagerduty.EventOrchestrationPath { + return &pagerduty.EventOrchestrationPath{ + Parent: &pagerduty.EventOrchestrationPathReference{ + ID: d.Get("service").(string), + }, + Sets: expandServicePathSets(d.Get("set")), + CatchAll: expandServicePathCatchAll(d.Get("catch_all")), + } +} + +func expandServicePathSets(v interface{}) []*pagerduty.EventOrchestrationPathSet { + var sets []*pagerduty.EventOrchestrationPathSet + + for _, set := range v.([]interface{}) { + s := set.(map[string]interface{}) + + orchPathSet := &pagerduty.EventOrchestrationPathSet{ + ID: s["id"].(string), + Rules: expandServicePathRules(s["rule"].(interface{})), + } + + sets = append(sets, orchPathSet) + } + + return sets +} + +func expandServicePathRules(v interface{}) []*pagerduty.EventOrchestrationPathRule { + items := v.([]interface{}) + rules := []*pagerduty.EventOrchestrationPathRule{} + + for _, rule := range items { + r := rule.(map[string]interface{}) + + ruleInSet := &pagerduty.EventOrchestrationPathRule{ + ID: r["id"].(string), + Label: r["label"].(string), + Disabled: r["disabled"].(bool), + Conditions: expandEventOrchestrationPathConditions(r["condition"]), + Actions: expandServicePathActions(r["actions"]), + } + + rules = append(rules, ruleInSet) + } + return rules +} + +func expandServicePathCatchAll(v interface{}) *pagerduty.EventOrchestrationPathCatchAll { + var catchAll = new(pagerduty.EventOrchestrationPathCatchAll) + + for _, ca := range v.([]interface{}) { + if ca != nil { + am := ca.(map[string]interface{}) + catchAll.Actions = expandServicePathActions(am["actions"]) + } + } + + return catchAll +} + +func expandServicePathActions(v interface{}) *pagerduty.EventOrchestrationPathRuleActions { + var actions = &pagerduty.EventOrchestrationPathRuleActions{ + AutomationActions: []*pagerduty.EventOrchestrationPathAutomationAction{}, + PagerdutyAutomationActions: []*pagerduty.EventOrchestrationPathPagerdutyAutomationAction{}, + Variables: []*pagerduty.EventOrchestrationPathActionVariables{}, + Extractions: []*pagerduty.EventOrchestrationPathActionExtractions{}, + } + + for _, i := range v.([]interface{}) { + if i == nil { + continue + } + a := i.(map[string]interface{}) + + actions.RouteTo = a["route_to"].(string) + actions.Suppress = a["suppress"].(bool) + actions.Suspend = intTypeToIntPtr(a["suspend"].(int)) + actions.Priority = a["priority"].(string) + actions.Annotate = a["annotate"].(string) + actions.Severity = a["severity"].(string) + actions.EventAction = a["event_action"].(string) + actions.PagerdutyAutomationActions = expandServicePathPagerDutyAutomationActions(a["pagerduty_automation_action"]) + actions.AutomationActions = expandServicePathAutomationActions(a["automation_action"]) + actions.Variables = expandEventOrchestrationPathVariables(a["variable"]) + actions.Extractions = expandEventOrchestrationPathExtractions(a["extraction"]) + } + + return actions +} + +func expandServicePathPagerDutyAutomationActions(v interface{}) []*pagerduty.EventOrchestrationPathPagerdutyAutomationAction { + result := []*pagerduty.EventOrchestrationPathPagerdutyAutomationAction{} + + for _, i := range v.([]interface{}) { + a := i.(map[string]interface{}) + pdaa := &pagerduty.EventOrchestrationPathPagerdutyAutomationAction{ + ActionId: a["action_id"].(string), + } + + result = append(result, pdaa) + } + + return result +} + +func expandServicePathAutomationActions(v interface{}) []*pagerduty.EventOrchestrationPathAutomationAction { + result := []*pagerduty.EventOrchestrationPathAutomationAction{} + + for _, i := range v.([]interface{}) { + a := i.(map[string]interface{}) + aa := &pagerduty.EventOrchestrationPathAutomationAction{ + Name: a["name"].(string), + Url: a["url"].(string), + AutoSend: a["auto_send"].(bool), + Headers: expandEventOrchestrationAutomationActionObjects(a["header"]), + Parameters: expandEventOrchestrationAutomationActionObjects(a["parameter"]), + } + + result = append(result, aa) + } + + return result +} + +func expandEventOrchestrationAutomationActionObjects(v interface{}) []*pagerduty.EventOrchestrationPathAutomationActionObject { + result := []*pagerduty.EventOrchestrationPathAutomationActionObject{} + + for _, i := range v.([]interface{}) { + o := i.(map[string]interface{}) + obj := &pagerduty.EventOrchestrationPathAutomationActionObject{ + Key: o["key"].(string), + Value: o["value"].(string), + } + + result = append(result, obj) + } + + return result +} + +func setEventOrchestrationPathServiceProps(d *schema.ResourceData, p *pagerduty.EventOrchestrationPath) error { + d.SetId(p.Parent.ID) + d.Set("service", p.Parent.ID) + d.Set("set", flattenServicePathSets(p.Sets)) + d.Set("catch_all", flattenServicePathCatchAll(p.CatchAll)) + return nil +} + +func flattenServicePathSets(orchPathSets []*pagerduty.EventOrchestrationPathSet) []interface{} { + var flattenedSets []interface{} + + for _, set := range orchPathSets { + flattenedSet := map[string]interface{}{ + "id": set.ID, + "rule": flattenServicePathRules(set.Rules), + } + flattenedSets = append(flattenedSets, flattenedSet) + } + return flattenedSets +} + +func flattenServicePathCatchAll(catchAll *pagerduty.EventOrchestrationPathCatchAll) []map[string]interface{} { + var caMap []map[string]interface{} + + c := make(map[string]interface{}) + + c["actions"] = flattenServicePathActions(catchAll.Actions) + caMap = append(caMap, c) + + return caMap +} + +func flattenServicePathRules(rules []*pagerduty.EventOrchestrationPathRule) []interface{} { + var flattenedRules []interface{} + + for _, rule := range rules { + flattenedRule := map[string]interface{}{ + "id": rule.ID, + "label": rule.Label, + "disabled": rule.Disabled, + "condition": flattenEventOrchestrationPathConditions(rule.Conditions), + "actions": flattenServicePathActions(rule.Actions), + } + flattenedRules = append(flattenedRules, flattenedRule) + } + + return flattenedRules +} + +func flattenServicePathActions(actions *pagerduty.EventOrchestrationPathRuleActions) []map[string]interface{} { + var actionsMap []map[string]interface{} + + flattenedAction := map[string]interface{}{ + "route_to": actions.RouteTo, + "severity": actions.Severity, + "event_action": actions.EventAction, + "suppress": actions.Suppress, + "suspend": actions.Suspend, + "priority": actions.Priority, + "annotate": actions.Annotate, + } + + if actions.Variables != nil { + flattenedAction["variable"] = flattenEventOrchestrationPathVariables(actions.Variables) + } + if actions.Extractions != nil { + flattenedAction["extraction"] = flattenEventOrchestrationPathExtractions(actions.Extractions) + } + if actions.PagerdutyAutomationActions != nil { + flattenedAction["pagerduty_automation_action"] = flattenServicePathPagerDutyAutomationActions(actions.PagerdutyAutomationActions) + } + if actions.AutomationActions != nil { + flattenedAction["automation_action"] = flattenServicePathAutomationActions(actions.AutomationActions) + } + + actionsMap = append(actionsMap, flattenedAction) + + return actionsMap +} + +func flattenServicePathPagerDutyAutomationActions(v []*pagerduty.EventOrchestrationPathPagerdutyAutomationAction) []interface{} { + var result []interface{} + + for _, i := range v { + pdaa := map[string]string{ + "action_id": i.ActionId, + } + + result = append(result, pdaa) + } + + return result +} + +func flattenServicePathAutomationActions(v []*pagerduty.EventOrchestrationPathAutomationAction) []interface{} { + var result []interface{} + + for _, i := range v { + pdaa := map[string]interface{}{ + "name": i.Name, + "url": i.Url, + "auto_send": i.AutoSend, + "header": flattenServicePathAutomationActionObjects(i.Headers), + "parameter": flattenServicePathAutomationActionObjects(i.Parameters), + } + + result = append(result, pdaa) + } + + return result +} + +func flattenServicePathAutomationActionObjects(v []*pagerduty.EventOrchestrationPathAutomationActionObject) []interface{} { + var result []interface{} + + for _, i := range v { + pdaa := map[string]interface{}{ + "key": i.Key, + "value": i.Value, + } + + result = append(result, pdaa) + } + + return result +} diff --git a/pagerduty/resource_pagerduty_event_orchestration_path_service_test.go b/pagerduty/resource_pagerduty_event_orchestration_path_service_test.go new file mode 100644 index 000000000..700bf32ea --- /dev/null +++ b/pagerduty/resource_pagerduty_event_orchestration_path_service_test.go @@ -0,0 +1,733 @@ +package pagerduty + +import ( + "fmt" + "regexp" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func init() { + resource.AddTestSweepers("pagerduty_event_orchestration_service", &resource.Sweeper{ + Name: "pagerduty_event_orchestration_service", + F: testSweepEventOrchestration, + }) +} + +func TestAccPagerDutyEventOrchestrationPathService_Basic(t *testing.T) { + escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) + service := fmt.Sprintf("tf-%s", acctest.RandString(5)) + + resourceName := "pagerduty_event_orchestration_service.serviceA" + serviceResourceName := "pagerduty_service.bar" + + // Checks that run on every step except the last one. These checks that verify the existance of the resource + // and computed/default attributes. We're not checking individual resource attributes because + // according to the official docs (https://pkg.go.dev/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource#TestCheckResourceAttr) + // "State value checking is only recommended for testing Computed attributes and attribute defaults." + baseChecks := []resource.TestCheckFunc{ + testAccCheckPagerDutyEventOrchestrationPathServiceExists(resourceName), + testAccCheckPagerDutyEventOrchestrationPathServiceServiceID(resourceName, serviceResourceName), + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckPagerDutyEventOrchestrationServicePathDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckPagerDutyEventOrchestrationPathServiceDefaultConfig(escalationPolicy, service), + Check: resource.ComposeTestCheckFunc(baseChecks...), + }, + // Adding/updating/deleting automation_action properties + { + Config: testAccCheckPagerDutyEventOrchestrationPathServiceAutomationActionsConfig(escalationPolicy, service), + Check: resource.ComposeTestCheckFunc( + append( + baseChecks, + resource.TestCheckResourceAttrSet(resourceName, "set.0.rule.0.id"), + )..., + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathServiceAutomationActionsParamsUpdateConfig(escalationPolicy, service), + Check: resource.ComposeTestCheckFunc( + append( + baseChecks, + resource.TestCheckResourceAttr( + resourceName, "set.0.rule.0.actions.0.automation_action.0.auto_send", "false", + ), + )..., + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathServiceAutomationActionsParamsDeleteConfig(escalationPolicy, service), + Check: resource.ComposeTestCheckFunc(baseChecks...), + }, + // Providing invalid extractions attributes for set rules + { + Config: testAccCheckPagerDutyEventOrchestrationPathServiceInvalidExtractionsConfig( + escalationPolicy, service, invalidExtractionRegexTemplateNilConfig(), "", + ), + PlanOnly: true, + ExpectError: regexp.MustCompile("Invalid configuration in set.0.rule.0.actions.0.extraction.0: regex and template cannot both be null"), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathServiceInvalidExtractionsConfig( + escalationPolicy, service, invalidExtractionRegexTemplateValConfig(), "", + ), + PlanOnly: true, + ExpectError: regexp.MustCompile("Invalid configuration in set.0.rule.0.actions.0.extraction.0: regex and template cannot both have values"), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathServiceInvalidExtractionsConfig( + escalationPolicy, service, invalidExtractionRegexNilSourceConfig(), "", + ), + PlanOnly: true, + ExpectError: regexp.MustCompile("Invalid configuration in set.0.rule.0.actions.0.extraction.0: source can't be blank"), + }, + // Providing invalid extractions attributes for the catch_all rule + { + Config: testAccCheckPagerDutyEventOrchestrationPathServiceInvalidExtractionsConfig( + escalationPolicy, service, "", invalidExtractionRegexTemplateNilConfig(), + ), + PlanOnly: true, + ExpectError: regexp.MustCompile("Invalid configuration in catch_all.0.actions.0.extraction.0: regex and template cannot both be null"), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathServiceInvalidExtractionsConfig( + escalationPolicy, service, "", invalidExtractionRegexTemplateValConfig(), + ), + PlanOnly: true, + ExpectError: regexp.MustCompile("Invalid configuration in catch_all.0.actions.0.extraction.0: regex and template cannot both have values"), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathServiceInvalidExtractionsConfig( + escalationPolicy, service, "", invalidExtractionRegexNilSourceConfig(), + ), + PlanOnly: true, + ExpectError: regexp.MustCompile("Invalid configuration in catch_all.0.actions.0.extraction.0: source can't be blank"), + }, + // Adding/updating/deleting all actions + { + Config: testAccCheckPagerDutyEventOrchestrationPathServiceAllActionsConfig(escalationPolicy, service), + Check: resource.ComposeTestCheckFunc( + append( + baseChecks, + []resource.TestCheckFunc{ + resource.TestCheckResourceAttrSet(resourceName, "set.0.rule.0.id"), + resource.TestCheckResourceAttrSet(resourceName, "set.1.rule.0.id"), + resource.TestCheckResourceAttrSet(resourceName, "set.1.rule.1.id"), + }..., + )..., + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathServiceAllActionsUpdateConfig(escalationPolicy, service), + Check: resource.ComposeTestCheckFunc( + append( + baseChecks, + []resource.TestCheckFunc{ + resource.TestCheckResourceAttrSet(resourceName, "set.0.rule.0.id"), + resource.TestCheckResourceAttrSet(resourceName, "set.1.rule.0.id"), + resource.TestCheckResourceAttrSet(resourceName, "set.1.rule.1.id"), + }..., + )..., + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathServiceAllActionsDeleteConfig(escalationPolicy, service), + Check: resource.ComposeTestCheckFunc( + append( + baseChecks, + []resource.TestCheckFunc{ + resource.TestCheckResourceAttrSet(resourceName, "set.0.rule.0.id"), + resource.TestCheckResourceAttrSet(resourceName, "set.1.rule.0.id"), + resource.TestCheckResourceAttrSet(resourceName, "set.1.rule.1.id"), + }..., + )..., + ), + }, + // Deleting sets and the service path resource + { + Config: testAccCheckPagerDutyEventOrchestrationPathServiceOneSetNoActionsConfig(escalationPolicy, service), + Check: resource.ComposeTestCheckFunc( + append( + baseChecks, + resource.TestCheckResourceAttrSet(resourceName, "set.0.rule.0.id"), + )..., + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathServiceResourceDeleteConfig(escalationPolicy, service), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationServicePathNotExists(resourceName), + ), + }, + }, + }) +} + +func testAccCheckPagerDutyEventOrchestrationServicePathDestroy(s *terraform.State) error { + client, _ := testAccProvider.Meta().(*Config).Client() + for _, r := range s.RootModule().Resources { + if r.Type != "pagerduty_event_orchestration_path_service" { + continue + } + + srv := s.RootModule().Resources["pagerduty_service.bar"] + + if _, _, err := client.EventOrchestrationPaths.Get(srv.Primary.ID, "service"); err == nil { + return fmt.Errorf("Event Orchestration Service Path still exists") + } + } + return nil +} + +func testAccCheckPagerDutyEventOrchestrationPathServiceExists(rn string) resource.TestCheckFunc { + return func(s *terraform.State) error { + orch, ok := s.RootModule().Resources[rn] + if !ok { + return fmt.Errorf("Not found: %s", rn) + } + if orch.Primary.ID == "" { + return fmt.Errorf("No Event Orchestration Service ID is set") + } + + client, _ := testAccProvider.Meta().(*Config).Client() + found, _, err := client.EventOrchestrationPaths.Get(orch.Primary.ID, "service") + if err != nil { + return err + } + if found.Parent.ID != orch.Primary.ID { + return fmt.Errorf("Event Orchrestration Service not found: %v - %v", orch.Primary.ID, found) + } + + return nil + } +} + +func testAccCheckPagerDutyEventOrchestrationServicePathNotExists(rn string) resource.TestCheckFunc { + return func(s *terraform.State) error { + _, ok := s.RootModule().Resources[rn] + if ok { + return fmt.Errorf("Event Orchestration Service Path is not deleted from the state: %s", rn) + } + + return nil + } +} + +func testAccCheckPagerDutyEventOrchestrationPathServiceServiceID(rn, sn string) resource.TestCheckFunc { + return func(s *terraform.State) error { + p, _ := s.RootModule().Resources[rn] + srv, ok := s.RootModule().Resources[sn] + + if !ok { + return fmt.Errorf("Service not found: %s", sn) + } + + var pId = p.Primary.Attributes["service"] + var sId = srv.Primary.Attributes["id"] + if pId != sId { + return fmt.Errorf("Event Orchestration Service path service ID (%v) not matching provided service ID: %v", pId, sId) + } + + return nil + } +} + +func createBaseServicePathConfig(ep, s string) string { + return fmt.Sprintf(` + resource "pagerduty_user" "foo" { + name = "tf-user" + email = "user@pagerduty.com" + color = "green" + role = "user" + job_title = "foo" + description = "foo" + } + + resource "pagerduty_escalation_policy" "foo" { + name = "%s" + description = "bar" + num_loops = 2 + + rule { + escalation_delay_in_minutes = 10 + target { + type = "user_reference" + id = pagerduty_user.foo.id + } + } + } + + resource "pagerduty_service" "bar" { + name = "%s" + escalation_policy = pagerduty_escalation_policy.foo.id + + incident_urgency_rule { + type = "constant" + urgency = "high" + } + } + `, ep, s) +} + +func testAccCheckPagerDutyEventOrchestrationPathServiceDefaultConfig(ep, s string) string { + return fmt.Sprintf("%s%s", createBaseServicePathConfig(ep, s), + `resource "pagerduty_event_orchestration_service" "serviceA" { + service = pagerduty_service.bar.id + + set { + id = "start" + } + + catch_all { + actions { } + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationPathServiceAutomationActionsConfig(ep, s string) string { + return fmt.Sprintf("%s%s", createBaseServicePathConfig(ep, s), + `resource "pagerduty_event_orchestration_service" "serviceA" { + service = pagerduty_service.bar.id + + set { + id = "start" + rule { + label = "rule 1" + actions { + automation_action { + name = "test" + url = "https://test.com" + auto_send = true + + header { + key = "foo" + value = "bar" + } + header { + key = "baz" + value = "buz" + } + + parameter { + key = "source" + value = "orch" + } + parameter { + key = "region" + value = "us" + } + } + } + } + } + + catch_all { + actions { + automation_action { + name = "catch-all test" + url = "https://catch-all-test.com" + auto_send = true + + header { + key = "foo1" + value = "bar1" + } + header { + key = "baz1" + value = "buz1" + } + + parameter { + key = "source1" + value = "orch1" + } + parameter { + key = "region1" + value = "us1" + } + } + } + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationPathServiceAutomationActionsParamsUpdateConfig(ep, s string) string { + return fmt.Sprintf("%s%s", createBaseServicePathConfig(ep, s), + `resource "pagerduty_event_orchestration_service" "serviceA" { + service = pagerduty_service.bar.id + + set { + id = "start" + rule { + label = "rule 1" + actions { + automation_action { + name = "test1" + url = "https://test1.com" + + header { + key = "foo1" + value = "bar1" + } + parameter { + key = "source_region" + value = "eu" + } + } + } + } + } + + catch_all { + actions { + automation_action { + name = "catch-all test upd" + url = "https://catch-all-test-upd.com" + + header { + key = "baz2" + value = "buz2" + } + + parameter { + key = "source2" + value = "orch2" + } + } + } + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationPathServiceAutomationActionsParamsDeleteConfig(ep, s string) string { + return fmt.Sprintf("%s%s", createBaseServicePathConfig(ep, s), + `resource "pagerduty_event_orchestration_service" "serviceA" { + service = pagerduty_service.bar.id + + set { + id = "start" + rule { + label = "rule 1" + actions { + automation_action { + name = "test" + url = "https://test.com" + } + } + } + } + + catch_all { + actions { + automation_action { + name = "catch-all test upd" + url = "https://catch-all-test-upd.com" + } + } + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationPathServiceInvalidExtractionsConfig(ep, s, re, cae string) string { + return fmt.Sprintf( + "%s%s", + createBaseServicePathConfig(ep, s), + fmt.Sprintf(`resource "pagerduty_event_orchestration_service" "serviceA" { + service = pagerduty_service.bar.id + + set { + id = "start" + rule { + actions { + %s + } + } + } + catch_all { + actions { + %s + } + } + } + `, re, cae), + ) +} + +func testAccCheckPagerDutyEventOrchestrationPathServiceAllActionsConfig(ep, s string) string { + return fmt.Sprintf("%s%s", createBaseServicePathConfig(ep, s), + `resource "pagerduty_event_orchestration_service" "serviceA" { + service = pagerduty_service.bar.id + + set { + id = "start" + rule { + label = "rule 1" + condition { + expression = "event.summary matches part 'timeout'" + } + condition { + expression = "event.custom_details.timeout_err exists" + } + actions { + route_to = "set-1" + priority = "P0IN2KQ" + annotate = "Routed through an event orchestration" + pagerduty_automation_action { + action_id = "01CSB5SMOKCKVRI5GN0LJG7SMB" + } + severity = "critical" + event_action = "trigger" + variable { + name = "hostname" + path = "event.source" + type = "regex" + value = "Source host: (.*)" + } + variable { + name = "cpu_val" + path = "event.custom_details.cpu" + type = "regex" + value = "(.*)" + } + extraction { + target = "event.summary" + template = "High CPU usage on {{variables.hostname}}" + } + extraction { + regex = ".*" + source = "event.group" + target = "event.custom_details.message" + } + } + } + } + set { + id = "set-1" + rule { + label = "set-1 rule 1" + actions { + suspend = 300 + } + } + rule { + label = "set-1 rule 2" + condition { + expression = "event.source matches part 'stg-'" + } + actions { + suppress = true + } + } + } + + catch_all { + actions { + suspend = 120 + priority = "P0IN2KW" + annotate = "Routed through an event orchestration - catch-all rule" + pagerduty_automation_action { + action_id = "01CSB5SMOKCKVRI5GN0LJG7SMC" + } + severity = "warning" + event_action = "trigger" + variable { + name = "user_id" + path = "event.custom_details.user_id" + type = "regex" + value = "Source host: (.*)" + } + variable { + name = "updated_at" + path = "event.custom_details.updated_at" + type = "regex" + value = "(.*)" + } + extraction { + target = "event.custom_details.message" + template = "Last modified by {{variables.user_id}} on {{variables.updated_at}}" + } + extraction { + regex = ".*" + source = "event.custom_details.region" + target = "event.group" + } + } + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationPathServiceAllActionsUpdateConfig(ep, s string) string { + return fmt.Sprintf("%s%s", createBaseServicePathConfig(ep, s), + `resource "pagerduty_event_orchestration_service" "serviceA" { + service = pagerduty_service.bar.id + + set { + id = "start" + rule { + label = "rule 1 updated" + condition { + expression = "event.custom_details.timeout_err matches part 'timeout'" + } + actions { + route_to = "set-2" + priority = "P0IN2KR" + annotate = "Routed through a service orchestration!" + pagerduty_automation_action { + action_id = "01CSB5SMOKCKVRI5GN0LJG7SMBUPDATED" + } + severity = "warning" + event_action = "resolve" + variable { + name = "cpu_val_upd" + path = "event.custom_details.cpu_upd" + type = "regex" + value = "CPU:(.*)" + } + extraction { + regex = ".*" + source = "event.custom_details.region_upd" + target = "event.source" + } + extraction { + target = "event.custom_details.message_upd" + template = "[UPD] High CPU usage on {{variables.hostname}}: {{variables.cpu_val}}" + } + } + } + } + set { + id = "set-2" + rule { + label = "set-2 rule 1" + actions { + suspend = 15 + } + } + rule { + label = "set-2 rule 2" + condition { + expression = "event.source matches part 'test-'" + } + actions { + annotate = "Matched set-2 rule 2" + variable { + name = "host_name" + path = "event.custom_details.memory" + type = "regex" + value = "High memory usage on (.*) server" + } + extraction { + target = "event.summary" + template = "High memory usage on {{variables.hostname}} server: {{event.custom_details.max_memory}}" + } + extraction { + regex = ".*" + source = "event.custom_details.region" + target = "event.group" + } + extraction { + regex = ".*" + source = "event.custom_details.hostname" + target = "event.source" + } + } + } + } + + catch_all { + actions { + suspend = 360 + suppress = true + priority = "P0IN2KX" + annotate = "[UPD] Routed through an event orchestration - catch-all rule" + pagerduty_automation_action { + action_id = "01CSB5SMOKCKVRI5GN0LJG7SMD" + } + severity = "info" + event_action = "resolve" + variable { + name = "updated_at_upd" + path = "event.custom_details.updated_at" + type = "regex" + value = "UPD (.*)" + } + extraction { + regex = ".*" + source = "event.custom_details.region_upd" + target = "event.class" + } + } + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationPathServiceAllActionsDeleteConfig(ep, s string) string { + return fmt.Sprintf("%s%s", createBaseServicePathConfig(ep, s), + `resource "pagerduty_event_orchestration_service" "serviceA" { + service = pagerduty_service.bar.id + + set { + id = "start" + rule { + label = "rule 1 updated" + actions { + route_to = "set-2" + } + } + } + set { + id = "set-2" + rule { + label = "set-2 rule 1" + actions { } + } + rule { + label = "set-2 rule 2" + actions { } + } + } + + catch_all { + actions { } + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationPathServiceOneSetNoActionsConfig(ep, s string) string { + return fmt.Sprintf("%s%s", createBaseServicePathConfig(ep, s), + `resource "pagerduty_event_orchestration_service" "serviceA" { + service = pagerduty_service.bar.id + + set { + id = "start" + rule { + label = "rule 1 updated" + actions {} + } + } + + catch_all { + actions { } + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationPathServiceResourceDeleteConfig(ep, s string) string { + return createBaseServicePathConfig(ep, s) +} diff --git a/pagerduty/resource_pagerduty_event_orchestration_path_unrouted.go b/pagerduty/resource_pagerduty_event_orchestration_path_unrouted.go new file mode 100644 index 000000000..2fc4cc787 --- /dev/null +++ b/pagerduty/resource_pagerduty_event_orchestration_path_unrouted.go @@ -0,0 +1,445 @@ +package pagerduty + +import ( + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/heimweh/go-pagerduty/pagerduty" +) + +func resourcePagerDutyEventOrchestrationPathUnrouted() *schema.Resource { + return &schema.Resource{ + Read: resourcePagerDutyEventOrchestrationPathUnroutedRead, + Create: resourcePagerDutyEventOrchestrationPathUnroutedCreate, + Update: resourcePagerDutyEventOrchestrationPathUnroutedUpdate, + Delete: resourcePagerDutyEventOrchestrationPathUnroutedDelete, + Importer: &schema.ResourceImporter{ + State: resourcePagerDutyEventOrchestrationPathUnroutedImport, + }, + CustomizeDiff: checkExtractions, + Schema: map[string]*schema.Schema{ + "event_orchestration": { + Type: schema.TypeString, + Required: true, + }, + "set": { + Type: schema.TypeList, + Required: true, + MinItems: 1, // An Unrouted Orchestration must contain at least a "start" set + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Required: true, + }, + "rule": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + "label": { + Type: schema.TypeString, + Optional: true, + }, + "condition": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: eventOrchestrationPathConditionsSchema, + }, + }, + "actions": { + Type: schema.TypeList, + Required: true, // even if there are no actions, API returns actions as an empty list + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "route_to": { + Type: schema.TypeString, + Optional: true, // If there is only start set we don't need route_to + }, + "severity": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateEventOrchestrationPathSeverity(), + }, + "event_action": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateEventOrchestrationPathEventAction(), + }, + "variable": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: eventOrchestrationPathVariablesSchema, + }, + }, + "extraction": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: eventOrchestrationPathExtractionsSchema, + }, + }, + }, + }, + }, + "disabled": { + Type: schema.TypeBool, + Optional: true, + }, + }, + }, + }, + }, + }, + }, + "catch_all": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "actions": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "suppress": { + Type: schema.TypeBool, + Computed: true, + }, + "severity": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateValueFunc([]string{ + "info", + "error", + "warning", + "critical", + }), + }, + "event_action": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateValueFunc([]string{ + "trigger", + "resolve", + }), + }, + "variable": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: eventOrchestrationPathVariablesSchema, + }, + }, + "extraction": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: eventOrchestrationPathExtractionsSchema, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func resourcePagerDutyEventOrchestrationPathUnroutedRead(d *schema.ResourceData, meta interface{}) error { + client, err := meta.(*Config).Client() + if err != nil { + return err + } + + return resource.Retry(2*time.Minute, func() *resource.RetryError { + + log.Printf("[INFO] Reading PagerDuty Event Orchestration Path of type: %s for orchestration: %s", "unrouted", d.Id()) + + if unroutedPath, _, err := client.EventOrchestrationPaths.Get(d.Id(), "unrouted"); err != nil { + time.Sleep(2 * time.Second) + return resource.RetryableError(err) + } else if unroutedPath != nil { + if unroutedPath.Sets != nil { + d.Set("set", flattenUnroutedSets(unroutedPath.Sets)) + } + + if unroutedPath.CatchAll != nil { + d.Set("catch_all", flattenUnroutedCatchAll(unroutedPath.CatchAll)) + } + } + return nil + }) + +} + +// EventOrchestrationPath cannot be created, use update to add / edit / remove rules and sets +func resourcePagerDutyEventOrchestrationPathUnroutedCreate(d *schema.ResourceData, meta interface{}) error { + return resourcePagerDutyEventOrchestrationPathUnroutedUpdate(d, meta) +} + +// EventOrchestrationPath cannot be deleted, use update to add / edit / remove rules and sets +func resourcePagerDutyEventOrchestrationPathUnroutedDelete(d *schema.ResourceData, meta interface{}) error { + d.SetId("") + return nil +} + +func resourcePagerDutyEventOrchestrationPathUnroutedUpdate(d *schema.ResourceData, meta interface{}) error { + client, err := meta.(*Config).Client() + if err != nil { + return err + } + + updatePath := buildUnroutedPathStructForUpdate(d) + + log.Printf("[INFO] Updating PagerDuty EventOrchestrationPath of type: %s for orchestration: %s", "unrouted", updatePath.Parent.ID) + + return performUnroutedPathUpdate(d, updatePath, client) +} + +func performUnroutedPathUpdate(d *schema.ResourceData, unroutedPath *pagerduty.EventOrchestrationPath, client *pagerduty.Client) error { + retryErr := resource.Retry(30*time.Second, func() *resource.RetryError { + updatedPath, _, err := client.EventOrchestrationPaths.Update(unroutedPath.Parent.ID, "unrouted", unroutedPath) + if err != nil { + return resource.RetryableError(err) + } + if updatedPath == nil { + return resource.NonRetryableError(fmt.Errorf("no event orchestration unrouted found")) + } + d.SetId(unroutedPath.Parent.ID) + d.Set("event_orchestration", unroutedPath.Parent.ID) + if unroutedPath.Sets != nil { + d.Set("set", flattenUnroutedSets(unroutedPath.Sets)) + } + if updatedPath.CatchAll != nil { + d.Set("catch_all", flattenUnroutedCatchAll(updatedPath.CatchAll)) + } + return nil + }) + if retryErr != nil { + time.Sleep(2 * time.Second) + return retryErr + } + return nil +} + +func buildUnroutedPathStructForUpdate(d *schema.ResourceData) *pagerduty.EventOrchestrationPath { + + orchPath := &pagerduty.EventOrchestrationPath{ + Parent: &pagerduty.EventOrchestrationPathReference{ + ID: d.Get("event_orchestration").(string), + }, + } + + if attr, ok := d.GetOk("set"); ok { + orchPath.Sets = expandUnroutedSets(attr.([]interface{})) + } + + if attr, ok := d.GetOk("catch_all"); ok { + orchPath.CatchAll = expandUnroutedCatchAll(attr.([]interface{})) + } + + return orchPath +} + +func expandUnroutedSets(v interface{}) []*pagerduty.EventOrchestrationPathSet { + var sets []*pagerduty.EventOrchestrationPathSet + + for _, set := range v.([]interface{}) { + s := set.(map[string]interface{}) + + orchPathSet := &pagerduty.EventOrchestrationPathSet{ + ID: s["id"].(string), + Rules: expandUnroutedRules(s["rule"]), + } + + sets = append(sets, orchPathSet) + } + + return sets +} + +func expandUnroutedRules(v interface{}) []*pagerduty.EventOrchestrationPathRule { + items := v.([]interface{}) + rules := []*pagerduty.EventOrchestrationPathRule{} + + for _, rule := range items { + r := rule.(map[string]interface{}) + + ruleInSet := &pagerduty.EventOrchestrationPathRule{ + ID: r["id"].(string), + Label: r["label"].(string), + Disabled: r["disabled"].(bool), + Conditions: expandEventOrchestrationPathConditions(r["condition"]), + Actions: expandUnroutedActions(r["actions"]), + } + + rules = append(rules, ruleInSet) + } + return rules +} + +func expandUnroutedActions(v interface{}) *pagerduty.EventOrchestrationPathRuleActions { + var actions = &pagerduty.EventOrchestrationPathRuleActions{ + Variables: []*pagerduty.EventOrchestrationPathActionVariables{}, + Extractions: []*pagerduty.EventOrchestrationPathActionExtractions{}, + } + + for _, ai := range v.([]interface{}) { + if ai != nil { + am := ai.(map[string]interface{}) + actions.RouteTo = am["route_to"].(string) + actions.Severity = am["severity"].(string) + actions.EventAction = am["event_action"].(string) + actions.Variables = expandEventOrchestrationPathVariables(am["variable"]) + actions.Extractions = expandEventOrchestrationPathExtractions(am["extraction"]) + } + } + + return actions +} + +func expandUnroutedCatchAll(v interface{}) *pagerduty.EventOrchestrationPathCatchAll { + var catchAll = new(pagerduty.EventOrchestrationPathCatchAll) + + for _, ca := range v.([]interface{}) { + if ca != nil { + am := ca.(map[string]interface{}) + catchAll.Actions = expandUnroutedCatchAllActions(am["actions"]) + } + } + + return catchAll +} + +func expandUnroutedCatchAllActions(v interface{}) *pagerduty.EventOrchestrationPathRuleActions { + var actions = new(pagerduty.EventOrchestrationPathRuleActions) + for _, ai := range v.([]interface{}) { + if ai != nil { + am := ai.(map[string]interface{}) + actions.Severity = am["severity"].(string) + actions.EventAction = am["event_action"].(string) + actions.Variables = expandEventOrchestrationPathVariables(am["variable"]) + actions.Extractions = expandEventOrchestrationPathExtractions(am["extraction"]) + } + } + + return actions +} + +func flattenUnroutedSets(orchPathSets []*pagerduty.EventOrchestrationPathSet) []interface{} { + var flattenedSets []interface{} + + for _, set := range orchPathSets { + flattenedSet := map[string]interface{}{ + "id": set.ID, + "rule": flattenUnroutedRules(set.Rules), + } + flattenedSets = append(flattenedSets, flattenedSet) + } + return flattenedSets +} + +func flattenUnroutedRules(rules []*pagerduty.EventOrchestrationPathRule) []interface{} { + var flattenedRules []interface{} + + for _, rule := range rules { + flattenedRule := map[string]interface{}{ + "id": rule.ID, + "label": rule.Label, + "disabled": rule.Disabled, + "condition": flattenEventOrchestrationPathConditions(rule.Conditions), + "actions": flattenUnroutedActions(rule.Actions), + } + flattenedRules = append(flattenedRules, flattenedRule) + } + + return flattenedRules +} + +func flattenUnroutedActions(actions *pagerduty.EventOrchestrationPathRuleActions) []map[string]interface{} { + var actionsMap []map[string]interface{} + + flattenedAction := map[string]interface{}{ + "route_to": actions.RouteTo, + "severity": actions.Severity, + "event_action": actions.EventAction, + } + + if actions.Variables != nil { + flattenedAction["variable"] = flattenEventOrchestrationPathVariables(actions.Variables) + } + if actions.Extractions != nil { + flattenedAction["extraction"] = flattenEventOrchestrationPathExtractions(actions.Extractions) + } + + actionsMap = append(actionsMap, flattenedAction) + + return actionsMap +} + +func flattenUnroutedCatchAll(catchAll *pagerduty.EventOrchestrationPathCatchAll) []map[string]interface{} { + var caMap []map[string]interface{} + + c := make(map[string]interface{}) + + c["actions"] = flattenUnroutedCatchAllActions(catchAll.Actions) + caMap = append(caMap, c) + + return caMap +} + +func flattenUnroutedCatchAllActions(actions *pagerduty.EventOrchestrationPathRuleActions) []map[string]interface{} { + var actionsMap []map[string]interface{} + + flattenedAction := map[string]interface{}{ + "severity": actions.Severity, + "event_action": actions.EventAction, + "suppress": actions.Suppress, // By default suppress is set to "true" by API for unrouted + } + + if actions.Variables != nil { + flattenedAction["variable"] = flattenEventOrchestrationPathVariables(actions.Variables) + } + if actions.Variables != nil { + flattenedAction["extraction"] = flattenEventOrchestrationPathExtractions(actions.Extractions) + } + + actionsMap = append(actionsMap, flattenedAction) + + return actionsMap +} + +func resourcePagerDutyEventOrchestrationPathUnroutedImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + client, err := meta.(*Config).Client() + if err != nil { + return []*schema.ResourceData{}, err + } + // given an orchestration ID import the unrouted orchestration path + orchestrationID := d.Id() + pathType := "unrouted" + _, _, err = client.EventOrchestrationPaths.Get(orchestrationID, pathType) + + if err != nil { + return []*schema.ResourceData{}, err + } + + d.SetId(orchestrationID) + d.Set("event_orchestration", orchestrationID) + + return []*schema.ResourceData{d}, nil +} diff --git a/pagerduty/resource_pagerduty_event_orchestration_path_unrouted_test.go b/pagerduty/resource_pagerduty_event_orchestration_path_unrouted_test.go new file mode 100644 index 000000000..4d2180ec0 --- /dev/null +++ b/pagerduty/resource_pagerduty_event_orchestration_path_unrouted_test.go @@ -0,0 +1,549 @@ +package pagerduty + +import ( + "fmt" + "regexp" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func init() { + resource.AddTestSweepers("pagerduty_event_orchestration_unrouted", &resource.Sweeper{ + Name: "pagerduty_event_orchestration_unrouted", + F: testSweepEventOrchestration, + }) +} + +func TestAccPagerDutyEventOrchestrationPathUnrouted_Basic(t *testing.T) { + team := fmt.Sprintf("tf-team-%s", acctest.RandString(5)) + escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) + service := fmt.Sprintf("tf-%s", acctest.RandString(5)) + orchestration := fmt.Sprintf("tf-orchestration-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckPagerDutyEventOrchestrationPathUnroutedDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckPagerDutyEventOrchestrationPathUnroutedConfigNoRules(team, escalationPolicy, service, orchestration), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationPathUnroutedExists("pagerduty_event_orchestration_unrouted.unrouted"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.0.rule.#", "0"), + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathUnroutedConfigWithConditions(team, escalationPolicy, service, orchestration), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationPathUnroutedExists("pagerduty_event_orchestration_unrouted.unrouted"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.0.rule.0.condition.0.expression", "event.summary matches part 'rds'"), + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathUnroutedConfigWithMultipleRules(team, escalationPolicy, service, orchestration), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationPathUnroutedExists("pagerduty_event_orchestration_unrouted.unrouted"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.0.rule.#", "2"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.0.rule.0.condition.0.expression", "event.summary matches part 'rds'"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.0.rule.0.condition.1.expression", "event.severity matches part 'warning'"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.0.rule.1.condition.0.expression", "event.severity matches part 'info'"), + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathUnroutedWithAllConfig(team, escalationPolicy, service, orchestration), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationPathUnroutedExists("pagerduty_event_orchestration_unrouted.unrouted"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.#", "2"), + //Set #1 + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.0.id", "start"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.0.rule.0.condition.#", "2"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.0.rule.0.actions.0.route_to", "child-1"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.0.rule.0.condition.0.expression", "event.severity matches part 'info'"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.0.rule.0.condition.1.expression", "event.severity matches part 'warning'"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.0.rule.0.actions.0.severity", "info"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.0.rule.0.actions.0.event_action", "trigger"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.0.rule.0.actions.0.variable.#", "2"), + resource.TestCheckTypeSetElemNestedAttrs( + "pagerduty_event_orchestration_unrouted.unrouted", + "set.0.rule.0.actions.0.variable.*", + map[string]string{ + "name": "server_name_cpu", + "path": "event.summary", + "type": "regex", + "value": "High CPU on (.*) server", + }, + ), + resource.TestCheckTypeSetElemNestedAttrs( + "pagerduty_event_orchestration_unrouted.unrouted", + "set.0.rule.0.actions.0.variable.*", + map[string]string{ + "name": "server_name_memory", + "path": "event.custom_details", + "type": "regex", + "value": "High memory usage on (.*) server", + }, + ), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.0.rule.0.actions.0.extraction.#", "2"), + + resource.TestCheckTypeSetElemNestedAttrs( + "pagerduty_event_orchestration_unrouted.unrouted", + "set.0.rule.0.actions.0.extraction.*", + map[string]string{ + "target": "event.summary", + "template": "High memory usage on {{variables.hostname}} server", + }, + ), + resource.TestCheckTypeSetElemNestedAttrs( + "pagerduty_event_orchestration_unrouted.unrouted", + "set.0.rule.0.actions.0.extraction.*", + map[string]string{ + "target": "event.custom_details", + "template": "High memory usage on {{variables.hostname}} server", + }, + ), + //Set #2 + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.1.id", "child-1"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.1.rule.0.condition.0.expression", "event.severity matches part 'warning'"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.1.rule.0.actions.0.event_action", "resolve"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.1.rule.1.condition.0.expression", "event.severity matches part 'critical'"), + // Catch All + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "catch_all.0.actions.0.severity", "critical"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "catch_all.0.actions.0.event_action", "trigger"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "catch_all.0.actions.0.variable.#", "2"), + resource.TestCheckTypeSetElemNestedAttrs( + "pagerduty_event_orchestration_unrouted.unrouted", + "catch_all.0.actions.0.variable.*", + map[string]string{ + "name": "server_name_cpu", + "path": "event.summary", + "type": "regex", + "value": "High CPU on (.*) server", + }, + ), + resource.TestCheckTypeSetElemNestedAttrs( + "pagerduty_event_orchestration_unrouted.unrouted", + "catch_all.0.actions.0.variable.*", + map[string]string{ + "name": "server_name_memory", + "path": "event.custom_details", + "type": "regex", + "value": "High memory usage on (.*) server", + }, + ), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "catch_all.0.actions.0.extraction.#", "2"), + + resource.TestCheckTypeSetElemNestedAttrs( + "pagerduty_event_orchestration_unrouted.unrouted", + "catch_all.0.actions.0.extraction.*", + map[string]string{ + "target": "event.summary", + "template": "High memory usage on {{variables.hostname}} server", + }, + ), + resource.TestCheckTypeSetElemNestedAttrs( + "pagerduty_event_orchestration_unrouted.unrouted", + "catch_all.0.actions.0.extraction.*", + map[string]string{ + "target": "event.custom_details", + "template": "High memory usage on {{variables.hostname}} server", + }, + ), + ), + }, + // Providing invalid extractions attributes for set rules + { + Config: testAccCheckPagerDutyEventOrchestrationPathUnroutedInvalidExtractionsConfig( + team, escalationPolicy, service, orchestration, invalidExtractionRegexTemplateValConfig(), "", + ), + PlanOnly: true, + ExpectError: regexp.MustCompile("Invalid configuration in set.0.rule.0.actions.0.extraction.0: regex and template cannot both have values"), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathUnroutedInvalidExtractionsConfig( + team, escalationPolicy, service, orchestration, invalidExtractionRegexTemplateValConfig(), "", + ), + PlanOnly: true, + ExpectError: regexp.MustCompile("Invalid configuration in set.0.rule.0.actions.0.extraction.0: regex and template cannot both have values"), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathUnroutedInvalidExtractionsConfig( + team, escalationPolicy, service, orchestration, invalidExtractionRegexNilSourceConfig(), "", + ), + PlanOnly: true, + ExpectError: regexp.MustCompile("Invalid configuration in set.0.rule.0.actions.0.extraction.0: source can't be blank"), + }, + // Providing invalid extractions attributes for the catch_all rule + { + Config: testAccCheckPagerDutyEventOrchestrationPathUnroutedInvalidExtractionsConfig( + team, escalationPolicy, service, orchestration, "", invalidExtractionRegexTemplateNilConfig(), + ), + PlanOnly: true, + ExpectError: regexp.MustCompile("Invalid configuration in catch_all.0.actions.0.extraction.0: regex and template cannot both be null"), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathUnroutedInvalidExtractionsConfig( + team, escalationPolicy, service, orchestration, "", invalidExtractionRegexTemplateValConfig(), + ), + PlanOnly: true, + ExpectError: regexp.MustCompile("Invalid configuration in catch_all.0.actions.0.extraction.0: regex and template cannot both have values"), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathUnroutedInvalidExtractionsConfig( + team, escalationPolicy, service, orchestration, "", invalidExtractionRegexNilSourceConfig(), + ), + PlanOnly: true, + ExpectError: regexp.MustCompile("Invalid configuration in catch_all.0.actions.0.extraction.0: source can't be blank"), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathUnroutedConfigNoRules(team, escalationPolicy, service, orchestration), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationPathUnroutedExists("pagerduty_event_orchestration_unrouted.unrouted"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration_unrouted.unrouted", "set.0.rule.#", "0"), + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationPathUnroutedConfigDelete(team, escalationPolicy, service, orchestration), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationPathUnroutedNotExists("pagerduty_event_orchestration_unrouted.unrouted"), + ), + }, + }, + }) +} + +func testAccCheckPagerDutyEventOrchestrationPathUnroutedDestroy(s *terraform.State) error { + client, _ := testAccProvider.Meta().(*Config).Client() + for _, r := range s.RootModule().Resources { + if r.Type != "pagerduty_event_orchestration_path_unrouted" { + continue + } + + orch := s.RootModule().Resources["pagerduty_event_orchestration.orch"] + + if _, _, err := client.EventOrchestrationPaths.Get(orch.Primary.ID, "unrouted"); err == nil { + return fmt.Errorf("Event Orchestration Path still exists") + } + } + return nil +} + +func testAccCheckPagerDutyEventOrchestrationPathUnroutedExists(rn string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[rn] + if !ok { + return fmt.Errorf("Not found: %s", rn) + } + if rs.Primary.ID == "" { + return fmt.Errorf("No Event Orchestration Unrouted Path is set") + } + + orch := s.RootModule().Resources["pagerduty_event_orchestration.orch"] + client, _ := testAccProvider.Meta().(*Config).Client() + _, _, err := client.EventOrchestrationPaths.Get(orch.Primary.ID, "unrouted") + + if err != nil { + return fmt.Errorf("Event Orchestration Unrouted Path not found: %v for orchestration %v", "unrouted", orch.Primary.ID) + } + + return nil + } +} + +func testAccCheckPagerDutyEventOrchestrationPathUnroutedNotExists(rn string) resource.TestCheckFunc { + return func(s *terraform.State) error { + _, ok := s.RootModule().Resources[rn] + if ok { + return fmt.Errorf("Event Orchestration Unrouted Path is not deleted: %s", rn) + } + + return nil + } +} + +func testAccCheckPagerDutyEventOrchestrationPathUnroutedConfigDelete(t, ep, s, o string) string { + return createUnroutedBaseConfig(t, ep, s, o) +} + +func createUnroutedBaseConfig(t, ep, s, o string) string { + return fmt.Sprintf(` + resource "pagerduty_team" "foo" { + name = "%s" + } + resource "pagerduty_user" "foo" { + name = "tf-user" + email = "user@pagerduty.com" + color = "green" + role = "user" + job_title = "foo" + description = "foo" + } + resource "pagerduty_escalation_policy" "foo" { + name = "%s" + description = "bar" + num_loops = 2 + rule { + escalation_delay_in_minutes = 10 + target { + type = "user_reference" + id = pagerduty_user.foo.id + } + } + } + resource "pagerduty_service" "bar" { + name = "%s" + escalation_policy = pagerduty_escalation_policy.foo.id + incident_urgency_rule { + type = "constant" + urgency = "high" + } + } + resource "pagerduty_event_orchestration" "orch" { + name = "%s" + team = pagerduty_team.foo.id + } + `, t, ep, s, o) +} + +func testAccCheckPagerDutyEventOrchestrationPathUnroutedConfigNoRules(t, ep, s, o string) string { + return fmt.Sprintf("%s%s", createUnroutedBaseConfig(t, ep, s, o), + `resource "pagerduty_event_orchestration_unrouted" "unrouted" { + event_orchestration = pagerduty_event_orchestration.orch.id + + set { + id = "start" + } + catch_all { + actions { } + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationPathUnroutedConfigWithConditions(t, ep, s, o string) string { + return fmt.Sprintf("%s%s", createUnroutedBaseConfig(t, ep, s, o), + `resource "pagerduty_event_orchestration_unrouted" "unrouted" { + event_orchestration = pagerduty_event_orchestration.orch.id + + set { + id = "start" + rule { + disabled = false + label = "rule1 label" + actions { } + condition { + expression = "event.summary matches part 'rds'" + } + } + } + catch_all { + actions { } + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationPathUnroutedConfigWithMultipleRules(t, ep, s, o string) string { + return fmt.Sprintf("%s%s", createUnroutedBaseConfig(t, ep, s, o), + `resource "pagerduty_event_orchestration_unrouted" "unrouted" { + event_orchestration = pagerduty_event_orchestration.orch.id + + set { + id = "start" + rule { + disabled = false + label = "rule1 label" + actions { } + condition { + expression = "event.summary matches part 'rds'" + } + condition { + expression = "event.severity matches part 'warning'" + } + } + + rule { + disabled = false + label = "rule2 label" + actions { } + condition { + expression = "event.severity matches part 'info'" + } + } + } + catch_all { + actions { } + } + } +`) +} + +func testAccCheckPagerDutyEventOrchestrationPathUnroutedWithAllConfig(t, ep, s, o string) string { + return fmt.Sprintf("%s%s", createUnroutedBaseConfig(t, ep, s, o), + `resource "pagerduty_event_orchestration_unrouted" "unrouted" { + event_orchestration = pagerduty_event_orchestration.orch.id + + set { + id = "start" + rule { + disabled = false + label = "rule1 label" + condition { + expression = "event.severity matches part 'info'" + } + condition { + expression = "event.severity matches part 'warning'" + } + actions { + route_to = "child-1" + severity = "info" + event_action = "trigger" + variable { + name = "server_name_cpu" + path = "event.summary" + type = "regex" + value = "High CPU on (.*) server" + } + variable { + name = "server_name_memory" + path = "event.custom_details" + type = "regex" + value = "High memory usage on (.*) server" + } + extraction { + target = "event.summary" + template = "High memory usage on {{variables.hostname}} server" + } + extraction { + target = "event.custom_details" + template = "High memory usage on {{variables.hostname}} server" + } + } + } + } + set { + id = "child-1" + rule { + disabled = false + label = "rule2 label1" + condition { + expression = "event.severity matches part 'warning'" + } + actions { + severity = "warning" + event_action = "resolve" + variable { + name = "server_name_cpu" + path = "event.summary" + type = "regex" + value = "High CPU on (.*) server" + } + extraction { + target = "event.summary" + template = "High CPU on {{event.custom_details.hostname}} server" + } + } + } + rule { + disabled = false + label = "rule2 label2" + condition { + expression = "event.severity matches part 'critical'" + } + actions { + severity = "warning" + event_action = "trigger" + variable { + name = "server_name_cpu" + path = "event.summary" + type = "regex" + value = "High CPU on (.*) server" + } + extraction { + target = "event.summary" + template = "High CPU on {{event.custom_details.hostname}} server" + } + } + } + } + catch_all { + actions { + severity = "critical" + event_action = "trigger" + variable { + name = "server_name_cpu" + path = "event.summary" + type = "regex" + value = "High CPU on (.*) server" + } + variable { + name = "server_name_memory" + path = "event.custom_details" + type = "regex" + value = "High memory usage on (.*) server" + } + extraction { + target = "event.summary" + template = "High memory usage on {{variables.hostname}} server" + } + extraction { + target = "event.custom_details" + template = "High memory usage on {{variables.hostname}} server" + } + } + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationPathUnroutedInvalidExtractionsConfig(t, ep, s, o, re, cae string) string { + return fmt.Sprintf( + "%s%s", + createUnroutedBaseConfig(t, ep, s, o), + fmt.Sprintf(`resource "pagerduty_event_orchestration_unrouted" "unrouted" { + event_orchestration = pagerduty_event_orchestration.orch.id + + set { + id = "start" + rule { + actions { + %s + } + } + } + catch_all { + actions { + %s + } + } + } + `, re, cae), + ) +} diff --git a/pagerduty/resource_pagerduty_event_orchestration_test.go b/pagerduty/resource_pagerduty_event_orchestration_test.go new file mode 100644 index 000000000..6e39fa640 --- /dev/null +++ b/pagerduty/resource_pagerduty_event_orchestration_test.go @@ -0,0 +1,245 @@ +package pagerduty + +import ( + "fmt" + "log" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func init() { + resource.AddTestSweepers("pagerduty_event_orchestration", &resource.Sweeper{ + Name: "pagerduty_event_orchestration", + F: testSweepEventOrchestration, + Dependencies: []string{ + "pagerduty_schedule", + "pagerduty_team", + "pagerduty_user", + "pagerduty_escalation_policy", + "pagerduty_service", + }, + }) +} + +func testSweepEventOrchestration(region string) error { + config, err := sharedConfigForRegion(region) + if err != nil { + return err + } + + client, err := config.Client() + if err != nil { + return err + } + + resp, _, err := client.EventOrchestrations.List() + if err != nil { + return err + } + + for _, orchestration := range resp.Orchestrations { + if strings.HasPrefix(orchestration.Name, "tf-orchestration-") { + log.Printf("Destroying Event Orchestration %s (%s)", orchestration.Name, orchestration.ID) + if _, err := client.EventOrchestrations.Delete(orchestration.ID); err != nil { + return err + } + } + } + + return nil +} + +func TestAccPagerDutyEventOrchestration_Basic(t *testing.T) { + name := fmt.Sprintf("tf-orchestration-%s", acctest.RandString(5)) + description := fmt.Sprintf("tf-description-%s", acctest.RandString(5)) + nameUpdated := fmt.Sprintf("tf-name-%s", acctest.RandString(5)) + descriptionUpdated := fmt.Sprintf("tf-description-%s", acctest.RandString(5)) + team1 := fmt.Sprintf("tf-team-%s", acctest.RandString(5)) + team2 := fmt.Sprintf("tf-team-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckPagerDutyEventOrchestrationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckPagerDutyEventOrchestrationConfigNameOnly(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationExists("pagerduty_event_orchestration.foo"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration.foo", "name", name, + ), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration.foo", "description", "", + ), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration.foo", "team.#", "0", + ), + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationConfig(name, description, team1, team2), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationExists("pagerduty_event_orchestration.foo"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration.foo", "name", name, + ), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration.foo", "description", description, + ), + testAccCheckPagerDutyEventOrchestrationTeamMatch("pagerduty_event_orchestration.foo", "pagerduty_team.foo"), + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationConfigUpdated(nameUpdated, descriptionUpdated, team1, team2), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationExists("pagerduty_event_orchestration.foo"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration.foo", "name", nameUpdated, + ), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration.foo", "description", descriptionUpdated, + ), + testAccCheckPagerDutyEventOrchestrationTeamMatch("pagerduty_event_orchestration.foo", "pagerduty_team.bar"), + ), + }, + { + Config: testAccCheckPagerDutyEventOrchestrationConfigDescriptionTeamDeleted(nameUpdated, team1, team2), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationExists("pagerduty_event_orchestration.foo"), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration.foo", "name", nameUpdated, + ), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration.foo", "description", "", + ), + resource.TestCheckResourceAttr( + "pagerduty_event_orchestration.foo", "team.#", "0", + ), + ), + }, + }, + }) +} + +func testAccCheckPagerDutyEventOrchestrationDestroy(s *terraform.State) error { + client, _ := testAccProvider.Meta().(*Config).Client() + for _, r := range s.RootModule().Resources { + if r.Type != "pagerduty_event_orchestration" { + continue + } + if _, _, err := client.EventOrchestrations.Get(r.Primary.ID); err == nil { + return fmt.Errorf("Event Orchestration still exists") + } + } + return nil +} + +func testAccCheckPagerDutyEventOrchestrationExists(rn string) resource.TestCheckFunc { + return func(s *terraform.State) error { + orch, ok := s.RootModule().Resources[rn] + if !ok { + return fmt.Errorf("Not found: %s", rn) + } + if orch.Primary.ID == "" { + return fmt.Errorf("No Event Orchestration ID is set") + } + + client, _ := testAccProvider.Meta().(*Config).Client() + found, _, err := client.EventOrchestrations.Get(orch.Primary.ID) + if err != nil { + return err + } + if found.ID != orch.Primary.ID { + return fmt.Errorf("Event Orchrestration not found: %v - %v", orch.Primary.ID, found) + } + + return nil + } +} + +func testAccCheckPagerDutyEventOrchestrationTeamMatch(orchName, teamName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + o, orchOk := s.RootModule().Resources[orchName] + + if !orchOk { + return fmt.Errorf("Not found: %s", orchName) + } + + t, tOk := s.RootModule().Resources[teamName] + if !tOk { + return fmt.Errorf("Not found: %s", teamName) + } + + var otId = o.Primary.Attributes["team"] + var tId = t.Primary.Attributes["id"] + + if otId != tId { + return fmt.Errorf("Event Orchestration team ID (%v) not matching provided team ID: %v", otId, tId) + } + + return nil + } +} + +func testAccCheckPagerDutyEventOrchestrationConfigNameOnly(n string) string { + return fmt.Sprintf(` + +resource "pagerduty_event_orchestration" "foo" { + name = "%s" +} +`, n) +} + +func testAccCheckPagerDutyEventOrchestrationConfig(name, description, team1, team2 string) string { + return fmt.Sprintf(` + +resource "pagerduty_team" "foo" { + name = "%s" +} +resource "pagerduty_team" "bar" { + name = "%s" +} +resource "pagerduty_event_orchestration" "foo" { + name = "%s" + description = "%s" + team = pagerduty_team.foo.id +} +`, team1, team2, name, description) +} + +func testAccCheckPagerDutyEventOrchestrationConfigUpdated(name, description, team1, team2 string) string { + return fmt.Sprintf(` + +resource "pagerduty_team" "foo" { + name = "%s" +} +resource "pagerduty_team" "bar" { + name = "%s" +} +resource "pagerduty_event_orchestration" "foo" { + name = "%s" + description = "%s" + team = pagerduty_team.bar.id +} +`, team1, team2, name, description) +} + +func testAccCheckPagerDutyEventOrchestrationConfigDescriptionTeamDeleted(name, team1, team2 string) string { + return fmt.Sprintf(` + +resource "pagerduty_team" "foo" { + name = "%s" +} +resource "pagerduty_team" "bar" { + name = "%s" +} +resource "pagerduty_event_orchestration" "foo" { + name = "%s" +} +`, team1, team2, name) +} diff --git a/pagerduty/util.go b/pagerduty/util.go index ea256a931..7689b8c45 100644 --- a/pagerduty/util.go +++ b/pagerduty/util.go @@ -145,3 +145,10 @@ func stringPtrToStringType(v *string) string { } return *v } + +func intTypeToIntPtr(v int) *int { + if v == 0 { + return nil + } + return &v +} diff --git a/vendor/github.com/heimweh/go-pagerduty/pagerduty/event_orchestration.go b/vendor/github.com/heimweh/go-pagerduty/pagerduty/event_orchestration.go new file mode 100644 index 000000000..0eeedbd5f --- /dev/null +++ b/vendor/github.com/heimweh/go-pagerduty/pagerduty/event_orchestration.go @@ -0,0 +1,127 @@ +package pagerduty + +import ( + "fmt" +) + +type EventOrchestrationService service + +type EventOrchestration struct { + ID string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Description string `json:"description"` + Team *EventOrchestrationObject `json:"team"` + Routes int `json:"routes,omitempty"` + Integrations []*EventOrchestrationIntegration `json:"integrations,omitempty"` +} + +type EventOrchestrationObject struct { + Type string `json:"type,omitempty"` + ID *string `json:"id"` +} + +type EventOrchestrationIntegrationParameters struct { + RoutingKey string `json:"routing_key,omitempty"` + Type string `json:"type,omitempty"` +} + +type EventOrchestrationIntegration struct { + ID string `json:"id,omitempty"` + Parameters *EventOrchestrationIntegrationParameters `json:"parameters,omitempty"` +} + +type EventOrchestrationPayload struct { + Orchestration *EventOrchestration `json:"orchestration,omitempty"` +} + +type ListEventOrchestrationsResponse struct { + Total int `json:"total,omitempty"` + Offset int `json:"offset,omitempty"` + More bool `json:"more,omitempty"` + Limit int `json:"limit,omitempty"` + Orchestrations []*EventOrchestration `json:"orchestrations,omitempty"` +} + +var eventOrchestrationBaseUrl = "/event_orchestrations" + +func (s *EventOrchestrationService) List() (*ListEventOrchestrationsResponse, *Response, error) { + v := new(ListEventOrchestrationsResponse) + v.Total = 0 + + orchestrations := make([]*EventOrchestration, 0) + + // Create a handler closure capable of parsing data from the event orchestrations endpoint + // and appending resultant orchestrations to the return slice. + responseHandler := func(response *Response) (ListResp, *Response, error) { + var result ListEventOrchestrationsResponse + + if err := s.client.DecodeJSON(response, &result); err != nil { + return ListResp{}, response, err + } + + v.Total += result.Total + v.Offset = result.Offset + v.More = result.More + v.Limit = result.Limit + orchestrations = append(orchestrations, result.Orchestrations...) + + // Return stats on the current page. Caller can use this information to + // adjust for requesting additional pages. + return ListResp{ + More: result.More, + Offset: result.Offset, + Limit: result.Limit, + }, response, nil + } + err := s.client.newRequestPagedGetDo(eventOrchestrationBaseUrl, responseHandler) + if err != nil { + return nil, nil, err + } + v.Orchestrations = orchestrations + + return v, nil, nil +} + +func (s *EventOrchestrationService) Create(orchestration *EventOrchestration) (*EventOrchestration, *Response, error) { + v := new(EventOrchestrationPayload) + p := &EventOrchestrationPayload{Orchestration: orchestration} + + resp, err := s.client.newRequestDo("POST", eventOrchestrationBaseUrl, nil, p, v) + + if err != nil { + return nil, nil, err + } + + return v.Orchestration, resp, nil +} + +func (s *EventOrchestrationService) Get(ID string) (*EventOrchestration, *Response, error) { + u := fmt.Sprintf("%s/%s", eventOrchestrationBaseUrl, ID) + v := new(EventOrchestrationPayload) + p := &EventOrchestrationPayload{} + + resp, err := s.client.newRequestDo("GET", u, nil, p, v) + if err != nil { + return nil, nil, err + } + + return v.Orchestration, resp, nil +} + +func (s *EventOrchestrationService) Update(ID string, orchestration *EventOrchestration) (*EventOrchestration, *Response, error) { + u := fmt.Sprintf("%s/%s", eventOrchestrationBaseUrl, ID) + v := new(EventOrchestrationPayload) + p := &EventOrchestrationPayload{Orchestration: orchestration} + + resp, err := s.client.newRequestDo("PUT", u, nil, p, v) + if err != nil { + return nil, nil, err + } + + return v.Orchestration, resp, nil +} + +func (s *EventOrchestrationService) Delete(ID string) (*Response, error) { + u := fmt.Sprintf("%s/%s", eventOrchestrationBaseUrl, ID) + return s.client.newRequestDo("DELETE", u, nil, nil, nil) +} diff --git a/vendor/github.com/heimweh/go-pagerduty/pagerduty/event_orchestration_path.go b/vendor/github.com/heimweh/go-pagerduty/pagerduty/event_orchestration_path.go new file mode 100644 index 000000000..ddc7e0091 --- /dev/null +++ b/vendor/github.com/heimweh/go-pagerduty/pagerduty/event_orchestration_path.go @@ -0,0 +1,147 @@ +package pagerduty + +import ( + "fmt" +) + +type EventOrchestrationPathService service + +type EventOrchestrationPath struct { + Type string `json:"type,omitempty"` + Self string `json:"self,omitempty"` + Parent *EventOrchestrationPathReference `json:"parent,omitempty"` + Sets []*EventOrchestrationPathSet `json:"sets,omitempty"` + CatchAll *EventOrchestrationPathCatchAll `json:"catch_all,omitempty"` + CreatedAt string `json:"created_at,omitempty"` + CreatedBy *EventOrchestrationPathReference `json:"created_by,omitempty"` + UpdatedAt string `json:"updated_at,omitempty"` + UpdatedBy *EventOrchestrationPathReference `json:"updated_by,omitempty"` + Version string `json:"version,omitempty"` +} + +// A reference to a related object (e.g. an EventOrchestration, User, Team, etc) +type EventOrchestrationPathReference struct { + ID string `json:"id,omitempty"` + Type string `json:"type,omitempty"` + Self string `json:"self,omitempty"` +} + +type EventOrchestrationPathSet struct { + ID string `json:"id,omitempty"` + Rules []*EventOrchestrationPathRule `json:"rules"` +} + +type EventOrchestrationPathRule struct { + ID string `json:"id,omitempty"` + Label string `json:"label,omitempty"` + Conditions []*EventOrchestrationPathRuleCondition `json:"conditions"` + Actions *EventOrchestrationPathRuleActions `json:"actions,omitempty"` + Disabled bool `json:"disabled,omitempty"` +} + +type EventOrchestrationPathRuleCondition struct { + // A PCL string: https://developer.pagerduty.com/docs/ZG9jOjM1NTE0MDc0-pcl-overview + Expression string `json:"expression,omitempty"` +} + +// See the full list of supported actions for path types: +// Router: https://developer.pagerduty.com/api-reference/f0fae270c70b3-get-the-router-for-a-global-event-orchestration +// Service: https://developer.pagerduty.com/api-reference/179537b835e2d-get-the-service-orchestration-for-a-service +// Unrouted: https://developer.pagerduty.com/api-reference/70aa1139e1013-get-the-unrouted-orchestration-for-a-global-event-orchestration +type EventOrchestrationPathRuleActions struct { + RouteTo string `json:"route_to"` + Suppress bool `json:"suppress"` + Suspend *int `json:"suspend"` + Priority string `json:"priority"` + Annotate string `json:"annotate"` + PagerdutyAutomationActions []*EventOrchestrationPathPagerdutyAutomationAction `json:"pagerduty_automation_actions"` + AutomationActions []*EventOrchestrationPathAutomationAction `json:"automation_actions"` + Severity string `json:"severity"` + EventAction string `json:"event_action"` + Variables []*EventOrchestrationPathActionVariables `json:"variables"` + Extractions []*EventOrchestrationPathActionExtractions `json:"extractions"` +} + +type EventOrchestrationPathPagerdutyAutomationAction struct { + ActionId string `json:"action_id,omitempty"` +} + +type EventOrchestrationPathAutomationAction struct { + Name string `json:"name,omitempty"` + Url string `json:"url,omitempty"` + AutoSend bool `json:"auto_send,omitempty"` + Headers []*EventOrchestrationPathAutomationActionObject `json:"headers"` + Parameters []*EventOrchestrationPathAutomationActionObject `json:"parameters"` +} + +type EventOrchestrationPathAutomationActionObject struct { + Key string `json:"key,omitempty"` + Value string `json:"value,omitempty"` +} + +type EventOrchestrationPathActionVariables struct { + Name string `json:"name,omitempty"` + Path string `json:"path,omitempty"` + Type string `json:"type,omitempty"` + Value string `json:"value,omitempty"` +} + +type EventOrchestrationPathActionExtractions struct { + Target string `json:"target,omitempty"` + Regex string `json:"regex,omitempty"` + Template string `json:"template,omitempty"` + Source string `json:"source,omitempty"` +} + +type EventOrchestrationPathCatchAll struct { + Actions *EventOrchestrationPathRuleActions `json:"actions,omitempty"` +} + +type EventOrchestrationPathPayload struct { + OrchestrationPath *EventOrchestrationPath `json:"orchestration_path,omitempty"` +} + +const PathTypeRouter string = "router" +const PathTypeService string = "service" +const PathTypeUnrouted string = "unrouted" + +func orchestrationPathUrlBuilder(id string, pathType string) string { + switch { + case pathType == PathTypeService: + return fmt.Sprintf("%s/services/%s", eventOrchestrationBaseUrl, id) + case pathType == PathTypeUnrouted: + return fmt.Sprintf("%s/%s/unrouted", eventOrchestrationBaseUrl, id) + case pathType == PathTypeRouter: + return fmt.Sprintf("%s/%s/router", eventOrchestrationBaseUrl, id) + default: + return "" + } +} + +// Get for EventOrchestrationPath +func (s *EventOrchestrationPathService) Get(id string, pathType string) (*EventOrchestrationPath, *Response, error) { + u := orchestrationPathUrlBuilder(id, pathType) + v := new(EventOrchestrationPathPayload) + + resp, err := s.client.newRequestDo("GET", u, nil, nil, &v) + + if err != nil { + return nil, nil, err + } + + return v.OrchestrationPath, resp, nil +} + +// Update for EventOrchestrationPath +func (s *EventOrchestrationPathService) Update(id string, pathType string, orchestration_path *EventOrchestrationPath) (*EventOrchestrationPath, *Response, error) { + u := orchestrationPathUrlBuilder(id, pathType) + v := new(EventOrchestrationPathPayload) + p := EventOrchestrationPathPayload{OrchestrationPath: orchestration_path} + + resp, err := s.client.newRequestDo("PUT", u, nil, p, &v) + if err != nil { + return nil, nil, err + } + + return v.OrchestrationPath, resp, nil +} diff --git a/vendor/github.com/heimweh/go-pagerduty/pagerduty/pagerduty.go b/vendor/github.com/heimweh/go-pagerduty/pagerduty/pagerduty.go index e3dbbaf8f..f25b916d7 100644 --- a/vendor/github.com/heimweh/go-pagerduty/pagerduty/pagerduty.go +++ b/vendor/github.com/heimweh/go-pagerduty/pagerduty/pagerduty.go @@ -41,6 +41,8 @@ type Client struct { Extensions *ExtensionService MaintenanceWindows *MaintenanceWindowService Rulesets *RulesetService + EventOrchestrations *EventOrchestrationService + EventOrchestrationPaths *EventOrchestrationPathService Schedules *ScheduleService Services *ServicesService Teams *TeamService @@ -99,6 +101,8 @@ func NewClient(config *Config) (*Client, error) { c.EscalationPolicies = &EscalationPolicyService{c} c.MaintenanceWindows = &MaintenanceWindowService{c} c.Rulesets = &RulesetService{c} + c.EventOrchestrations = &EventOrchestrationService{c} + c.EventOrchestrationPaths = &EventOrchestrationPathService{c} c.Schedules = &ScheduleService{c} c.Services = &ServicesService{c} c.Teams = &TeamService{c} diff --git a/vendor/go.mongodb.org/mongo-driver/mongo/options/datakeyoptions.go b/vendor/go.mongodb.org/mongo-driver/mongo/options/datakeyoptions.go index 3da8f652a..c6a17f9e0 100644 --- a/vendor/go.mongodb.org/mongo-driver/mongo/options/datakeyoptions.go +++ b/vendor/go.mongodb.org/mongo-driver/mongo/options/datakeyoptions.go @@ -22,7 +22,7 @@ func DataKey() *DataKeyOptions { // If being used with a local KMS provider, this option is not applicable and should not be specified. // // For the AWS, Azure, and GCP KMS providers, this option is required and must be a document. For each, the value of the -// "endpoint" or "keyVaultEndpoint" must be a host name with an optional port number (e.g. "foo.test" or "foo.test:443"). +// "endpoint" or "keyVaultEndpoint" must be a host name with an optional port number (e.g. "foo.com" or "foo.com:443"). // // When using AWS, the document must have the format: // { diff --git a/vendor/modules.txt b/vendor/modules.txt index 8f52ef197..0fd9953e9 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -124,7 +124,7 @@ github.com/hashicorp/terraform-registry-address github.com/hashicorp/terraform-svchost # github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d github.com/hashicorp/yamux -# github.com/heimweh/go-pagerduty v0.0.0-20220422231448-43095fe5ba3f +# github.com/heimweh/go-pagerduty v0.0.0-20220527195341-4e587aa9b58e ## explicit github.com/heimweh/go-pagerduty/pagerduty # github.com/klauspost/compress v1.11.2 diff --git a/website/docs/d/event_orchestration.html.markdown b/website/docs/d/event_orchestration.html.markdown new file mode 100644 index 000000000..e9cb650ca --- /dev/null +++ b/website/docs/d/event_orchestration.html.markdown @@ -0,0 +1,60 @@ +--- +layout: "pagerduty" +page_title: "PagerDuty: pagerduty_event_orchestration" +sidebar_current: "docs-pagerduty-datasource-event-orchestration" +description: |- + Get information about a Global Event Orchestration that you have created. +--- + +# pagerduty\_event_orchestration + +Use this data source to get information about a specific Global [Event Orchestration][1] + +## Example Usage +```hcl +resource "pagerduty_event_orchestration" "tf_orch_a" { + name = "Test Event Orchestration" +} + +data "pagerduty_event_orchestration" "tf_my_monitor" { + name = pagerduty_event_orchestration.tf_orch_a.name +} + +resource "pagerduty_event_orchestration_router" "router" { + parent { + id = data.pagerduty_event_orchestration.tf_my_monitor.id + } + catch_all { + actions { + route_to = "unrouted" + } + } + set { + id = "start" + rule { + actions { + route_to = pagerduty_service.db.id + } + } + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the Global Event orchestration to find in the PagerDuty API. + +## Attributes Reference + +* `id` - The ID of the found Event Orchestration. +* `name` - The name of the found Event Orchestration. +* `integration` - An integration for the Event Orchestration. + * `id` - ID of the integration + * `parameters` + * `routing_key` - Routing key that routes to this Orchestration. + * `type` - Type of the routing key. `global` is the default type. + + +[1]: https://developer.pagerduty.com/api-reference/7ba0fe7bdb26a-list-event-orchestrations diff --git a/website/docs/r/event_orchestration.html.markdown b/website/docs/r/event_orchestration.html.markdown new file mode 100644 index 000000000..1fcb07d33 --- /dev/null +++ b/website/docs/r/event_orchestration.html.markdown @@ -0,0 +1,52 @@ +--- +layout: "pagerduty" +page_title: "PagerDuty: pagerduty_event_orchestration" +sidebar_current: "docs-pagerduty-resource-event-orchestration" +description: |- + Creates and manages a Global Event Orchestration in PagerDuty. +--- + +# pagerduty_event_orchestration + +[Global Event Orchestrations](https://support.pagerduty.com/docs/event-orchestration#global-orchestrations) allow you define a set of Event Rules, so that when you ingest events using the Orchestration's Routing Key your events will be routed to the correct Service, based on the event's content. + +## Example of configuring a Global Event Orchestration + +```hcl +resource "pagerduty_team" "engineering" { + name = "Engineering" +} + +resource "pagerduty_event_orchestration" "my_monitor" { + name = "My Monitoring Orchestration" + description = "Send events to a pair of services" + team = pagerduty_team.engineering.id +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) Name of the Event Orchestration. +* `description` - (Optional) A human-friendly description of the Event Orchestration. +* `team` - (Optional) ID of the team that owns the Event Orchestration. If none is specified, only admins have access. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The ID of the Event Orchestration. +* `integration` - An integration for the Event Orchestration. + * `id` - ID of the integration + * `parameters` + * `routing_key` - Routing key that routes to this Orchestration. + * `type` - Type of the routing key. `global` is the default type. + +## Import + +EventOrchestrations can be imported using the `id`, e.g. + +``` +$ terraform import pagerduty_event_orchestration.main 19acac92-027a-4ea0-b06c-bbf516519601 +``` diff --git a/website/docs/r/event_orchestration_router.html.markdown b/website/docs/r/event_orchestration_router.html.markdown new file mode 100644 index 000000000..822588006 --- /dev/null +++ b/website/docs/r/event_orchestration_router.html.markdown @@ -0,0 +1,93 @@ +--- +layout: "pagerduty" +page_title: "PagerDuty: pagerduty_event_orchestration_router" +sidebar_current: "docs-pagerduty-resource-event-orchestration-router" +description: |- + Creates and manages a Router for Global Event Orchestration in PagerDuty. +--- + +# pagerduty_event_orchestration_router + +An Orchestration Router allows users to create a set of Event Rules. The Router evaluates events sent to this Orchestration against each of its rules, one at a time, and routes the event to a specific Service based on the first rule that matches. If an event doesn't match any rules, it'll be sent to service specified in the `catch_all` or to the "Unrouted" Orchestration if no service is specified. + +## Example of configuring Router rules for an Orchestration + +In this example the user has defined the Router with two rules, each routing to a different service. + +This example assumes services used in the `route_to` configuration already exists. So it does not show creation of service resource. + +```hcl +resource "pagerduty_event_orchestration_router" "router" { + event_orchestration = pagerduty_event_orchestration.my_monitor.id + set { + rule { + label = "Events relating to our relational database" + condition { + expression = "event.summary matches part 'database'" + } + condition { + expression = "event.source matches regex 'db[0-9]+-server'" + } + actions { + route_to = pageduty_service.database.id + } + } + rule { + condition { + expression = "event.summary matches part 'www'" + } + actions { + route_to = pagerduty_service.www.id + } + } + } + catch_all { + actions { + route_to = "unrouted" + } + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `event_orchestration` - (Required) ID of the Event Orchestration to which the Router belongs. +* `set` - (Required) The Router contains a single set of rules (the "start" set). +* `catch_all` - (Required) When none of the rules match an event, the event will be routed according to the catch_all settings. + +### Set (`set`) supports the following: +* `id` - (Required) ID of the `start` set. Router supports only one set and it's id has to be `start` +* `rule` - (Optional) The Router evaluates Events against these Rules, one at a time, and routes each Event to a specific Service based on the first rule that matches. If no rules are provided as part of Terraform configuration, the API returns empty list of rules. + +### Rule (`rule`) supports the following: +* `label` - (Optional) A description of this rule's purpose. +* `condition` - (Optional) Each of these conditions is evaluated to check if an event matches this rule. The rule is considered a match if any of these conditions match. If none are provided, the event will _always_ match against the rule. +* `actions` - (Required) Actions that will be taken to change the resulting alert and incident, when an event matches this rule. +* `disabled` - (Optional) Indicates whether the rule is disabled and would therefore not be evaluated. + +### Condition (`condition`) supports the following: +* `expression`- (Required) A [PCL condition](https://developer.pagerduty.com/docs/ZG9jOjM1NTE0MDc0-pcl-overview) string. + +### Actions (`actions`) supports the following: +* `route_to` - (Required) The ID of the target Service for the resulting alert. + +### Catch All (`catch_all`) supports the following: +* `actions` - (Required) These are the actions that will be taken to change the resulting alert and incident. + * `route_to` - (Required) Defines where an alert will be sent if doesn't match any rules. Can either be the ID of a Service _or_ the string `"unrouted"` to send events to the Unrouted Orchestration. + +## Attributes Reference + +The following attributes are exported: +* `self` - The URL at which the Router Orchestration is accessible. +* `rule` + * `id` - The ID of the rule within the `start` set. + +## Import + +Router can be imported using the `id` of the Event Orchestration, e.g. + +``` +$ terraform import pagerduty_event_orchestration_router 1b49abe7-26db-4439-a715-c6d883acfb3e +``` diff --git a/website/docs/r/event_orchestration_service.html.markdown b/website/docs/r/event_orchestration_service.html.markdown new file mode 100644 index 000000000..cda7a031d --- /dev/null +++ b/website/docs/r/event_orchestration_service.html.markdown @@ -0,0 +1,215 @@ +--- +layout: "pagerduty" +page_title: "PagerDuty: pagerduty_event_orchestration_service" +sidebar_current: "docs-pagerduty-resource-event-orchestration-service" +description: |- + Creates and manages a Service Orchestration for a Service. +--- + +# pagerduty_event_orchestration_service + +A [Service Orchestration](https://support.pagerduty.com/docs/event-orchestration#service-orchestrations) allows you to create a set of Event Rules. The Service Orchestration evaluates Events sent to this Service against each of its rules, beginning with the rules in the "start" set. When a matching rule is found, it can modify and enhance the event and can route the event to another set of rules within this Service Orchestration for further processing. + +**Note:** If you have a Service that uses [Service Event Rules](https://support.pagerduty.com/docs/rulesets#service-event-rules), you can switch to [Service Orchestrations](https://support.pagerduty.com/docs/event-orchestration#service-orchestrations) at any time. Please read the [Switch to Service Orchestrations](https://support.pagerduty.com/docs/event-orchestration#switch-to-service-orchestrations) instructions for more information. + +## Example of configuring a Service Orchestration + +This example shows creating `Team`, `User`, `Escalation Policy`, and `Service` resources followed by creating a Service Orchestration to handle Events sent to that Service. + +This example also shows using `priority` [data source](https://registry.terraform.io/providers/PagerDuty/pagerduty/latest/docs/data-sources/priority) to configure `priority` action for a rule. If the Event matches the first rule in set "step-two" the resulting incident will have the Priority `P1`. + +This example shows a Service Orchestration that has nested sets: a rule in the "start" set has a `route_to` action pointing at the "step-two" set. + +The `catch_all` actions will be applied if an Event reaches the end of any set without matching any rules in that set. In this example the `catch_all` doesn't have any `actions` so it'll leave events as-is. + + +```hcl +resource "pagerduty_team" "engineering" { + name = "Engineering" +} + +resource "pagerduty_user" "example" { + name = "Earline Greenholt" + email = "125.greenholt.earline@graham.name" + teams = [pagerduty_team.engineering.id] +} + +resource "pagerduty_escalation_policy" "foo" { + name = "Engineering Escalation Policy" + num_loops = 2 + + rule { + escalation_delay_in_minutes = 10 + target { + type = "user" + id = pagerduty_user.example.id + } + } +} + +resource "pagerduty_service" "example" { + name = "My Web App" + auto_resolve_timeout = 14400 + acknowledgement_timeout = 600 + escalation_policy = pagerduty_escalation_policy.example.id + alert_creation = "create_alerts_and_incidents" +} + +data "pagerduty_priority" "p1" { + name = "P1" +} + +resource "pagerduty_event_orchestration_service" "www" { + service = pagerduty_service.example.id + set { + id = "start" + rule { + label = "Always apply some consistent event transformations to all events" + actions { + variable { + name = "hostname" + path = "event.component" + value = "hostname: (.*)" + type = "regex" + } + extraction { + # Demonstrating a template-style extraction + template = "{{variables.hostname}}" + target = "event.custom_details.hostname" + } + extraction { + # Demonstrating a regex-style extraction + source = "event.source" + regex = "www (.*) service" + target = "event.source" + } + # Id of the next set + route_to = "step-two" + } + } + } + set { + id = "step-two" + rule { + label = "All critical alerts should be treated as P1 incident" + condition { + expression = "event.severity matches 'critical'" + } + actions { + annotate = "Please use our P1 runbook: https://docs.test/p1-runbook" + priority = data.pagerduty_priority.p1.id + } + } + rule { + label = "If there's something wrong on the canary let the team know about it in our deployments Slack channel" + condition { + expression = "event.custom_details.hostname matches part 'canary'" + } + # create webhook action with parameters and headers + actions { + automation_action { + name = "Canary Slack Notification" + url = "https://our-slack-listerner.test/canary-notification" + auto_send = true + parameter { + key = "channel" + value = "#my-team-channel" + } + parameter { + key = "message" + value = "something is wrong with the canary deployment" + } + header { + key = "X-Notification-Source" + value = "PagerDuty Incident Webhook" + } + } + } + } + rule { + label = "Never bother the on-call for info-level events outside of work hours" + condition { + expression = "event.severity matches 'info' and not (now in Mon,Tue,Wed,Thu,Fri 09:00:00 to 17:00:00 America/Los_Angeles)" + } + actions { + suppress = true + } + } + } + catch_all { + actions { } + } +} +``` +## Argument Reference + +The following arguments are supported: + +* `service` - (Required) ID of the Service to which this Service Orchestration belongs to. +* `set` - (Required) A Service Orchestration must contain at least a "start" set, but can contain any number of additional sets that are routed to by other rules to form a directional graph. +* `catch_all` - (Required) the `catch_all` actions will be applied if an Event reaches the end of any set without matching any rules in that set. + +### Set (`set`) supports the following: +* `id` - (Required) The ID of this set of rules. Rules in other sets can route events into this set using the rule's `route_to` property. +* `rule` - (Optional) The service orchestration evaluates Events against these Rules, one at a time, and applies all the actions for first rule it finds where the event matches the rule's conditions. If no rules are provided as part of Terraform configuration, the API returns empty list of rules. + +### Rule (`rule`) supports the following: +* `label` - (Optional) A description of this rule's purpose. +* `condition` - (Optional) Each of these conditions is evaluated to check if an event matches this rule. The rule is considered a match if any of these conditions match. If none are provided, the event will `always` match against the rule. +* `actions` - (Required) Actions that will be taken to change the resulting alert and incident, when an event matches this rule. +* `disabled` - (Optional) Indicates whether the rule is disabled and would therefore not be evaluated. + +### Condition (`condition`) supports the following: +* `expression`- (Required) A [PCL condition](https://developer.pagerduty.com/docs/ZG9jOjM1NTE0MDc0-pcl-overview) string. + +### Actions (`actions`) supports the following: +* `route_to` - (Optional) The ID of a Set from this Service Orchestration whose rules you also want to use with event that match this rule. +* `suppress` - (Optional) Set whether the resulting alert is suppressed. Suppressed alerts will not trigger an incident. +* `suspend` - (Optional) The number of seconds to suspend the resulting alert before triggering. This effectively pauses incident notifications. If a `resolve` event arrives before the alert triggers then PagerDuty won't create an incident for this the resulting alert. +* `priority` - (Optional) The ID of the priority you want to set on resulting incident. Consider using the [`pagerduty_priority`](https://registry.terraform.io/providers/PagerDuty/pagerduty/latest/docs/data-sources/priority) data source. +* `annotate` - (Optional) Add this text as a note on the resulting incident. +* `pagerduty_automation_action` - (Optional) Configure a [Process Automation](https://support.pagerduty.com/docs/event-orchestration#process-automation) associated with the resulting incident. + * `action_id` - (Required) Id of the Process Automation action to be triggered. +* `automation_action` - (Optional) Create a [Webhook](https://support.pagerduty.com/docs/event-orchestration#webhooks) associated with the resulting incident. + * `name` - (Required) Name of this Webhook. + * `url` - (Required) The API endpoint where PagerDuty's servers will send the webhook request. + * `auto_send` - (Optional) When true, PagerDuty's servers will automatically send this webhook request as soon as the resulting incident is created. When false, your incident responder will be able to manually trigger the Webhook via the PagerDuty website and mobile app. + * `header` - (Optional) Specify custom key/value pairs that'll be sent with the webhook request as request headers. + * `key` - (Required) Name to identify the header + * `value` - (Required) Value of this header + * `parameter` - (Optional) Specify custom key/value pairs that'll be included in the webhook request's JSON payload. + * `key` - (Required) Name to identify the parameter + * `value` - (Required) Value of this parameter +* `severity` - (Optional) sets Severity of the resulting alert. Allowed values are: `info`, `error`, `warning`, `critical` +* `event_action` - (Optional) sets whether the resulting alert status is trigger or resolve. Allowed values are: `trigger`, `resolve` +* `variable` - (Optional) Populate variables from event payloads and use those variables in other event actions. + * `name` - (Required) The name of the variable + * `path` - (Required) Path to a field in an event, in dot-notation. This supports both PagerDuty Common Event Format [PD-CEF](https://support.pagerduty.com/docs/pd-cef) and non-CEF fields. Eg: Use `event.summary` for the `summary` CEF field. Use `raw_event.fieldname` to read from the original event `fieldname` data. You can use any valid [PCL path](https://developer.pagerduty.com/docs/ZG9jOjM1NTE0MDc0-pcl-overview#paths). + * `type` - (Required) Only `regex` is supported + * `value` - (Required) The Regex expression to match against. Must use valid [RE2 regular expression](https://github.com/google/re2/wiki/Syntax) syntax. +* `extraction` - (Optional) Replace any CEF field or Custom Details object field using custom variables. + * `target` - (Required) The PagerDuty Common Event Format [PD-CEF](https://support.pagerduty.com/docs/pd-cef) field that will be set with the value from the `template` or based on `regex` and `source` fields. + * `template` - (Optional) A string that will be used to populate the `target` field. You can reference variables or event data within your template using double curly braces. For example: + * Use variables named `ip` and `subnet` with a template like: `{{variables.ip}}/{{variables.subnet}}` + * Combine the event severity & summary with template like: `{{event.severity}}:{{event.summary}}` + * `regex` - (Optional) A [RE2 regular expression](https://github.com/google/re2/wiki/Syntax) that will be matched against field specified via the `source` argument. If the regex contains one or more capture groups, their values will be extracted and appended together. If it contains no capture groups, the whole match is used. This field can be ignored for `template` based extractions. + * `source` - (Optional) The path to the event field where the `regex` will be applied to extract a value. You can use any valid [PCL path](https://developer.pagerduty.com/docs/ZG9jOjM1NTE0MDc0-pcl-overview#paths) like `event.summary` and you can reference previously-defined variables using a path like `variables.hostname`. This field can be ignored for `template` based extractions. + +### Catch All (`catch_all`) supports the following: +* `actions` - (Required) These are the actions that will be taken to change the resulting alert and incident. `catch_all` supports all actions described above for `rule` _except_ `route_to` action. + + +## Attributes Reference + +The following attributes are exported: +* `self` - The URL at which the Service Orchestration is accessible. +* `rule` + * `id` - The ID of the rule within the set. + +## Import + +Service Orchestration can be imported using the `id` of the Service, e.g. + +``` +$ terraform import pagerduty_event_orchestration_service PFEODA7 +``` diff --git a/website/docs/r/event_orchestration_unrouted.html.markdown b/website/docs/r/event_orchestration_unrouted.html.markdown new file mode 100644 index 000000000..0ae8f084d --- /dev/null +++ b/website/docs/r/event_orchestration_unrouted.html.markdown @@ -0,0 +1,102 @@ +--- +layout: "pagerduty" +page_title: "PagerDuty: pagerduty_event_orchestration_unrouted" +sidebar_current: "docs-pagerduty-resource-event-orchestration-unrouted" +description: |- + Creates and manages an Unrouted Orchestration for a Global Event Orchestration in PagerDuty. +--- + +# pagerduty_event_orchestration_unrouted + +An Unrouted Orchestration allows users to create a set of Event Rules that will be evaluated against all events that don't match any rules in the Orchestration's Router. + +The Unrouted Orchestration evaluates events sent to it against each of its rules, beginning with the rules in the "start" set. When a matching rule is found, it can modify and enhance the event and can route the event to another set of rules within this Unrouted Orchestration for further processing. + +## Example of configuring Unrouted Rules for an Orchestration + +In this example of an Unrouted Orchestration, the rule matches only if the condition is matched. +Alerts created for events that do not match the rule will have severity level set to `info` as defined in `catch_all` block. + +```hcl +resource "pagerduty_event_orchestration_unrouted" "unrouted" { + event_orchestration = pagerduty_event_orchestration.my_monitor.id + set { + id = "start" + rule { + label = "Update the summary of un-matched Critical alerts so they're easier to spot" + condition { + expression = "event.severity matches 'critical'" + } + actions { + severity = "critical" + extraction { + target = "event.summary" + template = "[Critical Unrouted] {{event.summary}}" + } + } + } + } + catch_all { + actions { + severity = "info" + } + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `event_orchestration` - (Required) The Event Orchestration to which this Unrouted Orchestration belongs to. +* `set` - (Required) An Unrouted Orchestration must contain at least a "start" set, but can contain any number of additional sets that are routed to by other rules to form a directional graph. +* `catch_all` - (Required) the `catch_all` actions will be applied if an Event reaches the end of any set without matching any rules in that set. + +### Set (`set`) supports the following: +* `id` - (Required) The ID of this set of rules. Rules in other sets can route events into this set using the rule's `route_to` property. +* `rule` - (Optional) The Unrouted Orchestration evaluates Events against these Rules, one at a time, and applies all the actions for first rule it finds where the event matches the rule's conditions. If no rules are provided as part of Terraform configuration, the API returns empty list of rules. + +### Rule (`rule`) supports the following: +* `label` - (Optional) A description of this rule's purpose. +* `condition` - (Optional) Each of these conditions is evaluated to check if an event matches this rule. The rule is considered a match if any of these conditions match. If none are provided, the event will `always` match against the rule. +* `actions` - (Required) Actions that will be taken to change the resulting alert and incident, when an event matches this rule. +* `disabled` - (Optional) Indicates whether the rule is disabled and would therefore not be evaluated. + +### Condition (`condition`) supports the following: +* `expression`- (Required) A [PCL condition](https://developer.pagerduty.com/docs/ZG9jOjM1NTE0MDc0-pcl-overview) string. + +### Actions (`actions`) supports the following: +* `route_to` - (Optional) The ID of a Set from this Unrouted Orchestration whose rules you also want to use with event that match this rule. +* `severity` - (Optional) sets Severity of the resulting alert. Allowed values are: `info`, `error`, `warning`, `critical` +* `event_action` - (Optional) sets whether the resulting alert status is trigger or resolve. Allowed values are: `trigger`, `resolve` +* `variable` - (Optional) Populate variables from event payloads and use those variables in other event actions. + * `name` - (Required) The name of the variable + * `path` - (Required) Path to a field in an event, in dot-notation. This supports both [PD-CEF](https://support.pagerduty.com/docs/pd-cef) and non-CEF fields. Eg: Use `event.summary` for the `summary` CEF field. Use `raw_event.fieldname` to read from the original event `fieldname` data. + * `type` - (Required) Only `regex` is supported + * `value` - (Required) The Regex expression to match against. Must use valid [RE2 regular expression](https://github.com/google/re2/wiki/Syntax) syntax. +* `extraction` - (Optional) Replace any CEF field or Custom Details object field using custom variables. + * `target` - (Required) The PagerDuty Common Event Format [PD-CEF](https://support.pagerduty.com/docs/pd-cef) field that will be set with the value from the `template` or based on `regex` and `source` fields. + * `template` - (Optional) A string that will be used to populate the `target` field. You can reference variables or event data within your template using double curly braces. For example: + * Use variables named `ip` and `subnet` with a template like: `{{variables.ip}}/{{variables.subnet}}` + * Combine the event severity & summary with template like: `{{event.severity}}:{{event.summary}}` + * `target` - (Required) The PagerDuty Common Event Format [PD-CEF](https://support.pagerduty.com/docs/pd-cef) field that will be set with the value from the `template` or based on `regex` and `source` fields. + * `regex` - (Optional) A [RE2 regular expression](https://github.com/google/re2/wiki/Syntax) that will be matched against field specified via the `source` argument. If the regex contains one or more capture groups, their values will be extracted and appended together. If it contains no capture groups, the whole match is used. This field can be ignored for `template` based extractions. + * `source` - (Optional) The path to the event field where the `regex` will be applied to extract a value. You can use any valid [PCL path](https://developer.pagerduty.com/docs/ZG9jOjM1NTE0MDc0-pcl-overview#paths) like `event.summary` and you can reference previously-defined variables using a path like `variables.hostname`. This field can be ignored for `template` based extractions. + +### Catch All (`catch_all`) supports the following: +* `actions` - (Required) These are the actions that will be taken to change the resulting alert and incident. `catch_all` supports all actions described above for `rule` _except_ `route_to` action. + +## Attributes Reference + +The following attributes are exported: +* `self` - The URL at which the Unrouted Event Orchestration is accessible. +* `rule` + * `id` - The ID of the rule within the set. + +## Import + +Unrouted Orchestration can be imported using the `id` of the Event Orchestration, e.g. + +``` +$ terraform import pagerduty_event_orchestration_unrouted 1b49abe7-26db-4439-a715-c6d883acfb3e +``` From 8ad6d93fb8da6f451ac4f5071f73cba713bf9c6b Mon Sep 17 00:00:00 2001 From: Scott McAllister Date: Wed, 1 Jun 2022 13:37:02 -0700 Subject: [PATCH 44/63] Update CHANGELOG for v2.5.0 Release --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5dfe244f..c84e5e959 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,13 @@ FEATURES: * `resource/pagerduty_event_orchestration_router` * `resource/pagerduty_event_orchestration_unrouted` * `resource/pagerduty_event_orchestration_service` + * `data_source/pagerduty_event_orchestration` + +IMPROVEMENTS: +* `data_source/pagerduty_user`: Add support for pagination. Gets all users. ([#511](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/511)) + +BUG FIXES: +* `resource/pagerduty_service_integration`: Fix permadiff in email_parser with type regex & minor docs update ([#479](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/479)) ## 2.4.2 (May 20, 2022) From 8b3e47111b2903578d6577ab79408e5b1b8511f2 Mon Sep 17 00:00:00 2001 From: Scott McAllister Date: Wed, 8 Jun 2022 23:23:34 -0700 Subject: [PATCH 45/63] add test for custom_header --- ...resource_pagerduty_webhook_subscription.go | 23 ++++++++++++++++++- ...rce_pagerduty_webhook_subscription_test.go | 4 ++++ .../pagerduty/webhook_subscription.go | 2 +- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/pagerduty/resource_pagerduty_webhook_subscription.go b/pagerduty/resource_pagerduty_webhook_subscription.go index 6b9d73e72..bffa014b9 100644 --- a/pagerduty/resource_pagerduty_webhook_subscription.go +++ b/pagerduty/resource_pagerduty_webhook_subscription.go @@ -54,6 +54,14 @@ func resourcePagerDutyWebhookSubscription() *schema.Resource { "value": { Type: schema.TypeString, Required: true, + ForceNew: true, + // Suppress the diff shown if the base_image name are equal when both compared in lower case. + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + if old == "-- redacted --" { + return true + } + return false + }, }, }, }, @@ -256,7 +264,7 @@ func flattenDeliveryMethod(method pagerduty.DeliveryMethod) []map[string]interfa "temporarily_disabled": method.TemporarilyDisabled, "type": method.Type, "url": method.URL, - "custom_header": method.CustomHeaders, + "custom_header": flattenCustomHeader(method.CustomHeaders), } methods = append(methods, methodMap) return methods @@ -271,3 +279,16 @@ func flattenFilter(filter pagerduty.Filter) []map[string]interface{} { filters = append(filters, filterMap) return filters } + +func flattenCustomHeader(customHeaders []*pagerduty.CustomHeaders) []map[string]interface{} { + var headers []map[string]interface{} + + for _, ch := range customHeaders { + headerMap := map[string]interface{}{ + "name": ch.Name, + "value": ch.Value, + } + headers = append(headers, headerMap) + } + return headers +} diff --git a/pagerduty/resource_pagerduty_webhook_subscription_test.go b/pagerduty/resource_pagerduty_webhook_subscription_test.go index dbddad061..6a06e8f3a 100644 --- a/pagerduty/resource_pagerduty_webhook_subscription_test.go +++ b/pagerduty/resource_pagerduty_webhook_subscription_test.go @@ -145,6 +145,10 @@ func testAccCheckPagerDutyWebhookSubscriptionConfig(username, useremail, escalat delivery_method { type = "http_delivery_method" url = "https://example.com/receive_a_pagerduty_webhook" + custom_header { + name = "X-Foo" + value = "foo" + } } description = "%s" events = [ diff --git a/vendor/github.com/heimweh/go-pagerduty/pagerduty/webhook_subscription.go b/vendor/github.com/heimweh/go-pagerduty/pagerduty/webhook_subscription.go index b799dbbaf..19f06ddbd 100644 --- a/vendor/github.com/heimweh/go-pagerduty/pagerduty/webhook_subscription.go +++ b/vendor/github.com/heimweh/go-pagerduty/pagerduty/webhook_subscription.go @@ -21,7 +21,7 @@ type DeliveryMethod struct { TemporarilyDisabled bool `json:"temporarily_disabled,omitempty"` Type string `json:"type,omitempty"` URL string `json:"url,omitempty"` - CustomHeaders []*CustomHeaders `json:"custom_header"` + CustomHeaders []*CustomHeaders `json:"custom_headers"` } type CustomHeaders struct { From 6eb3505acebc4db39123eda36eb034b4e8623c48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Antonio=20Reyes?= Date: Thu, 9 Jun 2022 13:21:35 -0400 Subject: [PATCH 46/63] add acc test for `priorities` attribute in `slack_connection` --- ...esource_pagerduty_slack_connection_test.go | 161 ++++++++++++++++++ 1 file changed, 161 insertions(+) diff --git a/pagerduty/resource_pagerduty_slack_connection_test.go b/pagerduty/resource_pagerduty_slack_connection_test.go index 147ca848c..bb80620d0 100644 --- a/pagerduty/resource_pagerduty_slack_connection_test.go +++ b/pagerduty/resource_pagerduty_slack_connection_test.go @@ -103,6 +103,41 @@ func TestAccPagerDutySlackConnection_Envar(t *testing.T) { }) } +func TestAccPagerDutySlackConnection_NonAndAnyPriorities(t *testing.T) { + username := fmt.Sprintf("tf-%s", acctest.RandString(5)) + email := fmt.Sprintf("%s@foo.test", username) + escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) + service := fmt.Sprintf("tf-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckPagerDutySlackConnectionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckPagerDutySlackConnectionConfigNonAndAnyPriorities(username, email, escalationPolicy, service, workspaceID, channelID), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutySlackConnectionExists("pagerduty_slack_connection.foo"), + resource.TestCheckResourceAttr( + "pagerduty_slack_connection.foo", "source_name", service), + resource.TestCheckResourceAttr( + "pagerduty_slack_connection.foo", "config.0.priorities.#", "0"), + ), + }, + { + Config: testAccCheckPagerDutySlackConnectionConfigNonAndAnyPrioritiesUpdated(username, email, escalationPolicy, service, workspaceID, channelID), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutySlackConnectionExists("pagerduty_slack_connection.foo"), + resource.TestCheckResourceAttr( + "pagerduty_slack_connection.foo", "config.0.priorities.#", "1"), + resource.TestCheckResourceAttr( + "pagerduty_slack_connection.foo", "config.0.priorities.0", "*"), + ), + }, + }, + }) +} + func testAccCheckPagerDutySlackConnectionDestroy(s *terraform.State) error { config := &pagerduty.Config{ Token: os.Getenv("PAGERDUTY_USER_TOKEN"), @@ -388,3 +423,129 @@ func testAccCheckPagerDutySlackConnectionConfigEnvar(team, channelID string) str } `, team, channelID) } + +func testAccCheckPagerDutySlackConnectionConfigNonAndAnyPriorities(username, useremail, escalationPolicy, service, workspaceID, channelID string) string { + return fmt.Sprintf(` + resource "pagerduty_user" "foo" { + name = "%s" + email = "%s" + } + + resource "pagerduty_escalation_policy" "foo" { + name = "%s" + description = "foo" + num_loops = 1 + + rule { + escalation_delay_in_minutes = 10 + + target { + type = "user_reference" + id = pagerduty_user.foo.id + } + } + } + + resource "pagerduty_service" "foo" { + name = "%s" + description = "foo" + auto_resolve_timeout = 1800 + acknowledgement_timeout = 1800 + escalation_policy = pagerduty_escalation_policy.foo.id + + incident_urgency_rule { + type = "constant" + urgency = "high" + } + } + resource "pagerduty_slack_connection" "foo" { + source_id = pagerduty_service.foo.id + source_type = "service_reference" + workspace_id = "%s" + channel_id = "%s" + notification_type = "responder" + config { + events = [ + "incident.triggered", + "incident.acknowledged", + "incident.escalated", + "incident.resolved", + "incident.reassigned", + "incident.annotated", + "incident.unacknowledged", + "incident.delegated", + "incident.priority_updated", + "incident.responder.added", + "incident.responder.replied", + "incident.status_update_published", + "incident.reopened" + ] + priorities = [] + urgency = "high" + } + } + `, username, useremail, escalationPolicy, service, workspaceID, channelID) +} + +func testAccCheckPagerDutySlackConnectionConfigNonAndAnyPrioritiesUpdated(username, email, escalationPolicy, service, workspaceID, channelID string) string { + return fmt.Sprintf(` + resource "pagerduty_user" "foo" { + name = "%s" + email = "%s" + } + + resource "pagerduty_escalation_policy" "foo" { + name = "%s" + description = "foo" + num_loops = 1 + + rule { + escalation_delay_in_minutes = 10 + + target { + type = "user_reference" + id = pagerduty_user.foo.id + } + } + } + + resource "pagerduty_service" "foo" { + name = "%s" + description = "foo" + auto_resolve_timeout = 1800 + acknowledgement_timeout = 1800 + escalation_policy = pagerduty_escalation_policy.foo.id + + incident_urgency_rule { + type = "constant" + urgency = "high" + } + } + resource "pagerduty_slack_connection" "foo" { + source_id = pagerduty_service.foo.id + source_type = "service_reference" + workspace_id = "%s" + channel_id = "%s" + notification_type = "responder" + config { + events = [ + "incident.triggered", + "incident.acknowledged", + "incident.escalated", + "incident.resolved", + "incident.reassigned", + "incident.annotated", + "incident.unacknowledged", + "incident.delegated", + "incident.priority_updated", + "incident.responder.added", + "incident.responder.replied", + "incident.status_update_published", + "incident.reopened" + ] + priorities = ["*"] + urgency = "high" + } + } + `, username, email, escalationPolicy, service, workspaceID, channelID) +} From 612632c7c740ef733d4df6eb0949762cb020f67c Mon Sep 17 00:00:00 2001 From: "Robert Barnes (DevOps Rob)" Date: Mon, 7 Feb 2022 15:22:37 +0000 Subject: [PATCH 47/63] Adding custom_headers to delivery_method in webhook_subscription resource. --- pagerduty/resource_pagerduty_webhook_subscription.go | 6 ++++++ website/docs/r/webhook_subscription.html.markdown | 1 + 2 files changed, 7 insertions(+) diff --git a/pagerduty/resource_pagerduty_webhook_subscription.go b/pagerduty/resource_pagerduty_webhook_subscription.go index d629fda82..b2c194cd7 100644 --- a/pagerduty/resource_pagerduty_webhook_subscription.go +++ b/pagerduty/resource_pagerduty_webhook_subscription.go @@ -41,6 +41,10 @@ func resourcePagerDutyWebhookSubscription() *schema.Resource { Type: schema.TypeString, Optional: true, }, + "custom_headers": { + Type: schema.TypeMap, + Optional: true, + }, }, }, }, @@ -208,6 +212,7 @@ func expandDeliveryMethod(v interface{}) pagerduty.DeliveryMethod { TemporarilyDisabled: dmMap["temporarily_disabled"].(bool), Type: dmMap["type"].(string), URL: dmMap["url"].(string), + CustomHeaders: dmMap["custom_headers"].(map[string]string), } return method } @@ -229,6 +234,7 @@ func flattenDeliveryMethod(method pagerduty.DeliveryMethod) []map[string]interfa "temporarily_disabled": method.TemporarilyDisabled, "type": method.Type, "url": method.URL, + "custom_headers": method.CustomHeaders, } methods = append(methods, methodMap) return methods diff --git a/website/docs/r/webhook_subscription.html.markdown b/website/docs/r/webhook_subscription.html.markdown index e193563b5..195284dfc 100644 --- a/website/docs/r/webhook_subscription.html.markdown +++ b/website/docs/r/webhook_subscription.html.markdown @@ -77,6 +77,7 @@ The following arguments are supported: * `temporarily_disabled` - (Required) Whether this webhook subscription is temporarily disabled. Becomes true if the delivery method URL is repeatedly rejected by the server. * `type` - (Required) Indicates the type of the delivery method. Allowed and default value: `http_delivery_method`. * `url` - (Required) The destination URL for webhook delivery. +* `custom_headers` - (Optional) The custom_headers of a webhook subscription define any optional headers that will be passed along with the payload to the destination URL. ### Webhook filter (`filter`) supports the following: From ce30e765ad6b8d7e1c042726b220b4535568218c Mon Sep 17 00:00:00 2001 From: "Robert Barnes (DevOps Rob)" Date: Tue, 8 Feb 2022 18:57:28 +0000 Subject: [PATCH 48/63] fixing type error --- ...resource_pagerduty_webhook_subscription.go | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/pagerduty/resource_pagerduty_webhook_subscription.go b/pagerduty/resource_pagerduty_webhook_subscription.go index b2c194cd7..6671b2b2a 100644 --- a/pagerduty/resource_pagerduty_webhook_subscription.go +++ b/pagerduty/resource_pagerduty_webhook_subscription.go @@ -42,8 +42,21 @@ func resourcePagerDutyWebhookSubscription() *schema.Resource { Optional: true, }, "custom_headers": { - Type: schema.TypeMap, + Type: schema.TypeList, Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + + "value": { + Type: schema.TypeString, + Required: true, + }, + }, + }, }, }, }, @@ -208,11 +221,21 @@ func expandDeliveryMethod(v interface{}) pagerduty.DeliveryMethod { var method pagerduty.DeliveryMethod + // convert interface to []*pagerduty.CustomHeaders + var list []*pagerduty.CustomHeaders + for _, raw := range dmMap["custom_headers"].([]interface{}) { + list = append(list, &pagerduty.CustomHeaders{ + Name: raw.(map[string]interface{})["name"].(string), + Value: raw.(map[string]interface{})["value"].(string), + }) + } + + method = pagerduty.DeliveryMethod{ TemporarilyDisabled: dmMap["temporarily_disabled"].(bool), Type: dmMap["type"].(string), URL: dmMap["url"].(string), - CustomHeaders: dmMap["custom_headers"].(map[string]string), + CustomHeaders: list, } return method } From 5c7a1df6c1b1de718f8bb972b8b987a73b35ccfb Mon Sep 17 00:00:00 2001 From: DevOps Rob Date: Wed, 9 Feb 2022 11:02:53 +0000 Subject: [PATCH 49/63] Update pagerduty/resource_pagerduty_webhook_subscription.go Co-authored-by: Shohei Maeda <11495867+smaeda-ks@users.noreply.github.com> --- pagerduty/resource_pagerduty_webhook_subscription.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pagerduty/resource_pagerduty_webhook_subscription.go b/pagerduty/resource_pagerduty_webhook_subscription.go index 6671b2b2a..e719305e6 100644 --- a/pagerduty/resource_pagerduty_webhook_subscription.go +++ b/pagerduty/resource_pagerduty_webhook_subscription.go @@ -235,7 +235,7 @@ func expandDeliveryMethod(v interface{}) pagerduty.DeliveryMethod { TemporarilyDisabled: dmMap["temporarily_disabled"].(bool), Type: dmMap["type"].(string), URL: dmMap["url"].(string), - CustomHeaders: list, + CustomHeaders: headers, } return method } From ee271388eb1985c524d49452e802a5de4cab3ec0 Mon Sep 17 00:00:00 2001 From: DevOps Rob Date: Wed, 9 Feb 2022 11:03:06 +0000 Subject: [PATCH 50/63] Update pagerduty/resource_pagerduty_webhook_subscription.go Co-authored-by: Shohei Maeda <11495867+smaeda-ks@users.noreply.github.com> --- pagerduty/resource_pagerduty_webhook_subscription.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pagerduty/resource_pagerduty_webhook_subscription.go b/pagerduty/resource_pagerduty_webhook_subscription.go index e719305e6..e66792ada 100644 --- a/pagerduty/resource_pagerduty_webhook_subscription.go +++ b/pagerduty/resource_pagerduty_webhook_subscription.go @@ -222,9 +222,9 @@ func expandDeliveryMethod(v interface{}) pagerduty.DeliveryMethod { var method pagerduty.DeliveryMethod // convert interface to []*pagerduty.CustomHeaders - var list []*pagerduty.CustomHeaders + var headers []*pagerduty.CustomHeaders for _, raw := range dmMap["custom_headers"].([]interface{}) { - list = append(list, &pagerduty.CustomHeaders{ + headers = append(headers, &pagerduty.CustomHeaders{ Name: raw.(map[string]interface{})["name"].(string), Value: raw.(map[string]interface{})["value"].(string), }) From 463b0e6c69659e532f2af3cb00e82f931e1205d8 Mon Sep 17 00:00:00 2001 From: "Robert Barnes (DevOps Rob)" Date: Wed, 9 Feb 2022 11:14:05 +0000 Subject: [PATCH 51/63] Updated the dependancy hash and example usage --- .../heimweh/go-pagerduty/pagerduty/user.go | 28 +++++++++++++++++++ vendor/modules.txt | 4 +++ .../docs/r/webhook_subscription.html.markdown | 3 ++ 3 files changed, 35 insertions(+) diff --git a/vendor/github.com/heimweh/go-pagerduty/pagerduty/user.go b/vendor/github.com/heimweh/go-pagerduty/pagerduty/user.go index bbbb3798f..3be1b4956 100644 --- a/vendor/github.com/heimweh/go-pagerduty/pagerduty/user.go +++ b/vendor/github.com/heimweh/go-pagerduty/pagerduty/user.go @@ -333,6 +333,7 @@ func (s *UserService) CreateContactMethod(userID string, contactMethod *ContactM resp, err := s.client.newRequestDo("POST", u, nil, &ContactMethodPayload{ContactMethod: contactMethod}, &v) if err != nil { +<<<<<<< HEAD if e, ok := err.(*Error); !ok || strings.Compare(fmt.Sprintf("%v", e.Errors), "[User Contact method must be unique]") != 0 { return nil, nil, err } @@ -343,6 +344,24 @@ func (s *UserService) CreateContactMethod(userID string, contactMethod *ContactM } v.ContactMethod = sContact resp = sResp +======= + if e, ok := err.(*Error); ok && strings.Compare(fmt.Sprintf("%v", e.Errors), "[User Contact method must be unique]") == 0 { + resp, _, lErr := s.ListContactMethods(userID) + if lErr != nil { + return nil, nil, fmt.Errorf("user contact method is not unique and failed to fetch existing ones: %w", lErr) + } + + for _, contact := range resp.ContactMethods { + if isSameContactMethod(contact, contactMethod) { + return s.GetContactMethod(userID, contact.ID) + } + } + + return nil, nil, fmt.Errorf("user contact method address is used with different attributes (possibly label)") + } else { + return nil, nil, err + } +>>>>>>> a246bf7 (Updated the dependancy hash and example usage) } if err = cachePutContactMethod(v.ContactMethod); err != nil { @@ -354,6 +373,7 @@ func (s *UserService) CreateContactMethod(userID string, contactMethod *ContactM return v.ContactMethod, resp, nil } +<<<<<<< HEAD func (s *UserService) findExistingContactMethod(userID string, contactMethod *ContactMethod) (*ContactMethod, *Response, error) { lResp, _, lErr := s.ListContactMethods(userID) if lErr != nil { @@ -369,12 +389,20 @@ func (s *UserService) findExistingContactMethod(userID string, contactMethod *Co return nil, nil, fmt.Errorf("[User Contact method must be unique]") } +======= +>>>>>>> a246bf7 (Updated the dependancy hash and example usage) // isSameContactMethod checks if an existing contact method should be taken as the same as a new one users want to create. // note new contact method misses some fields like Self, HTMLURL. func isSameContactMethod(existingContact, newContact *ContactMethod) bool { return existingContact.Type == newContact.Type && existingContact.Address == newContact.Address && +<<<<<<< HEAD existingContact.CountryCode == newContact.CountryCode +======= + existingContact.Label == newContact.Label && + existingContact.CountryCode == newContact.CountryCode && + existingContact.Summary == newContact.Summary +>>>>>>> a246bf7 (Updated the dependancy hash and example usage) } // GetContactMethod retrieves a contact method for a user. diff --git a/vendor/modules.txt b/vendor/modules.txt index 0fd9953e9..e89c27b1a 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -124,7 +124,11 @@ github.com/hashicorp/terraform-registry-address github.com/hashicorp/terraform-svchost # github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d github.com/hashicorp/yamux +<<<<<<< HEAD # github.com/heimweh/go-pagerduty v0.0.0-20220527195341-4e587aa9b58e +======= +# github.com/heimweh/go-pagerduty v0.0.0-20220208022815-41d374b4d21b +>>>>>>> a246bf7 (Updated the dependancy hash and example usage) ## explicit github.com/heimweh/go-pagerduty/pagerduty # github.com/klauspost/compress v1.11.2 diff --git a/website/docs/r/webhook_subscription.html.markdown b/website/docs/r/webhook_subscription.html.markdown index 195284dfc..b7c2edb91 100644 --- a/website/docs/r/webhook_subscription.html.markdown +++ b/website/docs/r/webhook_subscription.html.markdown @@ -21,6 +21,9 @@ resource "pagerduty_webhook_subscription" "foo" { delivery_method { type = "http_delivery_method" url = "https://example.com/receive_a_pagerduty_webhook" + custom_headers = { + example_key = "example_value" + } } description = "%s" events = [ From a04c7259e785293e6827c28c0d777001e2eb7bec Mon Sep 17 00:00:00 2001 From: DevOps Rob Date: Fri, 11 Feb 2022 10:39:12 +0000 Subject: [PATCH 52/63] Update website/docs/r/webhook_subscription.html.markdown Co-authored-by: Shohei Maeda <11495867+smaeda-ks@users.noreply.github.com> --- website/docs/r/webhook_subscription.html.markdown | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/website/docs/r/webhook_subscription.html.markdown b/website/docs/r/webhook_subscription.html.markdown index b7c2edb91..42dbaccf0 100644 --- a/website/docs/r/webhook_subscription.html.markdown +++ b/website/docs/r/webhook_subscription.html.markdown @@ -21,8 +21,13 @@ resource "pagerduty_webhook_subscription" "foo" { delivery_method { type = "http_delivery_method" url = "https://example.com/receive_a_pagerduty_webhook" - custom_headers = { - example_key = "example_value" + custom_headers { + name = "X-Foo" + value = "foo" + } + custom_headers { + name = "X-Bar" + value = "bar" } } description = "%s" From da265a2f7df56d62a999183706ad39e81e13d260 Mon Sep 17 00:00:00 2001 From: DevOps Rob Date: Wed, 8 Jun 2022 11:05:32 +0100 Subject: [PATCH 53/63] refactor: customer_headers => custom_header --- pagerduty/resource_pagerduty_webhook_subscription.go | 9 ++++----- .../go-pagerduty/pagerduty/webhook_subscription.go | 2 +- website/docs/r/webhook_subscription.html.markdown | 6 +++--- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/pagerduty/resource_pagerduty_webhook_subscription.go b/pagerduty/resource_pagerduty_webhook_subscription.go index e66792ada..6b9d73e72 100644 --- a/pagerduty/resource_pagerduty_webhook_subscription.go +++ b/pagerduty/resource_pagerduty_webhook_subscription.go @@ -41,7 +41,7 @@ func resourcePagerDutyWebhookSubscription() *schema.Resource { Type: schema.TypeString, Optional: true, }, - "custom_headers": { + "custom_header": { Type: schema.TypeList, Optional: true, Elem: &schema.Resource{ @@ -223,19 +223,18 @@ func expandDeliveryMethod(v interface{}) pagerduty.DeliveryMethod { // convert interface to []*pagerduty.CustomHeaders var headers []*pagerduty.CustomHeaders - for _, raw := range dmMap["custom_headers"].([]interface{}) { + for _, raw := range dmMap["custom_header"].([]interface{}) { headers = append(headers, &pagerduty.CustomHeaders{ Name: raw.(map[string]interface{})["name"].(string), Value: raw.(map[string]interface{})["value"].(string), }) } - method = pagerduty.DeliveryMethod{ TemporarilyDisabled: dmMap["temporarily_disabled"].(bool), Type: dmMap["type"].(string), URL: dmMap["url"].(string), - CustomHeaders: headers, + CustomHeaders: headers, } return method } @@ -257,7 +256,7 @@ func flattenDeliveryMethod(method pagerduty.DeliveryMethod) []map[string]interfa "temporarily_disabled": method.TemporarilyDisabled, "type": method.Type, "url": method.URL, - "custom_headers": method.CustomHeaders, + "custom_header": method.CustomHeaders, } methods = append(methods, methodMap) return methods diff --git a/vendor/github.com/heimweh/go-pagerduty/pagerduty/webhook_subscription.go b/vendor/github.com/heimweh/go-pagerduty/pagerduty/webhook_subscription.go index 19f06ddbd..b799dbbaf 100644 --- a/vendor/github.com/heimweh/go-pagerduty/pagerduty/webhook_subscription.go +++ b/vendor/github.com/heimweh/go-pagerduty/pagerduty/webhook_subscription.go @@ -21,7 +21,7 @@ type DeliveryMethod struct { TemporarilyDisabled bool `json:"temporarily_disabled,omitempty"` Type string `json:"type,omitempty"` URL string `json:"url,omitempty"` - CustomHeaders []*CustomHeaders `json:"custom_headers"` + CustomHeaders []*CustomHeaders `json:"custom_header"` } type CustomHeaders struct { diff --git a/website/docs/r/webhook_subscription.html.markdown b/website/docs/r/webhook_subscription.html.markdown index 42dbaccf0..a1ed7ec51 100644 --- a/website/docs/r/webhook_subscription.html.markdown +++ b/website/docs/r/webhook_subscription.html.markdown @@ -21,11 +21,11 @@ resource "pagerduty_webhook_subscription" "foo" { delivery_method { type = "http_delivery_method" url = "https://example.com/receive_a_pagerduty_webhook" - custom_headers { + custom_header { name = "X-Foo" value = "foo" } - custom_headers { + custom_header { name = "X-Bar" value = "bar" } @@ -85,7 +85,7 @@ The following arguments are supported: * `temporarily_disabled` - (Required) Whether this webhook subscription is temporarily disabled. Becomes true if the delivery method URL is repeatedly rejected by the server. * `type` - (Required) Indicates the type of the delivery method. Allowed and default value: `http_delivery_method`. * `url` - (Required) The destination URL for webhook delivery. -* `custom_headers` - (Optional) The custom_headers of a webhook subscription define any optional headers that will be passed along with the payload to the destination URL. +* `custom_header` - (Optional) The custom_header of a webhook subscription define any optional headers that will be passed along with the payload to the destination URL. ### Webhook filter (`filter`) supports the following: From 31a0d4f179ce42e7c00165380feb8f291a7f8cd9 Mon Sep 17 00:00:00 2001 From: Marcos Wright-Kuhns Date: Fri, 6 May 2022 09:59:15 -0700 Subject: [PATCH 54/63] Switch to always use @foo.test TLD in our tests & documentation ...because [he test TLD[1] will never be publicly addressable & therefore we'll be certain to never send real email to a random domain when the acceptance tests run. [1]:https://en.wikipedia.org/wiki/.test --- CHANGELOG.md | 7 +++++++ .../mongo-driver/mongo/options/datakeyoptions.go | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c84e5e959..252ba5c17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +<<<<<<< HEAD ## 2.5.0 (June 1, 2022) FEATURES: @@ -27,6 +28,12 @@ BUG FIXES: * Docs: `resource/pagerduty_escalation_policy`: Fixed `user` -> `user_reference` in samples ([#497](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/497)) * Build Process: Include `timezdata` build tag in goreleaser config ([#488](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/488)) * `data_source/pagerduty_escalation_policy`,`data_source/pagerduty_ruleset`: Changed logic to retry on all errors returned by PD API. Remedies GOAWAY error. ([#507](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/507)) +======= +## 2.4.2 (Unreleased) + +IMPROVEMENTS: +* Use "@foo.test" email addresses in tests +>>>>>>> 3037c29 (Switch to always use @foo.test TLD in our tests & documentation) ## 2.4.1 (April 22, 2022) IMPROVEMENTS: diff --git a/vendor/go.mongodb.org/mongo-driver/mongo/options/datakeyoptions.go b/vendor/go.mongodb.org/mongo-driver/mongo/options/datakeyoptions.go index c6a17f9e0..3da8f652a 100644 --- a/vendor/go.mongodb.org/mongo-driver/mongo/options/datakeyoptions.go +++ b/vendor/go.mongodb.org/mongo-driver/mongo/options/datakeyoptions.go @@ -22,7 +22,7 @@ func DataKey() *DataKeyOptions { // If being used with a local KMS provider, this option is not applicable and should not be specified. // // For the AWS, Azure, and GCP KMS providers, this option is required and must be a document. For each, the value of the -// "endpoint" or "keyVaultEndpoint" must be a host name with an optional port number (e.g. "foo.com" or "foo.com:443"). +// "endpoint" or "keyVaultEndpoint" must be a host name with an optional port number (e.g. "foo.test" or "foo.test:443"). // // When using AWS, the document must have the format: // { From 786f72b49a9683df2c2e9b0f3e40532323a57550 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Antonio=20Reyes?= Date: Thu, 12 May 2022 17:57:45 -0400 Subject: [PATCH 55/63] update slack integration docs --- CHANGELOG.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 252ba5c17..c84e5e959 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,3 @@ -<<<<<<< HEAD ## 2.5.0 (June 1, 2022) FEATURES: @@ -28,12 +27,6 @@ BUG FIXES: * Docs: `resource/pagerduty_escalation_policy`: Fixed `user` -> `user_reference` in samples ([#497](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/497)) * Build Process: Include `timezdata` build tag in goreleaser config ([#488](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/488)) * `data_source/pagerduty_escalation_policy`,`data_source/pagerduty_ruleset`: Changed logic to retry on all errors returned by PD API. Remedies GOAWAY error. ([#507](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/507)) -======= -## 2.4.2 (Unreleased) - -IMPROVEMENTS: -* Use "@foo.test" email addresses in tests ->>>>>>> 3037c29 (Switch to always use @foo.test TLD in our tests & documentation) ## 2.4.1 (April 22, 2022) IMPROVEMENTS: From 97ca5b4f637bad323a9d8ab70315c5dfc8f2b169 Mon Sep 17 00:00:00 2001 From: alenapan <47909261+alenapan@users.noreply.github.com> Date: Wed, 1 Jun 2022 16:29:28 -0400 Subject: [PATCH 56/63] [ORCA-3444] Add support for Event Orchestrations (#512) * ORCA-3459 - event orchestration resource * reformat * [REVERT LATER] Temporarily pointing to the local copy of go-pagerduty * rename Orchestration references to EventOrchestration * add more properties, mapping logic; add tests * more tests to event_orchestration_resource * add datasource event orchestration * [REVERT LATER]-local testing * fix create logic (set integrations), remove description and routes from orchestration data source * fix data source, add data source tests * reformat * Add import tests * update to latest alenapan/go-pagerduty * add team checks to the tests * [ORCA-3475] Allow deleting event orchestration team from an orchestration (#494) * support unsetting orch team * add retry logic to the event orchestration update method * [ORCA-3463] Orchestration Path Router Resource (#493) * router path * Add support for parent * refactor * update handler and actions support * support conditions * move conditions to util * move parent to util * test for multiple rules and conditions * actions and catchall * refactor tests * validateFunc * refactor * undo local vendor module path change * rules schema change and test * PR comments addressed * Event orchestration unrouted resource (#495) * Init commit for unrouted * Added tests for unrouted * Added catch_all to unrouted schema * Tweaked catch_all * Merge event-orchestrations * Add testacc for unrouted * Added full config test for unrouted * Add test for number of extractions and variables * Cleaned router and added new test checks to unrouted * Change escalation_policy from snake case to camel case * make type computed and set it on read/update * Orca 3486 refactor (#500) * Clean sweeper function for router/unrouted * Clean sweeper function * [ORCA-3465] - Event Orchestration Service path resource (#499) * ORCA-3465 - Event Orchestration Service Path resource * add resource file * fix read/update, add test * more tests * more service path tests, add conditions * more tests * more tests * add more service path props * fix orch path PUT payload, add tests * fix Suspend * ToDos * add catch_all support, fix tests * add support for regex extractions, add mor tests, add service path import test * update client * PR feedback * Flatten teams block (#506) * Flatten teams block * Fixed naming for the test orchestration * ORCA-3486 - remove team attribute from service path * flatten/rename parent to 'service' for service path * remove type attribute from unrouted * remove type attribute from router * flatten/rename parent to 'event_orchestration' for router * set event_orchestration attr on router import * flatten/rename parent to 'event_orchestration' for unrouted * Clean teams block * revert changes on web file * [ORCA-3486] - Reuse shared Event Orchestration Path logic, add import tests (#509) * ORCA-3486 - add import tests for router/unrouted * ORCA-3486 - add import tests for router, unrouted * reuse severity/event_action validation functions in unrouted/service * reuse variables and extractions schema in router/unrouted * reuse shared conditions schema and mapping functions in router/unrouted/service * [ORCA-3486] Extend unrouted tests, add CustomizeDiff, clean shared functions (#510) * Extend unrouted tests, add CustomizeDiff, clean shared functions * Move shared functions for unrouted and service paths to utils file * orchestration and path resource documentation * datasource documentation * refactor * update comment * update type field documentation * update documentation * cleanup * Remove mention of the suppress action from event_orchestration_unrouted docs * Add "Optional" info to 1 attribute in event_orchestration_service docs * give a better datasource example * cleanup * Add Event Orchestration info to the CHANGELOG (release date TBD) (#514) * update go-pagerduty package * Router - make sets, rules, conditions singular * Unrouted, Service - make sets, rules, conditions, variables, extractions, pd_automation_actions, automations_action (headers, params) singular * Event Orchestration - make integrations singular * update Event Orchestration documentation * EO data source - retry on any error * EO data source - retry on any error Co-authored-by: Pari Dhanakoti Co-authored-by: Alex Zakabluk Co-authored-by: Marcos Wright-Kuhns Co-authored-by: Scott McAllister --- .../mongo-driver/mongo/options/datakeyoptions.go | 2 +- vendor/modules.txt | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/vendor/go.mongodb.org/mongo-driver/mongo/options/datakeyoptions.go b/vendor/go.mongodb.org/mongo-driver/mongo/options/datakeyoptions.go index 3da8f652a..c6a17f9e0 100644 --- a/vendor/go.mongodb.org/mongo-driver/mongo/options/datakeyoptions.go +++ b/vendor/go.mongodb.org/mongo-driver/mongo/options/datakeyoptions.go @@ -22,7 +22,7 @@ func DataKey() *DataKeyOptions { // If being used with a local KMS provider, this option is not applicable and should not be specified. // // For the AWS, Azure, and GCP KMS providers, this option is required and must be a document. For each, the value of the -// "endpoint" or "keyVaultEndpoint" must be a host name with an optional port number (e.g. "foo.test" or "foo.test:443"). +// "endpoint" or "keyVaultEndpoint" must be a host name with an optional port number (e.g. "foo.com" or "foo.com:443"). // // When using AWS, the document must have the format: // { diff --git a/vendor/modules.txt b/vendor/modules.txt index e89c27b1a..66037ca08 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -125,10 +125,14 @@ github.com/hashicorp/terraform-svchost # github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d github.com/hashicorp/yamux <<<<<<< HEAD +<<<<<<< HEAD # github.com/heimweh/go-pagerduty v0.0.0-20220527195341-4e587aa9b58e ======= # github.com/heimweh/go-pagerduty v0.0.0-20220208022815-41d374b4d21b >>>>>>> a246bf7 (Updated the dependancy hash and example usage) +======= +# github.com/heimweh/go-pagerduty v0.0.0-20220527195341-4e587aa9b58e +>>>>>>> d223aac ([ORCA-3444] Add support for Event Orchestrations (#512)) ## explicit github.com/heimweh/go-pagerduty/pagerduty # github.com/klauspost/compress v1.11.2 From a3352d2da63615df052dde2b5b491613131d6621 Mon Sep 17 00:00:00 2001 From: Scott McAllister Date: Wed, 8 Jun 2022 23:23:34 -0700 Subject: [PATCH 57/63] add test for custom_header --- ...resource_pagerduty_webhook_subscription.go | 23 ++++++++++++++++++- ...rce_pagerduty_webhook_subscription_test.go | 4 ++++ .../pagerduty/webhook_subscription.go | 2 +- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/pagerduty/resource_pagerduty_webhook_subscription.go b/pagerduty/resource_pagerduty_webhook_subscription.go index 6b9d73e72..bffa014b9 100644 --- a/pagerduty/resource_pagerduty_webhook_subscription.go +++ b/pagerduty/resource_pagerduty_webhook_subscription.go @@ -54,6 +54,14 @@ func resourcePagerDutyWebhookSubscription() *schema.Resource { "value": { Type: schema.TypeString, Required: true, + ForceNew: true, + // Suppress the diff shown if the base_image name are equal when both compared in lower case. + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + if old == "-- redacted --" { + return true + } + return false + }, }, }, }, @@ -256,7 +264,7 @@ func flattenDeliveryMethod(method pagerduty.DeliveryMethod) []map[string]interfa "temporarily_disabled": method.TemporarilyDisabled, "type": method.Type, "url": method.URL, - "custom_header": method.CustomHeaders, + "custom_header": flattenCustomHeader(method.CustomHeaders), } methods = append(methods, methodMap) return methods @@ -271,3 +279,16 @@ func flattenFilter(filter pagerduty.Filter) []map[string]interface{} { filters = append(filters, filterMap) return filters } + +func flattenCustomHeader(customHeaders []*pagerduty.CustomHeaders) []map[string]interface{} { + var headers []map[string]interface{} + + for _, ch := range customHeaders { + headerMap := map[string]interface{}{ + "name": ch.Name, + "value": ch.Value, + } + headers = append(headers, headerMap) + } + return headers +} diff --git a/pagerduty/resource_pagerduty_webhook_subscription_test.go b/pagerduty/resource_pagerduty_webhook_subscription_test.go index dbddad061..6a06e8f3a 100644 --- a/pagerduty/resource_pagerduty_webhook_subscription_test.go +++ b/pagerduty/resource_pagerduty_webhook_subscription_test.go @@ -145,6 +145,10 @@ func testAccCheckPagerDutyWebhookSubscriptionConfig(username, useremail, escalat delivery_method { type = "http_delivery_method" url = "https://example.com/receive_a_pagerduty_webhook" + custom_header { + name = "X-Foo" + value = "foo" + } } description = "%s" events = [ diff --git a/vendor/github.com/heimweh/go-pagerduty/pagerduty/webhook_subscription.go b/vendor/github.com/heimweh/go-pagerduty/pagerduty/webhook_subscription.go index b799dbbaf..19f06ddbd 100644 --- a/vendor/github.com/heimweh/go-pagerduty/pagerduty/webhook_subscription.go +++ b/vendor/github.com/heimweh/go-pagerduty/pagerduty/webhook_subscription.go @@ -21,7 +21,7 @@ type DeliveryMethod struct { TemporarilyDisabled bool `json:"temporarily_disabled,omitempty"` Type string `json:"type,omitempty"` URL string `json:"url,omitempty"` - CustomHeaders []*CustomHeaders `json:"custom_header"` + CustomHeaders []*CustomHeaders `json:"custom_headers"` } type CustomHeaders struct { From 1a84884af408aa8d83e0e151d43a175d00dcaa5c Mon Sep 17 00:00:00 2001 From: Scott McAllister Date: Thu, 9 Jun 2022 15:21:23 -0700 Subject: [PATCH 58/63] fix conflicts --- .../heimweh/go-pagerduty/pagerduty/user.go | 28 ------------------- vendor/modules.txt | 9 +----- 2 files changed, 1 insertion(+), 36 deletions(-) diff --git a/vendor/github.com/heimweh/go-pagerduty/pagerduty/user.go b/vendor/github.com/heimweh/go-pagerduty/pagerduty/user.go index 3be1b4956..bbbb3798f 100644 --- a/vendor/github.com/heimweh/go-pagerduty/pagerduty/user.go +++ b/vendor/github.com/heimweh/go-pagerduty/pagerduty/user.go @@ -333,7 +333,6 @@ func (s *UserService) CreateContactMethod(userID string, contactMethod *ContactM resp, err := s.client.newRequestDo("POST", u, nil, &ContactMethodPayload{ContactMethod: contactMethod}, &v) if err != nil { -<<<<<<< HEAD if e, ok := err.(*Error); !ok || strings.Compare(fmt.Sprintf("%v", e.Errors), "[User Contact method must be unique]") != 0 { return nil, nil, err } @@ -344,24 +343,6 @@ func (s *UserService) CreateContactMethod(userID string, contactMethod *ContactM } v.ContactMethod = sContact resp = sResp -======= - if e, ok := err.(*Error); ok && strings.Compare(fmt.Sprintf("%v", e.Errors), "[User Contact method must be unique]") == 0 { - resp, _, lErr := s.ListContactMethods(userID) - if lErr != nil { - return nil, nil, fmt.Errorf("user contact method is not unique and failed to fetch existing ones: %w", lErr) - } - - for _, contact := range resp.ContactMethods { - if isSameContactMethod(contact, contactMethod) { - return s.GetContactMethod(userID, contact.ID) - } - } - - return nil, nil, fmt.Errorf("user contact method address is used with different attributes (possibly label)") - } else { - return nil, nil, err - } ->>>>>>> a246bf7 (Updated the dependancy hash and example usage) } if err = cachePutContactMethod(v.ContactMethod); err != nil { @@ -373,7 +354,6 @@ func (s *UserService) CreateContactMethod(userID string, contactMethod *ContactM return v.ContactMethod, resp, nil } -<<<<<<< HEAD func (s *UserService) findExistingContactMethod(userID string, contactMethod *ContactMethod) (*ContactMethod, *Response, error) { lResp, _, lErr := s.ListContactMethods(userID) if lErr != nil { @@ -389,20 +369,12 @@ func (s *UserService) findExistingContactMethod(userID string, contactMethod *Co return nil, nil, fmt.Errorf("[User Contact method must be unique]") } -======= ->>>>>>> a246bf7 (Updated the dependancy hash and example usage) // isSameContactMethod checks if an existing contact method should be taken as the same as a new one users want to create. // note new contact method misses some fields like Self, HTMLURL. func isSameContactMethod(existingContact, newContact *ContactMethod) bool { return existingContact.Type == newContact.Type && existingContact.Address == newContact.Address && -<<<<<<< HEAD existingContact.CountryCode == newContact.CountryCode -======= - existingContact.Label == newContact.Label && - existingContact.CountryCode == newContact.CountryCode && - existingContact.Summary == newContact.Summary ->>>>>>> a246bf7 (Updated the dependancy hash and example usage) } // GetContactMethod retrieves a contact method for a user. diff --git a/vendor/modules.txt b/vendor/modules.txt index 66037ca08..b6805b182 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -124,15 +124,8 @@ github.com/hashicorp/terraform-registry-address github.com/hashicorp/terraform-svchost # github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d github.com/hashicorp/yamux -<<<<<<< HEAD -<<<<<<< HEAD + # github.com/heimweh/go-pagerduty v0.0.0-20220527195341-4e587aa9b58e -======= -# github.com/heimweh/go-pagerduty v0.0.0-20220208022815-41d374b4d21b ->>>>>>> a246bf7 (Updated the dependancy hash and example usage) -======= -# github.com/heimweh/go-pagerduty v0.0.0-20220527195341-4e587aa9b58e ->>>>>>> d223aac ([ORCA-3444] Add support for Event Orchestrations (#512)) ## explicit github.com/heimweh/go-pagerduty/pagerduty # github.com/klauspost/compress v1.11.2 From ea71ab1db72173f0118ca8bc9c9638ff678ad0df Mon Sep 17 00:00:00 2001 From: Scott McAllister Date: Thu, 9 Jun 2022 17:32:43 -0700 Subject: [PATCH 59/63] Add v2.5.1 to CHANGELOG --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c84e5e959..1dd402520 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +## 2.5.1 (June 9, 2022) +FEATURES: +* `resource/pagerduty_webhook_subscription`: Adding custom_header to delivery_method ([#455](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/455)) + +BUG FIXES: +* `resource/pagerduty_slack_connection`: Addressing pagerduty_slack_connection unable to set "No Priority" vs "Any Priority"([#519](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/519)) +* `data_source/pagerduty_user`,`data_source/pagerduty_schedule`,`data_source/pagerduty_vendor`: Changed logic to retry on all errors returned by PD API. Remedies GOAWAY error. ([#521](https://github.com/PagerDuty/terraform-provider-pagerduty/pull/521)) + + ## 2.5.0 (June 1, 2022) FEATURES: From 6b59244824ff5ea5bac34efd7d12e5a6900b7e6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Antonio=20Reyes?= Date: Wed, 8 Jun 2022 20:14:44 -0400 Subject: [PATCH 60/63] capture panic caused by casting nil interface{} in pagerduty_service --- pagerduty/resource_pagerduty_service.go | 8 ++- pagerduty/resource_pagerduty_service_test.go | 67 ++++++++++++++++++++ pagerduty/util.go | 14 ++++ 3 files changed, 88 insertions(+), 1 deletion(-) diff --git a/pagerduty/resource_pagerduty_service.go b/pagerduty/resource_pagerduty_service.go index 4d02b8b6e..42acc83cf 100644 --- a/pagerduty/resource_pagerduty_service.go +++ b/pagerduty/resource_pagerduty_service.go @@ -510,10 +510,16 @@ func flattenService(d *schema.ResourceData, service *pagerduty.Service) error { } func expandAlertGroupingParameters(v interface{}) *pagerduty.AlertGroupingParameters { - riur := v.([]interface{})[0].(map[string]interface{}) alertGroupingParameters := &pagerduty.AlertGroupingParameters{ Config: &pagerduty.AlertGroupingConfig{}, } + // First We capture a possible nil value for the interface to avoid the a + // panic + pre := v.([]interface{})[0] + if isNilFunc(pre) { + return nil + } + riur := pre.(map[string]interface{}) if len(riur["type"].(string)) > 0 { gt := riur["type"].(string) alertGroupingParameters.Type = > diff --git a/pagerduty/resource_pagerduty_service_test.go b/pagerduty/resource_pagerduty_service_test.go index 56de1270e..1d9eba648 100644 --- a/pagerduty/resource_pagerduty_service_test.go +++ b/pagerduty/resource_pagerduty_service_test.go @@ -238,6 +238,35 @@ func TestAccPagerDutyService_AlertContentGrouping(t *testing.T) { "pagerduty_service.foo", "incident_urgency_rule.0.type", "constant"), ), }, + { + Config: testAccCheckPagerDutyServiceConfigWithAlertContentGroupingUpdated(username, email, escalationPolicy, service), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyServiceExists("pagerduty_service.foo"), + resource.TestCheckResourceAttr( + "pagerduty_service.foo", "name", service), + resource.TestCheckResourceAttr( + "pagerduty_service.foo", "description", "foo"), + resource.TestCheckResourceAttr( + "pagerduty_service.foo", "auto_resolve_timeout", "1800"), + resource.TestCheckResourceAttr( + "pagerduty_service.foo", "acknowledgement_timeout", "1800"), + resource.TestCheckResourceAttr( + "pagerduty_service.foo", "alert_creation", "create_alerts_and_incidents"), + resource.TestCheckResourceAttr( + "pagerduty_service.foo", "alert_grouping", "rules"), + resource.TestCheckNoResourceAttr( + "pagerduty_service.foo", "alert_grouping_parameters.0.config"), + resource.TestCheckResourceAttr( + "pagerduty_service.foo", "alert_grouping_parameters.0.type", ""), + resource.TestCheckResourceAttr( + "pagerduty_service.foo", "incident_urgency_rule.#", "1"), + resource.TestCheckResourceAttr( + "pagerduty_service.foo", "incident_urgency_rule.0.urgency", "high"), + resource.TestCheckResourceAttr( + "pagerduty_service.foo", "incident_urgency_rule.0.type", "constant"), + ), + ExpectNonEmptyPlan: true, + }, }, }) } @@ -769,6 +798,44 @@ resource "pagerduty_service" "foo" { } `, username, email, escalationPolicy, service) } + +func testAccCheckPagerDutyServiceConfigWithAlertContentGroupingUpdated(username, email, escalationPolicy, service string) string { + return fmt.Sprintf(` +resource "pagerduty_user" "foo" { + name = "%s" + email = "%s" + color = "green" + role = "user" + job_title = "foo" + description = "foo" +} + +resource "pagerduty_escalation_policy" "foo" { + name = "%s" + description = "bar" + num_loops = 2 + rule { + escalation_delay_in_minutes = 10 + target { + type = "user_reference" + id = pagerduty_user.foo.id + } + } +} + +resource "pagerduty_service" "foo" { + name = "%s" + description = "foo" + auto_resolve_timeout = 1800 + acknowledgement_timeout = 1800 + escalation_policy = pagerduty_escalation_policy.foo.id + alert_creation = "create_alerts_and_incidents" + alert_grouping_parameters { + type = null + } +} +`, username, email, escalationPolicy, service) +} func testAccCheckPagerDutyServiceConfigWithAlertGroupingUpdated(username, email, escalationPolicy, service string) string { return fmt.Sprintf(` resource "pagerduty_user" "foo" { diff --git a/pagerduty/util.go b/pagerduty/util.go index 7689b8c45..03e11d0e2 100644 --- a/pagerduty/util.go +++ b/pagerduty/util.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "log" + "reflect" "strings" "time" @@ -152,3 +153,16 @@ func intTypeToIntPtr(v int) *int { } return &v } + +// isNilFunc is a helper which verifies if an empty interface expecting a +// nullable value indeed has a `nil` type assigned or it's just empty. +func isNilFunc(i interface{}) bool { + if i == nil { + return true + } + switch reflect.TypeOf(i).Kind() { + case reflect.Ptr, reflect.Map, reflect.Array, reflect.Chan, reflect.Slice: + return reflect.ValueOf(i).IsNil() + } + return false +} From 7d3d4ce05ca7ce5007fd4f46d3dc8887a2b16eef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Antonio=20Reyes?= Date: Tue, 14 Jun 2022 14:13:16 -0400 Subject: [PATCH 61/63] update output interface for `schedule` resource to display `rendered_coverage_performance` --- pagerduty/resource_pagerduty_schedule.go | 36 +++++++++++++++++++ pagerduty/resource_pagerduty_schedule_test.go | 4 +++ pagerduty/util.go | 8 +++++ 3 files changed, 48 insertions(+) diff --git a/pagerduty/resource_pagerduty_schedule.go b/pagerduty/resource_pagerduty_schedule.go index 5796c0633..6275496fd 100644 --- a/pagerduty/resource_pagerduty_schedule.go +++ b/pagerduty/resource_pagerduty_schedule.go @@ -120,6 +120,11 @@ func resourcePagerDutySchedule() *schema.Resource { }, }, + "rendered_coverage_percentage": { + Type: schema.TypeString, + Computed: true, + }, + "restriction": { Optional: true, Type: schema.TypeList, @@ -164,6 +169,23 @@ func resourcePagerDutySchedule() *schema.Resource { Type: schema.TypeString, }, }, + + "final_schedule": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + }, + "rendered_coverage_percentage": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, }, } } @@ -248,6 +270,9 @@ func resourcePagerDutyScheduleRead(d *schema.ResourceData, meta interface{}) err if err := d.Set("teams", flattenShedTeams(schedule.Teams)); err != nil { return resource.NonRetryableError(fmt.Errorf("error setting teams: %s", err)) } + if err := d.Set("final_schedule", flattenScheFinalSchedule(schedule.FinalSchedule)); err != nil { + return resource.NonRetryableError(fmt.Errorf("error setting final_schedule: %s", err)) + } } return nil @@ -445,6 +470,7 @@ func flattenScheduleLayers(v []*pagerduty.ScheduleLayer) ([]map[string]interface "start": sl.Start, "rotation_virtual_start": sl.RotationVirtualStart, "rotation_turn_length_seconds": sl.RotationTurnLengthSeconds, + "rendered_coverage_percentage": renderRoundedPercentage(sl.RenderedCoveragePercentage), } var users []string @@ -510,3 +536,13 @@ func flattenShedTeams(teams []*pagerduty.TeamReference) []string { return res } + +func flattenScheFinalSchedule(finalSche *pagerduty.SubSchedule) []map[string]interface{} { + var res []map[string]interface{} + elem := make(map[string]interface{}) + elem["name"] = finalSche.Name + elem["rendered_coverage_percentage"] = renderRoundedPercentage(finalSche.RenderedCoveragePercentage) + res = append(res, elem) + + return res +} diff --git a/pagerduty/resource_pagerduty_schedule_test.go b/pagerduty/resource_pagerduty_schedule_test.go index f02b29795..85966c710 100644 --- a/pagerduty/resource_pagerduty_schedule_test.go +++ b/pagerduty/resource_pagerduty_schedule_test.go @@ -79,6 +79,10 @@ func TestAccPagerDutySchedule_Basic(t *testing.T) { "pagerduty_schedule.foo", "layer.0.name", "foo"), resource.TestCheckResourceAttr( "pagerduty_schedule.foo", "layer.0.start", start), + resource.TestCheckResourceAttr( + "pagerduty_schedule.foo", "layer.0.rendered_coverage_percentage", "0.00"), + resource.TestCheckResourceAttr( + "pagerduty_schedule.foo", "final_schedule.0.rendered_coverage_percentage", "0.00"), resource.TestCheckResourceAttr( "pagerduty_schedule.foo", "layer.0.rotation_virtual_start", rotationVirtualStart), ), diff --git a/pagerduty/util.go b/pagerduty/util.go index 7689b8c45..bbe9da576 100644 --- a/pagerduty/util.go +++ b/pagerduty/util.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "log" + "math" "strings" "time" @@ -152,3 +153,10 @@ func intTypeToIntPtr(v int) *int { } return &v } + +// renderRoundedPercentage is a helper function to render percetanges +// represented as float64 numbers, by its round with two decimals string +// representation. +func renderRoundedPercentage(p float64) string { + return fmt.Sprintf("%.2f", math.Round(p*100)) +} From 2b84ebc3109f2a588241ece8cbaa34d6d568f2f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Antonio=20Reyes?= Date: Wed, 8 Jun 2022 20:14:44 -0400 Subject: [PATCH 62/63] capture panic caused by casting nil interface{} in pagerduty_service --- pagerduty/resource_pagerduty_service.go | 8 ++- pagerduty/resource_pagerduty_service_test.go | 67 ++++++++++++++++++++ pagerduty/util.go | 14 ++++ 3 files changed, 88 insertions(+), 1 deletion(-) diff --git a/pagerduty/resource_pagerduty_service.go b/pagerduty/resource_pagerduty_service.go index 4d02b8b6e..42acc83cf 100644 --- a/pagerduty/resource_pagerduty_service.go +++ b/pagerduty/resource_pagerduty_service.go @@ -510,10 +510,16 @@ func flattenService(d *schema.ResourceData, service *pagerduty.Service) error { } func expandAlertGroupingParameters(v interface{}) *pagerduty.AlertGroupingParameters { - riur := v.([]interface{})[0].(map[string]interface{}) alertGroupingParameters := &pagerduty.AlertGroupingParameters{ Config: &pagerduty.AlertGroupingConfig{}, } + // First We capture a possible nil value for the interface to avoid the a + // panic + pre := v.([]interface{})[0] + if isNilFunc(pre) { + return nil + } + riur := pre.(map[string]interface{}) if len(riur["type"].(string)) > 0 { gt := riur["type"].(string) alertGroupingParameters.Type = > diff --git a/pagerduty/resource_pagerduty_service_test.go b/pagerduty/resource_pagerduty_service_test.go index 56de1270e..1d9eba648 100644 --- a/pagerduty/resource_pagerduty_service_test.go +++ b/pagerduty/resource_pagerduty_service_test.go @@ -238,6 +238,35 @@ func TestAccPagerDutyService_AlertContentGrouping(t *testing.T) { "pagerduty_service.foo", "incident_urgency_rule.0.type", "constant"), ), }, + { + Config: testAccCheckPagerDutyServiceConfigWithAlertContentGroupingUpdated(username, email, escalationPolicy, service), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyServiceExists("pagerduty_service.foo"), + resource.TestCheckResourceAttr( + "pagerduty_service.foo", "name", service), + resource.TestCheckResourceAttr( + "pagerduty_service.foo", "description", "foo"), + resource.TestCheckResourceAttr( + "pagerduty_service.foo", "auto_resolve_timeout", "1800"), + resource.TestCheckResourceAttr( + "pagerduty_service.foo", "acknowledgement_timeout", "1800"), + resource.TestCheckResourceAttr( + "pagerduty_service.foo", "alert_creation", "create_alerts_and_incidents"), + resource.TestCheckResourceAttr( + "pagerduty_service.foo", "alert_grouping", "rules"), + resource.TestCheckNoResourceAttr( + "pagerduty_service.foo", "alert_grouping_parameters.0.config"), + resource.TestCheckResourceAttr( + "pagerduty_service.foo", "alert_grouping_parameters.0.type", ""), + resource.TestCheckResourceAttr( + "pagerduty_service.foo", "incident_urgency_rule.#", "1"), + resource.TestCheckResourceAttr( + "pagerduty_service.foo", "incident_urgency_rule.0.urgency", "high"), + resource.TestCheckResourceAttr( + "pagerduty_service.foo", "incident_urgency_rule.0.type", "constant"), + ), + ExpectNonEmptyPlan: true, + }, }, }) } @@ -769,6 +798,44 @@ resource "pagerduty_service" "foo" { } `, username, email, escalationPolicy, service) } + +func testAccCheckPagerDutyServiceConfigWithAlertContentGroupingUpdated(username, email, escalationPolicy, service string) string { + return fmt.Sprintf(` +resource "pagerduty_user" "foo" { + name = "%s" + email = "%s" + color = "green" + role = "user" + job_title = "foo" + description = "foo" +} + +resource "pagerduty_escalation_policy" "foo" { + name = "%s" + description = "bar" + num_loops = 2 + rule { + escalation_delay_in_minutes = 10 + target { + type = "user_reference" + id = pagerduty_user.foo.id + } + } +} + +resource "pagerduty_service" "foo" { + name = "%s" + description = "foo" + auto_resolve_timeout = 1800 + acknowledgement_timeout = 1800 + escalation_policy = pagerduty_escalation_policy.foo.id + alert_creation = "create_alerts_and_incidents" + alert_grouping_parameters { + type = null + } +} +`, username, email, escalationPolicy, service) +} func testAccCheckPagerDutyServiceConfigWithAlertGroupingUpdated(username, email, escalationPolicy, service string) string { return fmt.Sprintf(` resource "pagerduty_user" "foo" { diff --git a/pagerduty/util.go b/pagerduty/util.go index bbe9da576..fd75d74f1 100644 --- a/pagerduty/util.go +++ b/pagerduty/util.go @@ -5,6 +5,7 @@ import ( "fmt" "log" "math" + "reflect" "strings" "time" @@ -160,3 +161,16 @@ func intTypeToIntPtr(v int) *int { func renderRoundedPercentage(p float64) string { return fmt.Sprintf("%.2f", math.Round(p*100)) } + +// isNilFunc is a helper which verifies if an empty interface expecting a +// nullable value indeed has a `nil` type assigned or it's just empty. +func isNilFunc(i interface{}) bool { + if i == nil { + return true + } + switch reflect.TypeOf(i).Kind() { + case reflect.Ptr, reflect.Map, reflect.Array, reflect.Chan, reflect.Slice: + return reflect.ValueOf(i).IsNil() + } + return false +} From f56e7bb9fb5bdd819f21a36110e2ea3759ac05d1 Mon Sep 17 00:00:00 2001 From: Rucheli Berry <7971632+cmrberry@users.noreply.github.com> Date: Fri, 1 Jul 2022 09:37:28 -0700 Subject: [PATCH 63/63] Remove 429 check on remaining data sources --- pagerduty/data_source_pagerduty_business_service.go | 12 ++++-------- pagerduty/data_source_pagerduty_extension_schema.go | 12 ++++-------- pagerduty/data_source_pagerduty_priority.go | 12 ++++-------- pagerduty/data_source_pagerduty_service.go | 12 ++++-------- .../data_source_pagerduty_service_integration.go | 8 ++------ pagerduty/data_source_pagerduty_tag.go | 12 ++++-------- pagerduty/data_source_pagerduty_team.go | 12 ++++-------- 7 files changed, 26 insertions(+), 54 deletions(-) diff --git a/pagerduty/data_source_pagerduty_business_service.go b/pagerduty/data_source_pagerduty_business_service.go index 60278824a..9dc631183 100644 --- a/pagerduty/data_source_pagerduty_business_service.go +++ b/pagerduty/data_source_pagerduty_business_service.go @@ -40,14 +40,10 @@ func dataSourcePagerDutyBusinessServiceRead(d *schema.ResourceData, meta interfa return resource.Retry(5*time.Minute, func() *resource.RetryError { resp, _, err := client.BusinessServices.List() if err != nil { - if isErrCode(err, 429) { - // Delaying retry by 30s as recommended by PagerDuty - // https://developer.pagerduty.com/docs/rest-api-v2/rate-limiting/#what-are-possible-workarounds-to-the-events-api-rate-limit - time.Sleep(30 * time.Second) - return resource.RetryableError(err) - } - - return resource.NonRetryableError(err) + // Delaying retry by 30s as recommended by PagerDuty + // https://developer.pagerduty.com/docs/rest-api-v2/rate-limiting/#what-are-possible-workarounds-to-the-events-api-rate-limit + time.Sleep(30 * time.Second) + return resource.RetryableError(err) } var found *pagerduty.BusinessService diff --git a/pagerduty/data_source_pagerduty_extension_schema.go b/pagerduty/data_source_pagerduty_extension_schema.go index 0f2c7bf24..d0a1d3770 100644 --- a/pagerduty/data_source_pagerduty_extension_schema.go +++ b/pagerduty/data_source_pagerduty_extension_schema.go @@ -41,14 +41,10 @@ func dataSourcePagerDutyExtensionSchemaRead(d *schema.ResourceData, meta interfa return resource.Retry(5*time.Minute, func() *resource.RetryError { resp, _, err := client.ExtensionSchemas.List(&pagerduty.ListExtensionSchemasOptions{Query: searchName}) if err != nil { - if isErrCode(err, 429) { - // Delaying retry by 30s as recommended by PagerDuty - // https://developer.pagerduty.com/docs/rest-api-v2/rate-limiting/#what-are-possible-workarounds-to-the-events-api-rate-limit - time.Sleep(30 * time.Second) - return resource.RetryableError(err) - } - - return resource.NonRetryableError(err) + // Delaying retry by 30s as recommended by PagerDuty + // https://developer.pagerduty.com/docs/rest-api-v2/rate-limiting/#what-are-possible-workarounds-to-the-events-api-rate-limit + time.Sleep(30 * time.Second) + return resource.RetryableError(err) } var found *pagerduty.ExtensionSchema diff --git a/pagerduty/data_source_pagerduty_priority.go b/pagerduty/data_source_pagerduty_priority.go index 054968311..0a863104c 100644 --- a/pagerduty/data_source_pagerduty_priority.go +++ b/pagerduty/data_source_pagerduty_priority.go @@ -42,14 +42,10 @@ func dataSourcePagerDutyPriorityRead(d *schema.ResourceData, meta interface{}) e return resource.Retry(5*time.Minute, func() *resource.RetryError { resp, _, err := client.Priorities.List() if err != nil { - if isErrCode(err, 429) { - // Delaying retry by 30s as recommended by PagerDuty - // https://developer.pagerduty.com/docs/rest-api-v2/rate-limiting/#what-are-possible-workarounds-to-the-events-api-rate-limit - time.Sleep(30 * time.Second) - return resource.RetryableError(err) - } - - return resource.NonRetryableError(err) + // Delaying retry by 30s as recommended by PagerDuty + // https://developer.pagerduty.com/docs/rest-api-v2/rate-limiting/#what-are-possible-workarounds-to-the-events-api-rate-limit + time.Sleep(30 * time.Second) + return resource.RetryableError(err) } var found *pagerduty.Priority diff --git a/pagerduty/data_source_pagerduty_service.go b/pagerduty/data_source_pagerduty_service.go index 21a3531cf..730b65fdf 100644 --- a/pagerduty/data_source_pagerduty_service.go +++ b/pagerduty/data_source_pagerduty_service.go @@ -44,14 +44,10 @@ func dataSourcePagerDutyServiceRead(d *schema.ResourceData, meta interface{}) er return resource.Retry(5*time.Minute, func() *resource.RetryError { resp, _, err := client.Services.List(o) if err != nil { - if isErrCode(err, 429) { - // Delaying retry by 30s as recommended by PagerDuty - // https://developer.pagerduty.com/docs/rest-api-v2/rate-limiting/#what-are-possible-workarounds-to-the-events-api-rate-limit - time.Sleep(30 * time.Second) - return resource.RetryableError(err) - } - - return resource.NonRetryableError(err) + // Delaying retry by 30s as recommended by PagerDuty + // https://developer.pagerduty.com/docs/rest-api-v2/rate-limiting/#what-are-possible-workarounds-to-the-events-api-rate-limit + time.Sleep(30 * time.Second) + return resource.RetryableError(err) } var found *pagerduty.Service diff --git a/pagerduty/data_source_pagerduty_service_integration.go b/pagerduty/data_source_pagerduty_service_integration.go index 7d2adf9a4..0dfccf668 100644 --- a/pagerduty/data_source_pagerduty_service_integration.go +++ b/pagerduty/data_source_pagerduty_service_integration.go @@ -92,10 +92,6 @@ func dataSourcePagerDutyServiceIntegrationRead(d *schema.ResourceData, meta inte } func handleError(err error) *resource.RetryError { - if isErrCode(err, 429) { - time.Sleep(30 * time.Second) - return resource.RetryableError(err) - } - - return resource.NonRetryableError(err) + time.Sleep(30 * time.Second) + return resource.RetryableError(err) } diff --git a/pagerduty/data_source_pagerduty_tag.go b/pagerduty/data_source_pagerduty_tag.go index 4894806c1..c2d913754 100644 --- a/pagerduty/data_source_pagerduty_tag.go +++ b/pagerduty/data_source_pagerduty_tag.go @@ -41,14 +41,10 @@ func dataSourcePagerDutyTagRead(d *schema.ResourceData, meta interface{}) error return resource.Retry(5*time.Minute, func() *resource.RetryError { resp, _, err := client.Tags.List(o) if err != nil { - if isErrCode(err, 429) { - // Delaying retry by 30s as recommended by PagerDuty - // https://developer.pagerduty.com/docs/rest-api-v2/rate-limiting/#what-are-possible-workarounds-to-the-events-api-rate-limit - time.Sleep(30 * time.Second) - return resource.RetryableError(err) - } - - return resource.NonRetryableError(err) + // Delaying retry by 30s as recommended by PagerDuty + // https://developer.pagerduty.com/docs/rest-api-v2/rate-limiting/#what-are-possible-workarounds-to-the-events-api-rate-limit + time.Sleep(30 * time.Second) + return resource.RetryableError(err) } var found *pagerduty.Tag diff --git a/pagerduty/data_source_pagerduty_team.go b/pagerduty/data_source_pagerduty_team.go index 7f2347230..736df6e74 100644 --- a/pagerduty/data_source_pagerduty_team.go +++ b/pagerduty/data_source_pagerduty_team.go @@ -49,14 +49,10 @@ func dataSourcePagerDutyTeamRead(d *schema.ResourceData, meta interface{}) error return resource.Retry(5*time.Minute, func() *resource.RetryError { resp, _, err := client.Teams.List(o) if err != nil { - if isErrCode(err, 429) { - // Delaying retry by 30s as recommended by PagerDuty - // https://developer.pagerduty.com/docs/rest-api-v2/rate-limiting/#what-are-possible-workarounds-to-the-events-api-rate-limit - time.Sleep(30 * time.Second) - return resource.RetryableError(err) - } - - return resource.NonRetryableError(err) + // Delaying retry by 30s as recommended by PagerDuty + // https://developer.pagerduty.com/docs/rest-api-v2/rate-limiting/#what-are-possible-workarounds-to-the-events-api-rate-limit + time.Sleep(30 * time.Second) + return resource.RetryableError(err) } var found *pagerduty.Team