From 866b64bf13fc079970572d4fe3e5c1f2880e89e4 Mon Sep 17 00:00:00 2001 From: Carlos Gajardo Date: Fri, 4 Oct 2024 10:23:01 -0300 Subject: [PATCH] Add resource and data source for Alert Grouping Setting --- go.mod | 4 +- go.sum | 8 +- ...source_pagerduty_alert_grouping_setting.go | 110 +++++ ...e_pagerduty_alert_grouping_setting_test.go | 131 ++++++ pagerdutyplugin/provider.go | 2 + ...source_pagerduty_alert_grouping_setting.go | 419 ++++++++++++++++++ ...e_pagerduty_alert_grouping_setting_test.go | 274 ++++++++++++ .../go-pagerduty/alert_grouping_setting.go | 215 +++++++++ vendor/modules.txt | 4 +- .../d/alert_grouping_setting.html.markdown | 43 ++ .../r/alert_grouping_setting.html.markdown | 66 +++ 11 files changed, 1268 insertions(+), 8 deletions(-) create mode 100644 pagerdutyplugin/data_source_pagerduty_alert_grouping_setting.go create mode 100644 pagerdutyplugin/data_source_pagerduty_alert_grouping_setting_test.go create mode 100644 pagerdutyplugin/resource_pagerduty_alert_grouping_setting.go create mode 100644 pagerdutyplugin/resource_pagerduty_alert_grouping_setting_test.go create mode 100644 vendor/github.com/PagerDuty/go-pagerduty/alert_grouping_setting.go create mode 100644 website/docs/d/alert_grouping_setting.html.markdown create mode 100644 website/docs/r/alert_grouping_setting.html.markdown diff --git a/go.mod b/go.mod index 297000484..8809fb6c5 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/PagerDuty/terraform-provider-pagerduty go 1.20 require ( - github.com/PagerDuty/go-pagerduty v1.8.1-0.20240524180345-9b652f07c450 + github.com/PagerDuty/go-pagerduty v1.8.1-0.20241002154647-8ceedfd04d88 github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 github.com/hashicorp/go-version v1.6.0 github.com/hashicorp/hc-install v0.6.2 @@ -66,7 +66,7 @@ require ( golang.org/x/exp v0.0.0-20230809150735-7b3493d9a819 // indirect golang.org/x/mod v0.14.0 // indirect golang.org/x/net v0.22.0 // indirect - golang.org/x/oauth2 v0.18.0 // indirect + golang.org/x/oauth2 v0.15.0 // indirect golang.org/x/sync v0.5.0 // indirect golang.org/x/sys v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect diff --git a/go.sum b/go.sum index fcd0790d5..9fca179c9 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/PagerDuty/go-pagerduty v1.8.1-0.20240524180345-9b652f07c450 h1:G8EOmgL7i+vO6hYAnjpVbPDqUpPY7ThF6NfasZntop0= -github.com/PagerDuty/go-pagerduty v1.8.1-0.20240524180345-9b652f07c450/go.mod h1:ilimTqwHSBjmvKeYA/yayDBZvzf/CX4Pwa9Qbhekzok= +github.com/PagerDuty/go-pagerduty v1.8.1-0.20241002154647-8ceedfd04d88 h1:y/icahuphX4xGMW4nLN+Bl4MbFUU4rEA9spwgcPIDJk= +github.com/PagerDuty/go-pagerduty v1.8.1-0.20241002154647-8ceedfd04d88/go.mod h1:ilimTqwHSBjmvKeYA/yayDBZvzf/CX4Pwa9Qbhekzok= github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c h1:kMFnB0vCcX7IL/m9Y5LO+KQYv+t1CQOiFe6+SV2J7bE= github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= @@ -189,8 +189,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= -golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= +golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ= +golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= diff --git a/pagerdutyplugin/data_source_pagerduty_alert_grouping_setting.go b/pagerdutyplugin/data_source_pagerduty_alert_grouping_setting.go new file mode 100644 index 000000000..208005f3b --- /dev/null +++ b/pagerdutyplugin/data_source_pagerduty_alert_grouping_setting.go @@ -0,0 +1,110 @@ +package pagerduty + +import ( + "context" + "fmt" + "log" + + "github.com/PagerDuty/go-pagerduty" + "github.com/PagerDuty/terraform-provider-pagerduty/util/apiutil" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type dataSourceAlertGroupingSetting struct{ client *pagerduty.Client } + +var _ datasource.DataSourceWithConfigure = (*dataSourceAlertGroupingSetting)(nil) + +func (*dataSourceAlertGroupingSetting) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "pagerduty_alert_grouping_setting" +} + +func (*dataSourceAlertGroupingSetting) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{Computed: true}, + "name": schema.StringAttribute{Required: true}, + "description": schema.StringAttribute{Computed: true}, + "type": schema.StringAttribute{Computed: true}, + "services": schema.ListAttribute{ + Computed: true, + ElementType: types.StringType, + }, + }, + Blocks: map[string]schema.Block{ + "config": schema.SingleNestedBlock{ + Attributes: map[string]schema.Attribute{ + "timeout": schema.Int64Attribute{ + Computed: true, + }, + "time_window": schema.Int64Attribute{ + Computed: true, + }, + "aggregate": schema.StringAttribute{ + Optional: true, + }, + "fields": schema.ListAttribute{ + ElementType: types.StringType, + Optional: true, + }, + }, + }, + }, + } +} + +func (d *dataSourceAlertGroupingSetting) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + resp.Diagnostics.Append(ConfigurePagerdutyClient(&d.client, req.ProviderData)...) +} + +func (d *dataSourceAlertGroupingSetting) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + log.Println("[INFO] Reading PagerDuty alert grouping setting") + + var searchName types.String + resp.Diagnostics.Append(req.Config.GetAttribute(ctx, path.Root("name"), &searchName)...) + if resp.Diagnostics.HasError() { + return + } + + var cursorAfter, cursorBefore string + var found *pagerduty.AlertGroupingSetting + err := apiutil.All(ctx, func(offset int) (bool, error) { + resp, err := d.client.ListAlertGroupingSettings(ctx, pagerduty.ListAlertGroupingSettingsOptions{ + After: cursorAfter, + Before: cursorBefore, + Limit: 100, + }) + if err != nil { + return false, err + } + + for _, alertGroupingSetting := range resp.AlertGroupingSettings { + if alertGroupingSetting.Name == searchName.ValueString() { + found = &alertGroupingSetting + break + } + } + + return resp.After != "", nil + }) + if err != nil { + resp.Diagnostics.AddError( + fmt.Sprintf("Error reading PagerDuty alert grouping setting %s", searchName), + err.Error(), + ) + return + } + + if found == nil { + resp.Diagnostics.AddError( + fmt.Sprintf("Unable to locate any alert grouping setting with the name: %s", searchName), + "", + ) + return + } + + model := flattenAlertGroupingSetting(found) + resp.Diagnostics.Append(resp.State.Set(ctx, &model)...) +} diff --git a/pagerdutyplugin/data_source_pagerduty_alert_grouping_setting_test.go b/pagerdutyplugin/data_source_pagerduty_alert_grouping_setting_test.go new file mode 100644 index 000000000..f26f9361f --- /dev/null +++ b/pagerdutyplugin/data_source_pagerduty_alert_grouping_setting_test.go @@ -0,0 +1,131 @@ +package pagerduty + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" +) + +func TestAccDataSourcePagerDutyAlertGroupingSetting_Time(t *testing.T) { + name := fmt.Sprintf("tf-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV5ProviderFactories: testAccProtoV5ProviderFactories(), + Steps: []resource.TestStep{ + { + Config: testAccDataSourcePagerDutyAlertGroupingSettingTimeConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccDataSourcePagerDutyAlertGroupingSetting("pagerduty_alert_grouping_setting.test", "data.pagerduty_alert_grouping_setting.by_name"), + resource.TestCheckResourceAttr("data.pagerduty_alert_grouping_setting.by_name", "name", name), + resource.TestCheckResourceAttr("data.pagerduty_alert_grouping_setting.by_name", "type", "time"), + resource.TestCheckResourceAttrSet("data.pagerduty_alert_grouping_setting.by_name", "description"), + resource.TestCheckResourceAttr("data.pagerduty_alert_grouping_setting.by_name", "services.#", "1"), + ), + }, + }, + }) +} + +func TestAccDataSourcePagerDutyAlertGroupingSetting_ContentBased(t *testing.T) { + name := fmt.Sprintf("tf-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV5ProviderFactories: testAccProtoV5ProviderFactories(), + Steps: []resource.TestStep{ + { + Config: testAccDataSourcePagerDutyAlertGroupingSettingContentBasedConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccDataSourcePagerDutyAlertGroupingSetting("pagerduty_alert_grouping_setting.test", "data.pagerduty_alert_grouping_setting.by_name"), + resource.TestCheckResourceAttr("data.pagerduty_alert_grouping_setting.by_name", "name", name), + resource.TestCheckResourceAttr("data.pagerduty_alert_grouping_setting.by_name", "type", "content_based"), + resource.TestCheckResourceAttrSet("data.pagerduty_alert_grouping_setting.by_name", "description"), + resource.TestCheckResourceAttr("data.pagerduty_alert_grouping_setting.by_name", "services.#", "1"), + resource.TestCheckResourceAttr("data.pagerduty_alert_grouping_setting.by_name", "config.time_window", "300"), + resource.TestCheckResourceAttr("data.pagerduty_alert_grouping_setting.by_name", "config.aggregate", "any"), + resource.TestCheckResourceAttr("data.pagerduty_alert_grouping_setting.by_name", "config.fields.#", "1"), + resource.TestCheckResourceAttr("data.pagerduty_alert_grouping_setting.by_name", "config.fields.0", "summary"), + ), + }, + }, + }) +} + +func testAccDataSourcePagerDutyAlertGroupingSetting(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 a alert grouping setting ID from PagerDuty") + } + + testAtts := []string{"id", "name"} + + for _, att := range testAtts { + if a[att] != srcA[att] { + return fmt.Errorf("Expected the alert grouping setting %s to be: %s, but got: %s", att, srcA[att], a[att]) + } + } + + return nil + } +} + +func testAccDataSourcePagerDutyAlertGroupingSettingTimeConfig(name string) string { + return fmt.Sprintf(` +data "pagerduty_escalation_policy" "test" { + name = "Default" +} + +resource "pagerduty_service" "test" { + name = "%s" + escalation_policy = data.pagerduty_escalation_policy.test.id +} + +resource "pagerduty_alert_grouping_setting" "test" { + name = "%[1]s" + type = "time" + services = [pagerduty_service.test.id] + config {} +} + +data "pagerduty_alert_grouping_setting" "by_name" { + name = pagerduty_alert_grouping_setting.test.name +} +`, name) +} + +func testAccDataSourcePagerDutyAlertGroupingSettingContentBasedConfig(name string) string { + return fmt.Sprintf(` +data "pagerduty_escalation_policy" "test" { + name = "Default" +} + +resource "pagerduty_service" "test" { + name = "%s" + escalation_policy = data.pagerduty_escalation_policy.test.id +} + +resource "pagerduty_alert_grouping_setting" "test" { + name = "%[1]s" + type = "content_based" + services = [pagerduty_service.test.id] + config { + aggregate = "any" + fields = ["summary"] + } +} + +data "pagerduty_alert_grouping_setting" "by_name" { + name = pagerduty_alert_grouping_setting.test.name +} +`, name) +} diff --git a/pagerdutyplugin/provider.go b/pagerdutyplugin/provider.go index 4a6f7e795..1e1050af9 100644 --- a/pagerdutyplugin/provider.go +++ b/pagerdutyplugin/provider.go @@ -52,6 +52,7 @@ func (p *Provider) Schema(_ context.Context, _ provider.SchemaRequest, resp *pro func (p *Provider) DataSources(_ context.Context) [](func() datasource.DataSource) { return [](func() datasource.DataSource){ + func() datasource.DataSource { return &dataSourceAlertGroupingSetting{} }, func() datasource.DataSource { return &dataSourceBusinessService{} }, func() datasource.DataSource { return &dataSourceExtensionSchema{} }, func() datasource.DataSource { return &dataSourceIntegration{} }, @@ -69,6 +70,7 @@ func (p *Provider) DataSources(_ context.Context) [](func() datasource.DataSourc func (p *Provider) Resources(_ context.Context) [](func() resource.Resource) { return [](func() resource.Resource){ func() resource.Resource { return &resourceAddon{} }, + func() resource.Resource { return &resourceAlertGroupingSetting{} }, func() resource.Resource { return &resourceBusinessService{} }, func() resource.Resource { return &resourceExtensionServiceNow{} }, func() resource.Resource { return &resourceExtension{} }, diff --git a/pagerdutyplugin/resource_pagerduty_alert_grouping_setting.go b/pagerdutyplugin/resource_pagerduty_alert_grouping_setting.go new file mode 100644 index 000000000..1b2f10e6f --- /dev/null +++ b/pagerdutyplugin/resource_pagerduty_alert_grouping_setting.go @@ -0,0 +1,419 @@ +package pagerduty + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/PagerDuty/go-pagerduty" + "github.com/PagerDuty/terraform-provider-pagerduty/util" + "github.com/hashicorp/terraform-plugin-framework-validators/int64validator" + "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" +) + +type resourceAlertGroupingSetting struct{ client *pagerduty.Client } + +var ( + _ resource.ResourceWithConfigure = (*resourceAlertGroupingSetting)(nil) + _ resource.ResourceWithImportState = (*resourceAlertGroupingSetting)(nil) + _ resource.ResourceWithValidateConfig = (*resourceAlertGroupingSetting)(nil) +) + +func (r *resourceAlertGroupingSetting) Metadata(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "pagerduty_alert_grouping_setting" +} + +func (r *resourceAlertGroupingSetting) ValidateConfig(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) { + var model resourceAlertGroupingSettingModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &model)...) + if resp.Diagnostics.HasError() { + return + } + + /* + t := pagerduty.AlertGroupingSettingType(model.Type.ValueString()) + attr := model.Config.Attributes() + + if t != pagerduty.AlertGroupingSettingTimeType { + if attr["time_window"].IsNull() { + resp.Diagnostics.AddAttributeError(path.Root("config").AtName("time_window"), + "Invalid configuration", + fmt.Sprintf("Field cannot be blank when 'type' is '%s'.", t)) + } + } + + if t == pagerduty.AlertGroupingSettingContentBasedType || t == pagerduty.AlertGroupingSettingContentBasedIntelligentType { + if attr["aggregate"].IsNull() { + resp.Diagnostics.AddAttributeError(path.Root("config").AtName("aggregate"), + "Invalid configuration", + fmt.Sprintf("Field cannot be blank when 'type' is '%s'.", t)) + } + if attr["fields"].IsNull() { + resp.Diagnostics.AddAttributeError(path.Root("config").AtName("fields"), + "Invalid configuration", + fmt.Sprintf("Field cannot be blank when 'type' is '%s'.", t)) + } + } + + if t == pagerduty.AlertGroupingSettingTimeType { + if attr["timeout"].IsNull() { + resp.Diagnostics.AddAttributeError(path.Root("config").AtName("time_window"), + "Invalid configuration", + fmt.Sprintf("Field cannot be blank when 'type' is '%s'.", t)) + } + } + */ +} + +func (r *resourceAlertGroupingSetting) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "name": schema.StringAttribute{ + Required: true, + }, + "description": schema.StringAttribute{ + Computed: true, + Optional: true, + Default: stringdefault.StaticString("Managed by Terraform"), + }, + "type": schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + stringvalidator.OneOf( + "content_based", + "content_based_intelligent", + "intelligent", + "time", + ), + }, + }, + "services": schema.ListAttribute{ + ElementType: types.StringType, + Required: true, + Validators: []validator.List{ + listvalidator.SizeAtLeast(1), + }, + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, + }, + }, + Blocks: map[string]schema.Block{ + "config": schema.SingleNestedBlock{ + Attributes: map[string]schema.Attribute{ + "timeout": schema.Int64Attribute{ + Optional: true, + Computed: true, + Validators: []validator.Int64{int64validator.NoneOf(0)}, + }, + "time_window": schema.Int64Attribute{ + Optional: true, + Computed: true, + Validators: []validator.Int64{int64validator.NoneOf(0)}, + }, + "aggregate": schema.StringAttribute{ + Optional: true, + }, + "fields": schema.ListAttribute{ + ElementType: types.StringType, + Optional: true, + }, + }, + }, + }, + } +} + +func (r *resourceAlertGroupingSetting) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var model resourceAlertGroupingSettingModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &model)...) + if resp.Diagnostics.HasError() { + return + } + plan := buildPagerdutyAlertGroupingSetting(ctx, &model, &resp.Diagnostics) + log.Printf("[INFO] Creating PagerDuty alert grouping setting %s", plan.Name) + + err := retry.RetryContext(ctx, 2*time.Minute, func() *retry.RetryError { + response, err := r.client.CreateAlertGroupingSetting(ctx, plan) + if err != nil { + return retry.RetryableError(err) + } + plan.ID = response.ID + return nil + }) + if err != nil { + resp.Diagnostics.AddError( + fmt.Sprintf("Error creating PagerDuty alert grouping setting %s", plan.Name), + err.Error(), + ) + return + } + + model, err = requestGetAlertGroupingSetting(ctx, r.client, plan.ID, true, &resp.Diagnostics) + if err != nil { + resp.Diagnostics.AddError( + fmt.Sprintf("Error reading PagerDuty alert grouping setting %s", plan.ID), + err.Error(), + ) + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &model)...) +} + +func (r *resourceAlertGroupingSetting) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var id types.String + + resp.Diagnostics.Append(req.State.GetAttribute(ctx, path.Root("id"), &id)...) + if resp.Diagnostics.HasError() { + return + } + log.Printf("[INFO] Reading PagerDuty alert grouping setting %s", id) + + state, err := requestGetAlertGroupingSetting(ctx, r.client, id.ValueString(), false, &resp.Diagnostics) + if err != nil { + if util.IsNotFoundError(err) { + resp.State.RemoveResource(ctx) + return + } + resp.Diagnostics.AddError( + fmt.Sprintf("Error reading PagerDuty alert grouping setting %s", id), + err.Error(), + ) + return + } + resp.Diagnostics.Append(resp.State.Set(ctx, state)...) +} + +func (r *resourceAlertGroupingSetting) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var model resourceAlertGroupingSettingModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &model)...) + if resp.Diagnostics.HasError() { + return + } + + plan := buildPagerdutyAlertGroupingSetting(ctx, &model, &resp.Diagnostics) + log.Printf("[INFO] Updating PagerDuty alert grouping setting %s", plan.ID) + + alertGroupingSetting, err := r.client.UpdateAlertGroupingSetting(ctx, plan) + if err != nil { + if util.IsNotFoundError(err) { + resp.State.RemoveResource(ctx) + return + } + resp.Diagnostics.AddError( + fmt.Sprintf("Error creating PagerDuty alert grouping setting %s", plan.Name), + err.Error(), + ) + return + } + model = flattenAlertGroupingSetting(alertGroupingSetting) + + resp.Diagnostics.Append(resp.State.Set(ctx, &model)...) +} + +func (r *resourceAlertGroupingSetting) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var id types.String + + resp.Diagnostics.Append(req.State.GetAttribute(ctx, path.Root("id"), &id)...) + if resp.Diagnostics.HasError() { + return + } + log.Printf("[INFO] Deleting PagerDuty alert grouping setting %s", id) + + err := r.client.DeleteAlertGroupingSetting(ctx, id.ValueString()) + if err != nil && !util.IsNotFoundError(err) { + resp.Diagnostics.AddError( + fmt.Sprintf("Error deleting PagerDuty alert grouping setting %s", id), + err.Error(), + ) + return + } + resp.State.RemoveResource(ctx) +} + +func (r *resourceAlertGroupingSetting) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + resp.Diagnostics.Append(ConfigurePagerdutyClient(&r.client, req.ProviderData)...) +} + +func (r *resourceAlertGroupingSetting) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) +} + +type resourceAlertGroupingSettingModel struct { + ID types.String `tfsdk:"id"` + Name types.String `tfsdk:"name"` + Description types.String `tfsdk:"description"` + Type types.String `tfsdk:"type"` + Config types.Object `tfsdk:"config"` + Services types.List `tfsdk:"services"` +} + +func requestGetAlertGroupingSetting(ctx context.Context, client *pagerduty.Client, id string, retryNotFound bool, diags *diag.Diagnostics) (resourceAlertGroupingSettingModel, error) { + var model resourceAlertGroupingSettingModel + + err := retry.RetryContext(ctx, 2*time.Minute, func() *retry.RetryError { + alertGroupingSetting, err := client.GetAlertGroupingSetting(ctx, id) + if err != nil { + if util.IsBadRequestError(err) { + return retry.NonRetryableError(err) + } + if !retryNotFound && util.IsNotFoundError(err) { + return retry.NonRetryableError(err) + } + return retry.RetryableError(err) + } + model = flattenAlertGroupingSetting(alertGroupingSetting) + return nil + }) + + return model, err +} + +func buildPagerdutyAlertGroupingSetting(ctx context.Context, model *resourceAlertGroupingSettingModel, diags *diag.Diagnostics) pagerduty.AlertGroupingSetting { + alertGroupingSetting := pagerduty.AlertGroupingSetting{ + ID: model.ID.ValueString(), + Name: model.Name.ValueString(), + Description: model.Description.ValueString(), + Type: pagerduty.AlertGroupingSettingType(model.Type.ValueString()), + Config: buildPagerdutyAlertGroupingSettingConfig(ctx, model, diags), + Services: buildPagerdutyAlertGroupingSettingServices(model), + } + return alertGroupingSetting +} + +func buildPagerdutyAlertGroupingSettingConfig(ctx context.Context, model *resourceAlertGroupingSettingModel, diags *diag.Diagnostics) interface{} { + var target struct { + Timeout types.Int64 `tfsdk:"timeout"` + TimeWindow types.Int64 `tfsdk:"time_window"` + Aggregate types.String `tfsdk:"aggregate"` + Fields types.List `tfsdk:"fields"` + } + + switch model.Type.ValueString() { + case string(pagerduty.AlertGroupingSettingContentBasedType), string(pagerduty.AlertGroupingSettingContentBasedIntelligentType): + d := model.Config.As(ctx, &target, basetypes.ObjectAsOptions{UnhandledNullAsEmpty: true}) + if diags.Append(d...); d.HasError() { + return pagerduty.AlertGroupingSettingConfigContentBased{} + } + fields := []string{} + diags.Append(target.Fields.ElementsAs(ctx, &fields, false)...) + return pagerduty.AlertGroupingSettingConfigContentBased{ + TimeWindow: uint(target.TimeWindow.ValueInt64()), + Aggregate: target.Aggregate.ValueString(), + Fields: fields, + } + + case string(pagerduty.AlertGroupingSettingIntelligentType): + diags.Append(model.Config.As(ctx, &target, basetypes.ObjectAsOptions{})...) + return pagerduty.AlertGroupingSettingConfigIntelligent{ + TimeWindow: uint(target.TimeWindow.ValueInt64()), + } + + case string(pagerduty.AlertGroupingSettingTimeType): + diags.Append(model.Config.As(ctx, &target, basetypes.ObjectAsOptions{})...) + return pagerduty.AlertGroupingSettingConfigTime{ + Timeout: uint(target.Timeout.ValueInt64()), + } + } + + return nil +} + +func buildPagerdutyAlertGroupingSettingServices(model *resourceAlertGroupingSettingModel) []pagerduty.AlertGroupingSettingService { + elements := model.Services.Elements() + list := make([]pagerduty.AlertGroupingSettingService, 0, len(elements)) + for _, e := range elements { + v, _ := e.(types.String) + list = append(list, pagerduty.AlertGroupingSettingService{ID: v.ValueString()}) + } + return list +} + +func flattenAlertGroupingSetting(response *pagerduty.AlertGroupingSetting) resourceAlertGroupingSettingModel { + model := resourceAlertGroupingSettingModel{ + ID: types.StringValue(response.ID), + Name: types.StringValue(response.Name), + Description: types.StringValue(response.Description), + Type: types.StringValue(string(response.Type)), + Config: flattenAlertGroupingSettingConfig(response), + Services: flattenAlertGroupingSettingServices(response), + } + return model +} + +func flattenAlertGroupingSettingConfig(response *pagerduty.AlertGroupingSetting) types.Object { + var alertGroupingSettingConfigAttrTypes = map[string]attr.Type{ + "timeout": types.Int64Type, + "time_window": types.Int64Type, + "aggregate": types.StringType, + "fields": types.ListType{ElemType: types.StringType}, + } + + var obj map[string]attr.Value + + switch c := response.Config.(type) { + case pagerduty.AlertGroupingSettingConfigContentBased: + fields := make([]attr.Value, 0, len(c.Fields)) + for _, f := range c.Fields { + fields = append(fields, types.StringValue(f)) + } + tw := types.Int64Value(int64(c.TimeWindow)) + obj = map[string]attr.Value{ + "timeout": types.Int64Null(), + "time_window": tw, + "aggregate": types.StringValue(c.Aggregate), + "fields": types.ListValueMust(types.StringType, fields), + } + + case pagerduty.AlertGroupingSettingConfigIntelligent: + obj = map[string]attr.Value{ + "timeout": types.Int64Null(), + "time_window": types.Int64Value(int64(c.TimeWindow)), + "aggregate": types.StringNull(), + "fields": types.ListNull(types.StringType), + } + + case pagerduty.AlertGroupingSettingConfigTime: + obj = map[string]attr.Value{ + "timeout": types.Int64Value(int64(c.Timeout)), + "time_window": types.Int64Null(), + "aggregate": types.StringNull(), + "fields": types.ListNull(types.StringType), + } + } + + return types.ObjectValueMust(alertGroupingSettingConfigAttrTypes, obj) +} + +func flattenAlertGroupingSettingServices(response *pagerduty.AlertGroupingSetting) types.List { + serviceIDs := make([]attr.Value, 0, len(response.Services)) + for _, s := range response.Services { + serviceIDs = append(serviceIDs, types.StringValue(s.ID)) + } + return types.ListValueMust(types.StringType, serviceIDs) +} diff --git a/pagerdutyplugin/resource_pagerduty_alert_grouping_setting_test.go b/pagerdutyplugin/resource_pagerduty_alert_grouping_setting_test.go new file mode 100644 index 000000000..e1efbcfe1 --- /dev/null +++ b/pagerdutyplugin/resource_pagerduty_alert_grouping_setting_test.go @@ -0,0 +1,274 @@ +package pagerduty + +import ( + "context" + "fmt" + "log" + "strings" + "testing" + + "github.com/PagerDuty/go-pagerduty" + "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" +) + +func init() { + resource.AddTestSweepers("pagerduty_alert_grouping_setting", &resource.Sweeper{ + Name: "pagerduty_alert_grouping_setting", + F: testSweepAlertGroupingSetting, + }) +} + +func testSweepAlertGroupingSetting(_ string) error { + ctx := context.Background() + + resp, err := testAccProvider.client.ListAlertGroupingSettings(ctx, pagerduty.ListAlertGroupingSettingsOptions{ + Limit: 100, + }) + if err != nil { + return err + } + + for _, setting := range resp.AlertGroupingSettings { + if strings.HasPrefix(setting.Name, "test") || strings.HasPrefix(setting.Name, "tf-") { + log.Printf("Destroying alert grouping setting %s (%s)", setting.Name, setting.ID) + if err := testAccProvider.client.DeleteAlertGroupingSetting(ctx, setting.ID); err != nil { + return err + } + } + } + + return nil +} + +func TestAccPagerDutyAlertGroupingSetting_Basic(t *testing.T) { + ref := fmt.Sprint("tf-", acctest.RandString(5)) + resourceRef := "pagerduty_alert_grouping_setting." + ref + + service := fmt.Sprint("tf-", acctest.RandString(5)) + serviceUpdated := fmt.Sprint("tf-", acctest.RandString(5)) + name := ref + "'s name" + nameUpdated := ref + "'s name updated" + + configType := string(pagerduty.AlertGroupingSettingContentBasedType) + config := pagerduty.AlertGroupingSettingConfigContentBased{ + TimeWindow: 0, + Aggregate: "all", + Fields: []string{"summary"}, + } + configTypeUpdated := string(pagerduty.AlertGroupingSettingTimeType) + configUpdated := pagerduty.AlertGroupingSettingConfigTime{Timeout: 60} + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV5ProviderFactories: testAccProtoV5ProviderFactories(), + CheckDestroy: testAccCheckPagerDutyAlertGroupingSettingDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckPagerDutyAlertGroupingSettingConfig(ref, name, configType, service, config), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyAlertGroupingSettingExists(resourceRef), + resource.TestCheckResourceAttr(resourceRef, "name", name), + resource.TestCheckResourceAttrSet(resourceRef, "description"), + resource.TestCheckResourceAttr(resourceRef, "type", configType), + resource.TestCheckResourceAttr(resourceRef, "config.time_window", fmt.Sprint(300)), + resource.TestCheckResourceAttr(resourceRef, "config.aggregate", config.Aggregate), + resource.TestCheckResourceAttr(resourceRef, "config.fields.0", config.Fields[0]), + resource.TestCheckResourceAttrSet(resourceRef, "services.0"), + ), + }, + { + Config: testAccCheckPagerDutyAlertGroupingSettingConfig(ref, nameUpdated, configTypeUpdated, serviceUpdated, configUpdated), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyAlertGroupingSettingExists(resourceRef), + resource.TestCheckResourceAttr(resourceRef, "name", nameUpdated), + resource.TestCheckResourceAttrSet(resourceRef, "description"), + resource.TestCheckResourceAttr(resourceRef, "type", configTypeUpdated), + resource.TestCheckResourceAttr(resourceRef, "config.timeout", fmt.Sprint(configUpdated.Timeout)), + resource.TestCheckResourceAttrSet(resourceRef, "services.0"), + ), + }, + }, + }) +} + +func TestAccPagerDutyAlertGroupingSetting_ContentBased_WithTimeWindow(t *testing.T) { + ref := fmt.Sprint("tf-", acctest.RandString(5)) + resourceRef := "pagerduty_alert_grouping_setting." + ref + name := ref + "'s name" + + configType := string(pagerduty.AlertGroupingSettingContentBasedType) + config := pagerduty.AlertGroupingSettingConfigContentBased{ + TimeWindow: 600, + Aggregate: "all", + Fields: []string{"summary"}, + } + + service := fmt.Sprint("tf-", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV5ProviderFactories: testAccProtoV5ProviderFactories(), + CheckDestroy: testAccCheckPagerDutyAlertGroupingSettingDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckPagerDutyAlertGroupingSettingConfig(ref, name, configType, service, config), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyAlertGroupingSettingExists(resourceRef), + resource.TestCheckResourceAttr(resourceRef, "name", name), + resource.TestCheckResourceAttrSet(resourceRef, "description"), + resource.TestCheckResourceAttr(resourceRef, "type", configType), + resource.TestCheckResourceAttr(resourceRef, "config.time_window", fmt.Sprint(config.TimeWindow)), + resource.TestCheckResourceAttr(resourceRef, "config.aggregate", config.Aggregate), + resource.TestCheckResourceAttr(resourceRef, "config.fields.0", config.Fields[0]), + resource.TestCheckResourceAttrSet(resourceRef, "services.0"), + ), + }, + }, + }) +} + +func TestAccPagerDutyAlertGroupingSetting_Time_WithTimeoutZero(t *testing.T) { + ref := fmt.Sprint("tf-", acctest.RandString(5)) + name := ref + + configType := string(pagerduty.AlertGroupingSettingTimeType) + config := pagerduty.AlertGroupingSettingConfigTime{Timeout: 0} + + service := fmt.Sprint("tf-", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV5ProviderFactories: testAccProtoV5ProviderFactories(), + CheckDestroy: testAccCheckPagerDutyAlertGroupingSettingDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckPagerDutyAlertGroupingSettingConfig(ref, name, configType, service, config), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyAlertGroupingSettingExists("pagerduty_alert_grouping_setting."+ref), + resource.TestCheckResourceAttr("pagerduty_alert_grouping_setting."+ref, "name", name), + resource.TestCheckResourceAttrSet("pagerduty_alert_grouping_setting."+ref, "description"), + resource.TestCheckResourceAttr("pagerduty_alert_grouping_setting."+ref, "type", configType), + resource.TestCheckResourceAttr("pagerduty_alert_grouping_setting."+ref, "config.timeout", fmt.Sprint(config.Timeout)), + resource.TestCheckResourceAttrSet("pagerduty_alert_grouping_setting."+ref, "services.0"), + ), + }, + }, + }) +} + +func testAccCheckPagerDutyAlertGroupingSettingDestroy(s *terraform.State) error { + for _, r := range s.RootModule().Resources { + if r.Type != "pagerduty_alert_grouping_setting" { + continue + } + + ctx := context.Background() + + if _, err := testAccProvider.client.GetAlertGroupingSetting(ctx, r.Primary.ID); err == nil { + return fmt.Errorf("Alert grouping setting still exists") + } + + } + return nil +} + +func testAccCheckPagerDutyAlertGroupingSettingExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + ctx := context.Background() + + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No alert grouping setting ID is set") + } + + found, err := testAccProvider.client.GetAlertGroupingSetting(ctx, rs.Primary.ID) + if err != nil { + return err + } + + if found.ID != rs.Primary.ID { + return fmt.Errorf("Alert grouping setting not found: %v - %v", rs.Primary.ID, found) + } + + return nil + } +} + +func helperConfigPagerDutyAlertGroupingSettingConfig(config interface{}) string { + switch c := config.(type) { + case pagerduty.AlertGroupingSettingConfigContentBased: + timeWindowStr := "" + if c.TimeWindow != 0 { + timeWindowStr = fmt.Sprintf("time_window = %d", c.TimeWindow) + } + return fmt.Sprintf(`{ + %s + aggregate = "%s" + fields = ["%s"] + }`, timeWindowStr, c.Aggregate, strings.Join(c.Fields, `","`)) + case pagerduty.AlertGroupingSettingConfigIntelligent: + timeWindowStr := "" + if c.TimeWindow != 0 { + timeWindowStr = fmt.Sprintf("time_window = %d", c.TimeWindow) + } + return fmt.Sprintf("{\n\t%s\n}", timeWindowStr) + case pagerduty.AlertGroupingSettingConfigTime: + timeoutStr := "" + if c.Timeout != 0 { + timeoutStr = fmt.Sprintf("timeout = %d", c.Timeout) + } + return fmt.Sprintf("{\n%s\n}", timeoutStr) + } + return "{}" +} + +func testAccCheckPagerDutyAlertGroupingSettingConfig(ref, name, cfgType, serviceName string, cfg interface{}) string { + config := helperConfigPagerDutyAlertGroupingSettingConfig(cfg) + return fmt.Sprintf(` +data "pagerduty_escalation_policy" "default" { + name = "Default" +} + +resource "pagerduty_service" "%[4]s" { + name = "%[4]s" + escalation_policy = data.pagerduty_escalation_policy.default.id +} + +resource "pagerduty_alert_grouping_setting" "%[1]s" { + name = "%[2]s" + type = "%[3]s" + services = [pagerduty_service.%[4]s.id] + config %[5]s +}`, ref, name, cfgType, serviceName, config) +} + +func testAccCheckPagerDutyAlertGroupingSettingConfigUpdated(ref, name, cfgType, serviceName string, cfg interface{}) string { + config := helperConfigPagerDutyAlertGroupingSettingConfig(cfg) + return fmt.Sprintf(` +data "pagerduty_escalation_policy" "default" { + name = "Default" +} + +resource "pagerduty_service" "%[4]s" { + name = "%[4]s" + escalation_policy = data.pagerduty_escalation_policy.default.id +} + +resource "pagerduty_service" "%[4]s-copy" { + name = "Copy of %[4]s" + escalation_policy = data.pagerduty_escalation_policy.default.id +} + +resource "pagerduty_alert_grouping_setting" "%[1]s" { + name = "%[2]s" + type = "%[3]s" + services = [pagerduty_service.%[4]s.id, pagerduty_service.%[4]s-copy.id] + config %[5]s +}`, ref, name, cfgType, serviceName, config) +} diff --git a/vendor/github.com/PagerDuty/go-pagerduty/alert_grouping_setting.go b/vendor/github.com/PagerDuty/go-pagerduty/alert_grouping_setting.go new file mode 100644 index 000000000..c7e0cb3c7 --- /dev/null +++ b/vendor/github.com/PagerDuty/go-pagerduty/alert_grouping_setting.go @@ -0,0 +1,215 @@ +package pagerduty + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/google/go-querystring/query" +) + +// AlertGroupingSettingConfigTime is the configuration content for a +// AlertGroupingSetting of type "time" +type AlertGroupingSettingConfigTime struct { + Timeout uint `json:"timeout"` +} + +// AlertGroupingSettingConfigIntelligent is the configuration content for a +// AlertGroupingSetting of type "intelligent" +type AlertGroupingSettingConfigIntelligent struct { + TimeWindow uint `json:"time_window"` + RecommendedTimeWindow *uint `json:"recommended_time_window,omitempty"` +} + +// AlertGroupingSettingConfigContentBased is the configuration content for a +// AlertGroupingSetting of type "content_based" or "content_based_intelligent" +type AlertGroupingSettingConfigContentBased struct { + TimeWindow uint `json:"time_window"` + RecommendedTimeWindow *uint `json:"recommended_time_window,omitempty"` + Aggregate string `json:"aggregate"` + Fields []string `json:"fields"` +} + +type AlertGroupingSettingType string + +const ( + AlertGroupingSettingContentBasedType AlertGroupingSettingType = "content_based" + AlertGroupingSettingContentBasedIntelligentType AlertGroupingSettingType = "content_based_intelligent" + AlertGroupingSettingIntelligentType AlertGroupingSettingType = "intelligent" + AlertGroupingSettingTimeType AlertGroupingSettingType = "time" +) + +// AlertGroupingSetting is a configuration used during the grouping of the +// alerts easier to reuse and share between many services +type AlertGroupingSetting struct { + ID string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Description string `json:"description,omitempty"` + Type AlertGroupingSettingType `json:"type,omitempty"` + Config interface{} `json:"config,omitempty"` + Services []AlertGroupingSettingService `json:"services"` +} + +// AlertGroupingSettingService is a reference to services associated with an +// alert grouping setting. +type AlertGroupingSettingService struct { + ID string `json:"id,omitempty"` + Name string `json:"name,omitempty"` +} + +// CreateAlertGroupingSetting creates an instance of AlertGroupingSettings for +// either one service or many services that are in the alert group setting +func (c *Client) CreateAlertGroupingSetting(ctx context.Context, a AlertGroupingSetting) (*AlertGroupingSetting, error) { + d := map[string]AlertGroupingSetting{"alert_grouping_setting": a} + + resp, err := c.post(ctx, "/alert_grouping_settings", d, nil) + if err != nil { + return nil, err + } + + var resultRaw struct { + AlertGroupingSetting alertGroupingSettingRaw `json:"alert_grouping_setting"` + } + if err := c.decodeJSON(resp, &resultRaw); err != nil { + return nil, fmt.Errorf("Could not decode JSON response: %v", err) + } + + value := resultRaw.AlertGroupingSetting + return getAlertGroupingSettingFromRaw(value) +} + +// ListAlertGroupingSettingsOptions is the data structure used when calling the +// ListAlertGroupingSettings API endpoint. +type ListAlertGroupingSettingsOptions struct { + After string `url:"after,omitempty"` + Before string `url:"before,omitempty"` + Limit uint `url:"limit,omitempty"` + Total bool `url:"total,omitempty"` + ServiceIDs []string `url:"service_ids,omitempty,brackets"` +} + +// ListAlertGroupingSettingsResponse is the data structure returned from calling +// the ListAlertGroupingSettingsResponse API endpoint. +type ListAlertGroupingSettingsResponse struct { + After string `json:"after,omitempty"` + Before string `json:"before,omitempty"` + Limit uint `json:"limit,omitempty"` + Total bool `json:"total,omitempty"` + AlertGroupingSettings []AlertGroupingSetting `json:"alert_grouping_settings"` +} + +// ListAlertGroupingSettings lists all of your alert grouping settings including +// both single service settings and global content based settings. +func (c *Client) ListAlertGroupingSettings(ctx context.Context, o ListAlertGroupingSettingsOptions) (*ListAlertGroupingSettingsResponse, error) { + v, err := query.Values(o) + if err != nil { + return nil, err + } + + resp, err := c.get(ctx, "/alert_grouping_settings?"+v.Encode(), nil) + if err != nil { + return nil, err + } + + var resultRaw struct { + ListAlertGroupingSettingsResponse + AlertGroupingSettings []alertGroupingSettingRaw `json:"alert_grouping_settings"` + } + + if err = c.decodeJSON(resp, &resultRaw); err != nil { + return nil, err + } + + settings := make([]AlertGroupingSetting, 0, len(resultRaw.AlertGroupingSettings)) + for _, rawItem := range resultRaw.AlertGroupingSettings { + v, _ := getAlertGroupingSettingFromRaw(rawItem) + if v != nil { + settings = append(settings, *v) + } + } + + result := &resultRaw.ListAlertGroupingSettingsResponse + result.AlertGroupingSettings = settings + return result, nil +} + +// GetAlertGroupingSetting get an existing Alert Grouping Setting. +func (c *Client) GetAlertGroupingSetting(ctx context.Context, id string) (*AlertGroupingSetting, error) { + resp, err := c.get(ctx, "/alert_grouping_settings/"+id, nil) + if err != nil { + return nil, err + } + + var resultRaw struct { + AlertGroupingSetting alertGroupingSettingRaw `json:"alert_grouping_setting"` + } + if err := c.decodeJSON(resp, &resultRaw); err != nil { + return nil, fmt.Errorf("Could not decode JSON response: %v", err) + } + + value := resultRaw.AlertGroupingSetting + return getAlertGroupingSettingFromRaw(value) +} + +// DeleteAlertGroupingSetting deletes an existing Alert Grouping Setting. +func (c *Client) DeleteAlertGroupingSetting(ctx context.Context, id string) error { + _, err := c.delete(ctx, "/alert_grouping_settings/"+id) + return err +} + +// UpdateAlertGroupingSetting updates an Alert Grouping Setting. +func (c *Client) UpdateAlertGroupingSetting(ctx context.Context, a AlertGroupingSetting) (*AlertGroupingSetting, error) { + d := map[string]AlertGroupingSetting{"alert_grouping_setting": a} + + resp, err := c.put(ctx, "/alert_grouping_settings/"+a.ID, d, nil) + if err != nil { + return nil, err + } + + var resultRaw struct { + AlertGroupingSetting alertGroupingSettingRaw `json:"alert_grouping_setting"` + } + if err := c.decodeJSON(resp, &resultRaw); err != nil { + return nil, fmt.Errorf("Could not decode JSON response: %v", err) + } + + value := resultRaw.AlertGroupingSetting + return getAlertGroupingSettingFromRaw(value) +} + +// alertGroupingSettingRaw is an AlertGroupingSetting that overrides its Config with a json raw +// message in order to parse it later. +type alertGroupingSettingRaw struct { + AlertGroupingSetting + Config json.RawMessage `json:"config,omitempty"` +} + +// getAlertGroupingSettingFromRaw transform the content of a Alert Grouping +// Setting "config" field from a json raw message into the data structure +// corresponding to its "type". +func getAlertGroupingSettingFromRaw(raw alertGroupingSettingRaw) (*AlertGroupingSetting, error) { + result := &raw.AlertGroupingSetting + + switch raw.Type { + case AlertGroupingSettingContentBasedType, AlertGroupingSettingContentBasedIntelligentType: + var cfg AlertGroupingSettingConfigContentBased + if err := json.Unmarshal(raw.Config, &cfg); err != nil { + return nil, err + } + result.Config = cfg + case AlertGroupingSettingIntelligentType: + var cfg AlertGroupingSettingConfigIntelligent + if err := json.Unmarshal(raw.Config, &cfg); err != nil { + return nil, err + } + result.Config = cfg + case AlertGroupingSettingTimeType: + var cfg AlertGroupingSettingConfigTime + if err := json.Unmarshal(raw.Config, &cfg); err != nil { + return nil, err + } + result.Config = cfg + } + + return result, nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 378228d51..0fd87e8d4 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,4 +1,4 @@ -# github.com/PagerDuty/go-pagerduty v1.8.1-0.20240524180345-9b652f07c450 +# github.com/PagerDuty/go-pagerduty v1.8.1-0.20241002154647-8ceedfd04d88 ## explicit; go 1.19 github.com/PagerDuty/go-pagerduty # github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c @@ -422,7 +422,7 @@ golang.org/x/net/http2/hpack golang.org/x/net/idna golang.org/x/net/internal/timeseries golang.org/x/net/trace -# golang.org/x/oauth2 v0.18.0 +# golang.org/x/oauth2 v0.15.0 ## explicit; go 1.18 golang.org/x/oauth2 golang.org/x/oauth2/clientcredentials diff --git a/website/docs/d/alert_grouping_setting.html.markdown b/website/docs/d/alert_grouping_setting.html.markdown new file mode 100644 index 000000000..0a0f5e40e --- /dev/null +++ b/website/docs/d/alert_grouping_setting.html.markdown @@ -0,0 +1,43 @@ +--- +layout: "pagerduty" +page_title: "PagerDuty: pagerduty_alert_grouping_setting" +sidebar_current: "docs-pagerduty-datasource-alert-grouping-setting" +description: |- + Get information about an alert grouping setting that you have created. +--- + +# pagerduty\_alert\_grouping\_setting + +Use this data source to get information about a specific [alert grouping setting][1]. + +## Example Usage + +```hcl +data "pagerduty_alert_grouping_setting" "example" { + name = "My example setting" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name to use to find an alert grouping setting in the PagerDuty API. + +## Attributes Reference + +* `id` - The ID of the found alert grouping setting. +* `name` - The short name of the found alert grouping setting. +* `description` - A description of this alert grouping setting. +* `type` - The type of object. The value returned will be one of `content_based`, `content_based_intelligent`, `intelligent` or `time`. +* `config` - The values for the configuration setup for this setting. +* `services` - A list of string containing the IDs of services associated with this setting. + +The `config` block contains the following arguments: + +* `timeout` - The duration in minutes within which to automatically group incoming alerts. This setting is only required and applies when `type` is set to `time`. To continue grouping alerts until the incident is resolved leave this value unset or set it to `null`. +* `aggregate` - One of `any` or `all`. This setting is only required and applies when `type` is set to `content_based` or `content_based_intelligent`. Group alerts based on one or all of `fields` value(s). +* `fields` - Alerts will be grouped together if the content of these fields match. This setting is only required and applies when `type` is set to `content_based` or `content_based_intelligent`. +* `time_window` - The maximum amount of time allowed between Alerts. This setting applies only when `type` is set to `intelligent`, `content_based`, `content_based_intelligent`. Value must be between `300` and `3600` or exactly `86400` (86400 is supported only for `content_based` alert grouping). Any Alerts arriving greater than `time_window` seconds apart will not be grouped together. This is a rolling time window and is counted from the most recently grouped alert. The window is extended every time a new alert is added to the group, up to 24 hours. To use the recommended time window leave this value unset or set it to `null`. + +[1]: https://developer.pagerduty.com/api-reference/9b5a6c8d7379b-get-an-alert-grouping-setting diff --git a/website/docs/r/alert_grouping_setting.html.markdown b/website/docs/r/alert_grouping_setting.html.markdown new file mode 100644 index 000000000..e0ff5e1f6 --- /dev/null +++ b/website/docs/r/alert_grouping_setting.html.markdown @@ -0,0 +1,66 @@ +--- +layout: "pagerduty" +page_title: "PagerDuty: pagerduty_alert_grouping_setting" +sidebar_current: "docs-pagerduty-resource-alert-grouping-setting" +description: |- + Creates and manages an alert grouping setting in PagerDuty. +--- + +# pagerduty\_alert\_grouping\_setting + +An [alert grouping setting](https://developer.pagerduty.com/api-reference/create-an-alert-grouping-setting) +stores and centralize the configuration used during grouping of the alerts. + +## Example Usage + +```hcl +data "pagerduty_escalation_policy" "default" { + name = "Default" +} + +resource "pagerduty_service" "basic" { + name = "Example" + escalation_policy = data.pagerduty_escalation_policy.default.id +} + +resource "pagerduty_alert_grouping_setting" "%[1]s" { + name = "Configuration for type-1 devices" + type = "content_based" + services = [pagerduty_service.basic.id] + config { + time_window = 300 + aggregate = "all" + fields = ["fields"] + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name for the alert groupig settings. +* `type` - (Required) The type of alert grouping; one of `intelligent`, `time`, `content_based` or `content_based_intelligent`. +* `services` - (Required) The list IDs of services associated to this setting. +* `config` - (Required) The set of values used for configuration. + +The `config` block contains the following arguments: + +* `timeout` - (Optional) The duration in minutes within which to automatically group incoming alerts. This setting is only required and applies when `type` is set to `time`. To continue grouping alerts until the incident is resolved leave this value unset or set it to `null`. +* `aggregate` - (Optional) One of `any` or `all`. This setting is only required and applies when `type` is set to `content_based` or `content_based_intelligent`. Group alerts based on one or all of `fields` value(s). +* `fields` - (Optional) Alerts will be grouped together if the content of these fields match. This setting is only required and applies when `type` is set to `content_based` or `content_based_intelligent`. +* `time_window` - (Optional) The maximum amount of time allowed between Alerts. This setting applies only when `type` is set to `intelligent`, `content_based`, `content_based_intelligent`. Value must be between `300` and `3600` or exactly `86400` (86400 is supported only for `content_based` alert grouping). Any Alerts arriving greater than `time_window` seconds apart will not be grouped together. This is a rolling time window and is counted from the most recently grouped alert. The window is extended every time a new alert is added to the group, up to 24 hours. To use the recommended time window leave this value unset or set it to `null`. + +## Attributes Reference + +The following attributes are exported: + + * `id` - The ID of the alert grouping setting. + +## Import + +Alert grouping settings can be imported using its `id`, e.g. + +``` +$ terraform import pagerduty_alert_grouping_setting.example P3DH5M6 +```