From e2f5e1b186e276930e96fb0c6abe3367769a1c38 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 6 Dec 2024 00:10:58 +0000 Subject: [PATCH] feat(infrastructure_targets): add bulk endpoints (#2246) --- .stats.yml | 2 +- api.md | 3 + .../access/infrastructure/targets.py | 180 +++++++++++++++- .../access/infrastructure/__init__.py | 2 + .../target_bulk_update_params.py | 58 +++++ .../target_bulk_update_response.py | 65 ++++++ .../access/infrastructure/test_targets.py | 201 ++++++++++++++++++ 7 files changed, 508 insertions(+), 3 deletions(-) create mode 100644 src/cloudflare/types/zero_trust/access/infrastructure/target_bulk_update_params.py create mode 100644 src/cloudflare/types/zero_trust/access/infrastructure/target_bulk_update_response.py diff --git a/.stats.yml b/.stats.yml index c82be893b3e..ee82d7a6ae8 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ -configured_endpoints: 1448 +configured_endpoints: 1450 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-0530d6510c5b139af850d24a4f932d5139c8d321a955ffa101b0debafbd75465.yml diff --git a/api.md b/api.md index 05584bac4a9..3e782d77fbd 100644 --- a/api.md +++ b/api.md @@ -5215,6 +5215,7 @@ from cloudflare.types.zero_trust.access.infrastructure import ( TargetCreateResponse, TargetUpdateResponse, TargetListResponse, + TargetBulkUpdateResponse, TargetGetResponse, ) ``` @@ -5225,6 +5226,8 @@ Methods: - client.zero_trust.access.infrastructure.targets.update(target_id, \*, account_id, \*\*params) -> Optional[TargetUpdateResponse] - client.zero_trust.access.infrastructure.targets.list(\*, account_id, \*\*params) -> SyncV4PagePaginationArray[TargetListResponse] - client.zero_trust.access.infrastructure.targets.delete(target_id, \*, account_id) -> None +- client.zero_trust.access.infrastructure.targets.bulk_delete(\*, account_id) -> None +- client.zero_trust.access.infrastructure.targets.bulk_update(\*, account_id, \*\*params) -> TargetBulkUpdateResponse - client.zero_trust.access.infrastructure.targets.get(target_id, \*, account_id) -> Optional[TargetGetResponse] ### Applications diff --git a/src/cloudflare/resources/zero_trust/access/infrastructure/targets.py b/src/cloudflare/resources/zero_trust/access/infrastructure/targets.py index e2d05821a23..364b09d482d 100644 --- a/src/cloudflare/resources/zero_trust/access/infrastructure/targets.py +++ b/src/cloudflare/resources/zero_trust/access/infrastructure/targets.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Type, Union, Optional, cast +from typing import Type, Union, Iterable, Optional, cast from datetime import datetime import httpx @@ -23,11 +23,17 @@ from ....._wrappers import ResultWrapper from .....pagination import SyncV4PagePaginationArray, AsyncV4PagePaginationArray from ....._base_client import AsyncPaginator, make_request_options -from .....types.zero_trust.access.infrastructure import target_list_params, target_create_params, target_update_params +from .....types.zero_trust.access.infrastructure import ( + target_list_params, + target_create_params, + target_update_params, + target_bulk_update_params, +) from .....types.zero_trust.access.infrastructure.target_get_response import TargetGetResponse from .....types.zero_trust.access.infrastructure.target_list_response import TargetListResponse from .....types.zero_trust.access.infrastructure.target_create_response import TargetCreateResponse from .....types.zero_trust.access.infrastructure.target_update_response import TargetUpdateResponse +from .....types.zero_trust.access.infrastructure.target_bulk_update_response import TargetBulkUpdateResponse __all__ = ["TargetsResource", "AsyncTargetsResource"] @@ -286,6 +292,79 @@ def delete( cast_to=NoneType, ) + def bulk_delete( + self, + *, + account_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> None: + """ + Removes one or more targets. + + Args: + account_id: Account identifier + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not account_id: + raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/accounts/{account_id}/infrastructure/targets/batch", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def bulk_update( + self, + *, + account_id: str, + body: Iterable[target_bulk_update_params.Body], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> TargetBulkUpdateResponse: + """ + Adds one or more targets. + + Args: + account_id: Account identifier + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not account_id: + raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + return self._put( + f"/accounts/{account_id}/infrastructure/targets/batch", + body=maybe_transform(body, Iterable[target_bulk_update_params.Body]), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TargetBulkUpdateResponse, + ) + def get( self, target_id: str, @@ -585,6 +664,79 @@ async def delete( cast_to=NoneType, ) + async def bulk_delete( + self, + *, + account_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> None: + """ + Removes one or more targets. + + Args: + account_id: Account identifier + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not account_id: + raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/accounts/{account_id}/infrastructure/targets/batch", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def bulk_update( + self, + *, + account_id: str, + body: Iterable[target_bulk_update_params.Body], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> TargetBulkUpdateResponse: + """ + Adds one or more targets. + + Args: + account_id: Account identifier + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not account_id: + raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + return await self._put( + f"/accounts/{account_id}/infrastructure/targets/batch", + body=await async_maybe_transform(body, Iterable[target_bulk_update_params.Body]), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TargetBulkUpdateResponse, + ) + async def get( self, target_id: str, @@ -646,6 +798,12 @@ def __init__(self, targets: TargetsResource) -> None: self.delete = to_raw_response_wrapper( targets.delete, ) + self.bulk_delete = to_raw_response_wrapper( + targets.bulk_delete, + ) + self.bulk_update = to_raw_response_wrapper( + targets.bulk_update, + ) self.get = to_raw_response_wrapper( targets.get, ) @@ -667,6 +825,12 @@ def __init__(self, targets: AsyncTargetsResource) -> None: self.delete = async_to_raw_response_wrapper( targets.delete, ) + self.bulk_delete = async_to_raw_response_wrapper( + targets.bulk_delete, + ) + self.bulk_update = async_to_raw_response_wrapper( + targets.bulk_update, + ) self.get = async_to_raw_response_wrapper( targets.get, ) @@ -688,6 +852,12 @@ def __init__(self, targets: TargetsResource) -> None: self.delete = to_streamed_response_wrapper( targets.delete, ) + self.bulk_delete = to_streamed_response_wrapper( + targets.bulk_delete, + ) + self.bulk_update = to_streamed_response_wrapper( + targets.bulk_update, + ) self.get = to_streamed_response_wrapper( targets.get, ) @@ -709,6 +879,12 @@ def __init__(self, targets: AsyncTargetsResource) -> None: self.delete = async_to_streamed_response_wrapper( targets.delete, ) + self.bulk_delete = async_to_streamed_response_wrapper( + targets.bulk_delete, + ) + self.bulk_update = async_to_streamed_response_wrapper( + targets.bulk_update, + ) self.get = async_to_streamed_response_wrapper( targets.get, ) diff --git a/src/cloudflare/types/zero_trust/access/infrastructure/__init__.py b/src/cloudflare/types/zero_trust/access/infrastructure/__init__.py index eda840eb2f1..132ad5ee5cf 100644 --- a/src/cloudflare/types/zero_trust/access/infrastructure/__init__.py +++ b/src/cloudflare/types/zero_trust/access/infrastructure/__init__.py @@ -9,3 +9,5 @@ from .target_update_params import TargetUpdateParams as TargetUpdateParams from .target_create_response import TargetCreateResponse as TargetCreateResponse from .target_update_response import TargetUpdateResponse as TargetUpdateResponse +from .target_bulk_update_params import TargetBulkUpdateParams as TargetBulkUpdateParams +from .target_bulk_update_response import TargetBulkUpdateResponse as TargetBulkUpdateResponse diff --git a/src/cloudflare/types/zero_trust/access/infrastructure/target_bulk_update_params.py b/src/cloudflare/types/zero_trust/access/infrastructure/target_bulk_update_params.py new file mode 100644 index 00000000000..d68489ab62b --- /dev/null +++ b/src/cloudflare/types/zero_trust/access/infrastructure/target_bulk_update_params.py @@ -0,0 +1,58 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Required, TypedDict + +__all__ = ["TargetBulkUpdateParams", "Body", "BodyIP", "BodyIPIPV4", "BodyIPIPV6"] + + +class TargetBulkUpdateParams(TypedDict, total=False): + account_id: Required[str] + """Account identifier""" + + body: Required[Iterable[Body]] + + +class BodyIPIPV4(TypedDict, total=False): + ip_addr: str + """IP address of the target""" + + virtual_network_id: str + """(optional) Private virtual network identifier for the target. + + If omitted, the default virtual network ID will be used. + """ + + +class BodyIPIPV6(TypedDict, total=False): + ip_addr: str + """IP address of the target""" + + virtual_network_id: str + """(optional) Private virtual network identifier for the target. + + If omitted, the default virtual network ID will be used. + """ + + +class BodyIP(TypedDict, total=False): + ipv4: BodyIPIPV4 + """The target's IPv4 address""" + + ipv6: BodyIPIPV6 + """The target's IPv6 address""" + + +class Body(TypedDict, total=False): + hostname: Required[str] + """A non-unique field that refers to a target. + + Case insensitive, maximum length of 255 characters, supports the use of special + characters dash and period, does not support spaces, and must start and end with + an alphanumeric character. + """ + + ip: Required[BodyIP] + """The IPv4/IPv6 address that identifies where to reach a target""" diff --git a/src/cloudflare/types/zero_trust/access/infrastructure/target_bulk_update_response.py b/src/cloudflare/types/zero_trust/access/infrastructure/target_bulk_update_response.py new file mode 100644 index 00000000000..75920b7ca80 --- /dev/null +++ b/src/cloudflare/types/zero_trust/access/infrastructure/target_bulk_update_response.py @@ -0,0 +1,65 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime +from typing_extensions import TypeAlias + +from ....._models import BaseModel + +__all__ = [ + "TargetBulkUpdateResponse", + "TargetBulkUpdateResponseItem", + "TargetBulkUpdateResponseItemIP", + "TargetBulkUpdateResponseItemIPIPV4", + "TargetBulkUpdateResponseItemIPIPV6", +] + + +class TargetBulkUpdateResponseItemIPIPV4(BaseModel): + ip_addr: Optional[str] = None + """IP address of the target""" + + virtual_network_id: Optional[str] = None + """(optional) Private virtual network identifier for the target. + + If omitted, the default virtual network ID will be used. + """ + + +class TargetBulkUpdateResponseItemIPIPV6(BaseModel): + ip_addr: Optional[str] = None + """IP address of the target""" + + virtual_network_id: Optional[str] = None + """(optional) Private virtual network identifier for the target. + + If omitted, the default virtual network ID will be used. + """ + + +class TargetBulkUpdateResponseItemIP(BaseModel): + ipv4: Optional[TargetBulkUpdateResponseItemIPIPV4] = None + """The target's IPv4 address""" + + ipv6: Optional[TargetBulkUpdateResponseItemIPIPV6] = None + """The target's IPv6 address""" + + +class TargetBulkUpdateResponseItem(BaseModel): + id: str + """Target identifier""" + + created_at: datetime + """Date and time at which the target was created""" + + hostname: str + """A non-unique field that refers to a target""" + + ip: TargetBulkUpdateResponseItemIP + """The IPv4/IPv6 address that identifies where to reach a target""" + + modified_at: datetime + """Date and time at which the target was modified""" + + +TargetBulkUpdateResponse: TypeAlias = List[TargetBulkUpdateResponseItem] diff --git a/tests/api_resources/zero_trust/access/infrastructure/test_targets.py b/tests/api_resources/zero_trust/access/infrastructure/test_targets.py index ddb3ad4edb9..6d6fec64674 100644 --- a/tests/api_resources/zero_trust/access/infrastructure/test_targets.py +++ b/tests/api_resources/zero_trust/access/infrastructure/test_targets.py @@ -16,6 +16,7 @@ TargetListResponse, TargetCreateResponse, TargetUpdateResponse, + TargetBulkUpdateResponse, ) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -267,6 +268,106 @@ def test_path_params_delete(self, client: Cloudflare) -> None: account_id="023e105f4ecef8ad9ca31a8372d0c353", ) + @parametrize + def test_method_bulk_delete(self, client: Cloudflare) -> None: + target = client.zero_trust.access.infrastructure.targets.bulk_delete( + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + assert target is None + + @parametrize + def test_raw_response_bulk_delete(self, client: Cloudflare) -> None: + response = client.zero_trust.access.infrastructure.targets.with_raw_response.bulk_delete( + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + target = response.parse() + assert target is None + + @parametrize + def test_streaming_response_bulk_delete(self, client: Cloudflare) -> None: + with client.zero_trust.access.infrastructure.targets.with_streaming_response.bulk_delete( + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + target = response.parse() + assert target is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_bulk_delete(self, client: Cloudflare) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): + client.zero_trust.access.infrastructure.targets.with_raw_response.bulk_delete( + account_id="", + ) + + @parametrize + def test_method_bulk_update(self, client: Cloudflare) -> None: + target = client.zero_trust.access.infrastructure.targets.bulk_update( + account_id="023e105f4ecef8ad9ca31a8372d0c353", + body=[ + { + "hostname": "infra-access-target", + "ip": {}, + } + ], + ) + assert_matches_type(TargetBulkUpdateResponse, target, path=["response"]) + + @parametrize + def test_raw_response_bulk_update(self, client: Cloudflare) -> None: + response = client.zero_trust.access.infrastructure.targets.with_raw_response.bulk_update( + account_id="023e105f4ecef8ad9ca31a8372d0c353", + body=[ + { + "hostname": "infra-access-target", + "ip": {}, + } + ], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + target = response.parse() + assert_matches_type(TargetBulkUpdateResponse, target, path=["response"]) + + @parametrize + def test_streaming_response_bulk_update(self, client: Cloudflare) -> None: + with client.zero_trust.access.infrastructure.targets.with_streaming_response.bulk_update( + account_id="023e105f4ecef8ad9ca31a8372d0c353", + body=[ + { + "hostname": "infra-access-target", + "ip": {}, + } + ], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + target = response.parse() + assert_matches_type(TargetBulkUpdateResponse, target, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_bulk_update(self, client: Cloudflare) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): + client.zero_trust.access.infrastructure.targets.with_raw_response.bulk_update( + account_id="", + body=[ + { + "hostname": "infra-access-target", + "ip": {}, + } + ], + ) + @parametrize def test_method_get(self, client: Cloudflare) -> None: target = client.zero_trust.access.infrastructure.targets.get( @@ -562,6 +663,106 @@ async def test_path_params_delete(self, async_client: AsyncCloudflare) -> None: account_id="023e105f4ecef8ad9ca31a8372d0c353", ) + @parametrize + async def test_method_bulk_delete(self, async_client: AsyncCloudflare) -> None: + target = await async_client.zero_trust.access.infrastructure.targets.bulk_delete( + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + assert target is None + + @parametrize + async def test_raw_response_bulk_delete(self, async_client: AsyncCloudflare) -> None: + response = await async_client.zero_trust.access.infrastructure.targets.with_raw_response.bulk_delete( + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + target = await response.parse() + assert target is None + + @parametrize + async def test_streaming_response_bulk_delete(self, async_client: AsyncCloudflare) -> None: + async with async_client.zero_trust.access.infrastructure.targets.with_streaming_response.bulk_delete( + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + target = await response.parse() + assert target is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_bulk_delete(self, async_client: AsyncCloudflare) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): + await async_client.zero_trust.access.infrastructure.targets.with_raw_response.bulk_delete( + account_id="", + ) + + @parametrize + async def test_method_bulk_update(self, async_client: AsyncCloudflare) -> None: + target = await async_client.zero_trust.access.infrastructure.targets.bulk_update( + account_id="023e105f4ecef8ad9ca31a8372d0c353", + body=[ + { + "hostname": "infra-access-target", + "ip": {}, + } + ], + ) + assert_matches_type(TargetBulkUpdateResponse, target, path=["response"]) + + @parametrize + async def test_raw_response_bulk_update(self, async_client: AsyncCloudflare) -> None: + response = await async_client.zero_trust.access.infrastructure.targets.with_raw_response.bulk_update( + account_id="023e105f4ecef8ad9ca31a8372d0c353", + body=[ + { + "hostname": "infra-access-target", + "ip": {}, + } + ], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + target = await response.parse() + assert_matches_type(TargetBulkUpdateResponse, target, path=["response"]) + + @parametrize + async def test_streaming_response_bulk_update(self, async_client: AsyncCloudflare) -> None: + async with async_client.zero_trust.access.infrastructure.targets.with_streaming_response.bulk_update( + account_id="023e105f4ecef8ad9ca31a8372d0c353", + body=[ + { + "hostname": "infra-access-target", + "ip": {}, + } + ], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + target = await response.parse() + assert_matches_type(TargetBulkUpdateResponse, target, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_bulk_update(self, async_client: AsyncCloudflare) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): + await async_client.zero_trust.access.infrastructure.targets.with_raw_response.bulk_update( + account_id="", + body=[ + { + "hostname": "infra-access-target", + "ip": {}, + } + ], + ) + @parametrize async def test_method_get(self, async_client: AsyncCloudflare) -> None: target = await async_client.zero_trust.access.infrastructure.targets.get(