diff --git a/.generator/schemas/v1/openapi.yaml b/.generator/schemas/v1/openapi.yaml index e4c949659..4fc8dbe37 100644 --- a/.generator/schemas/v1/openapi.yaml +++ b/.generator/schemas/v1/openapi.yaml @@ -7255,6 +7255,12 @@ components: Monitor: description: Object describing a monitor. properties: + assets: + description: The list of monitor assets tied to a monitor, which represents + key links for users to take action on monitor alerts (for example, runbooks). + items: + $ref: '#/components/schemas/MonitorAsset' + type: array created: description: Timestamp of the monitor creation. format: date-time @@ -7338,6 +7344,52 @@ components: - type - query type: object + MonitorAsset: + description: 'Represents key links tied to a monitor to help users take action + on alerts. + + This feature is in Preview and only available to users with the feature enabled.' + properties: + category: + $ref: '#/components/schemas/MonitorAssetCategory' + name: + description: Name for the monitor asset + example: Monitor Runbook + type: string + resource_key: + description: Represents the identifier of the internal Datadog resource + that this asset represents. IDs in this field should be passed in as strings. + example: '12345' + type: string + resource_type: + $ref: '#/components/schemas/MonitorAssetResourceType' + url: + description: URL link for the asset. For links with an internal resource + type set, this should be the relative path to where the Datadog domain + is appended internally. For external links, this should be the full URL + path. + example: /notebooks/12345 + type: string + required: + - name + - url + - category + type: object + MonitorAssetCategory: + description: Indicates the type of asset this entity represents on a monitor. + enum: + - runbook + example: runbook + type: string + x-enum-varnames: + - RUNBOOK + MonitorAssetResourceType: + description: Type of internal Datadog resource associated with a monitor asset. + enum: + - notebook + type: string + x-enum-varnames: + - NOTEBOOK MonitorDeviceID: description: ID of the device the Synthetics monitor is running on. Same as `SyntheticsDeviceID`. @@ -8452,6 +8504,13 @@ components: MonitorUpdateRequest: description: Object describing a monitor update request. properties: + assets: + description: The list of monitor assets tied to a monitor, which represents + key links for users to take action on monitor alerts (for example, runbooks). + items: + $ref: '#/components/schemas/MonitorAsset' + nullable: true + type: array created: description: Timestamp of the monitor creation. format: date-time @@ -31584,6 +31643,13 @@ paths: required: false schema: type: boolean + - description: If this argument is set to `true`, the returned data includes + all assets tied to this monitor. + in: query + name: with_assets + required: false + schema: + type: boolean responses: '200': content: diff --git a/examples/v1_monitors_CreateMonitor_3541766733.rs b/examples/v1_monitors_CreateMonitor_3541766733.rs new file mode 100644 index 000000000..0a0afd690 --- /dev/null +++ b/examples/v1_monitors_CreateMonitor_3541766733.rs @@ -0,0 +1,48 @@ +// Create a monitor with assets returns "OK" response +use datadog_api_client::datadog; +use datadog_api_client::datadogV1::api_monitors::MonitorsAPI; +use datadog_api_client::datadogV1::model::Monitor; +use datadog_api_client::datadogV1::model::MonitorAsset; +use datadog_api_client::datadogV1::model::MonitorAssetCategory; +use datadog_api_client::datadogV1::model::MonitorAssetResourceType; +use datadog_api_client::datadogV1::model::MonitorOptions; +use datadog_api_client::datadogV1::model::MonitorOptionsSchedulingOptions; +use datadog_api_client::datadogV1::model::MonitorOptionsSchedulingOptionsEvaluationWindow; +use datadog_api_client::datadogV1::model::MonitorThresholds; +use datadog_api_client::datadogV1::model::MonitorType; + +#[tokio::main] +async fn main() { + let body = Monitor::new( + "avg(current_1mo):avg:system.load.5{*} > 0.5".to_string(), + MonitorType::METRIC_ALERT, + ) + .assets(vec![MonitorAsset::new( + MonitorAssetCategory::RUNBOOK, + "Monitor Runbook".to_string(), + "/notebooks/12345".to_string(), + ) + .resource_key("12345".to_string()) + .resource_type(MonitorAssetResourceType::NOTEBOOK)]) + .message("some message Notify: @hipchat-channel".to_string()) + .name("Example-Monitor".to_string()) + .options( + MonitorOptions::new() + .scheduling_options( + MonitorOptionsSchedulingOptions::new().evaluation_window( + MonitorOptionsSchedulingOptionsEvaluationWindow::new() + .day_starts("04:00".to_string()) + .month_starts(1), + ), + ) + .thresholds(MonitorThresholds::new().critical(0.5 as f64)), + ); + let configuration = datadog::Configuration::new(); + let api = MonitorsAPI::with_config(configuration); + let resp = api.create_monitor(body).await; + if let Ok(value) = resp { + println!("{:#?}", value); + } else { + println!("{:#?}", resp.unwrap_err()); + } +} diff --git a/src/datadogV1/api/api_monitors.rs b/src/datadogV1/api/api_monitors.rs index 1ec8843fa..9d42e772a 100644 --- a/src/datadogV1/api/api_monitors.rs +++ b/src/datadogV1/api/api_monitors.rs @@ -36,6 +36,8 @@ pub struct GetMonitorOptionalParams { pub group_states: Option, /// If this argument is set to true, then the returned data includes all current active downtimes for the monitor. pub with_downtimes: Option, + /// If this argument is set to `true`, the returned data includes all assets tied to this monitor. + pub with_assets: Option, } impl GetMonitorOptionalParams { @@ -49,6 +51,11 @@ impl GetMonitorOptionalParams { self.with_downtimes = Some(value); self } + /// If this argument is set to `true`, the returned data includes all assets tied to this monitor. + pub fn with_assets(mut self, value: bool) -> Self { + self.with_assets = Some(value); + self + } } /// ListMonitorsOptionalParams is a struct for passing parameters to the method [`MonitorsAPI::list_monitors`] @@ -1242,6 +1249,7 @@ impl MonitorsAPI { // unbox and build optional parameters let group_states = params.group_states; let with_downtimes = params.with_downtimes; + let with_assets = params.with_assets; let local_client = &self.client; @@ -1261,6 +1269,10 @@ impl MonitorsAPI { local_req_builder = local_req_builder.query(&[("with_downtimes", &local_query_param.to_string())]); }; + if let Some(ref local_query_param) = with_assets { + local_req_builder = + local_req_builder.query(&[("with_assets", &local_query_param.to_string())]); + }; // build headers let mut headers = HeaderMap::new(); diff --git a/src/datadogV1/model/mod.rs b/src/datadogV1/model/mod.rs index 7a29733b4..417066ecb 100644 --- a/src/datadogV1/model/mod.rs +++ b/src/datadogV1/model/mod.rs @@ -976,6 +976,12 @@ pub mod model_metric_metadata; pub use self::model_metric_metadata::MetricMetadata; pub mod model_monitor; pub use self::model_monitor::Monitor; +pub mod model_monitor_asset; +pub use self::model_monitor_asset::MonitorAsset; +pub mod model_monitor_asset_category; +pub use self::model_monitor_asset_category::MonitorAssetCategory; +pub mod model_monitor_asset_resource_type; +pub use self::model_monitor_asset_resource_type::MonitorAssetResourceType; pub mod model_monitor_draft_status; pub use self::model_monitor_draft_status::MonitorDraftStatus; pub mod model_matching_downtime; diff --git a/src/datadogV1/model/model_monitor.rs b/src/datadogV1/model/model_monitor.rs index f38d6dfd5..5ba8b9245 100644 --- a/src/datadogV1/model/model_monitor.rs +++ b/src/datadogV1/model/model_monitor.rs @@ -11,6 +11,9 @@ use std::fmt::{self, Formatter}; #[skip_serializing_none] #[derive(Clone, Debug, PartialEq, Serialize)] pub struct Monitor { + /// The list of monitor assets tied to a monitor, which represents key links for users to take action on monitor alerts (for example, runbooks). + #[serde(rename = "assets")] + pub assets: Option>, /// Timestamp of the monitor creation. #[serde(rename = "created")] pub created: Option>, @@ -92,6 +95,7 @@ pub struct Monitor { impl Monitor { pub fn new(query: String, type_: crate::datadogV1::model::MonitorType) -> Monitor { Monitor { + assets: None, created: None, creator: None, deleted: None, @@ -115,6 +119,11 @@ impl Monitor { } } + pub fn assets(mut self, value: Vec) -> Self { + self.assets = Some(value); + self + } + pub fn created(mut self, value: chrono::DateTime) -> Self { self.created = Some(value); self @@ -224,6 +233,7 @@ impl<'de> Deserialize<'de> for Monitor { where M: MapAccess<'a>, { + let mut assets: Option> = None; let mut created: Option> = None; let mut creator: Option = None; let mut deleted: Option>> = None; @@ -251,6 +261,12 @@ impl<'de> Deserialize<'de> for Monitor { while let Some((k, v)) = map.next_entry::()? { match k.as_str() { + "assets" => { + if v.is_null() { + continue; + } + assets = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } "created" => { if v.is_null() { continue; @@ -387,6 +403,7 @@ impl<'de> Deserialize<'de> for Monitor { let type_ = type_.ok_or_else(|| M::Error::missing_field("type_"))?; let content = Monitor { + assets, created, creator, deleted, diff --git a/src/datadogV1/model/model_monitor_asset.rs b/src/datadogV1/model/model_monitor_asset.rs new file mode 100644 index 000000000..e713c9df5 --- /dev/null +++ b/src/datadogV1/model/model_monitor_asset.rs @@ -0,0 +1,173 @@ +// 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. +use serde::de::{Error, MapAccess, Visitor}; +use serde::{Deserialize, Deserializer, Serialize}; +use serde_with::skip_serializing_none; +use std::fmt::{self, Formatter}; + +/// Represents key links tied to a monitor to help users take action on alerts. +/// This feature is in Preview and only available to users with the feature enabled. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct MonitorAsset { + /// Indicates the type of asset this entity represents on a monitor. + #[serde(rename = "category")] + pub category: crate::datadogV1::model::MonitorAssetCategory, + /// Name for the monitor asset + #[serde(rename = "name")] + pub name: String, + /// Represents the identifier of the internal Datadog resource that this asset represents. IDs in this field should be passed in as strings. + #[serde(rename = "resource_key")] + pub resource_key: Option, + /// Type of internal Datadog resource associated with a monitor asset. + #[serde(rename = "resource_type")] + pub resource_type: Option, + /// URL link for the asset. For links with an internal resource type set, this should be the relative path to where the Datadog domain is appended internally. For external links, this should be the full URL path. + #[serde(rename = "url")] + pub url: String, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl MonitorAsset { + pub fn new( + category: crate::datadogV1::model::MonitorAssetCategory, + name: String, + url: String, + ) -> MonitorAsset { + MonitorAsset { + category, + name, + resource_key: None, + resource_type: None, + url, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn resource_key(mut self, value: String) -> Self { + self.resource_key = Some(value); + self + } + + pub fn resource_type( + mut self, + value: crate::datadogV1::model::MonitorAssetResourceType, + ) -> Self { + self.resource_type = Some(value); + self + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl<'de> Deserialize<'de> for MonitorAsset { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct MonitorAssetVisitor; + impl<'a> Visitor<'a> for MonitorAssetVisitor { + type Value = MonitorAsset; + + fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str("a mapping") + } + + fn visit_map(self, mut map: M) -> Result + where + M: MapAccess<'a>, + { + let mut category: Option = None; + let mut name: Option = None; + let mut resource_key: Option = None; + let mut resource_type: Option = + None; + let mut url: Option = None; + let mut additional_properties: std::collections::BTreeMap< + String, + serde_json::Value, + > = std::collections::BTreeMap::new(); + let mut _unparsed = false; + + while let Some((k, v)) = map.next_entry::()? { + match k.as_str() { + "category" => { + category = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + if let Some(ref _category) = category { + match _category { + crate::datadogV1::model::MonitorAssetCategory::UnparsedObject(_category) => { + _unparsed = true; + }, + _ => {} + } + } + } + "name" => { + name = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "resource_key" => { + if v.is_null() { + continue; + } + resource_key = + Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "resource_type" => { + if v.is_null() { + continue; + } + resource_type = + Some(serde_json::from_value(v).map_err(M::Error::custom)?); + if let Some(ref _resource_type) = resource_type { + match _resource_type { + crate::datadogV1::model::MonitorAssetResourceType::UnparsedObject(_resource_type) => { + _unparsed = true; + }, + _ => {} + } + } + } + "url" => { + url = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + &_ => { + if let Ok(value) = serde_json::from_value(v.clone()) { + additional_properties.insert(k, value); + } + } + } + } + let category = category.ok_or_else(|| M::Error::missing_field("category"))?; + let name = name.ok_or_else(|| M::Error::missing_field("name"))?; + let url = url.ok_or_else(|| M::Error::missing_field("url"))?; + + let content = MonitorAsset { + category, + name, + resource_key, + resource_type, + url, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(MonitorAssetVisitor) + } +} diff --git a/src/datadogV1/model/model_monitor_asset_category.rs b/src/datadogV1/model/model_monitor_asset_category.rs new file mode 100644 index 000000000..032b649f8 --- /dev/null +++ b/src/datadogV1/model/model_monitor_asset_category.rs @@ -0,0 +1,48 @@ +// 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. + +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +#[non_exhaustive] +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum MonitorAssetCategory { + RUNBOOK, + UnparsedObject(crate::datadog::UnparsedObject), +} + +impl ToString for MonitorAssetCategory { + fn to_string(&self) -> String { + match self { + Self::RUNBOOK => String::from("runbook"), + Self::UnparsedObject(v) => v.value.to_string(), + } + } +} + +impl Serialize for MonitorAssetCategory { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self { + Self::UnparsedObject(v) => v.serialize(serializer), + _ => serializer.serialize_str(self.to_string().as_str()), + } + } +} + +impl<'de> Deserialize<'de> for MonitorAssetCategory { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s: String = String::deserialize(deserializer)?; + Ok(match s.as_str() { + "runbook" => Self::RUNBOOK, + _ => Self::UnparsedObject(crate::datadog::UnparsedObject { + value: serde_json::Value::String(s.into()), + }), + }) + } +} diff --git a/src/datadogV1/model/model_monitor_asset_resource_type.rs b/src/datadogV1/model/model_monitor_asset_resource_type.rs new file mode 100644 index 000000000..0e5033f9d --- /dev/null +++ b/src/datadogV1/model/model_monitor_asset_resource_type.rs @@ -0,0 +1,48 @@ +// 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. + +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +#[non_exhaustive] +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum MonitorAssetResourceType { + NOTEBOOK, + UnparsedObject(crate::datadog::UnparsedObject), +} + +impl ToString for MonitorAssetResourceType { + fn to_string(&self) -> String { + match self { + Self::NOTEBOOK => String::from("notebook"), + Self::UnparsedObject(v) => v.value.to_string(), + } + } +} + +impl Serialize for MonitorAssetResourceType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self { + Self::UnparsedObject(v) => v.serialize(serializer), + _ => serializer.serialize_str(self.to_string().as_str()), + } + } +} + +impl<'de> Deserialize<'de> for MonitorAssetResourceType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s: String = String::deserialize(deserializer)?; + Ok(match s.as_str() { + "notebook" => Self::NOTEBOOK, + _ => Self::UnparsedObject(crate::datadog::UnparsedObject { + value: serde_json::Value::String(s.into()), + }), + }) + } +} diff --git a/src/datadogV1/model/model_monitor_update_request.rs b/src/datadogV1/model/model_monitor_update_request.rs index 048ab1c11..65599e609 100644 --- a/src/datadogV1/model/model_monitor_update_request.rs +++ b/src/datadogV1/model/model_monitor_update_request.rs @@ -11,6 +11,9 @@ use std::fmt::{self, Formatter}; #[skip_serializing_none] #[derive(Clone, Debug, PartialEq, Serialize)] pub struct MonitorUpdateRequest { + /// The list of monitor assets tied to a monitor, which represents key links for users to take action on monitor alerts (for example, runbooks). + #[serde(rename = "assets", default, with = "::serde_with::rust::double_option")] + pub assets: Option>>, /// Timestamp of the monitor creation. #[serde(rename = "created")] pub created: Option>, @@ -89,6 +92,7 @@ pub struct MonitorUpdateRequest { impl MonitorUpdateRequest { pub fn new() -> MonitorUpdateRequest { MonitorUpdateRequest { + assets: None, created: None, creator: None, deleted: None, @@ -111,6 +115,11 @@ impl MonitorUpdateRequest { } } + pub fn assets(mut self, value: Option>) -> Self { + self.assets = Some(value); + self + } + pub fn created(mut self, value: chrono::DateTime) -> Self { self.created = Some(value); self @@ -228,6 +237,7 @@ impl<'de> Deserialize<'de> for MonitorUpdateRequest { where M: MapAccess<'a>, { + let mut assets: Option>> = None; let mut created: Option> = None; let mut creator: Option = None; let mut deleted: Option>> = None; @@ -253,6 +263,9 @@ impl<'de> Deserialize<'de> for MonitorUpdateRequest { while let Some((k, v)) = map.next_entry::()? { match k.as_str() { + "assets" => { + assets = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } "created" => { if v.is_null() { continue; @@ -386,6 +399,7 @@ impl<'de> Deserialize<'de> for MonitorUpdateRequest { } let content = MonitorUpdateRequest { + assets, created, creator, deleted, diff --git a/tests/scenarios/cassettes/v1/monitors/Check-if-a-monitor-can-be-deleted-returns-OK-response.frozen b/tests/scenarios/cassettes/v1/monitors/Check-if-a-monitor-can-be-deleted-returns-OK-response.frozen index 2dbbd94e2..9dda83bd1 100644 --- a/tests/scenarios/cassettes/v1/monitors/Check-if-a-monitor-can-be-deleted-returns-OK-response.frozen +++ b/tests/scenarios/cassettes/v1/monitors/Check-if-a-monitor-can-be-deleted-returns-OK-response.frozen @@ -1 +1 @@ -2024-10-10T16:41:03.364Z \ No newline at end of file +2025-11-21T18:03:25.715Z \ No newline at end of file diff --git a/tests/scenarios/cassettes/v1/monitors/Check-if-a-monitor-can-be-deleted-returns-OK-response.json b/tests/scenarios/cassettes/v1/monitors/Check-if-a-monitor-can-be-deleted-returns-OK-response.json index ec6806437..74eeaeea7 100644 --- a/tests/scenarios/cassettes/v1/monitors/Check-if-a-monitor-can-be-deleted-returns-OK-response.json +++ b/tests/scenarios/cassettes/v1/monitors/Check-if-a-monitor-can-be-deleted-returns-OK-response.json @@ -3,7 +3,7 @@ { "request": { "body": { - "string": "{\"message\":\"some message Notify: @hipchat-channel\",\"name\":\"Test-Check_if_a_monitor_can_be_deleted_returns_OK_response-1728578463\",\"options\":{\"enable_logs_sample\":true,\"escalation_message\":\"the situation has escalated\",\"evaluation_delay\":700,\"include_tags\":true,\"locked\":false,\"new_host_delay\":600,\"no_data_timeframe\":null,\"notification_preset_name\":\"hide_handles\",\"notify_audit\":false,\"notify_no_data\":false,\"on_missing_data\":\"show_and_notify_no_data\",\"renotify_interval\":60,\"require_full_window\":true,\"thresholds\":{\"critical\":2,\"warning\":1},\"timeout_h\":24},\"priority\":3,\"query\":\"logs(\\\"service:foo AND type:error\\\").index(\\\"main\\\").rollup(\\\"count\\\").by(\\\"source\\\").last(\\\"5m\\\") > 2\",\"tags\":[\"test:testcheckifamonitorcanbedeletedreturnsokresponse1728578463\",\"env:ci\"],\"type\":\"log alert\"}", + "string": "{\"message\":\"some message Notify: @hipchat-channel\",\"name\":\"Test-Check_if_a_monitor_can_be_deleted_returns_OK_response-1763748205\",\"options\":{\"enable_logs_sample\":true,\"escalation_message\":\"the situation has escalated\",\"evaluation_delay\":700,\"include_tags\":true,\"locked\":false,\"new_host_delay\":600,\"no_data_timeframe\":null,\"notification_preset_name\":\"hide_handles\",\"notify_audit\":false,\"notify_no_data\":false,\"on_missing_data\":\"show_and_notify_no_data\",\"renotify_interval\":60,\"require_full_window\":true,\"thresholds\":{\"critical\":2,\"warning\":1},\"timeout_h\":24},\"priority\":3,\"query\":\"logs(\\\"service:foo AND type:error\\\").index(\\\"main\\\").rollup(\\\"count\\\").by(\\\"source\\\").last(\\\"5m\\\") > 2\",\"tags\":[\"test:testcheckifamonitorcanbedeletedreturnsokresponse1763748205\",\"env:ci\"],\"type\":\"log alert\"}", "encoding": null }, "headers": { @@ -19,7 +19,7 @@ }, "response": { "body": { - "string": "{\"id\":155845287,\"org_id\":321813,\"type\":\"log alert\",\"name\":\"Test-Check_if_a_monitor_can_be_deleted_returns_OK_response-1728578463\",\"message\":\"some message Notify: @hipchat-channel\",\"tags\":[\"test:testcheckifamonitorcanbedeletedreturnsokresponse1728578463\",\"env:ci\"],\"query\":\"logs(\\\"service:foo AND type:error\\\").index(\\\"main\\\").rollup(\\\"count\\\").by(\\\"source\\\").last(\\\"5m\\\") > 2\",\"options\":{\"enable_logs_sample\":true,\"escalation_message\":\"the situation has escalated\",\"evaluation_delay\":700,\"include_tags\":true,\"locked\":false,\"new_host_delay\":600,\"no_data_timeframe\":null,\"notification_preset_name\":\"hide_handles\",\"notify_audit\":false,\"notify_no_data\":false,\"on_missing_data\":\"show_and_notify_no_data\",\"renotify_interval\":60,\"require_full_window\":true,\"thresholds\":{\"critical\":2.0,\"warning\":1.0},\"timeout_h\":24,\"groupby_simple_monitor\":false,\"silenced\":{}},\"multi\":true,\"created_at\":1728578463000,\"created\":\"2024-10-10T16:41:03.666877+00:00\",\"modified\":\"2024-10-10T16:41:03.666877+00:00\",\"deleted\":null,\"restricted_roles\":null,\"priority\":3,\"restriction_policy\":null,\"overall_state_modified\":null,\"overall_state\":\"No Data\",\"creator\":{\"name\":null,\"handle\":\"frog@datadoghq.com\",\"email\":\"frog@datadoghq.com\",\"id\":1445416}}\n", + "string": "{\"id\":238669218,\"org_id\":197728,\"type\":\"log alert\",\"name\":\"Test-Check_if_a_monitor_can_be_deleted_returns_OK_response-1763748205\",\"message\":\"some message Notify: @hipchat-channel\",\"tags\":[\"test:testcheckifamonitorcanbedeletedreturnsokresponse1763748205\",\"env:ci\"],\"query\":\"logs(\\\"service:foo AND type:error\\\").index(\\\"main\\\").rollup(\\\"count\\\").by(\\\"source\\\").last(\\\"5m\\\") > 2\",\"options\":{\"enable_logs_sample\":true,\"escalation_message\":\"the situation has escalated\",\"evaluation_delay\":700,\"include_tags\":true,\"locked\":false,\"new_host_delay\":600,\"no_data_timeframe\":null,\"notification_preset_name\":\"hide_handles\",\"notify_audit\":false,\"notify_no_data\":false,\"on_missing_data\":\"show_and_notify_no_data\",\"renotify_interval\":60,\"require_full_window\":true,\"thresholds\":{\"critical\":2.0,\"warning\":1.0},\"timeout_h\":24,\"groupby_simple_monitor\":false,\"silenced\":{}},\"multi\":true,\"created_at\":1763748206000,\"created\":\"2025-11-21T18:03:26.123200+00:00\",\"modified\":\"2025-11-21T18:03:26.123200+00:00\",\"deleted\":null,\"priority\":3,\"restricted_roles\":null,\"restriction_policy\":null,\"draft_status\":\"published\",\"assets\":[],\"overall_state_modified\":null,\"overall_state\":\"No Data\",\"creator\":{\"name\":\"Kevin Pombo\",\"handle\":\"kevin.pombo@datadoghq.com\",\"email\":\"kevin.pombo@datadoghq.com\",\"id\":25712273}}\n", "encoding": null }, "headers": { @@ -32,7 +32,7 @@ "message": "OK" } }, - "recorded_at": "Thu, 10 Oct 2024 16:41:03 GMT" + "recorded_at": "Fri, 21 Nov 2025 18:03:25 GMT" }, { "request": { @@ -43,11 +43,11 @@ ] }, "method": "get", - "uri": "https://api.datadoghq.com/api/v1/monitor/can_delete?monitor_ids=155845287" + "uri": "https://api.datadoghq.com/api/v1/monitor/can_delete?monitor_ids=238669218" }, "response": { "body": { - "string": "{\"data\":{\"ok\":[155845287]},\"errors\":null}\n", + "string": "{\"data\":{\"ok\":[238669218]},\"errors\":null}\n", "encoding": null }, "headers": { @@ -60,7 +60,7 @@ "message": "OK" } }, - "recorded_at": "Thu, 10 Oct 2024 16:41:03 GMT" + "recorded_at": "Fri, 21 Nov 2025 18:03:25 GMT" }, { "request": { @@ -71,11 +71,11 @@ ] }, "method": "delete", - "uri": "https://api.datadoghq.com/api/v1/monitor/155845287" + "uri": "https://api.datadoghq.com/api/v1/monitor/238669218" }, "response": { "body": { - "string": "{\"deleted_monitor_id\":155845287}\n", + "string": "{\"deleted_monitor_id\":238669218}\n", "encoding": null }, "headers": { @@ -88,7 +88,7 @@ "message": "OK" } }, - "recorded_at": "Thu, 10 Oct 2024 16:41:03 GMT" + "recorded_at": "Fri, 21 Nov 2025 18:03:25 GMT" } ], "recorded_with": "VCR 6.0.0" diff --git a/tests/scenarios/cassettes/v1/monitors/Create-a-monitor-with-assets-returns-OK-response.frozen b/tests/scenarios/cassettes/v1/monitors/Create-a-monitor-with-assets-returns-OK-response.frozen new file mode 100644 index 000000000..12b1e5fed --- /dev/null +++ b/tests/scenarios/cassettes/v1/monitors/Create-a-monitor-with-assets-returns-OK-response.frozen @@ -0,0 +1 @@ +2025-11-21T19:04:55.769Z \ No newline at end of file diff --git a/tests/scenarios/cassettes/v1/monitors/Create-a-monitor-with-assets-returns-OK-response.json b/tests/scenarios/cassettes/v1/monitors/Create-a-monitor-with-assets-returns-OK-response.json new file mode 100644 index 000000000..820a9796d --- /dev/null +++ b/tests/scenarios/cassettes/v1/monitors/Create-a-monitor-with-assets-returns-OK-response.json @@ -0,0 +1,67 @@ +{ + "http_interactions": [ + { + "request": { + "body": { + "string": "{\"assets\":[{\"category\":\"runbook\",\"name\":\"Monitor Runbook\",\"resource_key\":\"12345\",\"resource_type\":\"notebook\",\"url\":\"/notebooks/12345\"}],\"message\":\"some message Notify: @hipchat-channel\",\"name\":\"Test-Create_a_monitor_with_assets_returns_OK_response-1763751895\",\"options\":{\"scheduling_options\":{\"evaluation_window\":{\"day_starts\":\"04:00\",\"month_starts\":1}},\"thresholds\":{\"critical\":0.5}},\"query\":\"avg(current_1mo):avg:system.load.5{*} > 0.5\",\"type\":\"metric alert\"}", + "encoding": null + }, + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json" + ] + }, + "method": "post", + "uri": "https://api.datadoghq.com/api/v1/monitor" + }, + "response": { + "body": { + "string": "{\"id\":238681257,\"org_id\":321813,\"type\":\"query alert\",\"name\":\"Test-Create_a_monitor_with_assets_returns_OK_response-1763751895\",\"message\":\"some message Notify: @hipchat-channel\",\"tags\":[],\"query\":\"avg(current_1mo):avg:system.load.5{*} > 0.5\",\"options\":{\"scheduling_options\":{\"evaluation_window\":{\"day_starts\":\"04:00\",\"month_starts\":1}},\"thresholds\":{\"critical\":0.5},\"notify_no_data\":false,\"notify_audit\":false,\"new_host_delay\":300,\"include_tags\":true,\"silenced\":{}},\"multi\":false,\"created_at\":1763751896000,\"created\":\"2025-11-21T19:04:56.060346+00:00\",\"modified\":\"2025-11-21T19:04:56.060346+00:00\",\"deleted\":null,\"priority\":null,\"restricted_roles\":null,\"restriction_policy\":null,\"draft_status\":\"published\",\"assets\":[{\"monitor_id\":238681257,\"name\":\"Monitor Runbook\",\"category\":\"runbook\",\"url\":\"/notebooks/12345\",\"template_variables\":{},\"options\":{},\"resource_key\":\"12345\",\"resource_type\":\"notebook\"}],\"overall_state_modified\":null,\"overall_state\":\"No Data\",\"creator\":{\"name\":\"CI Account\",\"handle\":\"9919ec9b-ebc7-49ee-8dc8-03626e717cca\",\"email\":\"team-intg-tools-libs-spam@datadoghq.com\",\"id\":2320499}}\n", + "encoding": null + }, + "headers": { + "Content-Type": [ + "application/json" + ] + }, + "status": { + "code": 200, + "message": "OK" + } + }, + "recorded_at": "Fri, 21 Nov 2025 19:04:55 GMT" + }, + { + "request": { + "body": "", + "headers": { + "Accept": [ + "application/json" + ] + }, + "method": "delete", + "uri": "https://api.datadoghq.com/api/v1/monitor/238681257" + }, + "response": { + "body": { + "string": "{\"deleted_monitor_id\":238681257}\n", + "encoding": null + }, + "headers": { + "Content-Type": [ + "application/json" + ] + }, + "status": { + "code": 200, + "message": "OK" + } + }, + "recorded_at": "Fri, 21 Nov 2025 19:04:55 GMT" + } + ], + "recorded_with": "VCR 6.0.0" +} \ No newline at end of file diff --git a/tests/scenarios/features/v1/monitors.feature b/tests/scenarios/features/v1/monitors.feature index 64e72f698..75a681927 100644 --- a/tests/scenarios/features/v1/monitors.feature +++ b/tests/scenarios/features/v1/monitors.feature @@ -131,6 +131,18 @@ Feature: Monitors And the response "type" is equal to "log alert" And the response "query" is equal to "logs(\"service:foo AND type:error\").index(\"main\").rollup(\"count\").by(\"source\").last(\"5m\") > 2" + @team:DataDog/monitor-app + Scenario: Create a monitor with assets returns "OK" response + Given new "CreateMonitor" request + And body with value {"assets": [{"category": "runbook", "name": "Monitor Runbook", "resource_key": "12345", "resource_type": "notebook", "url": "/notebooks/12345"}], "name": "{{ unique }}", "type": "metric alert", "query": "avg(current_1mo):avg:system.load.5{*} > 0.5", "message": "some message Notify: @hipchat-channel", "options":{"thresholds":{"critical":0.5}, "scheduling_options":{"evaluation_window":{"day_starts":"04:00", "month_starts":1}}}} + When the request is sent + Then the response status is 200 OK + And the response "assets[0].category" is equal to "runbook" + And the response "assets[0].name" is equal to "Monitor Runbook" + And the response "assets[0].resource_key" is equal to "12345" + And the response "assets[0].resource_type" is equal to "notebook" + And the response "assets[0].url" is equal to "/notebooks/12345" + @team:DataDog/monitor-app Scenario: Create an Error Tracking monitor returns "OK" response Given new "CreateMonitor" request @@ -169,7 +181,7 @@ Feature: Monitors Scenario: Edit a monitor returns "Bad Request" response Given new "UpdateMonitor" request And request contains "monitor_id" parameter from "REPLACE.ME" - And body with value {"draft_status": "published", "options": {"evaluation_delay": null, "include_tags": true, "min_failure_duration": 0, "min_location_failed": 1, "new_group_delay": null, "new_host_delay": 300, "no_data_timeframe": null, "notification_preset_name": "show_all", "notify_audit": false, "notify_by": [], "on_missing_data": "default", "renotify_interval": null, "renotify_occurrences": null, "renotify_statuses": ["alert"], "scheduling_options": {"custom_schedule": {"recurrences": [{"rrule": "FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR", "start": "2023-08-31T16:30:00", "timezone": "Europe/Paris"}]}, "evaluation_window": {"day_starts": "04:00", "hour_starts": 0, "month_starts": 1, "timezone": "Europe/Paris"}}, "synthetics_check_id": null, "threshold_windows": {"recovery_window": null, "trigger_window": null}, "thresholds": {"critical_recovery": null, "ok": null, "unknown": null, "warning": null, "warning_recovery": null}, "timeout_h": null, "variables": [{"compute": {"aggregation": "avg", "interval": 60000, "metric": "@duration"}, "data_source": "rum", "group_by": [{"facet": "status", "limit": 10, "sort": {"aggregation": "avg", "order": "desc"}}], "indexes": ["days-3", "days-7"], "name": "query_errors", "search": {"query": "service:query"}}]}, "priority": null, "restricted_roles": [], "tags": [], "type": "query alert"} + And body with value {"assets": [{"category": "runbook", "name": "Monitor Runbook", "resource_key": "12345", "resource_type": "notebook", "url": "/notebooks/12345"}], "draft_status": "published", "options": {"evaluation_delay": null, "include_tags": true, "min_failure_duration": 0, "min_location_failed": 1, "new_group_delay": null, "new_host_delay": 300, "no_data_timeframe": null, "notification_preset_name": "show_all", "notify_audit": false, "notify_by": [], "on_missing_data": "default", "renotify_interval": null, "renotify_occurrences": null, "renotify_statuses": ["alert"], "scheduling_options": {"custom_schedule": {"recurrences": [{"rrule": "FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR", "start": "2023-08-31T16:30:00", "timezone": "Europe/Paris"}]}, "evaluation_window": {"day_starts": "04:00", "hour_starts": 0, "month_starts": 1, "timezone": "Europe/Paris"}}, "synthetics_check_id": null, "threshold_windows": {"recovery_window": null, "trigger_window": null}, "thresholds": {"critical_recovery": null, "ok": null, "unknown": null, "warning": null, "warning_recovery": null}, "timeout_h": null, "variables": [{"compute": {"aggregation": "avg", "interval": 60000, "metric": "@duration"}, "data_source": "rum", "group_by": [{"facet": "status", "limit": 10, "sort": {"aggregation": "avg", "order": "desc"}}], "indexes": ["days-3", "days-7"], "name": "query_errors", "search": {"query": "service:query"}}]}, "priority": null, "restricted_roles": [], "tags": [], "type": "query alert"} When the request is sent Then the response status is 400 Bad Request diff --git a/tests/scenarios/function_mappings.rs b/tests/scenarios/function_mappings.rs index 925d69993..b636e5777 100644 --- a/tests/scenarios/function_mappings.rs +++ b/tests/scenarios/function_mappings.rs @@ -9331,9 +9331,13 @@ fn test_v1_get_monitor(world: &mut DatadogWorld, _parameters: &HashMap response, Err(error) => {