From 950f30f15d76557cd61d8d9f6426ece1112084f8 Mon Sep 17 00:00:00 2001 From: "ci.datadog-api-spec" Date: Thu, 31 Oct 2024 16:09:35 +0000 Subject: [PATCH] Regenerate client from commit a11da7b5 of spec repo --- .apigentools-info | 8 +- .generator/schemas/v2/openapi.yaml | 132 +++++++++++++ ...age-metering_GetBillingDimensionMapping.rs | 19 ++ src/datadog/configuration.rs | 1 + src/datadogV2/api/api_usage_metering.rs | 174 ++++++++++++++++++ src/datadogV2/model/mod.rs | 10 + ...el_billing_dimensions_mapping_body_item.rs | 152 +++++++++++++++ ...dimensions_mapping_body_item_attributes.rs | 147 +++++++++++++++ ...ng_body_item_attributes_endpoints_items.rs | 153 +++++++++++++++ ..._item_attributes_endpoints_items_status.rs | 51 +++++ ...del_billing_dimensions_mapping_response.rs | 110 +++++++++++ ...points-returns-Bad-Request-response.frozen | 1 + ...ndpoints-returns-Bad-Request-response.json | 33 ++++ tests/scenarios/features/v2/undo.json | 6 + .../features/v2/usage_metering.feature | 14 ++ tests/scenarios/function_mappings.rs | 41 +++++ 16 files changed, 1048 insertions(+), 4 deletions(-) create mode 100644 examples/v2_usage-metering_GetBillingDimensionMapping.rs create mode 100644 src/datadogV2/model/model_billing_dimensions_mapping_body_item.rs create mode 100644 src/datadogV2/model/model_billing_dimensions_mapping_body_item_attributes.rs create mode 100644 src/datadogV2/model/model_billing_dimensions_mapping_body_item_attributes_endpoints_items.rs create mode 100644 src/datadogV2/model/model_billing_dimensions_mapping_body_item_attributes_endpoints_items_status.rs create mode 100644 src/datadogV2/model/model_billing_dimensions_mapping_response.rs create mode 100644 tests/scenarios/cassettes/v2/usage_metering/Get-billing-dimension-mapping-for-usage-endpoints-returns-Bad-Request-response.frozen create mode 100644 tests/scenarios/cassettes/v2/usage_metering/Get-billing-dimension-mapping-for-usage-endpoints-returns-Bad-Request-response.json diff --git a/.apigentools-info b/.apigentools-info index befb4fc5b..603b2f7bc 100644 --- a/.apigentools-info +++ b/.apigentools-info @@ -4,13 +4,13 @@ "spec_versions": { "v1": { "apigentools_version": "1.6.6", - "regenerated": "2024-10-31 15:33:04.806229", - "spec_repo_commit": "a7602fa1" + "regenerated": "2024-10-31 16:03:52.395794", + "spec_repo_commit": "a11da7b5" }, "v2": { "apigentools_version": "1.6.6", - "regenerated": "2024-10-31 15:33:04.824708", - "spec_repo_commit": "a7602fa1" + "regenerated": "2024-10-31 16:03:52.415002", + "spec_repo_commit": "a11da7b5" } } } \ No newline at end of file diff --git a/.generator/schemas/v2/openapi.yaml b/.generator/schemas/v2/openapi.yaml index 7f9b23070..61de273a3 100644 --- a/.generator/schemas/v2/openapi.yaml +++ b/.generator/schemas/v2/openapi.yaml @@ -2186,6 +2186,74 @@ components: - storage_account - storage_container type: object + BillingDimensionsMappingBody: + description: Billing dimensions mapping data. + items: + $ref: '#/components/schemas/BillingDimensionsMappingBodyItem' + type: array + BillingDimensionsMappingBodyItem: + description: The mapping data for each billing dimension. + properties: + attributes: + $ref: '#/components/schemas/BillingDimensionsMappingBodyItemAttributes' + id: + description: ID of the billing dimension. + type: string + type: + $ref: '#/components/schemas/ActiveBillingDimensionsType' + type: object + BillingDimensionsMappingBodyItemAttributes: + description: Mapping of billing dimensions to endpoint keys. + properties: + endpoints: + description: List of supported endpoints with their keys mapped to the billing_dimension. + items: + $ref: '#/components/schemas/BillingDimensionsMappingBodyItemAttributesEndpointsItems' + type: array + in_app_label: + description: Label used for the billing dimension in the Plan & Usage charts. + example: APM Hosts + type: string + timestamp: + description: 'Month in ISO-8601 format, UTC, and precise to the second: + `[YYYY-MM-DDThh:mm:ss]`.' + format: date-time + type: string + type: object + BillingDimensionsMappingBodyItemAttributesEndpointsItems: + description: An endpoint's keys mapped to the billing_dimension. + properties: + id: + description: The URL for the endpoint. + example: api/v1/usage/billable-summary + type: string + keys: + description: The billing dimension. + example: + - apm_host_top99p + - apm_host_sum + items: + example: apm_host_top99p + type: string + type: array + status: + $ref: '#/components/schemas/BillingDimensionsMappingBodyItemAttributesEndpointsItemsStatus' + type: object + BillingDimensionsMappingBodyItemAttributesEndpointsItemsStatus: + description: Denotes whether mapping keys were available for this endpoint. + enum: + - OK + - NOT_FOUND + type: string + x-enum-varnames: + - OK + - NOT_FOUND + BillingDimensionsMappingResponse: + description: Billing dimensions mapping response. + properties: + data: + $ref: '#/components/schemas/BillingDimensionsMappingBody' + type: object BulkMuteFindingsRequest: description: The new bulk mute finding request. properties: @@ -41037,6 +41105,70 @@ paths: operator: OR permissions: - usage_read + /api/v2/usage/billing_dimension_mapping: + get: + description: 'Get a mapping of billing dimensions to the corresponding keys + for the supported usage metering public API endpoints. + + Mapping data is updated on a monthly cadence. + + + This endpoint is only accessible to [parent-level organizations](https://docs.datadoghq.com/account_management/multi_organization/).' + operationId: GetBillingDimensionMapping + parameters: + - description: Datetime in ISO-8601 format, UTC, and for mappings beginning + this month. Defaults to the current month. + in: query + name: filter[month] + required: false + schema: + format: date-time + type: string + - description: String to specify whether to retrieve active billing dimension + mappings for the contract or for all available mappings. Allowed views have + the string `active` or `all`. Defaults to `active`. + in: query + name: filter[view] + required: false + schema: + default: active + type: string + responses: + '200': + content: + application/json;datetime-format=rfc3339: + schema: + $ref: '#/components/schemas/BillingDimensionsMappingResponse' + description: OK + '400': + content: + application/json;datetime-format=rfc3339: + schema: + $ref: '#/components/schemas/APIErrorResponse' + description: Bad Request + '403': + content: + application/json;datetime-format=rfc3339: + schema: + $ref: '#/components/schemas/APIErrorResponse' + description: Forbidden - User is not authorized + '429': + content: + application/json;datetime-format=rfc3339: + schema: + $ref: '#/components/schemas/APIErrorResponse' + description: Too many requests + security: + - apiKeyAuth: [] + appKeyAuth: [] + - AuthZ: + - usage_read + summary: Get billing dimension mapping for usage endpoints + tags: + - Usage Metering + x-unstable: '**Note**: This endpoint is in Preview. + + If you have any feedback, contact [Datadog support](https://docs.datadoghq.com/help/).' /api/v2/usage/cost_by_org: get: deprecated: true diff --git a/examples/v2_usage-metering_GetBillingDimensionMapping.rs b/examples/v2_usage-metering_GetBillingDimensionMapping.rs new file mode 100644 index 000000000..8ac80bf84 --- /dev/null +++ b/examples/v2_usage-metering_GetBillingDimensionMapping.rs @@ -0,0 +1,19 @@ +// Get billing dimension mapping for usage endpoints returns "OK" response +use datadog_api_client::datadog; +use datadog_api_client::datadogV2::api_usage_metering::GetBillingDimensionMappingOptionalParams; +use datadog_api_client::datadogV2::api_usage_metering::UsageMeteringAPI; + +#[tokio::main] +async fn main() { + let mut configuration = datadog::Configuration::new(); + configuration.set_unstable_operation_enabled("v2.GetBillingDimensionMapping", true); + let api = UsageMeteringAPI::with_config(configuration); + let resp = api + .get_billing_dimension_mapping(GetBillingDimensionMappingOptionalParams::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 1ac7e0bb0..d490acb2c 100644 --- a/src/datadog/configuration.rs +++ b/src/datadog/configuration.rs @@ -135,6 +135,7 @@ impl Default for Configuration { ("v2.list_apis".to_owned(), false), ("v2.update_open_api".to_owned(), false), ("v2.get_active_billing_dimensions".to_owned(), false), + ("v2.get_billing_dimension_mapping".to_owned(), false), ("v2.get_monthly_cost_attribution".to_owned(), false), ("v2.create_dora_deployment".to_owned(), false), ("v2.create_dora_incident".to_owned(), false), diff --git a/src/datadogV2/api/api_usage_metering.rs b/src/datadogV2/api/api_usage_metering.rs index f4f30832a..68c9ad315 100644 --- a/src/datadogV2/api/api_usage_metering.rs +++ b/src/datadogV2/api/api_usage_metering.rs @@ -6,6 +6,29 @@ use log::warn; use reqwest::header::{HeaderMap, HeaderValue}; use serde::{Deserialize, Serialize}; +/// GetBillingDimensionMappingOptionalParams is a struct for passing parameters to the method [`UsageMeteringAPI::get_billing_dimension_mapping`] +#[non_exhaustive] +#[derive(Clone, Default, Debug)] +pub struct GetBillingDimensionMappingOptionalParams { + /// Datetime in ISO-8601 format, UTC, and for mappings beginning this month. Defaults to the current month. + pub filter_month: Option>, + /// String to specify whether to retrieve active billing dimension mappings for the contract or for all available mappings. Allowed views have the string `active` or `all`. Defaults to `active`. + pub filter_view: Option, +} + +impl GetBillingDimensionMappingOptionalParams { + /// Datetime in ISO-8601 format, UTC, and for mappings beginning this month. Defaults to the current month. + pub fn filter_month(mut self, value: chrono::DateTime) -> Self { + self.filter_month = Some(value); + self + } + /// String to specify whether to retrieve active billing dimension mappings for the contract or for all available mappings. Allowed views have the string `active` or `all`. Defaults to `active`. + pub fn filter_view(mut self, value: String) -> Self { + self.filter_view = Some(value); + self + } +} + /// GetCostByOrgOptionalParams is a struct for passing parameters to the method [`UsageMeteringAPI::get_cost_by_org`] #[non_exhaustive] #[derive(Clone, Default, Debug)] @@ -303,6 +326,14 @@ pub enum GetActiveBillingDimensionsError { UnknownValue(serde_json::Value), } +/// GetBillingDimensionMappingError is a struct for typed errors of method [`UsageMeteringAPI::get_billing_dimension_mapping`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum GetBillingDimensionMappingError { + APIErrorResponse(crate::datadogV2::model::APIErrorResponse), + UnknownValue(serde_json::Value), +} + /// GetCostByOrgError is a struct for typed errors of method [`UsageMeteringAPI::get_cost_by_org`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] @@ -566,6 +597,149 @@ impl UsageMeteringAPI { } } + /// Get a mapping of billing dimensions to the corresponding keys for the supported usage metering public API endpoints. + /// Mapping data is updated on a monthly cadence. + /// + /// This endpoint is only accessible to [parent-level organizations](). + pub async fn get_billing_dimension_mapping( + &self, + params: GetBillingDimensionMappingOptionalParams, + ) -> Result< + crate::datadogV2::model::BillingDimensionsMappingResponse, + datadog::Error, + > { + match self + .get_billing_dimension_mapping_with_http_info(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 a mapping of billing dimensions to the corresponding keys for the supported usage metering public API endpoints. + /// Mapping data is updated on a monthly cadence. + /// + /// This endpoint is only accessible to [parent-level organizations](). + pub async fn get_billing_dimension_mapping_with_http_info( + &self, + params: GetBillingDimensionMappingOptionalParams, + ) -> Result< + datadog::ResponseContent, + datadog::Error, + > { + let local_configuration = &self.config; + let operation_id = "v2.get_billing_dimension_mapping"; + if local_configuration.is_unstable_operation_enabled(operation_id) { + warn!("Using unstable operation {operation_id}"); + } else { + let local_error = datadog::UnstableOperationDisabledError { + msg: "Operation 'v2.get_billing_dimension_mapping' is not enabled".to_string(), + }; + return Err(datadog::Error::UnstableOperationDisabledError(local_error)); + } + + // unbox and build optional parameters + let filter_month = params.filter_month; + let filter_view = params.filter_view; + + let local_client = &self.client; + + let local_uri_str = format!( + "{}/api/v2/usage/billing_dimension_mapping", + local_configuration.get_operation_host(operation_id) + ); + let mut local_req_builder = + local_client.request(reqwest::Method::GET, local_uri_str.as_str()); + + if let Some(ref local_query_param) = filter_month { + local_req_builder = local_req_builder.query(&[( + "filter[month]", + &local_query_param.to_rfc3339_opts(chrono::SecondsFormat::Millis, true), + )]); + }; + if let Some(ref local_query_param) = filter_view { + local_req_builder = + local_req_builder.query(&[("filter[view]", &local_query_param.to_string())]); + }; + + // build headers + let mut headers = HeaderMap::new(); + headers.insert( + "Accept", + HeaderValue::from_static("application/json;datetime-format=rfc3339"), + ); + + // 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 cost across multi-org account. /// Cost by org data for a given month becomes available no later than the 16th of the following month. /// **Note:** This endpoint has been deprecated. Please use the new endpoint diff --git a/src/datadogV2/model/mod.rs b/src/datadogV2/model/mod.rs index adbd072ca..6bebc06c9 100644 --- a/src/datadogV2/model/mod.rs +++ b/src/datadogV2/model/mod.rs @@ -3230,6 +3230,16 @@ pub mod model_hourly_usage_type; pub use self::model_hourly_usage_type::HourlyUsageType; pub mod model_usage_time_series_type; pub use self::model_usage_time_series_type::UsageTimeSeriesType; +pub mod model_billing_dimensions_mapping_response; +pub use self::model_billing_dimensions_mapping_response::BillingDimensionsMappingResponse; +pub mod model_billing_dimensions_mapping_body_item; +pub use self::model_billing_dimensions_mapping_body_item::BillingDimensionsMappingBodyItem; +pub mod model_billing_dimensions_mapping_body_item_attributes; +pub use self::model_billing_dimensions_mapping_body_item_attributes::BillingDimensionsMappingBodyItemAttributes; +pub mod model_billing_dimensions_mapping_body_item_attributes_endpoints_items; +pub use self::model_billing_dimensions_mapping_body_item_attributes_endpoints_items::BillingDimensionsMappingBodyItemAttributesEndpointsItems; +pub mod model_billing_dimensions_mapping_body_item_attributes_endpoints_items_status; +pub use self::model_billing_dimensions_mapping_body_item_attributes_endpoints_items_status::BillingDimensionsMappingBodyItemAttributesEndpointsItemsStatus; pub mod model_cost_by_org_response; pub use self::model_cost_by_org_response::CostByOrgResponse; pub mod model_cost_by_org; diff --git a/src/datadogV2/model/model_billing_dimensions_mapping_body_item.rs b/src/datadogV2/model/model_billing_dimensions_mapping_body_item.rs new file mode 100644 index 000000000..fafa4333f --- /dev/null +++ b/src/datadogV2/model/model_billing_dimensions_mapping_body_item.rs @@ -0,0 +1,152 @@ +// 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 mapping data for each billing dimension. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct BillingDimensionsMappingBodyItem { + /// Mapping of billing dimensions to endpoint keys. + #[serde(rename = "attributes")] + pub attributes: Option, + /// ID of the billing dimension. + #[serde(rename = "id")] + pub id: Option, + /// Type of active billing dimensions data. + #[serde(rename = "type")] + pub type_: Option, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl BillingDimensionsMappingBodyItem { + pub fn new() -> BillingDimensionsMappingBodyItem { + BillingDimensionsMappingBodyItem { + attributes: None, + id: None, + type_: None, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn attributes( + mut self, + value: crate::datadogV2::model::BillingDimensionsMappingBodyItemAttributes, + ) -> Self { + self.attributes = Some(value); + self + } + + pub fn id(mut self, value: String) -> Self { + self.id = Some(value); + self + } + + pub fn type_(mut self, value: crate::datadogV2::model::ActiveBillingDimensionsType) -> Self { + self.type_ = Some(value); + self + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl Default for BillingDimensionsMappingBodyItem { + fn default() -> Self { + Self::new() + } +} + +impl<'de> Deserialize<'de> for BillingDimensionsMappingBodyItem { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct BillingDimensionsMappingBodyItemVisitor; + impl<'a> Visitor<'a> for BillingDimensionsMappingBodyItemVisitor { + type Value = BillingDimensionsMappingBodyItem; + + 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::BillingDimensionsMappingBodyItemAttributes, + > = None; + let mut id: Option = None; + let mut type_: Option = None; + let mut additional_properties: std::collections::BTreeMap< + String, + serde_json::Value, + > = std::collections::BTreeMap::new(); + let mut _unparsed = false; + + while let Some((k, v)) = map.next_entry::()? { + match k.as_str() { + "attributes" => { + if v.is_null() { + continue; + } + attributes = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "id" => { + if v.is_null() { + continue; + } + id = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "type" => { + if v.is_null() { + continue; + } + type_ = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + if let Some(ref _type_) = type_ { + match _type_ { + crate::datadogV2::model::ActiveBillingDimensionsType::UnparsedObject(_type_) => { + _unparsed = true; + }, + _ => {} + } + } + } + &_ => { + if let Ok(value) = serde_json::from_value(v.clone()) { + additional_properties.insert(k, value); + } + } + } + } + + let content = BillingDimensionsMappingBodyItem { + attributes, + id, + type_, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(BillingDimensionsMappingBodyItemVisitor) + } +} diff --git a/src/datadogV2/model/model_billing_dimensions_mapping_body_item_attributes.rs b/src/datadogV2/model/model_billing_dimensions_mapping_body_item_attributes.rs new file mode 100644 index 000000000..67d296f77 --- /dev/null +++ b/src/datadogV2/model/model_billing_dimensions_mapping_body_item_attributes.rs @@ -0,0 +1,147 @@ +// 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}; + +/// Mapping of billing dimensions to endpoint keys. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct BillingDimensionsMappingBodyItemAttributes { + /// List of supported endpoints with their keys mapped to the billing_dimension. + #[serde(rename = "endpoints")] + pub endpoints: Option< + Vec, + >, + /// Label used for the billing dimension in the Plan & Usage charts. + #[serde(rename = "in_app_label")] + pub in_app_label: Option, + /// Month in ISO-8601 format, UTC, and precise to the second: `[YYYY-MM-DDThh:mm:ss]`. + #[serde(rename = "timestamp")] + pub timestamp: Option>, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl BillingDimensionsMappingBodyItemAttributes { + pub fn new() -> BillingDimensionsMappingBodyItemAttributes { + BillingDimensionsMappingBodyItemAttributes { + endpoints: None, + in_app_label: None, + timestamp: None, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn endpoints( + mut self, + value: Vec< + crate::datadogV2::model::BillingDimensionsMappingBodyItemAttributesEndpointsItems, + >, + ) -> Self { + self.endpoints = Some(value); + self + } + + pub fn in_app_label(mut self, value: String) -> Self { + self.in_app_label = Some(value); + self + } + + pub fn timestamp(mut self, value: chrono::DateTime) -> Self { + self.timestamp = Some(value); + self + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl Default for BillingDimensionsMappingBodyItemAttributes { + fn default() -> Self { + Self::new() + } +} + +impl<'de> Deserialize<'de> for BillingDimensionsMappingBodyItemAttributes { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct BillingDimensionsMappingBodyItemAttributesVisitor; + impl<'a> Visitor<'a> for BillingDimensionsMappingBodyItemAttributesVisitor { + type Value = BillingDimensionsMappingBodyItemAttributes; + + 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 endpoints: Option> = None; + let mut in_app_label: Option = None; + let mut timestamp: 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() { + "endpoints" => { + if v.is_null() { + continue; + } + endpoints = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "in_app_label" => { + if v.is_null() { + continue; + } + in_app_label = + Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "timestamp" => { + if v.is_null() { + continue; + } + timestamp = 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 = BillingDimensionsMappingBodyItemAttributes { + endpoints, + in_app_label, + timestamp, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(BillingDimensionsMappingBodyItemAttributesVisitor) + } +} diff --git a/src/datadogV2/model/model_billing_dimensions_mapping_body_item_attributes_endpoints_items.rs b/src/datadogV2/model/model_billing_dimensions_mapping_body_item_attributes_endpoints_items.rs new file mode 100644 index 000000000..da0d10410 --- /dev/null +++ b/src/datadogV2/model/model_billing_dimensions_mapping_body_item_attributes_endpoints_items.rs @@ -0,0 +1,153 @@ +// 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}; + +/// An endpoint's keys mapped to the billing_dimension. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct BillingDimensionsMappingBodyItemAttributesEndpointsItems { + /// The URL for the endpoint. + #[serde(rename = "id")] + pub id: Option, + /// The billing dimension. + #[serde(rename = "keys")] + pub keys: Option>, + /// Denotes whether mapping keys were available for this endpoint. + #[serde(rename = "status")] + pub status: Option< + crate::datadogV2::model::BillingDimensionsMappingBodyItemAttributesEndpointsItemsStatus, + >, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl BillingDimensionsMappingBodyItemAttributesEndpointsItems { + pub fn new() -> BillingDimensionsMappingBodyItemAttributesEndpointsItems { + BillingDimensionsMappingBodyItemAttributesEndpointsItems { + id: None, + keys: None, + status: None, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn id(mut self, value: String) -> Self { + self.id = Some(value); + self + } + + pub fn keys(mut self, value: Vec) -> Self { + self.keys = Some(value); + self + } + + pub fn status( + mut self, + value: crate::datadogV2::model::BillingDimensionsMappingBodyItemAttributesEndpointsItemsStatus, + ) -> Self { + self.status = Some(value); + self + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl Default for BillingDimensionsMappingBodyItemAttributesEndpointsItems { + fn default() -> Self { + Self::new() + } +} + +impl<'de> Deserialize<'de> for BillingDimensionsMappingBodyItemAttributesEndpointsItems { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct BillingDimensionsMappingBodyItemAttributesEndpointsItemsVisitor; + impl<'a> Visitor<'a> for BillingDimensionsMappingBodyItemAttributesEndpointsItemsVisitor { + type Value = BillingDimensionsMappingBodyItemAttributesEndpointsItems; + + 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 keys: Option> = None; + let mut status: Option = None; + let mut additional_properties: std::collections::BTreeMap< + String, + serde_json::Value, + > = std::collections::BTreeMap::new(); + let mut _unparsed = false; + + while let Some((k, v)) = map.next_entry::()? { + match k.as_str() { + "id" => { + if v.is_null() { + continue; + } + id = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "keys" => { + if v.is_null() { + continue; + } + keys = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "status" => { + if v.is_null() { + continue; + } + status = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + if let Some(ref _status) = status { + match _status { + crate::datadogV2::model::BillingDimensionsMappingBodyItemAttributesEndpointsItemsStatus::UnparsedObject(_status) => { + _unparsed = true; + }, + _ => {} + } + } + } + &_ => { + if let Ok(value) = serde_json::from_value(v.clone()) { + additional_properties.insert(k, value); + } + } + } + } + + let content = BillingDimensionsMappingBodyItemAttributesEndpointsItems { + id, + keys, + status, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer + .deserialize_any(BillingDimensionsMappingBodyItemAttributesEndpointsItemsVisitor) + } +} diff --git a/src/datadogV2/model/model_billing_dimensions_mapping_body_item_attributes_endpoints_items_status.rs b/src/datadogV2/model/model_billing_dimensions_mapping_body_item_attributes_endpoints_items_status.rs new file mode 100644 index 000000000..31d7a99f3 --- /dev/null +++ b/src/datadogV2/model/model_billing_dimensions_mapping_body_item_attributes_endpoints_items_status.rs @@ -0,0 +1,51 @@ +// 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 BillingDimensionsMappingBodyItemAttributesEndpointsItemsStatus { + OK, + NOT_FOUND, + UnparsedObject(crate::datadog::UnparsedObject), +} + +impl ToString for BillingDimensionsMappingBodyItemAttributesEndpointsItemsStatus { + fn to_string(&self) -> String { + match self { + Self::OK => String::from("OK"), + Self::NOT_FOUND => String::from("NOT_FOUND"), + Self::UnparsedObject(v) => v.value.to_string(), + } + } +} + +impl Serialize for BillingDimensionsMappingBodyItemAttributesEndpointsItemsStatus { + 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 BillingDimensionsMappingBodyItemAttributesEndpointsItemsStatus { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s: String = String::deserialize(deserializer)?; + Ok(match s.as_str() { + "OK" => Self::OK, + "NOT_FOUND" => Self::NOT_FOUND, + _ => Self::UnparsedObject(crate::datadog::UnparsedObject { + value: serde_json::Value::String(s.into()), + }), + }) + } +} diff --git a/src/datadogV2/model/model_billing_dimensions_mapping_response.rs b/src/datadogV2/model/model_billing_dimensions_mapping_response.rs new file mode 100644 index 000000000..2d4e3c3c5 --- /dev/null +++ b/src/datadogV2/model/model_billing_dimensions_mapping_response.rs @@ -0,0 +1,110 @@ +// 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}; + +/// Billing dimensions mapping response. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct BillingDimensionsMappingResponse { + /// Billing dimensions mapping data. + #[serde(rename = "data")] + pub data: Option>, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl BillingDimensionsMappingResponse { + pub fn new() -> BillingDimensionsMappingResponse { + BillingDimensionsMappingResponse { + data: None, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn data( + mut self, + value: Vec, + ) -> Self { + self.data = Some(value); + self + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl Default for BillingDimensionsMappingResponse { + fn default() -> Self { + Self::new() + } +} + +impl<'de> Deserialize<'de> for BillingDimensionsMappingResponse { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct BillingDimensionsMappingResponseVisitor; + impl<'a> Visitor<'a> for BillingDimensionsMappingResponseVisitor { + type Value = BillingDimensionsMappingResponse; + + 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< + Vec, + > = 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" => { + if v.is_null() { + continue; + } + 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 content = BillingDimensionsMappingResponse { + data, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(BillingDimensionsMappingResponseVisitor) + } +} diff --git a/tests/scenarios/cassettes/v2/usage_metering/Get-billing-dimension-mapping-for-usage-endpoints-returns-Bad-Request-response.frozen b/tests/scenarios/cassettes/v2/usage_metering/Get-billing-dimension-mapping-for-usage-endpoints-returns-Bad-Request-response.frozen new file mode 100644 index 000000000..ccd20a305 --- /dev/null +++ b/tests/scenarios/cassettes/v2/usage_metering/Get-billing-dimension-mapping-for-usage-endpoints-returns-Bad-Request-response.frozen @@ -0,0 +1 @@ +2024-10-28T16:04:40.774Z \ No newline at end of file diff --git a/tests/scenarios/cassettes/v2/usage_metering/Get-billing-dimension-mapping-for-usage-endpoints-returns-Bad-Request-response.json b/tests/scenarios/cassettes/v2/usage_metering/Get-billing-dimension-mapping-for-usage-endpoints-returns-Bad-Request-response.json new file mode 100644 index 000000000..eb8c383a1 --- /dev/null +++ b/tests/scenarios/cassettes/v2/usage_metering/Get-billing-dimension-mapping-for-usage-endpoints-returns-Bad-Request-response.json @@ -0,0 +1,33 @@ +{ + "http_interactions": [ + { + "request": { + "body": "", + "headers": { + "Accept": [ + "application/json;datetime-format=rfc3339" + ] + }, + "method": "get", + "uri": "https://api.datadoghq.com/api/v2/usage/billing_dimension_mapping" + }, + "response": { + "body": { + "string": "{\"errors\":[{\"id\":null,\"links\":null,\"status\":\"400\",\"code\":null,\"title\":\"Bad Request\",\"detail\":\"API called with non-parent org keys. Data is only available at the root level org\",\"source\":null,\"meta\":null}]}", + "encoding": null + }, + "headers": { + "Content-Type": [ + "application/vnd.api+json" + ] + }, + "status": { + "code": 400, + "message": "Bad Request" + } + }, + "recorded_at": "Mon, 28 Oct 2024 16:04:40 GMT" + } + ], + "recorded_with": "VCR 6.0.0" +} \ No newline at end of file diff --git a/tests/scenarios/features/v2/undo.json b/tests/scenarios/features/v2/undo.json index 62b494c8d..0e2af9556 100644 --- a/tests/scenarios/features/v2/undo.json +++ b/tests/scenarios/features/v2/undo.json @@ -2494,6 +2494,12 @@ "type": "safe" } }, + "GetBillingDimensionMapping": { + "tag": "Usage Metering", + "undo": { + "type": "safe" + } + }, "GetCostByOrg": { "tag": "Usage Metering", "undo": { diff --git a/tests/scenarios/features/v2/usage_metering.feature b/tests/scenarios/features/v2/usage_metering.feature index 4773ad013..525033821 100644 --- a/tests/scenarios/features/v2/usage_metering.feature +++ b/tests/scenarios/features/v2/usage_metering.feature @@ -48,6 +48,20 @@ Feature: Usage Metering When the request is sent Then the response status is 200 OK + @team:DataDog/revenue-query + Scenario: Get billing dimension mapping for usage endpoints returns "Bad Request" response + Given operation "GetBillingDimensionMapping" enabled + And new "GetBillingDimensionMapping" request + When the request is sent + Then the response status is 400 Bad Request + + @skip @team:DataDog/revenue-query + Scenario: Get billing dimension mapping for usage endpoints returns "OK" response + Given operation "GetBillingDimensionMapping" enabled + And new "GetBillingDimensionMapping" request + When the request is sent + Then the response status is 200 OK + @generated @skip @team:DataDog/revenue-query Scenario: Get cost across multi-org account returns "Bad Request" response Given new "GetCostByOrg" request diff --git a/tests/scenarios/function_mappings.rs b/tests/scenarios/function_mappings.rs index 66762eceb..ee787cb57 100644 --- a/tests/scenarios/function_mappings.rs +++ b/tests/scenarios/function_mappings.rs @@ -1903,6 +1903,10 @@ pub fn collect_function_calls(world: &mut DatadogWorld) { "v2.GetUsageApplicationSecurityMonitoring".into(), test_v2_get_usage_application_security_monitoring, ); + world.function_mappings.insert( + "v2.GetBillingDimensionMapping".into(), + test_v2_get_billing_dimension_mapping, + ); world .function_mappings .insert("v2.GetCostByOrg".into(), test_v2_get_cost_by_org); @@ -13292,6 +13296,43 @@ fn test_v2_get_usage_application_security_monitoring( world.response.code = response.status.as_u16(); } +fn test_v2_get_billing_dimension_mapping( + world: &mut DatadogWorld, + _parameters: &HashMap, +) { + let api = world + .api_instances + .v2_api_usage_metering + .as_ref() + .expect("api instance not found"); + let filter_month = _parameters + .get("filter[month]") + .and_then(|param| Some(serde_json::from_value(param.clone()).unwrap())); + let filter_view = _parameters + .get("filter[view]") + .and_then(|param| Some(serde_json::from_value(param.clone()).unwrap())); + let mut params = + datadogV2::api_usage_metering::GetBillingDimensionMappingOptionalParams::default(); + params.filter_month = filter_month; + params.filter_view = filter_view; + let response = match block_on(api.get_billing_dimension_mapping_with_http_info(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_get_cost_by_org(world: &mut DatadogWorld, _parameters: &HashMap) { let api = world .api_instances