From 793fc253bfe52d2c14a7953d0b5e20310a08185b Mon Sep 17 00:00:00 2001 From: Owen Goebel Date: Wed, 31 Jul 2024 22:17:30 +0000 Subject: [PATCH] separate resource for dst works locally --- .../operation/monitorv2_destination.graphql | 2 + client/meta/genqlient.generated.go | 4 +- client/oid/oid.go | 2 + docs/resources/monitor_v2_destination.md | 50 ++++++ observe/provider.go | 1 + observe/resource_monitor_v2_destination.go | 46 ++++- .../resource_monitor_v2_destination_test.go | 162 ++++++++++++++++++ 7 files changed, 257 insertions(+), 10 deletions(-) create mode 100644 docs/resources/monitor_v2_destination.md create mode 100644 observe/resource_monitor_v2_destination_test.go diff --git a/client/internal/meta/operation/monitorv2_destination.graphql b/client/internal/meta/operation/monitorv2_destination.graphql index bbb6294e..05be3dc0 100644 --- a/client/internal/meta/operation/monitorv2_destination.graphql +++ b/client/internal/meta/operation/monitorv2_destination.graphql @@ -67,6 +67,8 @@ mutation deleteMonitorV2Destination($id: ObjectId!) { } } +# @genqlient(for: "ActionDestinationLinkInput.sendEndNotifications", omitempty: true) +# @genqlient(for: "ActionDestinationLinkInput.sendRemindersInterval", omitempty: true) mutation saveActionWithDestinationLinks( $actionId: ObjectId!, $destinationLinks: [ActionDestinationLinkInput!]! diff --git a/client/meta/genqlient.generated.go b/client/meta/genqlient.generated.go index 5868baae..28397ecf 100644 --- a/client/meta/genqlient.generated.go +++ b/client/meta/genqlient.generated.go @@ -37,8 +37,8 @@ func (v *ActionDestinationLink) GetDefinition() MonitorV2DestinationDefinition { type ActionDestinationLinkInput struct { DestinationID string `json:"destinationID"` - SendEndNotifications *bool `json:"sendEndNotifications"` - SendRemindersInterval *types.DurationScalar `json:"sendRemindersInterval"` + SendEndNotifications *bool `json:"sendEndNotifications,omitempty"` + SendRemindersInterval *types.DurationScalar `json:"sendRemindersInterval,omitempty"` } // GetDestinationID returns ActionDestinationLinkInput.DestinationID, and is useful for accessing the field via an interface. diff --git a/client/oid/oid.go b/client/oid/oid.go index 7c96efd2..3602c856 100644 --- a/client/oid/oid.go +++ b/client/oid/oid.go @@ -74,6 +74,8 @@ func (t Type) IsValid() bool { case TypeMonitorAction: case TypeMonitorActionAttachment: case TypeMonitorV2: + case TypeMonitorV2Action: + case TypeMonitorV2Destination: case TypePoller: case TypePreferredPath: case TypeUser: diff --git a/docs/resources/monitor_v2_destination.md b/docs/resources/monitor_v2_destination.md new file mode 100644 index 00000000..7714dd18 --- /dev/null +++ b/docs/resources/monitor_v2_destination.md @@ -0,0 +1,50 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "observe_monitor_v2_destination Resource - terraform-provider-observe" +subcategory: "" +description: |- + +--- +# observe_monitor_v2_destination + + + + +## Schema + +### Required + +- `action` (String) +- `name` (String) +- `type` (String) +- `workspace` (String) + +### Optional + +- `description` (String) +- `email` (Block List) (see [below for nested schema](#nestedblock--email)) +- `icon_url` (String) +- `webhook` (Block List) (see [below for nested schema](#nestedblock--webhook)) + +### Read-Only + +- `id` (String) The ID of this resource. +- `oid` (String) + + +### Nested Schema for `email` + +Optional: + +- `addresses` (List of String) +- `users` (List of String) + + + +### Nested Schema for `webhook` + +Required: + +- `method` (String) +- `url` (String) + diff --git a/observe/provider.go b/observe/provider.go index f7e4429f..61b8a4e9 100644 --- a/observe/provider.go +++ b/observe/provider.go @@ -156,6 +156,7 @@ func Provider() *schema.Provider { "observe_monitor": resourceMonitor(), "observe_monitor_v2": resourceMonitorV2(), "observe_monitor_v2_action": resourceMonitorV2Action(), + "observe_monitor_v2_destination": resourceMonitorV2Destination(), "observe_board": resourceBoard(), "observe_poller": resourcePoller(), "observe_datastream": resourceDatastream(), diff --git a/observe/resource_monitor_v2_destination.go b/observe/resource_monitor_v2_destination.go index ead707a1..8173e0a8 100644 --- a/observe/resource_monitor_v2_destination.go +++ b/observe/resource_monitor_v2_destination.go @@ -12,6 +12,36 @@ import ( "github.com/observeinc/terraform-provider-observe/client/oid" ) +/************************************************************ +* * +* FOR WHOEVER GETS PUT ON THIS TASK AFTER I LEAVE: * +* * +* This file was written when the API used to require * +* separate calls for creating a monv2 action and a * +* destination. This is why, for example, the function * +* resourceMonitorV2DestinationCreate calls 2 create * +* API calls (one to make the action, another for dest). * +* If you're reading this message with the intent of * +* modifying this file, the API has probably changed * +* so that a shared action and inlined destination can * +* be edited in a single API call, which is likely * +* what you were asked to change about this code. * +* * +* If possible, please do NOT remove any params from the * +* existing schema or add any new required params. I * +* tried to write the schema so that it would map onto * +* the new API relatively cleanly. You probably won't * +* need to change the schema, but you'll likely need to * +* change how the variables read from said schema are * +* arranged into the inputs fed to the API call. * +* * +* After making the changes, please delete this comment. * +* * +* Thanks! :) * +* - Owen * +* * +***********************************************************/ + func resourceMonitorV2Destination() *schema.Resource { return &schema.Resource{ CreateContext: resourceMonitorV2DestinationCreate, @@ -39,7 +69,7 @@ func resourceMonitorV2Destination() *schema.Resource { Type: schema.TypeList, Optional: true, ExactlyOneOf: []string{"email", "webhook"}, - Elem: &schema.Resource{}, + Elem: monitorV2EmailDestinationResource(), }, "webhook": { // MonitorV2WebhookDestinationInput Type: schema.TypeList, @@ -51,7 +81,7 @@ func resourceMonitorV2Destination() *schema.Resource { Type: schema.TypeString, Required: true, }, - "iconUrl": { // String + "icon_url": { // String Type: schema.TypeString, Optional: true, }, @@ -122,7 +152,7 @@ func resourceMonitorV2DestinationCreate(ctx context.Context, data *schema.Resour actOID, _ := oid.NewOID(data.Get("action").(string)) dstLinks := []gql.ActionDestinationLinkInput{ { - DestinationID: id.Id, + DestinationID: result.Id, }, } _, err = client.Meta.SaveActionWithDestinationLinks(ctx, actOID.Id, dstLinks) @@ -185,7 +215,7 @@ func resourceMonitorV2DestinationRead(ctx context.Context, data *schema.Resource diags = append(diags, diag.FromErr(err)...) } - if err := data.Set("id", dest.Oid().String()); err != nil { + if err := data.Set("oid", dest.Oid().String()); err != nil { diags = append(diags, diag.FromErr(err)...) } @@ -233,7 +263,7 @@ func resourceMonitorV2DestinationDelete(ctx context.Context, data *schema.Resour return diags } -func monitorV2FlattenEmailDestination(gqlEmail gql.MonitorV2EmailDestination) interface{} { +func monitorV2FlattenEmailDestination(gqlEmail gql.MonitorV2EmailDestination) []interface{} { email := make(map[string]interface{}) if len(gqlEmail.Addresses) > 0 { addrs := make([]string, 0) @@ -249,15 +279,15 @@ func monitorV2FlattenEmailDestination(gqlEmail gql.MonitorV2EmailDestination) in } email["users"] = uidStrs } - return email + return []interface{}{email} } -func monitorv2FlattenWebhookDestination(gqlWebhook gql.MonitorV2WebhookDestination) interface{} { +func monitorv2FlattenWebhookDestination(gqlWebhook gql.MonitorV2WebhookDestination) []interface{} { webhook := map[string]interface{}{ "url": gqlWebhook.Url, "method": toSnake(string(gqlWebhook.Method)), } - return webhook + return []interface{}{webhook} } func newMonitorV2DestinationInput(data *schema.ResourceData) (input *gql.MonitorV2DestinationInput, diags diag.Diagnostics) { diff --git a/observe/resource_monitor_v2_destination_test.go b/observe/resource_monitor_v2_destination_test.go new file mode 100644 index 00000000..d9d01fca --- /dev/null +++ b/observe/resource_monitor_v2_destination_test.go @@ -0,0 +1,162 @@ +package observe + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccObserveMonitorV2DestinationEmail(t *testing.T) { + randomPrefix := acctest.RandomWithPrefix("tf") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: fmt.Sprintf(monitorV2ConfigPreamble+` + resource "observe_monitor_v2" "first" { + workspace = data.observe_workspace.default.oid + rule_kind = "count" + name = "%[1]s" + lookback_time = "30m" + comment = "a descriptive comment" + inputs = { + "test" = observe_datastream.test.dataset + } + stage { + pipeline = <<-EOF + colmake kind:"test", description:"test" + EOF + output_stage = true + } + stage { + pipeline = <<-EOF + filter kind ~ "test" + EOF + } + rules { + level = "informational" + count { + compare_values { + compare_fn = "greater" + value_int64 = [0] + } + } + } + scheduling { + interval { + interval = "15m" + randomize = "0" + } + } + } + + + resource "observe_monitor_v2_action" "act" { + workspace = data.observe_workspace.default.oid + type = "email" + email { + subject = "somebody once told me" + body = "the world is gonna roll me" + fragments = jsonencode({ + foo = "bar" + }) + } + name = "%[1]s" + description = "an interesting description" + } + `, randomPrefix), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("observe_monitor_v2_action.act", "workspace"), + resource.TestCheckResourceAttr("observe_monitor_v2_action.act", "name", randomPrefix), + resource.TestCheckResourceAttr("observe_monitor_v2_action.act", "type", "email"), + resource.TestCheckResourceAttr("observe_monitor_v2_action.act", "description", "an interesting description"), + resource.TestCheckResourceAttr("observe_monitor_v2_action.act", "email.0.fragments", "{\"foo\":\"bar\"}"), + resource.TestCheckResourceAttr("observe_monitor_v2_action.act", "email.0.subject", "somebody once told me"), + resource.TestCheckResourceAttr("observe_monitor_v2_action.act", "email.0.body", "the world is gonna roll me"), + ), + }, + }, + }) +} + +func TestAccObserveMonitorV2DestinationWebhook(t *testing.T) { + randomPrefix := acctest.RandomWithPrefix("tf") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: fmt.Sprintf(monitorV2ConfigPreamble+` + resource "observe_monitor_v2" "first" { + workspace = data.observe_workspace.default.oid + rule_kind = "count" + name = "%[1]s" + lookback_time = "30m" + comment = "a descriptive comment" + inputs = { + "test" = observe_datastream.test.dataset + } + stage { + pipeline = <<-EOF + colmake kind:"test", description:"test" + EOF + output_stage = true + } + stage { + pipeline = <<-EOF + filter kind ~ "test" + EOF + } + rules { + level = "informational" + count { + compare_values { + compare_fn = "greater" + value_int64 = [0] + } + } + } + scheduling { + interval { + interval = "15m" + randomize = "0" + } + } + } + + resource "observe_monitor_v2_action" "act" { + workspace = data.observe_workspace.default.oid + type = "webhook" + webhook { + headers { + header = "never gonna give you up" + value = "never gonna let you down" + } + body = "never gonna run around and desert you" + fragments = jsonencode({ + foo = "bar" + }) + } + name = "%[1]s" + description = "an interesting description" + } + `, randomPrefix), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("observe_monitor_v2_action.act", "workspace"), + resource.TestCheckResourceAttr("observe_monitor_v2_action.act", "name", randomPrefix), + resource.TestCheckResourceAttr("observe_monitor_v2_action.act", "type", "webhook"), + resource.TestCheckResourceAttr("observe_monitor_v2_action.act", "description", "an interesting description"), + resource.TestCheckResourceAttr("observe_monitor_v2_action.act", "webhook.0.fragments", "{\"foo\":\"bar\"}"), + resource.TestCheckResourceAttr("observe_monitor_v2_action.act", "webhook.0.headers.0.header", "never gonna give you up"), + resource.TestCheckResourceAttr("observe_monitor_v2_action.act", "webhook.0.headers.0.value", "never gonna let you down"), + resource.TestCheckResourceAttr("observe_monitor_v2_action.act", "webhook.0.body", "never gonna run around and desert you"), + ), + }, + }, + }) +}