diff --git a/.generator/schemas/v2/openapi.yaml b/.generator/schemas/v2/openapi.yaml index 5808b5f796..4cefb983db 100644 --- a/.generator/schemas/v2/openapi.yaml +++ b/.generator/schemas/v2/openapi.yaml @@ -93,6 +93,13 @@ components: required: true schema: type: string + AnomalyID: + description: The UUID of the cost anomaly. + in: path + name: anomaly_id + required: true + schema: + type: string ApplicationKeyFilterCreatedAtEndParameter: description: Only include application keys created on or before the specified date. in: query @@ -15490,6 +15497,204 @@ components: type: string x-enum-varnames: - CUMULATIVE + CostAnomaliesResponse: + description: Response object containing a list of detected Cloud Cost Management anomalies and aggregated totals. + properties: + data: + $ref: "#/components/schemas/CostAnomaliesResponseData" + type: object + CostAnomaliesResponseData: + description: Resource wrapper for the list of cost anomalies and aggregated totals. + properties: + attributes: + $ref: "#/components/schemas/CostAnomaliesResponseDataAttributes" + id: + description: Static identifier of the cost anomalies collection resource. + example: anomalies + type: string + type: + $ref: "#/components/schemas/CostAnomaliesResponseDataType" + required: + - id + - type + - attributes + type: object + CostAnomaliesResponseDataAttributes: + description: Cost anomaly results and aggregated totals for the queried window. + properties: + anomalies: + description: The list of cost anomalies that match the request. + items: + $ref: "#/components/schemas/CostAnomaly" + type: array + avg_daily_anomalous_cost: + description: Average daily anomalous cost change across the queried window. + example: 625.375 + format: double + type: number + total_actual_cost: + description: Total actual cost spent across the queried window for the matching providers. + example: 3001.24 + format: double + type: number + total_anomalous_cost: + description: Sum of the anomalous cost change across all returned anomalies. + example: 1250.75 + format: double + type: number + total_count: + description: Total number of anomalies that match the request. + example: 1 + format: int64 + type: integer + required: + - anomalies + - total_count + - total_anomalous_cost + - total_actual_cost + - avg_daily_anomalous_cost + type: object + CostAnomaliesResponseDataType: + default: anomalies + description: Type of the cost anomalies collection resource. Must be `anomalies`. + enum: + - anomalies + example: anomalies + type: string + x-enum-varnames: + - ANOMALIES + CostAnomaly: + description: A single detected Cloud Cost Management anomaly. + properties: + actual_cost: + description: Actual cost incurred during the anomaly window. + example: 3001.24 + format: double + type: number + anomalous_cost_change: + description: Anomalous cost change relative to the expected baseline. + example: 1250.75 + format: double + type: number + anomaly_end: + description: Anomaly end timestamp in Unix milliseconds. + example: 1730429150000 + format: int64 + type: integer + anomaly_start: + description: Anomaly start timestamp in Unix milliseconds. + example: 1730259950000 + format: int64 + type: integer + correlated_tags: + $ref: "#/components/schemas/CostAnomalyCorrelatedTags" + dimensions: + $ref: "#/components/schemas/CostAnomalyDimensions" + dismissal: + $ref: "#/components/schemas/CostAnomalyDismissal" + max_cost: + description: Maximum cost observed during the anomaly window. + example: 5000.5 + format: double + type: number + provider: + description: Cloud or SaaS provider associated with the anomaly (for example `aws`, `gcp`, `azure`). + example: aws + type: string + query: + description: The metrics query that detected the anomaly. + example: sum:aws.cost.net.amortized{aws_cost_type IN (Usage,DiscountedUsage,SavingsPlanCoveredUsage) AND aws_product NOT IN (supportenterprise) AND service:"ec2"}.rollup(sum, daily) + type: string + uuid: + description: The unique identifier of the anomaly. + example: b0a6aaa9-3c4c-48cb-9447-a0d1338b3e09 + type: string + required: + - uuid + - anomaly_start + - anomaly_end + - query + - dimensions + - correlated_tags + - anomalous_cost_change + - actual_cost + - max_cost + - provider + type: object + CostAnomalyCorrelatedTags: + additionalProperties: + description: The list of correlated values for the tag key. + items: + type: string + type: array + description: Map of correlated tag keys to the list of correlated tag values. + example: + region: + - us-east-1 + - us-west-2 + nullable: true + type: object + CostAnomalyDimensions: + additionalProperties: + description: The dimension value. + type: string + description: Map of cost dimension keys to their values for the anomaly grouping. + example: + service: ec2 + type: object + CostAnomalyDismissal: + description: Resolution metadata for an anomaly that has been dismissed. + properties: + cause: + description: Reason the anomaly was dismissed. + example: false_positive + type: string + dismissal_id: + description: Unique identifier of the dismissal record. + example: 12345678-1234-1234-1234-123456789abc + type: string + message: + description: Optional message explaining the dismissal. + example: This was expected due to planned infrastructure changes. + type: string + updated_at: + description: Timestamp of the last dismissal update in Unix milliseconds. + example: 1730344150000 + format: int64 + type: integer + updated_by: + description: Identifier of the user that last updated the dismissal. + example: user@example.com + type: string + required: + - dismissal_id + - cause + - message + - updated_at + - updated_by + type: object + CostAnomalyResponse: + description: Response object containing a single Cloud Cost Management anomaly. + properties: + data: + $ref: "#/components/schemas/CostAnomalyResponseData" + type: object + CostAnomalyResponseData: + description: Resource wrapper for a single cost anomaly. + properties: + attributes: + $ref: "#/components/schemas/CostAnomaly" + id: + description: The unique identifier of the anomaly. + example: b0a6aaa9-3c4c-48cb-9447-a0d1338b3e09 + type: string + type: + $ref: "#/components/schemas/CostAnomaliesResponseDataType" + required: + - id + - type + - attributes + type: object CostAttributionAggregates: description: An array of available aggregates. items: @@ -95324,6 +95529,204 @@ paths: "x-permission": operator: OPEN permissions: [] + /api/v2/cost/anomalies: + get: + description: List detected Cloud Cost Management anomalies for the organization. + operationId: ListCostAnomalies + parameters: + - description: Start time as Unix milliseconds. Defaults to the start of the latest stable seven-day window. + in: query + name: start + required: false + schema: + example: 1730259950000 + format: int64 + type: integer + - description: End time as Unix milliseconds. Defaults to the end of the latest stable seven-day window. + in: query + name: end + required: false + schema: + example: 1730429150000 + format: int64 + type: integer + - description: 'Optional JSON object mapping cost tag keys to allowed values, for example `{"team":["payments"],"env":["prod"]}`. Filters match anomaly dimensions or correlated tags.' + in: query + name: filter + required: false + schema: + example: '{"team":["payments"]}' + type: string + - description: Minimum absolute anomalous cost change to include. Numeric value; defaults to `1`. + in: query + name: min_anomalous_threshold + required: false + schema: + example: "1.0" + type: string + - description: Minimum absolute actual cost to include. Numeric value; defaults to `0`. + in: query + name: min_cost_threshold + required: false + schema: + example: "0.0" + type: string + - description: Filter by resolution state. Use `none` for unresolved anomalies, `all` or `*` for resolved anomalies, or a comma-separated list of causes. + in: query + name: dismissal_cause + required: false + schema: + example: none + type: string + - description: Sort field. One of `start_date`, `end_date`, `duration`, `max_cost`, `anomalous_cost`, or `dismissal_date`. Defaults to `anomalous_cost`. + in: query + name: order_by + required: false + schema: + example: anomalous_cost + type: string + - description: Sort direction. One of `asc` or `desc`. Defaults to `desc`. + in: query + name: order + required: false + schema: + example: desc + type: string + - description: Maximum number of anomalies to return. Defaults to `200`. + in: query + name: limit + required: false + schema: + example: 200 + type: integer + - description: Pagination offset. Defaults to `0`. + in: query + name: offset + required: false + schema: + example: 0 + type: integer + - description: Optional repeated cloud or SaaS provider filters, such as `aws`, `gcp`, `azure`, `Oracle`, `datadog`, `OpenAI`, or `Anthropic`. + explode: true + in: query + name: provider_ids + required: false + schema: + items: + example: aws + type: string + type: array + responses: + "200": + content: + application/json: + examples: + default: + value: + data: + attributes: + anomalies: + - actual_cost: 3001.24 + anomalous_cost_change: 1250.75 + anomaly_end: 1730429150000 + anomaly_start: 1730259950000 + correlated_tags: + region: + - us-east-1 + - us-west-2 + dimensions: + service: ec2 + max_cost: 5000.5 + provider: aws + query: 'sum:aws.cost.net.amortized{aws_cost_type IN (Usage,DiscountedUsage,SavingsPlanCoveredUsage) AND aws_product NOT IN (supportenterprise) AND service:"ec2"}.rollup(sum, daily)' + uuid: b0a6aaa9-3c4c-48cb-9447-a0d1338b3e09 + avg_daily_anomalous_cost: 625.375 + total_actual_cost: 3001.24 + total_anomalous_cost: 1250.75 + total_count: 1 + id: anomalies + type: anomalies + schema: + $ref: "#/components/schemas/CostAnomaliesResponse" + description: OK + "400": + $ref: "#/components/responses/BadRequestResponse" + "403": + content: + application/json: + schema: + $ref: "#/components/schemas/APIErrorResponse" + description: Forbidden + "429": + $ref: "#/components/responses/TooManyRequestsResponse" + security: + - apiKeyAuth: [] + appKeyAuth: [] + - AuthZ: + - cloud_cost_management_read + summary: List cost anomalies + tags: + - Cloud Cost Management + x-unstable: |- + **Note**: This endpoint is in Preview and is subject to change. + If you have any feedback, contact [Datadog support](https://docs.datadoghq.com/help/). + /api/v2/cost/anomalies/{anomaly_id}: + get: + description: Get a detected Cloud Cost Management anomaly by UUID. + operationId: GetCostAnomaly + parameters: + - $ref: "#/components/parameters/AnomalyID" + responses: + "200": + content: + application/json: + examples: + default: + value: + data: + attributes: + actual_cost: 3001.24 + anomalous_cost_change: 1250.75 + anomaly_end: 1730429150000 + anomaly_start: 1730259950000 + correlated_tags: + region: + - us-east-1 + - us-west-2 + dimensions: + service: ec2 + max_cost: 5000.5 + provider: aws + query: 'sum:aws.cost.net.amortized{aws_cost_type IN (Usage,DiscountedUsage,SavingsPlanCoveredUsage) AND aws_product NOT IN (supportenterprise) AND service:"ec2"}.rollup(sum, daily)' + uuid: b0a6aaa9-3c4c-48cb-9447-a0d1338b3e09 + id: b0a6aaa9-3c4c-48cb-9447-a0d1338b3e09 + type: anomalies + schema: + $ref: "#/components/schemas/CostAnomalyResponse" + description: OK + "400": + $ref: "#/components/responses/BadRequestResponse" + "403": + content: + application/json: + schema: + $ref: "#/components/schemas/APIErrorResponse" + description: Forbidden + "404": + $ref: "#/components/responses/NotFoundResponse" + "429": + $ref: "#/components/responses/TooManyRequestsResponse" + security: + - apiKeyAuth: [] + appKeyAuth: [] + - AuthZ: + - cloud_cost_management_read + summary: Get cost anomaly + tags: + - Cloud Cost Management + x-unstable: |- + **Note**: This endpoint is in Preview and is subject to change. + If you have any feedback, contact [Datadog support](https://docs.datadoghq.com/help/). /api/v2/cost/arbitrary_rule: get: description: List all custom allocation rules - Retrieve a list of all custom allocation rules for the organization diff --git a/docs/datadog_api_client.v2.model.rst b/docs/datadog_api_client.v2.model.rst index 406433db99..6209e5e57f 100644 --- a/docs/datadog_api_client.v2.model.rst +++ b/docs/datadog_api_client.v2.model.rst @@ -6171,6 +6171,76 @@ datadog\_api\_client.v2.model.cost\_aggregation\_type module :members: :show-inheritance: +datadog\_api\_client.v2.model.cost\_anomalies\_response module +-------------------------------------------------------------- + +.. automodule:: datadog_api_client.v2.model.cost_anomalies_response + :members: + :show-inheritance: + +datadog\_api\_client.v2.model.cost\_anomalies\_response\_data module +-------------------------------------------------------------------- + +.. automodule:: datadog_api_client.v2.model.cost_anomalies_response_data + :members: + :show-inheritance: + +datadog\_api\_client.v2.model.cost\_anomalies\_response\_data\_attributes module +-------------------------------------------------------------------------------- + +.. automodule:: datadog_api_client.v2.model.cost_anomalies_response_data_attributes + :members: + :show-inheritance: + +datadog\_api\_client.v2.model.cost\_anomalies\_response\_data\_type module +-------------------------------------------------------------------------- + +.. automodule:: datadog_api_client.v2.model.cost_anomalies_response_data_type + :members: + :show-inheritance: + +datadog\_api\_client.v2.model.cost\_anomaly module +-------------------------------------------------- + +.. automodule:: datadog_api_client.v2.model.cost_anomaly + :members: + :show-inheritance: + +datadog\_api\_client.v2.model.cost\_anomaly\_correlated\_tags module +-------------------------------------------------------------------- + +.. automodule:: datadog_api_client.v2.model.cost_anomaly_correlated_tags + :members: + :show-inheritance: + +datadog\_api\_client.v2.model.cost\_anomaly\_dimensions module +-------------------------------------------------------------- + +.. automodule:: datadog_api_client.v2.model.cost_anomaly_dimensions + :members: + :show-inheritance: + +datadog\_api\_client.v2.model.cost\_anomaly\_dismissal module +------------------------------------------------------------- + +.. automodule:: datadog_api_client.v2.model.cost_anomaly_dismissal + :members: + :show-inheritance: + +datadog\_api\_client.v2.model.cost\_anomaly\_response module +------------------------------------------------------------ + +.. automodule:: datadog_api_client.v2.model.cost_anomaly_response + :members: + :show-inheritance: + +datadog\_api\_client.v2.model.cost\_anomaly\_response\_data module +------------------------------------------------------------------ + +.. automodule:: datadog_api_client.v2.model.cost_anomaly_response_data + :members: + :show-inheritance: + datadog\_api\_client.v2.model.cost\_attribution\_aggregates\_body module ------------------------------------------------------------------------ diff --git a/examples/v2/cloud-cost-management/GetCostAnomaly.py b/examples/v2/cloud-cost-management/GetCostAnomaly.py new file mode 100644 index 0000000000..3431d1d827 --- /dev/null +++ b/examples/v2/cloud-cost-management/GetCostAnomaly.py @@ -0,0 +1,16 @@ +""" +Get cost anomaly returns "OK" response +""" + +from datadog_api_client import ApiClient, Configuration +from datadog_api_client.v2.api.cloud_cost_management_api import CloudCostManagementApi + +configuration = Configuration() +configuration.unstable_operations["get_cost_anomaly"] = True +with ApiClient(configuration) as api_client: + api_instance = CloudCostManagementApi(api_client) + response = api_instance.get_cost_anomaly( + anomaly_id="anomaly_id", + ) + + print(response) diff --git a/examples/v2/cloud-cost-management/ListCostAnomalies.py b/examples/v2/cloud-cost-management/ListCostAnomalies.py new file mode 100644 index 0000000000..f802df4d72 --- /dev/null +++ b/examples/v2/cloud-cost-management/ListCostAnomalies.py @@ -0,0 +1,14 @@ +""" +List cost anomalies returns "OK" response +""" + +from datadog_api_client import ApiClient, Configuration +from datadog_api_client.v2.api.cloud_cost_management_api import CloudCostManagementApi + +configuration = Configuration() +configuration.unstable_operations["list_cost_anomalies"] = True +with ApiClient(configuration) as api_client: + api_instance = CloudCostManagementApi(api_client) + response = api_instance.list_cost_anomalies() + + print(response) diff --git a/src/datadog_api_client/configuration.py b/src/datadog_api_client/configuration.py index 7bede2f3eb..7a46309686 100644 --- a/src/datadog_api_client/configuration.py +++ b/src/datadog_api_client/configuration.py @@ -351,6 +351,8 @@ def __init__( "v2.search_security_monitoring_histsignals": False, "v2.get_code_coverage_branch_summary": False, "v2.get_code_coverage_commit_summary": False, + "v2.get_cost_anomaly": False, + "v2.list_cost_anomalies": False, "v2.create_dashboard_secure_embed": False, "v2.delete_dashboard_secure_embed": False, "v2.get_dashboard_secure_embed": False, diff --git a/src/datadog_api_client/v2/api/cloud_cost_management_api.py b/src/datadog_api_client/v2/api/cloud_cost_management_api.py index 1c66232eae..44e81313e4 100644 --- a/src/datadog_api_client/v2/api/cloud_cost_management_api.py +++ b/src/datadog_api_client/v2/api/cloud_cost_management_api.py @@ -11,6 +11,8 @@ UnsetType, unset, ) +from datadog_api_client.v2.model.cost_anomalies_response import CostAnomaliesResponse +from datadog_api_client.v2.model.cost_anomaly_response import CostAnomalyResponse from datadog_api_client.v2.model.arbitrary_rule_response_array import ArbitraryRuleResponseArray from datadog_api_client.v2.model.arbitrary_rule_response import ArbitraryRuleResponse from datadog_api_client.v2.model.arbitrary_cost_upsert_request import ArbitraryCostUpsertRequest @@ -345,6 +347,29 @@ def __init__(self, api_client=None): api_client=api_client, ) + self._get_cost_anomaly_endpoint = _Endpoint( + settings={ + "response_type": (CostAnomalyResponse,), + "auth": ["apiKeyAuth", "appKeyAuth", "AuthZ"], + "endpoint_path": "/api/v2/cost/anomalies/{anomaly_id}", + "operation_id": "get_cost_anomaly", + "http_method": "GET", + "version": "v2", + }, + params_map={ + "anomaly_id": { + "required": True, + "openapi_types": (str,), + "attribute": "anomaly_id", + "location": "path", + }, + }, + headers_map={ + "accept": ["application/json"], + }, + api_client=api_client, + ) + self._get_cost_awscur_config_endpoint = _Endpoint( settings={ "response_type": (AwsCurConfigResponse,), @@ -499,6 +524,79 @@ def __init__(self, api_client=None): api_client=api_client, ) + self._list_cost_anomalies_endpoint = _Endpoint( + settings={ + "response_type": (CostAnomaliesResponse,), + "auth": ["apiKeyAuth", "appKeyAuth", "AuthZ"], + "endpoint_path": "/api/v2/cost/anomalies", + "operation_id": "list_cost_anomalies", + "http_method": "GET", + "version": "v2", + }, + params_map={ + "start": { + "openapi_types": (int,), + "attribute": "start", + "location": "query", + }, + "end": { + "openapi_types": (int,), + "attribute": "end", + "location": "query", + }, + "filter": { + "openapi_types": (str,), + "attribute": "filter", + "location": "query", + }, + "min_anomalous_threshold": { + "openapi_types": (str,), + "attribute": "min_anomalous_threshold", + "location": "query", + }, + "min_cost_threshold": { + "openapi_types": (str,), + "attribute": "min_cost_threshold", + "location": "query", + }, + "dismissal_cause": { + "openapi_types": (str,), + "attribute": "dismissal_cause", + "location": "query", + }, + "order_by": { + "openapi_types": (str,), + "attribute": "order_by", + "location": "query", + }, + "order": { + "openapi_types": (str,), + "attribute": "order", + "location": "query", + }, + "limit": { + "openapi_types": (int,), + "attribute": "limit", + "location": "query", + }, + "offset": { + "openapi_types": (int,), + "attribute": "offset", + "location": "query", + }, + "provider_ids": { + "openapi_types": ([str],), + "attribute": "provider_ids", + "location": "query", + "collection_format": "multi", + }, + }, + headers_map={ + "accept": ["application/json"], + }, + api_client=api_client, + ) + self._list_cost_awscur_configs_endpoint = _Endpoint( settings={ "response_type": (AwsCURConfigsResponse,), @@ -1194,6 +1292,23 @@ def get_budget( return self._get_budget_endpoint.call_with_http_info(**kwargs) + def get_cost_anomaly( + self, + anomaly_id: str, + ) -> CostAnomalyResponse: + """Get cost anomaly. + + Get a detected Cloud Cost Management anomaly by UUID. + + :param anomaly_id: The UUID of the cost anomaly. + :type anomaly_id: str + :rtype: CostAnomalyResponse + """ + kwargs: Dict[str, Any] = {} + kwargs["anomaly_id"] = anomaly_id + + return self._get_cost_anomaly_endpoint.call_with_http_info(**kwargs) + def get_cost_awscur_config( self, cloud_account_id: int, @@ -1308,6 +1423,85 @@ def list_budgets( kwargs: Dict[str, Any] = {} return self._list_budgets_endpoint.call_with_http_info(**kwargs) + def list_cost_anomalies( + self, + *, + start: Union[int, UnsetType] = unset, + end: Union[int, UnsetType] = unset, + filter: Union[str, UnsetType] = unset, + min_anomalous_threshold: Union[str, UnsetType] = unset, + min_cost_threshold: Union[str, UnsetType] = unset, + dismissal_cause: Union[str, UnsetType] = unset, + order_by: Union[str, UnsetType] = unset, + order: Union[str, UnsetType] = unset, + limit: Union[int, UnsetType] = unset, + offset: Union[int, UnsetType] = unset, + provider_ids: Union[List[str], UnsetType] = unset, + ) -> CostAnomaliesResponse: + """List cost anomalies. + + List detected Cloud Cost Management anomalies for the organization. + + :param start: Start time as Unix milliseconds. Defaults to the start of the latest stable seven-day window. + :type start: int, optional + :param end: End time as Unix milliseconds. Defaults to the end of the latest stable seven-day window. + :type end: int, optional + :param filter: Optional JSON object mapping cost tag keys to allowed values, for example ``{"team":["payments"],"env":["prod"]}``. Filters match anomaly dimensions or correlated tags. + :type filter: str, optional + :param min_anomalous_threshold: Minimum absolute anomalous cost change to include. Numeric value; defaults to ``1``. + :type min_anomalous_threshold: str, optional + :param min_cost_threshold: Minimum absolute actual cost to include. Numeric value; defaults to ``0``. + :type min_cost_threshold: str, optional + :param dismissal_cause: Filter by resolution state. Use ``none`` for unresolved anomalies, ``all`` or ``*`` for resolved anomalies, or a comma-separated list of causes. + :type dismissal_cause: str, optional + :param order_by: Sort field. One of ``start_date`` , ``end_date`` , ``duration`` , ``max_cost`` , ``anomalous_cost`` , or ``dismissal_date``. Defaults to ``anomalous_cost``. + :type order_by: str, optional + :param order: Sort direction. One of ``asc`` or ``desc``. Defaults to ``desc``. + :type order: str, optional + :param limit: Maximum number of anomalies to return. Defaults to ``200``. + :type limit: int, optional + :param offset: Pagination offset. Defaults to ``0``. + :type offset: int, optional + :param provider_ids: Optional repeated cloud or SaaS provider filters, such as ``aws`` , ``gcp`` , ``azure`` , ``Oracle`` , ``datadog`` , ``OpenAI`` , or ``Anthropic``. + :type provider_ids: [str], optional + :rtype: CostAnomaliesResponse + """ + kwargs: Dict[str, Any] = {} + if start is not unset: + kwargs["start"] = start + + if end is not unset: + kwargs["end"] = end + + if filter is not unset: + kwargs["filter"] = filter + + if min_anomalous_threshold is not unset: + kwargs["min_anomalous_threshold"] = min_anomalous_threshold + + if min_cost_threshold is not unset: + kwargs["min_cost_threshold"] = min_cost_threshold + + if dismissal_cause is not unset: + kwargs["dismissal_cause"] = dismissal_cause + + if order_by is not unset: + kwargs["order_by"] = order_by + + if order is not unset: + kwargs["order"] = order + + if limit is not unset: + kwargs["limit"] = limit + + if offset is not unset: + kwargs["offset"] = offset + + if provider_ids is not unset: + kwargs["provider_ids"] = provider_ids + + return self._list_cost_anomalies_endpoint.call_with_http_info(**kwargs) + def list_cost_awscur_configs( self, ) -> AwsCURConfigsResponse: diff --git a/src/datadog_api_client/v2/model/cost_anomalies_response.py b/src/datadog_api_client/v2/model/cost_anomalies_response.py new file mode 100644 index 0000000000..17af3a9313 --- /dev/null +++ b/src/datadog_api_client/v2/model/cost_anomalies_response.py @@ -0,0 +1,42 @@ +# 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. +from __future__ import annotations + +from typing import Union, TYPE_CHECKING + +from datadog_api_client.model_utils import ( + ModelNormal, + cached_property, + unset, + UnsetType, +) + + +if TYPE_CHECKING: + from datadog_api_client.v2.model.cost_anomalies_response_data import CostAnomaliesResponseData + + +class CostAnomaliesResponse(ModelNormal): + @cached_property + def openapi_types(_): + from datadog_api_client.v2.model.cost_anomalies_response_data import CostAnomaliesResponseData + + return { + "data": (CostAnomaliesResponseData,), + } + + attribute_map = { + "data": "data", + } + + def __init__(self_, data: Union[CostAnomaliesResponseData, UnsetType] = unset, **kwargs): + """ + Response object containing a list of detected Cloud Cost Management anomalies and aggregated totals. + + :param data: Resource wrapper for the list of cost anomalies and aggregated totals. + :type data: CostAnomaliesResponseData, optional + """ + if data is not unset: + kwargs["data"] = data + super().__init__(kwargs) diff --git a/src/datadog_api_client/v2/model/cost_anomalies_response_data.py b/src/datadog_api_client/v2/model/cost_anomalies_response_data.py new file mode 100644 index 0000000000..16d90160c8 --- /dev/null +++ b/src/datadog_api_client/v2/model/cost_anomalies_response_data.py @@ -0,0 +1,58 @@ +# 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. +from __future__ import annotations + +from typing import TYPE_CHECKING + +from datadog_api_client.model_utils import ( + ModelNormal, + cached_property, +) + + +if TYPE_CHECKING: + from datadog_api_client.v2.model.cost_anomalies_response_data_attributes import CostAnomaliesResponseDataAttributes + from datadog_api_client.v2.model.cost_anomalies_response_data_type import CostAnomaliesResponseDataType + + +class CostAnomaliesResponseData(ModelNormal): + @cached_property + def openapi_types(_): + from datadog_api_client.v2.model.cost_anomalies_response_data_attributes import ( + CostAnomaliesResponseDataAttributes, + ) + from datadog_api_client.v2.model.cost_anomalies_response_data_type import CostAnomaliesResponseDataType + + return { + "attributes": (CostAnomaliesResponseDataAttributes,), + "id": (str,), + "type": (CostAnomaliesResponseDataType,), + } + + attribute_map = { + "attributes": "attributes", + "id": "id", + "type": "type", + } + + def __init__( + self_, attributes: CostAnomaliesResponseDataAttributes, id: str, type: CostAnomaliesResponseDataType, **kwargs + ): + """ + Resource wrapper for the list of cost anomalies and aggregated totals. + + :param attributes: Cost anomaly results and aggregated totals for the queried window. + :type attributes: CostAnomaliesResponseDataAttributes + + :param id: Static identifier of the cost anomalies collection resource. + :type id: str + + :param type: Type of the cost anomalies collection resource. Must be ``anomalies``. + :type type: CostAnomaliesResponseDataType + """ + super().__init__(kwargs) + + self_.attributes = attributes + self_.id = id + self_.type = type diff --git a/src/datadog_api_client/v2/model/cost_anomalies_response_data_attributes.py b/src/datadog_api_client/v2/model/cost_anomalies_response_data_attributes.py new file mode 100644 index 0000000000..fc48c53504 --- /dev/null +++ b/src/datadog_api_client/v2/model/cost_anomalies_response_data_attributes.py @@ -0,0 +1,72 @@ +# 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. +from __future__ import annotations + +from typing import List, TYPE_CHECKING + +from datadog_api_client.model_utils import ( + ModelNormal, + cached_property, +) + + +if TYPE_CHECKING: + from datadog_api_client.v2.model.cost_anomaly import CostAnomaly + + +class CostAnomaliesResponseDataAttributes(ModelNormal): + @cached_property + def openapi_types(_): + from datadog_api_client.v2.model.cost_anomaly import CostAnomaly + + return { + "anomalies": ([CostAnomaly],), + "avg_daily_anomalous_cost": (float,), + "total_actual_cost": (float,), + "total_anomalous_cost": (float,), + "total_count": (int,), + } + + attribute_map = { + "anomalies": "anomalies", + "avg_daily_anomalous_cost": "avg_daily_anomalous_cost", + "total_actual_cost": "total_actual_cost", + "total_anomalous_cost": "total_anomalous_cost", + "total_count": "total_count", + } + + def __init__( + self_, + anomalies: List[CostAnomaly], + avg_daily_anomalous_cost: float, + total_actual_cost: float, + total_anomalous_cost: float, + total_count: int, + **kwargs, + ): + """ + Cost anomaly results and aggregated totals for the queried window. + + :param anomalies: The list of cost anomalies that match the request. + :type anomalies: [CostAnomaly] + + :param avg_daily_anomalous_cost: Average daily anomalous cost change across the queried window. + :type avg_daily_anomalous_cost: float + + :param total_actual_cost: Total actual cost spent across the queried window for the matching providers. + :type total_actual_cost: float + + :param total_anomalous_cost: Sum of the anomalous cost change across all returned anomalies. + :type total_anomalous_cost: float + + :param total_count: Total number of anomalies that match the request. + :type total_count: int + """ + super().__init__(kwargs) + + self_.anomalies = anomalies + self_.avg_daily_anomalous_cost = avg_daily_anomalous_cost + self_.total_actual_cost = total_actual_cost + self_.total_anomalous_cost = total_anomalous_cost + self_.total_count = total_count diff --git a/src/datadog_api_client/v2/model/cost_anomalies_response_data_type.py b/src/datadog_api_client/v2/model/cost_anomalies_response_data_type.py new file mode 100644 index 0000000000..42b56d8a7a --- /dev/null +++ b/src/datadog_api_client/v2/model/cost_anomalies_response_data_type.py @@ -0,0 +1,35 @@ +# 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. +from __future__ import annotations + + +from datadog_api_client.model_utils import ( + ModelSimple, + cached_property, +) + +from typing import ClassVar + + +class CostAnomaliesResponseDataType(ModelSimple): + """ + Type of the cost anomalies collection resource. Must be `anomalies`. + + :param value: If omitted defaults to "anomalies". Must be one of ["anomalies"]. + :type value: str + """ + + allowed_values = { + "anomalies", + } + ANOMALIES: ClassVar["CostAnomaliesResponseDataType"] + + @cached_property + def openapi_types(_): + return { + "value": (str,), + } + + +CostAnomaliesResponseDataType.ANOMALIES = CostAnomaliesResponseDataType("anomalies") diff --git a/src/datadog_api_client/v2/model/cost_anomaly.py b/src/datadog_api_client/v2/model/cost_anomaly.py new file mode 100644 index 0000000000..9731110b56 --- /dev/null +++ b/src/datadog_api_client/v2/model/cost_anomaly.py @@ -0,0 +1,122 @@ +# 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. +from __future__ import annotations + +from typing import Union, TYPE_CHECKING + +from datadog_api_client.model_utils import ( + ModelNormal, + cached_property, + none_type, + unset, + UnsetType, +) + + +if TYPE_CHECKING: + from datadog_api_client.v2.model.cost_anomaly_correlated_tags import CostAnomalyCorrelatedTags + from datadog_api_client.v2.model.cost_anomaly_dimensions import CostAnomalyDimensions + from datadog_api_client.v2.model.cost_anomaly_dismissal import CostAnomalyDismissal + + +class CostAnomaly(ModelNormal): + @cached_property + def openapi_types(_): + from datadog_api_client.v2.model.cost_anomaly_correlated_tags import CostAnomalyCorrelatedTags + from datadog_api_client.v2.model.cost_anomaly_dimensions import CostAnomalyDimensions + from datadog_api_client.v2.model.cost_anomaly_dismissal import CostAnomalyDismissal + + return { + "actual_cost": (float,), + "anomalous_cost_change": (float,), + "anomaly_end": (int,), + "anomaly_start": (int,), + "correlated_tags": (CostAnomalyCorrelatedTags,), + "dimensions": (CostAnomalyDimensions,), + "dismissal": (CostAnomalyDismissal,), + "max_cost": (float,), + "provider": (str,), + "query": (str,), + "uuid": (str,), + } + + attribute_map = { + "actual_cost": "actual_cost", + "anomalous_cost_change": "anomalous_cost_change", + "anomaly_end": "anomaly_end", + "anomaly_start": "anomaly_start", + "correlated_tags": "correlated_tags", + "dimensions": "dimensions", + "dismissal": "dismissal", + "max_cost": "max_cost", + "provider": "provider", + "query": "query", + "uuid": "uuid", + } + + def __init__( + self_, + actual_cost: float, + anomalous_cost_change: float, + anomaly_end: int, + anomaly_start: int, + correlated_tags: Union[CostAnomalyCorrelatedTags, none_type], + dimensions: CostAnomalyDimensions, + max_cost: float, + provider: str, + query: str, + uuid: str, + dismissal: Union[CostAnomalyDismissal, UnsetType] = unset, + **kwargs, + ): + """ + A single detected Cloud Cost Management anomaly. + + :param actual_cost: Actual cost incurred during the anomaly window. + :type actual_cost: float + + :param anomalous_cost_change: Anomalous cost change relative to the expected baseline. + :type anomalous_cost_change: float + + :param anomaly_end: Anomaly end timestamp in Unix milliseconds. + :type anomaly_end: int + + :param anomaly_start: Anomaly start timestamp in Unix milliseconds. + :type anomaly_start: int + + :param correlated_tags: Map of correlated tag keys to the list of correlated tag values. + :type correlated_tags: CostAnomalyCorrelatedTags, none_type + + :param dimensions: Map of cost dimension keys to their values for the anomaly grouping. + :type dimensions: CostAnomalyDimensions + + :param dismissal: Resolution metadata for an anomaly that has been dismissed. + :type dismissal: CostAnomalyDismissal, optional + + :param max_cost: Maximum cost observed during the anomaly window. + :type max_cost: float + + :param provider: Cloud or SaaS provider associated with the anomaly (for example ``aws`` , ``gcp`` , ``azure`` ). + :type provider: str + + :param query: The metrics query that detected the anomaly. + :type query: str + + :param uuid: The unique identifier of the anomaly. + :type uuid: str + """ + if dismissal is not unset: + kwargs["dismissal"] = dismissal + super().__init__(kwargs) + + self_.actual_cost = actual_cost + self_.anomalous_cost_change = anomalous_cost_change + self_.anomaly_end = anomaly_end + self_.anomaly_start = anomaly_start + self_.correlated_tags = correlated_tags + self_.dimensions = dimensions + self_.max_cost = max_cost + self_.provider = provider + self_.query = query + self_.uuid = uuid diff --git a/src/datadog_api_client/v2/model/cost_anomaly_correlated_tags.py b/src/datadog_api_client/v2/model/cost_anomaly_correlated_tags.py new file mode 100644 index 0000000000..68b061f9d4 --- /dev/null +++ b/src/datadog_api_client/v2/model/cost_anomaly_correlated_tags.py @@ -0,0 +1,24 @@ +# 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. +from __future__ import annotations + + +from datadog_api_client.model_utils import ( + ModelNormal, + cached_property, +) + + +class CostAnomalyCorrelatedTags(ModelNormal): + @cached_property + def additional_properties_type(_): + return ([str],) + + _nullable = True + + def __init__(self_, **kwargs): + """ + Map of correlated tag keys to the list of correlated tag values. + """ + super().__init__(kwargs) diff --git a/src/datadog_api_client/v2/model/cost_anomaly_dimensions.py b/src/datadog_api_client/v2/model/cost_anomaly_dimensions.py new file mode 100644 index 0000000000..3a7705c4ae --- /dev/null +++ b/src/datadog_api_client/v2/model/cost_anomaly_dimensions.py @@ -0,0 +1,22 @@ +# 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. +from __future__ import annotations + + +from datadog_api_client.model_utils import ( + ModelNormal, + cached_property, +) + + +class CostAnomalyDimensions(ModelNormal): + @cached_property + def additional_properties_type(_): + return (str,) + + def __init__(self_, **kwargs): + """ + Map of cost dimension keys to their values for the anomaly grouping. + """ + super().__init__(kwargs) diff --git a/src/datadog_api_client/v2/model/cost_anomaly_dismissal.py b/src/datadog_api_client/v2/model/cost_anomaly_dismissal.py new file mode 100644 index 0000000000..9908837b37 --- /dev/null +++ b/src/datadog_api_client/v2/model/cost_anomaly_dismissal.py @@ -0,0 +1,57 @@ +# 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. +from __future__ import annotations + + +from datadog_api_client.model_utils import ( + ModelNormal, + cached_property, +) + + +class CostAnomalyDismissal(ModelNormal): + @cached_property + def openapi_types(_): + return { + "cause": (str,), + "dismissal_id": (str,), + "message": (str,), + "updated_at": (int,), + "updated_by": (str,), + } + + attribute_map = { + "cause": "cause", + "dismissal_id": "dismissal_id", + "message": "message", + "updated_at": "updated_at", + "updated_by": "updated_by", + } + + def __init__(self_, cause: str, dismissal_id: str, message: str, updated_at: int, updated_by: str, **kwargs): + """ + Resolution metadata for an anomaly that has been dismissed. + + :param cause: Reason the anomaly was dismissed. + :type cause: str + + :param dismissal_id: Unique identifier of the dismissal record. + :type dismissal_id: str + + :param message: Optional message explaining the dismissal. + :type message: str + + :param updated_at: Timestamp of the last dismissal update in Unix milliseconds. + :type updated_at: int + + :param updated_by: Identifier of the user that last updated the dismissal. + :type updated_by: str + """ + super().__init__(kwargs) + + self_.cause = cause + self_.dismissal_id = dismissal_id + self_.message = message + self_.updated_at = updated_at + self_.updated_by = updated_by diff --git a/src/datadog_api_client/v2/model/cost_anomaly_response.py b/src/datadog_api_client/v2/model/cost_anomaly_response.py new file mode 100644 index 0000000000..5d41586201 --- /dev/null +++ b/src/datadog_api_client/v2/model/cost_anomaly_response.py @@ -0,0 +1,42 @@ +# 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. +from __future__ import annotations + +from typing import Union, TYPE_CHECKING + +from datadog_api_client.model_utils import ( + ModelNormal, + cached_property, + unset, + UnsetType, +) + + +if TYPE_CHECKING: + from datadog_api_client.v2.model.cost_anomaly_response_data import CostAnomalyResponseData + + +class CostAnomalyResponse(ModelNormal): + @cached_property + def openapi_types(_): + from datadog_api_client.v2.model.cost_anomaly_response_data import CostAnomalyResponseData + + return { + "data": (CostAnomalyResponseData,), + } + + attribute_map = { + "data": "data", + } + + def __init__(self_, data: Union[CostAnomalyResponseData, UnsetType] = unset, **kwargs): + """ + Response object containing a single Cloud Cost Management anomaly. + + :param data: Resource wrapper for a single cost anomaly. + :type data: CostAnomalyResponseData, optional + """ + if data is not unset: + kwargs["data"] = data + super().__init__(kwargs) diff --git a/src/datadog_api_client/v2/model/cost_anomaly_response_data.py b/src/datadog_api_client/v2/model/cost_anomaly_response_data.py new file mode 100644 index 0000000000..da7765ead7 --- /dev/null +++ b/src/datadog_api_client/v2/model/cost_anomaly_response_data.py @@ -0,0 +1,54 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2019-Present Datadog, Inc. +from __future__ import annotations + +from typing import TYPE_CHECKING + +from datadog_api_client.model_utils import ( + ModelNormal, + cached_property, +) + + +if TYPE_CHECKING: + from datadog_api_client.v2.model.cost_anomaly import CostAnomaly + from datadog_api_client.v2.model.cost_anomalies_response_data_type import CostAnomaliesResponseDataType + + +class CostAnomalyResponseData(ModelNormal): + @cached_property + def openapi_types(_): + from datadog_api_client.v2.model.cost_anomaly import CostAnomaly + from datadog_api_client.v2.model.cost_anomalies_response_data_type import CostAnomaliesResponseDataType + + return { + "attributes": (CostAnomaly,), + "id": (str,), + "type": (CostAnomaliesResponseDataType,), + } + + attribute_map = { + "attributes": "attributes", + "id": "id", + "type": "type", + } + + def __init__(self_, attributes: CostAnomaly, id: str, type: CostAnomaliesResponseDataType, **kwargs): + """ + Resource wrapper for a single cost anomaly. + + :param attributes: A single detected Cloud Cost Management anomaly. + :type attributes: CostAnomaly + + :param id: The unique identifier of the anomaly. + :type id: str + + :param type: Type of the cost anomalies collection resource. Must be ``anomalies``. + :type type: CostAnomaliesResponseDataType + """ + super().__init__(kwargs) + + self_.attributes = attributes + self_.id = id + self_.type = type diff --git a/src/datadog_api_client/v2/models/__init__.py b/src/datadog_api_client/v2/models/__init__.py index 3bb64eb0bb..e45d8d58d5 100644 --- a/src/datadog_api_client/v2/models/__init__.py +++ b/src/datadog_api_client/v2/models/__init__.py @@ -1164,6 +1164,16 @@ from datadog_api_client.v2.model.convert_job_results_to_signals_data_type import ConvertJobResultsToSignalsDataType from datadog_api_client.v2.model.convert_job_results_to_signals_request import ConvertJobResultsToSignalsRequest from datadog_api_client.v2.model.cost_aggregation_type import CostAggregationType +from datadog_api_client.v2.model.cost_anomalies_response import CostAnomaliesResponse +from datadog_api_client.v2.model.cost_anomalies_response_data import CostAnomaliesResponseData +from datadog_api_client.v2.model.cost_anomalies_response_data_attributes import CostAnomaliesResponseDataAttributes +from datadog_api_client.v2.model.cost_anomalies_response_data_type import CostAnomaliesResponseDataType +from datadog_api_client.v2.model.cost_anomaly import CostAnomaly +from datadog_api_client.v2.model.cost_anomaly_correlated_tags import CostAnomalyCorrelatedTags +from datadog_api_client.v2.model.cost_anomaly_dimensions import CostAnomalyDimensions +from datadog_api_client.v2.model.cost_anomaly_dismissal import CostAnomalyDismissal +from datadog_api_client.v2.model.cost_anomaly_response import CostAnomalyResponse +from datadog_api_client.v2.model.cost_anomaly_response_data import CostAnomalyResponseData from datadog_api_client.v2.model.cost_attribution_aggregates_body import CostAttributionAggregatesBody from datadog_api_client.v2.model.cost_attribution_tag_names import CostAttributionTagNames from datadog_api_client.v2.model.cost_attribution_type import CostAttributionType @@ -8461,6 +8471,16 @@ "ConvertJobResultsToSignalsDataType", "ConvertJobResultsToSignalsRequest", "CostAggregationType", + "CostAnomaliesResponse", + "CostAnomaliesResponseData", + "CostAnomaliesResponseDataAttributes", + "CostAnomaliesResponseDataType", + "CostAnomaly", + "CostAnomalyCorrelatedTags", + "CostAnomalyDimensions", + "CostAnomalyDismissal", + "CostAnomalyResponse", + "CostAnomalyResponseData", "CostAttributionAggregatesBody", "CostAttributionTagNames", "CostAttributionType", diff --git a/tests/v2/features/cloud_cost_management.feature b/tests/v2/features/cloud_cost_management.feature index bf9f695d40..9bab51741e 100644 --- a/tests/v2/features/cloud_cost_management.feature +++ b/tests/v2/features/cloud_cost_management.feature @@ -292,6 +292,30 @@ Feature: Cloud Cost Management And the response "data.attributes.configs[0].dataset_type" is equal to "amortized" And the response "data.attributes.configs[1].dataset_type" is equal to "actual" + @generated @skip @team:DataDog/cloud-cost-management + Scenario: Get cost anomaly returns "Bad Request" response + Given operation "GetCostAnomaly" enabled + And new "GetCostAnomaly" request + And request contains "anomaly_id" parameter from "REPLACE.ME" + When the request is sent + Then the response status is 400 Bad Request + + @generated @skip @team:DataDog/cloud-cost-management + Scenario: Get cost anomaly returns "Not Found" response + Given operation "GetCostAnomaly" enabled + And new "GetCostAnomaly" request + And request contains "anomaly_id" parameter from "REPLACE.ME" + When the request is sent + Then the response status is 404 Not Found + + @generated @skip @team:DataDog/cloud-cost-management + Scenario: Get cost anomaly returns "OK" response + Given operation "GetCostAnomaly" enabled + And new "GetCostAnomaly" request + And request contains "anomaly_id" parameter from "REPLACE.ME" + When the request is sent + Then the response status is 200 OK + @replay-only @team:DataDog/cloud-cost-management Scenario: Get custom allocation rule returns "OK" response Given new "GetCustomAllocationRule" request @@ -357,6 +381,20 @@ Feature: Cloud Cost Management When the request is sent Then the response status is 200 OK + @generated @skip @team:DataDog/cloud-cost-management + Scenario: List cost anomalies returns "Bad Request" response + Given operation "ListCostAnomalies" enabled + And new "ListCostAnomalies" request + When the request is sent + Then the response status is 400 Bad Request + + @generated @skip @team:DataDog/cloud-cost-management + Scenario: List cost anomalies returns "OK" response + Given operation "ListCostAnomalies" enabled + And new "ListCostAnomalies" request + When the request is sent + Then the response status is 200 OK + @generated @skip @team:DataDog/cloud-cost-management Scenario: List custom allocation rule statuses returns "OK" response Given new "ListCustomAllocationRulesStatus" request diff --git a/tests/v2/features/undo.json b/tests/v2/features/undo.json index 1ca1c2309a..b9805518e9 100644 --- a/tests/v2/features/undo.json +++ b/tests/v2/features/undo.json @@ -1265,6 +1265,18 @@ "type": "safe" } }, + "ListCostAnomalies": { + "tag": "Cloud Cost Management", + "undo": { + "type": "safe" + } + }, + "GetCostAnomaly": { + "tag": "Cloud Cost Management", + "undo": { + "type": "safe" + } + }, "ListCustomAllocationRules": { "tag": "Cloud Cost Management", "undo": {