diff --git a/.generator/schemas/v2/openapi.yaml b/.generator/schemas/v2/openapi.yaml index 42b12a3fb..4ed0b3520 100644 --- a/.generator/schemas/v2/openapi.yaml +++ b/.generator/schemas/v2/openapi.yaml @@ -467,6 +467,23 @@ components: required: true schema: type: string + IncidentImpactIDPathParameter: + description: The UUID of the incident impact. + in: path + name: impact_id + required: true + schema: + type: string + IncidentImpactIncludeQueryParameter: + description: Specifies which related resources should be included in the response. + explode: false + in: query + name: include + required: false + schema: + items: + $ref: '#/components/schemas/IncidentImpactRelatedObject' + type: array IncidentIncludeQueryParameter: description: Specifies which types of related objects should be included in the response. @@ -20120,6 +20137,177 @@ components: - TEXTARRAY - METRICTAG - AUTOCOMPLETE + IncidentImpactAttributes: + description: The incident impact's attributes. + properties: + created: + description: Timestamp when the impact was created. + example: '2025-08-29T13:17:00Z' + format: date-time + readOnly: true + type: string + description: + description: Description of the impact. + example: Service was unavailable for external users + type: string + end_at: + description: Timestamp when the impact ended. + example: '2025-08-29T13:17:00Z' + format: date-time + nullable: true + type: string + fields: + $ref: '#/components/schemas/IncidentImpactFieldsObject' + impact_type: + description: The type of impact. + example: customer + type: string + modified: + description: Timestamp when the impact was last modified. + example: '2025-08-29T13:17:00Z' + format: date-time + readOnly: true + type: string + start_at: + description: Timestamp representing when the impact started. + example: '2025-08-28T13:17:00Z' + format: date-time + type: string + required: + - description + - start_at + type: object + IncidentImpactCreateAttributes: + description: The incident impact's attributes for a create request. + properties: + description: + description: Description of the impact. + example: Service was unavailable for external users + type: string + end_at: + description: Timestamp when the impact ended. + example: '2025-08-29T13:17:00Z' + format: date-time + nullable: true + type: string + fields: + $ref: '#/components/schemas/IncidentImpactFieldsObject' + start_at: + description: Timestamp when the impact started. + example: '2025-08-28T13:17:00Z' + format: date-time + type: string + required: + - description + - start_at + type: object + IncidentImpactCreateData: + description: Incident impact data for a create request. + properties: + attributes: + $ref: '#/components/schemas/IncidentImpactCreateAttributes' + type: + $ref: '#/components/schemas/IncidentImpactType' + required: + - type + - attributes + type: object + IncidentImpactCreateRequest: + description: Create request for an incident impact. + properties: + data: + $ref: '#/components/schemas/IncidentImpactCreateData' + required: + - data + type: object + IncidentImpactFieldsObject: + additionalProperties: {} + description: An object mapping impact field names to field values. + example: + customers_impacted: all + products_impacted: + - shopping + - marketing + nullable: true + type: object + IncidentImpactRelatedObject: + description: A reference to a resource related to an incident impact. + enum: + - incident + - created_by_user + - last_modified_by_user + type: string + x-enum-varnames: + - INCIDENT + - CREATED_BY_USER + - LAST_MODIFIED_BY_USER + IncidentImpactRelationships: + description: The incident impact's resource relationships. + properties: + created_by_user: + $ref: '#/components/schemas/RelationshipToUser' + incident: + $ref: '#/components/schemas/RelationshipToIncident' + last_modified_by_user: + $ref: '#/components/schemas/RelationshipToUser' + type: object + IncidentImpactResponse: + description: Response with an incident impact. + properties: + data: + $ref: '#/components/schemas/IncidentImpactResponseData' + included: + description: Included related resources that the user requested. + items: + $ref: '#/components/schemas/IncidentUserData' + readOnly: true + type: array + required: + - data + type: object + IncidentImpactResponseData: + description: Incident impact data from a response. + properties: + attributes: + $ref: '#/components/schemas/IncidentImpactAttributes' + id: + description: The incident impact's ID. + example: 00000000-0000-0000-1234-000000000000 + type: string + relationships: + $ref: '#/components/schemas/IncidentImpactRelationships' + type: + $ref: '#/components/schemas/IncidentImpactType' + required: + - id + - type + type: object + IncidentImpactType: + default: incident_impacts + description: Incident impact resource type. + enum: + - incident_impacts + example: incident_impacts + type: string + x-enum-varnames: + - INCIDENT_IMPACTS + IncidentImpactsResponse: + description: Response with a list of incident impacts. + properties: + data: + description: An array of incident impacts. + items: + $ref: '#/components/schemas/IncidentImpactResponseData' + type: array + included: + description: Included related resources that the user requested. + items: + $ref: '#/components/schemas/IncidentUserData' + readOnly: true + type: array + required: + - data + type: object IncidentImpactsType: description: The incident impacts type. enum: @@ -20897,6 +21085,7 @@ components: - data type: object IncidentResponseAttributes: + additionalProperties: {} description: The incident's attributes from a response. properties: archived: @@ -20941,6 +21130,17 @@ components: description: A flag indicating whether the incident caused customer impact. example: false type: boolean + declared: + description: Timestamp when the incident was declared. + format: date-time + readOnly: true + type: string + declared_by: + $ref: '#/components/schemas/IncidentNonDatadogCreator' + declared_by_uuid: + description: UUID of the user who declared the incident. + nullable: true + type: string detected: description: Timestamp when the incident was detected. format: date-time @@ -21096,6 +21296,8 @@ components: $ref: '#/components/schemas/NullableRelationshipToUser' created_by_user: $ref: '#/components/schemas/RelationshipToUser' + declared_by_user: + $ref: '#/components/schemas/RelationshipToUser' impacts: $ref: '#/components/schemas/RelationshipToIncidentImpacts' integrations: @@ -35408,6 +35610,14 @@ components: description: Relationship type. type: string type: object + RelationshipToIncident: + description: Relationship to incident. + properties: + data: + $ref: '#/components/schemas/RelationshipToIncidentData' + required: + - data + type: object RelationshipToIncidentAttachment: description: A relationship reference for attachments. properties: @@ -35432,6 +35642,19 @@ components: - id - type type: object + RelationshipToIncidentData: + description: Relationship to incident object. + properties: + id: + description: A unique identifier that represents the incident. + example: 00000000-0000-0000-1234-000000000000 + type: string + type: + $ref: '#/components/schemas/IncidentType' + required: + - id + - type + type: object RelationshipToIncidentImpactData: description: Relationship to impact object. properties: @@ -56351,6 +56574,124 @@ paths: - incident_write x-unstable: '**Note**: This endpoint is in public beta. + If you have any feedback, contact [Datadog support](https://docs.datadoghq.com/help/).' + /api/v2/incidents/{incident_id}/impacts: + get: + description: Get all impacts for an incident. + operationId: ListIncidentImpacts + parameters: + - $ref: '#/components/parameters/IncidentIDPathParameter' + - $ref: '#/components/parameters/IncidentImpactIncludeQueryParameter' + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/IncidentImpactsResponse' + description: OK + '400': + $ref: '#/components/responses/BadRequestResponse' + '401': + $ref: '#/components/responses/UnauthorizedResponse' + '403': + $ref: '#/components/responses/ForbiddenResponse' + '404': + $ref: '#/components/responses/NotFoundResponse' + '429': + $ref: '#/components/responses/TooManyRequestsResponse' + security: + - apiKeyAuth: [] + appKeyAuth: [] + - AuthZ: + - incident_read + summary: List an incident's impacts + tags: + - Incidents + x-permission: + operator: OR + permissions: + - incident_read + x-unstable: '**Note**: This endpoint is in Preview. + + If you have any feedback, contact [Datadog support](https://docs.datadoghq.com/help/).' + post: + description: Create an impact for an incident. + operationId: CreateIncidentImpact + parameters: + - $ref: '#/components/parameters/IncidentIDPathParameter' + - $ref: '#/components/parameters/IncidentImpactIncludeQueryParameter' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/IncidentImpactCreateRequest' + description: Incident impact payload. + required: true + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/IncidentImpactResponse' + description: CREATED + '400': + $ref: '#/components/responses/BadRequestResponse' + '401': + $ref: '#/components/responses/UnauthorizedResponse' + '403': + $ref: '#/components/responses/ForbiddenResponse' + '404': + $ref: '#/components/responses/NotFoundResponse' + '429': + $ref: '#/components/responses/TooManyRequestsResponse' + security: + - apiKeyAuth: [] + appKeyAuth: [] + - AuthZ: + - incident_write + summary: Create an incident impact + tags: + - Incidents + x-codegen-request-body-name: body + x-permission: + operator: OR + permissions: + - incident_write + x-unstable: '**Note**: This endpoint is in Preview. + + If you have any feedback, contact [Datadog support](https://docs.datadoghq.com/help/).' + /api/v2/incidents/{incident_id}/impacts/{impact_id}: + delete: + description: Delete an incident impact. + operationId: DeleteIncidentImpact + parameters: + - $ref: '#/components/parameters/IncidentIDPathParameter' + - $ref: '#/components/parameters/IncidentImpactIDPathParameter' + responses: + '204': + description: No Content + '401': + $ref: '#/components/responses/UnauthorizedResponse' + '403': + $ref: '#/components/responses/ForbiddenResponse' + '404': + $ref: '#/components/responses/NotFoundResponse' + '429': + $ref: '#/components/responses/TooManyRequestsResponse' + security: + - apiKeyAuth: [] + appKeyAuth: [] + - AuthZ: + - incident_write + summary: Delete an incident impact + tags: + - Incidents + x-permission: + operator: OR + permissions: + - incident_write + x-unstable: '**Note**: This endpoint is in Preview. + If you have any feedback, contact [Datadog support](https://docs.datadoghq.com/help/).' /api/v2/incidents/{incident_id}/relationships/integrations: get: diff --git a/examples/v2_incidents_CreateIncidentImpact.rs b/examples/v2_incidents_CreateIncidentImpact.rs new file mode 100644 index 000000000..760e727d8 --- /dev/null +++ b/examples/v2_incidents_CreateIncidentImpact.rs @@ -0,0 +1,44 @@ +// Create an incident impact returns "CREATED" response +use chrono::{DateTime, Utc}; +use datadog_api_client::datadog; +use datadog_api_client::datadogV2::api_incidents::CreateIncidentImpactOptionalParams; +use datadog_api_client::datadogV2::api_incidents::IncidentsAPI; +use datadog_api_client::datadogV2::model::IncidentImpactCreateAttributes; +use datadog_api_client::datadogV2::model::IncidentImpactCreateData; +use datadog_api_client::datadogV2::model::IncidentImpactCreateRequest; +use datadog_api_client::datadogV2::model::IncidentImpactType; + +#[tokio::main] +async fn main() { + // there is a valid "incident" in the system + let incident_data_id = std::env::var("INCIDENT_DATA_ID").unwrap(); + let body = IncidentImpactCreateRequest::new(IncidentImpactCreateData::new( + IncidentImpactCreateAttributes::new( + "Outage in the us-east-1 region".to_string(), + DateTime::parse_from_rfc3339("2025-09-12T13:50:00+00:00") + .expect("Failed to parse datetime") + .with_timezone(&Utc), + ) + .end_at(Some( + DateTime::parse_from_rfc3339("2025-09-12T14:50:00+00:00") + .expect("Failed to parse datetime") + .with_timezone(&Utc), + )), + IncidentImpactType::INCIDENT_IMPACTS, + )); + let mut configuration = datadog::Configuration::new(); + configuration.set_unstable_operation_enabled("v2.CreateIncidentImpact", true); + let api = IncidentsAPI::with_config(configuration); + let resp = api + .create_incident_impact( + incident_data_id.clone(), + body, + CreateIncidentImpactOptionalParams::default(), + ) + .await; + if let Ok(value) = resp { + println!("{:#?}", value); + } else { + println!("{:#?}", resp.unwrap_err()); + } +} diff --git a/examples/v2_incidents_DeleteIncidentImpact.rs b/examples/v2_incidents_DeleteIncidentImpact.rs new file mode 100644 index 000000000..64dd7a706 --- /dev/null +++ b/examples/v2_incidents_DeleteIncidentImpact.rs @@ -0,0 +1,25 @@ +// Delete an incident impact returns "No Content" response +use datadog_api_client::datadog; +use datadog_api_client::datadogV2::api_incidents::IncidentsAPI; + +#[tokio::main] +async fn main() { + // the "incident" has an "incident_impact" + let incident_impact_data_id = std::env::var("INCIDENT_IMPACT_DATA_ID").unwrap(); + let incident_impact_data_relationships_incident_data_id = + std::env::var("INCIDENT_IMPACT_DATA_RELATIONSHIPS_INCIDENT_DATA_ID").unwrap(); + let mut configuration = datadog::Configuration::new(); + configuration.set_unstable_operation_enabled("v2.DeleteIncidentImpact", true); + let api = IncidentsAPI::with_config(configuration); + let resp = api + .delete_incident_impact( + incident_impact_data_relationships_incident_data_id.clone(), + incident_impact_data_id.clone(), + ) + .await; + if let Ok(value) = resp { + println!("{:#?}", value); + } else { + println!("{:#?}", resp.unwrap_err()); + } +} diff --git a/examples/v2_incidents_ListIncidentImpacts.rs b/examples/v2_incidents_ListIncidentImpacts.rs new file mode 100644 index 000000000..37bafc569 --- /dev/null +++ b/examples/v2_incidents_ListIncidentImpacts.rs @@ -0,0 +1,24 @@ +// List an incident's impacts returns "OK" response +use datadog_api_client::datadog; +use datadog_api_client::datadogV2::api_incidents::IncidentsAPI; +use datadog_api_client::datadogV2::api_incidents::ListIncidentImpactsOptionalParams; + +#[tokio::main] +async fn main() { + // there is a valid "incident" in the system + let incident_data_id = std::env::var("INCIDENT_DATA_ID").unwrap(); + let mut configuration = datadog::Configuration::new(); + configuration.set_unstable_operation_enabled("v2.ListIncidentImpacts", true); + let api = IncidentsAPI::with_config(configuration); + let resp = api + .list_incident_impacts( + incident_data_id.clone(), + ListIncidentImpactsOptionalParams::default(), + ) + .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 1afc7abf9..be52fdc2e 100644 --- a/src/datadog/configuration.rs +++ b/src/datadog/configuration.rs @@ -160,12 +160,14 @@ impl Default for Configuration { ("v2.create_data_deletion_request".to_owned(), false), ("v2.get_data_deletion_requests".to_owned(), false), ("v2.create_incident".to_owned(), false), + ("v2.create_incident_impact".to_owned(), false), ("v2.create_incident_integration".to_owned(), false), ("v2.create_incident_notification_rule".to_owned(), false), ("v2.create_incident_notification_template".to_owned(), false), ("v2.create_incident_todo".to_owned(), false), ("v2.create_incident_type".to_owned(), false), ("v2.delete_incident".to_owned(), false), + ("v2.delete_incident_impact".to_owned(), false), ("v2.delete_incident_integration".to_owned(), false), ("v2.delete_incident_notification_rule".to_owned(), false), ("v2.delete_incident_notification_template".to_owned(), false), @@ -178,6 +180,7 @@ impl Default for Configuration { ("v2.get_incident_todo".to_owned(), false), ("v2.get_incident_type".to_owned(), false), ("v2.list_incident_attachments".to_owned(), false), + ("v2.list_incident_impacts".to_owned(), false), ("v2.list_incident_integrations".to_owned(), false), ("v2.list_incident_notification_rules".to_owned(), false), ("v2.list_incident_notification_templates".to_owned(), false), diff --git a/src/datadogV2/api/api_incidents.rs b/src/datadogV2/api/api_incidents.rs index f338f3961..96bd4780b 100644 --- a/src/datadogV2/api/api_incidents.rs +++ b/src/datadogV2/api/api_incidents.rs @@ -13,6 +13,25 @@ use reqwest::header::{HeaderMap, HeaderValue}; use serde::{Deserialize, Serialize}; use std::io::Write; +/// CreateIncidentImpactOptionalParams is a struct for passing parameters to the method [`IncidentsAPI::create_incident_impact`] +#[non_exhaustive] +#[derive(Clone, Default, Debug)] +pub struct CreateIncidentImpactOptionalParams { + /// Specifies which related resources should be included in the response. + pub include: Option>, +} + +impl CreateIncidentImpactOptionalParams { + /// Specifies which related resources should be included in the response. + pub fn include( + mut self, + value: Vec, + ) -> Self { + self.include = Some(value); + self + } +} + /// DeleteIncidentNotificationRuleOptionalParams is a struct for passing parameters to the method [`IncidentsAPI::delete_incident_notification_rule`] #[non_exhaustive] #[derive(Clone, Default, Debug)] @@ -131,6 +150,25 @@ impl ListIncidentAttachmentsOptionalParams { } } +/// ListIncidentImpactsOptionalParams is a struct for passing parameters to the method [`IncidentsAPI::list_incident_impacts`] +#[non_exhaustive] +#[derive(Clone, Default, Debug)] +pub struct ListIncidentImpactsOptionalParams { + /// Specifies which related resources should be included in the response. + pub include: Option>, +} + +impl ListIncidentImpactsOptionalParams { + /// Specifies which related resources should be included in the response. + pub fn include( + mut self, + value: Vec, + ) -> Self { + self.include = Some(value); + self + } +} + /// ListIncidentNotificationRulesOptionalParams is a struct for passing parameters to the method [`IncidentsAPI::list_incident_notification_rules`] #[non_exhaustive] #[derive(Clone, Default, Debug)] @@ -336,6 +374,14 @@ pub enum CreateIncidentError { UnknownValue(serde_json::Value), } +/// CreateIncidentImpactError is a struct for typed errors of method [`IncidentsAPI::create_incident_impact`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum CreateIncidentImpactError { + APIErrorResponse(crate::datadogV2::model::APIErrorResponse), + UnknownValue(serde_json::Value), +} + /// CreateIncidentIntegrationError is a struct for typed errors of method [`IncidentsAPI::create_incident_integration`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] @@ -384,6 +430,14 @@ pub enum DeleteIncidentError { UnknownValue(serde_json::Value), } +/// DeleteIncidentImpactError is a struct for typed errors of method [`IncidentsAPI::delete_incident_impact`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum DeleteIncidentImpactError { + APIErrorResponse(crate::datadogV2::model::APIErrorResponse), + UnknownValue(serde_json::Value), +} + /// DeleteIncidentIntegrationError is a struct for typed errors of method [`IncidentsAPI::delete_incident_integration`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] @@ -480,6 +534,14 @@ pub enum ListIncidentAttachmentsError { UnknownValue(serde_json::Value), } +/// ListIncidentImpactsError is a struct for typed errors of method [`IncidentsAPI::list_incident_impacts`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum ListIncidentImpactsError { + APIErrorResponse(crate::datadogV2::model::APIErrorResponse), + UnknownValue(serde_json::Value), +} + /// ListIncidentIntegrationsError is a struct for typed errors of method [`IncidentsAPI::list_incident_integrations`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] @@ -816,6 +878,191 @@ impl IncidentsAPI { } } + /// Create an impact for an incident. + pub async fn create_incident_impact( + &self, + incident_id: String, + body: crate::datadogV2::model::IncidentImpactCreateRequest, + params: CreateIncidentImpactOptionalParams, + ) -> Result< + crate::datadogV2::model::IncidentImpactResponse, + datadog::Error, + > { + match self + .create_incident_impact_with_http_info(incident_id, body, params) + .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), + } + } + + /// Create an impact for an incident. + pub async fn create_incident_impact_with_http_info( + &self, + incident_id: String, + body: crate::datadogV2::model::IncidentImpactCreateRequest, + params: CreateIncidentImpactOptionalParams, + ) -> Result< + datadog::ResponseContent, + datadog::Error, + > { + let local_configuration = &self.config; + let operation_id = "v2.create_incident_impact"; + if local_configuration.is_unstable_operation_enabled(operation_id) { + warn!("Using unstable operation {operation_id}"); + } else { + let local_error = datadog::UnstableOperationDisabledError { + msg: "Operation 'v2.create_incident_impact' is not enabled".to_string(), + }; + return Err(datadog::Error::UnstableOperationDisabledError(local_error)); + } + + // unbox and build optional parameters + let include = params.include; + + let local_client = &self.client; + + let local_uri_str = format!( + "{}/api/v2/incidents/{incident_id}/impacts", + local_configuration.get_operation_host(operation_id), + incident_id = datadog::urlencode(incident_id) + ); + let mut local_req_builder = + local_client.request(reqwest::Method::POST, local_uri_str.as_str()); + + if let Some(ref local) = include { + local_req_builder = local_req_builder.query(&[( + "include", + &local + .iter() + .map(|p| p.to_string()) + .collect::>() + .join(",") + .to_string(), + )]); + }; + + // build headers + let mut headers = HeaderMap::new(); + headers.insert("Content-Type", HeaderValue::from_static("application/json")); + 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"), + ); + }; + + // build body parameters + let output = Vec::new(); + let mut ser = serde_json::Serializer::with_formatter(output, datadog::DDFormatter); + if body.serialize(&mut ser).is_ok() { + if let Some(content_encoding) = headers.get("Content-Encoding") { + match content_encoding.to_str().unwrap_or_default() { + "gzip" => { + let mut enc = GzEncoder::new(Vec::new(), Compression::default()); + let _ = enc.write_all(ser.into_inner().as_slice()); + match enc.finish() { + Ok(buf) => { + local_req_builder = local_req_builder.body(buf); + } + Err(e) => return Err(datadog::Error::Io(e)), + } + } + "deflate" => { + let mut enc = ZlibEncoder::new(Vec::new(), Compression::default()); + let _ = enc.write_all(ser.into_inner().as_slice()); + match enc.finish() { + Ok(buf) => { + local_req_builder = local_req_builder.body(buf); + } + Err(e) => return Err(datadog::Error::Io(e)), + } + } + "zstd1" => { + let mut enc = zstd::stream::Encoder::new(Vec::new(), 0).unwrap(); + let _ = enc.write_all(ser.into_inner().as_slice()); + match enc.finish() { + Ok(buf) => { + local_req_builder = local_req_builder.body(buf); + } + Err(e) => return Err(datadog::Error::Io(e)), + } + } + _ => { + local_req_builder = local_req_builder.body(ser.into_inner()); + } + } + } else { + local_req_builder = local_req_builder.body(ser.into_inner()); + } + } + + 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)) + } + } + /// Create an incident integration metadata. pub async fn create_incident_integration( &self, @@ -1741,6 +1988,108 @@ impl IncidentsAPI { } } + /// Delete an incident impact. + pub async fn delete_incident_impact( + &self, + incident_id: String, + impact_id: String, + ) -> Result<(), datadog::Error> { + match self + .delete_incident_impact_with_http_info(incident_id, impact_id) + .await + { + Ok(_) => Ok(()), + Err(err) => Err(err), + } + } + + /// Delete an incident impact. + pub async fn delete_incident_impact_with_http_info( + &self, + incident_id: String, + impact_id: String, + ) -> Result, datadog::Error> { + let local_configuration = &self.config; + let operation_id = "v2.delete_incident_impact"; + if local_configuration.is_unstable_operation_enabled(operation_id) { + warn!("Using unstable operation {operation_id}"); + } else { + let local_error = datadog::UnstableOperationDisabledError { + msg: "Operation 'v2.delete_incident_impact' is not enabled".to_string(), + }; + return Err(datadog::Error::UnstableOperationDisabledError(local_error)); + } + + let local_client = &self.client; + + let local_uri_str = format!( + "{}/api/v2/incidents/{incident_id}/impacts/{impact_id}", + local_configuration.get_operation_host(operation_id), + incident_id = datadog::urlencode(incident_id), + impact_id = datadog::urlencode(impact_id) + ); + let mut local_req_builder = + local_client.request(reqwest::Method::DELETE, local_uri_str.as_str()); + + // build headers + let mut headers = HeaderMap::new(); + headers.insert("Accept", HeaderValue::from_static("*/*")); + + // 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() { + Ok(datadog::ResponseContent { + status: local_status, + content: local_content, + entity: None, + }) + } 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)) + } + } + /// Delete an incident integration metadata. pub async fn delete_incident_integration( &self, @@ -3167,6 +3516,143 @@ impl IncidentsAPI { } } + /// Get all impacts for an incident. + pub async fn list_incident_impacts( + &self, + incident_id: String, + params: ListIncidentImpactsOptionalParams, + ) -> Result< + crate::datadogV2::model::IncidentImpactsResponse, + datadog::Error, + > { + match self + .list_incident_impacts_with_http_info(incident_id, params) + .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), + } + } + + /// Get all impacts for an incident. + pub async fn list_incident_impacts_with_http_info( + &self, + incident_id: String, + params: ListIncidentImpactsOptionalParams, + ) -> Result< + datadog::ResponseContent, + datadog::Error, + > { + let local_configuration = &self.config; + let operation_id = "v2.list_incident_impacts"; + if local_configuration.is_unstable_operation_enabled(operation_id) { + warn!("Using unstable operation {operation_id}"); + } else { + let local_error = datadog::UnstableOperationDisabledError { + msg: "Operation 'v2.list_incident_impacts' is not enabled".to_string(), + }; + return Err(datadog::Error::UnstableOperationDisabledError(local_error)); + } + + // unbox and build optional parameters + let include = params.include; + + let local_client = &self.client; + + let local_uri_str = format!( + "{}/api/v2/incidents/{incident_id}/impacts", + local_configuration.get_operation_host(operation_id), + incident_id = datadog::urlencode(incident_id) + ); + let mut local_req_builder = + local_client.request(reqwest::Method::GET, local_uri_str.as_str()); + + if let Some(ref local) = include { + local_req_builder = local_req_builder.query(&[( + "include", + &local + .iter() + .map(|p| p.to_string()) + .collect::>() + .join(",") + .to_string(), + )]); + }; + + // 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)) + } + } + /// Get all integration metadata for an incident. pub async fn list_incident_integrations( &self, diff --git a/src/datadogV2/model/mod.rs b/src/datadogV2/model/mod.rs index 2e6155c97..d18ae608d 100644 --- a/src/datadogV2/model/mod.rs +++ b/src/datadogV2/model/mod.rs @@ -2214,6 +2214,8 @@ pub mod model_incident_response_data; pub use self::model_incident_response_data::IncidentResponseData; pub mod model_incident_response_attributes; pub use self::model_incident_response_attributes::IncidentResponseAttributes; +pub mod model_incident_non_datadog_creator; +pub use self::model_incident_non_datadog_creator::IncidentNonDatadogCreator; pub mod model_incident_field_attributes_single_value; pub use self::model_incident_field_attributes_single_value::IncidentFieldAttributesSingleValue; pub mod model_incident_field_attributes_single_value_type; @@ -2224,8 +2226,6 @@ pub mod model_incident_field_attributes_value_type; pub use self::model_incident_field_attributes_value_type::IncidentFieldAttributesValueType; pub mod model_incident_field_attributes; pub use self::model_incident_field_attributes::IncidentFieldAttributes; -pub mod model_incident_non_datadog_creator; -pub use self::model_incident_non_datadog_creator::IncidentNonDatadogCreator; pub mod model_incident_notification_handle; pub use self::model_incident_notification_handle::IncidentNotificationHandle; pub mod model_incident_severity; @@ -2478,6 +2478,30 @@ pub mod model_incident_attachment_update_attributes; pub use self::model_incident_attachment_update_attributes::IncidentAttachmentUpdateAttributes; pub mod model_incident_attachment_update_response; pub use self::model_incident_attachment_update_response::IncidentAttachmentUpdateResponse; +pub mod model_incident_impact_related_object; +pub use self::model_incident_impact_related_object::IncidentImpactRelatedObject; +pub mod model_incident_impacts_response; +pub use self::model_incident_impacts_response::IncidentImpactsResponse; +pub mod model_incident_impact_response_data; +pub use self::model_incident_impact_response_data::IncidentImpactResponseData; +pub mod model_incident_impact_attributes; +pub use self::model_incident_impact_attributes::IncidentImpactAttributes; +pub mod model_incident_impact_relationships; +pub use self::model_incident_impact_relationships::IncidentImpactRelationships; +pub mod model_relationship_to_incident; +pub use self::model_relationship_to_incident::RelationshipToIncident; +pub mod model_relationship_to_incident_data; +pub use self::model_relationship_to_incident_data::RelationshipToIncidentData; +pub mod model_incident_impact_type; +pub use self::model_incident_impact_type::IncidentImpactType; +pub mod model_incident_impact_create_request; +pub use self::model_incident_impact_create_request::IncidentImpactCreateRequest; +pub mod model_incident_impact_create_data; +pub use self::model_incident_impact_create_data::IncidentImpactCreateData; +pub mod model_incident_impact_create_attributes; +pub use self::model_incident_impact_create_attributes::IncidentImpactCreateAttributes; +pub mod model_incident_impact_response; +pub use self::model_incident_impact_response::IncidentImpactResponse; pub mod model_incident_integration_metadata_list_response; pub use self::model_incident_integration_metadata_list_response::IncidentIntegrationMetadataListResponse; pub mod model_incident_integration_metadata_response_data; diff --git a/src/datadogV2/model/model_incident_impact_attributes.rs b/src/datadogV2/model/model_incident_impact_attributes.rs new file mode 100644 index 000000000..77da9b6be --- /dev/null +++ b/src/datadogV2/model/model_incident_impact_attributes.rs @@ -0,0 +1,192 @@ +// 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 incident impact's attributes. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct IncidentImpactAttributes { + /// Timestamp when the impact was created. + #[serde(rename = "created")] + pub created: Option>, + /// Description of the impact. + #[serde(rename = "description")] + pub description: String, + /// Timestamp when the impact ended. + #[serde(rename = "end_at", default, with = "::serde_with::rust::double_option")] + pub end_at: Option>>, + /// An object mapping impact field names to field values. + #[serde(rename = "fields", default, with = "::serde_with::rust::double_option")] + pub fields: Option>>, + /// The type of impact. + #[serde(rename = "impact_type")] + pub impact_type: Option, + /// Timestamp when the impact was last modified. + #[serde(rename = "modified")] + pub modified: Option>, + /// Timestamp representing when the impact started. + #[serde(rename = "start_at")] + pub start_at: chrono::DateTime, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl IncidentImpactAttributes { + pub fn new( + description: String, + start_at: chrono::DateTime, + ) -> IncidentImpactAttributes { + IncidentImpactAttributes { + created: None, + description, + end_at: None, + fields: None, + impact_type: None, + modified: None, + start_at, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn created(mut self, value: chrono::DateTime) -> Self { + self.created = Some(value); + self + } + + pub fn end_at(mut self, value: Option>) -> Self { + self.end_at = Some(value); + self + } + + pub fn fields( + mut self, + value: Option>, + ) -> Self { + self.fields = Some(value); + self + } + + pub fn impact_type(mut self, value: String) -> Self { + self.impact_type = Some(value); + self + } + + pub fn modified(mut self, value: chrono::DateTime) -> Self { + self.modified = Some(value); + self + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl<'de> Deserialize<'de> for IncidentImpactAttributes { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct IncidentImpactAttributesVisitor; + impl<'a> Visitor<'a> for IncidentImpactAttributesVisitor { + type Value = IncidentImpactAttributes; + + 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 created: Option> = None; + let mut description: Option = None; + let mut end_at: Option>> = None; + let mut fields: Option< + Option>, + > = None; + let mut impact_type: Option = None; + let mut modified: Option> = None; + let mut start_at: 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() { + "created" => { + if v.is_null() { + continue; + } + created = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "description" => { + description = + Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "end_at" => { + end_at = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "fields" => { + fields = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "impact_type" => { + if v.is_null() { + continue; + } + impact_type = + Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "modified" => { + if v.is_null() { + continue; + } + modified = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "start_at" => { + start_at = 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 description = + description.ok_or_else(|| M::Error::missing_field("description"))?; + let start_at = start_at.ok_or_else(|| M::Error::missing_field("start_at"))?; + + let content = IncidentImpactAttributes { + created, + description, + end_at, + fields, + impact_type, + modified, + start_at, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(IncidentImpactAttributesVisitor) + } +} diff --git a/src/datadogV2/model/model_incident_impact_create_attributes.rs b/src/datadogV2/model/model_incident_impact_create_attributes.rs new file mode 100644 index 000000000..690acb02b --- /dev/null +++ b/src/datadogV2/model/model_incident_impact_create_attributes.rs @@ -0,0 +1,140 @@ +// 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 incident impact's attributes for a create request. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct IncidentImpactCreateAttributes { + /// Description of the impact. + #[serde(rename = "description")] + pub description: String, + /// Timestamp when the impact ended. + #[serde(rename = "end_at", default, with = "::serde_with::rust::double_option")] + pub end_at: Option>>, + /// An object mapping impact field names to field values. + #[serde(rename = "fields", default, with = "::serde_with::rust::double_option")] + pub fields: Option>>, + /// Timestamp when the impact started. + #[serde(rename = "start_at")] + pub start_at: chrono::DateTime, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl IncidentImpactCreateAttributes { + pub fn new( + description: String, + start_at: chrono::DateTime, + ) -> IncidentImpactCreateAttributes { + IncidentImpactCreateAttributes { + description, + end_at: None, + fields: None, + start_at, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn end_at(mut self, value: Option>) -> Self { + self.end_at = Some(value); + self + } + + pub fn fields( + mut self, + value: Option>, + ) -> Self { + self.fields = Some(value); + self + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl<'de> Deserialize<'de> for IncidentImpactCreateAttributes { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct IncidentImpactCreateAttributesVisitor; + impl<'a> Visitor<'a> for IncidentImpactCreateAttributesVisitor { + type Value = IncidentImpactCreateAttributes; + + 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 description: Option = None; + let mut end_at: Option>> = None; + let mut fields: Option< + Option>, + > = None; + let mut start_at: 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() { + "description" => { + description = + Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "end_at" => { + end_at = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "fields" => { + fields = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "start_at" => { + start_at = 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 description = + description.ok_or_else(|| M::Error::missing_field("description"))?; + let start_at = start_at.ok_or_else(|| M::Error::missing_field("start_at"))?; + + let content = IncidentImpactCreateAttributes { + description, + end_at, + fields, + start_at, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(IncidentImpactCreateAttributesVisitor) + } +} diff --git a/src/datadogV2/model/model_incident_impact_create_data.rs b/src/datadogV2/model/model_incident_impact_create_data.rs new file mode 100644 index 000000000..f423543ca --- /dev/null +++ b/src/datadogV2/model/model_incident_impact_create_data.rs @@ -0,0 +1,117 @@ +// 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}; + +/// Incident impact data for a create request. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct IncidentImpactCreateData { + /// The incident impact's attributes for a create request. + #[serde(rename = "attributes")] + pub attributes: crate::datadogV2::model::IncidentImpactCreateAttributes, + /// Incident impact resource type. + #[serde(rename = "type")] + pub type_: crate::datadogV2::model::IncidentImpactType, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl IncidentImpactCreateData { + pub fn new( + attributes: crate::datadogV2::model::IncidentImpactCreateAttributes, + type_: crate::datadogV2::model::IncidentImpactType, + ) -> IncidentImpactCreateData { + IncidentImpactCreateData { + attributes, + 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 IncidentImpactCreateData { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct IncidentImpactCreateDataVisitor; + impl<'a> Visitor<'a> for IncidentImpactCreateDataVisitor { + type Value = IncidentImpactCreateData; + + 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::IncidentImpactCreateAttributes, + > = 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)?); + } + "type" => { + type_ = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + if let Some(ref _type_) = type_ { + match _type_ { + crate::datadogV2::model::IncidentImpactType::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 type_ = type_.ok_or_else(|| M::Error::missing_field("type_"))?; + + let content = IncidentImpactCreateData { + attributes, + type_, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(IncidentImpactCreateDataVisitor) + } +} diff --git a/src/datadogV2/model/model_incident_impact_create_request.rs b/src/datadogV2/model/model_incident_impact_create_request.rs new file mode 100644 index 000000000..fc6797757 --- /dev/null +++ b/src/datadogV2/model/model_incident_impact_create_request.rs @@ -0,0 +1,94 @@ +// 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}; + +/// Create request for an incident impact. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct IncidentImpactCreateRequest { + /// Incident impact data for a create request. + #[serde(rename = "data")] + pub data: crate::datadogV2::model::IncidentImpactCreateData, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl IncidentImpactCreateRequest { + pub fn new( + data: crate::datadogV2::model::IncidentImpactCreateData, + ) -> IncidentImpactCreateRequest { + IncidentImpactCreateRequest { + 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 IncidentImpactCreateRequest { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct IncidentImpactCreateRequestVisitor; + impl<'a> Visitor<'a> for IncidentImpactCreateRequestVisitor { + type Value = IncidentImpactCreateRequest; + + 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 = 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 = IncidentImpactCreateRequest { + data, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(IncidentImpactCreateRequestVisitor) + } +} diff --git a/src/datadogV2/model/model_incident_impact_related_object.rs b/src/datadogV2/model/model_incident_impact_related_object.rs new file mode 100644 index 000000000..6887be664 --- /dev/null +++ b/src/datadogV2/model/model_incident_impact_related_object.rs @@ -0,0 +1,54 @@ +// 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 IncidentImpactRelatedObject { + INCIDENT, + CREATED_BY_USER, + LAST_MODIFIED_BY_USER, + UnparsedObject(crate::datadog::UnparsedObject), +} + +impl ToString for IncidentImpactRelatedObject { + fn to_string(&self) -> String { + match self { + Self::INCIDENT => String::from("incident"), + Self::CREATED_BY_USER => String::from("created_by_user"), + Self::LAST_MODIFIED_BY_USER => String::from("last_modified_by_user"), + Self::UnparsedObject(v) => v.value.to_string(), + } + } +} + +impl Serialize for IncidentImpactRelatedObject { + 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 IncidentImpactRelatedObject { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s: String = String::deserialize(deserializer)?; + Ok(match s.as_str() { + "incident" => Self::INCIDENT, + "created_by_user" => Self::CREATED_BY_USER, + "last_modified_by_user" => Self::LAST_MODIFIED_BY_USER, + _ => Self::UnparsedObject(crate::datadog::UnparsedObject { + value: serde_json::Value::String(s.into()), + }), + }) + } +} diff --git a/src/datadogV2/model/model_incident_impact_relationships.rs b/src/datadogV2/model/model_incident_impact_relationships.rs new file mode 100644 index 000000000..8f3253d2f --- /dev/null +++ b/src/datadogV2/model/model_incident_impact_relationships.rs @@ -0,0 +1,145 @@ +// 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 incident impact's resource relationships. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct IncidentImpactRelationships { + /// Relationship to user. + #[serde(rename = "created_by_user")] + pub created_by_user: Option, + /// Relationship to incident. + #[serde(rename = "incident")] + pub incident: Option, + /// Relationship to user. + #[serde(rename = "last_modified_by_user")] + pub last_modified_by_user: Option, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl IncidentImpactRelationships { + pub fn new() -> IncidentImpactRelationships { + IncidentImpactRelationships { + created_by_user: None, + incident: None, + last_modified_by_user: None, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn created_by_user(mut self, value: crate::datadogV2::model::RelationshipToUser) -> Self { + self.created_by_user = Some(value); + self + } + + pub fn incident(mut self, value: crate::datadogV2::model::RelationshipToIncident) -> Self { + self.incident = Some(value); + self + } + + pub fn last_modified_by_user( + mut self, + value: crate::datadogV2::model::RelationshipToUser, + ) -> Self { + self.last_modified_by_user = Some(value); + self + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl Default for IncidentImpactRelationships { + fn default() -> Self { + Self::new() + } +} + +impl<'de> Deserialize<'de> for IncidentImpactRelationships { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct IncidentImpactRelationshipsVisitor; + impl<'a> Visitor<'a> for IncidentImpactRelationshipsVisitor { + type Value = IncidentImpactRelationships; + + 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 created_by_user: Option = None; + let mut incident: Option = None; + let mut last_modified_by_user: 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() { + "created_by_user" => { + if v.is_null() { + continue; + } + created_by_user = + Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "incident" => { + if v.is_null() { + continue; + } + incident = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "last_modified_by_user" => { + if v.is_null() { + continue; + } + last_modified_by_user = + 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 content = IncidentImpactRelationships { + created_by_user, + incident, + last_modified_by_user, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(IncidentImpactRelationshipsVisitor) + } +} diff --git a/src/datadogV2/model/model_incident_impact_response.rs b/src/datadogV2/model/model_incident_impact_response.rs new file mode 100644 index 000000000..da784a87c --- /dev/null +++ b/src/datadogV2/model/model_incident_impact_response.rs @@ -0,0 +1,111 @@ +// 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}; + +/// Response with an incident impact. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct IncidentImpactResponse { + /// Incident impact data from a response. + #[serde(rename = "data")] + pub data: crate::datadogV2::model::IncidentImpactResponseData, + /// Included related resources that the user requested. + #[serde(rename = "included")] + pub included: Option>, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl IncidentImpactResponse { + pub fn new( + data: crate::datadogV2::model::IncidentImpactResponseData, + ) -> IncidentImpactResponse { + IncidentImpactResponse { + data, + included: None, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn included(mut self, value: Vec) -> Self { + self.included = Some(value); + self + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl<'de> Deserialize<'de> for IncidentImpactResponse { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct IncidentImpactResponseVisitor; + impl<'a> Visitor<'a> for IncidentImpactResponseVisitor { + type Value = IncidentImpactResponse; + + 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 = None; + let mut included: 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() { + "data" => { + data = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "included" => { + if v.is_null() { + continue; + } + included = 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 = IncidentImpactResponse { + data, + included, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(IncidentImpactResponseVisitor) + } +} diff --git a/src/datadogV2/model/model_incident_impact_response_data.rs b/src/datadogV2/model/model_incident_impact_response_data.rs new file mode 100644 index 000000000..47888ddb6 --- /dev/null +++ b/src/datadogV2/model/model_incident_impact_response_data.rs @@ -0,0 +1,156 @@ +// 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}; + +/// Incident impact data from a response. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct IncidentImpactResponseData { + /// The incident impact's attributes. + #[serde(rename = "attributes")] + pub attributes: Option, + /// The incident impact's ID. + #[serde(rename = "id")] + pub id: String, + /// The incident impact's resource relationships. + #[serde(rename = "relationships")] + pub relationships: Option, + /// Incident impact resource type. + #[serde(rename = "type")] + pub type_: crate::datadogV2::model::IncidentImpactType, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl IncidentImpactResponseData { + pub fn new( + id: String, + type_: crate::datadogV2::model::IncidentImpactType, + ) -> IncidentImpactResponseData { + IncidentImpactResponseData { + attributes: None, + id, + relationships: None, + type_, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn attributes(mut self, value: crate::datadogV2::model::IncidentImpactAttributes) -> Self { + self.attributes = Some(value); + self + } + + pub fn relationships( + mut self, + value: crate::datadogV2::model::IncidentImpactRelationships, + ) -> Self { + self.relationships = Some(value); + self + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl<'de> Deserialize<'de> for IncidentImpactResponseData { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct IncidentImpactResponseDataVisitor; + impl<'a> Visitor<'a> for IncidentImpactResponseDataVisitor { + type Value = IncidentImpactResponseData; + + 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 = + None; + let mut id: Option = None; + let mut relationships: Option< + crate::datadogV2::model::IncidentImpactRelationships, + > = 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" => { + if v.is_null() { + continue; + } + 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)?); + } + "relationships" => { + if v.is_null() { + continue; + } + relationships = + 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::IncidentImpactType::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 = IncidentImpactResponseData { + attributes, + id, + relationships, + type_, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(IncidentImpactResponseDataVisitor) + } +} diff --git a/src/datadogV2/model/model_incident_impact_type.rs b/src/datadogV2/model/model_incident_impact_type.rs new file mode 100644 index 000000000..f636dc93e --- /dev/null +++ b/src/datadogV2/model/model_incident_impact_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 IncidentImpactType { + INCIDENT_IMPACTS, + UnparsedObject(crate::datadog::UnparsedObject), +} + +impl ToString for IncidentImpactType { + fn to_string(&self) -> String { + match self { + Self::INCIDENT_IMPACTS => String::from("incident_impacts"), + Self::UnparsedObject(v) => v.value.to_string(), + } + } +} + +impl Serialize for IncidentImpactType { + 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 IncidentImpactType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s: String = String::deserialize(deserializer)?; + Ok(match s.as_str() { + "incident_impacts" => Self::INCIDENT_IMPACTS, + _ => Self::UnparsedObject(crate::datadog::UnparsedObject { + value: serde_json::Value::String(s.into()), + }), + }) + } +} diff --git a/src/datadogV2/model/model_incident_impacts_response.rs b/src/datadogV2/model/model_incident_impacts_response.rs new file mode 100644 index 000000000..dc4b8ce64 --- /dev/null +++ b/src/datadogV2/model/model_incident_impacts_response.rs @@ -0,0 +1,112 @@ +// 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}; + +/// Response with a list of incident impacts. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct IncidentImpactsResponse { + /// An array of incident impacts. + #[serde(rename = "data")] + pub data: Vec, + /// Included related resources that the user requested. + #[serde(rename = "included")] + pub included: Option>, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl IncidentImpactsResponse { + pub fn new( + data: Vec, + ) -> IncidentImpactsResponse { + IncidentImpactsResponse { + data, + included: None, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn included(mut self, value: Vec) -> Self { + self.included = Some(value); + self + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl<'de> Deserialize<'de> for IncidentImpactsResponse { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct IncidentImpactsResponseVisitor; + impl<'a> Visitor<'a> for IncidentImpactsResponseVisitor { + type Value = IncidentImpactsResponse; + + 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> = + None; + let mut included: 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() { + "data" => { + data = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "included" => { + if v.is_null() { + continue; + } + included = 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 = IncidentImpactsResponse { + data, + included, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(IncidentImpactsResponseVisitor) + } +} diff --git a/src/datadogV2/model/model_incident_response_attributes.rs b/src/datadogV2/model/model_incident_response_attributes.rs index 3740bb636..86ae14c4d 100644 --- a/src/datadogV2/model/model_incident_response_attributes.rs +++ b/src/datadogV2/model/model_incident_response_attributes.rs @@ -56,6 +56,23 @@ pub struct IncidentResponseAttributes { /// A flag indicating whether the incident caused customer impact. #[serde(rename = "customer_impacted")] pub customer_impacted: Option, + /// Timestamp when the incident was declared. + #[serde(rename = "declared")] + pub declared: Option>, + /// Incident's non Datadog creator. + #[serde( + rename = "declared_by", + default, + with = "::serde_with::rust::double_option" + )] + pub declared_by: Option>, + /// UUID of the user who declared the incident. + #[serde( + rename = "declared_by_uuid", + default, + with = "::serde_with::rust::double_option" + )] + pub declared_by_uuid: Option>, /// Timestamp when the incident was detected. #[serde( rename = "detected", @@ -149,6 +166,9 @@ impl IncidentResponseAttributes { customer_impact_scope: None, customer_impact_start: None, customer_impacted: None, + declared: None, + declared_by: None, + declared_by_uuid: None, detected: None, fields: None, incident_type_uuid: None, @@ -211,6 +231,24 @@ impl IncidentResponseAttributes { self } + pub fn declared(mut self, value: chrono::DateTime) -> Self { + self.declared = Some(value); + self + } + + pub fn declared_by( + mut self, + value: Option, + ) -> Self { + self.declared_by = Some(value); + self + } + + pub fn declared_by_uuid(mut self, value: Option) -> Self { + self.declared_by_uuid = Some(value); + self + } + pub fn detected(mut self, value: Option>) -> Self { self.detected = Some(value); self @@ -334,6 +372,11 @@ impl<'de> Deserialize<'de> for IncidentResponseAttributes { let mut customer_impact_scope: Option> = None; let mut customer_impact_start: Option>> = None; let mut customer_impacted: Option = None; + let mut declared: Option> = None; + let mut declared_by: Option< + Option, + > = None; + let mut declared_by_uuid: Option> = None; let mut detected: Option>> = None; let mut fields: Option< std::collections::BTreeMap< @@ -406,6 +449,20 @@ impl<'de> Deserialize<'de> for IncidentResponseAttributes { customer_impacted = Some(serde_json::from_value(v).map_err(M::Error::custom)?); } + "declared" => { + if v.is_null() { + continue; + } + declared = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "declared_by" => { + declared_by = + Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "declared_by_uuid" => { + declared_by_uuid = + Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } "detected" => { detected = Some(serde_json::from_value(v).map_err(M::Error::custom)?); } @@ -522,6 +579,9 @@ impl<'de> Deserialize<'de> for IncidentResponseAttributes { customer_impact_scope, customer_impact_start, customer_impacted, + declared, + declared_by, + declared_by_uuid, detected, fields, incident_type_uuid, diff --git a/src/datadogV2/model/model_incident_response_relationships.rs b/src/datadogV2/model/model_incident_response_relationships.rs index a3e2d8ad6..d47582e79 100644 --- a/src/datadogV2/model/model_incident_response_relationships.rs +++ b/src/datadogV2/model/model_incident_response_relationships.rs @@ -24,6 +24,9 @@ pub struct IncidentResponseRelationships { /// Relationship to user. #[serde(rename = "created_by_user")] pub created_by_user: Option, + /// Relationship to user. + #[serde(rename = "declared_by_user")] + pub declared_by_user: Option, /// Relationship to impacts. #[serde(rename = "impacts")] pub impacts: Option, @@ -53,6 +56,7 @@ impl IncidentResponseRelationships { attachments: None, commander_user: None, created_by_user: None, + declared_by_user: None, impacts: None, integrations: None, last_modified_by_user: None, @@ -84,6 +88,11 @@ impl IncidentResponseRelationships { self } + pub fn declared_by_user(mut self, value: crate::datadogV2::model::RelationshipToUser) -> Self { + self.declared_by_user = Some(value); + self + } + pub fn impacts( mut self, value: crate::datadogV2::model::RelationshipToIncidentImpacts, @@ -163,6 +172,8 @@ impl<'de> Deserialize<'de> for IncidentResponseRelationships { Option, > = None; let mut created_by_user: Option = None; + let mut declared_by_user: Option = + None; let mut impacts: Option = None; let mut integrations: Option< @@ -202,6 +213,13 @@ impl<'de> Deserialize<'de> for IncidentResponseRelationships { created_by_user = Some(serde_json::from_value(v).map_err(M::Error::custom)?); } + "declared_by_user" => { + if v.is_null() { + continue; + } + declared_by_user = + Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } "impacts" => { if v.is_null() { continue; @@ -247,6 +265,7 @@ impl<'de> Deserialize<'de> for IncidentResponseRelationships { attachments, commander_user, created_by_user, + declared_by_user, impacts, integrations, last_modified_by_user, diff --git a/src/datadogV2/model/model_relationship_to_incident.rs b/src/datadogV2/model/model_relationship_to_incident.rs new file mode 100644 index 000000000..cf4f1b1e1 --- /dev/null +++ b/src/datadogV2/model/model_relationship_to_incident.rs @@ -0,0 +1,94 @@ +// 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}; + +/// Relationship to incident. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct RelationshipToIncident { + /// Relationship to incident object. + #[serde(rename = "data")] + pub data: crate::datadogV2::model::RelationshipToIncidentData, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl RelationshipToIncident { + pub fn new( + data: crate::datadogV2::model::RelationshipToIncidentData, + ) -> RelationshipToIncident { + RelationshipToIncident { + 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 RelationshipToIncident { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct RelationshipToIncidentVisitor; + impl<'a> Visitor<'a> for RelationshipToIncidentVisitor { + type Value = RelationshipToIncident; + + 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 = 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 = RelationshipToIncident { + data, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(RelationshipToIncidentVisitor) + } +} diff --git a/src/datadogV2/model/model_relationship_to_incident_data.rs b/src/datadogV2/model/model_relationship_to_incident_data.rs new file mode 100644 index 000000000..5163e67d1 --- /dev/null +++ b/src/datadogV2/model/model_relationship_to_incident_data.rs @@ -0,0 +1,115 @@ +// 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}; + +/// Relationship to incident object. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct RelationshipToIncidentData { + /// A unique identifier that represents the incident. + #[serde(rename = "id")] + pub id: String, + /// Incident resource type. + #[serde(rename = "type")] + pub type_: crate::datadogV2::model::IncidentType, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl RelationshipToIncidentData { + pub fn new( + id: String, + type_: crate::datadogV2::model::IncidentType, + ) -> RelationshipToIncidentData { + RelationshipToIncidentData { + 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 RelationshipToIncidentData { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct RelationshipToIncidentDataVisitor; + impl<'a> Visitor<'a> for RelationshipToIncidentDataVisitor { + type Value = RelationshipToIncidentData; + + 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::IncidentType::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 = RelationshipToIncidentData { + id, + type_, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(RelationshipToIncidentDataVisitor) + } +} diff --git a/tests/scenarios/cassettes/v2/incidents/Create-an-incident-impact-returns-Bad-Request-response.frozen b/tests/scenarios/cassettes/v2/incidents/Create-an-incident-impact-returns-Bad-Request-response.frozen new file mode 100644 index 000000000..0016a9985 --- /dev/null +++ b/tests/scenarios/cassettes/v2/incidents/Create-an-incident-impact-returns-Bad-Request-response.frozen @@ -0,0 +1 @@ +2025-09-16T19:46:43.553Z \ No newline at end of file diff --git a/tests/scenarios/cassettes/v2/incidents/Create-an-incident-impact-returns-Bad-Request-response.json b/tests/scenarios/cassettes/v2/incidents/Create-an-incident-impact-returns-Bad-Request-response.json new file mode 100644 index 000000000..c3b6accaf --- /dev/null +++ b/tests/scenarios/cassettes/v2/incidents/Create-an-incident-impact-returns-Bad-Request-response.json @@ -0,0 +1,39 @@ +{ + "http_interactions": [ + { + "request": { + "body": { + "string": "{\"data\":{\"attributes\":{\"description\":\"Service was unavailable for external users\",\"end_at\":\"2025-08-29T13:17:00Z\",\"fields\":{\"customers_impacted\":\"all\",\"products_impacted\":[\"shopping\",\"marketing\"]},\"start_at\":\"2025-08-28T13:17:00Z\"},\"type\":\"incident_impacts\"}}", + "encoding": null + }, + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json" + ] + }, + "method": "post", + "uri": "https://api.datadoghq.com/api/v2/incidents/00000000-0000-0000-0000-000000000000/impacts" + }, + "response": { + "body": { + "string": "{\"errors\":[{\"title\":\"Bad Request\",\"detail\":\"invalid impact data: incident id is required: invalid impact\"}]}", + "encoding": null + }, + "headers": { + "Content-Type": [ + "application/vnd.api+json" + ] + }, + "status": { + "code": 400, + "message": "Bad Request" + } + }, + "recorded_at": "Tue, 16 Sep 2025 19:46:43 GMT" + } + ], + "recorded_with": "VCR 6.0.0" +} \ No newline at end of file diff --git a/tests/scenarios/cassettes/v2/incidents/Create-an-incident-impact-returns-CREATED-response.frozen b/tests/scenarios/cassettes/v2/incidents/Create-an-incident-impact-returns-CREATED-response.frozen new file mode 100644 index 000000000..aa2f3172f --- /dev/null +++ b/tests/scenarios/cassettes/v2/incidents/Create-an-incident-impact-returns-CREATED-response.frozen @@ -0,0 +1 @@ +2025-09-16T19:46:53.892Z \ No newline at end of file diff --git a/tests/scenarios/cassettes/v2/incidents/Create-an-incident-impact-returns-CREATED-response.json b/tests/scenarios/cassettes/v2/incidents/Create-an-incident-impact-returns-CREATED-response.json new file mode 100644 index 000000000..a4d08663a --- /dev/null +++ b/tests/scenarios/cassettes/v2/incidents/Create-an-incident-impact-returns-CREATED-response.json @@ -0,0 +1,125 @@ +{ + "http_interactions": [ + { + "request": { + "body": { + "string": "{\"data\":{\"attributes\":{\"customer_impacted\":false,\"title\":\"Test-Create_an_incident_impact_returns_CREATED_response-1758052013\"},\"type\":\"incidents\"}}", + "encoding": null + }, + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json" + ] + }, + "method": "post", + "uri": "https://api.datadoghq.com/api/v2/incidents" + }, + "response": { + "body": { + "string": "{\"data\":{\"type\":\"incidents\",\"id\":\"5826fc99-ad8c-54cb-8c18-cd270bfe42fb\",\"attributes\":{\"public_id\":309851,\"incident_type_uuid\":\"41d2e10b-4108-4736-92d7-791d00ea0702\",\"title\":\"Test-Create_an_incident_impact_returns_CREATED_response-1758052013\",\"resolved\":null,\"customer_impact_scope\":null,\"customer_impact_start\":null,\"customer_impact_end\":null,\"customer_impacted\":false,\"notification_handles\":null,\"last_modified_by\":{\"data\":{\"type\":\"users\",\"id\":\"3ad549bf-eba0-11e9-a77a-0705486660d0\",\"attributes\":{\"uuid\":\"3ad549bf-eba0-11e9-a77a-0705486660d0\",\"handle\":\"frog@datadoghq.com\",\"email\":\"frog@datadoghq.com\",\"name\":\"frog\",\"icon\":\"https://secure.gravatar.com/avatar/28a16dfe36e73b60c1d55872cb0f1172?s=48&d=retro\"}}},\"last_modified_by_uuid\":null,\"created\":\"2025-09-16T19:46:54.038695+00:00\",\"modified\":\"2025-09-16T19:46:54.038695+00:00\",\"commander\":null,\"detected\":\"2025-09-16T19:46:54.027387+00:00\",\"created_by\":{\"data\":{\"type\":\"users\",\"id\":\"3ad549bf-eba0-11e9-a77a-0705486660d0\",\"attributes\":{\"uuid\":\"3ad549bf-eba0-11e9-a77a-0705486660d0\",\"handle\":\"frog@datadoghq.com\",\"email\":\"frog@datadoghq.com\",\"name\":\"frog\",\"icon\":\"https://secure.gravatar.com/avatar/28a16dfe36e73b60c1d55872cb0f1172?s=48&d=retro\"}}},\"created_by_uuid\":null,\"creation_idempotency_key\":null,\"customer_impact_duration\":0,\"time_to_detect\":0,\"time_to_repair\":0,\"time_to_internal_response\":0,\"time_to_resolve\":0,\"archived\":null,\"is_test\":false,\"declared\":\"2025-09-16T19:46:54.038695+00:00\",\"declared_by\":{\"data\":{\"type\":\"users\",\"id\":\"3ad549bf-eba0-11e9-a77a-0705486660d0\",\"attributes\":{\"uuid\":\"3ad549bf-eba0-11e9-a77a-0705486660d0\",\"handle\":\"frog@datadoghq.com\",\"email\":\"frog@datadoghq.com\",\"name\":\"frog\",\"icon\":\"https://secure.gravatar.com/avatar/28a16dfe36e73b60c1d55872cb0f1172?s=48&d=retro\"}}},\"declared_by_uuid\":null,\"fields\":{\"severity\":{\"type\":\"dropdown\",\"value\":\"UNKNOWN\"},\"state\":{\"type\":\"dropdown\",\"value\":\"active\"},\"detection_method\":{\"type\":\"dropdown\",\"value\":\"unknown\"},\"root_cause\":{\"type\":\"textbox\",\"value\":null},\"summary\":{\"type\":\"textbox\",\"value\":null},\"services\":{\"type\":\"autocomplete\",\"value\":null},\"teams\":{\"type\":\"autocomplete\",\"value\":null}},\"field_analytics\":null,\"severity\":\"UNKNOWN\",\"state\":\"active\",\"non_datadog_creator\":null,\"visibility\":\"organization\",\"case_id\":null},\"relationships\":{\"created_by_user\":{\"data\":{\"type\":\"users\",\"id\":\"3ad549bf-eba0-11e9-a77a-0705486660d0\"}},\"last_modified_by_user\":{\"data\":{\"type\":\"users\",\"id\":\"3ad549bf-eba0-11e9-a77a-0705486660d0\"}},\"commander_user\":{\"data\":null},\"declared_by_user\":{\"data\":{\"type\":\"users\",\"id\":\"3ad549bf-eba0-11e9-a77a-0705486660d0\"}},\"user_defined_fields\":{\"data\":[{\"type\":\"user_defined_field\",\"id\":\"33457d2a-570c-5567-b4af-979a2a8f1164\"},{\"type\":\"user_defined_field\",\"id\":\"d003693c-bee9-5420-8d46-859269c20914\"},{\"type\":\"user_defined_field\",\"id\":\"1ddff6f6-cb1f-51a0-9d81-dc18ef52cc9d\"},{\"type\":\"user_defined_field\",\"id\":\"6bc9d32b-c2cd-591e-9b7a-74c886a5ddcf\"},{\"type\":\"user_defined_field\",\"id\":\"95c53547-2ba3-5d8a-9c3b-cf245bc0c629\"},{\"type\":\"user_defined_field\",\"id\":\"39044b03-cee4-555f-b1e0-3eb3aa759a86\"},{\"type\":\"user_defined_field\",\"id\":\"3cbe9e60-d794-532c-acc0-73641f782813\"}]},\"integrations\":{\"data\":[]},\"attachments\":{\"data\":[]},\"responders\":{\"data\":[]},\"impacts\":{\"data\":[]}}}}\n", + "encoding": null + }, + "headers": { + "Content-Type": [ + "application/json" + ] + }, + "status": { + "code": 201, + "message": "Created" + } + }, + "recorded_at": "Tue, 16 Sep 2025 19:46:53 GMT" + }, + { + "request": { + "body": { + "string": "{\"data\":{\"attributes\":{\"description\":\"Outage in the us-east-1 region\",\"end_at\":\"2025-09-12T14:50:00.000Z\",\"start_at\":\"2025-09-12T13:50:00.000Z\"},\"type\":\"incident_impacts\"}}", + "encoding": null + }, + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json" + ] + }, + "method": "post", + "uri": "https://api.datadoghq.com/api/v2/incidents/5826fc99-ad8c-54cb-8c18-cd270bfe42fb/impacts" + }, + "response": { + "body": { + "string": "{\"data\":{\"id\":\"7d4f5663-7c01-4727-b90b-323953603092\",\"type\":\"incident_impacts\",\"attributes\":{\"created\":\"2025-09-16T19:46:54.291754Z\",\"description\":\"Outage in the us-east-1 region\",\"end_at\":\"2025-09-12T14:50:00Z\",\"fields\":null,\"impact_type\":\"customer\",\"modified\":\"2025-09-16T19:46:54.291754Z\",\"start_at\":\"2025-09-12T13:50:00Z\"},\"relationships\":{\"created_by_user\":{\"data\":{\"id\":\"3ad549bf-eba0-11e9-a77a-0705486660d0\",\"type\":\"users\"}},\"incident\":{\"data\":{\"id\":\"5826fc99-ad8c-54cb-8c18-cd270bfe42fb\",\"type\":\"incidents\"}},\"last_modified_by_user\":{\"data\":{\"id\":\"3ad549bf-eba0-11e9-a77a-0705486660d0\",\"type\":\"users\"}}}}}", + "encoding": null + }, + "headers": { + "Content-Type": [ + "application/vnd.api+json" + ] + }, + "status": { + "code": 201, + "message": "Created" + } + }, + "recorded_at": "Tue, 16 Sep 2025 19:46:53 GMT" + }, + { + "request": { + "body": "", + "headers": { + "Accept": [ + "*/*" + ] + }, + "method": "delete", + "uri": "https://api.datadoghq.com/api/v2/incidents/5826fc99-ad8c-54cb-8c18-cd270bfe42fb/impacts/7d4f5663-7c01-4727-b90b-323953603092" + }, + "response": { + "body": { + "string": "", + "encoding": null + }, + "headers": {}, + "status": { + "code": 204, + "message": "No Content" + } + }, + "recorded_at": "Tue, 16 Sep 2025 19:46:53 GMT" + }, + { + "request": { + "body": "", + "headers": { + "Accept": [ + "*/*" + ] + }, + "method": "delete", + "uri": "https://api.datadoghq.com/api/v2/incidents/5826fc99-ad8c-54cb-8c18-cd270bfe42fb" + }, + "response": { + "body": { + "string": "", + "encoding": null + }, + "headers": { + "Content-Type": [ + "text/html; charset=utf-8" + ] + }, + "status": { + "code": 204, + "message": "No Content" + } + }, + "recorded_at": "Tue, 16 Sep 2025 19:46:53 GMT" + } + ], + "recorded_with": "VCR 6.0.0" +} \ No newline at end of file diff --git a/tests/scenarios/cassettes/v2/incidents/Create-an-incident-impact-returns-Not-Found-response.frozen b/tests/scenarios/cassettes/v2/incidents/Create-an-incident-impact-returns-Not-Found-response.frozen new file mode 100644 index 000000000..112e404d1 --- /dev/null +++ b/tests/scenarios/cassettes/v2/incidents/Create-an-incident-impact-returns-Not-Found-response.frozen @@ -0,0 +1 @@ +2025-09-16T19:47:06.306Z \ No newline at end of file diff --git a/tests/scenarios/cassettes/v2/incidents/Create-an-incident-impact-returns-Not-Found-response.json b/tests/scenarios/cassettes/v2/incidents/Create-an-incident-impact-returns-Not-Found-response.json new file mode 100644 index 000000000..c76f07f51 --- /dev/null +++ b/tests/scenarios/cassettes/v2/incidents/Create-an-incident-impact-returns-Not-Found-response.json @@ -0,0 +1,39 @@ +{ + "http_interactions": [ + { + "request": { + "body": { + "string": "{\"data\":{\"attributes\":{\"description\":\"Service was unavailable for external users\",\"end_at\":\"2025-08-29T13:17:00Z\",\"fields\":{\"customers_impacted\":\"all\",\"products_impacted\":[\"shopping\",\"marketing\"]},\"start_at\":\"2025-08-28T13:17:00Z\"},\"type\":\"incident_impacts\"}}", + "encoding": null + }, + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json" + ] + }, + "method": "post", + "uri": "https://api.datadoghq.com/api/v2/incidents/00000000-0000-0000-0000-000000000001/impacts" + }, + "response": { + "body": { + "string": "{\"errors\":[{\"title\":\"Generic Error\",\"detail\":\"rpc error: code = NotFound desc = incident not found: failed to get incident: incident not found\"}]}", + "encoding": null + }, + "headers": { + "Content-Type": [ + "application/vnd.api+json" + ] + }, + "status": { + "code": 404, + "message": "Not Found" + } + }, + "recorded_at": "Tue, 16 Sep 2025 19:47:06 GMT" + } + ], + "recorded_with": "VCR 6.0.0" +} \ No newline at end of file diff --git a/tests/scenarios/cassettes/v2/incidents/Delete-an-incident-impact-returns-No-Content-response.frozen b/tests/scenarios/cassettes/v2/incidents/Delete-an-incident-impact-returns-No-Content-response.frozen new file mode 100644 index 000000000..69564fd4b --- /dev/null +++ b/tests/scenarios/cassettes/v2/incidents/Delete-an-incident-impact-returns-No-Content-response.frozen @@ -0,0 +1 @@ +2025-09-16T19:47:17.707Z \ No newline at end of file diff --git a/tests/scenarios/cassettes/v2/incidents/Delete-an-incident-impact-returns-No-Content-response.json b/tests/scenarios/cassettes/v2/incidents/Delete-an-incident-impact-returns-No-Content-response.json new file mode 100644 index 000000000..d8c6b372e --- /dev/null +++ b/tests/scenarios/cassettes/v2/incidents/Delete-an-incident-impact-returns-No-Content-response.json @@ -0,0 +1,153 @@ +{ + "http_interactions": [ + { + "request": { + "body": { + "string": "{\"data\":{\"attributes\":{\"customer_impacted\":false,\"title\":\"Test-Delete_an_incident_impact_returns_No_Content_response-1758052037\"},\"type\":\"incidents\"}}", + "encoding": null + }, + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json" + ] + }, + "method": "post", + "uri": "https://api.datadoghq.com/api/v2/incidents" + }, + "response": { + "body": { + "string": "{\"data\":{\"type\":\"incidents\",\"id\":\"1a838ffb-9c95-5df6-978c-4cf21f854fd1\",\"attributes\":{\"public_id\":309852,\"incident_type_uuid\":\"41d2e10b-4108-4736-92d7-791d00ea0702\",\"title\":\"Test-Delete_an_incident_impact_returns_No_Content_response-1758052037\",\"resolved\":null,\"customer_impact_scope\":null,\"customer_impact_start\":null,\"customer_impact_end\":null,\"customer_impacted\":false,\"notification_handles\":null,\"last_modified_by\":{\"data\":{\"type\":\"users\",\"id\":\"3ad549bf-eba0-11e9-a77a-0705486660d0\",\"attributes\":{\"uuid\":\"3ad549bf-eba0-11e9-a77a-0705486660d0\",\"handle\":\"frog@datadoghq.com\",\"email\":\"frog@datadoghq.com\",\"name\":\"frog\",\"icon\":\"https://secure.gravatar.com/avatar/28a16dfe36e73b60c1d55872cb0f1172?s=48&d=retro\"}}},\"last_modified_by_uuid\":null,\"created\":\"2025-09-16T19:47:17.862681+00:00\",\"modified\":\"2025-09-16T19:47:17.862681+00:00\",\"commander\":null,\"detected\":\"2025-09-16T19:47:17.850799+00:00\",\"created_by\":{\"data\":{\"type\":\"users\",\"id\":\"3ad549bf-eba0-11e9-a77a-0705486660d0\",\"attributes\":{\"uuid\":\"3ad549bf-eba0-11e9-a77a-0705486660d0\",\"handle\":\"frog@datadoghq.com\",\"email\":\"frog@datadoghq.com\",\"name\":\"frog\",\"icon\":\"https://secure.gravatar.com/avatar/28a16dfe36e73b60c1d55872cb0f1172?s=48&d=retro\"}}},\"created_by_uuid\":null,\"creation_idempotency_key\":null,\"customer_impact_duration\":0,\"time_to_detect\":0,\"time_to_repair\":0,\"time_to_internal_response\":0,\"time_to_resolve\":0,\"archived\":null,\"is_test\":false,\"declared\":\"2025-09-16T19:47:17.862681+00:00\",\"declared_by\":{\"data\":{\"type\":\"users\",\"id\":\"3ad549bf-eba0-11e9-a77a-0705486660d0\",\"attributes\":{\"uuid\":\"3ad549bf-eba0-11e9-a77a-0705486660d0\",\"handle\":\"frog@datadoghq.com\",\"email\":\"frog@datadoghq.com\",\"name\":\"frog\",\"icon\":\"https://secure.gravatar.com/avatar/28a16dfe36e73b60c1d55872cb0f1172?s=48&d=retro\"}}},\"declared_by_uuid\":null,\"fields\":{\"severity\":{\"type\":\"dropdown\",\"value\":\"UNKNOWN\"},\"state\":{\"type\":\"dropdown\",\"value\":\"active\"},\"detection_method\":{\"type\":\"dropdown\",\"value\":\"unknown\"},\"root_cause\":{\"type\":\"textbox\",\"value\":null},\"summary\":{\"type\":\"textbox\",\"value\":null},\"services\":{\"type\":\"autocomplete\",\"value\":null},\"teams\":{\"type\":\"autocomplete\",\"value\":null}},\"field_analytics\":null,\"severity\":\"UNKNOWN\",\"state\":\"active\",\"non_datadog_creator\":null,\"visibility\":\"organization\",\"case_id\":null},\"relationships\":{\"created_by_user\":{\"data\":{\"type\":\"users\",\"id\":\"3ad549bf-eba0-11e9-a77a-0705486660d0\"}},\"last_modified_by_user\":{\"data\":{\"type\":\"users\",\"id\":\"3ad549bf-eba0-11e9-a77a-0705486660d0\"}},\"commander_user\":{\"data\":null},\"declared_by_user\":{\"data\":{\"type\":\"users\",\"id\":\"3ad549bf-eba0-11e9-a77a-0705486660d0\"}},\"user_defined_fields\":{\"data\":[{\"type\":\"user_defined_field\",\"id\":\"33457d2a-570c-5567-b4af-979a2a8f1164\"},{\"type\":\"user_defined_field\",\"id\":\"d003693c-bee9-5420-8d46-859269c20914\"},{\"type\":\"user_defined_field\",\"id\":\"1ddff6f6-cb1f-51a0-9d81-dc18ef52cc9d\"},{\"type\":\"user_defined_field\",\"id\":\"6bc9d32b-c2cd-591e-9b7a-74c886a5ddcf\"},{\"type\":\"user_defined_field\",\"id\":\"95c53547-2ba3-5d8a-9c3b-cf245bc0c629\"},{\"type\":\"user_defined_field\",\"id\":\"39044b03-cee4-555f-b1e0-3eb3aa759a86\"},{\"type\":\"user_defined_field\",\"id\":\"3cbe9e60-d794-532c-acc0-73641f782813\"}]},\"integrations\":{\"data\":[]},\"attachments\":{\"data\":[]},\"responders\":{\"data\":[]},\"impacts\":{\"data\":[]}}}}\n", + "encoding": null + }, + "headers": { + "Content-Type": [ + "application/json" + ] + }, + "status": { + "code": 201, + "message": "Created" + } + }, + "recorded_at": "Tue, 16 Sep 2025 19:47:17 GMT" + }, + { + "request": { + "body": { + "string": "{\"data\":{\"attributes\":{\"description\":\"Outage in the us-east-1 region\",\"end_at\":\"2025-09-12T14:50:00.000Z\",\"start_at\":\"2025-09-12T13:50:00.000Z\"},\"type\":\"incident_impacts\"}}", + "encoding": null + }, + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json" + ] + }, + "method": "post", + "uri": "https://api.datadoghq.com/api/v2/incidents/1a838ffb-9c95-5df6-978c-4cf21f854fd1/impacts" + }, + "response": { + "body": { + "string": "{\"data\":{\"id\":\"db11b25d-0383-4f98-bde7-bfc4a10d16eb\",\"type\":\"incident_impacts\",\"attributes\":{\"created\":\"2025-09-16T19:47:18.208811Z\",\"description\":\"Outage in the us-east-1 region\",\"end_at\":\"2025-09-12T14:50:00Z\",\"fields\":null,\"impact_type\":\"customer\",\"modified\":\"2025-09-16T19:47:18.208811Z\",\"start_at\":\"2025-09-12T13:50:00Z\"},\"relationships\":{\"created_by_user\":{\"data\":{\"id\":\"3ad549bf-eba0-11e9-a77a-0705486660d0\",\"type\":\"users\"}},\"incident\":{\"data\":{\"id\":\"1a838ffb-9c95-5df6-978c-4cf21f854fd1\",\"type\":\"incidents\"}},\"last_modified_by_user\":{\"data\":{\"id\":\"3ad549bf-eba0-11e9-a77a-0705486660d0\",\"type\":\"users\"}}}}}", + "encoding": null + }, + "headers": { + "Content-Type": [ + "application/vnd.api+json" + ] + }, + "status": { + "code": 201, + "message": "Created" + } + }, + "recorded_at": "Tue, 16 Sep 2025 19:47:17 GMT" + }, + { + "request": { + "body": "", + "headers": { + "Accept": [ + "*/*" + ] + }, + "method": "delete", + "uri": "https://api.datadoghq.com/api/v2/incidents/1a838ffb-9c95-5df6-978c-4cf21f854fd1/impacts/db11b25d-0383-4f98-bde7-bfc4a10d16eb" + }, + "response": { + "body": { + "string": "", + "encoding": null + }, + "headers": {}, + "status": { + "code": 204, + "message": "No Content" + } + }, + "recorded_at": "Tue, 16 Sep 2025 19:47:17 GMT" + }, + { + "request": { + "body": "", + "headers": { + "Accept": [ + "*/*" + ] + }, + "method": "delete", + "uri": "https://api.datadoghq.com/api/v2/incidents/1a838ffb-9c95-5df6-978c-4cf21f854fd1/impacts/db11b25d-0383-4f98-bde7-bfc4a10d16eb" + }, + "response": { + "body": { + "string": "{\"errors\":[{\"title\":\"Generic Error\",\"detail\":\"rpc error: code = NotFound desc = impact not found: impact not found\"}]}", + "encoding": null + }, + "headers": { + "Content-Type": [ + "application/vnd.api+json" + ] + }, + "status": { + "code": 404, + "message": "Not Found" + } + }, + "recorded_at": "Tue, 16 Sep 2025 19:47:17 GMT" + }, + { + "request": { + "body": "", + "headers": { + "Accept": [ + "*/*" + ] + }, + "method": "delete", + "uri": "https://api.datadoghq.com/api/v2/incidents/1a838ffb-9c95-5df6-978c-4cf21f854fd1" + }, + "response": { + "body": { + "string": "", + "encoding": null + }, + "headers": { + "Content-Type": [ + "text/html; charset=utf-8" + ] + }, + "status": { + "code": 204, + "message": "No Content" + } + }, + "recorded_at": "Tue, 16 Sep 2025 19:47:17 GMT" + } + ], + "recorded_with": "VCR 6.0.0" +} \ No newline at end of file diff --git a/tests/scenarios/cassettes/v2/incidents/Delete-an-incident-impact-returns-Not-Found-response-different-invalid-IDs-.frozen b/tests/scenarios/cassettes/v2/incidents/Delete-an-incident-impact-returns-Not-Found-response-different-invalid-IDs-.frozen new file mode 100644 index 000000000..81d2f935c --- /dev/null +++ b/tests/scenarios/cassettes/v2/incidents/Delete-an-incident-impact-returns-Not-Found-response-different-invalid-IDs-.frozen @@ -0,0 +1 @@ +2025-09-16T14:11:22.028Z \ No newline at end of file diff --git a/tests/scenarios/cassettes/v2/incidents/Delete-an-incident-impact-returns-Not-Found-response-different-invalid-IDs-.json b/tests/scenarios/cassettes/v2/incidents/Delete-an-incident-impact-returns-Not-Found-response-different-invalid-IDs-.json new file mode 100644 index 000000000..c274404e5 --- /dev/null +++ b/tests/scenarios/cassettes/v2/incidents/Delete-an-incident-impact-returns-Not-Found-response-different-invalid-IDs-.json @@ -0,0 +1,33 @@ +{ + "http_interactions": [ + { + "request": { + "body": "", + "headers": { + "Accept": [ + "*/*" + ] + }, + "method": "delete", + "uri": "https://api.datadoghq.com/api/v2/incidents/00000000-0000-0000-0000-000000000002/impacts/00000000-0000-0000-0000-000000000002" + }, + "response": { + "body": { + "string": "{\"errors\":[{\"title\":\"Generic Error\",\"detail\":\"rpc error: code = NotFound desc = impact not found: impact not found\"}]}", + "encoding": null + }, + "headers": { + "Content-Type": [ + "application/vnd.api+json" + ] + }, + "status": { + "code": 404, + "message": "Not Found" + } + }, + "recorded_at": "Tue, 16 Sep 2025 14:11:22 GMT" + } + ], + "recorded_with": "VCR 6.0.0" +} \ No newline at end of file diff --git a/tests/scenarios/cassettes/v2/incidents/Delete-an-incident-impact-returns-Not-Found-response-invalid-incident-and-impact-.frozen b/tests/scenarios/cassettes/v2/incidents/Delete-an-incident-impact-returns-Not-Found-response-invalid-incident-and-impact-.frozen new file mode 100644 index 000000000..17375a815 --- /dev/null +++ b/tests/scenarios/cassettes/v2/incidents/Delete-an-incident-impact-returns-Not-Found-response-invalid-incident-and-impact-.frozen @@ -0,0 +1 @@ +2025-09-16T14:11:00.035Z \ No newline at end of file diff --git a/tests/scenarios/cassettes/v2/incidents/Delete-an-incident-impact-returns-Not-Found-response-invalid-incident-and-impact-.json b/tests/scenarios/cassettes/v2/incidents/Delete-an-incident-impact-returns-Not-Found-response-invalid-incident-and-impact-.json new file mode 100644 index 000000000..4d89f7ff0 --- /dev/null +++ b/tests/scenarios/cassettes/v2/incidents/Delete-an-incident-impact-returns-Not-Found-response-invalid-incident-and-impact-.json @@ -0,0 +1,33 @@ +{ + "http_interactions": [ + { + "request": { + "body": "", + "headers": { + "Accept": [ + "*/*" + ] + }, + "method": "delete", + "uri": "https://api.datadoghq.com/api/v2/incidents/00000000-0000-0000-0000-000000000000/impacts/00000000-0000-0000-0000-000000000000" + }, + "response": { + "body": { + "string": "{\"errors\":[{\"title\":\"Generic Error\",\"detail\":\"rpc error: code = NotFound desc = impact not found: impact not found\"}]}", + "encoding": null + }, + "headers": { + "Content-Type": [ + "application/vnd.api+json" + ] + }, + "status": { + "code": 404, + "message": "Not Found" + } + }, + "recorded_at": "Tue, 16 Sep 2025 14:11:00 GMT" + } + ], + "recorded_with": "VCR 6.0.0" +} \ No newline at end of file diff --git a/tests/scenarios/cassettes/v2/incidents/Delete-an-incident-impact-returns-Not-Found-response.frozen b/tests/scenarios/cassettes/v2/incidents/Delete-an-incident-impact-returns-Not-Found-response.frozen new file mode 100644 index 000000000..849419447 --- /dev/null +++ b/tests/scenarios/cassettes/v2/incidents/Delete-an-incident-impact-returns-Not-Found-response.frozen @@ -0,0 +1 @@ +2025-09-16T19:47:29.411Z \ No newline at end of file diff --git a/tests/scenarios/cassettes/v2/incidents/Delete-an-incident-impact-returns-Not-Found-response.json b/tests/scenarios/cassettes/v2/incidents/Delete-an-incident-impact-returns-Not-Found-response.json new file mode 100644 index 000000000..2f702cf87 --- /dev/null +++ b/tests/scenarios/cassettes/v2/incidents/Delete-an-incident-impact-returns-Not-Found-response.json @@ -0,0 +1,33 @@ +{ + "http_interactions": [ + { + "request": { + "body": "", + "headers": { + "Accept": [ + "*/*" + ] + }, + "method": "delete", + "uri": "https://api.datadoghq.com/api/v2/incidents/00000000-0000-0000-0000-000000000001/impacts/00000000-0000-0000-0000-000000000001" + }, + "response": { + "body": { + "string": "{\"errors\":[{\"title\":\"Generic Error\",\"detail\":\"rpc error: code = NotFound desc = impact not found: impact not found\"}]}", + "encoding": null + }, + "headers": { + "Content-Type": [ + "application/vnd.api+json" + ] + }, + "status": { + "code": 404, + "message": "Not Found" + } + }, + "recorded_at": "Tue, 16 Sep 2025 19:47:29 GMT" + } + ], + "recorded_with": "VCR 6.0.0" +} \ No newline at end of file diff --git a/tests/scenarios/cassettes/v2/incidents/List-an-incident-s-impacts-returns-OK-response.frozen b/tests/scenarios/cassettes/v2/incidents/List-an-incident-s-impacts-returns-OK-response.frozen new file mode 100644 index 000000000..55431a90f --- /dev/null +++ b/tests/scenarios/cassettes/v2/incidents/List-an-incident-s-impacts-returns-OK-response.frozen @@ -0,0 +1 @@ +2025-09-16T19:47:40.461Z \ No newline at end of file diff --git a/tests/scenarios/cassettes/v2/incidents/List-an-incident-s-impacts-returns-OK-response.json b/tests/scenarios/cassettes/v2/incidents/List-an-incident-s-impacts-returns-OK-response.json new file mode 100644 index 000000000..8fc7dd61b --- /dev/null +++ b/tests/scenarios/cassettes/v2/incidents/List-an-incident-s-impacts-returns-OK-response.json @@ -0,0 +1,95 @@ +{ + "http_interactions": [ + { + "request": { + "body": { + "string": "{\"data\":{\"attributes\":{\"customer_impacted\":false,\"title\":\"Test-List_an_incident_s_impacts_returns_OK_response-1758052060\"},\"type\":\"incidents\"}}", + "encoding": null + }, + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json" + ] + }, + "method": "post", + "uri": "https://api.datadoghq.com/api/v2/incidents" + }, + "response": { + "body": { + "string": "{\"data\":{\"type\":\"incidents\",\"id\":\"81b6cd9f-526a-5a08-a204-ac402f36ea5f\",\"attributes\":{\"public_id\":309853,\"incident_type_uuid\":\"41d2e10b-4108-4736-92d7-791d00ea0702\",\"title\":\"Test-List_an_incident_s_impacts_returns_OK_response-1758052060\",\"resolved\":null,\"customer_impact_scope\":null,\"customer_impact_start\":null,\"customer_impact_end\":null,\"customer_impacted\":false,\"notification_handles\":null,\"last_modified_by\":{\"data\":{\"type\":\"users\",\"id\":\"3ad549bf-eba0-11e9-a77a-0705486660d0\",\"attributes\":{\"uuid\":\"3ad549bf-eba0-11e9-a77a-0705486660d0\",\"handle\":\"frog@datadoghq.com\",\"email\":\"frog@datadoghq.com\",\"name\":\"frog\",\"icon\":\"https://secure.gravatar.com/avatar/28a16dfe36e73b60c1d55872cb0f1172?s=48&d=retro\"}}},\"last_modified_by_uuid\":null,\"created\":\"2025-09-16T19:47:40.679710+00:00\",\"modified\":\"2025-09-16T19:47:40.679710+00:00\",\"commander\":null,\"detected\":\"2025-09-16T19:47:40.668385+00:00\",\"created_by\":{\"data\":{\"type\":\"users\",\"id\":\"3ad549bf-eba0-11e9-a77a-0705486660d0\",\"attributes\":{\"uuid\":\"3ad549bf-eba0-11e9-a77a-0705486660d0\",\"handle\":\"frog@datadoghq.com\",\"email\":\"frog@datadoghq.com\",\"name\":\"frog\",\"icon\":\"https://secure.gravatar.com/avatar/28a16dfe36e73b60c1d55872cb0f1172?s=48&d=retro\"}}},\"created_by_uuid\":null,\"creation_idempotency_key\":null,\"customer_impact_duration\":0,\"time_to_detect\":0,\"time_to_repair\":0,\"time_to_internal_response\":0,\"time_to_resolve\":0,\"archived\":null,\"is_test\":false,\"declared\":\"2025-09-16T19:47:40.679710+00:00\",\"declared_by\":{\"data\":{\"type\":\"users\",\"id\":\"3ad549bf-eba0-11e9-a77a-0705486660d0\",\"attributes\":{\"uuid\":\"3ad549bf-eba0-11e9-a77a-0705486660d0\",\"handle\":\"frog@datadoghq.com\",\"email\":\"frog@datadoghq.com\",\"name\":\"frog\",\"icon\":\"https://secure.gravatar.com/avatar/28a16dfe36e73b60c1d55872cb0f1172?s=48&d=retro\"}}},\"declared_by_uuid\":null,\"fields\":{\"severity\":{\"type\":\"dropdown\",\"value\":\"UNKNOWN\"},\"state\":{\"type\":\"dropdown\",\"value\":\"active\"},\"detection_method\":{\"type\":\"dropdown\",\"value\":\"unknown\"},\"root_cause\":{\"type\":\"textbox\",\"value\":null},\"summary\":{\"type\":\"textbox\",\"value\":null},\"services\":{\"type\":\"autocomplete\",\"value\":null},\"teams\":{\"type\":\"autocomplete\",\"value\":null}},\"field_analytics\":null,\"severity\":\"UNKNOWN\",\"state\":\"active\",\"non_datadog_creator\":null,\"visibility\":\"organization\",\"case_id\":null},\"relationships\":{\"created_by_user\":{\"data\":{\"type\":\"users\",\"id\":\"3ad549bf-eba0-11e9-a77a-0705486660d0\"}},\"last_modified_by_user\":{\"data\":{\"type\":\"users\",\"id\":\"3ad549bf-eba0-11e9-a77a-0705486660d0\"}},\"commander_user\":{\"data\":null},\"declared_by_user\":{\"data\":{\"type\":\"users\",\"id\":\"3ad549bf-eba0-11e9-a77a-0705486660d0\"}},\"user_defined_fields\":{\"data\":[{\"type\":\"user_defined_field\",\"id\":\"33457d2a-570c-5567-b4af-979a2a8f1164\"},{\"type\":\"user_defined_field\",\"id\":\"d003693c-bee9-5420-8d46-859269c20914\"},{\"type\":\"user_defined_field\",\"id\":\"1ddff6f6-cb1f-51a0-9d81-dc18ef52cc9d\"},{\"type\":\"user_defined_field\",\"id\":\"6bc9d32b-c2cd-591e-9b7a-74c886a5ddcf\"},{\"type\":\"user_defined_field\",\"id\":\"95c53547-2ba3-5d8a-9c3b-cf245bc0c629\"},{\"type\":\"user_defined_field\",\"id\":\"39044b03-cee4-555f-b1e0-3eb3aa759a86\"},{\"type\":\"user_defined_field\",\"id\":\"3cbe9e60-d794-532c-acc0-73641f782813\"}]},\"integrations\":{\"data\":[]},\"attachments\":{\"data\":[]},\"responders\":{\"data\":[]},\"impacts\":{\"data\":[]}}}}\n", + "encoding": null + }, + "headers": { + "Content-Type": [ + "application/json" + ] + }, + "status": { + "code": 201, + "message": "Created" + } + }, + "recorded_at": "Tue, 16 Sep 2025 19:47:40 GMT" + }, + { + "request": { + "body": "", + "headers": { + "Accept": [ + "application/json" + ] + }, + "method": "get", + "uri": "https://api.datadoghq.com/api/v2/incidents/81b6cd9f-526a-5a08-a204-ac402f36ea5f/impacts" + }, + "response": { + "body": { + "string": "{\"data\":[]}", + "encoding": null + }, + "headers": { + "Content-Type": [ + "application/vnd.api+json" + ] + }, + "status": { + "code": 200, + "message": "OK" + } + }, + "recorded_at": "Tue, 16 Sep 2025 19:47:40 GMT" + }, + { + "request": { + "body": "", + "headers": { + "Accept": [ + "*/*" + ] + }, + "method": "delete", + "uri": "https://api.datadoghq.com/api/v2/incidents/81b6cd9f-526a-5a08-a204-ac402f36ea5f" + }, + "response": { + "body": { + "string": "", + "encoding": null + }, + "headers": { + "Content-Type": [ + "text/html; charset=utf-8" + ] + }, + "status": { + "code": 204, + "message": "No Content" + } + }, + "recorded_at": "Tue, 16 Sep 2025 19:47:40 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 a4872ca4d..06f7f855c 100644 --- a/tests/scenarios/features/v2/given.json +++ b/tests/scenarios/features/v2/given.json @@ -329,6 +329,22 @@ "tag": "Incidents", "operationId": "UpdateIncidentAttachments" }, + { + "operationId": "CreateIncidentImpact", + "parameters": [ + { + "name": "incident_id", + "source": "incident.data.id" + }, + { + "name": "body", + "value": "{\n \"data\": {\n \"type\": \"incident_impacts\",\n \"attributes\": {\n \"start_at\": \"2025-09-12T13:50:00.000Z\",\n \"end_at\": \"2025-09-12T14:50:00.000Z\",\n \"description\": \"Outage in the us-east-1 region\"\n }\n }\n}" + } + ], + "step": "the \"incident\" has an \"incident_impact\"", + "key": "incident_impact", + "tag": "Incidents" + }, { "parameters": [ { diff --git a/tests/scenarios/features/v2/incidents.feature b/tests/scenarios/features/v2/incidents.feature index 4f278f281..74ae96596 100644 --- a/tests/scenarios/features/v2/incidents.feature +++ b/tests/scenarios/features/v2/incidents.feature @@ -35,6 +35,36 @@ Feature: Incidents And the response "data[0].attributes.attachment_type" is equal to "link" And the response "data[0].attributes.attachment.documentUrl" is equal to "https://www.example.com/doc" + @skip @team:DataDog/incident-app + Scenario: Create an incident impact returns "Bad Request" response + Given operation "CreateIncidentImpact" enabled + And new "CreateIncidentImpact" request + And request contains "incident_id" parameter with value "00000000-0000-0000-0000-000000000000" + And body with value {"data": {"attributes": {"description": "Service was unavailable for external users", "end_at": "2025-08-29T13:17:00Z", "fields": {"customers_impacted": "all", "products_impacted": ["shopping", "marketing"]}, "start_at": "2025-08-28T13:17:00Z"}, "type": "incident_impacts"}} + When the request is sent + Then the response status is 400 Bad Request + + @skip @team:DataDog/incident-app + Scenario: Create an incident impact returns "CREATED" response + Given there is a valid "incident" in the system + And operation "CreateIncidentImpact" enabled + And new "CreateIncidentImpact" request + And request contains "incident_id" parameter from "incident.data.id" + And body with value {"data": {"type": "incident_impacts", "attributes": {"start_at": "2025-09-12T13:50:00.000Z", "end_at": "2025-09-12T14:50:00.000Z", "description": "Outage in the us-east-1 region"}}} + When the request is sent + Then the response status is 201 CREATED + And the response "data.type" is equal to "incident_impacts" + And the response "data.relationships.incident.data.id" has the same value as "incident.data.id" + + @skip @team:DataDog/incident-app + Scenario: Create an incident impact returns "Not Found" response + Given operation "CreateIncidentImpact" enabled + And new "CreateIncidentImpact" request + And request contains "incident_id" parameter with value "00000000-0000-0000-0000-000000000001" + And body with value {"data": {"attributes": {"description": "Service was unavailable for external users", "end_at": "2025-08-29T13:17:00Z", "fields": {"customers_impacted": "all", "products_impacted": ["shopping", "marketing"]}, "start_at": "2025-08-28T13:17:00Z"}, "type": "incident_impacts"}} + When the request is sent + Then the response status is 404 Not Found + @generated @skip @team:DataDog/incident-app Scenario: Create an incident integration metadata returns "Bad Request" response Given operation "CreateIncidentIntegration" enabled @@ -295,6 +325,26 @@ Feature: Incidents When the request is sent Then the response status is 204 OK + @skip @team:DataDog/incident-app + Scenario: Delete an incident impact returns "No Content" response + Given there is a valid "incident" in the system + And the "incident" has an "incident_impact" + And operation "DeleteIncidentImpact" enabled + And new "DeleteIncidentImpact" request + And request contains "incident_id" parameter from "incident_impact.data.relationships.incident.data.id" + And request contains "impact_id" parameter from "incident_impact.data.id" + When the request is sent + Then the response status is 204 No Content + + @skip @team:DataDog/incident-app + Scenario: Delete an incident impact returns "Not Found" response + Given operation "DeleteIncidentImpact" enabled + And new "DeleteIncidentImpact" request + And request contains "incident_id" parameter with value "00000000-0000-0000-0000-000000000001" + And request contains "impact_id" parameter with value "00000000-0000-0000-0000-000000000001" + When the request is sent + Then the response status is 404 Not Found + @generated @skip @team:DataDog/incident-app Scenario: Delete an incident integration metadata returns "Bad Request" response Given operation "DeleteIncidentIntegration" enabled @@ -754,6 +804,31 @@ Feature: Incidents Then the response status is 200 OK And the response "data.attributes.title" has the same value as "incident.data.attributes.title" + @generated @skip @team:DataDog/incident-app + Scenario: List an incident's impacts returns "Bad Request" response + Given operation "ListIncidentImpacts" enabled + And new "ListIncidentImpacts" request + And request contains "incident_id" parameter from "REPLACE.ME" + When the request is sent + Then the response status is 400 Bad Request + + @generated @skip @team:DataDog/incident-app + Scenario: List an incident's impacts returns "Not Found" response + Given operation "ListIncidentImpacts" enabled + And new "ListIncidentImpacts" request + And request contains "incident_id" parameter from "REPLACE.ME" + When the request is sent + Then the response status is 404 Not Found + + @skip @team:DataDog/incident-app + Scenario: List an incident's impacts returns "OK" response + Given there is a valid "incident" in the system + And operation "ListIncidentImpacts" enabled + And new "ListIncidentImpacts" request + And request contains "incident_id" parameter from "incident.data.id" + When the request is sent + Then the response status is 200 OK + @generated @skip @team:Datadog/incident-app Scenario: List incident notification rules returns "Bad Request" response Given operation "ListIncidentNotificationRules" enabled diff --git a/tests/scenarios/features/v2/undo.json b/tests/scenarios/features/v2/undo.json index 9aa936bc9..b2fe236d0 100644 --- a/tests/scenarios/features/v2/undo.json +++ b/tests/scenarios/features/v2/undo.json @@ -1297,6 +1297,35 @@ "type": "idempotent" } }, + "ListIncidentImpacts": { + "tag": "Incidents", + "undo": { + "type": "safe" + } + }, + "CreateIncidentImpact": { + "tag": "Incidents", + "undo": { + "operationId": "DeleteIncidentImpact", + "parameters": [ + { + "name": "incident_id", + "source": "data.relationships.incident.data.id" + }, + { + "name": "impact_id", + "source": "data.id" + } + ], + "type": "unsafe" + } + }, + "DeleteIncidentImpact": { + "tag": "Incidents", + "undo": { + "type": "idempotent" + } + }, "ListIncidentIntegrations": { "tag": "Incidents", "undo": { diff --git a/tests/scenarios/function_mappings.rs b/tests/scenarios/function_mappings.rs index e825244a7..8354972e6 100644 --- a/tests/scenarios/function_mappings.rs +++ b/tests/scenarios/function_mappings.rs @@ -2755,6 +2755,18 @@ pub fn collect_function_calls(world: &mut DatadogWorld) { "v2.UpdateIncidentAttachments".into(), test_v2_update_incident_attachments, ); + world.function_mappings.insert( + "v2.ListIncidentImpacts".into(), + test_v2_list_incident_impacts, + ); + world.function_mappings.insert( + "v2.CreateIncidentImpact".into(), + test_v2_create_incident_impact, + ); + world.function_mappings.insert( + "v2.DeleteIncidentImpact".into(), + test_v2_delete_incident_impact, + ); world.function_mappings.insert( "v2.ListIncidentIntegrations".into(), test_v2_list_incident_integrations, @@ -20652,6 +20664,98 @@ fn test_v2_update_incident_attachments( world.response.code = response.status.as_u16(); } +fn test_v2_list_incident_impacts(world: &mut DatadogWorld, _parameters: &HashMap) { + let api = world + .api_instances + .v2_api_incidents + .as_ref() + .expect("api instance not found"); + let incident_id = + serde_json::from_value(_parameters.get("incident_id").unwrap().clone()).unwrap(); + let include = _parameters + .get("include") + .and_then(|param| Some(serde_json::from_value(param.clone()).unwrap())); + let mut params = datadogV2::api_incidents::ListIncidentImpactsOptionalParams::default(); + params.include = include; + let response = match block_on(api.list_incident_impacts_with_http_info(incident_id, params)) { + 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_create_incident_impact(world: &mut DatadogWorld, _parameters: &HashMap) { + let api = world + .api_instances + .v2_api_incidents + .as_ref() + .expect("api instance not found"); + let incident_id = + serde_json::from_value(_parameters.get("incident_id").unwrap().clone()).unwrap(); + let body = serde_json::from_value(_parameters.get("body").unwrap().clone()).unwrap(); + let include = _parameters + .get("include") + .and_then(|param| Some(serde_json::from_value(param.clone()).unwrap())); + let mut params = datadogV2::api_incidents::CreateIncidentImpactOptionalParams::default(); + params.include = include; + let response = + match block_on(api.create_incident_impact_with_http_info(incident_id, body, params)) { + 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_delete_incident_impact(world: &mut DatadogWorld, _parameters: &HashMap) { + let api = world + .api_instances + .v2_api_incidents + .as_ref() + .expect("api instance not found"); + let incident_id = + serde_json::from_value(_parameters.get("incident_id").unwrap().clone()).unwrap(); + let impact_id = serde_json::from_value(_parameters.get("impact_id").unwrap().clone()).unwrap(); + let response = match block_on(api.delete_incident_impact_with_http_info(incident_id, impact_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_list_incident_integrations( world: &mut DatadogWorld, _parameters: &HashMap,