diff --git a/.release-please-manifest.json b/.release-please-manifest.json index ce5e5c7c..157f0355 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.35.0" + ".": "0.36.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index efb5f168..eed43293 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 645 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gcore%2Fgcore-2f258036cad399055647446f0aae41c40f29bf6b486de68ed565653c10adb569.yml -openapi_spec_hash: 319b97727a2c05125aa27228db52053c -config_hash: 332323cce99008ceec46e04aeb672e0a +configured_endpoints: 647 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gcore%2Fgcore-3cc106e393b7a5de098a164d2a52ff79530d085d29bdf62a3c5026ad2273f748.yml +openapi_spec_hash: ad410d0835dc26f01ea6aabfd3587f7f +config_hash: ee9fe3677a3591bb2fcc219ef6448eb2 diff --git a/CHANGELOG.md b/CHANGELOG.md index e2a6eb33..3508c8d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,29 @@ # Changelog +## 0.36.0 (2026-02-25) + +Full Changelog: [v0.35.0...v0.36.0](https://github.com/G-Core/gcore-python/compare/v0.35.0...v0.36.0) + +### ⚠ BREAKING CHANGES + +* **cloud:** update gpu baremetal endpoints to latest versions + +### Features + +* **api:** aggregated API specs update ([b484f9c](https://github.com/G-Core/gcore-python/commit/b484f9c9aa4d3e54b42b49fbb06805d290ec2264)) +* **api:** aggregated API specs update ([0e36db9](https://github.com/G-Core/gcore-python/commit/0e36db93402657340c5c9f38263662ba0c905593)) +* **cloud:** update gpu baremetal endpoints to latest versions ([14512b9](https://github.com/G-Core/gcore-python/commit/14512b9907e7201e6b3f6a934dd84d0f277fc55c)) + + +### Bug Fixes + +* **cloud:** restore custom polling methods and missing wrappers for gpu baremetal ([3321a2f](https://github.com/G-Core/gcore-python/commit/3321a2f287f4a94aa88c738f09c5677e2c670ca9)) + + +### Chores + +* **internal:** make `test_proxy_environment_variables` more resilient to env ([cdfe354](https://github.com/G-Core/gcore-python/commit/cdfe3544b44f065624b5d7054873b291a54da836)) + ## 0.35.0 (2026-02-24) Full Changelog: [v0.34.0...v0.35.0](https://github.com/G-Core/gcore-python/compare/v0.34.0...v0.35.0) diff --git a/pyproject.toml b/pyproject.toml index 8d80f22d..045fe512 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "gcore" -version = "0.35.0" +version = "0.36.0" description = "The official Python library for the gcore API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/gcore/_version.py b/src/gcore/_version.py index 7bcbde4b..72b7e16a 100644 --- a/src/gcore/_version.py +++ b/src/gcore/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "gcore" -__version__ = "0.35.0" # x-release-please-version +__version__ = "0.36.0" # x-release-please-version diff --git a/src/gcore/resources/cloud/api.md b/src/gcore/resources/cloud/api.md index 79c3958d..0028620e 100644 --- a/src/gcore/resources/cloud/api.md +++ b/src/gcore/resources/cloud/api.md @@ -792,8 +792,9 @@ Methods: - client.cloud.gpu_baremetal.clusters.get(cluster_id, \*, project_id, region_id) -> GPUBaremetalCluster - client.cloud.gpu_baremetal.clusters.powercycle_all_servers(cluster_id, \*, project_id, region_id) -> GPUBaremetalClusterServerV1List - client.cloud.gpu_baremetal.clusters.reboot_all_servers(cluster_id, \*, project_id, region_id) -> GPUBaremetalClusterServerV1List -- client.cloud.gpu_baremetal.clusters.rebuild(cluster_id, \*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.gpu_baremetal.clusters.rebuild(cluster_id, \*, project_id, region_id) -> TaskIDList - client.cloud.gpu_baremetal.clusters.resize(cluster_id, \*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.gpu_baremetal.clusters.update_servers_settings(cluster_id, \*, project_id, region_id, \*\*params) -> GPUBaremetalCluster #### Interfaces @@ -822,6 +823,7 @@ Methods: - client.cloud.gpu_baremetal.clusters.servers.get_console(instance_id, \*, project_id, region_id) -> Console - client.cloud.gpu_baremetal.clusters.servers.powercycle(instance_id, \*, project_id, region_id) -> GPUBaremetalClusterServerV1 - client.cloud.gpu_baremetal.clusters.servers.reboot(instance_id, \*, project_id, region_id) -> GPUBaremetalClusterServerV1 +- client.cloud.gpu_baremetal.clusters.servers.rebuild(server_id, \*, project_id, region_id, cluster_id) -> TaskIDList #### Flavors diff --git a/src/gcore/resources/cloud/gpu_baremetal/clusters/clusters.py b/src/gcore/resources/cloud/gpu_baremetal/clusters/clusters.py index 700297ba..0ea1d06c 100644 --- a/src/gcore/resources/cloud/gpu_baremetal/clusters/clusters.py +++ b/src/gcore/resources/cloud/gpu_baremetal/clusters/clusters.py @@ -31,7 +31,7 @@ ServersResourceWithStreamingResponse, AsyncServersResourceWithStreamingResponse, ) -from ....._types import NOT_GIVEN, Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ....._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given from ....._utils import maybe_transform, async_maybe_transform from .interfaces import ( InterfacesResource, @@ -58,7 +58,7 @@ cluster_create_params, cluster_delete_params, cluster_resize_params, - cluster_rebuild_params, + cluster_update_servers_settings_params, ) from .....types.cloud.tag_update_map_param import TagUpdateMapParam from .....types.cloud.gpu_baremetal.gpu_baremetal_cluster import GPUBaremetalCluster @@ -522,9 +522,6 @@ def rebuild( *, project_id: int | None = None, region_id: int | None = None, - nodes: SequenceNotStr[str], - image_id: Optional[str] | Omit = omit, - user_data: Optional[str] | Omit = omit, # 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, @@ -532,19 +529,21 @@ def rebuild( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TaskIDList: - """Rebuild one or more nodes in a GPU cluster. + """Perform a rebuild operation on a bare metal GPU cluster. - All cluster nodes must be specified - to update the cluster image. + During the rebuild + process, the servers in cluster receive a new image, SSH key, and user data. + Important: Before triggering a rebuild, the cluster must have updated server + settings to apply. These cluster settings must be patched using the following + endpoint: PATCH + '/v3/gpu/baremetal/{`project_id`}/{`region_id`}/clusters/{`cluster_id`}/servers_settings' Args: - nodes: List of nodes uuids to be rebuild + project_id: Project ID - image_id: AI GPU image ID + region_id: Region ID - user_data: - String in base64 format.Examples of the `user_data`: - https://cloudinit.readthedocs.io/en/latest/topics/examples.html + cluster_id: Cluster unique identifier extra_headers: Send extra headers @@ -561,15 +560,7 @@ def rebuild( if not cluster_id: raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") return self._post( - f"/cloud/v1/ai/clusters/gpu/{project_id}/{region_id}/{cluster_id}/rebuild", - body=maybe_transform( - { - "nodes": nodes, - "image_id": image_id, - "user_data": user_data, - }, - cluster_rebuild_params.ClusterRebuildParams, - ), + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/clusters/{cluster_id}/rebuild", options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -621,6 +612,69 @@ def resize( cast_to=TaskIDList, ) + def update_servers_settings( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + image_id: str | Omit = omit, + servers_settings: cluster_update_servers_settings_params.ServersSettings | Omit = omit, + # 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, + ) -> GPUBaremetalCluster: + """ + This operation only modifies cluster settings such as SSH key, image, and user + data. **It does NOT modify or rebuild any existing servers in the cluster.** + + To apply these configuration changes to running servers, use the + `/cloud/v3/gpu/baremetal/{project_id}/{region_id}/clusters/{cluster_id}/rebuild` + endpoint. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + image_id: System image ID + + servers_settings: Configuration settings for the servers in the cluster + + 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 project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return self._patch( + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/clusters/{cluster_id}/servers_settings", + body=maybe_transform( + { + "image_id": image_id, + "servers_settings": servers_settings, + }, + cluster_update_servers_settings_params.ClusterUpdateServersSettingsParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GPUBaremetalCluster, + ) + def create_and_poll( self, *, @@ -639,7 +693,7 @@ def create_and_poll( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> GPUBaremetalCluster: """ Create a bare metal GPU cluster and wait for it to be ready. @@ -687,9 +741,6 @@ def rebuild_and_poll( *, project_id: int | None = None, region_id: int | None = None, - nodes: List[str], - image_id: Optional[str] | Omit = omit, - user_data: Optional[str] | Omit = omit, polling_interval_seconds: int | Omit = omit, polling_timeout_seconds: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -697,7 +748,7 @@ def rebuild_and_poll( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> GPUBaremetalCluster: """ Rebuild a bare metal GPU cluster and poll for the result. Only the first task will be polled. If you need to poll more tasks, use the `tasks.poll` method. @@ -706,9 +757,6 @@ def rebuild_and_poll( cluster_id=cluster_id, project_id=project_id, region_id=region_id, - nodes=nodes, - image_id=image_id, - user_data=user_data, extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, @@ -748,7 +796,7 @@ def resize_and_poll( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> GPUBaremetalCluster: """ Resize a bare metal GPU cluster and poll for the result. Only the first task will be polled. If you need to poll more tasks, use the `tasks.poll` method. @@ -1239,9 +1287,6 @@ async def rebuild( *, project_id: int | None = None, region_id: int | None = None, - nodes: SequenceNotStr[str], - image_id: Optional[str] | Omit = omit, - user_data: Optional[str] | Omit = omit, # 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, @@ -1249,19 +1294,21 @@ async def rebuild( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TaskIDList: - """Rebuild one or more nodes in a GPU cluster. + """Perform a rebuild operation on a bare metal GPU cluster. - All cluster nodes must be specified - to update the cluster image. + During the rebuild + process, the servers in cluster receive a new image, SSH key, and user data. + Important: Before triggering a rebuild, the cluster must have updated server + settings to apply. These cluster settings must be patched using the following + endpoint: PATCH + '/v3/gpu/baremetal/{`project_id`}/{`region_id`}/clusters/{`cluster_id`}/servers_settings' Args: - nodes: List of nodes uuids to be rebuild + project_id: Project ID - image_id: AI GPU image ID + region_id: Region ID - user_data: - String in base64 format.Examples of the `user_data`: - https://cloudinit.readthedocs.io/en/latest/topics/examples.html + cluster_id: Cluster unique identifier extra_headers: Send extra headers @@ -1278,15 +1325,7 @@ async def rebuild( if not cluster_id: raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") return await self._post( - f"/cloud/v1/ai/clusters/gpu/{project_id}/{region_id}/{cluster_id}/rebuild", - body=await async_maybe_transform( - { - "nodes": nodes, - "image_id": image_id, - "user_data": user_data, - }, - cluster_rebuild_params.ClusterRebuildParams, - ), + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/clusters/{cluster_id}/rebuild", options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1340,6 +1379,69 @@ async def resize( cast_to=TaskIDList, ) + async def update_servers_settings( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + image_id: str | Omit = omit, + servers_settings: cluster_update_servers_settings_params.ServersSettings | Omit = omit, + # 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, + ) -> GPUBaremetalCluster: + """ + This operation only modifies cluster settings such as SSH key, image, and user + data. **It does NOT modify or rebuild any existing servers in the cluster.** + + To apply these configuration changes to running servers, use the + `/cloud/v3/gpu/baremetal/{project_id}/{region_id}/clusters/{cluster_id}/rebuild` + endpoint. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + image_id: System image ID + + servers_settings: Configuration settings for the servers in the cluster + + 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 project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return await self._patch( + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/clusters/{cluster_id}/servers_settings", + body=await async_maybe_transform( + { + "image_id": image_id, + "servers_settings": servers_settings, + }, + cluster_update_servers_settings_params.ClusterUpdateServersSettingsParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GPUBaremetalCluster, + ) + async def create_and_poll( self, *, @@ -1358,7 +1460,7 @@ async def create_and_poll( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> GPUBaremetalCluster: """ Create a bare metal GPU cluster and wait for it to be ready. @@ -1406,9 +1508,6 @@ async def rebuild_and_poll( *, project_id: int | None = None, region_id: int | None = None, - nodes: List[str], - image_id: Optional[str] | Omit = omit, - user_data: Optional[str] | Omit = omit, polling_interval_seconds: int | Omit = omit, polling_timeout_seconds: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -1416,7 +1515,7 @@ async def rebuild_and_poll( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> GPUBaremetalCluster: """ Rebuild a bare metal GPU cluster and poll for the result. Only the first task will be polled. If you need to poll more tasks, use the `tasks.poll` method. @@ -1425,9 +1524,6 @@ async def rebuild_and_poll( cluster_id=cluster_id, project_id=project_id, region_id=region_id, - nodes=nodes, - image_id=image_id, - user_data=user_data, extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, @@ -1467,7 +1563,7 @@ async def resize_and_poll( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> GPUBaremetalCluster: """ Resize a bare metal GPU cluster and poll for the result. Only the first task will be polled. If you need to poll more tasks, use the `tasks.poll` method. @@ -1534,6 +1630,9 @@ def __init__(self, clusters: ClustersResource) -> None: self.resize = to_raw_response_wrapper( clusters.resize, ) + self.update_servers_settings = to_raw_response_wrapper( + clusters.update_servers_settings, + ) self.create_and_poll = to_raw_response_wrapper( clusters.create_and_poll, ) @@ -1592,6 +1691,9 @@ def __init__(self, clusters: AsyncClustersResource) -> None: self.resize = async_to_raw_response_wrapper( clusters.resize, ) + self.update_servers_settings = async_to_raw_response_wrapper( + clusters.update_servers_settings, + ) self.create_and_poll = async_to_raw_response_wrapper( clusters.create_and_poll, ) @@ -1650,6 +1752,9 @@ def __init__(self, clusters: ClustersResource) -> None: self.resize = to_streamed_response_wrapper( clusters.resize, ) + self.update_servers_settings = to_streamed_response_wrapper( + clusters.update_servers_settings, + ) self.create_and_poll = to_streamed_response_wrapper( clusters.create_and_poll, ) @@ -1708,6 +1813,9 @@ def __init__(self, clusters: AsyncClustersResource) -> None: self.resize = async_to_streamed_response_wrapper( clusters.resize, ) + self.update_servers_settings = async_to_streamed_response_wrapper( + clusters.update_servers_settings, + ) self.create_and_poll = async_to_streamed_response_wrapper( clusters.create_and_poll, ) diff --git a/src/gcore/resources/cloud/gpu_baremetal/clusters/servers.py b/src/gcore/resources/cloud/gpu_baremetal/clusters/servers.py index c4d6ad91..23ecc80b 100644 --- a/src/gcore/resources/cloud/gpu_baremetal/clusters/servers.py +++ b/src/gcore/resources/cloud/gpu_baremetal/clusters/servers.py @@ -215,50 +215,6 @@ def delete( cast_to=TaskIDList, ) - - def delete_and_poll( - self, - instance_id: str, - *, - project_id: int | None = None, - region_id: int | None = None, - cluster_id: str, - delete_floatings: bool | Omit = omit, - polling_interval_seconds: int | Omit = omit, - polling_timeout_seconds: int | Omit = omit, - # 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: - """ - Delete a bare metal GPU server from cluster and poll for the result. Only the first task will be polled. If you need to poll more tasks, use the `tasks.poll` method. - """ - response = self.delete( - instance_id=instance_id, - project_id=project_id, - region_id=region_id, - cluster_id=cluster_id, - delete_floatings=delete_floatings, - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - ) - if not response.tasks or len(response.tasks) < 1: - raise ValueError("Expected at least one task to be created") - self._client.cloud.tasks.poll( - response.tasks[0], - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - polling_interval_seconds=polling_interval_seconds, - polling_timeout_seconds=polling_timeout_seconds, - ) - - def get_console( self, instance_id: str, @@ -376,6 +332,104 @@ def reboot( cast_to=GPUBaremetalClusterServerV1, ) + def rebuild( + self, + server_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + cluster_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, + ) -> TaskIDList: + """Perform a rebuild operation on a bare metal GPU cluster server. + + During the + rebuild process, the server receive a new image, SSH key, and user data. + Important: Before triggering a rebuild, the cluster must have updated server + settings to apply. These cluster settings must be patched using the following + endpoint: PATCH + '/v3/gpu/baremetal/{`project_id`}/{`region_id`}/clusters/{`cluster_id`}/servers_settings' + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + server_id: Server unique 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 project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + if not server_id: + raise ValueError(f"Expected a non-empty value for `server_id` but received {server_id!r}") + return self._post( + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/clusters/{cluster_id}/servers/{server_id}/rebuild", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def delete_and_poll( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + cluster_id: str, + delete_floatings: bool | Omit = omit, + polling_interval_seconds: int | Omit = omit, + polling_timeout_seconds: int | Omit = omit, + # 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: + """ + Delete a bare metal GPU server from cluster and poll for the result. Only the first task will be polled. If you need to poll more tasks, use the `tasks.poll` method. + """ + response = self.delete( + instance_id=instance_id, + project_id=project_id, + region_id=region_id, + cluster_id=cluster_id, + delete_floatings=delete_floatings, + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + ) + if not response.tasks or len(response.tasks) < 1: + raise ValueError("Expected at least one task to be created") + self._client.cloud.tasks.poll( + response.tasks[0], + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + polling_interval_seconds=polling_interval_seconds, + polling_timeout_seconds=polling_timeout_seconds, + ) + class AsyncServersResource(AsyncAPIResource): @cached_property @@ -565,50 +619,6 @@ async def delete( cast_to=TaskIDList, ) - - async def delete_and_poll( - self, - instance_id: str, - *, - project_id: int | None = None, - region_id: int | None = None, - cluster_id: str, - delete_floatings: bool | Omit = omit, - polling_interval_seconds: int | Omit = omit, - polling_timeout_seconds: int | Omit = omit, - # 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: - """ - Delete a bare metal GPU server from cluster and poll for the result. Only the first task will be polled. If you need to poll more tasks, use the `tasks.poll` method. - """ - response = await self.delete( - instance_id=instance_id, - project_id=project_id, - region_id=region_id, - cluster_id=cluster_id, - delete_floatings=delete_floatings, - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - ) - if not response.tasks or len(response.tasks) < 1: - raise ValueError("Expected at least one task to be created") - await self._client.cloud.tasks.poll( - response.tasks[0], - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - polling_interval_seconds=polling_interval_seconds, - polling_timeout_seconds=polling_timeout_seconds, - ) - - async def get_console( self, instance_id: str, @@ -726,6 +736,104 @@ async def reboot( cast_to=GPUBaremetalClusterServerV1, ) + async def rebuild( + self, + server_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + cluster_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, + ) -> TaskIDList: + """Perform a rebuild operation on a bare metal GPU cluster server. + + During the + rebuild process, the server receive a new image, SSH key, and user data. + Important: Before triggering a rebuild, the cluster must have updated server + settings to apply. These cluster settings must be patched using the following + endpoint: PATCH + '/v3/gpu/baremetal/{`project_id`}/{`region_id`}/clusters/{`cluster_id`}/servers_settings' + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + server_id: Server unique 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 project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + if not server_id: + raise ValueError(f"Expected a non-empty value for `server_id` but received {server_id!r}") + return await self._post( + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/clusters/{cluster_id}/servers/{server_id}/rebuild", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def delete_and_poll( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + cluster_id: str, + delete_floatings: bool | Omit = omit, + polling_interval_seconds: int | Omit = omit, + polling_timeout_seconds: int | Omit = omit, + # 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: + """ + Delete a bare metal GPU server from cluster and poll for the result. Only the first task will be polled. If you need to poll more tasks, use the `tasks.poll` method. + """ + response = await self.delete( + instance_id=instance_id, + project_id=project_id, + region_id=region_id, + cluster_id=cluster_id, + delete_floatings=delete_floatings, + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + ) + if not response.tasks or len(response.tasks) < 1: + raise ValueError("Expected at least one task to be created") + await self._client.cloud.tasks.poll( + response.tasks[0], + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + polling_interval_seconds=polling_interval_seconds, + polling_timeout_seconds=polling_timeout_seconds, + ) + class ServersResourceWithRawResponse: def __init__(self, servers: ServersResource) -> None: @@ -746,6 +854,9 @@ def __init__(self, servers: ServersResource) -> None: self.reboot = to_raw_response_wrapper( servers.reboot, ) + self.rebuild = to_raw_response_wrapper( + servers.rebuild, + ) self.delete_and_poll = to_raw_response_wrapper( servers.delete_and_poll, ) @@ -770,6 +881,9 @@ def __init__(self, servers: AsyncServersResource) -> None: self.reboot = async_to_raw_response_wrapper( servers.reboot, ) + self.rebuild = async_to_raw_response_wrapper( + servers.rebuild, + ) self.delete_and_poll = async_to_raw_response_wrapper( servers.delete_and_poll, ) @@ -794,6 +908,9 @@ def __init__(self, servers: ServersResource) -> None: self.reboot = to_streamed_response_wrapper( servers.reboot, ) + self.rebuild = to_streamed_response_wrapper( + servers.rebuild, + ) self.delete_and_poll = to_streamed_response_wrapper( servers.delete_and_poll, ) @@ -818,6 +935,9 @@ def __init__(self, servers: AsyncServersResource) -> None: self.reboot = async_to_streamed_response_wrapper( servers.reboot, ) + self.rebuild = async_to_streamed_response_wrapper( + servers.rebuild, + ) self.delete_and_poll = async_to_streamed_response_wrapper( servers.delete_and_poll, ) diff --git a/src/gcore/resources/cloud/volumes.py b/src/gcore/resources/cloud/volumes.py index 28bd9ea0..f07ab83d 100644 --- a/src/gcore/resources/cloud/volumes.py +++ b/src/gcore/resources/cloud/volumes.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Iterable, Optional +from typing import Dict, Iterable, Optional from typing_extensions import Literal, overload import httpx @@ -69,7 +69,7 @@ def create( attachment_tag: str | Omit = omit, instance_id_to_attach_to: str | Omit = omit, lifecycle_policy_ids: Iterable[int] | Omit = omit, - tags: TagUpdateMapParam | Omit = omit, + tags: Dict[str, str] | Omit = omit, type_name: Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"] | Omit = omit, # 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. @@ -138,7 +138,7 @@ def create( instance_id_to_attach_to: str | Omit = omit, lifecycle_policy_ids: Iterable[int] | Omit = omit, size: int | Omit = omit, - tags: TagUpdateMapParam | Omit = omit, + tags: Dict[str, str] | Omit = omit, type_name: Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"] | Omit = omit, # 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. @@ -207,7 +207,7 @@ def create( attachment_tag: str | Omit = omit, instance_id_to_attach_to: str | Omit = omit, lifecycle_policy_ids: Iterable[int] | Omit = omit, - tags: TagUpdateMapParam | Omit = omit, + tags: Dict[str, str] | Omit = omit, type_name: Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"] | Omit = omit, # 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. @@ -276,7 +276,7 @@ def create( attachment_tag: str | Omit = omit, instance_id_to_attach_to: str | Omit = omit, lifecycle_policy_ids: Iterable[int] | Omit = omit, - tags: TagUpdateMapParam | Omit = omit, + tags: Dict[str, str] | Omit = omit, type_name: Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"] | Omit = omit, snapshot_id: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -1313,7 +1313,7 @@ async def create( attachment_tag: str | Omit = omit, instance_id_to_attach_to: str | Omit = omit, lifecycle_policy_ids: Iterable[int] | Omit = omit, - tags: TagUpdateMapParam | Omit = omit, + tags: Dict[str, str] | Omit = omit, type_name: Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"] | Omit = omit, # 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. @@ -1382,7 +1382,7 @@ async def create( instance_id_to_attach_to: str | Omit = omit, lifecycle_policy_ids: Iterable[int] | Omit = omit, size: int | Omit = omit, - tags: TagUpdateMapParam | Omit = omit, + tags: Dict[str, str] | Omit = omit, type_name: Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"] | Omit = omit, # 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. @@ -1451,7 +1451,7 @@ async def create( attachment_tag: str | Omit = omit, instance_id_to_attach_to: str | Omit = omit, lifecycle_policy_ids: Iterable[int] | Omit = omit, - tags: TagUpdateMapParam | Omit = omit, + tags: Dict[str, str] | Omit = omit, type_name: Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"] | Omit = omit, # 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. @@ -1520,7 +1520,7 @@ async def create( attachment_tag: str | Omit = omit, instance_id_to_attach_to: str | Omit = omit, lifecycle_policy_ids: Iterable[int] | Omit = omit, - tags: TagUpdateMapParam | Omit = omit, + tags: Dict[str, str] | Omit = omit, type_name: Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"] | Omit = omit, snapshot_id: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. diff --git a/src/gcore/resources/security/bgp_announces.py b/src/gcore/resources/security/bgp_announces.py index 1908f05a..a8f7cd47 100644 --- a/src/gcore/resources/security/bgp_announces.py +++ b/src/gcore/resources/security/bgp_announces.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Optional +from typing import List, Optional from typing_extensions import Literal import httpx @@ -48,7 +48,10 @@ def list( self, *, announced: Optional[bool] | Omit = omit, - origin: Optional[Literal["STATIC", "DYNAMIC"]] | Omit = omit, + client_id: Optional[int] | Omit = omit, + limit: Optional[int] | Omit = omit, + offset: Optional[int] | Omit = omit, + origin: Optional[List[Literal["STATIC", "DYNAMIC", "IAAS", "PROTECTED_NETWORK", "EDGE_PROXY"]]] | Omit = omit, site: Optional[str] | Omit = omit, # 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. @@ -57,13 +60,13 @@ def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> BgpAnnounceListResponse: - """Get BGP announces filtered by parameters. - - Shows announces in active profiles, - meaning that to get a non-empty response, the client must have at least one - active profile. + """ + List BGP announces with optional filtering by site, origin, announcement status, + and client. Args: + client_id: A positive integer ID + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -82,6 +85,9 @@ def list( query=maybe_transform( { "announced": announced, + "client_id": client_id, + "limit": limit, + "offset": offset, "origin": origin, "site": site, }, @@ -104,13 +110,16 @@ def toggle( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> object: - """Change BGP announces (it can be enabled or disabled, but not created or - updated). - - Can be applied to already existing announces in active profiles, - meaning that the client must have at least one active profile. + """ + Enable or disable BGP announces for a client. Args: + announce: IP network to announce + + enabled: Whether the announcement is enabled + + client_id: A positive integer ID + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -163,7 +172,10 @@ async def list( self, *, announced: Optional[bool] | Omit = omit, - origin: Optional[Literal["STATIC", "DYNAMIC"]] | Omit = omit, + client_id: Optional[int] | Omit = omit, + limit: Optional[int] | Omit = omit, + offset: Optional[int] | Omit = omit, + origin: Optional[List[Literal["STATIC", "DYNAMIC", "IAAS", "PROTECTED_NETWORK", "EDGE_PROXY"]]] | Omit = omit, site: Optional[str] | Omit = omit, # 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. @@ -172,13 +184,13 @@ async def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> BgpAnnounceListResponse: - """Get BGP announces filtered by parameters. - - Shows announces in active profiles, - meaning that to get a non-empty response, the client must have at least one - active profile. + """ + List BGP announces with optional filtering by site, origin, announcement status, + and client. Args: + client_id: A positive integer ID + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -197,6 +209,9 @@ async def list( query=await async_maybe_transform( { "announced": announced, + "client_id": client_id, + "limit": limit, + "offset": offset, "origin": origin, "site": site, }, @@ -219,13 +234,16 @@ async def toggle( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> object: - """Change BGP announces (it can be enabled or disabled, but not created or - updated). - - Can be applied to already existing announces in active profiles, - meaning that the client must have at least one active profile. + """ + Enable or disable BGP announces for a client. Args: + announce: IP network to announce + + enabled: Whether the announcement is enabled + + client_id: A positive integer ID + extra_headers: Send extra headers extra_query: Add additional query parameters to the request diff --git a/src/gcore/types/cloud/gpu_baremetal/__init__.py b/src/gcore/types/cloud/gpu_baremetal/__init__.py index baff756f..ccd8f847 100644 --- a/src/gcore/types/cloud/gpu_baremetal/__init__.py +++ b/src/gcore/types/cloud/gpu_baremetal/__init__.py @@ -8,4 +8,6 @@ from .cluster_delete_params import ClusterDeleteParams as ClusterDeleteParams from .cluster_resize_params import ClusterResizeParams as ClusterResizeParams from .gpu_baremetal_cluster import GPUBaremetalCluster as GPUBaremetalCluster -from .cluster_rebuild_params import ClusterRebuildParams as ClusterRebuildParams +from .cluster_update_servers_settings_params import ( + ClusterUpdateServersSettingsParams as ClusterUpdateServersSettingsParams, +) diff --git a/src/gcore/types/cloud/gpu_baremetal/cluster_rebuild_params.py b/src/gcore/types/cloud/gpu_baremetal/cluster_rebuild_params.py deleted file mode 100644 index f9fe6f9d..00000000 --- a/src/gcore/types/cloud/gpu_baremetal/cluster_rebuild_params.py +++ /dev/null @@ -1,28 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Required, TypedDict - -from ...._types import SequenceNotStr - -__all__ = ["ClusterRebuildParams"] - - -class ClusterRebuildParams(TypedDict, total=False): - project_id: int - - region_id: int - - nodes: Required[SequenceNotStr[str]] - """List of nodes uuids to be rebuild""" - - image_id: Optional[str] - """AI GPU image ID""" - - user_data: Optional[str] - """ - String in base64 format.Examples of the `user_data`: - https://cloudinit.readthedocs.io/en/latest/topics/examples.html - """ diff --git a/src/gcore/types/cloud/gpu_baremetal/cluster_update_servers_settings_params.py b/src/gcore/types/cloud/gpu_baremetal/cluster_update_servers_settings_params.py new file mode 100644 index 00000000..60977f28 --- /dev/null +++ b/src/gcore/types/cloud/gpu_baremetal/cluster_update_servers_settings_params.py @@ -0,0 +1,41 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["ClusterUpdateServersSettingsParams", "ServersSettings", "ServersSettingsCredentials"] + + +class ClusterUpdateServersSettingsParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + image_id: str + """System image ID""" + + servers_settings: ServersSettings + """Configuration settings for the servers in the cluster""" + + +class ServersSettingsCredentials(TypedDict, total=False): + """Optional server access credentials""" + + ssh_key_name: str + """ + Specifies the name of the SSH keypair, created via the + [/v1/`ssh_keys` endpoint](/docs/api-reference/cloud/ssh-keys/add-or-generate-ssh-key). + """ + + +class ServersSettings(TypedDict, total=False): + """Configuration settings for the servers in the cluster""" + + credentials: ServersSettingsCredentials + """Optional server access credentials""" + + user_data: str + """Optional custom user data (Base64-encoded)""" diff --git a/src/gcore/types/cloud/volume_create_params.py b/src/gcore/types/cloud/volume_create_params.py index 2e2dd5a7..43b240c3 100644 --- a/src/gcore/types/cloud/volume_create_params.py +++ b/src/gcore/types/cloud/volume_create_params.py @@ -2,11 +2,9 @@ from __future__ import annotations -from typing import Union, Iterable +from typing import Dict, Union, Iterable from typing_extensions import Literal, Required, TypeAlias, TypedDict -from .tag_update_map_param import TagUpdateMapParam - __all__ = [ "VolumeCreateParams", "CreateVolumeFromImageSerializer", @@ -49,7 +47,7 @@ class CreateVolumeFromImageSerializer(TypedDict, total=False): volume """ - tags: TagUpdateMapParam + tags: Dict[str, str] """Key-value tags to associate with the resource. A tag is a key-value pair that can be associated with a resource, enabling @@ -104,7 +102,7 @@ class CreateVolumeFromSnapshotSerializer(TypedDict, total=False): If specified, value must be equal to respective snapshot size """ - tags: TagUpdateMapParam + tags: Dict[str, str] """Key-value tags to associate with the resource. A tag is a key-value pair that can be associated with a resource, enabling @@ -153,7 +151,7 @@ class CreateNewVolumeSerializer(TypedDict, total=False): volume """ - tags: TagUpdateMapParam + tags: Dict[str, str] """Key-value tags to associate with the resource. A tag is a key-value pair that can be associated with a resource, enabling diff --git a/src/gcore/types/security/bgp_announce_list_params.py b/src/gcore/types/security/bgp_announce_list_params.py index 2bc6a994..64cf7ccf 100644 --- a/src/gcore/types/security/bgp_announce_list_params.py +++ b/src/gcore/types/security/bgp_announce_list_params.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Optional +from typing import List, Optional from typing_extensions import Literal, TypedDict __all__ = ["BgpAnnounceListParams"] @@ -11,6 +11,13 @@ class BgpAnnounceListParams(TypedDict, total=False): announced: Optional[bool] - origin: Optional[Literal["STATIC", "DYNAMIC"]] + client_id: Optional[int] + """A positive integer ID""" + + limit: Optional[int] + + offset: Optional[int] + + origin: Optional[List[Literal["STATIC", "DYNAMIC", "IAAS", "PROTECTED_NETWORK", "EDGE_PROXY"]]] site: Optional[str] diff --git a/src/gcore/types/security/bgp_announce_toggle_params.py b/src/gcore/types/security/bgp_announce_toggle_params.py index 4c5dd1b6..0dcd2a00 100644 --- a/src/gcore/types/security/bgp_announce_toggle_params.py +++ b/src/gcore/types/security/bgp_announce_toggle_params.py @@ -10,7 +10,10 @@ class BgpAnnounceToggleParams(TypedDict, total=False): announce: Required[str] + """IP network to announce""" enabled: Required[bool] + """Whether the announcement is enabled""" client_id: Optional[int] + """A positive integer ID""" diff --git a/tests/api_resources/cloud/gpu_baremetal/clusters/test_servers.py b/tests/api_resources/cloud/gpu_baremetal/clusters/test_servers.py index d468d7c4..d51f5379 100644 --- a/tests/api_resources/cloud/gpu_baremetal/clusters/test_servers.py +++ b/tests/api_resources/cloud/gpu_baremetal/clusters/test_servers.py @@ -294,6 +294,64 @@ def test_path_params_reboot(self, client: Gcore) -> None: region_id=0, ) + @parametrize + def test_method_rebuild(self, client: Gcore) -> None: + server = client.cloud.gpu_baremetal.clusters.servers.rebuild( + server_id="f1c1eeb6-1834-48c9-a7b0-daafce64872b", + project_id=1, + region_id=7, + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + ) + assert_matches_type(TaskIDList, server, path=["response"]) + + @parametrize + def test_raw_response_rebuild(self, client: Gcore) -> None: + response = client.cloud.gpu_baremetal.clusters.servers.with_raw_response.rebuild( + server_id="f1c1eeb6-1834-48c9-a7b0-daafce64872b", + project_id=1, + region_id=7, + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + server = response.parse() + assert_matches_type(TaskIDList, server, path=["response"]) + + @parametrize + def test_streaming_response_rebuild(self, client: Gcore) -> None: + with client.cloud.gpu_baremetal.clusters.servers.with_streaming_response.rebuild( + server_id="f1c1eeb6-1834-48c9-a7b0-daafce64872b", + project_id=1, + region_id=7, + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + server = response.parse() + assert_matches_type(TaskIDList, server, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_rebuild(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + client.cloud.gpu_baremetal.clusters.servers.with_raw_response.rebuild( + server_id="f1c1eeb6-1834-48c9-a7b0-daafce64872b", + project_id=1, + region_id=7, + cluster_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `server_id` but received ''"): + client.cloud.gpu_baremetal.clusters.servers.with_raw_response.rebuild( + server_id="", + project_id=1, + region_id=7, + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + ) + class TestAsyncServers: parametrize = pytest.mark.parametrize( @@ -570,3 +628,61 @@ async def test_path_params_reboot(self, async_client: AsyncGcore) -> None: project_id=0, region_id=0, ) + + @parametrize + async def test_method_rebuild(self, async_client: AsyncGcore) -> None: + server = await async_client.cloud.gpu_baremetal.clusters.servers.rebuild( + server_id="f1c1eeb6-1834-48c9-a7b0-daafce64872b", + project_id=1, + region_id=7, + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + ) + assert_matches_type(TaskIDList, server, path=["response"]) + + @parametrize + async def test_raw_response_rebuild(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_baremetal.clusters.servers.with_raw_response.rebuild( + server_id="f1c1eeb6-1834-48c9-a7b0-daafce64872b", + project_id=1, + region_id=7, + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + server = await response.parse() + assert_matches_type(TaskIDList, server, path=["response"]) + + @parametrize + async def test_streaming_response_rebuild(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_baremetal.clusters.servers.with_streaming_response.rebuild( + server_id="f1c1eeb6-1834-48c9-a7b0-daafce64872b", + project_id=1, + region_id=7, + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + server = await response.parse() + assert_matches_type(TaskIDList, server, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_rebuild(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + await async_client.cloud.gpu_baremetal.clusters.servers.with_raw_response.rebuild( + server_id="f1c1eeb6-1834-48c9-a7b0-daafce64872b", + project_id=1, + region_id=7, + cluster_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `server_id` but received ''"): + await async_client.cloud.gpu_baremetal.clusters.servers.with_raw_response.rebuild( + server_id="", + project_id=1, + region_id=7, + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + ) diff --git a/tests/api_resources/cloud/gpu_baremetal/test_clusters.py b/tests/api_resources/cloud/gpu_baremetal/test_clusters.py index a46257df..a1522ef3 100644 --- a/tests/api_resources/cloud/gpu_baremetal/test_clusters.py +++ b/tests/api_resources/cloud/gpu_baremetal/test_clusters.py @@ -405,32 +405,18 @@ def test_path_params_reboot_all_servers(self, client: Gcore) -> None: @parametrize def test_method_rebuild(self, client: Gcore) -> None: cluster = client.cloud.gpu_baremetal.clusters.rebuild( - cluster_id="cluster_id", - project_id=0, - region_id=0, - nodes=["string"], - ) - assert_matches_type(TaskIDList, cluster, path=["response"]) - - @parametrize - def test_method_rebuild_with_all_params(self, client: Gcore) -> None: - cluster = client.cloud.gpu_baremetal.clusters.rebuild( - cluster_id="cluster_id", - project_id=0, - region_id=0, - nodes=["string"], - image_id="f01fd9a0-9548-48ba-82dc-a8c8b2d6f2f1", - user_data="user_data", + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, ) assert_matches_type(TaskIDList, cluster, path=["response"]) @parametrize def test_raw_response_rebuild(self, client: Gcore) -> None: response = client.cloud.gpu_baremetal.clusters.with_raw_response.rebuild( - cluster_id="cluster_id", - project_id=0, - region_id=0, - nodes=["string"], + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, ) assert response.is_closed is True @@ -441,10 +427,9 @@ def test_raw_response_rebuild(self, client: Gcore) -> None: @parametrize def test_streaming_response_rebuild(self, client: Gcore) -> None: with client.cloud.gpu_baremetal.clusters.with_streaming_response.rebuild( - cluster_id="cluster_id", - project_id=0, - region_id=0, - nodes=["string"], + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -459,9 +444,8 @@ def test_path_params_rebuild(self, client: Gcore) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): client.cloud.gpu_baremetal.clusters.with_raw_response.rebuild( cluster_id="", - project_id=0, - region_id=0, - nodes=["string"], + project_id=1, + region_id=7, ) @parametrize @@ -514,6 +498,66 @@ def test_path_params_resize(self, client: Gcore) -> None: instances_count=1, ) + @parametrize + def test_method_update_servers_settings(self, client: Gcore) -> None: + cluster = client.cloud.gpu_baremetal.clusters.update_servers_settings( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + assert_matches_type(GPUBaremetalCluster, cluster, path=["response"]) + + @parametrize + def test_method_update_servers_settings_with_all_params(self, client: Gcore) -> None: + cluster = client.cloud.gpu_baremetal.clusters.update_servers_settings( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + image_id="3793c250-0b3b-4678-bab3-e11afbc29657", + servers_settings={ + "credentials": {"ssh_key_name": "my-ssh-key"}, + "user_data": "eyJ0ZXN0IjogImRhdGEifQ==", + }, + ) + assert_matches_type(GPUBaremetalCluster, cluster, path=["response"]) + + @parametrize + def test_raw_response_update_servers_settings(self, client: Gcore) -> None: + response = client.cloud.gpu_baremetal.clusters.with_raw_response.update_servers_settings( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(GPUBaremetalCluster, cluster, path=["response"]) + + @parametrize + def test_streaming_response_update_servers_settings(self, client: Gcore) -> None: + with client.cloud.gpu_baremetal.clusters.with_streaming_response.update_servers_settings( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(GPUBaremetalCluster, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update_servers_settings(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + client.cloud.gpu_baremetal.clusters.with_raw_response.update_servers_settings( + cluster_id="", + project_id=1, + region_id=7, + ) + class TestAsyncClusters: parametrize = pytest.mark.parametrize( @@ -903,32 +947,18 @@ async def test_path_params_reboot_all_servers(self, async_client: AsyncGcore) -> @parametrize async def test_method_rebuild(self, async_client: AsyncGcore) -> None: cluster = await async_client.cloud.gpu_baremetal.clusters.rebuild( - cluster_id="cluster_id", - project_id=0, - region_id=0, - nodes=["string"], - ) - assert_matches_type(TaskIDList, cluster, path=["response"]) - - @parametrize - async def test_method_rebuild_with_all_params(self, async_client: AsyncGcore) -> None: - cluster = await async_client.cloud.gpu_baremetal.clusters.rebuild( - cluster_id="cluster_id", - project_id=0, - region_id=0, - nodes=["string"], - image_id="f01fd9a0-9548-48ba-82dc-a8c8b2d6f2f1", - user_data="user_data", + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, ) assert_matches_type(TaskIDList, cluster, path=["response"]) @parametrize async def test_raw_response_rebuild(self, async_client: AsyncGcore) -> None: response = await async_client.cloud.gpu_baremetal.clusters.with_raw_response.rebuild( - cluster_id="cluster_id", - project_id=0, - region_id=0, - nodes=["string"], + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, ) assert response.is_closed is True @@ -939,10 +969,9 @@ async def test_raw_response_rebuild(self, async_client: AsyncGcore) -> None: @parametrize async def test_streaming_response_rebuild(self, async_client: AsyncGcore) -> None: async with async_client.cloud.gpu_baremetal.clusters.with_streaming_response.rebuild( - cluster_id="cluster_id", - project_id=0, - region_id=0, - nodes=["string"], + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -957,9 +986,8 @@ async def test_path_params_rebuild(self, async_client: AsyncGcore) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): await async_client.cloud.gpu_baremetal.clusters.with_raw_response.rebuild( cluster_id="", - project_id=0, - region_id=0, - nodes=["string"], + project_id=1, + region_id=7, ) @parametrize @@ -1011,3 +1039,63 @@ async def test_path_params_resize(self, async_client: AsyncGcore) -> None: region_id=0, instances_count=1, ) + + @parametrize + async def test_method_update_servers_settings(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.gpu_baremetal.clusters.update_servers_settings( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + assert_matches_type(GPUBaremetalCluster, cluster, path=["response"]) + + @parametrize + async def test_method_update_servers_settings_with_all_params(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.gpu_baremetal.clusters.update_servers_settings( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + image_id="3793c250-0b3b-4678-bab3-e11afbc29657", + servers_settings={ + "credentials": {"ssh_key_name": "my-ssh-key"}, + "user_data": "eyJ0ZXN0IjogImRhdGEifQ==", + }, + ) + assert_matches_type(GPUBaremetalCluster, cluster, path=["response"]) + + @parametrize + async def test_raw_response_update_servers_settings(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_baremetal.clusters.with_raw_response.update_servers_settings( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(GPUBaremetalCluster, cluster, path=["response"]) + + @parametrize + async def test_streaming_response_update_servers_settings(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_baremetal.clusters.with_streaming_response.update_servers_settings( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(GPUBaremetalCluster, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update_servers_settings(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + await async_client.cloud.gpu_baremetal.clusters.with_raw_response.update_servers_settings( + cluster_id="", + project_id=1, + region_id=7, + ) diff --git a/tests/api_resources/cloud/test_volumes.py b/tests/api_resources/cloud/test_volumes.py index ffe1d3bc..1b58422a 100644 --- a/tests/api_resources/cloud/test_volumes.py +++ b/tests/api_resources/cloud/test_volumes.py @@ -45,7 +45,7 @@ def test_method_create_with_all_params_overload_1(self, client: Gcore) -> None: attachment_tag="device-tag", instance_id_to_attach_to="88f3e0bd-ca86-4cf7-be8b-dd2988e23c2d", lifecycle_policy_ids=[1, 2], - tags={"foo": "string"}, + tags={"my-tag": "my-tag-value"}, type_name="standard", ) assert_matches_type(TaskIDList, volume, path=["response"]) @@ -107,7 +107,7 @@ def test_method_create_with_all_params_overload_2(self, client: Gcore) -> None: instance_id_to_attach_to="88f3e0bd-ca86-4cf7-be8b-dd2988e23c2d", lifecycle_policy_ids=[1, 2], size=10, - tags={"foo": "string"}, + tags={"my-tag": "my-tag-value"}, type_name="standard", ) assert_matches_type(TaskIDList, volume, path=["response"]) @@ -166,7 +166,7 @@ def test_method_create_with_all_params_overload_3(self, client: Gcore) -> None: attachment_tag="device-tag", instance_id_to_attach_to="88f3e0bd-ca86-4cf7-be8b-dd2988e23c2d", lifecycle_policy_ids=[1, 2], - tags={"foo": "string"}, + tags={"my-tag": "my-tag-value"}, type_name="standard", ) assert_matches_type(TaskIDList, volume, path=["response"]) @@ -701,7 +701,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn attachment_tag="device-tag", instance_id_to_attach_to="88f3e0bd-ca86-4cf7-be8b-dd2988e23c2d", lifecycle_policy_ids=[1, 2], - tags={"foo": "string"}, + tags={"my-tag": "my-tag-value"}, type_name="standard", ) assert_matches_type(TaskIDList, volume, path=["response"]) @@ -763,7 +763,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn instance_id_to_attach_to="88f3e0bd-ca86-4cf7-be8b-dd2988e23c2d", lifecycle_policy_ids=[1, 2], size=10, - tags={"foo": "string"}, + tags={"my-tag": "my-tag-value"}, type_name="standard", ) assert_matches_type(TaskIDList, volume, path=["response"]) @@ -822,7 +822,7 @@ async def test_method_create_with_all_params_overload_3(self, async_client: Asyn attachment_tag="device-tag", instance_id_to_attach_to="88f3e0bd-ca86-4cf7-be8b-dd2988e23c2d", lifecycle_policy_ids=[1, 2], - tags={"foo": "string"}, + tags={"my-tag": "my-tag-value"}, type_name="standard", ) assert_matches_type(TaskIDList, volume, path=["response"]) diff --git a/tests/api_resources/security/test_bgp_announces.py b/tests/api_resources/security/test_bgp_announces.py index 8907ce2f..bac96db4 100644 --- a/tests/api_resources/security/test_bgp_announces.py +++ b/tests/api_resources/security/test_bgp_announces.py @@ -26,7 +26,10 @@ def test_method_list(self, client: Gcore) -> None: def test_method_list_with_all_params(self, client: Gcore) -> None: bgp_announce = client.security.bgp_announces.list( announced=True, - origin="STATIC", + client_id=1, + limit=1, + offset=0, + origin=["STATIC", "DYNAMIC"], site="x", ) assert_matches_type(BgpAnnounceListResponse, bgp_announce, path=["response"]) @@ -64,7 +67,7 @@ def test_method_toggle_with_all_params(self, client: Gcore) -> None: bgp_announce = client.security.bgp_announces.toggle( announce="192.9.9.1/32", enabled=True, - client_id=0, + client_id=1, ) assert_matches_type(object, bgp_announce, path=["response"]) @@ -109,7 +112,10 @@ async def test_method_list(self, async_client: AsyncGcore) -> None: async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: bgp_announce = await async_client.security.bgp_announces.list( announced=True, - origin="STATIC", + client_id=1, + limit=1, + offset=0, + origin=["STATIC", "DYNAMIC"], site="x", ) assert_matches_type(BgpAnnounceListResponse, bgp_announce, path=["response"]) @@ -147,7 +153,7 @@ async def test_method_toggle_with_all_params(self, async_client: AsyncGcore) -> bgp_announce = await async_client.security.bgp_announces.toggle( announce="192.9.9.1/32", enabled=True, - client_id=0, + client_id=1, ) assert_matches_type(object, bgp_announce, path=["response"]) diff --git a/tests/test_client.py b/tests/test_client.py index c04ade3d..9a14904e 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -965,8 +965,14 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None: # Test that the proxy environment variables are set correctly monkeypatch.setenv("HTTPS_PROXY", "https://example.org") - # Delete in case our environment has this set + # Delete in case our environment has any proxy env vars set monkeypatch.delenv("HTTP_PROXY", raising=False) + monkeypatch.delenv("ALL_PROXY", raising=False) + monkeypatch.delenv("NO_PROXY", raising=False) + monkeypatch.delenv("http_proxy", raising=False) + monkeypatch.delenv("https_proxy", raising=False) + monkeypatch.delenv("all_proxy", raising=False) + monkeypatch.delenv("no_proxy", raising=False) client = DefaultHttpxClient() @@ -1889,8 +1895,14 @@ async def test_get_platform(self) -> None: async def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None: # Test that the proxy environment variables are set correctly monkeypatch.setenv("HTTPS_PROXY", "https://example.org") - # Delete in case our environment has this set + # Delete in case our environment has any proxy env vars set monkeypatch.delenv("HTTP_PROXY", raising=False) + monkeypatch.delenv("ALL_PROXY", raising=False) + monkeypatch.delenv("NO_PROXY", raising=False) + monkeypatch.delenv("http_proxy", raising=False) + monkeypatch.delenv("https_proxy", raising=False) + monkeypatch.delenv("all_proxy", raising=False) + monkeypatch.delenv("no_proxy", raising=False) client = DefaultAsyncHttpxClient()