From 7fb56e0e0777ae303904427e3997087e534014a3 Mon Sep 17 00:00:00 2001 From: "ci.datadog-api-spec" Date: Wed, 30 Apr 2025 13:02:13 +0000 Subject: [PATCH] Regenerate client from commit ca363d75 of spec repo --- .apigentools-info | 8 +- .generator/schemas/v2/openapi.yaml | 247 ++++++++++++++++++ docs/datadog_api_client.v2.model.rst | 49 ++++ .../v2/cloud-cost-management/DeleteBudget.py | 13 + .../v2/cloud-cost-management/GetBudget.py | 15 ++ .../v2/cloud-cost-management/ListBudgets.py | 13 + .../v2/cloud-cost-management/UpsertBudget.py | 48 ++++ .../v2/api/cloud_cost_management_api.py | 146 +++++++++++ src/datadog_api_client/v2/model/budget.py | 62 +++++ .../v2/model/budget_array.py | 42 +++ .../v2/model/budget_attributes.py | 126 +++++++++ .../v2/model/budget_entry.py | 62 +++++ .../v2/model/budget_with_entries.py | 42 +++ .../v2/model/budget_with_entries_data.py | 62 +++++ src/datadog_api_client/v2/model/tag_filter.py | 43 +++ src/datadog_api_client/v2/models/__init__.py | 14 + ...budget_returns_bad_request_response.frozen | 1 + ...a_budget_returns_bad_request_response.yaml | 19 ++ ...a_budget_returns_not_found_response.frozen | 1 + ...t_a_budget_returns_not_found_response.yaml | 18 ++ ...st_list_budgets_returns_ok_response.frozen | 1 + ...test_list_budgets_returns_ok_response.yaml | 38 +++ ...budget_returns_bad_request_response.frozen | 1 + ...w_budget_returns_bad_request_response.yaml | 21 ++ ...w_budget_returns_not_found_response.frozen | 1 + ...new_budget_returns_not_found_response.yaml | 22 ++ ...te_a_new_budget_returns_ok_response.frozen | 1 + ...eate_a_new_budget_returns_ok_response.yaml | 36 +++ .../v2/features/cloud_cost_management.feature | 62 +++++ tests/v2/features/undo.json | 31 +++ 30 files changed, 1241 insertions(+), 4 deletions(-) create mode 100644 examples/v2/cloud-cost-management/DeleteBudget.py create mode 100644 examples/v2/cloud-cost-management/GetBudget.py create mode 100644 examples/v2/cloud-cost-management/ListBudgets.py create mode 100644 examples/v2/cloud-cost-management/UpsertBudget.py create mode 100644 src/datadog_api_client/v2/model/budget.py create mode 100644 src/datadog_api_client/v2/model/budget_array.py create mode 100644 src/datadog_api_client/v2/model/budget_attributes.py create mode 100644 src/datadog_api_client/v2/model/budget_entry.py create mode 100644 src/datadog_api_client/v2/model/budget_with_entries.py create mode 100644 src/datadog_api_client/v2/model/budget_with_entries_data.py create mode 100644 src/datadog_api_client/v2/model/tag_filter.py create mode 100644 tests/v2/cassettes/test_scenarios/test_delete_a_budget_returns_bad_request_response.frozen create mode 100644 tests/v2/cassettes/test_scenarios/test_delete_a_budget_returns_bad_request_response.yaml create mode 100644 tests/v2/cassettes/test_scenarios/test_get_a_budget_returns_not_found_response.frozen create mode 100644 tests/v2/cassettes/test_scenarios/test_get_a_budget_returns_not_found_response.yaml create mode 100644 tests/v2/cassettes/test_scenarios/test_list_budgets_returns_ok_response.frozen create mode 100644 tests/v2/cassettes/test_scenarios/test_list_budgets_returns_ok_response.yaml create mode 100644 tests/v2/cassettes/test_scenarios/test_update_if_exists_or_create_a_new_budget_returns_bad_request_response.frozen create mode 100644 tests/v2/cassettes/test_scenarios/test_update_if_exists_or_create_a_new_budget_returns_bad_request_response.yaml create mode 100644 tests/v2/cassettes/test_scenarios/test_update_if_exists_or_create_a_new_budget_returns_not_found_response.frozen create mode 100644 tests/v2/cassettes/test_scenarios/test_update_if_exists_or_create_a_new_budget_returns_not_found_response.yaml create mode 100644 tests/v2/cassettes/test_scenarios/test_update_if_exists_or_create_a_new_budget_returns_ok_response.frozen create mode 100644 tests/v2/cassettes/test_scenarios/test_update_if_exists_or_create_a_new_budget_returns_ok_response.yaml diff --git a/.apigentools-info b/.apigentools-info index 22556ef6d1..33bbca2dee 100644 --- a/.apigentools-info +++ b/.apigentools-info @@ -4,13 +4,13 @@ "spec_versions": { "v1": { "apigentools_version": "1.6.6", - "regenerated": "2025-04-29 18:57:43.853175", - "spec_repo_commit": "d1252b21" + "regenerated": "2025-04-30 13:01:34.246044", + "spec_repo_commit": "ca363d75" }, "v2": { "apigentools_version": "1.6.6", - "regenerated": "2025-04-29 18:57:43.868755", - "spec_repo_commit": "d1252b21" + "regenerated": "2025-04-30 13:01:34.261200", + "spec_repo_commit": "ca363d75" } } } \ No newline at end of file diff --git a/.generator/schemas/v2/openapi.yaml b/.generator/schemas/v2/openapi.yaml index dd3346b50b..d86f5ef23c 100644 --- a/.generator/schemas/v2/openapi.yaml +++ b/.generator/schemas/v2/openapi.yaml @@ -186,6 +186,13 @@ components: required: true schema: type: string + BudgetID: + description: Budget id. + in: path + name: budget_id + required: true + schema: + type: string CaseIDPathParameter: description: Case's UUID or key example: f98a5a5b-e0ff-45d4-b2f5-afe6e74de504 @@ -4720,6 +4727,135 @@ components: data: $ref: '#/components/schemas/BillingDimensionsMappingBody' type: object + Budget: + description: A budget. + properties: + attributes: + $ref: '#/components/schemas/BudgetAttributes' + id: + description: The id of the budget. + type: string + type: + description: The type of the object, must be `budget`. + type: string + type: object + BudgetArray: + description: An array of budgets. + example: + data: + - attributes: + created_at: 1741011342772 + created_by: user1 + end_month: 202502 + metrics_query: aws.cost.amortized{service:ec2} by {service} + name: my budget + org_id: 123 + start_month: 202501 + total_amount: 1000 + updated_at: 1741011342772 + updated_by: user2 + id: 00000000-0a0a-0a0a-aaa0-00000000000a + type: budget + properties: + data: + description: The `BudgetArray` `data`. + items: + $ref: '#/components/schemas/Budget' + type: array + type: object + BudgetAttributes: + description: The attributes of a budget. + properties: + created_at: + description: The timestamp when the budget was created. + example: 1738258683590 + format: int64 + type: integer + created_by: + description: The id of the user that created the budget. + example: 00000000-0a0a-0a0a-aaa0-00000000000a + type: string + end_month: + description: The month when the budget ends. + example: 202502 + format: int64 + type: integer + entries: + description: The entries of the budget. + items: + $ref: '#/components/schemas/BudgetEntry' + type: array + metrics_query: + description: The cost query used to track against the budget. + example: aws.cost.amortized{service:ec2} by {service} + type: string + name: + description: The name of the budget. + example: my budget + type: string + org_id: + description: The id of the org the budget belongs to. + example: 123 + format: int64 + type: integer + start_month: + description: The month when the budget starts. + example: 202501 + format: int64 + type: integer + total_amount: + description: The sum of all budget entries' amounts. + example: 1000 + format: double + type: number + updated_at: + description: The timestamp when the budget was last updated. + example: 1738258683590 + format: int64 + type: integer + updated_by: + description: The id of the user that created the budget. + example: 00000000-0a0a-0a0a-aaa0-00000000000a + type: string + type: object + BudgetEntry: + description: The entry of a budget. + properties: + amount: + description: The `amount` of the budget entry. + example: 500 + format: double + type: number + month: + description: The `month` of the budget entry. + example: 202501 + format: int64 + type: integer + tag_filters: + description: The `tag_filters` of the budget entry. + items: + $ref: '#/components/schemas/TagFilter' + type: array + type: object + BudgetWithEntries: + description: The definition of the `BudgetWithEntries` object. + properties: + data: + $ref: '#/components/schemas/BudgetWithEntriesData' + type: object + BudgetWithEntriesData: + description: A budget and all its entries. + properties: + attributes: + $ref: '#/components/schemas/BudgetAttributes' + id: + description: The `BudgetWithEntriesData` `id`. + example: 00000000-0a0a-0a0a-aaa0-00000000000a + type: string + type: + description: The type of the object, must be `budget`. + type: string + type: object BulkMuteFindingsRequest: description: The new bulk mute finding request. properties: @@ -36898,6 +37034,18 @@ components: format: double type: number type: object + TagFilter: + description: Tag filter for the budget's entries. + properties: + tag_key: + description: The key of the tag. + example: service + type: string + tag_value: + description: The value of the tag. + example: ec2 + type: string + type: object TagsEventAttribute: description: Array of tags associated with your event. example: @@ -43463,6 +43611,105 @@ paths: operator: OR permissions: - cloud_cost_management_write + /api/v2/cost/budget: + put: + description: Create a new budget or update an existing one. + operationId: UpsertBudget + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/BudgetWithEntries' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/BudgetWithEntries' + description: OK + '400': + $ref: '#/components/responses/BadRequestResponse' + '404': + $ref: '#/components/responses/NotFoundResponse' + '429': + $ref: '#/components/responses/TooManyRequestsResponse' + security: + - apiKeyAuth: [] + appKeyAuth: [] + - AuthZ: + - cloud_cost_management_write + summary: Create or update a budget + tags: + - Cloud Cost Management + /api/v2/cost/budget/{budget_id}: + delete: + description: Delete a budget. + operationId: DeleteBudget + parameters: + - $ref: '#/components/parameters/BudgetID' + responses: + '204': + description: No Content + '400': + $ref: '#/components/responses/BadRequestResponse' + '429': + $ref: '#/components/responses/TooManyRequestsResponse' + security: + - apiKeyAuth: [] + appKeyAuth: [] + - AuthZ: + - cloud_cost_management_write + summary: Delete a budget + tags: + - Cloud Cost Management + get: + description: Get a budget. + operationId: GetBudget + parameters: + - $ref: '#/components/parameters/BudgetID' + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/BudgetWithEntries' + description: OK + '400': + $ref: '#/components/responses/BadRequestResponse' + '404': + $ref: '#/components/responses/NotFoundResponse' + '429': + $ref: '#/components/responses/TooManyRequestsResponse' + security: + - apiKeyAuth: [] + appKeyAuth: [] + - AuthZ: + - cloud_cost_management_read + summary: Get a budget + tags: + - Cloud Cost Management + /api/v2/cost/budgets: + get: + description: List budgets. + operationId: ListBudgets + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/BudgetArray' + description: OK + '429': + $ref: '#/components/responses/TooManyRequestsResponse' + security: + - apiKeyAuth: [] + appKeyAuth: [] + - AuthZ: + - cloud_cost_management_read + summary: List budgets + tags: + - Cloud Cost Management /api/v2/cost/custom_costs: get: description: List the Custom Costs files. diff --git a/docs/datadog_api_client.v2.model.rst b/docs/datadog_api_client.v2.model.rst index 86a647f665..ac89d61639 100644 --- a/docs/datadog_api_client.v2.model.rst +++ b/docs/datadog_api_client.v2.model.rst @@ -1796,6 +1796,48 @@ datadog\_api\_client.v2.model.billing\_dimensions\_mapping\_response module :members: :show-inheritance: +datadog\_api\_client.v2.model.budget module +------------------------------------------- + +.. automodule:: datadog_api_client.v2.model.budget + :members: + :show-inheritance: + +datadog\_api\_client.v2.model.budget\_array module +-------------------------------------------------- + +.. automodule:: datadog_api_client.v2.model.budget_array + :members: + :show-inheritance: + +datadog\_api\_client.v2.model.budget\_attributes module +------------------------------------------------------- + +.. automodule:: datadog_api_client.v2.model.budget_attributes + :members: + :show-inheritance: + +datadog\_api\_client.v2.model.budget\_entry module +-------------------------------------------------- + +.. automodule:: datadog_api_client.v2.model.budget_entry + :members: + :show-inheritance: + +datadog\_api\_client.v2.model.budget\_with\_entries module +---------------------------------------------------------- + +.. automodule:: datadog_api_client.v2.model.budget_with_entries + :members: + :show-inheritance: + +datadog\_api\_client.v2.model.budget\_with\_entries\_data module +---------------------------------------------------------------- + +.. automodule:: datadog_api_client.v2.model.budget_with_entries_data + :members: + :show-inheritance: + datadog\_api\_client.v2.model.bulk\_mute\_findings\_request module ------------------------------------------------------------------ @@ -16020,6 +16062,13 @@ datadog\_api\_client.v2.model.step\_display\_bounds module :members: :show-inheritance: +datadog\_api\_client.v2.model.tag\_filter module +------------------------------------------------ + +.. automodule:: datadog_api_client.v2.model.tag_filter + :members: + :show-inheritance: + datadog\_api\_client.v2.model.tags\_event\_attribute module ----------------------------------------------------------- diff --git a/examples/v2/cloud-cost-management/DeleteBudget.py b/examples/v2/cloud-cost-management/DeleteBudget.py new file mode 100644 index 0000000000..715185c45a --- /dev/null +++ b/examples/v2/cloud-cost-management/DeleteBudget.py @@ -0,0 +1,13 @@ +""" +Delete a budget returns "No Content" response +""" + +from datadog_api_client import ApiClient, Configuration +from datadog_api_client.v2.api.cloud_cost_management_api import CloudCostManagementApi + +configuration = Configuration() +with ApiClient(configuration) as api_client: + api_instance = CloudCostManagementApi(api_client) + api_instance.delete_budget( + budget_id="budget_id", + ) diff --git a/examples/v2/cloud-cost-management/GetBudget.py b/examples/v2/cloud-cost-management/GetBudget.py new file mode 100644 index 0000000000..58a2d27659 --- /dev/null +++ b/examples/v2/cloud-cost-management/GetBudget.py @@ -0,0 +1,15 @@ +""" +Get a budget returns "OK" response +""" + +from datadog_api_client import ApiClient, Configuration +from datadog_api_client.v2.api.cloud_cost_management_api import CloudCostManagementApi + +configuration = Configuration() +with ApiClient(configuration) as api_client: + api_instance = CloudCostManagementApi(api_client) + response = api_instance.get_budget( + budget_id="budget_id", + ) + + print(response) diff --git a/examples/v2/cloud-cost-management/ListBudgets.py b/examples/v2/cloud-cost-management/ListBudgets.py new file mode 100644 index 0000000000..a51ed4bed1 --- /dev/null +++ b/examples/v2/cloud-cost-management/ListBudgets.py @@ -0,0 +1,13 @@ +""" +List budgets returns "OK" response +""" + +from datadog_api_client import ApiClient, Configuration +from datadog_api_client.v2.api.cloud_cost_management_api import CloudCostManagementApi + +configuration = Configuration() +with ApiClient(configuration) as api_client: + api_instance = CloudCostManagementApi(api_client) + response = api_instance.list_budgets() + + print(response) diff --git a/examples/v2/cloud-cost-management/UpsertBudget.py b/examples/v2/cloud-cost-management/UpsertBudget.py new file mode 100644 index 0000000000..480fb33fcc --- /dev/null +++ b/examples/v2/cloud-cost-management/UpsertBudget.py @@ -0,0 +1,48 @@ +""" +Create or update a budget returns "OK" response +""" + +from datadog_api_client import ApiClient, Configuration +from datadog_api_client.v2.api.cloud_cost_management_api import CloudCostManagementApi +from datadog_api_client.v2.model.budget_attributes import BudgetAttributes +from datadog_api_client.v2.model.budget_entry import BudgetEntry +from datadog_api_client.v2.model.budget_with_entries import BudgetWithEntries +from datadog_api_client.v2.model.budget_with_entries_data import BudgetWithEntriesData +from datadog_api_client.v2.model.tag_filter import TagFilter + +body = BudgetWithEntries( + data=BudgetWithEntriesData( + attributes=BudgetAttributes( + created_at=1738258683590, + created_by="00000000-0a0a-0a0a-aaa0-00000000000a", + end_month=202502, + entries=[ + BudgetEntry( + amount=500.0, + month=202501, + tag_filters=[ + TagFilter( + tag_key="service", + tag_value="ec2", + ), + ], + ), + ], + metrics_query="aws.cost.amortized{service:ec2} by {service}", + name="my budget", + org_id=123, + start_month=202501, + total_amount=1000.0, + updated_at=1738258683590, + updated_by="00000000-0a0a-0a0a-aaa0-00000000000a", + ), + id="00000000-0a0a-0a0a-aaa0-00000000000a", + ), +) + +configuration = Configuration() +with ApiClient(configuration) as api_client: + api_instance = CloudCostManagementApi(api_client) + response = api_instance.upsert_budget(body=body) + + print(response) 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 283f9b256a..efc896dc1b 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 @@ -15,6 +15,8 @@ from datadog_api_client.v2.model.azure_uc_config_pairs_response import AzureUCConfigPairsResponse from datadog_api_client.v2.model.azure_uc_config_post_request import AzureUCConfigPostRequest from datadog_api_client.v2.model.azure_uc_config_patch_request import AzureUCConfigPatchRequest +from datadog_api_client.v2.model.budget_with_entries import BudgetWithEntries +from datadog_api_client.v2.model.budget_array import BudgetArray from datadog_api_client.v2.model.custom_costs_file_list_response import CustomCostsFileListResponse from datadog_api_client.v2.model.custom_costs_file_upload_response import CustomCostsFileUploadResponse from datadog_api_client.v2.model.custom_costs_file_line_item import CustomCostsFileLineItem @@ -71,6 +73,29 @@ def __init__(self, api_client=None): api_client=api_client, ) + self._delete_budget_endpoint = _Endpoint( + settings={ + "response_type": None, + "auth": ["apiKeyAuth", "appKeyAuth", "AuthZ"], + "endpoint_path": "/api/v2/cost/budget/{budget_id}", + "operation_id": "delete_budget", + "http_method": "DELETE", + "version": "v2", + }, + params_map={ + "budget_id": { + "required": True, + "openapi_types": (str,), + "attribute": "budget_id", + "location": "path", + }, + }, + headers_map={ + "accept": ["*/*"], + }, + api_client=api_client, + ) + self._delete_cost_awscur_config_endpoint = _Endpoint( settings={ "response_type": None, @@ -140,6 +165,29 @@ def __init__(self, api_client=None): api_client=api_client, ) + self._get_budget_endpoint = _Endpoint( + settings={ + "response_type": (BudgetWithEntries,), + "auth": ["apiKeyAuth", "appKeyAuth", "AuthZ"], + "endpoint_path": "/api/v2/cost/budget/{budget_id}", + "operation_id": "get_budget", + "http_method": "GET", + "version": "v2", + }, + params_map={ + "budget_id": { + "required": True, + "openapi_types": (str,), + "attribute": "budget_id", + "location": "path", + }, + }, + headers_map={ + "accept": ["application/json"], + }, + api_client=api_client, + ) + self._get_custom_costs_file_endpoint = _Endpoint( settings={ "response_type": (CustomCostsFileGetResponse,), @@ -163,6 +211,22 @@ def __init__(self, api_client=None): api_client=api_client, ) + self._list_budgets_endpoint = _Endpoint( + settings={ + "response_type": (BudgetArray,), + "auth": ["apiKeyAuth", "appKeyAuth", "AuthZ"], + "endpoint_path": "/api/v2/cost/budgets", + "operation_id": "list_budgets", + "http_method": "GET", + "version": "v2", + }, + params_map={}, + headers_map={ + "accept": ["application/json"], + }, + api_client=api_client, + ) + self._list_cost_awscur_configs_endpoint = _Endpoint( settings={ "response_type": (AwsCURConfigsResponse,), @@ -284,6 +348,26 @@ def __init__(self, api_client=None): api_client=api_client, ) + self._upsert_budget_endpoint = _Endpoint( + settings={ + "response_type": (BudgetWithEntries,), + "auth": ["apiKeyAuth", "appKeyAuth", "AuthZ"], + "endpoint_path": "/api/v2/cost/budget", + "operation_id": "upsert_budget", + "http_method": "PUT", + "version": "v2", + }, + params_map={ + "body": { + "required": True, + "openapi_types": (BudgetWithEntries,), + "location": "body", + }, + }, + headers_map={"accept": ["application/json"], "content_type": ["application/json"]}, + api_client=api_client, + ) + def create_cost_awscur_config( self, body: AwsCURConfigPostRequest, @@ -316,6 +400,23 @@ def create_cost_azure_uc_configs( return self._create_cost_azure_uc_configs_endpoint.call_with_http_info(**kwargs) + def delete_budget( + self, + budget_id: str, + ) -> None: + """Delete a budget. + + Delete a budget. + + :param budget_id: Budget id. + :type budget_id: str + :rtype: None + """ + kwargs: Dict[str, Any] = {} + kwargs["budget_id"] = budget_id + + return self._delete_budget_endpoint.call_with_http_info(**kwargs) + def delete_cost_awscur_config( self, cloud_account_id: str, @@ -367,6 +468,23 @@ def delete_custom_costs_file( return self._delete_custom_costs_file_endpoint.call_with_http_info(**kwargs) + def get_budget( + self, + budget_id: str, + ) -> BudgetWithEntries: + """Get a budget. + + Get a budget. + + :param budget_id: Budget id. + :type budget_id: str + :rtype: BudgetWithEntries + """ + kwargs: Dict[str, Any] = {} + kwargs["budget_id"] = budget_id + + return self._get_budget_endpoint.call_with_http_info(**kwargs) + def get_custom_costs_file( self, file_id: str, @@ -384,6 +502,18 @@ def get_custom_costs_file( return self._get_custom_costs_file_endpoint.call_with_http_info(**kwargs) + def list_budgets( + self, + ) -> BudgetArray: + """List budgets. + + List budgets. + + :rtype: BudgetArray + """ + kwargs: Dict[str, Any] = {} + return self._list_budgets_endpoint.call_with_http_info(**kwargs) + def list_cost_awscur_configs( self, ) -> AwsCURConfigsResponse: @@ -477,3 +607,19 @@ def upload_custom_costs_file( kwargs["body"] = body return self._upload_custom_costs_file_endpoint.call_with_http_info(**kwargs) + + def upsert_budget( + self, + body: BudgetWithEntries, + ) -> BudgetWithEntries: + """Create or update a budget. + + Create a new budget or update an existing one. + + :type body: BudgetWithEntries + :rtype: BudgetWithEntries + """ + kwargs: Dict[str, Any] = {} + kwargs["body"] = body + + return self._upsert_budget_endpoint.call_with_http_info(**kwargs) diff --git a/src/datadog_api_client/v2/model/budget.py b/src/datadog_api_client/v2/model/budget.py new file mode 100644 index 0000000000..086fe301a4 --- /dev/null +++ b/src/datadog_api_client/v2/model/budget.py @@ -0,0 +1,62 @@ +# 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.budget_attributes import BudgetAttributes + + +class Budget(ModelNormal): + @cached_property + def openapi_types(_): + from datadog_api_client.v2.model.budget_attributes import BudgetAttributes + + return { + "attributes": (BudgetAttributes,), + "id": (str,), + "type": (str,), + } + + attribute_map = { + "attributes": "attributes", + "id": "id", + "type": "type", + } + + def __init__( + self_, + attributes: Union[BudgetAttributes, UnsetType] = unset, + id: Union[str, UnsetType] = unset, + type: Union[str, UnsetType] = unset, + **kwargs, + ): + """ + A budget. + + :param attributes: The attributes of a budget. + :type attributes: BudgetAttributes, optional + + :param id: The id of the budget. + :type id: str, optional + + :param type: The type of the object, must be ``budget``. + :type type: str, optional + """ + if attributes is not unset: + kwargs["attributes"] = attributes + if id is not unset: + kwargs["id"] = id + if type is not unset: + kwargs["type"] = type + super().__init__(kwargs) diff --git a/src/datadog_api_client/v2/model/budget_array.py b/src/datadog_api_client/v2/model/budget_array.py new file mode 100644 index 0000000000..90299f86ea --- /dev/null +++ b/src/datadog_api_client/v2/model/budget_array.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 List, Union, TYPE_CHECKING + +from datadog_api_client.model_utils import ( + ModelNormal, + cached_property, + unset, + UnsetType, +) + + +if TYPE_CHECKING: + from datadog_api_client.v2.model.budget import Budget + + +class BudgetArray(ModelNormal): + @cached_property + def openapi_types(_): + from datadog_api_client.v2.model.budget import Budget + + return { + "data": ([Budget],), + } + + attribute_map = { + "data": "data", + } + + def __init__(self_, data: Union[List[Budget], UnsetType] = unset, **kwargs): + """ + An array of budgets. + + :param data: The ``BudgetArray`` ``data``. + :type data: [Budget], optional + """ + if data is not unset: + kwargs["data"] = data + super().__init__(kwargs) diff --git a/src/datadog_api_client/v2/model/budget_attributes.py b/src/datadog_api_client/v2/model/budget_attributes.py new file mode 100644 index 0000000000..17eb229c6e --- /dev/null +++ b/src/datadog_api_client/v2/model/budget_attributes.py @@ -0,0 +1,126 @@ +# 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, Union, TYPE_CHECKING + +from datadog_api_client.model_utils import ( + ModelNormal, + cached_property, + unset, + UnsetType, +) + + +if TYPE_CHECKING: + from datadog_api_client.v2.model.budget_entry import BudgetEntry + + +class BudgetAttributes(ModelNormal): + @cached_property + def openapi_types(_): + from datadog_api_client.v2.model.budget_entry import BudgetEntry + + return { + "created_at": (int,), + "created_by": (str,), + "end_month": (int,), + "entries": ([BudgetEntry],), + "metrics_query": (str,), + "name": (str,), + "org_id": (int,), + "start_month": (int,), + "total_amount": (float,), + "updated_at": (int,), + "updated_by": (str,), + } + + attribute_map = { + "created_at": "created_at", + "created_by": "created_by", + "end_month": "end_month", + "entries": "entries", + "metrics_query": "metrics_query", + "name": "name", + "org_id": "org_id", + "start_month": "start_month", + "total_amount": "total_amount", + "updated_at": "updated_at", + "updated_by": "updated_by", + } + + def __init__( + self_, + created_at: Union[int, UnsetType] = unset, + created_by: Union[str, UnsetType] = unset, + end_month: Union[int, UnsetType] = unset, + entries: Union[List[BudgetEntry], UnsetType] = unset, + metrics_query: Union[str, UnsetType] = unset, + name: Union[str, UnsetType] = unset, + org_id: Union[int, UnsetType] = unset, + start_month: Union[int, UnsetType] = unset, + total_amount: Union[float, UnsetType] = unset, + updated_at: Union[int, UnsetType] = unset, + updated_by: Union[str, UnsetType] = unset, + **kwargs, + ): + """ + The attributes of a budget. + + :param created_at: The timestamp when the budget was created. + :type created_at: int, optional + + :param created_by: The id of the user that created the budget. + :type created_by: str, optional + + :param end_month: The month when the budget ends. + :type end_month: int, optional + + :param entries: The entries of the budget. + :type entries: [BudgetEntry], optional + + :param metrics_query: The cost query used to track against the budget. + :type metrics_query: str, optional + + :param name: The name of the budget. + :type name: str, optional + + :param org_id: The id of the org the budget belongs to. + :type org_id: int, optional + + :param start_month: The month when the budget starts. + :type start_month: int, optional + + :param total_amount: The sum of all budget entries' amounts. + :type total_amount: float, optional + + :param updated_at: The timestamp when the budget was last updated. + :type updated_at: int, optional + + :param updated_by: The id of the user that created the budget. + :type updated_by: str, optional + """ + if created_at is not unset: + kwargs["created_at"] = created_at + if created_by is not unset: + kwargs["created_by"] = created_by + if end_month is not unset: + kwargs["end_month"] = end_month + if entries is not unset: + kwargs["entries"] = entries + if metrics_query is not unset: + kwargs["metrics_query"] = metrics_query + if name is not unset: + kwargs["name"] = name + if org_id is not unset: + kwargs["org_id"] = org_id + if start_month is not unset: + kwargs["start_month"] = start_month + if total_amount is not unset: + kwargs["total_amount"] = total_amount + if updated_at is not unset: + kwargs["updated_at"] = updated_at + if updated_by is not unset: + kwargs["updated_by"] = updated_by + super().__init__(kwargs) diff --git a/src/datadog_api_client/v2/model/budget_entry.py b/src/datadog_api_client/v2/model/budget_entry.py new file mode 100644 index 0000000000..f173465b6d --- /dev/null +++ b/src/datadog_api_client/v2/model/budget_entry.py @@ -0,0 +1,62 @@ +# 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, Union, TYPE_CHECKING + +from datadog_api_client.model_utils import ( + ModelNormal, + cached_property, + unset, + UnsetType, +) + + +if TYPE_CHECKING: + from datadog_api_client.v2.model.tag_filter import TagFilter + + +class BudgetEntry(ModelNormal): + @cached_property + def openapi_types(_): + from datadog_api_client.v2.model.tag_filter import TagFilter + + return { + "amount": (float,), + "month": (int,), + "tag_filters": ([TagFilter],), + } + + attribute_map = { + "amount": "amount", + "month": "month", + "tag_filters": "tag_filters", + } + + def __init__( + self_, + amount: Union[float, UnsetType] = unset, + month: Union[int, UnsetType] = unset, + tag_filters: Union[List[TagFilter], UnsetType] = unset, + **kwargs, + ): + """ + The entry of a budget. + + :param amount: The ``amount`` of the budget entry. + :type amount: float, optional + + :param month: The ``month`` of the budget entry. + :type month: int, optional + + :param tag_filters: The ``tag_filters`` of the budget entry. + :type tag_filters: [TagFilter], optional + """ + if amount is not unset: + kwargs["amount"] = amount + if month is not unset: + kwargs["month"] = month + if tag_filters is not unset: + kwargs["tag_filters"] = tag_filters + super().__init__(kwargs) diff --git a/src/datadog_api_client/v2/model/budget_with_entries.py b/src/datadog_api_client/v2/model/budget_with_entries.py new file mode 100644 index 0000000000..0e55a60da4 --- /dev/null +++ b/src/datadog_api_client/v2/model/budget_with_entries.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.budget_with_entries_data import BudgetWithEntriesData + + +class BudgetWithEntries(ModelNormal): + @cached_property + def openapi_types(_): + from datadog_api_client.v2.model.budget_with_entries_data import BudgetWithEntriesData + + return { + "data": (BudgetWithEntriesData,), + } + + attribute_map = { + "data": "data", + } + + def __init__(self_, data: Union[BudgetWithEntriesData, UnsetType] = unset, **kwargs): + """ + The definition of the ``BudgetWithEntries`` object. + + :param data: A budget and all its entries. + :type data: BudgetWithEntriesData, optional + """ + if data is not unset: + kwargs["data"] = data + super().__init__(kwargs) diff --git a/src/datadog_api_client/v2/model/budget_with_entries_data.py b/src/datadog_api_client/v2/model/budget_with_entries_data.py new file mode 100644 index 0000000000..0b130514f3 --- /dev/null +++ b/src/datadog_api_client/v2/model/budget_with_entries_data.py @@ -0,0 +1,62 @@ +# 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.budget_attributes import BudgetAttributes + + +class BudgetWithEntriesData(ModelNormal): + @cached_property + def openapi_types(_): + from datadog_api_client.v2.model.budget_attributes import BudgetAttributes + + return { + "attributes": (BudgetAttributes,), + "id": (str,), + "type": (str,), + } + + attribute_map = { + "attributes": "attributes", + "id": "id", + "type": "type", + } + + def __init__( + self_, + attributes: Union[BudgetAttributes, UnsetType] = unset, + id: Union[str, UnsetType] = unset, + type: Union[str, UnsetType] = unset, + **kwargs, + ): + """ + A budget and all its entries. + + :param attributes: The attributes of a budget. + :type attributes: BudgetAttributes, optional + + :param id: The ``BudgetWithEntriesData`` ``id``. + :type id: str, optional + + :param type: The type of the object, must be ``budget``. + :type type: str, optional + """ + if attributes is not unset: + kwargs["attributes"] = attributes + if id is not unset: + kwargs["id"] = id + if type is not unset: + kwargs["type"] = type + super().__init__(kwargs) diff --git a/src/datadog_api_client/v2/model/tag_filter.py b/src/datadog_api_client/v2/model/tag_filter.py new file mode 100644 index 0000000000..adc18d0c67 --- /dev/null +++ b/src/datadog_api_client/v2/model/tag_filter.py @@ -0,0 +1,43 @@ +# 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 + +from datadog_api_client.model_utils import ( + ModelNormal, + cached_property, + unset, + UnsetType, +) + + +class TagFilter(ModelNormal): + @cached_property + def openapi_types(_): + return { + "tag_key": (str,), + "tag_value": (str,), + } + + attribute_map = { + "tag_key": "tag_key", + "tag_value": "tag_value", + } + + def __init__(self_, tag_key: Union[str, UnsetType] = unset, tag_value: Union[str, UnsetType] = unset, **kwargs): + """ + Tag filter for the budget's entries. + + :param tag_key: The key of the tag. + :type tag_key: str, optional + + :param tag_value: The value of the tag. + :type tag_value: str, optional + """ + if tag_key is not unset: + kwargs["tag_key"] = tag_key + if tag_value is not unset: + kwargs["tag_value"] = tag_value + super().__init__(kwargs) diff --git a/src/datadog_api_client/v2/models/__init__.py b/src/datadog_api_client/v2/models/__init__.py index e4cebd23b3..25285ddad4 100644 --- a/src/datadog_api_client/v2/models/__init__.py +++ b/src/datadog_api_client/v2/models/__init__.py @@ -333,6 +333,12 @@ BillingDimensionsMappingBodyItemAttributesEndpointsItemsStatus, ) from datadog_api_client.v2.model.billing_dimensions_mapping_response import BillingDimensionsMappingResponse +from datadog_api_client.v2.model.budget import Budget +from datadog_api_client.v2.model.budget_array import BudgetArray +from datadog_api_client.v2.model.budget_attributes import BudgetAttributes +from datadog_api_client.v2.model.budget_entry import BudgetEntry +from datadog_api_client.v2.model.budget_with_entries import BudgetWithEntries +from datadog_api_client.v2.model.budget_with_entries_data import BudgetWithEntriesData from datadog_api_client.v2.model.bulk_mute_findings_request import BulkMuteFindingsRequest from datadog_api_client.v2.model.bulk_mute_findings_request_attributes import BulkMuteFindingsRequestAttributes from datadog_api_client.v2.model.bulk_mute_findings_request_data import BulkMuteFindingsRequestData @@ -3211,6 +3217,7 @@ from datadog_api_client.v2.model.step import Step from datadog_api_client.v2.model.step_display import StepDisplay from datadog_api_client.v2.model.step_display_bounds import StepDisplayBounds +from datadog_api_client.v2.model.tag_filter import TagFilter from datadog_api_client.v2.model.tags_event_attribute import TagsEventAttribute from datadog_api_client.v2.model.team import Team from datadog_api_client.v2.model.team_attributes import TeamAttributes @@ -3668,6 +3675,12 @@ "BillingDimensionsMappingBodyItemAttributesEndpointsItems", "BillingDimensionsMappingBodyItemAttributesEndpointsItemsStatus", "BillingDimensionsMappingResponse", + "Budget", + "BudgetArray", + "BudgetAttributes", + "BudgetEntry", + "BudgetWithEntries", + "BudgetWithEntriesData", "BulkMuteFindingsRequest", "BulkMuteFindingsRequestAttributes", "BulkMuteFindingsRequestData", @@ -5708,6 +5721,7 @@ "Step", "StepDisplay", "StepDisplayBounds", + "TagFilter", "TagsEventAttribute", "Team", "TeamAttributes", diff --git a/tests/v2/cassettes/test_scenarios/test_delete_a_budget_returns_bad_request_response.frozen b/tests/v2/cassettes/test_scenarios/test_delete_a_budget_returns_bad_request_response.frozen new file mode 100644 index 0000000000..e8c5ba9a55 --- /dev/null +++ b/tests/v2/cassettes/test_scenarios/test_delete_a_budget_returns_bad_request_response.frozen @@ -0,0 +1 @@ +2025-04-28T11:45:34.874Z \ No newline at end of file diff --git a/tests/v2/cassettes/test_scenarios/test_delete_a_budget_returns_bad_request_response.yaml b/tests/v2/cassettes/test_scenarios/test_delete_a_budget_returns_bad_request_response.yaml new file mode 100644 index 0000000000..34a230c819 --- /dev/null +++ b/tests/v2/cassettes/test_scenarios/test_delete_a_budget_returns_bad_request_response.yaml @@ -0,0 +1,19 @@ +interactions: +- request: + body: null + headers: + accept: + - '*/*' + method: DELETE + uri: https://api.datadoghq.com/api/v2/cost/budget/1 + response: + body: + string: '{"errors":[{"status":"400","title":"Bad Request","detail":"invalid + budgetId"}]}' + headers: + content-type: + - application/vnd.api+json + status: + code: 400 + message: Bad Request +version: 1 diff --git a/tests/v2/cassettes/test_scenarios/test_get_a_budget_returns_not_found_response.frozen b/tests/v2/cassettes/test_scenarios/test_get_a_budget_returns_not_found_response.frozen new file mode 100644 index 0000000000..c5afe1be6b --- /dev/null +++ b/tests/v2/cassettes/test_scenarios/test_get_a_budget_returns_not_found_response.frozen @@ -0,0 +1 @@ +2025-04-28T11:45:35.263Z \ No newline at end of file diff --git a/tests/v2/cassettes/test_scenarios/test_get_a_budget_returns_not_found_response.yaml b/tests/v2/cassettes/test_scenarios/test_get_a_budget_returns_not_found_response.yaml new file mode 100644 index 0000000000..2c04a031a9 --- /dev/null +++ b/tests/v2/cassettes/test_scenarios/test_get_a_budget_returns_not_found_response.yaml @@ -0,0 +1,18 @@ +interactions: +- request: + body: null + headers: + accept: + - application/json + method: GET + uri: https://api.datadoghq.com/api/v2/cost/budget/9d055d22-0a0a-0a0a-aaa0-00000000000a + response: + body: + string: '{"errors":[{"status":"404","title":"Not Found"}]}' + headers: + content-type: + - application/vnd.api+json + status: + code: 404 + message: Not Found +version: 1 diff --git a/tests/v2/cassettes/test_scenarios/test_list_budgets_returns_ok_response.frozen b/tests/v2/cassettes/test_scenarios/test_list_budgets_returns_ok_response.frozen new file mode 100644 index 0000000000..934d4786d1 --- /dev/null +++ b/tests/v2/cassettes/test_scenarios/test_list_budgets_returns_ok_response.frozen @@ -0,0 +1 @@ +2025-04-28T11:45:35.577Z \ No newline at end of file diff --git a/tests/v2/cassettes/test_scenarios/test_list_budgets_returns_ok_response.yaml b/tests/v2/cassettes/test_scenarios/test_list_budgets_returns_ok_response.yaml new file mode 100644 index 0000000000..6e7ab458dd --- /dev/null +++ b/tests/v2/cassettes/test_scenarios/test_list_budgets_returns_ok_response.yaml @@ -0,0 +1,38 @@ +interactions: +- request: + body: null + headers: + accept: + - application/json + method: GET + uri: https://api.datadoghq.com/api/v2/cost/budgets + response: + body: + string: '{"data":[{"id":"3fba18e7-0067-491a-9308-3f73c8e2c575","type":"budget","attributes":{"created_at":1745571497036,"created_by":"3ad549bf-eba0-11e9-a77a-0705486660d0","end_month":202502,"metrics_query":"aws.cost.amortized{service:ec2} + by {service}","name":"my budget","org_id":321813,"start_month":202501,"total_amount":1000,"updated_at":1745571497036,"updated_by":"3ad549bf-eba0-11e9-a77a-0705486660d0"}},{"id":"57238082-4cc2-45a6-9064-22043737ed7c","type":"budget","attributes":{"created_at":1745583730189,"created_by":"3ad549bf-eba0-11e9-a77a-0705486660d0","end_month":202502,"metrics_query":"aws.cost.amortized{service:ec2} + by {service}","name":"my budget","org_id":321813,"start_month":202501,"total_amount":1000,"updated_at":1745583730189,"updated_by":"3ad549bf-eba0-11e9-a77a-0705486660d0"}},{"id":"f916baf2-02a4-4160-82b6-db389e4b43be","type":"budget","attributes":{"created_at":1745574561009,"created_by":"3ad549bf-eba0-11e9-a77a-0705486660d0","end_month":202502,"metrics_query":"aws.cost.amortized{service:ec2} + by {service}","name":"my budget","org_id":321813,"start_month":202501,"total_amount":1000,"updated_at":1745574561009,"updated_by":"3ad549bf-eba0-11e9-a77a-0705486660d0"}},{"id":"851ed069-23ab-441a-b8f3-8a5773403b3e","type":"budget","attributes":{"created_at":1745577123330,"created_by":"3ad549bf-eba0-11e9-a77a-0705486660d0","end_month":202502,"metrics_query":"aws.cost.amortized{service:ec2} + by {service}","name":"my budget","org_id":321813,"start_month":202501,"total_amount":1000,"updated_at":1745577123330,"updated_by":"3ad549bf-eba0-11e9-a77a-0705486660d0"}},{"id":"59073cc2-2478-421a-82a1-d79a5da28dda","type":"budget","attributes":{"created_at":1745577169183,"created_by":"3ad549bf-eba0-11e9-a77a-0705486660d0","end_month":202502,"metrics_query":"aws.cost.amortized{service:ec2} + by {service}","name":"my budget","org_id":321813,"start_month":202501,"total_amount":1000,"updated_at":1745577169183,"updated_by":"3ad549bf-eba0-11e9-a77a-0705486660d0"}},{"id":"5f349d8d-d387-4e15-afff-4782431e15d7","type":"budget","attributes":{"created_at":1745577608689,"created_by":"3ad549bf-eba0-11e9-a77a-0705486660d0","end_month":202502,"metrics_query":"aws.cost.amortized{service:ec2} + by {service}","name":"my budget","org_id":321813,"start_month":202501,"total_amount":1000,"updated_at":1745577608689,"updated_by":"3ad549bf-eba0-11e9-a77a-0705486660d0"}},{"id":"15ab22ba-5518-4e0c-9e06-a7f7bf2678bd","type":"budget","attributes":{"created_at":1745577943069,"created_by":"3ad549bf-eba0-11e9-a77a-0705486660d0","end_month":202502,"metrics_query":"aws.cost.amortized{service:ec2} + by {service}","name":"my budget","org_id":321813,"start_month":202501,"total_amount":1000,"updated_at":1745577943069,"updated_by":"3ad549bf-eba0-11e9-a77a-0705486660d0"}},{"id":"b18dc99d-1a12-469d-bd32-6bd98a6e5acb","type":"budget","attributes":{"created_at":1745577421488,"created_by":"3ad549bf-eba0-11e9-a77a-0705486660d0","end_month":202502,"metrics_query":"aws.cost.amortized{service:ec2} + by {service}","name":"my budget","org_id":321813,"start_month":202501,"total_amount":1000,"updated_at":1745577421488,"updated_by":"3ad549bf-eba0-11e9-a77a-0705486660d0"}},{"id":"8f569dc8-aea1-485d-a1c3-abc157c99a93","type":"budget","attributes":{"created_at":1745579211960,"created_by":"3ad549bf-eba0-11e9-a77a-0705486660d0","end_month":202502,"metrics_query":"aws.cost.amortized{service:ec2} + by {service}","name":"my budget","org_id":321813,"start_month":202501,"total_amount":1000,"updated_at":1745579211960,"updated_by":"3ad549bf-eba0-11e9-a77a-0705486660d0"}},{"id":"f3994f9b-dd15-43ea-a841-728d531eb11b","type":"budget","attributes":{"created_at":1745579361284,"created_by":"3ad549bf-eba0-11e9-a77a-0705486660d0","end_month":202502,"metrics_query":"aws.cost.amortized{service:ec2} + by {service}","name":"my budget","org_id":321813,"start_month":202501,"total_amount":1000,"updated_at":1745579361284,"updated_by":"3ad549bf-eba0-11e9-a77a-0705486660d0"}},{"id":"cb9fb4a9-c0df-4e4d-9835-3d210363d0bb","type":"budget","attributes":{"created_at":1745577992084,"created_by":"3ad549bf-eba0-11e9-a77a-0705486660d0","end_month":202502,"metrics_query":"aws.cost.amortized{service:ec2} + by {service}","name":"my budget","org_id":321813,"start_month":202501,"total_amount":1000,"updated_at":1745577992084,"updated_by":"3ad549bf-eba0-11e9-a77a-0705486660d0"}},{"id":"ff79e81b-1e6f-4a98-9500-91700fec0c2b","type":"budget","attributes":{"created_at":1745579291324,"created_by":"3ad549bf-eba0-11e9-a77a-0705486660d0","end_month":202502,"metrics_query":"aws.cost.amortized{service:ec2} + by {service}","name":"my budget","org_id":321813,"start_month":202501,"total_amount":1000,"updated_at":1745579291324,"updated_by":"3ad549bf-eba0-11e9-a77a-0705486660d0"}},{"id":"891f1139-fd93-499e-bad9-00409f61c565","type":"budget","attributes":{"created_at":1745586407929,"created_by":"3ad549bf-eba0-11e9-a77a-0705486660d0","end_month":202502,"metrics_query":"aws.cost.amortized{service:ec2} + by {service}","name":"my budget","org_id":321813,"start_month":202501,"total_amount":1000,"updated_at":1745586407929,"updated_by":"3ad549bf-eba0-11e9-a77a-0705486660d0"}},{"id":"85731223-6603-4639-9e01-b973f1ec9a24","type":"budget","attributes":{"created_at":1745579613007,"created_by":"3ad549bf-eba0-11e9-a77a-0705486660d0","end_month":202502,"metrics_query":"aws.cost.amortized{service:ec2} + by {service}","name":"my budget","org_id":321813,"start_month":202501,"total_amount":1000,"updated_at":1745579613007,"updated_by":"3ad549bf-eba0-11e9-a77a-0705486660d0"}},{"id":"affbf979-ed21-422f-a2eb-f8edcab237ff","type":"budget","attributes":{"created_at":1745579759927,"created_by":"3ad549bf-eba0-11e9-a77a-0705486660d0","end_month":202502,"metrics_query":"aws.cost.amortized{service:ec2} + by {service}","name":"my budget","org_id":321813,"start_month":202501,"total_amount":1000,"updated_at":1745579759927,"updated_by":"3ad549bf-eba0-11e9-a77a-0705486660d0"}},{"id":"651e9d4a-87aa-43c2-83ce-ec256e5cfea4","type":"budget","attributes":{"created_at":1745579644284,"created_by":"3ad549bf-eba0-11e9-a77a-0705486660d0","end_month":202502,"metrics_query":"aws.cost.amortized{service:ec2} + by {service}","name":"my budget","org_id":321813,"start_month":202501,"total_amount":1000,"updated_at":1745579644284,"updated_by":"3ad549bf-eba0-11e9-a77a-0705486660d0"}},{"id":"4abf19e6-9e97-4a76-bc33-3fc3a12c802c","type":"budget","attributes":{"created_at":1745580084222,"created_by":"3ad549bf-eba0-11e9-a77a-0705486660d0","end_month":202502,"metrics_query":"aws.cost.amortized{service:ec2} + by {service}","name":"my budget","org_id":321813,"start_month":202501,"total_amount":1000,"updated_at":1745580084222,"updated_by":"3ad549bf-eba0-11e9-a77a-0705486660d0"}},{"id":"fdf6d71d-30b3-4e5e-a644-2045be260b56","type":"budget","attributes":{"created_at":1745580326048,"created_by":"3ad549bf-eba0-11e9-a77a-0705486660d0","end_month":202502,"metrics_query":"aws.cost.amortized{service:ec2} + by {service}","name":"my budget","org_id":321813,"start_month":202501,"total_amount":1000,"updated_at":1745580326048,"updated_by":"3ad549bf-eba0-11e9-a77a-0705486660d0"}},{"id":"1c232ea0-94a4-442f-b618-5340a066f629","type":"budget","attributes":{"created_at":1745581289211,"created_by":"3ad549bf-eba0-11e9-a77a-0705486660d0","end_month":202502,"metrics_query":"aws.cost.amortized{service:ec2} + by {service}","name":"my budget","org_id":321813,"start_month":202501,"total_amount":1000,"updated_at":1745581289211,"updated_by":"3ad549bf-eba0-11e9-a77a-0705486660d0"}},{"id":"fc600e23-ebd1-454c-b863-d4be67481c65","type":"budget","attributes":{"created_at":1745580744852,"created_by":"3ad549bf-eba0-11e9-a77a-0705486660d0","end_month":202502,"metrics_query":"aws.cost.amortized{service:ec2} + by {service}","name":"my budget","org_id":321813,"start_month":202501,"total_amount":1000,"updated_at":1745580744852,"updated_by":"3ad549bf-eba0-11e9-a77a-0705486660d0"}}]}' + headers: + content-type: + - application/vnd.api+json + status: + code: 200 + message: OK +version: 1 diff --git a/tests/v2/cassettes/test_scenarios/test_update_if_exists_or_create_a_new_budget_returns_bad_request_response.frozen b/tests/v2/cassettes/test_scenarios/test_update_if_exists_or_create_a_new_budget_returns_bad_request_response.frozen new file mode 100644 index 0000000000..80edb05b38 --- /dev/null +++ b/tests/v2/cassettes/test_scenarios/test_update_if_exists_or_create_a_new_budget_returns_bad_request_response.frozen @@ -0,0 +1 @@ +2025-04-28T11:19:55.670Z \ No newline at end of file diff --git a/tests/v2/cassettes/test_scenarios/test_update_if_exists_or_create_a_new_budget_returns_bad_request_response.yaml b/tests/v2/cassettes/test_scenarios/test_update_if_exists_or_create_a_new_budget_returns_bad_request_response.yaml new file mode 100644 index 0000000000..f18c1c94b8 --- /dev/null +++ b/tests/v2/cassettes/test_scenarios/test_update_if_exists_or_create_a_new_budget_returns_bad_request_response.yaml @@ -0,0 +1,21 @@ +interactions: +- request: + body: '{"data":{"attributes":{}}}' + headers: + accept: + - application/json + content-type: + - application/json + method: PUT + uri: https://api.datadoghq.com/api/v2/cost/budget + response: + body: + string: '{"errors":[{"status":"400","title":"Bad Request","detail":"got type + \"\" expected one of \"budget\""}]}' + headers: + content-type: + - application/vnd.api+json + status: + code: 400 + message: Bad Request +version: 1 diff --git a/tests/v2/cassettes/test_scenarios/test_update_if_exists_or_create_a_new_budget_returns_not_found_response.frozen b/tests/v2/cassettes/test_scenarios/test_update_if_exists_or_create_a_new_budget_returns_not_found_response.frozen new file mode 100644 index 0000000000..2592ae96cc --- /dev/null +++ b/tests/v2/cassettes/test_scenarios/test_update_if_exists_or_create_a_new_budget_returns_not_found_response.frozen @@ -0,0 +1 @@ +2025-04-28T11:19:55.806Z \ No newline at end of file diff --git a/tests/v2/cassettes/test_scenarios/test_update_if_exists_or_create_a_new_budget_returns_not_found_response.yaml b/tests/v2/cassettes/test_scenarios/test_update_if_exists_or_create_a_new_budget_returns_not_found_response.yaml new file mode 100644 index 0000000000..400eca1ab8 --- /dev/null +++ b/tests/v2/cassettes/test_scenarios/test_update_if_exists_or_create_a_new_budget_returns_not_found_response.yaml @@ -0,0 +1,22 @@ +interactions: +- request: + body: '{"data":{"attributes":{"end_month":202502,"entries":[{"amount":500,"month":202501,"tag_filters":[{"tag_key":"service","tag_value":"ec2"}]},{"amount":500,"month":202502,"tag_filters":[{"tag_key":"service","tag_value":"ec2"}]}],"metrics_query":"aws.cost.amortized{service:ec2} + by {service}","name":"my budget","start_month":202501,"tags":["service"]},"id":"00000000-0a0a-0a0a-aaa0-00000000000a","type":"budget"}}' + headers: + accept: + - application/json + content-type: + - application/json + method: PUT + uri: https://api.datadoghq.com/api/v2/cost/budget + response: + body: + string: '{"errors":[{"title":"Generic Error","detail":"failed to upsert budget: + budget not found"}]}' + headers: + content-type: + - application/vnd.api+json + status: + code: 404 + message: Not Found +version: 1 diff --git a/tests/v2/cassettes/test_scenarios/test_update_if_exists_or_create_a_new_budget_returns_ok_response.frozen b/tests/v2/cassettes/test_scenarios/test_update_if_exists_or_create_a_new_budget_returns_ok_response.frozen new file mode 100644 index 0000000000..f698296318 --- /dev/null +++ b/tests/v2/cassettes/test_scenarios/test_update_if_exists_or_create_a_new_budget_returns_ok_response.frozen @@ -0,0 +1 @@ +2025-04-28T11:19:56.204Z \ No newline at end of file diff --git a/tests/v2/cassettes/test_scenarios/test_update_if_exists_or_create_a_new_budget_returns_ok_response.yaml b/tests/v2/cassettes/test_scenarios/test_update_if_exists_or_create_a_new_budget_returns_ok_response.yaml new file mode 100644 index 0000000000..abc374b881 --- /dev/null +++ b/tests/v2/cassettes/test_scenarios/test_update_if_exists_or_create_a_new_budget_returns_ok_response.yaml @@ -0,0 +1,36 @@ +interactions: +- request: + body: '{"data":{"attributes":{"end_month":202502,"entries":[{"amount":500,"month":202501,"tag_filters":[{"tag_key":"service","tag_value":"ec2"}]},{"amount":500,"month":202502,"tag_filters":[{"tag_key":"service","tag_value":"ec2"}]}],"metrics_query":"aws.cost.amortized{service:ec2} + by {service}","name":"my budget","start_month":202501},"type":"budget"}}' + headers: + accept: + - application/json + content-type: + - application/json + method: PUT + uri: https://api.datadoghq.com/api/v2/cost/budget + response: + body: + string: '{"data":{"id":"041ec283-154d-4427-987b-113f806e73f0","type":"budget","attributes":{"created_at":1745839196458,"created_by":"3ad549bf-eba0-11e9-a77a-0705486660d0","end_month":202502,"entries":[{"month":202501,"amount":500,"tag_filters":[{"tag_key":"service","tag_value":"ec2"}]},{"month":202502,"amount":500,"tag_filters":[{"tag_key":"service","tag_value":"ec2"}]}],"metrics_query":"aws.cost.amortized{service:ec2} + by {service}","name":"my budget","org_id":321813,"start_month":202501,"total_amount":1000,"updated_at":1745839196458,"updated_by":"3ad549bf-eba0-11e9-a77a-0705486660d0"}}}' + headers: + content-type: + - application/vnd.api+json + status: + code: 200 + message: OK +- request: + body: null + headers: + accept: + - '*/*' + method: DELETE + uri: https://api.datadoghq.com/api/v2/cost/budget/041ec283-154d-4427-987b-113f806e73f0 + response: + body: + string: '' + headers: {} + status: + code: 204 + message: No Content +version: 1 diff --git a/tests/v2/features/cloud_cost_management.feature b/tests/v2/features/cloud_cost_management.feature index d6c84a584e..4c31885101 100644 --- a/tests/v2/features/cloud_cost_management.feature +++ b/tests/v2/features/cloud_cost_management.feature @@ -43,6 +43,27 @@ Feature: Cloud Cost Management Then the response status is 200 OK And the response "data.attributes.configs[0].account_id" is equal to "1234abcd-1234-abcd-1234-1234abcd1234" + @generated @skip @team:Datadog/cloud-cost-management + Scenario: Create or update a budget returns "Bad Request" response + Given new "UpsertBudget" request + And body with value {"data": {"attributes": {"created_at": 1738258683590, "created_by": "00000000-0a0a-0a0a-aaa0-00000000000a", "end_month": 202502, "entries": [{"amount": 500, "month": 202501, "tag_filters": [{"tag_key": "service", "tag_value": "ec2"}]}], "metrics_query": "aws.cost.amortized{service:ec2} by {service}", "name": "my budget", "org_id": 123, "start_month": 202501, "total_amount": 1000, "updated_at": 1738258683590, "updated_by": "00000000-0a0a-0a0a-aaa0-00000000000a"}, "id": "00000000-0a0a-0a0a-aaa0-00000000000a"}} + When the request is sent + Then the response status is 400 Bad Request + + @generated @skip @team:Datadog/cloud-cost-management + Scenario: Create or update a budget returns "Not Found" response + Given new "UpsertBudget" request + And body with value {"data": {"attributes": {"created_at": 1738258683590, "created_by": "00000000-0a0a-0a0a-aaa0-00000000000a", "end_month": 202502, "entries": [{"amount": 500, "month": 202501, "tag_filters": [{"tag_key": "service", "tag_value": "ec2"}]}], "metrics_query": "aws.cost.amortized{service:ec2} by {service}", "name": "my budget", "org_id": 123, "start_month": 202501, "total_amount": 1000, "updated_at": 1738258683590, "updated_by": "00000000-0a0a-0a0a-aaa0-00000000000a"}, "id": "00000000-0a0a-0a0a-aaa0-00000000000a"}} + When the request is sent + Then the response status is 404 Not Found + + @generated @skip @team:Datadog/cloud-cost-management + Scenario: Create or update a budget returns "OK" response + Given new "UpsertBudget" request + And body with value {"data": {"attributes": {"created_at": 1738258683590, "created_by": "00000000-0a0a-0a0a-aaa0-00000000000a", "end_month": 202502, "entries": [{"amount": 500, "month": 202501, "tag_filters": [{"tag_key": "service", "tag_value": "ec2"}]}], "metrics_query": "aws.cost.amortized{service:ec2} by {service}", "name": "my budget", "org_id": 123, "start_month": 202501, "total_amount": 1000, "updated_at": 1738258683590, "updated_by": "00000000-0a0a-0a0a-aaa0-00000000000a"}, "id": "00000000-0a0a-0a0a-aaa0-00000000000a"}} + When the request is sent + Then the response status is 200 OK + @generated @skip @team:Datadog/cloud-cost-management Scenario: Delete Cloud Cost Management AWS CUR config returns "Bad Request" response Given new "DeleteCostAWSCURConfig" request @@ -99,6 +120,20 @@ Feature: Cloud Cost Management When the request is sent Then the response status is 204 No Content + @team:Datadog/cloud-cost-management + Scenario: Delete a budget returns "Bad Request" response + Given new "DeleteBudget" request + And request contains "budget_id" parameter with value "1" + When the request is sent + Then the response status is 400 Bad Request + + @generated @skip @team:Datadog/cloud-cost-management + Scenario: Delete a budget returns "No Content" response + Given new "DeleteBudget" request + And request contains "budget_id" parameter from "REPLACE.ME" + When the request is sent + Then the response status is 204 No Content + @replay-only @team:Datadog/cloud-cost-management Scenario: Get Custom Costs File returns "OK" response Given new "GetCustomCostsFile" request @@ -115,6 +150,27 @@ Feature: Cloud Cost Management When the request is sent Then the response status is 200 OK + @generated @skip @team:Datadog/cloud-cost-management + Scenario: Get a budget returns "Bad Request" response + Given new "GetBudget" request + And request contains "budget_id" parameter from "REPLACE.ME" + When the request is sent + Then the response status is 400 Bad Request + + @team:Datadog/cloud-cost-management + Scenario: Get a budget returns "Not Found" response + Given new "GetBudget" request + And request contains "budget_id" parameter with value "9d055d22-0a0a-0a0a-aaa0-00000000000a" + When the request is sent + Then the response status is 404 Not Found + + @generated @skip @team:Datadog/cloud-cost-management + Scenario: Get a budget returns "OK" response + Given new "GetBudget" request + And request contains "budget_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: List Cloud Cost Management AWS CUR configs returns "OK" response Given new "ListCostAWSCURConfigs" request @@ -142,6 +198,12 @@ Feature: Cloud Cost Management When the request is sent Then the response status is 200 OK + @team:Datadog/cloud-cost-management + Scenario: List budgets returns "OK" response + Given new "ListBudgets" request + When the request is sent + Then the response status is 200 OK + @replay-only @team:Datadog/cloud-cost-management Scenario: Update Cloud Cost Management AWS CUR config returns "OK" response Given new "UpdateCostAWSCURConfig" request diff --git a/tests/v2/features/undo.json b/tests/v2/features/undo.json index 4aba315c34..c1daab3852 100644 --- a/tests/v2/features/undo.json +++ b/tests/v2/features/undo.json @@ -608,6 +608,37 @@ "type": "idempotent" } }, + "UpsertBudget": { + "tag": "Cloud Cost Management", + "undo": { + "operationId": "DeleteBudget", + "parameters": [ + { + "name": "budget_id", + "source": "data.id" + } + ], + "type": "unsafe" + } + }, + "DeleteBudget": { + "tag": "Cloud Cost Management", + "undo": { + "type": "idempotent" + } + }, + "GetBudget": { + "tag": "Cloud Cost Management", + "undo": { + "type": "safe" + } + }, + "ListBudgets": { + "tag": "Cloud Cost Management", + "undo": { + "type": "safe" + } + }, "ListCustomCostsFiles": { "tag": "Cloud Cost Management", "undo": {