diff --git a/client/internal/meta/operation/monitorv2_destination.graphql b/client/internal/meta/operation/monitorv2_destination.graphql index e16787c0..bbb6294e 100644 --- a/client/internal/meta/operation/monitorv2_destination.graphql +++ b/client/internal/meta/operation/monitorv2_destination.graphql @@ -67,3 +67,12 @@ mutation deleteMonitorV2Destination($id: ObjectId!) { } } +mutation saveActionWithDestinationLinks( + $actionId: ObjectId!, + $destinationLinks: [ActionDestinationLinkInput!]! +) { + # @genqlient(flatten: true) + monitorV2Action: saveActionWithDestinationLinks(actionId: $actionId, destinationLinks: $destinationLinks) { + ...MonitorV2Action + } +} \ No newline at end of file diff --git a/client/meta/genqlient.generated.go b/client/meta/genqlient.generated.go index ea9969e4..5868baae 100644 --- a/client/meta/genqlient.generated.go +++ b/client/meta/genqlient.generated.go @@ -35,6 +35,23 @@ func (v *ActionDestinationLink) GetSendRemindersInterval() *types.DurationScalar // GetDefinition returns ActionDestinationLink.Definition, and is useful for accessing the field via an interface. func (v *ActionDestinationLink) GetDefinition() MonitorV2DestinationDefinition { return v.Definition } +type ActionDestinationLinkInput struct { + DestinationID string `json:"destinationID"` + SendEndNotifications *bool `json:"sendEndNotifications"` + SendRemindersInterval *types.DurationScalar `json:"sendRemindersInterval"` +} + +// GetDestinationID returns ActionDestinationLinkInput.DestinationID, and is useful for accessing the field via an interface. +func (v *ActionDestinationLinkInput) GetDestinationID() string { return v.DestinationID } + +// GetSendEndNotifications returns ActionDestinationLinkInput.SendEndNotifications, and is useful for accessing the field via an interface. +func (v *ActionDestinationLinkInput) GetSendEndNotifications() *bool { return v.SendEndNotifications } + +// GetSendRemindersInterval returns ActionDestinationLinkInput.SendRemindersInterval, and is useful for accessing the field via an interface. +func (v *ActionDestinationLinkInput) GetSendRemindersInterval() *types.DurationScalar { + return v.SendRemindersInterval +} + type ActionInput struct { Name *string `json:"name"` IconUrl *string `json:"iconUrl"` @@ -9238,6 +9255,20 @@ func (v *__removeCorrelationTagInput) GetPath() LinkFieldInput { return v.Path } // GetTag returns __removeCorrelationTagInput.Tag, and is useful for accessing the field via an interface. func (v *__removeCorrelationTagInput) GetTag() string { return v.Tag } +// __saveActionWithDestinationLinksInput is used internally by genqlient +type __saveActionWithDestinationLinksInput struct { + ActionId string `json:"actionId"` + DestinationLinks []ActionDestinationLinkInput `json:"destinationLinks"` +} + +// GetActionId returns __saveActionWithDestinationLinksInput.ActionId, and is useful for accessing the field via an interface. +func (v *__saveActionWithDestinationLinksInput) GetActionId() string { return v.ActionId } + +// GetDestinationLinks returns __saveActionWithDestinationLinksInput.DestinationLinks, and is useful for accessing the field via an interface. +func (v *__saveActionWithDestinationLinksInput) GetDestinationLinks() []ActionDestinationLinkInput { + return v.DestinationLinks +} + // __saveDashboardInput is used internally by genqlient type __saveDashboardInput struct { DashboardInput DashboardInput `json:"dashboardInput"` @@ -11065,6 +11096,21 @@ type removeCorrelationTagResponse struct { // GetResultStatus returns removeCorrelationTagResponse.ResultStatus, and is useful for accessing the field via an interface. func (v *removeCorrelationTagResponse) GetResultStatus() ResultStatus { return v.ResultStatus } +// saveActionWithDestinationLinksResponse is returned by saveActionWithDestinationLinks on success. +type saveActionWithDestinationLinksResponse struct { + // saveActionsWithDestinations replaces all action's links to the destinations (MonitorV2) for the provided + // shared action. It only allows you to mutate shared actions' relationships with the shared destinations. + // Private actions' links can't be mutated through this call, so you will need to use saveMonitorV2Relations to do so. + // The purpose of the API is such that the users can create a shared action and make links to the destinations + // from the shared actions page or when an action has been shared from within the monitor editing page. + MonitorV2Action MonitorV2Action `json:"monitorV2Action"` +} + +// GetMonitorV2Action returns saveActionWithDestinationLinksResponse.MonitorV2Action, and is useful for accessing the field via an interface. +func (v *saveActionWithDestinationLinksResponse) GetMonitorV2Action() MonitorV2Action { + return v.MonitorV2Action +} + // saveDashboardResponse is returned by saveDashboard on success. type saveDashboardResponse struct { Dashboard Dashboard `json:"dashboard"` @@ -18037,6 +18083,105 @@ func removeCorrelationTag( return &data, err } +// The query or mutation executed by saveActionWithDestinationLinks. +const saveActionWithDestinationLinks_Operation = ` +mutation saveActionWithDestinationLinks ($actionId: ObjectId!, $destinationLinks: [ActionDestinationLinkInput!]!) { + monitorV2Action: saveActionWithDestinationLinks(actionId: $actionId, destinationLinks: $destinationLinks) { + ... MonitorV2Action + } +} +fragment MonitorV2Action on MonitorV2Action { + inline + type + destinationLinks { + ... ActionDestinationLink + } + email { + ... MonitorV2EmailAction + } + webhook { + ... MonitorV2WebhookAction + } + id + workspaceId + name + iconUrl + description + createdBy + createdDate +} +fragment ActionDestinationLink on ActionDestinationLink { + destinationID + sendEndNotifications + sendRemindersInterval + definition { + ... MonitorV2DestinationDefinition + } +} +fragment MonitorV2EmailAction on MonitorV2EmailAction { + subject + body + fragments +} +fragment MonitorV2WebhookAction on MonitorV2WebhookAction { + headers { + ... MonitorV2WebhookHeader + } + body + fragments +} +fragment MonitorV2DestinationDefinition on MonitorV2DestinationDefinition { + inline + type + email { + ... MonitorV2EmailDestination + } + webhook { + ... MonitorV2WebhookDestination + } +} +fragment MonitorV2WebhookHeader on MonitorV2WebhookHeader { + header + value +} +fragment MonitorV2EmailDestination on MonitorV2EmailDestination { + users + addresses +} +fragment MonitorV2WebhookDestination on MonitorV2WebhookDestination { + url + method +} +` + +func saveActionWithDestinationLinks( + ctx context.Context, + client graphql.Client, + actionId string, + destinationLinks []ActionDestinationLinkInput, +) (*saveActionWithDestinationLinksResponse, error) { + req := &graphql.Request{ + OpName: "saveActionWithDestinationLinks", + Query: saveActionWithDestinationLinks_Operation, + Variables: &__saveActionWithDestinationLinksInput{ + ActionId: actionId, + DestinationLinks: destinationLinks, + }, + } + var err error + + var data saveActionWithDestinationLinksResponse + resp := &graphql.Response{Data: &data} + + err = client.MakeRequest( + ctx, + req, + resp, + ) + + return &data, err +} + // The query or mutation executed by saveDashboard. const saveDashboard_Operation = ` mutation saveDashboard ($dashboardInput: DashboardInput!) { diff --git a/client/meta/monitorv2_action.go b/client/meta/monitorv2_action.go index 39763834..dda928bc 100644 --- a/client/meta/monitorv2_action.go +++ b/client/meta/monitorv2_action.go @@ -38,6 +38,12 @@ func (client *Client) DeleteMonitorV2Action(ctx context.Context, id string) erro return resultStatusError(resp, err) } +// used only when creating or updating a destination +func (client *Client) SaveActionWithDestinationLinks(ctx context.Context, actionId string, destinationLinks []ActionDestinationLinkInput) (*MonitorV2Action, error) { + resp, err := saveActionWithDestinationLinks(ctx, client.Gql, actionId, destinationLinks) + return monitorV2ActionOrError(resp, err) +} + func (m *MonitorV2Action) Oid() *oid.OID { return &oid.OID{ Id: m.Id, diff --git a/client/meta/monitorv2_destination.go b/client/meta/monitorv2_destination.go index 3625f3f8..8adcdc67 100644 --- a/client/meta/monitorv2_destination.go +++ b/client/meta/monitorv2_destination.go @@ -41,6 +41,6 @@ func (client *Client) DeleteMonitorV2Destination(ctx context.Context, id string) func (m *MonitorV2Destination) Oid() *oid.OID { return &oid.OID{ Id: m.Id, - Type: oid.TypeMonitorV2, + Type: oid.TypeMonitorV2Destination, } } diff --git a/client/oid/oid.go b/client/oid/oid.go index 30ff1cad..7c96efd2 100644 --- a/client/oid/oid.go +++ b/client/oid/oid.go @@ -38,6 +38,7 @@ const ( TypeMonitor Type = "monitor" TypeMonitorV2 Type = "monitorv2" TypeMonitorV2Action Type = "monitorv2action" + TypeMonitorV2Destination Type = "monitorv2destination" TypeMonitorAction Type = "monitoraction" TypeMonitorActionAttachment Type = "monitoractionattachment" TypePoller Type = "poller" diff --git a/observe/resource_monitor_v2_destination.go b/observe/resource_monitor_v2_destination.go index 5ee39a15..ead707a1 100644 --- a/observe/resource_monitor_v2_destination.go +++ b/observe/resource_monitor_v2_destination.go @@ -19,15 +19,16 @@ func resourceMonitorV2Destination() *schema.Resource { UpdateContext: resourceMonitorV2DestinationUpdate, DeleteContext: resourceMonitorV2DestinationDelete, Schema: map[string]*schema.Schema{ - "workspace_id": { // ? + "workspace": { // ? Type: schema.TypeString, ForceNew: true, Required: true, ValidateDiagFunc: validateOID(oid.TypeWorkspace), }, - "inline": { // Boolean - Type: schema.TypeBool, - Optional: true, + "action": { // associated action + Type: schema.TypeString, + Required: true, + ValidateDiagFunc: validateOID(oid.TypeMonitorV2Action), }, "type": { // MonitorV2ActionType! Type: schema.TypeString, @@ -59,7 +60,7 @@ func resourceMonitorV2Destination() *schema.Resource { Optional: true, }, // ^^^ end of input - "id": { // ObjectId! + "oid": { // ObjectId! Type: schema.TypeString, Computed: true, }, @@ -111,12 +112,24 @@ func resourceMonitorV2DestinationCreate(ctx context.Context, data *schema.Resour return diags } - id, _ := oid.NewOID(data.Get("workspace_id").(string)) + id, _ := oid.NewOID(data.Get("workspace").(string)) result, err := client.CreateMonitorV2Destination(ctx, id.Id, input) if err != nil { return diag.FromErr(err) } + // update the link between action and destination + actOID, _ := oid.NewOID(data.Get("action").(string)) + dstLinks := []gql.ActionDestinationLinkInput{ + { + DestinationID: id.Id, + }, + } + _, err = client.Meta.SaveActionWithDestinationLinks(ctx, actOID.Id, dstLinks) + if err != nil { + return diag.FromErr(err) + } + data.SetId(result.Id) return append(diags, resourceMonitorV2DestinationRead(ctx, data, meta)...) } @@ -141,6 +154,18 @@ func resourceMonitorV2DestinationUpdate(ctx context.Context, data *schema.Resour return diag.FromErr(err) } + // update the link between action and destination + actOID, _ := oid.NewOID(data.Get("action").(string)) + dstLinks := []gql.ActionDestinationLinkInput{ + { + DestinationID: data.Id(), + }, + } + _, err = client.Meta.SaveActionWithDestinationLinks(ctx, actOID.Id, dstLinks) + if err != nil { + return diag.FromErr(err) + } + return append(diags, resourceMonitorV2DestinationRead(ctx, data, meta)...) } @@ -156,7 +181,7 @@ func resourceMonitorV2DestinationRead(ctx context.Context, data *schema.Resource } // required - if err := data.Set("workspace_id", oid.WorkspaceOid(dest.WorkspaceId).String()); err != nil { + if err := data.Set("workspace", oid.WorkspaceOid(dest.WorkspaceId).String()); err != nil { diags = append(diags, diag.FromErr(err)...) } @@ -191,14 +216,8 @@ func resourceMonitorV2DestinationRead(ctx context.Context, data *schema.Resource } } - if dest.Inline != nil { - if err := data.Set("inline", *dest.Inline); err != nil { - diags = append(diags, diag.FromErr(err)...) - } - } - if dest.Webhook != nil { - if err := data.Set("inline", monitorv2FlattenWebhookDestination(*dest.Webhook)); err != nil { + if err := data.Set("webhook", monitorv2FlattenWebhookDestination(*dest.Webhook)); err != nil { diags = append(diags, diag.FromErr(err)...) } } @@ -247,9 +266,11 @@ func newMonitorV2DestinationInput(data *schema.ResourceData) (input *gql.Monitor name := data.Get("name").(string) // instantiation + inlineVal := true // we are currently only allowing destinations to be inlined input = &gql.MonitorV2DestinationInput{ - Type: actionType, - Name: name, + Type: actionType, + Name: name, + Inline: &inlineVal, } // optionals