diff --git a/.generator/schemas/v2/openapi.yaml b/.generator/schemas/v2/openapi.yaml index f5b3f39298..1c4b251e01 100644 --- a/.generator/schemas/v2/openapi.yaml +++ b/.generator/schemas/v2/openapi.yaml @@ -1699,6 +1699,15 @@ components: required: true schema: type: string + SecurityMonitoringRuleVersion: + description: The historical version number of the rule. + in: path + name: version + required: true + schema: + example: 1 + format: int64 + type: integer SecurityMonitoringSuppressionID: description: The ID of the suppression rule in: path @@ -28735,6 +28744,31 @@ components: - bucket_name - bucket_region type: object + DataObservabilityMonitorRunStatus: + description: The status of a data observability monitor run. + enum: + - pending + - ok + - warn + - alert + - error + example: pending + type: string + x-enum-varnames: + - PENDING + - OK + - WARN + - ALERT + - ERROR + DataObservabilityMonitorRunType: + default: monitor_run + description: The JSON:API resource type for a data observability monitor run. + enum: + - monitor_run + example: monitor_run + type: string + x-enum-varnames: + - MONITOR_RUN DataRelationshipsTeams: description: Associates teams with this schedule in a data structure. properties: @@ -39045,6 +39079,42 @@ components: meta: $ref: "#/components/schemas/DataDeletionResponseMeta" type: object + GetDataObservabilityMonitorRunStatusResponse: + description: The response for getting the status of a data observability monitor run. + properties: + data: + $ref: "#/components/schemas/GetDataObservabilityMonitorRunStatusResponseData" + required: + - data + type: object + GetDataObservabilityMonitorRunStatusResponseAttributes: + description: The attributes of a data observability monitor run status response. + properties: + error_message: + description: Error message describing why the monitor run failed. Only present when status is error. + example: "run completed but produced no metric data" + type: string + status: + $ref: "#/components/schemas/DataObservabilityMonitorRunStatus" + required: + - status + type: object + GetDataObservabilityMonitorRunStatusResponseData: + description: The data object for a data observability monitor run status response. + properties: + attributes: + $ref: "#/components/schemas/GetDataObservabilityMonitorRunStatusResponseAttributes" + id: + description: The unique identifier of the monitor run. + example: "abc123def456" + type: string + type: + $ref: "#/components/schemas/DataObservabilityMonitorRunType" + required: + - id + - type + - attributes + type: object GetDeviceAttributes: description: The device attributes properties: @@ -77898,6 +77968,27 @@ components: $ref: "#/components/schemas/RumRetentionFilterData" type: array type: object + RunDataObservabilityMonitorResponse: + description: The response returned when a data observability monitor run is triggered. + properties: + data: + $ref: "#/components/schemas/RunDataObservabilityMonitorResponseData" + required: + - data + type: object + RunDataObservabilityMonitorResponseData: + description: The data object returned when a data observability monitor run is triggered. + properties: + id: + description: The unique identifier of the monitor run. + example: "abc123def456" + type: string + type: + $ref: "#/components/schemas/DataObservabilityMonitorRunType" + required: + - id + - type + type: object RunHistoricalJobRequest: description: Run a historical job request. properties: @@ -124777,6 +124868,105 @@ paths: x-unstable: |- **Note**: This endpoint is in preview and is subject to change. If you have any feedback, contact [Datadog support](https://docs.datadoghq.com/help/). + /api/v2/data-observability/monitors/runs/{run_id}/status: + get: + description: Retrieves the current status of a data observability monitor run. Poll this endpoint after triggering a run to determine when evaluation is complete. + operationId: GetDataObservabilityMonitorRunStatus + parameters: + - description: The ID of the monitor run to retrieve status for. + example: "abc123def456" + in: path + name: run_id + required: true + schema: + type: string + responses: + "200": + content: + application/json: + examples: + default: + value: + data: + attributes: + status: ok + id: "abc123def456" + type: monitor_run + schema: + $ref: "#/components/schemas/GetDataObservabilityMonitorRunStatusResponse" + description: OK + "404": + content: + application/json: + schema: + $ref: "#/components/schemas/JSONAPIErrorResponse" + description: Not Found + "429": + $ref: "#/components/responses/TooManyRequestsResponse" + security: + - apiKeyAuth: [] + appKeyAuth: [] + - AuthZ: + - data_observability_monitors_write + - monitors_write + summary: Get data observability monitor run status + tags: + - Data Observability + x-unstable: |- + **Note**: This endpoint is in preview and is subject to change. + If you have any feedback, contact [Datadog support](https://docs.datadoghq.com/help/). + /api/v2/data-observability/monitors/{monitor_id}/run: + post: + description: Manually triggers a run for a data observability monitor. Only monitors that are not scheduled (manually-runnable) can be triggered this way. + operationId: RunDataObservabilityMonitor + parameters: + - description: The ID of the data observability monitor to run. + example: 12345 + in: path + name: monitor_id + required: true + schema: + format: int64 + type: integer + responses: + "200": + content: + application/json: + examples: + default: + value: + data: + id: "abc123def456" + type: monitor_run + schema: + $ref: "#/components/schemas/RunDataObservabilityMonitorResponse" + description: OK + "400": + content: + application/json: + schema: + $ref: "#/components/schemas/JSONAPIErrorResponse" + description: Bad Request + "404": + content: + application/json: + schema: + $ref: "#/components/schemas/JSONAPIErrorResponse" + description: Not Found + "429": + $ref: "#/components/responses/TooManyRequestsResponse" + security: + - apiKeyAuth: [] + appKeyAuth: [] + - AuthZ: + - data_observability_monitors_write + - monitors_write + summary: Run a data observability monitor + tags: + - Data Observability + x-unstable: |- + **Note**: This endpoint is in preview and is subject to change. + If you have any feedback, contact [Datadog support](https://docs.datadoghq.com/help/). /api/v2/datasets: get: description: Get all datasets that have been configured for an organization. @@ -169731,6 +169921,60 @@ paths: operator: OR permissions: - security_monitoring_rules_read + /api/v2/security_monitoring/rules/{rule_id}/restore/{version}: + post: + description: |- + Restores a custom detection rule to a previously saved historical version. + Only custom rules can be restored. Default and partner rules return 400. + The restore creates a new version entry; it does not overwrite history. + operationId: RestoreSecurityMonitoringRule + parameters: + - $ref: "#/components/parameters/SecurityMonitoringRuleID" + - $ref: "#/components/parameters/SecurityMonitoringRuleVersion" + responses: + "200": + content: + "application/json": + examples: + default: + value: + cases: + - condition: "a > 0" + name: "" + notifications: [] + status: info + id: abc-123 + isEnabled: true + message: Test rule + name: My security monitoring rule. + tags: [] + type: log_detection + schema: + $ref: "#/components/schemas/SecurityMonitoringRuleResponse" + description: OK + "400": + $ref: "#/components/responses/BadRequestResponse" + "403": + $ref: "#/components/responses/NotAuthorizedResponse" + "404": + $ref: "#/components/responses/NotFoundResponse" + "409": + $ref: "#/components/responses/ConflictResponse" + "429": + $ref: "#/components/responses/TooManyRequestsResponse" + security: + - apiKeyAuth: [] + appKeyAuth: [] + - AuthZ: + - security_monitoring_rules_write + summary: Restore a rule to a historical version + tags: ["Security Monitoring"] + "x-permission": + operator: OR + permissions: + - security_monitoring_rules_write + x-unstable: |- + **Note**: This endpoint is in beta and may be subject to changes. /api/v2/security_monitoring/rules/{rule_id}/test: post: description: |- @@ -186518,6 +186762,8 @@ tags: - description: |- The Data Deletion API allows the user to target and delete data from the allowed products. It's currently enabled for Logs and RUM and depends on `logs_delete_data` and `rum_delete_data` permissions respectively. name: Data Deletion + - description: Manage and run data observability monitors. + name: Data Observability - description: |- Data Access Controls in Datadog is a feature that allows administrators and access managers to regulate access to sensitive data. By defining Restricted Datasets, you can ensure that only specific teams or roles can diff --git a/examples/v2_security-monitoring_RestoreSecurityMonitoringRule.rs b/examples/v2_security-monitoring_RestoreSecurityMonitoringRule.rs new file mode 100644 index 0000000000..fadb505a30 --- /dev/null +++ b/examples/v2_security-monitoring_RestoreSecurityMonitoringRule.rs @@ -0,0 +1,20 @@ +// Restore a rule to a historical version returns "OK" response +use datadog_api_client::datadog; +use datadog_api_client::datadogV2::api_security_monitoring::SecurityMonitoringAPI; + +#[tokio::main] +async fn main() { + // there is a valid "security_rule" in the system + let security_rule_id = std::env::var("SECURITY_RULE_ID").unwrap(); + let mut configuration = datadog::Configuration::new(); + configuration.set_unstable_operation_enabled("v2.RestoreSecurityMonitoringRule", true); + let api = SecurityMonitoringAPI::with_config(configuration); + let resp = api + .restore_security_monitoring_rule(security_rule_id.clone(), 1) + .await; + if let Ok(value) = resp { + println!("{:#?}", value); + } else { + println!("{:#?}", resp.unwrap_err()); + } +} diff --git a/src/datadog/configuration.rs b/src/datadog/configuration.rs index 38fb41d509..394e13eace 100644 --- a/src/datadog/configuration.rs +++ b/src/datadog/configuration.rs @@ -374,6 +374,7 @@ impl Default for Configuration { ("v2.list_vulnerabilities".to_owned(), false), ("v2.list_vulnerable_assets".to_owned(), false), ("v2.mute_findings".to_owned(), false), + ("v2.restore_security_monitoring_rule".to_owned(), false), ("v2.run_historical_job".to_owned(), false), ( "v2.search_security_monitoring_histsignals".to_owned(), @@ -441,6 +442,11 @@ impl Default for Configuration { ("v2.update_dashboard_secure_embed".to_owned(), false), ("v2.get_dashboard_usage".to_owned(), false), ("v2.list_dashboards_usage".to_owned(), false), + ( + "v2.get_data_observability_monitor_run_status".to_owned(), + false, + ), + ("v2.run_data_observability_monitor".to_owned(), false), ("v2.create_dataset".to_owned(), false), ("v2.delete_dataset".to_owned(), false), ("v2.get_all_datasets".to_owned(), false), diff --git a/src/datadogV2/api/api_data_observability.rs b/src/datadogV2/api/api_data_observability.rs new file mode 100644 index 0000000000..198227eadb --- /dev/null +++ b/src/datadogV2/api/api_data_observability.rs @@ -0,0 +1,344 @@ +// 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 crate::datadog; +use log::warn; +use reqwest::header::{HeaderMap, HeaderValue}; +use serde::{Deserialize, Serialize}; + +/// GetDataObservabilityMonitorRunStatusError is a struct for typed errors of method [`DataObservabilityAPI::get_data_observability_monitor_run_status`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum GetDataObservabilityMonitorRunStatusError { + JSONAPIErrorResponse(crate::datadogV2::model::JSONAPIErrorResponse), + APIErrorResponse(crate::datadogV2::model::APIErrorResponse), + UnknownValue(serde_json::Value), +} + +/// RunDataObservabilityMonitorError is a struct for typed errors of method [`DataObservabilityAPI::run_data_observability_monitor`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum RunDataObservabilityMonitorError { + JSONAPIErrorResponse(crate::datadogV2::model::JSONAPIErrorResponse), + APIErrorResponse(crate::datadogV2::model::APIErrorResponse), + UnknownValue(serde_json::Value), +} + +/// Manage and run data observability monitors. +#[derive(Debug, Clone)] +pub struct DataObservabilityAPI { + config: datadog::Configuration, + client: reqwest_middleware::ClientWithMiddleware, +} + +impl Default for DataObservabilityAPI { + fn default() -> Self { + Self::with_config(datadog::Configuration::default()) + } +} + +impl DataObservabilityAPI { + pub fn new() -> Self { + Self::default() + } + pub fn with_config(config: datadog::Configuration) -> Self { + let reqwest_client_builder = { + let builder = reqwest::Client::builder(); + #[cfg(not(target_arch = "wasm32"))] + let builder = if let Some(proxy_url) = &config.proxy_url { + builder.proxy(reqwest::Proxy::all(proxy_url).expect("Failed to parse proxy URL")) + } else { + builder + }; + builder + }; + + let middleware_client_builder = { + let builder = + reqwest_middleware::ClientBuilder::new(reqwest_client_builder.build().unwrap()); + #[cfg(feature = "retry")] + let builder = if config.enable_retry { + struct RetryableStatus; + impl reqwest_retry::RetryableStrategy for RetryableStatus { + fn handle( + &self, + res: &Result, + ) -> Option { + match res { + Ok(success) => reqwest_retry::default_on_request_success(success), + Err(_) => None, + } + } + } + let backoff_policy = reqwest_retry::policies::ExponentialBackoff::builder() + .build_with_max_retries(config.max_retries); + + let retry_middleware = + reqwest_retry::RetryTransientMiddleware::new_with_policy_and_strategy( + backoff_policy, + RetryableStatus, + ); + + builder.with(retry_middleware) + } else { + builder + }; + builder + }; + + let client = middleware_client_builder.build(); + + Self { config, client } + } + + pub fn with_client_and_config( + config: datadog::Configuration, + client: reqwest_middleware::ClientWithMiddleware, + ) -> Self { + Self { config, client } + } + + /// Retrieves the current status of a data observability monitor run. Poll this endpoint after triggering a run to determine when evaluation is complete. + pub async fn get_data_observability_monitor_run_status( + &self, + run_id: String, + ) -> Result< + crate::datadogV2::model::GetDataObservabilityMonitorRunStatusResponse, + datadog::Error, + > { + match self + .get_data_observability_monitor_run_status_with_http_info(run_id) + .await + { + Ok(response_content) => { + if let Some(e) = response_content.entity { + Ok(e) + } else { + Err(datadog::Error::Serde(serde::de::Error::custom( + "response content was None", + ))) + } + } + Err(err) => Err(err), + } + } + + /// Retrieves the current status of a data observability monitor run. Poll this endpoint after triggering a run to determine when evaluation is complete. + pub async fn get_data_observability_monitor_run_status_with_http_info( + &self, + run_id: String, + ) -> Result< + datadog::ResponseContent< + crate::datadogV2::model::GetDataObservabilityMonitorRunStatusResponse, + >, + datadog::Error, + > { + let local_configuration = &self.config; + let operation_id = "v2.get_data_observability_monitor_run_status"; + if local_configuration.is_unstable_operation_enabled(operation_id) { + warn!("Using unstable operation {operation_id}"); + } else { + let local_error = datadog::UnstableOperationDisabledError { + msg: "Operation 'v2.get_data_observability_monitor_run_status' is not enabled" + .to_string(), + }; + return Err(datadog::Error::UnstableOperationDisabledError(local_error)); + } + + let local_client = &self.client; + + let local_uri_str = format!( + "{}/api/v2/data-observability/monitors/runs/{run_id}/status", + local_configuration.get_operation_host(operation_id), + run_id = datadog::urlencode(run_id) + ); + let mut local_req_builder = + local_client.request(reqwest::Method::GET, local_uri_str.as_str()); + + // build headers + let mut headers = HeaderMap::new(); + headers.insert("Accept", HeaderValue::from_static("application/json")); + + // build user agent + match HeaderValue::from_str(local_configuration.user_agent.as_str()) { + Ok(user_agent) => headers.insert(reqwest::header::USER_AGENT, user_agent), + Err(e) => { + log::warn!("Failed to parse user agent header: {e}, falling back to default"); + headers.insert( + reqwest::header::USER_AGENT, + HeaderValue::from_static(datadog::DEFAULT_USER_AGENT.as_str()), + ) + } + }; + + // build auth + if let Some(local_key) = local_configuration.auth_keys.get("apiKeyAuth") { + headers.insert( + "DD-API-KEY", + HeaderValue::from_str(local_key.key.as_str()) + .expect("failed to parse DD-API-KEY header"), + ); + }; + if let Some(local_key) = local_configuration.auth_keys.get("appKeyAuth") { + headers.insert( + "DD-APPLICATION-KEY", + HeaderValue::from_str(local_key.key.as_str()) + .expect("failed to parse DD-APPLICATION-KEY header"), + ); + }; + + local_req_builder = local_req_builder.headers(headers); + let local_req = local_req_builder.build()?; + log::debug!("request content: {:?}", local_req.body()); + let local_resp = local_client.execute(local_req).await?; + + let local_status = local_resp.status(); + let local_content = local_resp.text().await?; + log::debug!("response content: {}", local_content); + + if !local_status.is_client_error() && !local_status.is_server_error() { + match serde_json::from_str::< + crate::datadogV2::model::GetDataObservabilityMonitorRunStatusResponse, + >(&local_content) + { + Ok(e) => { + return Ok(datadog::ResponseContent { + status: local_status, + content: local_content, + entity: Some(e), + }) + } + Err(e) => return Err(datadog::Error::Serde(e)), + }; + } else { + let local_entity: Option = + serde_json::from_str(&local_content).ok(); + let local_error = datadog::ResponseContent { + status: local_status, + content: local_content, + entity: local_entity, + }; + Err(datadog::Error::ResponseError(local_error)) + } + } + + /// Manually triggers a run for a data observability monitor. Only monitors that are not scheduled (manually-runnable) can be triggered this way. + pub async fn run_data_observability_monitor( + &self, + monitor_id: i64, + ) -> Result< + crate::datadogV2::model::RunDataObservabilityMonitorResponse, + datadog::Error, + > { + match self + .run_data_observability_monitor_with_http_info(monitor_id) + .await + { + Ok(response_content) => { + if let Some(e) = response_content.entity { + Ok(e) + } else { + Err(datadog::Error::Serde(serde::de::Error::custom( + "response content was None", + ))) + } + } + Err(err) => Err(err), + } + } + + /// Manually triggers a run for a data observability monitor. Only monitors that are not scheduled (manually-runnable) can be triggered this way. + pub async fn run_data_observability_monitor_with_http_info( + &self, + monitor_id: i64, + ) -> Result< + datadog::ResponseContent, + datadog::Error, + > { + let local_configuration = &self.config; + let operation_id = "v2.run_data_observability_monitor"; + if local_configuration.is_unstable_operation_enabled(operation_id) { + warn!("Using unstable operation {operation_id}"); + } else { + let local_error = datadog::UnstableOperationDisabledError { + msg: "Operation 'v2.run_data_observability_monitor' is not enabled".to_string(), + }; + return Err(datadog::Error::UnstableOperationDisabledError(local_error)); + } + + let local_client = &self.client; + + let local_uri_str = format!( + "{}/api/v2/data-observability/monitors/{monitor_id}/run", + local_configuration.get_operation_host(operation_id), + monitor_id = monitor_id + ); + let mut local_req_builder = + local_client.request(reqwest::Method::POST, local_uri_str.as_str()); + + // build headers + let mut headers = HeaderMap::new(); + headers.insert("Accept", HeaderValue::from_static("application/json")); + + // build user agent + match HeaderValue::from_str(local_configuration.user_agent.as_str()) { + Ok(user_agent) => headers.insert(reqwest::header::USER_AGENT, user_agent), + Err(e) => { + log::warn!("Failed to parse user agent header: {e}, falling back to default"); + headers.insert( + reqwest::header::USER_AGENT, + HeaderValue::from_static(datadog::DEFAULT_USER_AGENT.as_str()), + ) + } + }; + + // build auth + if let Some(local_key) = local_configuration.auth_keys.get("apiKeyAuth") { + headers.insert( + "DD-API-KEY", + HeaderValue::from_str(local_key.key.as_str()) + .expect("failed to parse DD-API-KEY header"), + ); + }; + if let Some(local_key) = local_configuration.auth_keys.get("appKeyAuth") { + headers.insert( + "DD-APPLICATION-KEY", + HeaderValue::from_str(local_key.key.as_str()) + .expect("failed to parse DD-APPLICATION-KEY header"), + ); + }; + + local_req_builder = local_req_builder.headers(headers); + let local_req = local_req_builder.build()?; + log::debug!("request content: {:?}", local_req.body()); + let local_resp = local_client.execute(local_req).await?; + + let local_status = local_resp.status(); + let local_content = local_resp.text().await?; + log::debug!("response content: {}", local_content); + + if !local_status.is_client_error() && !local_status.is_server_error() { + match serde_json::from_str::( + &local_content, + ) { + Ok(e) => { + return Ok(datadog::ResponseContent { + status: local_status, + content: local_content, + entity: Some(e), + }) + } + Err(e) => return Err(datadog::Error::Serde(e)), + }; + } else { + let local_entity: Option = + serde_json::from_str(&local_content).ok(); + let local_error = datadog::ResponseContent { + status: local_status, + content: local_content, + entity: local_entity, + }; + Err(datadog::Error::ResponseError(local_error)) + } + } +} diff --git a/src/datadogV2/api/api_security_monitoring.rs b/src/datadogV2/api/api_security_monitoring.rs index 4aed79d923..4b73e2c1a9 100644 --- a/src/datadogV2/api/api_security_monitoring.rs +++ b/src/datadogV2/api/api_security_monitoring.rs @@ -2379,6 +2379,14 @@ pub enum PatchVulnerabilityNotificationRuleError { UnknownValue(serde_json::Value), } +/// RestoreSecurityMonitoringRuleError is a struct for typed errors of method [`SecurityMonitoringAPI::restore_security_monitoring_rule`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum RestoreSecurityMonitoringRuleError { + APIErrorResponse(crate::datadogV2::model::APIErrorResponse), + UnknownValue(serde_json::Value), +} + /// RunHistoricalJobError is a struct for typed errors of method [`SecurityMonitoringAPI::run_historical_job`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] @@ -18785,6 +18793,133 @@ impl SecurityMonitoringAPI { } } + /// Restores a custom detection rule to a previously saved historical version. + /// Only custom rules can be restored. Default and partner rules return 400. + /// The restore creates a new version entry; it does not overwrite history. + pub async fn restore_security_monitoring_rule( + &self, + rule_id: String, + version: i64, + ) -> Result< + crate::datadogV2::model::SecurityMonitoringRuleResponse, + datadog::Error, + > { + match self + .restore_security_monitoring_rule_with_http_info(rule_id, version) + .await + { + Ok(response_content) => { + if let Some(e) = response_content.entity { + Ok(e) + } else { + Err(datadog::Error::Serde(serde::de::Error::custom( + "response content was None", + ))) + } + } + Err(err) => Err(err), + } + } + + /// Restores a custom detection rule to a previously saved historical version. + /// Only custom rules can be restored. Default and partner rules return 400. + /// The restore creates a new version entry; it does not overwrite history. + pub async fn restore_security_monitoring_rule_with_http_info( + &self, + rule_id: String, + version: i64, + ) -> Result< + datadog::ResponseContent, + datadog::Error, + > { + let local_configuration = &self.config; + let operation_id = "v2.restore_security_monitoring_rule"; + if local_configuration.is_unstable_operation_enabled(operation_id) { + warn!("Using unstable operation {operation_id}"); + } else { + let local_error = datadog::UnstableOperationDisabledError { + msg: "Operation 'v2.restore_security_monitoring_rule' is not enabled".to_string(), + }; + return Err(datadog::Error::UnstableOperationDisabledError(local_error)); + } + + let local_client = &self.client; + + let local_uri_str = format!( + "{}/api/v2/security_monitoring/rules/{rule_id}/restore/{version}", + local_configuration.get_operation_host(operation_id), + rule_id = datadog::urlencode(rule_id), + version = version + ); + let mut local_req_builder = + local_client.request(reqwest::Method::POST, local_uri_str.as_str()); + + // build headers + let mut headers = HeaderMap::new(); + headers.insert("Accept", HeaderValue::from_static("application/json")); + + // build user agent + match HeaderValue::from_str(local_configuration.user_agent.as_str()) { + Ok(user_agent) => headers.insert(reqwest::header::USER_AGENT, user_agent), + Err(e) => { + log::warn!("Failed to parse user agent header: {e}, falling back to default"); + headers.insert( + reqwest::header::USER_AGENT, + HeaderValue::from_static(datadog::DEFAULT_USER_AGENT.as_str()), + ) + } + }; + + // build auth + if let Some(local_key) = local_configuration.auth_keys.get("apiKeyAuth") { + headers.insert( + "DD-API-KEY", + HeaderValue::from_str(local_key.key.as_str()) + .expect("failed to parse DD-API-KEY header"), + ); + }; + if let Some(local_key) = local_configuration.auth_keys.get("appKeyAuth") { + headers.insert( + "DD-APPLICATION-KEY", + HeaderValue::from_str(local_key.key.as_str()) + .expect("failed to parse DD-APPLICATION-KEY header"), + ); + }; + + local_req_builder = local_req_builder.headers(headers); + let local_req = local_req_builder.build()?; + log::debug!("request content: {:?}", local_req.body()); + let local_resp = local_client.execute(local_req).await?; + + let local_status = local_resp.status(); + let local_content = local_resp.text().await?; + log::debug!("response content: {}", local_content); + + if !local_status.is_client_error() && !local_status.is_server_error() { + match serde_json::from_str::( + &local_content, + ) { + Ok(e) => { + return Ok(datadog::ResponseContent { + status: local_status, + content: local_content, + entity: Some(e), + }) + } + Err(e) => return Err(datadog::Error::Serde(e)), + }; + } else { + let local_entity: Option = + serde_json::from_str(&local_content).ok(); + let local_error = datadog::ResponseContent { + status: local_status, + content: local_content, + entity: local_entity, + }; + Err(datadog::Error::ResponseError(local_error)) + } + } + /// Run a historical job. pub async fn run_historical_job( &self, diff --git a/src/datadogV2/api/mod.rs b/src/datadogV2/api/mod.rs index af005bf9f1..7e2d875918 100644 --- a/src/datadogV2/api/mod.rs +++ b/src/datadogV2/api/mod.rs @@ -43,6 +43,7 @@ pub mod api_dashboard_secure_embed; pub mod api_dashboard_sharing; pub mod api_dashboards; pub mod api_data_deletion; +pub mod api_data_observability; pub mod api_datasets; pub mod api_deployment_gates; pub mod api_domain_allowlist; diff --git a/src/datadogV2/mod.rs b/src/datadogV2/mod.rs index ef4f879123..0a2e8b7756 100644 --- a/src/datadogV2/mod.rs +++ b/src/datadogV2/mod.rs @@ -44,6 +44,7 @@ pub use self::api::api_dashboard_secure_embed; pub use self::api::api_dashboard_sharing; pub use self::api::api_dashboards; pub use self::api::api_data_deletion; +pub use self::api::api_data_observability; pub use self::api::api_datasets; pub use self::api::api_deployment_gates; pub use self::api::api_domain_allowlist; diff --git a/src/datadogV2/model/mod.rs b/src/datadogV2/model/mod.rs index 8012c40d7f..31f22bc459 100644 --- a/src/datadogV2/model/mod.rs +++ b/src/datadogV2/model/mod.rs @@ -3380,6 +3380,20 @@ pub mod model_pagination_meta_page_type; pub use self::model_pagination_meta_page_type::PaginationMetaPageType; pub mod model_dashboard_usage_response; pub use self::model_dashboard_usage_response::DashboardUsageResponse; +pub mod model_get_data_observability_monitor_run_status_response; +pub use self::model_get_data_observability_monitor_run_status_response::GetDataObservabilityMonitorRunStatusResponse; +pub mod model_get_data_observability_monitor_run_status_response_data; +pub use self::model_get_data_observability_monitor_run_status_response_data::GetDataObservabilityMonitorRunStatusResponseData; +pub mod model_get_data_observability_monitor_run_status_response_attributes; +pub use self::model_get_data_observability_monitor_run_status_response_attributes::GetDataObservabilityMonitorRunStatusResponseAttributes; +pub mod model_data_observability_monitor_run_status; +pub use self::model_data_observability_monitor_run_status::DataObservabilityMonitorRunStatus; +pub mod model_data_observability_monitor_run_type; +pub use self::model_data_observability_monitor_run_type::DataObservabilityMonitorRunType; +pub mod model_run_data_observability_monitor_response; +pub use self::model_run_data_observability_monitor_response::RunDataObservabilityMonitorResponse; +pub mod model_run_data_observability_monitor_response_data; +pub use self::model_run_data_observability_monitor_response_data::RunDataObservabilityMonitorResponseData; pub mod model_dataset_response_multi; pub use self::model_dataset_response_multi::DatasetResponseMulti; pub mod model_dataset_response; diff --git a/src/datadogV2/model/model_data_observability_monitor_run_status.rs b/src/datadogV2/model/model_data_observability_monitor_run_status.rs new file mode 100644 index 0000000000..fad90694fd --- /dev/null +++ b/src/datadogV2/model/model_data_observability_monitor_run_status.rs @@ -0,0 +1,60 @@ +// 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 DataObservabilityMonitorRunStatus { + PENDING, + OK, + WARN, + ALERT, + ERROR, + UnparsedObject(crate::datadog::UnparsedObject), +} + +impl ToString for DataObservabilityMonitorRunStatus { + fn to_string(&self) -> String { + match self { + Self::PENDING => String::from("pending"), + Self::OK => String::from("ok"), + Self::WARN => String::from("warn"), + Self::ALERT => String::from("alert"), + Self::ERROR => String::from("error"), + Self::UnparsedObject(v) => v.value.to_string(), + } + } +} + +impl Serialize for DataObservabilityMonitorRunStatus { + 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 DataObservabilityMonitorRunStatus { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s: String = String::deserialize(deserializer)?; + Ok(match s.as_str() { + "pending" => Self::PENDING, + "ok" => Self::OK, + "warn" => Self::WARN, + "alert" => Self::ALERT, + "error" => Self::ERROR, + _ => Self::UnparsedObject(crate::datadog::UnparsedObject { + value: serde_json::Value::String(s.into()), + }), + }) + } +} diff --git a/src/datadogV2/model/model_data_observability_monitor_run_type.rs b/src/datadogV2/model/model_data_observability_monitor_run_type.rs new file mode 100644 index 0000000000..f1e23063f0 --- /dev/null +++ b/src/datadogV2/model/model_data_observability_monitor_run_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 DataObservabilityMonitorRunType { + MONITOR_RUN, + UnparsedObject(crate::datadog::UnparsedObject), +} + +impl ToString for DataObservabilityMonitorRunType { + fn to_string(&self) -> String { + match self { + Self::MONITOR_RUN => String::from("monitor_run"), + Self::UnparsedObject(v) => v.value.to_string(), + } + } +} + +impl Serialize for DataObservabilityMonitorRunType { + 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 DataObservabilityMonitorRunType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s: String = String::deserialize(deserializer)?; + Ok(match s.as_str() { + "monitor_run" => Self::MONITOR_RUN, + _ => Self::UnparsedObject(crate::datadog::UnparsedObject { + value: serde_json::Value::String(s.into()), + }), + }) + } +} diff --git a/src/datadogV2/model/model_get_data_observability_monitor_run_status_response.rs b/src/datadogV2/model/model_get_data_observability_monitor_run_status_response.rs new file mode 100644 index 0000000000..ce0ce799c5 --- /dev/null +++ b/src/datadogV2/model/model_get_data_observability_monitor_run_status_response.rs @@ -0,0 +1,96 @@ +// 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}; + +/// The response for getting the status of a data observability monitor run. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct GetDataObservabilityMonitorRunStatusResponse { + /// The data object for a data observability monitor run status response. + #[serde(rename = "data")] + pub data: crate::datadogV2::model::GetDataObservabilityMonitorRunStatusResponseData, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl GetDataObservabilityMonitorRunStatusResponse { + pub fn new( + data: crate::datadogV2::model::GetDataObservabilityMonitorRunStatusResponseData, + ) -> GetDataObservabilityMonitorRunStatusResponse { + GetDataObservabilityMonitorRunStatusResponse { + data, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl<'de> Deserialize<'de> for GetDataObservabilityMonitorRunStatusResponse { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct GetDataObservabilityMonitorRunStatusResponseVisitor; + impl<'a> Visitor<'a> for GetDataObservabilityMonitorRunStatusResponseVisitor { + type Value = GetDataObservabilityMonitorRunStatusResponse; + + 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 data: Option< + crate::datadogV2::model::GetDataObservabilityMonitorRunStatusResponseData, + > = 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() { + "data" => { + data = 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 data = data.ok_or_else(|| M::Error::missing_field("data"))?; + + let content = GetDataObservabilityMonitorRunStatusResponse { + data, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(GetDataObservabilityMonitorRunStatusResponseVisitor) + } +} diff --git a/src/datadogV2/model/model_get_data_observability_monitor_run_status_response_attributes.rs b/src/datadogV2/model/model_get_data_observability_monitor_run_status_response_attributes.rs new file mode 100644 index 0000000000..84b67bfd3f --- /dev/null +++ b/src/datadogV2/model/model_get_data_observability_monitor_run_status_response_attributes.rs @@ -0,0 +1,121 @@ +// 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}; + +/// The attributes of a data observability monitor run status response. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct GetDataObservabilityMonitorRunStatusResponseAttributes { + /// Error message describing why the monitor run failed. Only present when status is error. + #[serde(rename = "error_message")] + pub error_message: Option, + /// The status of a data observability monitor run. + #[serde(rename = "status")] + pub status: crate::datadogV2::model::DataObservabilityMonitorRunStatus, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl GetDataObservabilityMonitorRunStatusResponseAttributes { + pub fn new( + status: crate::datadogV2::model::DataObservabilityMonitorRunStatus, + ) -> GetDataObservabilityMonitorRunStatusResponseAttributes { + GetDataObservabilityMonitorRunStatusResponseAttributes { + error_message: None, + status, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn error_message(mut self, value: String) -> Self { + self.error_message = Some(value); + self + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl<'de> Deserialize<'de> for GetDataObservabilityMonitorRunStatusResponseAttributes { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct GetDataObservabilityMonitorRunStatusResponseAttributesVisitor; + impl<'a> Visitor<'a> for GetDataObservabilityMonitorRunStatusResponseAttributesVisitor { + type Value = GetDataObservabilityMonitorRunStatusResponseAttributes; + + 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 error_message: Option = None; + let mut status: 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() { + "error_message" => { + if v.is_null() { + continue; + } + error_message = + Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "status" => { + status = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + if let Some(ref _status) = status { + match _status { + crate::datadogV2::model::DataObservabilityMonitorRunStatus::UnparsedObject(_status) => { + _unparsed = true; + }, + _ => {} + } + } + } + &_ => { + if let Ok(value) = serde_json::from_value(v.clone()) { + additional_properties.insert(k, value); + } + } + } + } + let status = status.ok_or_else(|| M::Error::missing_field("status"))?; + + let content = GetDataObservabilityMonitorRunStatusResponseAttributes { + error_message, + status, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(GetDataObservabilityMonitorRunStatusResponseAttributesVisitor) + } +} diff --git a/src/datadogV2/model/model_get_data_observability_monitor_run_status_response_data.rs b/src/datadogV2/model/model_get_data_observability_monitor_run_status_response_data.rs new file mode 100644 index 0000000000..7a6028162e --- /dev/null +++ b/src/datadogV2/model/model_get_data_observability_monitor_run_status_response_data.rs @@ -0,0 +1,127 @@ +// 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}; + +/// The data object for a data observability monitor run status response. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct GetDataObservabilityMonitorRunStatusResponseData { + /// The attributes of a data observability monitor run status response. + #[serde(rename = "attributes")] + pub attributes: crate::datadogV2::model::GetDataObservabilityMonitorRunStatusResponseAttributes, + /// The unique identifier of the monitor run. + #[serde(rename = "id")] + pub id: String, + /// The JSON:API resource type for a data observability monitor run. + #[serde(rename = "type")] + pub type_: crate::datadogV2::model::DataObservabilityMonitorRunType, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl GetDataObservabilityMonitorRunStatusResponseData { + pub fn new( + attributes: crate::datadogV2::model::GetDataObservabilityMonitorRunStatusResponseAttributes, + id: String, + type_: crate::datadogV2::model::DataObservabilityMonitorRunType, + ) -> GetDataObservabilityMonitorRunStatusResponseData { + GetDataObservabilityMonitorRunStatusResponseData { + attributes, + id, + type_, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl<'de> Deserialize<'de> for GetDataObservabilityMonitorRunStatusResponseData { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct GetDataObservabilityMonitorRunStatusResponseDataVisitor; + impl<'a> Visitor<'a> for GetDataObservabilityMonitorRunStatusResponseDataVisitor { + type Value = GetDataObservabilityMonitorRunStatusResponseData; + + 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 attributes: Option< + crate::datadogV2::model::GetDataObservabilityMonitorRunStatusResponseAttributes, + > = None; + let mut id: Option = None; + let mut type_: 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() { + "attributes" => { + attributes = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "id" => { + id = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "type" => { + type_ = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + if let Some(ref _type_) = type_ { + match _type_ { + crate::datadogV2::model::DataObservabilityMonitorRunType::UnparsedObject(_type_) => { + _unparsed = true; + }, + _ => {} + } + } + } + &_ => { + if let Ok(value) = serde_json::from_value(v.clone()) { + additional_properties.insert(k, value); + } + } + } + } + let attributes = attributes.ok_or_else(|| M::Error::missing_field("attributes"))?; + let id = id.ok_or_else(|| M::Error::missing_field("id"))?; + let type_ = type_.ok_or_else(|| M::Error::missing_field("type_"))?; + + let content = GetDataObservabilityMonitorRunStatusResponseData { + attributes, + id, + type_, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(GetDataObservabilityMonitorRunStatusResponseDataVisitor) + } +} diff --git a/src/datadogV2/model/model_run_data_observability_monitor_response.rs b/src/datadogV2/model/model_run_data_observability_monitor_response.rs new file mode 100644 index 0000000000..fd50fd5c86 --- /dev/null +++ b/src/datadogV2/model/model_run_data_observability_monitor_response.rs @@ -0,0 +1,96 @@ +// 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}; + +/// The response returned when a data observability monitor run is triggered. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct RunDataObservabilityMonitorResponse { + /// The data object returned when a data observability monitor run is triggered. + #[serde(rename = "data")] + pub data: crate::datadogV2::model::RunDataObservabilityMonitorResponseData, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl RunDataObservabilityMonitorResponse { + pub fn new( + data: crate::datadogV2::model::RunDataObservabilityMonitorResponseData, + ) -> RunDataObservabilityMonitorResponse { + RunDataObservabilityMonitorResponse { + data, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl<'de> Deserialize<'de> for RunDataObservabilityMonitorResponse { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct RunDataObservabilityMonitorResponseVisitor; + impl<'a> Visitor<'a> for RunDataObservabilityMonitorResponseVisitor { + type Value = RunDataObservabilityMonitorResponse; + + 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 data: Option< + crate::datadogV2::model::RunDataObservabilityMonitorResponseData, + > = 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() { + "data" => { + data = 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 data = data.ok_or_else(|| M::Error::missing_field("data"))?; + + let content = RunDataObservabilityMonitorResponse { + data, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(RunDataObservabilityMonitorResponseVisitor) + } +} diff --git a/src/datadogV2/model/model_run_data_observability_monitor_response_data.rs b/src/datadogV2/model/model_run_data_observability_monitor_response_data.rs new file mode 100644 index 0000000000..64a2ddccf0 --- /dev/null +++ b/src/datadogV2/model/model_run_data_observability_monitor_response_data.rs @@ -0,0 +1,114 @@ +// 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}; + +/// The data object returned when a data observability monitor run is triggered. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct RunDataObservabilityMonitorResponseData { + /// The unique identifier of the monitor run. + #[serde(rename = "id")] + pub id: String, + /// The JSON:API resource type for a data observability monitor run. + #[serde(rename = "type")] + pub type_: crate::datadogV2::model::DataObservabilityMonitorRunType, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl RunDataObservabilityMonitorResponseData { + pub fn new( + id: String, + type_: crate::datadogV2::model::DataObservabilityMonitorRunType, + ) -> RunDataObservabilityMonitorResponseData { + RunDataObservabilityMonitorResponseData { + id, + type_, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl<'de> Deserialize<'de> for RunDataObservabilityMonitorResponseData { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct RunDataObservabilityMonitorResponseDataVisitor; + impl<'a> Visitor<'a> for RunDataObservabilityMonitorResponseDataVisitor { + type Value = RunDataObservabilityMonitorResponseData; + + 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 id: Option = None; + let mut type_: 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() { + "id" => { + id = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "type" => { + type_ = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + if let Some(ref _type_) = type_ { + match _type_ { + crate::datadogV2::model::DataObservabilityMonitorRunType::UnparsedObject(_type_) => { + _unparsed = true; + }, + _ => {} + } + } + } + &_ => { + if let Ok(value) = serde_json::from_value(v.clone()) { + additional_properties.insert(k, value); + } + } + } + } + let id = id.ok_or_else(|| M::Error::missing_field("id"))?; + let type_ = type_.ok_or_else(|| M::Error::missing_field("type_"))?; + + let content = RunDataObservabilityMonitorResponseData { + id, + type_, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(RunDataObservabilityMonitorResponseDataVisitor) + } +} diff --git a/tests/scenarios/cassettes/v2/security_monitoring/Restore-a-rule-to-a-historical-version-returns-Conflict-response.frozen b/tests/scenarios/cassettes/v2/security_monitoring/Restore-a-rule-to-a-historical-version-returns-Conflict-response.frozen new file mode 100644 index 0000000000..86182034b5 --- /dev/null +++ b/tests/scenarios/cassettes/v2/security_monitoring/Restore-a-rule-to-a-historical-version-returns-Conflict-response.frozen @@ -0,0 +1 @@ +2026-06-12T09:57:22.725Z \ No newline at end of file diff --git a/tests/scenarios/cassettes/v2/security_monitoring/Restore-a-rule-to-a-historical-version-returns-Conflict-response.json b/tests/scenarios/cassettes/v2/security_monitoring/Restore-a-rule-to-a-historical-version-returns-Conflict-response.json new file mode 100644 index 0000000000..7e0b79501e --- /dev/null +++ b/tests/scenarios/cassettes/v2/security_monitoring/Restore-a-rule-to-a-historical-version-returns-Conflict-response.json @@ -0,0 +1,125 @@ +{ + "http_interactions": [ + { + "request": { + "body": { + "string": "{\"cases\":[{\"condition\":\"a > 0\",\"name\":\"\",\"notifications\":[],\"status\":\"info\"}],\"filters\":[],\"isEnabled\":true,\"message\":\"Test rule\",\"name\":\"Test-Restore_a_rule_to_a_historical_version_returns_Conflict_response-1781258242\",\"options\":{\"evaluationWindow\":900,\"keepAlive\":3600,\"maxSignalDuration\":86400},\"queries\":[{\"aggregation\":\"count\",\"distinctFields\":[],\"groupByFields\":[],\"metrics\":[],\"query\":\"@test:true\"}],\"tags\":[],\"type\":\"log_detection\"}", + "encoding": null + }, + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json" + ] + }, + "method": "post", + "uri": "https://api.datadoghq.com/api/v2/security_monitoring/rules" + }, + "response": { + "body": { + "string": "{\"name\":\"Test-Restore_a_rule_to_a_historical_version_returns_Conflict_response-1781258242\",\"createdAt\":1781258244898,\"isDefault\":false,\"isPartner\":false,\"isEnabled\":true,\"isBeta\":false,\"isDeleted\":false,\"isDeprecated\":false,\"queries\":[{\"query\":\"@test:true\",\"groupByFields\":[],\"hasOptionalGroupByFields\":false,\"distinctFields\":[],\"aggregation\":\"count\",\"name\":\"\",\"dataSource\":\"logs\"}],\"options\":{\"evaluationWindow\":900,\"detectionMethod\":\"threshold\",\"maxSignalDuration\":86400,\"keepAlive\":3600},\"cases\":[{\"name\":\"\",\"status\":\"info\",\"notifications\":[],\"condition\":\"a \\u003e 0\"}],\"message\":\"Test rule\",\"tags\":[],\"hasExtendedTitle\":false,\"type\":\"log_detection\",\"filters\":[],\"version\":1,\"id\":\"xrz-jfq-dfm\",\"blocking\":false,\"metadata\":{\"entities\":null,\"sources\":null},\"creationAuthorId\":2320499,\"creator\":{\"handle\":\"9919ec9b-ebc7-49ee-8dc8-03626e717cca\",\"name\":\"CI Account\"},\"updater\":{\"handle\":\"\",\"name\":\"\"}}", + "encoding": null + }, + "headers": { + "Content-Type": [ + "application/json" + ] + }, + "status": { + "code": 200, + "message": "OK" + } + }, + "recorded_at": "Fri, 12 Jun 2026 09:57:22 GMT" + }, + { + "request": { + "body": { + "string": "{\"cases\":[{\"condition\":\"a > 0\",\"name\":\"\",\"notifications\":[],\"status\":\"info\"}],\"filters\":[],\"isEnabled\":true,\"message\":\"Test rule updated\",\"name\":\"Test-Restore_a_rule_to_a_historical_version_returns_Conflict_response-1781258242-updated\",\"options\":{\"evaluationWindow\":900,\"keepAlive\":3600,\"maxSignalDuration\":86400},\"queries\":[{\"aggregation\":\"count\",\"distinctFields\":[],\"groupByFields\":[],\"metrics\":[],\"query\":\"@test:true\"}],\"tags\":[]}", + "encoding": null + }, + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json" + ] + }, + "method": "put", + "uri": "https://api.datadoghq.com/api/v2/security_monitoring/rules/xrz-jfq-dfm" + }, + "response": { + "body": { + "string": "{\"name\":\"Test-Restore_a_rule_to_a_historical_version_returns_Conflict_response-1781258242-updated\",\"isEnabled\":true,\"queries\":[{\"query\":\"@test:true\",\"groupByFields\":[],\"hasOptionalGroupByFields\":false,\"distinctFields\":[],\"aggregation\":\"count\",\"name\":\"\",\"dataSource\":\"logs\"}],\"options\":{\"evaluationWindow\":900,\"detectionMethod\":\"threshold\",\"maxSignalDuration\":86400,\"keepAlive\":3600},\"cases\":[{\"name\":\"\",\"status\":\"info\",\"notifications\":[],\"condition\":\"a \\u003e 0\"}],\"message\":\"Test rule updated\",\"tags\":[],\"hasExtendedTitle\":false,\"type\":\"log_detection\",\"filters\":[],\"id\":\"xrz-jfq-dfm\",\"version\":2,\"createdAt\":1781258244898,\"creationAuthorId\":2320499,\"updateAuthorId\":2320499,\"updatedAt\":1781258245104,\"isDefault\":false,\"blocking\":false,\"isBeta\":false,\"isDeleted\":false,\"isDeprecated\":false,\"metadata\":{\"entities\":null,\"sources\":null}}", + "encoding": null + }, + "headers": { + "Content-Type": [ + "application/json" + ] + }, + "status": { + "code": 200, + "message": "OK" + } + }, + "recorded_at": "Fri, 12 Jun 2026 09:57:22 GMT" + }, + { + "request": { + "body": "", + "headers": { + "Accept": [ + "application/json" + ] + }, + "method": "post", + "uri": "https://api.datadoghq.com/api/v2/security_monitoring/rules/xrz-jfq-dfm/restore/2" + }, + "response": { + "body": { + "string": "{\"error\":{\"code\":\"AlreadyExists\",\"message\":\"Cannot restore: target version is the current version.\"}}", + "encoding": null + }, + "headers": { + "Content-Type": [ + "application/json" + ] + }, + "status": { + "code": 409, + "message": "Conflict" + } + }, + "recorded_at": "Fri, 12 Jun 2026 09:57:22 GMT" + }, + { + "request": { + "body": "", + "headers": { + "Accept": [ + "*/*" + ] + }, + "method": "delete", + "uri": "https://api.datadoghq.com/api/v2/security_monitoring/rules/xrz-jfq-dfm" + }, + "response": { + "body": { + "string": "", + "encoding": null + }, + "headers": {}, + "status": { + "code": 204, + "message": "No Content" + } + }, + "recorded_at": "Fri, 12 Jun 2026 09:57:22 GMT" + } + ], + "recorded_with": "VCR 6.0.0" +} \ No newline at end of file diff --git a/tests/scenarios/cassettes/v2/security_monitoring/Restore-a-rule-to-a-historical-version-returns-Not-Found-response.frozen b/tests/scenarios/cassettes/v2/security_monitoring/Restore-a-rule-to-a-historical-version-returns-Not-Found-response.frozen new file mode 100644 index 0000000000..d762af22af --- /dev/null +++ b/tests/scenarios/cassettes/v2/security_monitoring/Restore-a-rule-to-a-historical-version-returns-Not-Found-response.frozen @@ -0,0 +1 @@ +2026-06-12T08:39:41.348Z \ No newline at end of file diff --git a/tests/scenarios/cassettes/v2/security_monitoring/Restore-a-rule-to-a-historical-version-returns-Not-Found-response.json b/tests/scenarios/cassettes/v2/security_monitoring/Restore-a-rule-to-a-historical-version-returns-Not-Found-response.json new file mode 100644 index 0000000000..b7dea5d4bf --- /dev/null +++ b/tests/scenarios/cassettes/v2/security_monitoring/Restore-a-rule-to-a-historical-version-returns-Not-Found-response.json @@ -0,0 +1,91 @@ +{ + "http_interactions": [ + { + "request": { + "body": { + "string": "{\"cases\":[{\"condition\":\"a > 0\",\"name\":\"\",\"notifications\":[],\"status\":\"info\"}],\"filters\":[],\"isEnabled\":true,\"message\":\"Test rule\",\"name\":\"Test-Restore_a_rule_to_a_historical_version_returns_Not_Found_response-1781253581\",\"options\":{\"evaluationWindow\":900,\"keepAlive\":3600,\"maxSignalDuration\":86400},\"queries\":[{\"aggregation\":\"count\",\"distinctFields\":[],\"groupByFields\":[],\"metrics\":[],\"query\":\"@test:true\"}],\"tags\":[],\"type\":\"log_detection\"}", + "encoding": null + }, + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json" + ] + }, + "method": "post", + "uri": "https://api.datadoghq.com/api/v2/security_monitoring/rules" + }, + "response": { + "body": { + "string": "{\"name\":\"Test-Restore_a_rule_to_a_historical_version_returns_Not_Found_response-1781253581\",\"createdAt\":1781253581645,\"isDefault\":false,\"isPartner\":false,\"isEnabled\":true,\"isBeta\":false,\"isDeleted\":false,\"isDeprecated\":false,\"queries\":[{\"query\":\"@test:true\",\"groupByFields\":[],\"hasOptionalGroupByFields\":false,\"distinctFields\":[],\"aggregation\":\"count\",\"name\":\"\",\"dataSource\":\"logs\"}],\"options\":{\"evaluationWindow\":900,\"detectionMethod\":\"threshold\",\"maxSignalDuration\":86400,\"keepAlive\":3600},\"cases\":[{\"name\":\"\",\"status\":\"info\",\"notifications\":[],\"condition\":\"a \\u003e 0\"}],\"message\":\"Test rule\",\"tags\":[],\"hasExtendedTitle\":false,\"type\":\"log_detection\",\"filters\":[],\"version\":1,\"id\":\"uig-ynq-xlh\",\"blocking\":false,\"metadata\":{\"entities\":null,\"sources\":null},\"creationAuthorId\":2320499,\"creator\":{\"handle\":\"9919ec9b-ebc7-49ee-8dc8-03626e717cca\",\"name\":\"CI Account\"},\"updater\":{\"handle\":\"\",\"name\":\"\"}}", + "encoding": null + }, + "headers": { + "Content-Type": [ + "application/json" + ] + }, + "status": { + "code": 200, + "message": "OK" + } + }, + "recorded_at": "Fri, 12 Jun 2026 08:39:41 GMT" + }, + { + "request": { + "body": "", + "headers": { + "Accept": [ + "application/json" + ] + }, + "method": "post", + "uri": "https://api.datadoghq.com/api/v2/security_monitoring/rules/uig-ynq-xlh/restore/9999" + }, + "response": { + "body": { + "string": "{\"error\":{\"code\":\"NotFound\",\"message\":\"Threat detection rule not found: uig-ynq-xlh, version=9999\"}}", + "encoding": null + }, + "headers": { + "Content-Type": [ + "application/json" + ] + }, + "status": { + "code": 404, + "message": "Not Found" + } + }, + "recorded_at": "Fri, 12 Jun 2026 08:39:41 GMT" + }, + { + "request": { + "body": "", + "headers": { + "Accept": [ + "*/*" + ] + }, + "method": "delete", + "uri": "https://api.datadoghq.com/api/v2/security_monitoring/rules/uig-ynq-xlh" + }, + "response": { + "body": { + "string": "", + "encoding": null + }, + "headers": {}, + "status": { + "code": 204, + "message": "No Content" + } + }, + "recorded_at": "Fri, 12 Jun 2026 08:39:41 GMT" + } + ], + "recorded_with": "VCR 6.0.0" +} \ No newline at end of file diff --git a/tests/scenarios/cassettes/v2/security_monitoring/Restore-a-rule-to-a-historical-version-returns-OK-response.frozen b/tests/scenarios/cassettes/v2/security_monitoring/Restore-a-rule-to-a-historical-version-returns-OK-response.frozen new file mode 100644 index 0000000000..47bbb311c9 --- /dev/null +++ b/tests/scenarios/cassettes/v2/security_monitoring/Restore-a-rule-to-a-historical-version-returns-OK-response.frozen @@ -0,0 +1 @@ +2026-06-12T09:57:25.549Z \ No newline at end of file diff --git a/tests/scenarios/cassettes/v2/security_monitoring/Restore-a-rule-to-a-historical-version-returns-OK-response.json b/tests/scenarios/cassettes/v2/security_monitoring/Restore-a-rule-to-a-historical-version-returns-OK-response.json new file mode 100644 index 0000000000..74702abde3 --- /dev/null +++ b/tests/scenarios/cassettes/v2/security_monitoring/Restore-a-rule-to-a-historical-version-returns-OK-response.json @@ -0,0 +1,125 @@ +{ + "http_interactions": [ + { + "request": { + "body": { + "string": "{\"cases\":[{\"condition\":\"a > 0\",\"name\":\"\",\"notifications\":[],\"status\":\"info\"}],\"filters\":[],\"isEnabled\":true,\"message\":\"Test rule\",\"name\":\"Test-Restore_a_rule_to_a_historical_version_returns_OK_response-1781258245\",\"options\":{\"evaluationWindow\":900,\"keepAlive\":3600,\"maxSignalDuration\":86400},\"queries\":[{\"aggregation\":\"count\",\"distinctFields\":[],\"groupByFields\":[],\"metrics\":[],\"query\":\"@test:true\"}],\"tags\":[],\"type\":\"log_detection\"}", + "encoding": null + }, + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json" + ] + }, + "method": "post", + "uri": "https://api.datadoghq.com/api/v2/security_monitoring/rules" + }, + "response": { + "body": { + "string": "{\"name\":\"Test-Restore_a_rule_to_a_historical_version_returns_OK_response-1781258245\",\"createdAt\":1781258245670,\"isDefault\":false,\"isPartner\":false,\"isEnabled\":true,\"isBeta\":false,\"isDeleted\":false,\"isDeprecated\":false,\"queries\":[{\"query\":\"@test:true\",\"groupByFields\":[],\"hasOptionalGroupByFields\":false,\"distinctFields\":[],\"aggregation\":\"count\",\"name\":\"\",\"dataSource\":\"logs\"}],\"options\":{\"evaluationWindow\":900,\"detectionMethod\":\"threshold\",\"maxSignalDuration\":86400,\"keepAlive\":3600},\"cases\":[{\"name\":\"\",\"status\":\"info\",\"notifications\":[],\"condition\":\"a \\u003e 0\"}],\"message\":\"Test rule\",\"tags\":[],\"hasExtendedTitle\":false,\"type\":\"log_detection\",\"filters\":[],\"version\":1,\"id\":\"7sm-pyl-xzv\",\"blocking\":false,\"metadata\":{\"entities\":null,\"sources\":null},\"creationAuthorId\":2320499,\"creator\":{\"handle\":\"9919ec9b-ebc7-49ee-8dc8-03626e717cca\",\"name\":\"CI Account\"},\"updater\":{\"handle\":\"\",\"name\":\"\"}}", + "encoding": null + }, + "headers": { + "Content-Type": [ + "application/json" + ] + }, + "status": { + "code": 200, + "message": "OK" + } + }, + "recorded_at": "Fri, 12 Jun 2026 09:57:25 GMT" + }, + { + "request": { + "body": { + "string": "{\"cases\":[{\"condition\":\"a > 0\",\"name\":\"\",\"notifications\":[],\"status\":\"info\"}],\"filters\":[],\"isEnabled\":true,\"message\":\"Test rule updated\",\"name\":\"Test-Restore_a_rule_to_a_historical_version_returns_OK_response-1781258245-updated\",\"options\":{\"evaluationWindow\":900,\"keepAlive\":3600,\"maxSignalDuration\":86400},\"queries\":[{\"aggregation\":\"count\",\"distinctFields\":[],\"groupByFields\":[],\"metrics\":[],\"query\":\"@test:true\"}],\"tags\":[]}", + "encoding": null + }, + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json" + ] + }, + "method": "put", + "uri": "https://api.datadoghq.com/api/v2/security_monitoring/rules/7sm-pyl-xzv" + }, + "response": { + "body": { + "string": "{\"name\":\"Test-Restore_a_rule_to_a_historical_version_returns_OK_response-1781258245-updated\",\"isEnabled\":true,\"queries\":[{\"query\":\"@test:true\",\"groupByFields\":[],\"hasOptionalGroupByFields\":false,\"distinctFields\":[],\"aggregation\":\"count\",\"name\":\"\",\"dataSource\":\"logs\"}],\"options\":{\"evaluationWindow\":900,\"detectionMethod\":\"threshold\",\"maxSignalDuration\":86400,\"keepAlive\":3600},\"cases\":[{\"name\":\"\",\"status\":\"info\",\"notifications\":[],\"condition\":\"a \\u003e 0\"}],\"message\":\"Test rule updated\",\"tags\":[],\"hasExtendedTitle\":false,\"type\":\"log_detection\",\"filters\":[],\"id\":\"7sm-pyl-xzv\",\"version\":2,\"createdAt\":1781258245670,\"creationAuthorId\":2320499,\"updateAuthorId\":2320499,\"updatedAt\":1781258245844,\"isDefault\":false,\"blocking\":false,\"isBeta\":false,\"isDeleted\":false,\"isDeprecated\":false,\"metadata\":{\"entities\":null,\"sources\":null}}", + "encoding": null + }, + "headers": { + "Content-Type": [ + "application/json" + ] + }, + "status": { + "code": 200, + "message": "OK" + } + }, + "recorded_at": "Fri, 12 Jun 2026 09:57:25 GMT" + }, + { + "request": { + "body": "", + "headers": { + "Accept": [ + "application/json" + ] + }, + "method": "post", + "uri": "https://api.datadoghq.com/api/v2/security_monitoring/rules/7sm-pyl-xzv/restore/1" + }, + "response": { + "body": { + "string": "{\"name\":\"Test-Restore_a_rule_to_a_historical_version_returns_OK_response-1781258245\",\"createdAt\":1781258245670,\"isDefault\":false,\"isPartner\":false,\"isEnabled\":true,\"isBeta\":false,\"isDeleted\":false,\"isDeprecated\":false,\"queries\":[{\"query\":\"@test:true\",\"groupByFields\":[],\"hasOptionalGroupByFields\":false,\"distinctFields\":[],\"aggregation\":\"count\",\"name\":\"\",\"dataSource\":\"logs\"}],\"options\":{\"evaluationWindow\":900,\"detectionMethod\":\"threshold\",\"maxSignalDuration\":86400,\"keepAlive\":3600},\"cases\":[{\"name\":\"\",\"status\":\"info\",\"notifications\":[],\"condition\":\"a \\u003e 0\"}],\"message\":\"Test rule\",\"tags\":[],\"hasExtendedTitle\":false,\"type\":\"log_detection\",\"filters\":[],\"version\":3,\"id\":\"7sm-pyl-xzv\",\"updatedAt\":1781258246099,\"blocking\":false,\"metadata\":{\"entities\":null,\"sources\":null},\"creationAuthorId\":2320499,\"updateAuthorId\":2320499,\"creator\":{\"handle\":\"9919ec9b-ebc7-49ee-8dc8-03626e717cca\",\"name\":\"CI Account\"},\"updater\":{\"handle\":\"9919ec9b-ebc7-49ee-8dc8-03626e717cca\",\"name\":\"CI Account\"}}", + "encoding": null + }, + "headers": { + "Content-Type": [ + "application/json" + ] + }, + "status": { + "code": 200, + "message": "OK" + } + }, + "recorded_at": "Fri, 12 Jun 2026 09:57:25 GMT" + }, + { + "request": { + "body": "", + "headers": { + "Accept": [ + "*/*" + ] + }, + "method": "delete", + "uri": "https://api.datadoghq.com/api/v2/security_monitoring/rules/7sm-pyl-xzv" + }, + "response": { + "body": { + "string": "", + "encoding": null + }, + "headers": {}, + "status": { + "code": 204, + "message": "No Content" + } + }, + "recorded_at": "Fri, 12 Jun 2026 09:57:25 GMT" + } + ], + "recorded_with": "VCR 6.0.0" +} \ No newline at end of file diff --git a/tests/scenarios/features/v2/given.json b/tests/scenarios/features/v2/given.json index fb03c29c05..f5ce3365da 100644 --- a/tests/scenarios/features/v2/given.json +++ b/tests/scenarios/features/v2/given.json @@ -1422,6 +1422,22 @@ "tag": "Security Monitoring", "operationId": "CreateSecurityMonitoringRule" }, + { + "parameters": [ + { + "name": "rule_id", + "source": "security_rule.id" + }, + { + "name": "body", + "value": "{\n \"name\": \"{{ unique }}-updated\",\n \"queries\": [{\n \"query\": \"@test:true\",\n \"aggregation\": \"count\",\n \"groupByFields\": [],\n \"distinctFields\": [],\n \"metrics\": []\n }],\n \"filters\": [],\n \"cases\": [{\n \"name\": \"\",\n \"status\": \"info\",\n \"condition\": \"a > 0\",\n \"notifications\": []\n }],\n \"options\": {\n \"evaluationWindow\": 900,\n \"keepAlive\": 3600,\n \"maxSignalDuration\": 86400\n },\n \"message\": \"Test rule updated\",\n \"tags\": [],\n \"isEnabled\": true\n}" + } + ], + "step": "there is a valid \"security_rule_updated\" in the system", + "key": "security_rule_updated", + "tag": "Security Monitoring", + "operationId": "UpdateSecurityMonitoringRule" + }, { "step": "a valid \"configuration\" in the system", "key": "configuration", diff --git a/tests/scenarios/features/v2/security_monitoring.feature b/tests/scenarios/features/v2/security_monitoring.feature index eb583c92cd..d6ec475edf 100644 --- a/tests/scenarios/features/v2/security_monitoring.feature +++ b/tests/scenarios/features/v2/security_monitoring.feature @@ -2532,6 +2532,48 @@ Feature: Security Monitoring When the request is sent Then the response status is 422 The server cannot process the request because it contains invalid data. + @generated @skip @team:DataDog/k9-cloud-siem + Scenario: Restore a rule to a historical version returns "Bad Request" response + Given operation "RestoreSecurityMonitoringRule" enabled + And new "RestoreSecurityMonitoringRule" request + And request contains "rule_id" parameter from "REPLACE.ME" + And request contains "version" parameter from "REPLACE.ME" + When the request is sent + Then the response status is 400 Bad Request + + @team:DataDog/k9-cloud-siem + Scenario: Restore a rule to a historical version returns "Conflict" response + Given operation "RestoreSecurityMonitoringRule" enabled + And there is a valid "security_rule" in the system + And there is a valid "security_rule_updated" in the system + And new "RestoreSecurityMonitoringRule" request + And request contains "rule_id" parameter from "security_rule.id" + And request contains "version" parameter with value 2 + When the request is sent + Then the response status is 409 Conflict + + @team:DataDog/k9-cloud-siem + Scenario: Restore a rule to a historical version returns "Not Found" response + Given operation "RestoreSecurityMonitoringRule" enabled + And there is a valid "security_rule" in the system + And new "RestoreSecurityMonitoringRule" request + And request contains "rule_id" parameter from "security_rule.id" + And request contains "version" parameter with value 9999 + When the request is sent + Then the response status is 404 Not Found + + @skip-validation @team:DataDog/k9-cloud-siem + Scenario: Restore a rule to a historical version returns "OK" response + Given operation "RestoreSecurityMonitoringRule" enabled + And there is a valid "security_rule" in the system + And there is a valid "security_rule_updated" in the system + And new "RestoreSecurityMonitoringRule" request + And request contains "rule_id" parameter from "security_rule.id" + And request contains "version" parameter with value 1 + When the request is sent + Then the response status is 200 OK + And the response "id" has the same value as "security_rule.id" + @generated @skip @team:DataDog/k9-vm-ast Scenario: Returns a list of Secrets rules returns "OK" response Given operation "GetSecretsRules" enabled diff --git a/tests/scenarios/features/v2/undo.json b/tests/scenarios/features/v2/undo.json index 54f20db646..1f2560a782 100644 --- a/tests/scenarios/features/v2/undo.json +++ b/tests/scenarios/features/v2/undo.json @@ -7457,6 +7457,12 @@ "type": "idempotent" } }, + "RestoreSecurityMonitoringRule": { + "tag": "Security Monitoring", + "undo": { + "type": "idempotent" + } + }, "TestExistingSecurityMonitoringRule": { "tag": "Security Monitoring", "undo": { diff --git a/tests/scenarios/function_mappings.rs b/tests/scenarios/function_mappings.rs index def162d613..c28b34cff1 100644 --- a/tests/scenarios/function_mappings.rs +++ b/tests/scenarios/function_mappings.rs @@ -100,6 +100,7 @@ pub struct ApiInstances { pub v2_api_dashboard_secure_embed: Option, pub v2_api_dashboards: Option, + pub v2_api_data_observability: Option, pub v2_api_datasets: Option, pub v2_api_data_deletion: Option, pub v2_api_deployment_gates: Option, @@ -832,6 +833,14 @@ pub fn initialize_api_instance(world: &mut DatadogWorld, api: String) { world.http_client.as_ref().unwrap().clone() )); } + "DataObservability" => { + world.api_instances.v2_api_data_observability = Some( + datadogV2::api_data_observability::DataObservabilityAPI::with_client_and_config( + world.config.clone(), + world.http_client.as_ref().unwrap().clone(), + ), + ); + } "Datasets" => { world.api_instances.v2_api_datasets = Some( datadogV2::api_datasets::DatasetsAPI::with_client_and_config( @@ -3714,6 +3723,10 @@ pub fn collect_function_calls(world: &mut DatadogWorld) { "v2.ConvertExistingSecurityMonitoringRule".into(), test_v2_convert_existing_security_monitoring_rule, ); + world.function_mappings.insert( + "v2.RestoreSecurityMonitoringRule".into(), + test_v2_restore_security_monitoring_rule, + ); world.function_mappings.insert( "v2.TestExistingSecurityMonitoringRule".into(), test_v2_test_existing_security_monitoring_rule, @@ -4328,6 +4341,14 @@ pub fn collect_function_calls(world: &mut DatadogWorld) { world .function_mappings .insert("v2.GetDashboardUsage".into(), test_v2_get_dashboard_usage); + world.function_mappings.insert( + "v2.GetDataObservabilityMonitorRunStatus".into(), + test_v2_get_data_observability_monitor_run_status, + ); + world.function_mappings.insert( + "v2.RunDataObservabilityMonitor".into(), + test_v2_run_data_observability_monitor, + ); world .function_mappings .insert("v2.GetAllDatasets".into(), test_v2_get_all_datasets); @@ -27565,6 +27586,36 @@ fn test_v2_convert_existing_security_monitoring_rule( world.response.code = response.status.as_u16(); } +fn test_v2_restore_security_monitoring_rule( + world: &mut DatadogWorld, + _parameters: &HashMap, +) { + let api = world + .api_instances + .v2_api_security_monitoring + .as_ref() + .expect("api instance not found"); + let rule_id = serde_json::from_value(_parameters.get("rule_id").unwrap().clone()).unwrap(); + let version = serde_json::from_value(_parameters.get("version").unwrap().clone()).unwrap(); + let response = + match block_on(api.restore_security_monitoring_rule_with_http_info(rule_id, version)) { + Ok(response) => response, + Err(error) => { + return match error { + Error::ResponseError(e) => { + world.response.code = e.status.as_u16(); + if let Some(entity) = e.entity { + world.response.object = serde_json::to_value(entity).unwrap(); + } + } + _ => panic!("error parsing response: {error}"), + }; + } + }; + world.response.object = serde_json::to_value(response.entity).unwrap(); + world.response.code = response.status.as_u16(); +} + fn test_v2_test_existing_security_monitoring_rule( world: &mut DatadogWorld, _parameters: &HashMap, @@ -32947,6 +32998,64 @@ fn test_v2_get_dashboard_usage(world: &mut DatadogWorld, _parameters: &HashMap, +) { + let api = world + .api_instances + .v2_api_data_observability + .as_ref() + .expect("api instance not found"); + let run_id = serde_json::from_value(_parameters.get("run_id").unwrap().clone()).unwrap(); + let response = + match block_on(api.get_data_observability_monitor_run_status_with_http_info(run_id)) { + Ok(response) => response, + Err(error) => { + return match error { + Error::ResponseError(e) => { + world.response.code = e.status.as_u16(); + if let Some(entity) = e.entity { + world.response.object = serde_json::to_value(entity).unwrap(); + } + } + _ => panic!("error parsing response: {error}"), + }; + } + }; + world.response.object = serde_json::to_value(response.entity).unwrap(); + world.response.code = response.status.as_u16(); +} + +fn test_v2_run_data_observability_monitor( + world: &mut DatadogWorld, + _parameters: &HashMap, +) { + let api = world + .api_instances + .v2_api_data_observability + .as_ref() + .expect("api instance not found"); + let monitor_id = + serde_json::from_value(_parameters.get("monitor_id").unwrap().clone()).unwrap(); + let response = match block_on(api.run_data_observability_monitor_with_http_info(monitor_id)) { + Ok(response) => response, + Err(error) => { + return match error { + Error::ResponseError(e) => { + world.response.code = e.status.as_u16(); + if let Some(entity) = e.entity { + world.response.object = serde_json::to_value(entity).unwrap(); + } + } + _ => panic!("error parsing response: {error}"), + }; + } + }; + world.response.object = serde_json::to_value(response.entity).unwrap(); + world.response.code = response.status.as_u16(); +} + fn test_v2_get_all_datasets(world: &mut DatadogWorld, _parameters: &HashMap) { let api = world .api_instances