diff --git a/.generator/schemas/v2/openapi.yaml b/.generator/schemas/v2/openapi.yaml index 51127c3ae..51829339a 100644 --- a/.generator/schemas/v2/openapi.yaml +++ b/.generator/schemas/v2/openapi.yaml @@ -1909,6 +1909,14 @@ components: required: true schema: type: string + VercelConfigurationID: + description: The Vercel configuration ID. + example: icfg_abc123 + in: path + name: configuration_id + required: true + schema: + type: string ViewIDPathParameter: description: The UUID of the case view. example: a1b2c3d4-e5f6-7890-abcd-ef1234567890 @@ -106727,6 +106735,168 @@ components: required: - value type: object + VercelApiKey: + description: Datadog API key reference used by the Vercel integration to send telemetry. + properties: + id: + description: ID of the Datadog API key used by the Vercel integration. + example: 00000000-0000-0000-0000-000000000001 + type: string + value: + description: Value of the Datadog API key. Returned as an empty string in read responses. + example: "" + type: string + required: + - id + - value + type: object + VercelConfigAttributes: + description: Attributes of the Datadog Vercel integration configuration. + properties: + apiKey: + $ref: "#/components/schemas/VercelApiKey" + logsConfig: + $ref: "#/components/schemas/VercelLogsConfig" + traceConfig: + $ref: "#/components/schemas/VercelTraceConfig" + required: + - apiKey + - logsConfig + - traceConfig + type: object + VercelConfigDataResponse: + description: Vercel configuration data returned by the API. + properties: + attributes: + $ref: "#/components/schemas/VercelConfigAttributes" + id: + description: Vercel configuration ID. + example: icfg_abc123 + type: string + type: + $ref: "#/components/schemas/VercelConfigDataResponseType" + required: + - id + - type + - attributes + type: object + VercelConfigDataResponseType: + default: vercelConfiguration + description: Type identifier for a Vercel configuration resource. + enum: + - vercelConfiguration + example: vercelConfiguration + type: string + x-enum-varnames: + - VERCEL_CONFIGURATION + VercelConfigResponse: + description: Response containing the Datadog Vercel integration configuration. + properties: + data: + $ref: "#/components/schemas/VercelConfigDataResponse" + required: + - data + type: object + VercelEnvironment: + description: Vercel deployment environment. + enum: + - production + - preview + example: production + type: string + x-enum-varnames: + - PRODUCTION + - PREVIEW + VercelLogSource: + description: Source of logs that Vercel forwards to Datadog. + enum: + - static + - lambda + - edge + - build + - external + - firewall + example: lambda + type: string + x-enum-varnames: + - STATIC + - LAMBDA + - EDGE + - BUILD + - EXTERNAL + - FIREWALL + VercelLogsConfig: + description: Logs forwarding configuration for the Vercel integration. + properties: + enabled: + description: Whether logs forwarding is enabled. + example: true + type: boolean + environments: + description: List of Vercel deployment environments to forward telemetry from. + example: + - production + items: + $ref: "#/components/schemas/VercelEnvironment" + type: array + logSources: + description: List of Vercel log sources to forward to Datadog. + example: + - lambda + items: + $ref: "#/components/schemas/VercelLogSource" + type: array + samplingPercentage: + description: Percentage of logs to forward to Datadog, between 0 and 100. + example: 100 + format: int32 + maximum: 100 + minimum: 0 + type: integer + required: + - enabled + - samplingPercentage + - logSources + - environments + type: object + VercelTokenCreateRequest: + description: Request to exchange a Vercel marketplace authorization code for a Datadog-managed access token. + properties: + authGrantCode: + description: OAuth authorization code received from the Vercel marketplace flow. + example: code + type: string + vercelConfigurationId: + description: Vercel configuration identifier returned by the marketplace flow. + example: icfg_abc123 + type: string + required: + - authGrantCode + - vercelConfigurationId + type: object + VercelTraceConfig: + description: Tracing configuration for the Vercel integration. + properties: + enabled: + description: Whether tracing is enabled. + example: true + type: boolean + isDeprecatedOtel: + description: Whether the configuration uses the deprecated OpenTelemetry tracing setup. + example: false + type: boolean + samplingPercentage: + description: Percentage of traces to forward to Datadog, between 0 and 100. + example: 100 + format: int32 + maximum: 100 + minimum: 0 + type: integer + required: + - enabled + - samplingPercentage + - isDeprecatedOtel + type: object Version: description: Version of the notification rule. It is updated when the rule is modified. example: 1 @@ -191561,6 +191731,154 @@ paths: "x-permission": operator: OPEN permissions: [] + /api/v2/vercel/config/{configuration_id}: + get: + description: Retrieve the Datadog Vercel integration configuration for a given Vercel configuration. The response contains the API key reference, logs forwarding settings, and tracing settings stored in Datadog for this configuration. + operationId: GetVercelConfig + parameters: + - $ref: "#/components/parameters/VercelConfigurationID" + responses: + "200": + content: + application/json: + examples: + default: + value: + data: + attributes: + apiKey: + id: 00000000-0000-0000-0000-000000000001 + value: "" + logsConfig: + enabled: true + environments: + - production + logSources: + - lambda + - edge + samplingPercentage: 100 + traceConfig: + enabled: true + isDeprecatedOtel: false + samplingPercentage: 100 + id: icfg_abc123 + type: vercelConfiguration + schema: + $ref: "#/components/schemas/VercelConfigResponse" + description: OK + "400": + content: + application/json: + schema: + $ref: "#/components/schemas/JSONAPIErrorResponse" + description: Bad Request + "403": + content: + application/json: + schema: + $ref: "#/components/schemas/JSONAPIErrorResponse" + description: Forbidden + "404": + content: + application/json: + schema: + $ref: "#/components/schemas/JSONAPIErrorResponse" + description: Not Found + "429": + $ref: "#/components/responses/TooManyRequestsResponse" + summary: Get Vercel configuration + tags: + - Vercel + put: + description: Update the Datadog Vercel integration configuration for a given Vercel configuration. The provided payload replaces the existing API key reference, logs forwarding settings, and tracing settings stored in Datadog for this configuration. + operationId: UpdateVercelConfig + parameters: + - $ref: "#/components/parameters/VercelConfigurationID" + requestBody: + content: + application/json: + examples: + default: + value: + apiKey: + id: 00000000-0000-0000-0000-000000000001 + value: "" + logsConfig: + enabled: true + environments: + - production + logSources: + - lambda + - edge + samplingPercentage: 100 + traceConfig: + enabled: true + isDeprecatedOtel: false + samplingPercentage: 100 + schema: + $ref: "#/components/schemas/VercelConfigAttributes" + required: true + responses: + "200": + description: OK + "400": + content: + application/json: + schema: + $ref: "#/components/schemas/JSONAPIErrorResponse" + description: Bad Request + "403": + content: + application/json: + schema: + $ref: "#/components/schemas/JSONAPIErrorResponse" + description: Forbidden + "404": + content: + application/json: + schema: + $ref: "#/components/schemas/JSONAPIErrorResponse" + description: Not Found + "429": + $ref: "#/components/responses/TooManyRequestsResponse" + summary: Update Vercel configuration + tags: + - Vercel + /api/v2/vercel/token: + post: + description: Exchange a Vercel marketplace authorization code for an access token and store it in Datadog so that the integration can call Vercel APIs on behalf of the customer. This endpoint is invoked once when a customer installs the Datadog integration from the Vercel marketplace. + operationId: CreateVercelToken + requestBody: + content: + application/json: + examples: + default: + value: + authGrantCode: "code" + vercelConfigurationId: "icfg_abc123" + schema: + $ref: "#/components/schemas/VercelTokenCreateRequest" + required: true + responses: + "200": + description: OK + "400": + content: + application/json: + schema: + $ref: "#/components/schemas/JSONAPIErrorResponse" + description: Bad Request + "403": + content: + application/json: + schema: + $ref: "#/components/schemas/JSONAPIErrorResponse" + description: Forbidden + "429": + $ref: "#/components/responses/TooManyRequestsResponse" + summary: Create Vercel access token + tags: + - Vercel /api/v2/web-integrations/{integration_name}/accounts: get: description: List accounts for a given web integration. @@ -193556,6 +193874,8 @@ tags: externalDocs: url: https://docs.datadoghq.com/account_management/users name: Users + - description: Configure the Datadog Vercel integration. Endpoints in this section let you exchange a Vercel marketplace authorization code for a Datadog-managed access token and read or update the logs, traces, and API key configuration associated with a Vercel project. + name: Vercel - description: |- Manage web integration accounts programmatically through the Datadog API. See the [Web Integrations page](https://app.datadoghq.com/integrations) for more information. diff --git a/examples/v2_vercel_CreateVercelToken.rs b/examples/v2_vercel_CreateVercelToken.rs new file mode 100644 index 000000000..94d925316 --- /dev/null +++ b/examples/v2_vercel_CreateVercelToken.rs @@ -0,0 +1,17 @@ +// Create Vercel access token returns "OK" response +use datadog_api_client::datadog; +use datadog_api_client::datadogV2::api_vercel::VercelAPI; +use datadog_api_client::datadogV2::model::VercelTokenCreateRequest; + +#[tokio::main] +async fn main() { + let body = VercelTokenCreateRequest::new("code".to_string(), "icfg_abc123".to_string()); + let configuration = datadog::Configuration::new(); + let api = VercelAPI::with_config(configuration); + let resp = api.create_vercel_token(body).await; + if let Ok(value) = resp { + println!("{:#?}", value); + } else { + println!("{:#?}", resp.unwrap_err()); + } +} diff --git a/examples/v2_vercel_GetVercelConfig.rs b/examples/v2_vercel_GetVercelConfig.rs new file mode 100644 index 000000000..fbf32016d --- /dev/null +++ b/examples/v2_vercel_GetVercelConfig.rs @@ -0,0 +1,15 @@ +// Get Vercel configuration returns "OK" response +use datadog_api_client::datadog; +use datadog_api_client::datadogV2::api_vercel::VercelAPI; + +#[tokio::main] +async fn main() { + let configuration = datadog::Configuration::new(); + let api = VercelAPI::with_config(configuration); + let resp = api.get_vercel_config("configuration_id".to_string()).await; + if let Ok(value) = resp { + println!("{:#?}", value); + } else { + println!("{:#?}", resp.unwrap_err()); + } +} diff --git a/examples/v2_vercel_UpdateVercelConfig.rs b/examples/v2_vercel_UpdateVercelConfig.rs new file mode 100644 index 000000000..854e7ab25 --- /dev/null +++ b/examples/v2_vercel_UpdateVercelConfig.rs @@ -0,0 +1,36 @@ +// Update Vercel configuration returns "OK" response +use datadog_api_client::datadog; +use datadog_api_client::datadogV2::api_vercel::VercelAPI; +use datadog_api_client::datadogV2::model::VercelApiKey; +use datadog_api_client::datadogV2::model::VercelConfigAttributes; +use datadog_api_client::datadogV2::model::VercelEnvironment; +use datadog_api_client::datadogV2::model::VercelLogSource; +use datadog_api_client::datadogV2::model::VercelLogsConfig; +use datadog_api_client::datadogV2::model::VercelTraceConfig; + +#[tokio::main] +async fn main() { + let body = VercelConfigAttributes::new( + VercelApiKey::new( + "00000000-0000-0000-0000-000000000001".to_string(), + "".to_string(), + ), + VercelLogsConfig::new( + true, + vec![VercelEnvironment::PRODUCTION], + vec![VercelLogSource::LAMBDA], + 100, + ), + VercelTraceConfig::new(true, false, 100), + ); + let configuration = datadog::Configuration::new(); + let api = VercelAPI::with_config(configuration); + let resp = api + .update_vercel_config("configuration_id".to_string(), body) + .await; + if let Ok(value) = resp { + println!("{:#?}", value); + } else { + println!("{:#?}", resp.unwrap_err()); + } +} diff --git a/src/datadogV2/api/api_vercel.rs b/src/datadogV2/api/api_vercel.rs new file mode 100644 index 000000000..b2f3d41b5 --- /dev/null +++ b/src/datadogV2/api/api_vercel.rs @@ -0,0 +1,497 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2019-Present Datadog, Inc. +use crate::datadog; +use flate2::{ + write::{GzEncoder, ZlibEncoder}, + Compression, +}; +use reqwest::header::{HeaderMap, HeaderValue}; +use serde::{Deserialize, Serialize}; +use std::io::Write; + +/// CreateVercelTokenError is a struct for typed errors of method [`VercelAPI::create_vercel_token`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum CreateVercelTokenError { + JSONAPIErrorResponse(crate::datadogV2::model::JSONAPIErrorResponse), + APIErrorResponse(crate::datadogV2::model::APIErrorResponse), + UnknownValue(serde_json::Value), +} + +/// GetVercelConfigError is a struct for typed errors of method [`VercelAPI::get_vercel_config`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum GetVercelConfigError { + JSONAPIErrorResponse(crate::datadogV2::model::JSONAPIErrorResponse), + APIErrorResponse(crate::datadogV2::model::APIErrorResponse), + UnknownValue(serde_json::Value), +} + +/// UpdateVercelConfigError is a struct for typed errors of method [`VercelAPI::update_vercel_config`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum UpdateVercelConfigError { + JSONAPIErrorResponse(crate::datadogV2::model::JSONAPIErrorResponse), + APIErrorResponse(crate::datadogV2::model::APIErrorResponse), + UnknownValue(serde_json::Value), +} + +/// Configure the Datadog Vercel integration. Endpoints in this section let you exchange a Vercel marketplace authorization code for a Datadog-managed access token and read or update the logs, traces, and API key configuration associated with a Vercel project. +#[derive(Debug, Clone)] +pub struct VercelAPI { + config: datadog::Configuration, + client: reqwest_middleware::ClientWithMiddleware, +} + +impl Default for VercelAPI { + fn default() -> Self { + Self::with_config(datadog::Configuration::default()) + } +} + +impl VercelAPI { + pub fn new() -> Self { + Self::default() + } + pub fn with_config(config: datadog::Configuration) -> Self { + let reqwest_client_builder = { + let builder = reqwest::Client::builder(); + #[cfg(not(target_arch = "wasm32"))] + let builder = if let Some(proxy_url) = &config.proxy_url { + builder.proxy(reqwest::Proxy::all(proxy_url).expect("Failed to parse proxy URL")) + } else { + builder + }; + builder + }; + + let middleware_client_builder = { + let builder = + reqwest_middleware::ClientBuilder::new(reqwest_client_builder.build().unwrap()); + #[cfg(feature = "retry")] + let builder = if config.enable_retry { + struct RetryableStatus; + impl reqwest_retry::RetryableStrategy for RetryableStatus { + fn handle( + &self, + res: &Result, + ) -> Option { + match res { + Ok(success) => reqwest_retry::default_on_request_success(success), + Err(_) => None, + } + } + } + let backoff_policy = reqwest_retry::policies::ExponentialBackoff::builder() + .build_with_max_retries(config.max_retries); + + let retry_middleware = + reqwest_retry::RetryTransientMiddleware::new_with_policy_and_strategy( + backoff_policy, + RetryableStatus, + ); + + builder.with(retry_middleware) + } else { + builder + }; + builder + }; + + let client = middleware_client_builder.build(); + + Self { config, client } + } + + pub fn with_client_and_config( + config: datadog::Configuration, + client: reqwest_middleware::ClientWithMiddleware, + ) -> Self { + Self { config, client } + } + + /// Exchange a Vercel marketplace authorization code for an access token and store it in Datadog so that the integration can call Vercel APIs on behalf of the customer. This endpoint is invoked once when a customer installs the Datadog integration from the Vercel marketplace. + pub async fn create_vercel_token( + &self, + body: crate::datadogV2::model::VercelTokenCreateRequest, + ) -> Result<(), datadog::Error> { + match self.create_vercel_token_with_http_info(body).await { + Ok(_) => Ok(()), + Err(err) => Err(err), + } + } + + /// Exchange a Vercel marketplace authorization code for an access token and store it in Datadog so that the integration can call Vercel APIs on behalf of the customer. This endpoint is invoked once when a customer installs the Datadog integration from the Vercel marketplace. + pub async fn create_vercel_token_with_http_info( + &self, + body: crate::datadogV2::model::VercelTokenCreateRequest, + ) -> Result, datadog::Error> { + let local_configuration = &self.config; + let operation_id = "v2.create_vercel_token"; + + let local_client = &self.client; + + let local_uri_str = format!( + "{}/api/v2/vercel/token", + local_configuration.get_operation_host(operation_id) + ); + let mut local_req_builder = + local_client.request(reqwest::Method::POST, local_uri_str.as_str()); + + // build headers + let mut headers = HeaderMap::new(); + headers.insert("Content-Type", HeaderValue::from_static("application/json")); + 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"), + ); + }; + + // 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)), + } + } + #[cfg(feature = "zstd")] + "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() { + 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)) + } + } + + /// Retrieve the Datadog Vercel integration configuration for a given Vercel configuration. The response contains the API key reference, logs forwarding settings, and tracing settings stored in Datadog for this configuration. + pub async fn get_vercel_config( + &self, + configuration_id: String, + ) -> Result> + { + match self + .get_vercel_config_with_http_info(configuration_id) + .await + { + Ok(response_content) => { + if let Some(e) = response_content.entity { + Ok(e) + } else { + Err(datadog::Error::Serde(serde::de::Error::custom( + "response content was None", + ))) + } + } + Err(err) => Err(err), + } + } + + /// Retrieve the Datadog Vercel integration configuration for a given Vercel configuration. The response contains the API key reference, logs forwarding settings, and tracing settings stored in Datadog for this configuration. + pub async fn get_vercel_config_with_http_info( + &self, + configuration_id: String, + ) -> Result< + datadog::ResponseContent, + datadog::Error, + > { + let local_configuration = &self.config; + let operation_id = "v2.get_vercel_config"; + + let local_client = &self.client; + + let local_uri_str = format!( + "{}/api/v2/vercel/config/{configuration_id}", + local_configuration.get_operation_host(operation_id), + configuration_id = datadog::urlencode(configuration_id) + ); + let mut local_req_builder = + local_client.request(reqwest::Method::GET, local_uri_str.as_str()); + + // build headers + let mut headers = HeaderMap::new(); + headers.insert("Accept", HeaderValue::from_static("application/json")); + + // build user agent + match HeaderValue::from_str(local_configuration.user_agent.as_str()) { + Ok(user_agent) => headers.insert(reqwest::header::USER_AGENT, user_agent), + Err(e) => { + log::warn!("Failed to parse user agent header: {e}, falling back to default"); + headers.insert( + reqwest::header::USER_AGENT, + HeaderValue::from_static(datadog::DEFAULT_USER_AGENT.as_str()), + ) + } + }; + + // build auth + if let Some(local_key) = local_configuration.auth_keys.get("apiKeyAuth") { + headers.insert( + "DD-API-KEY", + HeaderValue::from_str(local_key.key.as_str()) + .expect("failed to parse DD-API-KEY header"), + ); + }; + if let Some(local_key) = local_configuration.auth_keys.get("appKeyAuth") { + headers.insert( + "DD-APPLICATION-KEY", + HeaderValue::from_str(local_key.key.as_str()) + .expect("failed to parse DD-APPLICATION-KEY header"), + ); + }; + + local_req_builder = local_req_builder.headers(headers); + let local_req = local_req_builder.build()?; + log::debug!("request content: {:?}", local_req.body()); + let local_resp = local_client.execute(local_req).await?; + + let local_status = local_resp.status(); + let local_content = local_resp.text().await?; + log::debug!("response content: {}", local_content); + + if !local_status.is_client_error() && !local_status.is_server_error() { + match serde_json::from_str::( + &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)) + } + } + + /// Update the Datadog Vercel integration configuration for a given Vercel configuration. The provided payload replaces the existing API key reference, logs forwarding settings, and tracing settings stored in Datadog for this configuration. + pub async fn update_vercel_config( + &self, + configuration_id: String, + body: crate::datadogV2::model::VercelConfigAttributes, + ) -> Result<(), datadog::Error> { + match self + .update_vercel_config_with_http_info(configuration_id, body) + .await + { + Ok(_) => Ok(()), + Err(err) => Err(err), + } + } + + /// Update the Datadog Vercel integration configuration for a given Vercel configuration. The provided payload replaces the existing API key reference, logs forwarding settings, and tracing settings stored in Datadog for this configuration. + pub async fn update_vercel_config_with_http_info( + &self, + configuration_id: String, + body: crate::datadogV2::model::VercelConfigAttributes, + ) -> Result, datadog::Error> { + let local_configuration = &self.config; + let operation_id = "v2.update_vercel_config"; + + let local_client = &self.client; + + let local_uri_str = format!( + "{}/api/v2/vercel/config/{configuration_id}", + local_configuration.get_operation_host(operation_id), + configuration_id = datadog::urlencode(configuration_id) + ); + let mut local_req_builder = + local_client.request(reqwest::Method::PUT, local_uri_str.as_str()); + + // build headers + let mut headers = HeaderMap::new(); + headers.insert("Content-Type", HeaderValue::from_static("application/json")); + 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"), + ); + }; + + // 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)), + } + } + #[cfg(feature = "zstd")] + "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() { + 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)) + } + } +} diff --git a/src/datadogV2/api/mod.rs b/src/datadogV2/api/mod.rs index 3dd3dc879..2616fd414 100644 --- a/src/datadogV2/api/mod.rs +++ b/src/datadogV2/api/mod.rs @@ -131,6 +131,7 @@ pub mod api_teams; pub mod api_test_optimization; pub mod api_usage_metering; pub mod api_users; +pub mod api_vercel; pub mod api_web_integrations; pub mod api_webhooks_integration; pub mod api_widgets; diff --git a/src/datadogV2/mod.rs b/src/datadogV2/mod.rs index 12b68cad6..324910d0c 100644 --- a/src/datadogV2/mod.rs +++ b/src/datadogV2/mod.rs @@ -132,6 +132,7 @@ pub use self::api::api_teams; pub use self::api::api_test_optimization; pub use self::api::api_usage_metering; pub use self::api::api_users; +pub use self::api::api_vercel; pub use self::api::api_web_integrations; pub use self::api::api_webhooks_integration; pub use self::api::api_widgets; diff --git a/src/datadogV2/model/mod.rs b/src/datadogV2/model/mod.rs index 9265dbade..65dae476d 100644 --- a/src/datadogV2/model/mod.rs +++ b/src/datadogV2/model/mod.rs @@ -13014,6 +13014,26 @@ pub mod model_validate_api_key_response; pub use self::model_validate_api_key_response::ValidateAPIKeyResponse; pub mod model_validate_api_key_status; pub use self::model_validate_api_key_status::ValidateAPIKeyStatus; +pub mod model_vercel_config_response; +pub use self::model_vercel_config_response::VercelConfigResponse; +pub mod model_vercel_config_data_response; +pub use self::model_vercel_config_data_response::VercelConfigDataResponse; +pub mod model_vercel_config_attributes; +pub use self::model_vercel_config_attributes::VercelConfigAttributes; +pub mod model_vercel_api_key; +pub use self::model_vercel_api_key::VercelApiKey; +pub mod model_vercel_logs_config; +pub use self::model_vercel_logs_config::VercelLogsConfig; +pub mod model_vercel_environment; +pub use self::model_vercel_environment::VercelEnvironment; +pub mod model_vercel_log_source; +pub use self::model_vercel_log_source::VercelLogSource; +pub mod model_vercel_trace_config; +pub use self::model_vercel_trace_config::VercelTraceConfig; +pub mod model_vercel_config_data_response_type; +pub use self::model_vercel_config_data_response_type::VercelConfigDataResponseType; +pub mod model_vercel_token_create_request; +pub use self::model_vercel_token_create_request::VercelTokenCreateRequest; pub mod model_web_integration_accounts_response; pub use self::model_web_integration_accounts_response::WebIntegrationAccountsResponse; pub mod model_web_integration_account_response_data; diff --git a/src/datadogV2/model/model_vercel_api_key.rs b/src/datadogV2/model/model_vercel_api_key.rs new file mode 100644 index 000000000..88730117b --- /dev/null +++ b/src/datadogV2/model/model_vercel_api_key.rs @@ -0,0 +1,102 @@ +// 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}; + +/// Datadog API key reference used by the Vercel integration to send telemetry. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct VercelApiKey { + /// ID of the Datadog API key used by the Vercel integration. + #[serde(rename = "id")] + pub id: String, + /// Value of the Datadog API key. Returned as an empty string in read responses. + #[serde(rename = "value")] + pub value: String, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl VercelApiKey { + pub fn new(id: String, value: String) -> VercelApiKey { + VercelApiKey { + id, + value, + 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 VercelApiKey { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct VercelApiKeyVisitor; + impl<'a> Visitor<'a> for VercelApiKeyVisitor { + type Value = VercelApiKey; + + 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 value: 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)?); + } + "value" => { + value = 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 id = id.ok_or_else(|| M::Error::missing_field("id"))?; + let value = value.ok_or_else(|| M::Error::missing_field("value"))?; + + let content = VercelApiKey { + id, + value, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(VercelApiKeyVisitor) + } +} diff --git a/src/datadogV2/model/model_vercel_config_attributes.rs b/src/datadogV2/model/model_vercel_config_attributes.rs new file mode 100644 index 000000000..52c58c00c --- /dev/null +++ b/src/datadogV2/model/model_vercel_config_attributes.rs @@ -0,0 +1,120 @@ +// 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}; + +/// Attributes of the Datadog Vercel integration configuration. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct VercelConfigAttributes { + /// Datadog API key reference used by the Vercel integration to send telemetry. + #[serde(rename = "apiKey")] + pub api_key: crate::datadogV2::model::VercelApiKey, + /// Logs forwarding configuration for the Vercel integration. + #[serde(rename = "logsConfig")] + pub logs_config: crate::datadogV2::model::VercelLogsConfig, + /// Tracing configuration for the Vercel integration. + #[serde(rename = "traceConfig")] + pub trace_config: crate::datadogV2::model::VercelTraceConfig, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl VercelConfigAttributes { + pub fn new( + api_key: crate::datadogV2::model::VercelApiKey, + logs_config: crate::datadogV2::model::VercelLogsConfig, + trace_config: crate::datadogV2::model::VercelTraceConfig, + ) -> VercelConfigAttributes { + VercelConfigAttributes { + api_key, + logs_config, + trace_config, + 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 VercelConfigAttributes { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct VercelConfigAttributesVisitor; + impl<'a> Visitor<'a> for VercelConfigAttributesVisitor { + type Value = VercelConfigAttributes; + + 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 api_key: Option = None; + let mut logs_config: Option = None; + let mut trace_config: 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() { + "apiKey" => { + api_key = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "logsConfig" => { + logs_config = + Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "traceConfig" => { + trace_config = + 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 api_key = api_key.ok_or_else(|| M::Error::missing_field("api_key"))?; + let logs_config = + logs_config.ok_or_else(|| M::Error::missing_field("logs_config"))?; + let trace_config = + trace_config.ok_or_else(|| M::Error::missing_field("trace_config"))?; + + let content = VercelConfigAttributes { + api_key, + logs_config, + trace_config, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(VercelConfigAttributesVisitor) + } +} diff --git a/src/datadogV2/model/model_vercel_config_data_response.rs b/src/datadogV2/model/model_vercel_config_data_response.rs new file mode 100644 index 000000000..4641366eb --- /dev/null +++ b/src/datadogV2/model/model_vercel_config_data_response.rs @@ -0,0 +1,124 @@ +// 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}; + +/// Vercel configuration data returned by the API. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct VercelConfigDataResponse { + /// Attributes of the Datadog Vercel integration configuration. + #[serde(rename = "attributes")] + pub attributes: crate::datadogV2::model::VercelConfigAttributes, + /// Vercel configuration ID. + #[serde(rename = "id")] + pub id: String, + /// Type identifier for a Vercel configuration resource. + #[serde(rename = "type")] + pub type_: crate::datadogV2::model::VercelConfigDataResponseType, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl VercelConfigDataResponse { + pub fn new( + attributes: crate::datadogV2::model::VercelConfigAttributes, + id: String, + type_: crate::datadogV2::model::VercelConfigDataResponseType, + ) -> VercelConfigDataResponse { + VercelConfigDataResponse { + attributes, + id, + type_, + additional_properties: std::collections::BTreeMap::new(), + _unparsed: false, + } + } + + pub fn additional_properties( + mut self, + value: std::collections::BTreeMap, + ) -> Self { + self.additional_properties = value; + self + } +} + +impl<'de> Deserialize<'de> for VercelConfigDataResponse { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct VercelConfigDataResponseVisitor; + impl<'a> Visitor<'a> for VercelConfigDataResponseVisitor { + type Value = VercelConfigDataResponse; + + 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 type_: Option = None; + let mut additional_properties: std::collections::BTreeMap< + String, + serde_json::Value, + > = std::collections::BTreeMap::new(); + let mut _unparsed = false; + + while let Some((k, v)) = map.next_entry::()? { + match k.as_str() { + "attributes" => { + attributes = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "id" => { + id = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "type" => { + type_ = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + if let Some(ref _type_) = type_ { + match _type_ { + crate::datadogV2::model::VercelConfigDataResponseType::UnparsedObject(_type_) => { + _unparsed = true; + }, + _ => {} + } + } + } + &_ => { + if let Ok(value) = serde_json::from_value(v.clone()) { + additional_properties.insert(k, value); + } + } + } + } + let attributes = attributes.ok_or_else(|| M::Error::missing_field("attributes"))?; + let id = id.ok_or_else(|| M::Error::missing_field("id"))?; + let type_ = type_.ok_or_else(|| M::Error::missing_field("type_"))?; + + let content = VercelConfigDataResponse { + attributes, + id, + type_, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(VercelConfigDataResponseVisitor) + } +} diff --git a/src/datadogV2/model/model_vercel_config_data_response_type.rs b/src/datadogV2/model/model_vercel_config_data_response_type.rs new file mode 100644 index 000000000..bd6c15079 --- /dev/null +++ b/src/datadogV2/model/model_vercel_config_data_response_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 VercelConfigDataResponseType { + VERCEL_CONFIGURATION, + UnparsedObject(crate::datadog::UnparsedObject), +} + +impl ToString for VercelConfigDataResponseType { + fn to_string(&self) -> String { + match self { + Self::VERCEL_CONFIGURATION => String::from("vercelConfiguration"), + Self::UnparsedObject(v) => v.value.to_string(), + } + } +} + +impl Serialize for VercelConfigDataResponseType { + 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 VercelConfigDataResponseType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s: String = String::deserialize(deserializer)?; + Ok(match s.as_str() { + "vercelConfiguration" => Self::VERCEL_CONFIGURATION, + _ => Self::UnparsedObject(crate::datadog::UnparsedObject { + value: serde_json::Value::String(s.into()), + }), + }) + } +} diff --git a/src/datadogV2/model/model_vercel_config_response.rs b/src/datadogV2/model/model_vercel_config_response.rs new file mode 100644 index 000000000..f0aae45ca --- /dev/null +++ b/src/datadogV2/model/model_vercel_config_response.rs @@ -0,0 +1,92 @@ +// 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 containing the Datadog Vercel integration configuration. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct VercelConfigResponse { + /// Vercel configuration data returned by the API. + #[serde(rename = "data")] + pub data: crate::datadogV2::model::VercelConfigDataResponse, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl VercelConfigResponse { + pub fn new(data: crate::datadogV2::model::VercelConfigDataResponse) -> VercelConfigResponse { + VercelConfigResponse { + 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 VercelConfigResponse { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct VercelConfigResponseVisitor; + impl<'a> Visitor<'a> for VercelConfigResponseVisitor { + type Value = VercelConfigResponse; + + 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 = VercelConfigResponse { + data, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(VercelConfigResponseVisitor) + } +} diff --git a/src/datadogV2/model/model_vercel_environment.rs b/src/datadogV2/model/model_vercel_environment.rs new file mode 100644 index 000000000..3c743f0f8 --- /dev/null +++ b/src/datadogV2/model/model_vercel_environment.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 VercelEnvironment { + PRODUCTION, + PREVIEW, + UnparsedObject(crate::datadog::UnparsedObject), +} + +impl ToString for VercelEnvironment { + fn to_string(&self) -> String { + match self { + Self::PRODUCTION => String::from("production"), + Self::PREVIEW => String::from("preview"), + Self::UnparsedObject(v) => v.value.to_string(), + } + } +} + +impl Serialize for VercelEnvironment { + 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 VercelEnvironment { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s: String = String::deserialize(deserializer)?; + Ok(match s.as_str() { + "production" => Self::PRODUCTION, + "preview" => Self::PREVIEW, + _ => Self::UnparsedObject(crate::datadog::UnparsedObject { + value: serde_json::Value::String(s.into()), + }), + }) + } +} diff --git a/src/datadogV2/model/model_vercel_log_source.rs b/src/datadogV2/model/model_vercel_log_source.rs new file mode 100644 index 000000000..bdf5c24b4 --- /dev/null +++ b/src/datadogV2/model/model_vercel_log_source.rs @@ -0,0 +1,63 @@ +// 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 VercelLogSource { + STATIC, + LAMBDA, + EDGE, + BUILD, + EXTERNAL, + FIREWALL, + UnparsedObject(crate::datadog::UnparsedObject), +} + +impl ToString for VercelLogSource { + fn to_string(&self) -> String { + match self { + Self::STATIC => String::from("static"), + Self::LAMBDA => String::from("lambda"), + Self::EDGE => String::from("edge"), + Self::BUILD => String::from("build"), + Self::EXTERNAL => String::from("external"), + Self::FIREWALL => String::from("firewall"), + Self::UnparsedObject(v) => v.value.to_string(), + } + } +} + +impl Serialize for VercelLogSource { + 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 VercelLogSource { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s: String = String::deserialize(deserializer)?; + Ok(match s.as_str() { + "static" => Self::STATIC, + "lambda" => Self::LAMBDA, + "edge" => Self::EDGE, + "build" => Self::BUILD, + "external" => Self::EXTERNAL, + "firewall" => Self::FIREWALL, + _ => Self::UnparsedObject(crate::datadog::UnparsedObject { + value: serde_json::Value::String(s.into()), + }), + }) + } +} diff --git a/src/datadogV2/model/model_vercel_logs_config.rs b/src/datadogV2/model/model_vercel_logs_config.rs new file mode 100644 index 000000000..6c863a037 --- /dev/null +++ b/src/datadogV2/model/model_vercel_logs_config.rs @@ -0,0 +1,134 @@ +// 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}; + +/// Logs forwarding configuration for the Vercel integration. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct VercelLogsConfig { + /// Whether logs forwarding is enabled. + #[serde(rename = "enabled")] + pub enabled: bool, + /// List of Vercel deployment environments to forward telemetry from. + #[serde(rename = "environments")] + pub environments: Vec, + /// List of Vercel log sources to forward to Datadog. + #[serde(rename = "logSources")] + pub log_sources: Vec, + /// Percentage of logs to forward to Datadog, between 0 and 100. + #[serde(rename = "samplingPercentage")] + pub sampling_percentage: i32, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl VercelLogsConfig { + pub fn new( + enabled: bool, + environments: Vec, + log_sources: Vec, + sampling_percentage: i32, + ) -> VercelLogsConfig { + VercelLogsConfig { + enabled, + environments, + log_sources, + sampling_percentage, + 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 VercelLogsConfig { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct VercelLogsConfigVisitor; + impl<'a> Visitor<'a> for VercelLogsConfigVisitor { + type Value = VercelLogsConfig; + + 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 enabled: Option = None; + let mut environments: Option> = + None; + let mut log_sources: Option> = None; + let mut sampling_percentage: 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() { + "enabled" => { + enabled = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "environments" => { + environments = + Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "logSources" => { + log_sources = + Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "samplingPercentage" => { + sampling_percentage = + 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 enabled = enabled.ok_or_else(|| M::Error::missing_field("enabled"))?; + let environments = + environments.ok_or_else(|| M::Error::missing_field("environments"))?; + let log_sources = + log_sources.ok_or_else(|| M::Error::missing_field("log_sources"))?; + let sampling_percentage = sampling_percentage + .ok_or_else(|| M::Error::missing_field("sampling_percentage"))?; + + let content = VercelLogsConfig { + enabled, + environments, + log_sources, + sampling_percentage, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(VercelLogsConfigVisitor) + } +} diff --git a/src/datadogV2/model/model_vercel_token_create_request.rs b/src/datadogV2/model/model_vercel_token_create_request.rs new file mode 100644 index 000000000..e32aa4094 --- /dev/null +++ b/src/datadogV2/model/model_vercel_token_create_request.rs @@ -0,0 +1,109 @@ +// 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}; + +/// Request to exchange a Vercel marketplace authorization code for a Datadog-managed access token. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct VercelTokenCreateRequest { + /// OAuth authorization code received from the Vercel marketplace flow. + #[serde(rename = "authGrantCode")] + pub auth_grant_code: String, + /// Vercel configuration identifier returned by the marketplace flow. + #[serde(rename = "vercelConfigurationId")] + pub vercel_configuration_id: String, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl VercelTokenCreateRequest { + pub fn new( + auth_grant_code: String, + vercel_configuration_id: String, + ) -> VercelTokenCreateRequest { + VercelTokenCreateRequest { + auth_grant_code, + vercel_configuration_id, + 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 VercelTokenCreateRequest { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct VercelTokenCreateRequestVisitor; + impl<'a> Visitor<'a> for VercelTokenCreateRequestVisitor { + type Value = VercelTokenCreateRequest; + + 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 auth_grant_code: Option = None; + let mut vercel_configuration_id: 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() { + "authGrantCode" => { + auth_grant_code = + Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "vercelConfigurationId" => { + vercel_configuration_id = + 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 auth_grant_code = + auth_grant_code.ok_or_else(|| M::Error::missing_field("auth_grant_code"))?; + let vercel_configuration_id = vercel_configuration_id + .ok_or_else(|| M::Error::missing_field("vercel_configuration_id"))?; + + let content = VercelTokenCreateRequest { + auth_grant_code, + vercel_configuration_id, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(VercelTokenCreateRequestVisitor) + } +} diff --git a/src/datadogV2/model/model_vercel_trace_config.rs b/src/datadogV2/model/model_vercel_trace_config.rs new file mode 100644 index 000000000..649480532 --- /dev/null +++ b/src/datadogV2/model/model_vercel_trace_config.rs @@ -0,0 +1,120 @@ +// 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}; + +/// Tracing configuration for the Vercel integration. +#[non_exhaustive] +#[skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct VercelTraceConfig { + /// Whether tracing is enabled. + #[serde(rename = "enabled")] + pub enabled: bool, + /// Whether the configuration uses the deprecated OpenTelemetry tracing setup. + #[serde(rename = "isDeprecatedOtel")] + pub is_deprecated_otel: bool, + /// Percentage of traces to forward to Datadog, between 0 and 100. + #[serde(rename = "samplingPercentage")] + pub sampling_percentage: i32, + #[serde(flatten)] + pub additional_properties: std::collections::BTreeMap, + #[serde(skip)] + #[serde(default)] + pub(crate) _unparsed: bool, +} + +impl VercelTraceConfig { + pub fn new( + enabled: bool, + is_deprecated_otel: bool, + sampling_percentage: i32, + ) -> VercelTraceConfig { + VercelTraceConfig { + enabled, + is_deprecated_otel, + sampling_percentage, + 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 VercelTraceConfig { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct VercelTraceConfigVisitor; + impl<'a> Visitor<'a> for VercelTraceConfigVisitor { + type Value = VercelTraceConfig; + + 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 enabled: Option = None; + let mut is_deprecated_otel: Option = None; + let mut sampling_percentage: 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() { + "enabled" => { + enabled = Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "isDeprecatedOtel" => { + is_deprecated_otel = + Some(serde_json::from_value(v).map_err(M::Error::custom)?); + } + "samplingPercentage" => { + sampling_percentage = + 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 enabled = enabled.ok_or_else(|| M::Error::missing_field("enabled"))?; + let is_deprecated_otel = is_deprecated_otel + .ok_or_else(|| M::Error::missing_field("is_deprecated_otel"))?; + let sampling_percentage = sampling_percentage + .ok_or_else(|| M::Error::missing_field("sampling_percentage"))?; + + let content = VercelTraceConfig { + enabled, + is_deprecated_otel, + sampling_percentage, + additional_properties, + _unparsed, + }; + + Ok(content) + } + } + + deserializer.deserialize_any(VercelTraceConfigVisitor) + } +} diff --git a/tests/scenarios/features/v2/undo.json b/tests/scenarios/features/v2/undo.json index 89626bc56..d1cdac288 100644 --- a/tests/scenarios/features/v2/undo.json +++ b/tests/scenarios/features/v2/undo.json @@ -9305,6 +9305,24 @@ "type": "safe" } }, + "GetVercelConfig": { + "tag": "Vercel", + "undo": { + "type": "safe" + } + }, + "UpdateVercelConfig": { + "tag": "Vercel", + "undo": { + "type": "idempotent" + } + }, + "CreateVercelToken": { + "tag": "Vercel", + "undo": { + "type": "unsafe" + } + }, "ListWebIntegrationAccounts": { "tag": "Web Integrations", "undo": { diff --git a/tests/scenarios/features/v2/vercel.feature b/tests/scenarios/features/v2/vercel.feature new file mode 100644 index 000000000..9a3b33d48 --- /dev/null +++ b/tests/scenarios/features/v2/vercel.feature @@ -0,0 +1,70 @@ +@endpoint(vercel) @endpoint(vercel-v2) +Feature: Vercel + Configure the Datadog Vercel integration. Endpoints in this section let + you exchange a Vercel marketplace authorization code for a Datadog-managed + access token and read or update the logs, traces, and API key + configuration associated with a Vercel project. + + Background: + Given a valid "apiKeyAuth" key in the system + And a valid "appKeyAuth" key in the system + And an instance of "Vercel" API + + @generated @skip @team:DataDog/serverless-onboarding-and-enablement + Scenario: Create Vercel access token returns "Bad Request" response + Given new "CreateVercelToken" request + And body with value {"authGrantCode": "code", "vercelConfigurationId": "icfg_abc123"} + When the request is sent + Then the response status is 400 Bad Request + + @generated @skip @team:DataDog/serverless-onboarding-and-enablement + Scenario: Create Vercel access token returns "OK" response + Given new "CreateVercelToken" request + And body with value {"authGrantCode": "code", "vercelConfigurationId": "icfg_abc123"} + When the request is sent + Then the response status is 200 OK + + @generated @skip @team:DataDog/serverless-onboarding-and-enablement + Scenario: Get Vercel configuration returns "Bad Request" response + Given new "GetVercelConfig" request + And request contains "configuration_id" parameter from "REPLACE.ME" + When the request is sent + Then the response status is 400 Bad Request + + @generated @skip @team:DataDog/serverless-onboarding-and-enablement + Scenario: Get Vercel configuration returns "Not Found" response + Given new "GetVercelConfig" request + And request contains "configuration_id" parameter from "REPLACE.ME" + When the request is sent + Then the response status is 404 Not Found + + @generated @skip @team:DataDog/serverless-onboarding-and-enablement + Scenario: Get Vercel configuration returns "OK" response + Given new "GetVercelConfig" request + And request contains "configuration_id" parameter from "REPLACE.ME" + When the request is sent + Then the response status is 200 OK + + @generated @skip @team:DataDog/serverless-onboarding-and-enablement + Scenario: Update Vercel configuration returns "Bad Request" response + Given new "UpdateVercelConfig" request + And request contains "configuration_id" parameter from "REPLACE.ME" + And body with value {"apiKey": {"id": "00000000-0000-0000-0000-000000000001", "value": ""}, "logsConfig": {"enabled": true, "environments": ["production"], "logSources": ["lambda"], "samplingPercentage": 100}, "traceConfig": {"enabled": true, "isDeprecatedOtel": false, "samplingPercentage": 100}} + When the request is sent + Then the response status is 400 Bad Request + + @generated @skip @team:DataDog/serverless-onboarding-and-enablement + Scenario: Update Vercel configuration returns "Not Found" response + Given new "UpdateVercelConfig" request + And request contains "configuration_id" parameter from "REPLACE.ME" + And body with value {"apiKey": {"id": "00000000-0000-0000-0000-000000000001", "value": ""}, "logsConfig": {"enabled": true, "environments": ["production"], "logSources": ["lambda"], "samplingPercentage": 100}, "traceConfig": {"enabled": true, "isDeprecatedOtel": false, "samplingPercentage": 100}} + When the request is sent + Then the response status is 404 Not Found + + @generated @skip @team:DataDog/serverless-onboarding-and-enablement + Scenario: Update Vercel configuration returns "OK" response + Given new "UpdateVercelConfig" request + And request contains "configuration_id" parameter from "REPLACE.ME" + And body with value {"apiKey": {"id": "00000000-0000-0000-0000-000000000001", "value": ""}, "logsConfig": {"enabled": true, "environments": ["production"], "logSources": ["lambda"], "samplingPercentage": 100}, "traceConfig": {"enabled": true, "isDeprecatedOtel": false, "samplingPercentage": 100}} + When the request is sent + Then the response status is 200 OK diff --git a/tests/scenarios/function_mappings.rs b/tests/scenarios/function_mappings.rs index 5b7efc21c..b2d12f98a 100644 --- a/tests/scenarios/function_mappings.rs +++ b/tests/scenarios/function_mappings.rs @@ -218,6 +218,7 @@ pub struct ApiInstances { pub v2_api_synthetics: Option, pub v2_api_tag_policies: Option, pub v2_api_teams: Option, + pub v2_api_vercel: Option, pub v2_api_web_integrations: Option, pub v2_api_widgets: Option, pub v2_api_workflow_automation: @@ -1399,6 +1400,13 @@ pub fn initialize_api_instance(world: &mut DatadogWorld, api: String) { world.http_client.as_ref().unwrap().clone(), )); } + "Vercel" => { + world.api_instances.v2_api_vercel = + Some(datadogV2::api_vercel::VercelAPI::with_client_and_config( + world.config.clone(), + world.http_client.as_ref().unwrap().clone(), + )); + } "WebIntegrations" => { world.api_instances.v2_api_web_integrations = Some( datadogV2::api_web_integrations::WebIntegrationsAPI::with_client_and_config( @@ -7421,6 +7429,15 @@ pub fn collect_function_calls(world: &mut DatadogWorld) { world .function_mappings .insert("v2.GetUserMemberships".into(), test_v2_get_user_memberships); + world + .function_mappings + .insert("v2.GetVercelConfig".into(), test_v2_get_vercel_config); + world + .function_mappings + .insert("v2.UpdateVercelConfig".into(), test_v2_update_vercel_config); + world + .function_mappings + .insert("v2.CreateVercelToken".into(), test_v2_create_vercel_token); world.function_mappings.insert( "v2.ListWebIntegrationAccounts".into(), test_v2_list_web_integration_accounts, @@ -59144,6 +59161,84 @@ fn test_v2_get_user_memberships(world: &mut DatadogWorld, _parameters: &HashMap< world.response.code = response.status.as_u16(); } +fn test_v2_get_vercel_config(world: &mut DatadogWorld, _parameters: &HashMap) { + let api = world + .api_instances + .v2_api_vercel + .as_ref() + .expect("api instance not found"); + let configuration_id = + serde_json::from_value(_parameters.get("configuration_id").unwrap().clone()).unwrap(); + let response = match block_on(api.get_vercel_config_with_http_info(configuration_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_update_vercel_config(world: &mut DatadogWorld, _parameters: &HashMap) { + let api = world + .api_instances + .v2_api_vercel + .as_ref() + .expect("api instance not found"); + let configuration_id = + serde_json::from_value(_parameters.get("configuration_id").unwrap().clone()).unwrap(); + let body = serde_json::from_value(_parameters.get("body").unwrap().clone()).unwrap(); + let response = match block_on(api.update_vercel_config_with_http_info(configuration_id, body)) { + 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_vercel_token(world: &mut DatadogWorld, _parameters: &HashMap) { + let api = world + .api_instances + .v2_api_vercel + .as_ref() + .expect("api instance not found"); + let body = serde_json::from_value(_parameters.get("body").unwrap().clone()).unwrap(); + let response = match block_on(api.create_vercel_token_with_http_info(body)) { + 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_web_integration_accounts( world: &mut DatadogWorld, _parameters: &HashMap,