From 0d6926de756e65077bd0810d8a62e519e5cf169d Mon Sep 17 00:00:00 2001 From: "api-clients-generation-pipeline[bot]" <54105614+api-clients-generation-pipeline[bot]@users.noreply.github.com> Date: Thu, 20 Nov 2025 20:37:51 +0000 Subject: [PATCH 1/2] Add filter.scope to Monitor Notification Rules (#3462) Co-authored-by: ci.datadog-api-spec --- .generator/schemas/v2/openapi.yaml | 42 ++++++--- ...el_monitor_notification_rule_attributes.go | 4 +- ...del_monitor_notification_rule_condition.go | 2 +- ...otification_rule_conditional_recipients.go | 4 +- .../model_monitor_notification_rule_filter.go | 34 +++++++- ..._monitor_notification_rule_filter_scope.go | 86 +++++++++++++++++++ ...l_monitor_notification_rule_filter_tags.go | 4 +- ...r_notification_rule_response_attributes.go | 4 +- ...reateMonitorNotificationRule_1379932371.go | 45 ++++++++++ ...pdateMonitorNotificationRule_1446058210.go | 48 +++++++++++ ...rule_with_scope_returns_OK_response.freeze | 1 + ...n_rule_with_scope_returns_OK_response.yaml | 43 ++++++++++ ...rule_with_scope_returns_OK_response.freeze | 1 + ...n_rule_with_scope_returns_OK_response.yaml | 67 +++++++++++++++ tests/scenarios/features/v2/monitors.feature | 18 ++++ 15 files changed, 382 insertions(+), 21 deletions(-) create mode 100644 api/datadogV2/model_monitor_notification_rule_filter_scope.go create mode 100644 examples/v2/monitors/CreateMonitorNotificationRule_1379932371.go create mode 100644 examples/v2/monitors/UpdateMonitorNotificationRule_1446058210.go create mode 100644 tests/scenarios/cassettes/TestScenarios/v2/Feature_Monitors/Scenario_Create_a_monitor_notification_rule_with_scope_returns_OK_response.freeze create mode 100644 tests/scenarios/cassettes/TestScenarios/v2/Feature_Monitors/Scenario_Create_a_monitor_notification_rule_with_scope_returns_OK_response.yaml create mode 100644 tests/scenarios/cassettes/TestScenarios/v2/Feature_Monitors/Scenario_Update_a_monitor_notification_rule_with_scope_returns_OK_response.freeze create mode 100644 tests/scenarios/cassettes/TestScenarios/v2/Feature_Monitors/Scenario_Update_a_monitor_notification_rule_with_scope_returns_OK_response.yaml diff --git a/.generator/schemas/v2/openapi.yaml b/.generator/schemas/v2/openapi.yaml index d2781f328c8..6e4cbaacff9 100644 --- a/.generator/schemas/v2/openapi.yaml +++ b/.generator/schemas/v2/openapi.yaml @@ -32691,15 +32691,23 @@ components: properties: recipients: $ref: '#/components/schemas/MonitorNotificationRuleRecipients' + description: A list of recipients to notify. Uses the same format as the + monitor `message` field. Must not start with an '@'. scope: - $ref: '#/components/schemas/MonitorNotificationRuleScope' + $ref: '#/components/schemas/MonitorNotificationRuleConditionScope' required: - scope - recipients type: object + MonitorNotificationRuleConditionScope: + description: The scope to which the monitor applied. + example: transition_type:alert + maxLength: 3000 + minLength: 1 + type: string MonitorNotificationRuleConditionalRecipients: description: Use conditional recipients to define different recipients for different - situations. + situations. Cannot be used with `recipients`. properties: conditions: description: Conditions of the notification rule. @@ -32749,12 +32757,30 @@ components: description: Filter used to associate the notification rule with monitors. oneOf: - $ref: '#/components/schemas/MonitorNotificationRuleFilterTags' + - $ref: '#/components/schemas/MonitorNotificationRuleFilterScope' + MonitorNotificationRuleFilterScope: + additionalProperties: false + description: Filter monitor notifications. A monitor notification must match + the scope. + properties: + scope: + description: A scope composed of one or several key:value pairs, which can + be used to filter monitor notifications on monitor and group tags. + example: service:(foo OR bar) AND team:test NOT environment:staging + maxLength: 3000 + minLength: 1 + type: string + required: + - scope + type: object MonitorNotificationRuleFilterTags: additionalProperties: false - description: Filter monitors by tags. Monitors must match all tags. + description: Filter monitor notifications by tags. A monitor notification must + match all tags. properties: tags: - description: A list of monitor tags. + description: A list of tags (key:value pairs), which can be used to filter + monitor notifications on monitor and group tags. example: - team:product - host:abc @@ -32794,7 +32820,7 @@ components: type: string MonitorNotificationRuleRecipients: description: A list of recipients to notify. Uses the same format as the monitor - `message` field. Must not start with an '@'. + `message` field. Must not start with an '@'. Cannot be used with `conditional_recipients`. example: - slack-test-channel - jira-test @@ -32877,12 +32903,6 @@ components: description: An object related to a monitor notification rule. oneOf: - $ref: '#/components/schemas/User' - MonitorNotificationRuleScope: - description: The scope to which the monitor applied. - example: transition_type:alert - maxLength: 3000 - minLength: 1 - type: string MonitorNotificationRuleUpdateRequest: description: Request for updating a monitor notification rule. properties: diff --git a/api/datadogV2/model_monitor_notification_rule_attributes.go b/api/datadogV2/model_monitor_notification_rule_attributes.go index 4e11a49b75e..f6c5e9e9bec 100644 --- a/api/datadogV2/model_monitor_notification_rule_attributes.go +++ b/api/datadogV2/model_monitor_notification_rule_attributes.go @@ -12,13 +12,13 @@ import ( // MonitorNotificationRuleAttributes Attributes of the monitor notification rule. type MonitorNotificationRuleAttributes struct { - // Use conditional recipients to define different recipients for different situations. + // Use conditional recipients to define different recipients for different situations. Cannot be used with `recipients`. ConditionalRecipients *MonitorNotificationRuleConditionalRecipients `json:"conditional_recipients,omitempty"` // Filter used to associate the notification rule with monitors. Filter *MonitorNotificationRuleFilter `json:"filter,omitempty"` // The name of the monitor notification rule. Name string `json:"name"` - // A list of recipients to notify. Uses the same format as the monitor `message` field. Must not start with an '@'. + // A list of recipients to notify. Uses the same format as the monitor `message` field. Must not start with an '@'. Cannot be used with `conditional_recipients`. Recipients []string `json:"recipients,omitempty"` // UnparsedObject contains the raw value of the object if there was an error when deserializing into the struct UnparsedObject map[string]interface{} `json:"-"` diff --git a/api/datadogV2/model_monitor_notification_rule_condition.go b/api/datadogV2/model_monitor_notification_rule_condition.go index d3f0b419836..78d3266db57 100644 --- a/api/datadogV2/model_monitor_notification_rule_condition.go +++ b/api/datadogV2/model_monitor_notification_rule_condition.go @@ -12,7 +12,7 @@ import ( // MonitorNotificationRuleCondition Conditions for `conditional_recipients`. type MonitorNotificationRuleCondition struct { - // A list of recipients to notify. Uses the same format as the monitor `message` field. Must not start with an '@'. + // A list of recipients to notify. Uses the same format as the monitor `message` field. Must not start with an '@'. Cannot be used with `conditional_recipients`. Recipients []string `json:"recipients"` // The scope to which the monitor applied. Scope string `json:"scope"` diff --git a/api/datadogV2/model_monitor_notification_rule_conditional_recipients.go b/api/datadogV2/model_monitor_notification_rule_conditional_recipients.go index b5aba782128..de58b0fcb3a 100644 --- a/api/datadogV2/model_monitor_notification_rule_conditional_recipients.go +++ b/api/datadogV2/model_monitor_notification_rule_conditional_recipients.go @@ -10,11 +10,11 @@ import ( "github.com/DataDog/datadog-api-client-go/v2/api/datadog" ) -// MonitorNotificationRuleConditionalRecipients Use conditional recipients to define different recipients for different situations. +// MonitorNotificationRuleConditionalRecipients Use conditional recipients to define different recipients for different situations. Cannot be used with `recipients`. type MonitorNotificationRuleConditionalRecipients struct { // Conditions of the notification rule. Conditions []MonitorNotificationRuleCondition `json:"conditions"` - // A list of recipients to notify. Uses the same format as the monitor `message` field. Must not start with an '@'. + // A list of recipients to notify. Uses the same format as the monitor `message` field. Must not start with an '@'. Cannot be used with `conditional_recipients`. FallbackRecipients []string `json:"fallback_recipients,omitempty"` // UnparsedObject contains the raw value of the object if there was an error when deserializing into the struct UnparsedObject map[string]interface{} `json:"-"` diff --git a/api/datadogV2/model_monitor_notification_rule_filter.go b/api/datadogV2/model_monitor_notification_rule_filter.go index ba01980a28f..8c4cf0d3536 100644 --- a/api/datadogV2/model_monitor_notification_rule_filter.go +++ b/api/datadogV2/model_monitor_notification_rule_filter.go @@ -10,7 +10,8 @@ import ( // MonitorNotificationRuleFilter - Filter used to associate the notification rule with monitors. type MonitorNotificationRuleFilter struct { - MonitorNotificationRuleFilterTags *MonitorNotificationRuleFilterTags + MonitorNotificationRuleFilterTags *MonitorNotificationRuleFilterTags + MonitorNotificationRuleFilterScope *MonitorNotificationRuleFilterScope // UnparsedObject contains the raw value of the object if there was an error when deserializing into the struct UnparsedObject interface{} @@ -21,6 +22,11 @@ func MonitorNotificationRuleFilterTagsAsMonitorNotificationRuleFilter(v *Monitor return MonitorNotificationRuleFilter{MonitorNotificationRuleFilterTags: v} } +// MonitorNotificationRuleFilterScopeAsMonitorNotificationRuleFilter is a convenience function that returns MonitorNotificationRuleFilterScope wrapped in MonitorNotificationRuleFilter. +func MonitorNotificationRuleFilterScopeAsMonitorNotificationRuleFilter(v *MonitorNotificationRuleFilterScope) MonitorNotificationRuleFilter { + return MonitorNotificationRuleFilter{MonitorNotificationRuleFilterScope: v} +} + // UnmarshalJSON turns data into one of the pointers in the struct. func (obj *MonitorNotificationRuleFilter) UnmarshalJSON(data []byte) error { var err error @@ -42,9 +48,27 @@ func (obj *MonitorNotificationRuleFilter) UnmarshalJSON(data []byte) error { obj.MonitorNotificationRuleFilterTags = nil } + // try to unmarshal data into MonitorNotificationRuleFilterScope + err = datadog.Unmarshal(data, &obj.MonitorNotificationRuleFilterScope) + if err == nil { + if obj.MonitorNotificationRuleFilterScope != nil && obj.MonitorNotificationRuleFilterScope.UnparsedObject == nil { + jsonMonitorNotificationRuleFilterScope, _ := datadog.Marshal(obj.MonitorNotificationRuleFilterScope) + if string(jsonMonitorNotificationRuleFilterScope) == "{}" { // empty struct + obj.MonitorNotificationRuleFilterScope = nil + } else { + match++ + } + } else { + obj.MonitorNotificationRuleFilterScope = nil + } + } else { + obj.MonitorNotificationRuleFilterScope = nil + } + if match != 1 { // more than 1 match // reset to nil obj.MonitorNotificationRuleFilterTags = nil + obj.MonitorNotificationRuleFilterScope = nil return datadog.Unmarshal(data, &obj.UnparsedObject) } return nil // exactly one match @@ -56,6 +80,10 @@ func (obj MonitorNotificationRuleFilter) MarshalJSON() ([]byte, error) { return datadog.Marshal(&obj.MonitorNotificationRuleFilterTags) } + if obj.MonitorNotificationRuleFilterScope != nil { + return datadog.Marshal(&obj.MonitorNotificationRuleFilterScope) + } + if obj.UnparsedObject != nil { return datadog.Marshal(obj.UnparsedObject) } @@ -68,6 +96,10 @@ func (obj *MonitorNotificationRuleFilter) GetActualInstance() interface{} { return obj.MonitorNotificationRuleFilterTags } + if obj.MonitorNotificationRuleFilterScope != nil { + return obj.MonitorNotificationRuleFilterScope + } + // all schemas are nil return nil } diff --git a/api/datadogV2/model_monitor_notification_rule_filter_scope.go b/api/datadogV2/model_monitor_notification_rule_filter_scope.go new file mode 100644 index 00000000000..0a620bc4eb3 --- /dev/null +++ b/api/datadogV2/model_monitor_notification_rule_filter_scope.go @@ -0,0 +1,86 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2019-Present Datadog, Inc. + +package datadogV2 + +import ( + "fmt" + + "github.com/DataDog/datadog-api-client-go/v2/api/datadog" +) + +// MonitorNotificationRuleFilterScope Filter monitor notifications. A monitor notification must match the scope. +type MonitorNotificationRuleFilterScope struct { + // A scope composed of one or several key:value pairs, which can be used to filter monitor notifications on monitor and group tags. + Scope string `json:"scope"` + // UnparsedObject contains the raw value of the object if there was an error when deserializing into the struct + UnparsedObject map[string]interface{} `json:"-"` +} + +// NewMonitorNotificationRuleFilterScope instantiates a new MonitorNotificationRuleFilterScope object. +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed. +func NewMonitorNotificationRuleFilterScope(scope string) *MonitorNotificationRuleFilterScope { + this := MonitorNotificationRuleFilterScope{} + this.Scope = scope + return &this +} + +// NewMonitorNotificationRuleFilterScopeWithDefaults instantiates a new MonitorNotificationRuleFilterScope object. +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set. +func NewMonitorNotificationRuleFilterScopeWithDefaults() *MonitorNotificationRuleFilterScope { + this := MonitorNotificationRuleFilterScope{} + return &this +} + +// GetScope returns the Scope field value. +func (o *MonitorNotificationRuleFilterScope) GetScope() string { + if o == nil { + var ret string + return ret + } + return o.Scope +} + +// GetScopeOk returns a tuple with the Scope field value +// and a boolean to check if the value has been set. +func (o *MonitorNotificationRuleFilterScope) GetScopeOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Scope, true +} + +// SetScope sets field value. +func (o *MonitorNotificationRuleFilterScope) SetScope(v string) { + o.Scope = v +} + +// MarshalJSON serializes the struct using spec logic. +func (o MonitorNotificationRuleFilterScope) MarshalJSON() ([]byte, error) { + toSerialize := map[string]interface{}{} + if o.UnparsedObject != nil { + return datadog.Marshal(o.UnparsedObject) + } + toSerialize["scope"] = o.Scope + return datadog.Marshal(toSerialize) +} + +// UnmarshalJSON deserializes the given payload. +func (o *MonitorNotificationRuleFilterScope) UnmarshalJSON(bytes []byte) (err error) { + all := struct { + Scope *string `json:"scope"` + }{} + if err = datadog.Unmarshal(bytes, &all); err != nil { + return datadog.Unmarshal(bytes, &o.UnparsedObject) + } + if all.Scope == nil { + return fmt.Errorf("required field scope missing") + } + o.Scope = *all.Scope + + return nil +} diff --git a/api/datadogV2/model_monitor_notification_rule_filter_tags.go b/api/datadogV2/model_monitor_notification_rule_filter_tags.go index b8c1d3eccff..2c5b13ffeb4 100644 --- a/api/datadogV2/model_monitor_notification_rule_filter_tags.go +++ b/api/datadogV2/model_monitor_notification_rule_filter_tags.go @@ -10,9 +10,9 @@ import ( "github.com/DataDog/datadog-api-client-go/v2/api/datadog" ) -// MonitorNotificationRuleFilterTags Filter monitors by tags. Monitors must match all tags. +// MonitorNotificationRuleFilterTags Filter monitor notifications by tags. A monitor notification must match all tags. type MonitorNotificationRuleFilterTags struct { - // A list of monitor tags. + // A list of tags (key:value pairs), which can be used to filter monitor notifications on monitor and group tags. Tags []string `json:"tags"` // UnparsedObject contains the raw value of the object if there was an error when deserializing into the struct UnparsedObject map[string]interface{} `json:"-"` diff --git a/api/datadogV2/model_monitor_notification_rule_response_attributes.go b/api/datadogV2/model_monitor_notification_rule_response_attributes.go index dba784d6ab2..cb1beab11ce 100644 --- a/api/datadogV2/model_monitor_notification_rule_response_attributes.go +++ b/api/datadogV2/model_monitor_notification_rule_response_attributes.go @@ -12,7 +12,7 @@ import ( // MonitorNotificationRuleResponseAttributes Attributes of the monitor notification rule. type MonitorNotificationRuleResponseAttributes struct { - // Use conditional recipients to define different recipients for different situations. + // Use conditional recipients to define different recipients for different situations. Cannot be used with `recipients`. ConditionalRecipients *MonitorNotificationRuleConditionalRecipients `json:"conditional_recipients,omitempty"` // Creation time of the monitor notification rule. Created *time.Time `json:"created,omitempty"` @@ -22,7 +22,7 @@ type MonitorNotificationRuleResponseAttributes struct { Modified *time.Time `json:"modified,omitempty"` // The name of the monitor notification rule. Name *string `json:"name,omitempty"` - // A list of recipients to notify. Uses the same format as the monitor `message` field. Must not start with an '@'. + // A list of recipients to notify. Uses the same format as the monitor `message` field. Must not start with an '@'. Cannot be used with `conditional_recipients`. Recipients []string `json:"recipients,omitempty"` // UnparsedObject contains the raw value of the object if there was an error when deserializing into the struct UnparsedObject map[string]interface{} `json:"-"` diff --git a/examples/v2/monitors/CreateMonitorNotificationRule_1379932371.go b/examples/v2/monitors/CreateMonitorNotificationRule_1379932371.go new file mode 100644 index 00000000000..c19bab3ebde --- /dev/null +++ b/examples/v2/monitors/CreateMonitorNotificationRule_1379932371.go @@ -0,0 +1,45 @@ +// Create a monitor notification rule with scope returns "OK" response + +package main + +import ( + "context" + "encoding/json" + "fmt" + "os" + + "github.com/DataDog/datadog-api-client-go/v2/api/datadog" + "github.com/DataDog/datadog-api-client-go/v2/api/datadogV2" +) + +func main() { + body := datadogV2.MonitorNotificationRuleCreateRequest{ + Data: datadogV2.MonitorNotificationRuleCreateRequestData{ + Attributes: datadogV2.MonitorNotificationRuleAttributes{ + Filter: &datadogV2.MonitorNotificationRuleFilter{ + MonitorNotificationRuleFilterScope: &datadogV2.MonitorNotificationRuleFilterScope{ + Scope: "test:example-monitor", + }}, + Name: "test rule", + Recipients: []string{ + "slack-test-channel", + "jira-test", + }, + }, + Type: datadogV2.MONITORNOTIFICATIONRULERESOURCETYPE_MONITOR_NOTIFICATION_RULE.Ptr(), + }, + } + ctx := datadog.NewDefaultContext(context.Background()) + configuration := datadog.NewConfiguration() + apiClient := datadog.NewAPIClient(configuration) + api := datadogV2.NewMonitorsApi(apiClient) + resp, r, err := api.CreateMonitorNotificationRule(ctx, body) + + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `MonitorsApi.CreateMonitorNotificationRule`: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + + responseContent, _ := json.MarshalIndent(resp, "", " ") + fmt.Fprintf(os.Stdout, "Response from `MonitorsApi.CreateMonitorNotificationRule`:\n%s\n", responseContent) +} diff --git a/examples/v2/monitors/UpdateMonitorNotificationRule_1446058210.go b/examples/v2/monitors/UpdateMonitorNotificationRule_1446058210.go new file mode 100644 index 00000000000..53c1947b71f --- /dev/null +++ b/examples/v2/monitors/UpdateMonitorNotificationRule_1446058210.go @@ -0,0 +1,48 @@ +// Update a monitor notification rule with scope returns "OK" response + +package main + +import ( + "context" + "encoding/json" + "fmt" + "os" + + "github.com/DataDog/datadog-api-client-go/v2/api/datadog" + "github.com/DataDog/datadog-api-client-go/v2/api/datadogV2" +) + +func main() { + // there is a valid "monitor_notification_rule" in the system + MonitorNotificationRuleDataID := os.Getenv("MONITOR_NOTIFICATION_RULE_DATA_ID") + + body := datadogV2.MonitorNotificationRuleUpdateRequest{ + Data: datadogV2.MonitorNotificationRuleUpdateRequestData{ + Attributes: datadogV2.MonitorNotificationRuleAttributes{ + Filter: &datadogV2.MonitorNotificationRuleFilter{ + MonitorNotificationRuleFilterScope: &datadogV2.MonitorNotificationRuleFilterScope{ + Scope: "test:example-monitor", + }}, + Name: "updated rule", + Recipients: []string{ + "slack-test-channel", + }, + }, + Id: MonitorNotificationRuleDataID, + Type: datadogV2.MONITORNOTIFICATIONRULERESOURCETYPE_MONITOR_NOTIFICATION_RULE.Ptr(), + }, + } + ctx := datadog.NewDefaultContext(context.Background()) + configuration := datadog.NewConfiguration() + apiClient := datadog.NewAPIClient(configuration) + api := datadogV2.NewMonitorsApi(apiClient) + resp, r, err := api.UpdateMonitorNotificationRule(ctx, MonitorNotificationRuleDataID, body) + + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `MonitorsApi.UpdateMonitorNotificationRule`: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + + responseContent, _ := json.MarshalIndent(resp, "", " ") + fmt.Fprintf(os.Stdout, "Response from `MonitorsApi.UpdateMonitorNotificationRule`:\n%s\n", responseContent) +} diff --git a/tests/scenarios/cassettes/TestScenarios/v2/Feature_Monitors/Scenario_Create_a_monitor_notification_rule_with_scope_returns_OK_response.freeze b/tests/scenarios/cassettes/TestScenarios/v2/Feature_Monitors/Scenario_Create_a_monitor_notification_rule_with_scope_returns_OK_response.freeze new file mode 100644 index 00000000000..94917c9e8b9 --- /dev/null +++ b/tests/scenarios/cassettes/TestScenarios/v2/Feature_Monitors/Scenario_Create_a_monitor_notification_rule_with_scope_returns_OK_response.freeze @@ -0,0 +1 @@ +2025-11-11T21:28:39.129Z \ No newline at end of file diff --git a/tests/scenarios/cassettes/TestScenarios/v2/Feature_Monitors/Scenario_Create_a_monitor_notification_rule_with_scope_returns_OK_response.yaml b/tests/scenarios/cassettes/TestScenarios/v2/Feature_Monitors/Scenario_Create_a_monitor_notification_rule_with_scope_returns_OK_response.yaml new file mode 100644 index 00000000000..e7f80b9c454 --- /dev/null +++ b/tests/scenarios/cassettes/TestScenarios/v2/Feature_Monitors/Scenario_Create_a_monitor_notification_rule_with_scope_returns_OK_response.yaml @@ -0,0 +1,43 @@ +interactions: +- request: + body: | + {"data":{"attributes":{"filter":{"scope":"test:test-create_a_monitor_notification_rule_with_scope_returns_ok_response-1762896519"},"name":"test rule","recipients":["slack-test-channel","jira-test"]},"type":"monitor-notification-rule"}} + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + id: 0 + method: POST + url: https://api.datadoghq.com/api/v2/monitor/notification_rule + response: + body: '{"data":{"type":"monitor-notification-rule","attributes":{"modified_at":"1970-01-01T00:00:00+00:00","filter":{"scope":"test:test-create_a_monitor_notification_rule_with_scope_returns_ok_response-1762896519"},"name":"test + rule","recipients":["slack-test-channel","jira-test"],"created_at":"2025-11-11T21:28:40.032148+00:00"},"relationships":{"created_by":{"data":{"type":"users","id":"9919ec9b-ebc7-49ee-8dc8-03626e717cca"}}},"id":"bbea2907-c191-48d0-9e0f-1ec5881ee37c"},"included":[{"type":"users","id":"9919ec9b-ebc7-49ee-8dc8-03626e717cca","attributes":{"name":"CI + Account","handle":"9919ec9b-ebc7-49ee-8dc8-03626e717cca","created_at":"2020-12-29T22:58:44.733921+00:00","modified_at":"2021-04-27T13:54:01.547888+00:00","email":"team-intg-tools-libs-spam@datadoghq.com","icon":"https://secure.gravatar.com/avatar/b7c189b5b4c2c429d7c1e0bc3749330e?s=48&d=retro","title":null,"verified":true,"service_account":true,"disabled":false,"allowed_login_methods":[],"status":"Active","last_login_time":null}}]} + + ' + code: 200 + duration: 0ms + headers: + Content-Type: + - application/json + status: 200 OK +- request: + body: '' + form: {} + headers: + Accept: + - '*/*' + id: 1 + method: DELETE + url: https://api.datadoghq.com/api/v2/monitor/notification_rule/bbea2907-c191-48d0-9e0f-1ec5881ee37c + response: + body: '' + code: 204 + duration: 0ms + headers: + Content-Type: + - text/html; charset=utf-8 + status: 204 No Content +version: 2 diff --git a/tests/scenarios/cassettes/TestScenarios/v2/Feature_Monitors/Scenario_Update_a_monitor_notification_rule_with_scope_returns_OK_response.freeze b/tests/scenarios/cassettes/TestScenarios/v2/Feature_Monitors/Scenario_Update_a_monitor_notification_rule_with_scope_returns_OK_response.freeze new file mode 100644 index 00000000000..ab91f3c3d08 --- /dev/null +++ b/tests/scenarios/cassettes/TestScenarios/v2/Feature_Monitors/Scenario_Update_a_monitor_notification_rule_with_scope_returns_OK_response.freeze @@ -0,0 +1 @@ +2025-11-11T21:28:40.357Z \ No newline at end of file diff --git a/tests/scenarios/cassettes/TestScenarios/v2/Feature_Monitors/Scenario_Update_a_monitor_notification_rule_with_scope_returns_OK_response.yaml b/tests/scenarios/cassettes/TestScenarios/v2/Feature_Monitors/Scenario_Update_a_monitor_notification_rule_with_scope_returns_OK_response.yaml new file mode 100644 index 00000000000..b6538c01899 --- /dev/null +++ b/tests/scenarios/cassettes/TestScenarios/v2/Feature_Monitors/Scenario_Update_a_monitor_notification_rule_with_scope_returns_OK_response.yaml @@ -0,0 +1,67 @@ +interactions: +- request: + body: | + {"data":{"attributes":{"filter":{"tags":["app:test-update_a_monitor_notification_rule_with_scope_returns_ok_response-1762896520"]},"name":"test rule","recipients":["slack-monitor-app"]},"type":"monitor-notification-rule"}} + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + id: 0 + method: POST + url: https://api.datadoghq.com/api/v2/monitor/notification_rule + response: + body: '{"data":{"type":"monitor-notification-rule","attributes":{"recipients":["slack-monitor-app"],"modified_at":"1970-01-01T00:00:00+00:00","created_at":"2025-11-11T21:28:40.540848+00:00","name":"test + rule","filter":{"tags":["app:test-update_a_monitor_notification_rule_with_scope_returns_ok_response-1762896520"]}},"relationships":{"created_by":{"data":{"type":"users","id":"9919ec9b-ebc7-49ee-8dc8-03626e717cca"}}},"id":"827442a0-5d3e-408c-a930-7ac44775fff1"},"included":[{"type":"users","id":"9919ec9b-ebc7-49ee-8dc8-03626e717cca","attributes":{"name":"CI + Account","handle":"9919ec9b-ebc7-49ee-8dc8-03626e717cca","created_at":"2020-12-29T22:58:44.733921+00:00","modified_at":"2021-04-27T13:54:01.547888+00:00","email":"team-intg-tools-libs-spam@datadoghq.com","icon":"https://secure.gravatar.com/avatar/b7c189b5b4c2c429d7c1e0bc3749330e?s=48&d=retro","title":null,"verified":true,"service_account":true,"disabled":false,"allowed_login_methods":[],"status":"Active","last_login_time":null}}]} + + ' + code: 200 + duration: 0ms + headers: + Content-Type: + - application/json + status: 200 OK +- request: + body: | + {"data":{"attributes":{"filter":{"scope":"test:test-update_a_monitor_notification_rule_with_scope_returns_ok_response-1762896520"},"name":"updated rule","recipients":["slack-test-channel"]},"id":"827442a0-5d3e-408c-a930-7ac44775fff1","type":"monitor-notification-rule"}} + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + id: 1 + method: PATCH + url: https://api.datadoghq.com/api/v2/monitor/notification_rule/827442a0-5d3e-408c-a930-7ac44775fff1 + response: + body: '{"data":{"type":"monitor-notification-rule","attributes":{"filter":{"scope":"test:test-update_a_monitor_notification_rule_with_scope_returns_ok_response-1762896520"},"recipients":["slack-test-channel"],"created_at":"2025-11-11T21:28:40.540848+00:00","name":"updated + rule","modified_at":"2025-11-11T21:28:40.815544+00:00"},"id":"827442a0-5d3e-408c-a930-7ac44775fff1","relationships":{"created_by":{"data":{"type":"users","id":"9919ec9b-ebc7-49ee-8dc8-03626e717cca"}}}},"included":[{"type":"users","id":"9919ec9b-ebc7-49ee-8dc8-03626e717cca","attributes":{"name":"CI + Account","handle":"9919ec9b-ebc7-49ee-8dc8-03626e717cca","created_at":"2020-12-29T22:58:44.733921+00:00","modified_at":"2021-04-27T13:54:01.547888+00:00","email":"team-intg-tools-libs-spam@datadoghq.com","icon":"https://secure.gravatar.com/avatar/b7c189b5b4c2c429d7c1e0bc3749330e?s=48&d=retro","title":null,"verified":true,"service_account":true,"disabled":false,"allowed_login_methods":[],"status":"Active","last_login_time":null}}]} + + ' + code: 200 + duration: 0ms + headers: + Content-Type: + - application/json + status: 200 OK +- request: + body: '' + form: {} + headers: + Accept: + - '*/*' + id: 2 + method: DELETE + url: https://api.datadoghq.com/api/v2/monitor/notification_rule/827442a0-5d3e-408c-a930-7ac44775fff1 + response: + body: '' + code: 204 + duration: 0ms + headers: + Content-Type: + - text/html; charset=utf-8 + status: 204 No Content +version: 2 diff --git a/tests/scenarios/features/v2/monitors.feature b/tests/scenarios/features/v2/monitors.feature index 346a646f83b..e84062637c1 100644 --- a/tests/scenarios/features/v2/monitors.feature +++ b/tests/scenarios/features/v2/monitors.feature @@ -52,6 +52,14 @@ Feature: Monitors Then the response status is 200 OK And the response "data.attributes.name" is equal to "test rule" + @team:DataDog/monitor-app + Scenario: Create a monitor notification rule with scope returns "OK" response + Given new "CreateMonitorNotificationRule" request + And body with value {"data": {"attributes": {"filter": {"scope": "test:{{ unique_lower }}"}, "name": "test rule", "recipients": ["slack-test-channel", "jira-test"]}, "type": "monitor-notification-rule"}} + When the request is sent + Then the response status is 200 OK + And the response "data.attributes.name" is equal to "test rule" + @skip-validation @team:DataDog/monitor-app Scenario: Create a monitor user template returns "Bad Request" response Given new "CreateMonitorUserTemplate" request @@ -272,6 +280,16 @@ Feature: Monitors Then the response status is 200 OK And the response "data.attributes.name" is equal to "updated rule" + @team:DataDog/monitor-app + Scenario: Update a monitor notification rule with scope returns "OK" response + Given there is a valid "monitor_notification_rule" in the system + And new "UpdateMonitorNotificationRule" request + And request contains "rule_id" parameter from "monitor_notification_rule.data.id" + And body with value {"data": {"attributes": {"filter": {"scope": "test:{{ unique_lower }}"}, "name": "updated rule", "recipients": ["slack-test-channel"]}, "id": "{{ monitor_notification_rule.data.id }}", "type": "monitor-notification-rule"}} + When the request is sent + Then the response status is 200 OK + And the response "data.attributes.name" is equal to "updated rule" + @skip-validation @team:DataDog/monitor-app Scenario: Update a monitor user template to a new version returns "Bad Request" response Given there is a valid "monitor_user_template" in the system From 6be4c9332530b65d7247842a17fc5ed371c191ec Mon Sep 17 00:00:00 2001 From: "api-clients-generation-pipeline[bot]" <54105614+api-clients-generation-pipeline[bot]@users.noreply.github.com> Date: Thu, 20 Nov 2025 22:35:31 +0000 Subject: [PATCH 2/2] Add rule type conversion limitations for Security Monitoring (#3464) Co-authored-by: ci.datadog-api-spec --- .generator/schemas/v2/openapi.yaml | 30 ++++++++++++++++++++---- api/datadogV2/api_security_monitoring.go | 18 ++++++++++---- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/.generator/schemas/v2/openapi.yaml b/.generator/schemas/v2/openapi.yaml index 6e4cbaacff9..9bceb715496 100644 --- a/.generator/schemas/v2/openapi.yaml +++ b/.generator/schemas/v2/openapi.yaml @@ -79133,9 +79133,20 @@ paths: /api/v2/security_monitoring/rules/convert: post: description: 'Convert a rule that doesn''t (yet) exist from JSON to Terraform - for datadog provider + for Datadog provider - resource datadog_security_monitoring_rule.' + resource `datadog_security_monitoring_rule`. You can do so for the following + rule types: + + - App and API Protection + + - Cloud SIEM (log detection and signal correlation) + + - Workload Protection + + + You can convert Cloud Security configuration rules using Terraform''s [Datadog + Cloud Configuration Rule resource](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/cloud_configuration_rule).' operationId: ConvertSecurityMonitoringRuleFromJSONToTerraform requestBody: content: @@ -79352,9 +79363,20 @@ paths: - security_monitoring_rules_write /api/v2/security_monitoring/rules/{rule_id}/convert: get: - description: 'Convert an existing rule from JSON to Terraform for datadog provider + description: 'Convert an existing rule from JSON to Terraform for Datadog provider + + resource `datadog_security_monitoring_rule`. You can do so for the following + rule types: + + - App and API Protection + + - Cloud SIEM (log detection and signal correlation) + + - Workload Protection + - resource datadog_security_monitoring_rule.' + You can convert Cloud Security configuration rules using Terraform''s [Datadog + Cloud Configuration Rule resource](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/cloud_configuration_rule).' operationId: ConvertExistingSecurityMonitoringRule parameters: - $ref: '#/components/parameters/SecurityMonitoringRuleID' diff --git a/api/datadogV2/api_security_monitoring.go b/api/datadogV2/api_security_monitoring.go index 7f459b02aef..fd8cacacc17 100644 --- a/api/datadogV2/api_security_monitoring.go +++ b/api/datadogV2/api_security_monitoring.go @@ -97,8 +97,13 @@ func (a *SecurityMonitoringApi) CancelThreatHuntingJob(ctx _context.Context, job } // ConvertExistingSecurityMonitoringRule Convert an existing rule from JSON to Terraform. -// Convert an existing rule from JSON to Terraform for datadog provider -// resource datadog_security_monitoring_rule. +// Convert an existing rule from JSON to Terraform for Datadog provider +// resource `datadog_security_monitoring_rule`. You can do so for the following rule types: +// - App and API Protection +// - Cloud SIEM (log detection and signal correlation) +// - Workload Protection +// +// You can convert Cloud Security configuration rules using Terraform's [Datadog Cloud Configuration Rule resource](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/cloud_configuration_rule). func (a *SecurityMonitoringApi) ConvertExistingSecurityMonitoringRule(ctx _context.Context, ruleId string) (SecurityMonitoringRuleConvertResponse, *_nethttp.Response, error) { var ( localVarHTTPMethod = _nethttp.MethodGet @@ -255,8 +260,13 @@ func (a *SecurityMonitoringApi) ConvertJobResultToSignal(ctx _context.Context, b } // ConvertSecurityMonitoringRuleFromJSONToTerraform Convert a rule from JSON to Terraform. -// Convert a rule that doesn't (yet) exist from JSON to Terraform for datadog provider -// resource datadog_security_monitoring_rule. +// Convert a rule that doesn't (yet) exist from JSON to Terraform for Datadog provider +// resource `datadog_security_monitoring_rule`. You can do so for the following rule types: +// - App and API Protection +// - Cloud SIEM (log detection and signal correlation) +// - Workload Protection +// +// You can convert Cloud Security configuration rules using Terraform's [Datadog Cloud Configuration Rule resource](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/cloud_configuration_rule). func (a *SecurityMonitoringApi) ConvertSecurityMonitoringRuleFromJSONToTerraform(ctx _context.Context, body SecurityMonitoringRuleConvertPayload) (SecurityMonitoringRuleConvertResponse, *_nethttp.Response, error) { var ( localVarHTTPMethod = _nethttp.MethodPost