From 99955b9208b2810fcbafbf5f8d941b5981faebbe Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Mon, 10 Nov 2025 11:29:53 +0000
Subject: [PATCH 1/6] chore(package): drop Python 3.8 support
---
README.md | 4 ++--
pyproject.toml | 5 ++---
src/gcore/_utils/_sync.py | 34 +++-------------------------------
3 files changed, 7 insertions(+), 36 deletions(-)
diff --git a/README.md b/README.md
index bcba1e06..3c62683a 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
[)[](https://app.fossa.com/projects/git%2Bgithub.com%2FG-Core%2Fgcore-python?ref=badge_shield)
](https://pypi.org/project/gcore/)
-The Gcore Python library provides convenient access to the Gcore REST API from any Python 3.8+
+The Gcore Python library provides convenient access to the Gcore REST API from any Python 3.9+
application. The library includes type definitions for all request params and response fields,
and offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx).
@@ -479,7 +479,7 @@ print(gcore.__version__)
## Requirements
-Python 3.8 or higher.
+Python 3.9 or higher.
## Contributing
diff --git a/pyproject.toml b/pyproject.toml
index e1d7434a..6aeac16c 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -15,11 +15,10 @@ dependencies = [
"distro>=1.7.0, <2",
"sniffio",
]
-requires-python = ">= 3.8"
+requires-python = ">= 3.9"
classifiers = [
"Typing :: Typed",
"Intended Audience :: Developers",
- "Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
@@ -143,7 +142,7 @@ filterwarnings = [
# there are a couple of flags that are still disabled by
# default in strict mode as they are experimental and niche.
typeCheckingMode = "strict"
-pythonVersion = "3.8"
+pythonVersion = "3.9"
exclude = [
"_dev",
diff --git a/src/gcore/_utils/_sync.py b/src/gcore/_utils/_sync.py
index ad7ec71b..f6027c18 100644
--- a/src/gcore/_utils/_sync.py
+++ b/src/gcore/_utils/_sync.py
@@ -1,10 +1,8 @@
from __future__ import annotations
-import sys
import asyncio
import functools
-import contextvars
-from typing import Any, TypeVar, Callable, Awaitable
+from typing import TypeVar, Callable, Awaitable
from typing_extensions import ParamSpec
import anyio
@@ -15,34 +13,11 @@
T_ParamSpec = ParamSpec("T_ParamSpec")
-if sys.version_info >= (3, 9):
- _asyncio_to_thread = asyncio.to_thread
-else:
- # backport of https://docs.python.org/3/library/asyncio-task.html#asyncio.to_thread
- # for Python 3.8 support
- async def _asyncio_to_thread(
- func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs
- ) -> Any:
- """Asynchronously run function *func* in a separate thread.
-
- Any *args and **kwargs supplied for this function are directly passed
- to *func*. Also, the current :class:`contextvars.Context` is propagated,
- allowing context variables from the main thread to be accessed in the
- separate thread.
-
- Returns a coroutine that can be awaited to get the eventual result of *func*.
- """
- loop = asyncio.events.get_running_loop()
- ctx = contextvars.copy_context()
- func_call = functools.partial(ctx.run, func, *args, **kwargs)
- return await loop.run_in_executor(None, func_call)
-
-
async def to_thread(
func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs
) -> T_Retval:
if sniffio.current_async_library() == "asyncio":
- return await _asyncio_to_thread(func, *args, **kwargs)
+ return await asyncio.to_thread(func, *args, **kwargs)
return await anyio.to_thread.run_sync(
functools.partial(func, *args, **kwargs),
@@ -53,10 +28,7 @@ async def to_thread(
def asyncify(function: Callable[T_ParamSpec, T_Retval]) -> Callable[T_ParamSpec, Awaitable[T_Retval]]:
"""
Take a blocking function and create an async one that receives the same
- positional and keyword arguments. For python version 3.9 and above, it uses
- asyncio.to_thread to run the function in a separate thread. For python version
- 3.8, it uses locally defined copy of the asyncio.to_thread function which was
- introduced in python 3.9.
+ positional and keyword arguments.
Usage:
From 90bfffeed8b28a360e1489162d4dc6a28745b411 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Mon, 10 Nov 2025 13:36:28 +0000
Subject: [PATCH 2/6] fix: compat with Python 3.14
---
src/gcore/_models.py | 11 ++++++++---
tests/test_models.py | 8 ++++----
2 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/src/gcore/_models.py b/src/gcore/_models.py
index 6a3cd1d2..fcec2cf9 100644
--- a/src/gcore/_models.py
+++ b/src/gcore/_models.py
@@ -2,6 +2,7 @@
import os
import inspect
+import weakref
from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, Optional, cast
from datetime import date, datetime
from typing_extensions import (
@@ -573,6 +574,9 @@ class CachedDiscriminatorType(Protocol):
__discriminator__: DiscriminatorDetails
+DISCRIMINATOR_CACHE: weakref.WeakKeyDictionary[type, DiscriminatorDetails] = weakref.WeakKeyDictionary()
+
+
class DiscriminatorDetails:
field_name: str
"""The name of the discriminator field in the variant class, e.g.
@@ -615,8 +619,9 @@ def __init__(
def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, ...]) -> DiscriminatorDetails | None:
- if isinstance(union, CachedDiscriminatorType):
- return union.__discriminator__
+ cached = DISCRIMINATOR_CACHE.get(union)
+ if cached is not None:
+ return cached
discriminator_field_name: str | None = None
@@ -669,7 +674,7 @@ def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any,
discriminator_field=discriminator_field_name,
discriminator_alias=discriminator_alias,
)
- cast(CachedDiscriminatorType, union).__discriminator__ = details
+ DISCRIMINATOR_CACHE.setdefault(union, details)
return details
diff --git a/tests/test_models.py b/tests/test_models.py
index 7b21d517..d899cd02 100644
--- a/tests/test_models.py
+++ b/tests/test_models.py
@@ -9,7 +9,7 @@
from gcore._utils import PropertyInfo
from gcore._compat import PYDANTIC_V1, parse_obj, model_dump, model_json
-from gcore._models import BaseModel, construct_type
+from gcore._models import DISCRIMINATOR_CACHE, BaseModel, construct_type
class BasicModel(BaseModel):
@@ -809,7 +809,7 @@ class B(BaseModel):
UnionType = cast(Any, Union[A, B])
- assert not hasattr(UnionType, "__discriminator__")
+ assert not DISCRIMINATOR_CACHE.get(UnionType)
m = construct_type(
value={"type": "b", "data": "foo"}, type_=cast(Any, Annotated[UnionType, PropertyInfo(discriminator="type")])
@@ -818,7 +818,7 @@ class B(BaseModel):
assert m.type == "b"
assert m.data == "foo" # type: ignore[comparison-overlap]
- discriminator = UnionType.__discriminator__
+ discriminator = DISCRIMINATOR_CACHE.get(UnionType)
assert discriminator is not None
m = construct_type(
@@ -830,7 +830,7 @@ class B(BaseModel):
# if the discriminator details object stays the same between invocations then
# we hit the cache
- assert UnionType.__discriminator__ is discriminator
+ assert DISCRIMINATOR_CACHE.get(UnionType) is discriminator
@pytest.mark.skipif(PYDANTIC_V1, reason="TypeAliasType is not supported in Pydantic v1")
From 767fdd5d74846369e3331efba210aff12a43e802 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 11 Nov 2025 06:14:13 +0000
Subject: [PATCH 3/6] feat(api): aggregated API specs update
---
.stats.yml | 4 ++--
src/gcore/resources/cdn/audit_log.py | 8 ++++----
src/gcore/types/cdn/audit_log_list_params.py | 4 ++--
3 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index 934a1512..11307508 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 618
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gcore%2Fgcore-29e2cc8d4eccb3e6657d61c17d200583cc2bd5bd90494b331881256e362d5873.yml
-openapi_spec_hash: de6249d14f251ef0a008dd506e0e99ef
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gcore%2Fgcore-cf3ae8749ead0412e761136b7c81a9ca98dd46ca9ef76c1f700cb1ecc814630d.yml
+openapi_spec_hash: d5b2b66116339bbe16ec0bbff5b6366f
config_hash: db560bc3873a6441828babf34ae5f184
diff --git a/src/gcore/resources/cdn/audit_log.py b/src/gcore/resources/cdn/audit_log.py
index f39a518f..a80c335e 100644
--- a/src/gcore/resources/cdn/audit_log.py
+++ b/src/gcore/resources/cdn/audit_log.py
@@ -99,9 +99,9 @@ def list(
offset: Offset relative to the beginning of activity logs.
- path: Path that a requested URL should contain.
+ path: Exact URL path.
- remote_ip_address: IP address or part of it from which requests are sent.
+ remote_ip_address: Exact IP address from which requests are sent.
status_code: Status code returned in the response.
@@ -263,9 +263,9 @@ def list(
offset: Offset relative to the beginning of activity logs.
- path: Path that a requested URL should contain.
+ path: Exact URL path.
- remote_ip_address: IP address or part of it from which requests are sent.
+ remote_ip_address: Exact IP address from which requests are sent.
status_code: Status code returned in the response.
diff --git a/src/gcore/types/cdn/audit_log_list_params.py b/src/gcore/types/cdn/audit_log_list_params.py
index 95024e59..e70beede 100644
--- a/src/gcore/types/cdn/audit_log_list_params.py
+++ b/src/gcore/types/cdn/audit_log_list_params.py
@@ -50,10 +50,10 @@ class AuditLogListParams(TypedDict, total=False):
"""Offset relative to the beginning of activity logs."""
path: str
- """Path that a requested URL should contain."""
+ """Exact URL path."""
remote_ip_address: str
- """IP address or part of it from which requests are sent."""
+ """Exact IP address from which requests are sent."""
status_code: int
"""Status code returned in the response.
From c406d97d04db03f5c4d105f2e9761e9b8c2d96c8 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 11 Nov 2025 13:50:59 +0000
Subject: [PATCH 4/6] feat(cloud): add support for GPU virtual clusters
---
.stats.yml | 4 +-
api.md | 81 +
src/gcore/resources/cloud/__init__.py | 14 +
src/gcore/resources/cloud/cloud.py | 32 +
.../cloud/gpu_virtual_clusters/__init__.py | 89 +
.../cloud/gpu_virtual_clusters/flavors.py | 211 +++
.../gpu_virtual_clusters.py | 1539 +++++++++++++++++
.../cloud/gpu_virtual_clusters/images.py | 580 +++++++
.../cloud/gpu_virtual_clusters/interfaces.py | 187 ++
.../cloud/gpu_virtual_clusters/servers.py | 506 ++++++
.../cloud/gpu_virtual_clusters/volumes.py | 187 ++
src/gcore/types/cloud/__init__.py | 6 +
src/gcore/types/cloud/gpu_virtual_cluster.py | 189 ++
.../gpu_virtual_cluster_action_params.py | 122 ++
.../gpu_virtual_cluster_create_params.py | 213 +++
.../gpu_virtual_cluster_delete_params.py | 41 +
.../cloud/gpu_virtual_cluster_list_params.py | 21 +
.../gpu_virtual_cluster_update_params.py | 18 +
.../cloud/gpu_virtual_clusters/__init__.py | 16 +
.../flavor_list_params.py | 21 +
.../gpu_virtual_cluster_server.py | 77 +
.../gpu_virtual_cluster_server_list.py | 16 +
.../gpu_virtual_cluster_volume.py | 64 +
.../gpu_virtual_cluster_volume_list.py | 16 +
.../gpu_virtual_flavor.py | 155 ++
.../gpu_virtual_flavor_list.py | 16 +
.../gpu_virtual_interface.py | 190 ++
.../gpu_virtual_interface_list.py | 16 +
.../image_upload_params.py | 56 +
.../server_delete_params.py | 44 +
.../server_list_params.py | 75 +
.../cloud/gpu_virtual_clusters/__init__.py | 1 +
.../gpu_virtual_clusters/test_flavors.py | 112 ++
.../cloud/gpu_virtual_clusters/test_images.py | 392 +++++
.../gpu_virtual_clusters/test_interfaces.py | 116 ++
.../gpu_virtual_clusters/test_servers.py | 302 ++++
.../gpu_virtual_clusters/test_volumes.py | 116 ++
.../cloud/test_gpu_virtual_clusters.py | 1294 ++++++++++++++
38 files changed, 7133 insertions(+), 2 deletions(-)
create mode 100644 src/gcore/resources/cloud/gpu_virtual_clusters/__init__.py
create mode 100644 src/gcore/resources/cloud/gpu_virtual_clusters/flavors.py
create mode 100644 src/gcore/resources/cloud/gpu_virtual_clusters/gpu_virtual_clusters.py
create mode 100644 src/gcore/resources/cloud/gpu_virtual_clusters/images.py
create mode 100644 src/gcore/resources/cloud/gpu_virtual_clusters/interfaces.py
create mode 100644 src/gcore/resources/cloud/gpu_virtual_clusters/servers.py
create mode 100644 src/gcore/resources/cloud/gpu_virtual_clusters/volumes.py
create mode 100644 src/gcore/types/cloud/gpu_virtual_cluster.py
create mode 100644 src/gcore/types/cloud/gpu_virtual_cluster_action_params.py
create mode 100644 src/gcore/types/cloud/gpu_virtual_cluster_create_params.py
create mode 100644 src/gcore/types/cloud/gpu_virtual_cluster_delete_params.py
create mode 100644 src/gcore/types/cloud/gpu_virtual_cluster_list_params.py
create mode 100644 src/gcore/types/cloud/gpu_virtual_cluster_update_params.py
create mode 100644 src/gcore/types/cloud/gpu_virtual_clusters/__init__.py
create mode 100644 src/gcore/types/cloud/gpu_virtual_clusters/flavor_list_params.py
create mode 100644 src/gcore/types/cloud/gpu_virtual_clusters/gpu_virtual_cluster_server.py
create mode 100644 src/gcore/types/cloud/gpu_virtual_clusters/gpu_virtual_cluster_server_list.py
create mode 100644 src/gcore/types/cloud/gpu_virtual_clusters/gpu_virtual_cluster_volume.py
create mode 100644 src/gcore/types/cloud/gpu_virtual_clusters/gpu_virtual_cluster_volume_list.py
create mode 100644 src/gcore/types/cloud/gpu_virtual_clusters/gpu_virtual_flavor.py
create mode 100644 src/gcore/types/cloud/gpu_virtual_clusters/gpu_virtual_flavor_list.py
create mode 100644 src/gcore/types/cloud/gpu_virtual_clusters/gpu_virtual_interface.py
create mode 100644 src/gcore/types/cloud/gpu_virtual_clusters/gpu_virtual_interface_list.py
create mode 100644 src/gcore/types/cloud/gpu_virtual_clusters/image_upload_params.py
create mode 100644 src/gcore/types/cloud/gpu_virtual_clusters/server_delete_params.py
create mode 100644 src/gcore/types/cloud/gpu_virtual_clusters/server_list_params.py
create mode 100644 tests/api_resources/cloud/gpu_virtual_clusters/__init__.py
create mode 100644 tests/api_resources/cloud/gpu_virtual_clusters/test_flavors.py
create mode 100644 tests/api_resources/cloud/gpu_virtual_clusters/test_images.py
create mode 100644 tests/api_resources/cloud/gpu_virtual_clusters/test_interfaces.py
create mode 100644 tests/api_resources/cloud/gpu_virtual_clusters/test_servers.py
create mode 100644 tests/api_resources/cloud/gpu_virtual_clusters/test_volumes.py
create mode 100644 tests/api_resources/cloud/test_gpu_virtual_clusters.py
diff --git a/.stats.yml b/.stats.yml
index 11307508..af8fa5c8 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 618
+configured_endpoints: 633
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gcore%2Fgcore-cf3ae8749ead0412e761136b7c81a9ca98dd46ca9ef76c1f700cb1ecc814630d.yml
openapi_spec_hash: d5b2b66116339bbe16ec0bbff5b6366f
-config_hash: db560bc3873a6441828babf34ae5f184
+config_hash: e759f29c457a9e3ac5031e760c36594a
diff --git a/api.md b/api.md
index 180b482b..6158d8b8 100644
--- a/api.md
+++ b/api.md
@@ -826,6 +826,87 @@ Methods:
- client.cloud.gpu_baremetal_clusters.images.get(image_id, \*, project_id, region_id) -> GPUImage
- client.cloud.gpu_baremetal_clusters.images.upload(\*, project_id, region_id, \*\*params) -> TaskIDList
+## GPUVirtualClusters
+
+Types:
+
+```python
+from gcore.types.cloud import GPUVirtualCluster
+```
+
+Methods:
+
+- client.cloud.gpu_virtual_clusters.create(\*, project_id, region_id, \*\*params) -> TaskIDList
+- client.cloud.gpu_virtual_clusters.update(cluster_id, \*, project_id, region_id, \*\*params) -> GPUVirtualCluster
+- client.cloud.gpu_virtual_clusters.list(\*, project_id, region_id, \*\*params) -> SyncOffsetPage[GPUVirtualCluster]
+- client.cloud.gpu_virtual_clusters.delete(cluster_id, \*, project_id, region_id, \*\*params) -> TaskIDList
+- client.cloud.gpu_virtual_clusters.action(cluster_id, \*, project_id, region_id, \*\*params) -> TaskIDList
+- client.cloud.gpu_virtual_clusters.get(cluster_id, \*, project_id, region_id) -> GPUVirtualCluster
+
+### Servers
+
+Types:
+
+```python
+from gcore.types.cloud.gpu_virtual_clusters import (
+ GPUVirtualClusterServer,
+ GPUVirtualClusterServerList,
+)
+```
+
+Methods:
+
+- client.cloud.gpu_virtual_clusters.servers.list(cluster_id, \*, project_id, region_id, \*\*params) -> GPUVirtualClusterServerList
+- client.cloud.gpu_virtual_clusters.servers.delete(server_id, \*, project_id, region_id, cluster_id, \*\*params) -> TaskIDList
+
+### Volumes
+
+Types:
+
+```python
+from gcore.types.cloud.gpu_virtual_clusters import (
+ GPUVirtualClusterVolume,
+ GPUVirtualClusterVolumeList,
+)
+```
+
+Methods:
+
+- client.cloud.gpu_virtual_clusters.volumes.list(cluster_id, \*, project_id, region_id) -> GPUVirtualClusterVolumeList
+
+### Interfaces
+
+Types:
+
+```python
+from gcore.types.cloud.gpu_virtual_clusters import GPUVirtualInterface, GPUVirtualInterfaceList
+```
+
+Methods:
+
+- client.cloud.gpu_virtual_clusters.interfaces.list(cluster_id, \*, project_id, region_id) -> GPUVirtualInterfaceList
+
+### Flavors
+
+Types:
+
+```python
+from gcore.types.cloud.gpu_virtual_clusters import GPUVirtualFlavor, GPUVirtualFlavorList
+```
+
+Methods:
+
+- client.cloud.gpu_virtual_clusters.flavors.list(\*, project_id, region_id, \*\*params) -> GPUVirtualFlavorList
+
+### Images
+
+Methods:
+
+- client.cloud.gpu_virtual_clusters.images.list(\*, project_id, region_id) -> GPUImageList
+- client.cloud.gpu_virtual_clusters.images.delete(image_id, \*, project_id, region_id) -> TaskIDList
+- client.cloud.gpu_virtual_clusters.images.get(image_id, \*, project_id, region_id) -> GPUImage
+- client.cloud.gpu_virtual_clusters.images.upload(\*, project_id, region_id, \*\*params) -> TaskIDList
+
## Instances
Types:
diff --git a/src/gcore/resources/cloud/__init__.py b/src/gcore/resources/cloud/__init__.py
index b430fc7c..6ae9dac7 100644
--- a/src/gcore/resources/cloud/__init__.py
+++ b/src/gcore/resources/cloud/__init__.py
@@ -216,6 +216,14 @@
BillingReservationsResourceWithStreamingResponse,
AsyncBillingReservationsResourceWithStreamingResponse,
)
+from .gpu_virtual_clusters import (
+ GPUVirtualClustersResource,
+ AsyncGPUVirtualClustersResource,
+ GPUVirtualClustersResourceWithRawResponse,
+ AsyncGPUVirtualClustersResourceWithRawResponse,
+ GPUVirtualClustersResourceWithStreamingResponse,
+ AsyncGPUVirtualClustersResourceWithStreamingResponse,
+)
from .gpu_baremetal_clusters import (
GPUBaremetalClustersResource,
AsyncGPUBaremetalClustersResource,
@@ -352,6 +360,12 @@
"AsyncGPUBaremetalClustersResourceWithRawResponse",
"GPUBaremetalClustersResourceWithStreamingResponse",
"AsyncGPUBaremetalClustersResourceWithStreamingResponse",
+ "GPUVirtualClustersResource",
+ "AsyncGPUVirtualClustersResource",
+ "GPUVirtualClustersResourceWithRawResponse",
+ "AsyncGPUVirtualClustersResourceWithRawResponse",
+ "GPUVirtualClustersResourceWithStreamingResponse",
+ "AsyncGPUVirtualClustersResourceWithStreamingResponse",
"InstancesResource",
"AsyncInstancesResource",
"InstancesResourceWithRawResponse",
diff --git a/src/gcore/resources/cloud/cloud.py b/src/gcore/resources/cloud/cloud.py
index 6583dc98..3f9ad996 100644
--- a/src/gcore/resources/cloud/cloud.py
+++ b/src/gcore/resources/cloud/cloud.py
@@ -212,6 +212,14 @@
ReservedFixedIPsResourceWithStreamingResponse,
AsyncReservedFixedIPsResourceWithStreamingResponse,
)
+from .gpu_virtual_clusters.gpu_virtual_clusters import (
+ GPUVirtualClustersResource,
+ AsyncGPUVirtualClustersResource,
+ GPUVirtualClustersResourceWithRawResponse,
+ AsyncGPUVirtualClustersResourceWithRawResponse,
+ GPUVirtualClustersResourceWithStreamingResponse,
+ AsyncGPUVirtualClustersResourceWithStreamingResponse,
+)
from .gpu_baremetal_clusters.gpu_baremetal_clusters import (
GPUBaremetalClustersResource,
AsyncGPUBaremetalClustersResource,
@@ -316,6 +324,10 @@ def billing_reservations(self) -> BillingReservationsResource:
def gpu_baremetal_clusters(self) -> GPUBaremetalClustersResource:
return GPUBaremetalClustersResource(self._client)
+ @cached_property
+ def gpu_virtual_clusters(self) -> GPUVirtualClustersResource:
+ return GPUVirtualClustersResource(self._client)
+
@cached_property
def instances(self) -> InstancesResource:
return InstancesResource(self._client)
@@ -452,6 +464,10 @@ def billing_reservations(self) -> AsyncBillingReservationsResource:
def gpu_baremetal_clusters(self) -> AsyncGPUBaremetalClustersResource:
return AsyncGPUBaremetalClustersResource(self._client)
+ @cached_property
+ def gpu_virtual_clusters(self) -> AsyncGPUVirtualClustersResource:
+ return AsyncGPUVirtualClustersResource(self._client)
+
@cached_property
def instances(self) -> AsyncInstancesResource:
return AsyncInstancesResource(self._client)
@@ -591,6 +607,10 @@ def billing_reservations(self) -> BillingReservationsResourceWithRawResponse:
def gpu_baremetal_clusters(self) -> GPUBaremetalClustersResourceWithRawResponse:
return GPUBaremetalClustersResourceWithRawResponse(self._cloud.gpu_baremetal_clusters)
+ @cached_property
+ def gpu_virtual_clusters(self) -> GPUVirtualClustersResourceWithRawResponse:
+ return GPUVirtualClustersResourceWithRawResponse(self._cloud.gpu_virtual_clusters)
+
@cached_property
def instances(self) -> InstancesResourceWithRawResponse:
return InstancesResourceWithRawResponse(self._cloud.instances)
@@ -711,6 +731,10 @@ def billing_reservations(self) -> AsyncBillingReservationsResourceWithRawRespons
def gpu_baremetal_clusters(self) -> AsyncGPUBaremetalClustersResourceWithRawResponse:
return AsyncGPUBaremetalClustersResourceWithRawResponse(self._cloud.gpu_baremetal_clusters)
+ @cached_property
+ def gpu_virtual_clusters(self) -> AsyncGPUVirtualClustersResourceWithRawResponse:
+ return AsyncGPUVirtualClustersResourceWithRawResponse(self._cloud.gpu_virtual_clusters)
+
@cached_property
def instances(self) -> AsyncInstancesResourceWithRawResponse:
return AsyncInstancesResourceWithRawResponse(self._cloud.instances)
@@ -831,6 +855,10 @@ def billing_reservations(self) -> BillingReservationsResourceWithStreamingRespon
def gpu_baremetal_clusters(self) -> GPUBaremetalClustersResourceWithStreamingResponse:
return GPUBaremetalClustersResourceWithStreamingResponse(self._cloud.gpu_baremetal_clusters)
+ @cached_property
+ def gpu_virtual_clusters(self) -> GPUVirtualClustersResourceWithStreamingResponse:
+ return GPUVirtualClustersResourceWithStreamingResponse(self._cloud.gpu_virtual_clusters)
+
@cached_property
def instances(self) -> InstancesResourceWithStreamingResponse:
return InstancesResourceWithStreamingResponse(self._cloud.instances)
@@ -951,6 +979,10 @@ def billing_reservations(self) -> AsyncBillingReservationsResourceWithStreamingR
def gpu_baremetal_clusters(self) -> AsyncGPUBaremetalClustersResourceWithStreamingResponse:
return AsyncGPUBaremetalClustersResourceWithStreamingResponse(self._cloud.gpu_baremetal_clusters)
+ @cached_property
+ def gpu_virtual_clusters(self) -> AsyncGPUVirtualClustersResourceWithStreamingResponse:
+ return AsyncGPUVirtualClustersResourceWithStreamingResponse(self._cloud.gpu_virtual_clusters)
+
@cached_property
def instances(self) -> AsyncInstancesResourceWithStreamingResponse:
return AsyncInstancesResourceWithStreamingResponse(self._cloud.instances)
diff --git a/src/gcore/resources/cloud/gpu_virtual_clusters/__init__.py b/src/gcore/resources/cloud/gpu_virtual_clusters/__init__.py
new file mode 100644
index 00000000..6957a34c
--- /dev/null
+++ b/src/gcore/resources/cloud/gpu_virtual_clusters/__init__.py
@@ -0,0 +1,89 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .images import (
+ ImagesResource,
+ AsyncImagesResource,
+ ImagesResourceWithRawResponse,
+ AsyncImagesResourceWithRawResponse,
+ ImagesResourceWithStreamingResponse,
+ AsyncImagesResourceWithStreamingResponse,
+)
+from .flavors import (
+ FlavorsResource,
+ AsyncFlavorsResource,
+ FlavorsResourceWithRawResponse,
+ AsyncFlavorsResourceWithRawResponse,
+ FlavorsResourceWithStreamingResponse,
+ AsyncFlavorsResourceWithStreamingResponse,
+)
+from .servers import (
+ ServersResource,
+ AsyncServersResource,
+ ServersResourceWithRawResponse,
+ AsyncServersResourceWithRawResponse,
+ ServersResourceWithStreamingResponse,
+ AsyncServersResourceWithStreamingResponse,
+)
+from .volumes import (
+ VolumesResource,
+ AsyncVolumesResource,
+ VolumesResourceWithRawResponse,
+ AsyncVolumesResourceWithRawResponse,
+ VolumesResourceWithStreamingResponse,
+ AsyncVolumesResourceWithStreamingResponse,
+)
+from .interfaces import (
+ InterfacesResource,
+ AsyncInterfacesResource,
+ InterfacesResourceWithRawResponse,
+ AsyncInterfacesResourceWithRawResponse,
+ InterfacesResourceWithStreamingResponse,
+ AsyncInterfacesResourceWithStreamingResponse,
+)
+from .gpu_virtual_clusters import (
+ GPUVirtualClustersResource,
+ AsyncGPUVirtualClustersResource,
+ GPUVirtualClustersResourceWithRawResponse,
+ AsyncGPUVirtualClustersResourceWithRawResponse,
+ GPUVirtualClustersResourceWithStreamingResponse,
+ AsyncGPUVirtualClustersResourceWithStreamingResponse,
+)
+
+__all__ = [
+ "ServersResource",
+ "AsyncServersResource",
+ "ServersResourceWithRawResponse",
+ "AsyncServersResourceWithRawResponse",
+ "ServersResourceWithStreamingResponse",
+ "AsyncServersResourceWithStreamingResponse",
+ "VolumesResource",
+ "AsyncVolumesResource",
+ "VolumesResourceWithRawResponse",
+ "AsyncVolumesResourceWithRawResponse",
+ "VolumesResourceWithStreamingResponse",
+ "AsyncVolumesResourceWithStreamingResponse",
+ "InterfacesResource",
+ "AsyncInterfacesResource",
+ "InterfacesResourceWithRawResponse",
+ "AsyncInterfacesResourceWithRawResponse",
+ "InterfacesResourceWithStreamingResponse",
+ "AsyncInterfacesResourceWithStreamingResponse",
+ "FlavorsResource",
+ "AsyncFlavorsResource",
+ "FlavorsResourceWithRawResponse",
+ "AsyncFlavorsResourceWithRawResponse",
+ "FlavorsResourceWithStreamingResponse",
+ "AsyncFlavorsResourceWithStreamingResponse",
+ "ImagesResource",
+ "AsyncImagesResource",
+ "ImagesResourceWithRawResponse",
+ "AsyncImagesResourceWithRawResponse",
+ "ImagesResourceWithStreamingResponse",
+ "AsyncImagesResourceWithStreamingResponse",
+ "GPUVirtualClustersResource",
+ "AsyncGPUVirtualClustersResource",
+ "GPUVirtualClustersResourceWithRawResponse",
+ "AsyncGPUVirtualClustersResourceWithRawResponse",
+ "GPUVirtualClustersResourceWithStreamingResponse",
+ "AsyncGPUVirtualClustersResourceWithStreamingResponse",
+]
diff --git a/src/gcore/resources/cloud/gpu_virtual_clusters/flavors.py b/src/gcore/resources/cloud/gpu_virtual_clusters/flavors.py
new file mode 100644
index 00000000..269932f2
--- /dev/null
+++ b/src/gcore/resources/cloud/gpu_virtual_clusters/flavors.py
@@ -0,0 +1,211 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from ...._utils import maybe_transform, async_maybe_transform
+from ...._compat import cached_property
+from ...._resource import SyncAPIResource, AsyncAPIResource
+from ...._response import (
+ to_raw_response_wrapper,
+ to_streamed_response_wrapper,
+ async_to_raw_response_wrapper,
+ async_to_streamed_response_wrapper,
+)
+from ...._base_client import make_request_options
+from ....types.cloud.gpu_virtual_clusters import flavor_list_params
+from ....types.cloud.gpu_virtual_clusters.gpu_virtual_flavor_list import GPUVirtualFlavorList
+
+__all__ = ["FlavorsResource", "AsyncFlavorsResource"]
+
+
+class FlavorsResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> FlavorsResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers
+ """
+ return FlavorsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> FlavorsResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response
+ """
+ return FlavorsResourceWithStreamingResponse(self)
+
+ def list(
+ self,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ hide_disabled: bool | Omit = omit,
+ include_prices: bool | 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,
+ ) -> GPUVirtualFlavorList:
+ """
+ List virtual GPU flavors
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ hide_disabled: Set to `true` to remove the disabled flavors from the response.
+
+ include_prices: Set to `true` if the response should include flavor prices.
+
+ 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()
+ return self._get(
+ f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/flavors",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "hide_disabled": hide_disabled,
+ "include_prices": include_prices,
+ },
+ flavor_list_params.FlavorListParams,
+ ),
+ ),
+ cast_to=GPUVirtualFlavorList,
+ )
+
+
+class AsyncFlavorsResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncFlavorsResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncFlavorsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncFlavorsResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response
+ """
+ return AsyncFlavorsResourceWithStreamingResponse(self)
+
+ async def list(
+ self,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ hide_disabled: bool | Omit = omit,
+ include_prices: bool | 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,
+ ) -> GPUVirtualFlavorList:
+ """
+ List virtual GPU flavors
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ hide_disabled: Set to `true` to remove the disabled flavors from the response.
+
+ include_prices: Set to `true` if the response should include flavor prices.
+
+ 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()
+ return await self._get(
+ f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/flavors",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "hide_disabled": hide_disabled,
+ "include_prices": include_prices,
+ },
+ flavor_list_params.FlavorListParams,
+ ),
+ ),
+ cast_to=GPUVirtualFlavorList,
+ )
+
+
+class FlavorsResourceWithRawResponse:
+ def __init__(self, flavors: FlavorsResource) -> None:
+ self._flavors = flavors
+
+ self.list = to_raw_response_wrapper(
+ flavors.list,
+ )
+
+
+class AsyncFlavorsResourceWithRawResponse:
+ def __init__(self, flavors: AsyncFlavorsResource) -> None:
+ self._flavors = flavors
+
+ self.list = async_to_raw_response_wrapper(
+ flavors.list,
+ )
+
+
+class FlavorsResourceWithStreamingResponse:
+ def __init__(self, flavors: FlavorsResource) -> None:
+ self._flavors = flavors
+
+ self.list = to_streamed_response_wrapper(
+ flavors.list,
+ )
+
+
+class AsyncFlavorsResourceWithStreamingResponse:
+ def __init__(self, flavors: AsyncFlavorsResource) -> None:
+ self._flavors = flavors
+
+ self.list = async_to_streamed_response_wrapper(
+ flavors.list,
+ )
diff --git a/src/gcore/resources/cloud/gpu_virtual_clusters/gpu_virtual_clusters.py b/src/gcore/resources/cloud/gpu_virtual_clusters/gpu_virtual_clusters.py
new file mode 100644
index 00000000..7711ec5a
--- /dev/null
+++ b/src/gcore/resources/cloud/gpu_virtual_clusters/gpu_virtual_clusters.py
@@ -0,0 +1,1539 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Dict, Optional
+from typing_extensions import Literal, overload
+
+import httpx
+
+from .images import (
+ ImagesResource,
+ AsyncImagesResource,
+ ImagesResourceWithRawResponse,
+ AsyncImagesResourceWithRawResponse,
+ ImagesResourceWithStreamingResponse,
+ AsyncImagesResourceWithStreamingResponse,
+)
+from .flavors import (
+ FlavorsResource,
+ AsyncFlavorsResource,
+ FlavorsResourceWithRawResponse,
+ AsyncFlavorsResourceWithRawResponse,
+ FlavorsResourceWithStreamingResponse,
+ AsyncFlavorsResourceWithStreamingResponse,
+)
+from .servers import (
+ ServersResource,
+ AsyncServersResource,
+ ServersResourceWithRawResponse,
+ AsyncServersResourceWithRawResponse,
+ ServersResourceWithStreamingResponse,
+ AsyncServersResourceWithStreamingResponse,
+)
+from .volumes import (
+ VolumesResource,
+ AsyncVolumesResource,
+ VolumesResourceWithRawResponse,
+ AsyncVolumesResourceWithRawResponse,
+ VolumesResourceWithStreamingResponse,
+ AsyncVolumesResourceWithStreamingResponse,
+)
+from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given
+from ...._utils import required_args, maybe_transform, async_maybe_transform
+from ...._compat import cached_property
+from .interfaces import (
+ InterfacesResource,
+ AsyncInterfacesResource,
+ InterfacesResourceWithRawResponse,
+ AsyncInterfacesResourceWithRawResponse,
+ InterfacesResourceWithStreamingResponse,
+ AsyncInterfacesResourceWithStreamingResponse,
+)
+from ...._resource import SyncAPIResource, AsyncAPIResource
+from ...._response import (
+ to_raw_response_wrapper,
+ to_streamed_response_wrapper,
+ async_to_raw_response_wrapper,
+ async_to_streamed_response_wrapper,
+)
+from ....pagination import SyncOffsetPage, AsyncOffsetPage
+from ....types.cloud import (
+ gpu_virtual_cluster_list_params,
+ gpu_virtual_cluster_action_params,
+ gpu_virtual_cluster_create_params,
+ gpu_virtual_cluster_delete_params,
+ gpu_virtual_cluster_update_params,
+)
+from ...._base_client import AsyncPaginator, make_request_options
+from ....types.cloud.task_id_list import TaskIDList
+from ....types.cloud.gpu_virtual_cluster import GPUVirtualCluster
+from ....types.cloud.tag_update_map_param import TagUpdateMapParam
+
+__all__ = ["GPUVirtualClustersResource", "AsyncGPUVirtualClustersResource"]
+
+
+class GPUVirtualClustersResource(SyncAPIResource):
+ @cached_property
+ def servers(self) -> ServersResource:
+ return ServersResource(self._client)
+
+ @cached_property
+ def volumes(self) -> VolumesResource:
+ return VolumesResource(self._client)
+
+ @cached_property
+ def interfaces(self) -> InterfacesResource:
+ return InterfacesResource(self._client)
+
+ @cached_property
+ def flavors(self) -> FlavorsResource:
+ return FlavorsResource(self._client)
+
+ @cached_property
+ def images(self) -> ImagesResource:
+ return ImagesResource(self._client)
+
+ @cached_property
+ def with_raw_response(self) -> GPUVirtualClustersResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers
+ """
+ return GPUVirtualClustersResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> GPUVirtualClustersResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response
+ """
+ return GPUVirtualClustersResourceWithStreamingResponse(self)
+
+ def create(
+ self,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ flavor: str,
+ name: str,
+ servers_count: int,
+ servers_settings: gpu_virtual_cluster_create_params.ServersSettings,
+ tags: Dict[str, 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,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> TaskIDList:
+ """
+ Create a new virtual GPU cluster with the specified configuration.
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ flavor: Cluster flavor ID
+
+ name: Cluster name
+
+ servers_count: Number of servers in the cluster
+
+ servers_settings: Configuration settings for the servers in the cluster
+
+ tags: Key-value tags to associate with the resource. A tag is a key-value pair that
+ can be associated with a resource, enabling efficient filtering and grouping for
+ better organization and management. Some tags are read-only and cannot be
+ modified by the user. Tags are also integrated with cost reports, allowing cost
+ data to be filtered based on tag keys or values.
+
+ 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()
+ return self._post(
+ f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters",
+ body=maybe_transform(
+ {
+ "flavor": flavor,
+ "name": name,
+ "servers_count": servers_count,
+ "servers_settings": servers_settings,
+ "tags": tags,
+ },
+ gpu_virtual_cluster_create_params.GPUVirtualClusterCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=TaskIDList,
+ )
+
+ def update(
+ self,
+ cluster_id: str,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ name: 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,
+ ) -> GPUVirtualCluster:
+ """
+ Update the name of an existing virtual GPU cluster.
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ cluster_id: Cluster unique identifier
+
+ name: Cluster name
+
+ 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/virtual/{project_id}/{region_id}/clusters/{cluster_id}",
+ body=maybe_transform({"name": name}, gpu_virtual_cluster_update_params.GPUVirtualClusterUpdateParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=GPUVirtualCluster,
+ )
+
+ def list(
+ self,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ limit: int | Omit = omit,
+ offset: 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,
+ ) -> SyncOffsetPage[GPUVirtualCluster]:
+ """
+ List all virtual GPU clusters in the specified project and region.
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ limit: Limit of items on a single page
+
+ offset: Offset in results list
+
+ 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()
+ return self._get_api_list(
+ f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters",
+ page=SyncOffsetPage[GPUVirtualCluster],
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "limit": limit,
+ "offset": offset,
+ },
+ gpu_virtual_cluster_list_params.GPUVirtualClusterListParams,
+ ),
+ ),
+ model=GPUVirtualCluster,
+ )
+
+ def delete(
+ self,
+ cluster_id: str,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ all_floating_ips: bool | Omit = omit,
+ all_reserved_fixed_ips: bool | Omit = omit,
+ all_volumes: bool | Omit = omit,
+ floating_ip_ids: SequenceNotStr[str] | Omit = omit,
+ reserved_fixed_ip_ids: SequenceNotStr[str] | Omit = omit,
+ volume_ids: SequenceNotStr[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,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> TaskIDList:
+ """
+ Delete a virtual GPU cluster and all its associated resources.
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ cluster_id: Cluster unique identifier
+
+ all_floating_ips: Flag indicating whether the floating ips associated with server / cluster are
+ deleted
+
+ all_reserved_fixed_ips: Flag indicating whether the reserved fixed ips associated with server / cluster
+ are deleted
+
+ all_volumes: Flag indicating whether all attached volumes are deleted
+
+ floating_ip_ids: Optional list of floating ips to be deleted
+
+ reserved_fixed_ip_ids: Optional list of reserved fixed ips to be deleted
+
+ volume_ids: Optional list of volumes to be deleted
+
+ 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._delete(
+ f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters/{cluster_id}",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "all_floating_ips": all_floating_ips,
+ "all_reserved_fixed_ips": all_reserved_fixed_ips,
+ "all_volumes": all_volumes,
+ "floating_ip_ids": floating_ip_ids,
+ "reserved_fixed_ip_ids": reserved_fixed_ip_ids,
+ "volume_ids": volume_ids,
+ },
+ gpu_virtual_cluster_delete_params.GPUVirtualClusterDeleteParams,
+ ),
+ ),
+ cast_to=TaskIDList,
+ )
+
+ @overload
+ def action(
+ self,
+ cluster_id: str,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ action: Literal["start"],
+ # 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 specific action on a virtual GPU cluster.
+
+ Available actions: start,
+ stop, soft reboot, hard reboot, resize, update tags.
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ cluster_id: Cluster unique identifier
+
+ action: Action name
+
+ 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
+ """
+ ...
+
+ @overload
+ def action(
+ self,
+ cluster_id: str,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ action: Literal["stop"],
+ # 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 specific action on a virtual GPU cluster.
+
+ Available actions: start,
+ stop, soft reboot, hard reboot, resize, update tags.
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ cluster_id: Cluster unique identifier
+
+ action: Action name
+
+ 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
+ """
+ ...
+
+ @overload
+ def action(
+ self,
+ cluster_id: str,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ action: Literal["soft_reboot"],
+ # 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 specific action on a virtual GPU cluster.
+
+ Available actions: start,
+ stop, soft reboot, hard reboot, resize, update tags.
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ cluster_id: Cluster unique identifier
+
+ action: Action name
+
+ 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
+ """
+ ...
+
+ @overload
+ def action(
+ self,
+ cluster_id: str,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ action: Literal["hard_reboot"],
+ # 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 specific action on a virtual GPU cluster.
+
+ Available actions: start,
+ stop, soft reboot, hard reboot, resize, update tags.
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ cluster_id: Cluster unique identifier
+
+ action: Action name
+
+ 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
+ """
+ ...
+
+ @overload
+ def action(
+ self,
+ cluster_id: str,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ action: Literal["update_tags"],
+ tags: Optional[TagUpdateMapParam],
+ # 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 specific action on a virtual GPU cluster.
+
+ Available actions: start,
+ stop, soft reboot, hard reboot, resize, update tags.
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ cluster_id: Cluster unique identifier
+
+ action: Action name
+
+ tags: Update key-value tags using JSON Merge Patch semantics (RFC 7386). Provide
+ key-value pairs to add or update tags. Set tag values to `null` to remove tags.
+ Unspecified tags remain unchanged. Read-only tags are always preserved and
+ cannot be modified.
+
+ **Examples:**
+
+ - **Add/update tags:**
+ `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or
+ updates existing ones.
+ - **Delete tags:** `{'tags': {'`old_tag`': null}}` removes specific tags.
+ - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only
+ tags are preserved).
+ - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates
+ specified tags.
+ - **Mixed operations:**
+ `{'tags': {'environment': 'production', '`cost_center`': 'engineering', '`deprecated_tag`': null}}`
+ adds/updates 'environment' and '`cost_center`' while removing
+ '`deprecated_tag`', preserving other existing tags.
+ - **Replace all:** first delete existing tags with null values, then add new
+ ones in the same request.
+
+ 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
+ """
+ ...
+
+ @overload
+ def action(
+ self,
+ cluster_id: str,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ action: Literal["resize"],
+ servers_count: int,
+ # 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 specific action on a virtual GPU cluster.
+
+ Available actions: start,
+ stop, soft reboot, hard reboot, resize, update tags.
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ cluster_id: Cluster unique identifier
+
+ action: Action name
+
+ servers_count: Requested servers count
+
+ 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
+ """
+ ...
+
+ @required_args(["action"], ["action", "tags"], ["action", "servers_count"])
+ def action(
+ self,
+ cluster_id: str,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ action: Literal["start"]
+ | Literal["stop"]
+ | Literal["soft_reboot"]
+ | Literal["hard_reboot"]
+ | Literal["update_tags"]
+ | Literal["resize"],
+ tags: Optional[TagUpdateMapParam] | Omit = omit,
+ servers_count: 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,
+ ) -> TaskIDList:
+ 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._post(
+ f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters/{cluster_id}/action",
+ body=maybe_transform(
+ {
+ "action": action,
+ "tags": tags,
+ "servers_count": servers_count,
+ },
+ gpu_virtual_cluster_action_params.GPUVirtualClusterActionParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=TaskIDList,
+ )
+
+ def get(
+ self,
+ cluster_id: str,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ # 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,
+ ) -> GPUVirtualCluster:
+ """
+ Get detailed information about a specific virtual GPU cluster.
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ cluster_id: Cluster 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}")
+ return self._get(
+ f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters/{cluster_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=GPUVirtualCluster,
+ )
+
+
+class AsyncGPUVirtualClustersResource(AsyncAPIResource):
+ @cached_property
+ def servers(self) -> AsyncServersResource:
+ return AsyncServersResource(self._client)
+
+ @cached_property
+ def volumes(self) -> AsyncVolumesResource:
+ return AsyncVolumesResource(self._client)
+
+ @cached_property
+ def interfaces(self) -> AsyncInterfacesResource:
+ return AsyncInterfacesResource(self._client)
+
+ @cached_property
+ def flavors(self) -> AsyncFlavorsResource:
+ return AsyncFlavorsResource(self._client)
+
+ @cached_property
+ def images(self) -> AsyncImagesResource:
+ return AsyncImagesResource(self._client)
+
+ @cached_property
+ def with_raw_response(self) -> AsyncGPUVirtualClustersResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncGPUVirtualClustersResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncGPUVirtualClustersResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response
+ """
+ return AsyncGPUVirtualClustersResourceWithStreamingResponse(self)
+
+ async def create(
+ self,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ flavor: str,
+ name: str,
+ servers_count: int,
+ servers_settings: gpu_virtual_cluster_create_params.ServersSettings,
+ tags: Dict[str, 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,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> TaskIDList:
+ """
+ Create a new virtual GPU cluster with the specified configuration.
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ flavor: Cluster flavor ID
+
+ name: Cluster name
+
+ servers_count: Number of servers in the cluster
+
+ servers_settings: Configuration settings for the servers in the cluster
+
+ tags: Key-value tags to associate with the resource. A tag is a key-value pair that
+ can be associated with a resource, enabling efficient filtering and grouping for
+ better organization and management. Some tags are read-only and cannot be
+ modified by the user. Tags are also integrated with cost reports, allowing cost
+ data to be filtered based on tag keys or values.
+
+ 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()
+ return await self._post(
+ f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters",
+ body=await async_maybe_transform(
+ {
+ "flavor": flavor,
+ "name": name,
+ "servers_count": servers_count,
+ "servers_settings": servers_settings,
+ "tags": tags,
+ },
+ gpu_virtual_cluster_create_params.GPUVirtualClusterCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=TaskIDList,
+ )
+
+ async def update(
+ self,
+ cluster_id: str,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ name: 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,
+ ) -> GPUVirtualCluster:
+ """
+ Update the name of an existing virtual GPU cluster.
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ cluster_id: Cluster unique identifier
+
+ name: Cluster name
+
+ 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/virtual/{project_id}/{region_id}/clusters/{cluster_id}",
+ body=await async_maybe_transform(
+ {"name": name}, gpu_virtual_cluster_update_params.GPUVirtualClusterUpdateParams
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=GPUVirtualCluster,
+ )
+
+ def list(
+ self,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ limit: int | Omit = omit,
+ offset: 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,
+ ) -> AsyncPaginator[GPUVirtualCluster, AsyncOffsetPage[GPUVirtualCluster]]:
+ """
+ List all virtual GPU clusters in the specified project and region.
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ limit: Limit of items on a single page
+
+ offset: Offset in results list
+
+ 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()
+ return self._get_api_list(
+ f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters",
+ page=AsyncOffsetPage[GPUVirtualCluster],
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "limit": limit,
+ "offset": offset,
+ },
+ gpu_virtual_cluster_list_params.GPUVirtualClusterListParams,
+ ),
+ ),
+ model=GPUVirtualCluster,
+ )
+
+ async def delete(
+ self,
+ cluster_id: str,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ all_floating_ips: bool | Omit = omit,
+ all_reserved_fixed_ips: bool | Omit = omit,
+ all_volumes: bool | Omit = omit,
+ floating_ip_ids: SequenceNotStr[str] | Omit = omit,
+ reserved_fixed_ip_ids: SequenceNotStr[str] | Omit = omit,
+ volume_ids: SequenceNotStr[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,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> TaskIDList:
+ """
+ Delete a virtual GPU cluster and all its associated resources.
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ cluster_id: Cluster unique identifier
+
+ all_floating_ips: Flag indicating whether the floating ips associated with server / cluster are
+ deleted
+
+ all_reserved_fixed_ips: Flag indicating whether the reserved fixed ips associated with server / cluster
+ are deleted
+
+ all_volumes: Flag indicating whether all attached volumes are deleted
+
+ floating_ip_ids: Optional list of floating ips to be deleted
+
+ reserved_fixed_ip_ids: Optional list of reserved fixed ips to be deleted
+
+ volume_ids: Optional list of volumes to be deleted
+
+ 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._delete(
+ f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters/{cluster_id}",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "all_floating_ips": all_floating_ips,
+ "all_reserved_fixed_ips": all_reserved_fixed_ips,
+ "all_volumes": all_volumes,
+ "floating_ip_ids": floating_ip_ids,
+ "reserved_fixed_ip_ids": reserved_fixed_ip_ids,
+ "volume_ids": volume_ids,
+ },
+ gpu_virtual_cluster_delete_params.GPUVirtualClusterDeleteParams,
+ ),
+ ),
+ cast_to=TaskIDList,
+ )
+
+ @overload
+ async def action(
+ self,
+ cluster_id: str,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ action: Literal["start"],
+ # 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 specific action on a virtual GPU cluster.
+
+ Available actions: start,
+ stop, soft reboot, hard reboot, resize, update tags.
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ cluster_id: Cluster unique identifier
+
+ action: Action name
+
+ 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
+ """
+ ...
+
+ @overload
+ async def action(
+ self,
+ cluster_id: str,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ action: Literal["stop"],
+ # 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 specific action on a virtual GPU cluster.
+
+ Available actions: start,
+ stop, soft reboot, hard reboot, resize, update tags.
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ cluster_id: Cluster unique identifier
+
+ action: Action name
+
+ 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
+ """
+ ...
+
+ @overload
+ async def action(
+ self,
+ cluster_id: str,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ action: Literal["soft_reboot"],
+ # 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 specific action on a virtual GPU cluster.
+
+ Available actions: start,
+ stop, soft reboot, hard reboot, resize, update tags.
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ cluster_id: Cluster unique identifier
+
+ action: Action name
+
+ 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
+ """
+ ...
+
+ @overload
+ async def action(
+ self,
+ cluster_id: str,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ action: Literal["hard_reboot"],
+ # 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 specific action on a virtual GPU cluster.
+
+ Available actions: start,
+ stop, soft reboot, hard reboot, resize, update tags.
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ cluster_id: Cluster unique identifier
+
+ action: Action name
+
+ 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
+ """
+ ...
+
+ @overload
+ async def action(
+ self,
+ cluster_id: str,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ action: Literal["update_tags"],
+ tags: Optional[TagUpdateMapParam],
+ # 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 specific action on a virtual GPU cluster.
+
+ Available actions: start,
+ stop, soft reboot, hard reboot, resize, update tags.
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ cluster_id: Cluster unique identifier
+
+ action: Action name
+
+ tags: Update key-value tags using JSON Merge Patch semantics (RFC 7386). Provide
+ key-value pairs to add or update tags. Set tag values to `null` to remove tags.
+ Unspecified tags remain unchanged. Read-only tags are always preserved and
+ cannot be modified.
+
+ **Examples:**
+
+ - **Add/update tags:**
+ `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or
+ updates existing ones.
+ - **Delete tags:** `{'tags': {'`old_tag`': null}}` removes specific tags.
+ - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only
+ tags are preserved).
+ - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates
+ specified tags.
+ - **Mixed operations:**
+ `{'tags': {'environment': 'production', '`cost_center`': 'engineering', '`deprecated_tag`': null}}`
+ adds/updates 'environment' and '`cost_center`' while removing
+ '`deprecated_tag`', preserving other existing tags.
+ - **Replace all:** first delete existing tags with null values, then add new
+ ones in the same request.
+
+ 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
+ """
+ ...
+
+ @overload
+ async def action(
+ self,
+ cluster_id: str,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ action: Literal["resize"],
+ servers_count: int,
+ # 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 specific action on a virtual GPU cluster.
+
+ Available actions: start,
+ stop, soft reboot, hard reboot, resize, update tags.
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ cluster_id: Cluster unique identifier
+
+ action: Action name
+
+ servers_count: Requested servers count
+
+ 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
+ """
+ ...
+
+ @required_args(["action"], ["action", "tags"], ["action", "servers_count"])
+ async def action(
+ self,
+ cluster_id: str,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ action: Literal["start"]
+ | Literal["stop"]
+ | Literal["soft_reboot"]
+ | Literal["hard_reboot"]
+ | Literal["update_tags"]
+ | Literal["resize"],
+ tags: Optional[TagUpdateMapParam] | Omit = omit,
+ servers_count: 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,
+ ) -> TaskIDList:
+ 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._post(
+ f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters/{cluster_id}/action",
+ body=await async_maybe_transform(
+ {
+ "action": action,
+ "tags": tags,
+ "servers_count": servers_count,
+ },
+ gpu_virtual_cluster_action_params.GPUVirtualClusterActionParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=TaskIDList,
+ )
+
+ async def get(
+ self,
+ cluster_id: str,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ # 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,
+ ) -> GPUVirtualCluster:
+ """
+ Get detailed information about a specific virtual GPU cluster.
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ cluster_id: Cluster 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}")
+ return await self._get(
+ f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters/{cluster_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=GPUVirtualCluster,
+ )
+
+
+class GPUVirtualClustersResourceWithRawResponse:
+ def __init__(self, gpu_virtual_clusters: GPUVirtualClustersResource) -> None:
+ self._gpu_virtual_clusters = gpu_virtual_clusters
+
+ self.create = to_raw_response_wrapper(
+ gpu_virtual_clusters.create,
+ )
+ self.update = to_raw_response_wrapper(
+ gpu_virtual_clusters.update,
+ )
+ self.list = to_raw_response_wrapper(
+ gpu_virtual_clusters.list,
+ )
+ self.delete = to_raw_response_wrapper(
+ gpu_virtual_clusters.delete,
+ )
+ self.action = to_raw_response_wrapper(
+ gpu_virtual_clusters.action,
+ )
+ self.get = to_raw_response_wrapper(
+ gpu_virtual_clusters.get,
+ )
+
+ @cached_property
+ def servers(self) -> ServersResourceWithRawResponse:
+ return ServersResourceWithRawResponse(self._gpu_virtual_clusters.servers)
+
+ @cached_property
+ def volumes(self) -> VolumesResourceWithRawResponse:
+ return VolumesResourceWithRawResponse(self._gpu_virtual_clusters.volumes)
+
+ @cached_property
+ def interfaces(self) -> InterfacesResourceWithRawResponse:
+ return InterfacesResourceWithRawResponse(self._gpu_virtual_clusters.interfaces)
+
+ @cached_property
+ def flavors(self) -> FlavorsResourceWithRawResponse:
+ return FlavorsResourceWithRawResponse(self._gpu_virtual_clusters.flavors)
+
+ @cached_property
+ def images(self) -> ImagesResourceWithRawResponse:
+ return ImagesResourceWithRawResponse(self._gpu_virtual_clusters.images)
+
+
+class AsyncGPUVirtualClustersResourceWithRawResponse:
+ def __init__(self, gpu_virtual_clusters: AsyncGPUVirtualClustersResource) -> None:
+ self._gpu_virtual_clusters = gpu_virtual_clusters
+
+ self.create = async_to_raw_response_wrapper(
+ gpu_virtual_clusters.create,
+ )
+ self.update = async_to_raw_response_wrapper(
+ gpu_virtual_clusters.update,
+ )
+ self.list = async_to_raw_response_wrapper(
+ gpu_virtual_clusters.list,
+ )
+ self.delete = async_to_raw_response_wrapper(
+ gpu_virtual_clusters.delete,
+ )
+ self.action = async_to_raw_response_wrapper(
+ gpu_virtual_clusters.action,
+ )
+ self.get = async_to_raw_response_wrapper(
+ gpu_virtual_clusters.get,
+ )
+
+ @cached_property
+ def servers(self) -> AsyncServersResourceWithRawResponse:
+ return AsyncServersResourceWithRawResponse(self._gpu_virtual_clusters.servers)
+
+ @cached_property
+ def volumes(self) -> AsyncVolumesResourceWithRawResponse:
+ return AsyncVolumesResourceWithRawResponse(self._gpu_virtual_clusters.volumes)
+
+ @cached_property
+ def interfaces(self) -> AsyncInterfacesResourceWithRawResponse:
+ return AsyncInterfacesResourceWithRawResponse(self._gpu_virtual_clusters.interfaces)
+
+ @cached_property
+ def flavors(self) -> AsyncFlavorsResourceWithRawResponse:
+ return AsyncFlavorsResourceWithRawResponse(self._gpu_virtual_clusters.flavors)
+
+ @cached_property
+ def images(self) -> AsyncImagesResourceWithRawResponse:
+ return AsyncImagesResourceWithRawResponse(self._gpu_virtual_clusters.images)
+
+
+class GPUVirtualClustersResourceWithStreamingResponse:
+ def __init__(self, gpu_virtual_clusters: GPUVirtualClustersResource) -> None:
+ self._gpu_virtual_clusters = gpu_virtual_clusters
+
+ self.create = to_streamed_response_wrapper(
+ gpu_virtual_clusters.create,
+ )
+ self.update = to_streamed_response_wrapper(
+ gpu_virtual_clusters.update,
+ )
+ self.list = to_streamed_response_wrapper(
+ gpu_virtual_clusters.list,
+ )
+ self.delete = to_streamed_response_wrapper(
+ gpu_virtual_clusters.delete,
+ )
+ self.action = to_streamed_response_wrapper(
+ gpu_virtual_clusters.action,
+ )
+ self.get = to_streamed_response_wrapper(
+ gpu_virtual_clusters.get,
+ )
+
+ @cached_property
+ def servers(self) -> ServersResourceWithStreamingResponse:
+ return ServersResourceWithStreamingResponse(self._gpu_virtual_clusters.servers)
+
+ @cached_property
+ def volumes(self) -> VolumesResourceWithStreamingResponse:
+ return VolumesResourceWithStreamingResponse(self._gpu_virtual_clusters.volumes)
+
+ @cached_property
+ def interfaces(self) -> InterfacesResourceWithStreamingResponse:
+ return InterfacesResourceWithStreamingResponse(self._gpu_virtual_clusters.interfaces)
+
+ @cached_property
+ def flavors(self) -> FlavorsResourceWithStreamingResponse:
+ return FlavorsResourceWithStreamingResponse(self._gpu_virtual_clusters.flavors)
+
+ @cached_property
+ def images(self) -> ImagesResourceWithStreamingResponse:
+ return ImagesResourceWithStreamingResponse(self._gpu_virtual_clusters.images)
+
+
+class AsyncGPUVirtualClustersResourceWithStreamingResponse:
+ def __init__(self, gpu_virtual_clusters: AsyncGPUVirtualClustersResource) -> None:
+ self._gpu_virtual_clusters = gpu_virtual_clusters
+
+ self.create = async_to_streamed_response_wrapper(
+ gpu_virtual_clusters.create,
+ )
+ self.update = async_to_streamed_response_wrapper(
+ gpu_virtual_clusters.update,
+ )
+ self.list = async_to_streamed_response_wrapper(
+ gpu_virtual_clusters.list,
+ )
+ self.delete = async_to_streamed_response_wrapper(
+ gpu_virtual_clusters.delete,
+ )
+ self.action = async_to_streamed_response_wrapper(
+ gpu_virtual_clusters.action,
+ )
+ self.get = async_to_streamed_response_wrapper(
+ gpu_virtual_clusters.get,
+ )
+
+ @cached_property
+ def servers(self) -> AsyncServersResourceWithStreamingResponse:
+ return AsyncServersResourceWithStreamingResponse(self._gpu_virtual_clusters.servers)
+
+ @cached_property
+ def volumes(self) -> AsyncVolumesResourceWithStreamingResponse:
+ return AsyncVolumesResourceWithStreamingResponse(self._gpu_virtual_clusters.volumes)
+
+ @cached_property
+ def interfaces(self) -> AsyncInterfacesResourceWithStreamingResponse:
+ return AsyncInterfacesResourceWithStreamingResponse(self._gpu_virtual_clusters.interfaces)
+
+ @cached_property
+ def flavors(self) -> AsyncFlavorsResourceWithStreamingResponse:
+ return AsyncFlavorsResourceWithStreamingResponse(self._gpu_virtual_clusters.flavors)
+
+ @cached_property
+ def images(self) -> AsyncImagesResourceWithStreamingResponse:
+ return AsyncImagesResourceWithStreamingResponse(self._gpu_virtual_clusters.images)
diff --git a/src/gcore/resources/cloud/gpu_virtual_clusters/images.py b/src/gcore/resources/cloud/gpu_virtual_clusters/images.py
new file mode 100644
index 00000000..47315e2a
--- /dev/null
+++ b/src/gcore/resources/cloud/gpu_virtual_clusters/images.py
@@ -0,0 +1,580 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Dict, Optional
+from typing_extensions import Literal
+
+import httpx
+
+from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from ...._utils import maybe_transform, async_maybe_transform
+from ...._compat import cached_property
+from ...._resource import SyncAPIResource, AsyncAPIResource
+from ...._response import (
+ to_raw_response_wrapper,
+ to_streamed_response_wrapper,
+ async_to_raw_response_wrapper,
+ async_to_streamed_response_wrapper,
+)
+from ...._base_client import make_request_options
+from ....types.cloud.gpu_image import GPUImage
+from ....types.cloud.task_id_list import TaskIDList
+from ....types.cloud.gpu_image_list import GPUImageList
+from ....types.cloud.gpu_virtual_clusters import image_upload_params
+
+__all__ = ["ImagesResource", "AsyncImagesResource"]
+
+
+class ImagesResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> ImagesResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers
+ """
+ return ImagesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> ImagesResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response
+ """
+ return ImagesResourceWithStreamingResponse(self)
+
+ def list(
+ self,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ # 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,
+ ) -> GPUImageList:
+ """
+ List virtual GPU images
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ 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()
+ return self._get(
+ f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/images",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=GPUImageList,
+ )
+
+ def delete(
+ self,
+ image_id: str,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ # 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:
+ """
+ Delete virtual GPU image
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ image_id: Image ID
+
+ 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 image_id:
+ raise ValueError(f"Expected a non-empty value for `image_id` but received {image_id!r}")
+ return self._delete(
+ f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/images/{image_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=TaskIDList,
+ )
+
+ def get(
+ self,
+ image_id: str,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ # 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,
+ ) -> GPUImage:
+ """
+ Get virtual GPU image
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ image_id: Image ID
+
+ 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 image_id:
+ raise ValueError(f"Expected a non-empty value for `image_id` but received {image_id!r}")
+ return self._get(
+ f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/images/{image_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=GPUImage,
+ )
+
+ def upload(
+ self,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ name: str,
+ url: str,
+ architecture: Optional[Literal["aarch64", "x86_64"]] | Omit = omit,
+ cow_format: bool | Omit = omit,
+ hw_firmware_type: Optional[Literal["bios", "uefi"]] | Omit = omit,
+ os_distro: Optional[str] | Omit = omit,
+ os_type: Optional[Literal["linux", "windows"]] | Omit = omit,
+ os_version: Optional[str] | Omit = omit,
+ ssh_key: Literal["allow", "deny", "required"] | Omit = omit,
+ tags: Dict[str, 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,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> TaskIDList:
+ """
+ Upload new virtual GPU image
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ name: Image name
+
+ url: Image URL
+
+ architecture: Image architecture type: aarch64, `x86_64`
+
+ cow_format: When True, image cannot be deleted unless all volumes, created from it, are
+ deleted.
+
+ hw_firmware_type: Specifies the type of firmware with which to boot the guest.
+
+ os_distro: OS Distribution, i.e. Debian, CentOS, Ubuntu, CoreOS etc.
+
+ os_type: The operating system installed on the image. Linux by default
+
+ os_version: OS version, i.e. 19.04 (for Ubuntu) or 9.4 for Debian
+
+ ssh_key: Permission to use a ssh key in instances
+
+ tags: Key-value tags to associate with the resource. A tag is a key-value pair that
+ can be associated with a resource, enabling efficient filtering and grouping for
+ better organization and management. Some tags are read-only and cannot be
+ modified by the user. Tags are also integrated with cost reports, allowing cost
+ data to be filtered based on tag keys or values.
+
+ 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()
+ return self._post(
+ f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/images",
+ body=maybe_transform(
+ {
+ "name": name,
+ "url": url,
+ "architecture": architecture,
+ "cow_format": cow_format,
+ "hw_firmware_type": hw_firmware_type,
+ "os_distro": os_distro,
+ "os_type": os_type,
+ "os_version": os_version,
+ "ssh_key": ssh_key,
+ "tags": tags,
+ },
+ image_upload_params.ImageUploadParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=TaskIDList,
+ )
+
+
+class AsyncImagesResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncImagesResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncImagesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncImagesResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response
+ """
+ return AsyncImagesResourceWithStreamingResponse(self)
+
+ async def list(
+ self,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ # 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,
+ ) -> GPUImageList:
+ """
+ List virtual GPU images
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ 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()
+ return await self._get(
+ f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/images",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=GPUImageList,
+ )
+
+ async def delete(
+ self,
+ image_id: str,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ # 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:
+ """
+ Delete virtual GPU image
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ image_id: Image ID
+
+ 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 image_id:
+ raise ValueError(f"Expected a non-empty value for `image_id` but received {image_id!r}")
+ return await self._delete(
+ f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/images/{image_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=TaskIDList,
+ )
+
+ async def get(
+ self,
+ image_id: str,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ # 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,
+ ) -> GPUImage:
+ """
+ Get virtual GPU image
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ image_id: Image ID
+
+ 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 image_id:
+ raise ValueError(f"Expected a non-empty value for `image_id` but received {image_id!r}")
+ return await self._get(
+ f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/images/{image_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=GPUImage,
+ )
+
+ async def upload(
+ self,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ name: str,
+ url: str,
+ architecture: Optional[Literal["aarch64", "x86_64"]] | Omit = omit,
+ cow_format: bool | Omit = omit,
+ hw_firmware_type: Optional[Literal["bios", "uefi"]] | Omit = omit,
+ os_distro: Optional[str] | Omit = omit,
+ os_type: Optional[Literal["linux", "windows"]] | Omit = omit,
+ os_version: Optional[str] | Omit = omit,
+ ssh_key: Literal["allow", "deny", "required"] | Omit = omit,
+ tags: Dict[str, 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,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> TaskIDList:
+ """
+ Upload new virtual GPU image
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ name: Image name
+
+ url: Image URL
+
+ architecture: Image architecture type: aarch64, `x86_64`
+
+ cow_format: When True, image cannot be deleted unless all volumes, created from it, are
+ deleted.
+
+ hw_firmware_type: Specifies the type of firmware with which to boot the guest.
+
+ os_distro: OS Distribution, i.e. Debian, CentOS, Ubuntu, CoreOS etc.
+
+ os_type: The operating system installed on the image. Linux by default
+
+ os_version: OS version, i.e. 19.04 (for Ubuntu) or 9.4 for Debian
+
+ ssh_key: Permission to use a ssh key in instances
+
+ tags: Key-value tags to associate with the resource. A tag is a key-value pair that
+ can be associated with a resource, enabling efficient filtering and grouping for
+ better organization and management. Some tags are read-only and cannot be
+ modified by the user. Tags are also integrated with cost reports, allowing cost
+ data to be filtered based on tag keys or values.
+
+ 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()
+ return await self._post(
+ f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/images",
+ body=await async_maybe_transform(
+ {
+ "name": name,
+ "url": url,
+ "architecture": architecture,
+ "cow_format": cow_format,
+ "hw_firmware_type": hw_firmware_type,
+ "os_distro": os_distro,
+ "os_type": os_type,
+ "os_version": os_version,
+ "ssh_key": ssh_key,
+ "tags": tags,
+ },
+ image_upload_params.ImageUploadParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=TaskIDList,
+ )
+
+
+class ImagesResourceWithRawResponse:
+ def __init__(self, images: ImagesResource) -> None:
+ self._images = images
+
+ self.list = to_raw_response_wrapper(
+ images.list,
+ )
+ self.delete = to_raw_response_wrapper(
+ images.delete,
+ )
+ self.get = to_raw_response_wrapper(
+ images.get,
+ )
+ self.upload = to_raw_response_wrapper(
+ images.upload,
+ )
+
+
+class AsyncImagesResourceWithRawResponse:
+ def __init__(self, images: AsyncImagesResource) -> None:
+ self._images = images
+
+ self.list = async_to_raw_response_wrapper(
+ images.list,
+ )
+ self.delete = async_to_raw_response_wrapper(
+ images.delete,
+ )
+ self.get = async_to_raw_response_wrapper(
+ images.get,
+ )
+ self.upload = async_to_raw_response_wrapper(
+ images.upload,
+ )
+
+
+class ImagesResourceWithStreamingResponse:
+ def __init__(self, images: ImagesResource) -> None:
+ self._images = images
+
+ self.list = to_streamed_response_wrapper(
+ images.list,
+ )
+ self.delete = to_streamed_response_wrapper(
+ images.delete,
+ )
+ self.get = to_streamed_response_wrapper(
+ images.get,
+ )
+ self.upload = to_streamed_response_wrapper(
+ images.upload,
+ )
+
+
+class AsyncImagesResourceWithStreamingResponse:
+ def __init__(self, images: AsyncImagesResource) -> None:
+ self._images = images
+
+ self.list = async_to_streamed_response_wrapper(
+ images.list,
+ )
+ self.delete = async_to_streamed_response_wrapper(
+ images.delete,
+ )
+ self.get = async_to_streamed_response_wrapper(
+ images.get,
+ )
+ self.upload = async_to_streamed_response_wrapper(
+ images.upload,
+ )
diff --git a/src/gcore/resources/cloud/gpu_virtual_clusters/interfaces.py b/src/gcore/resources/cloud/gpu_virtual_clusters/interfaces.py
new file mode 100644
index 00000000..ca97cda6
--- /dev/null
+++ b/src/gcore/resources/cloud/gpu_virtual_clusters/interfaces.py
@@ -0,0 +1,187 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from ...._types import Body, Query, Headers, NotGiven, not_given
+from ...._compat import cached_property
+from ...._resource import SyncAPIResource, AsyncAPIResource
+from ...._response import (
+ to_raw_response_wrapper,
+ to_streamed_response_wrapper,
+ async_to_raw_response_wrapper,
+ async_to_streamed_response_wrapper,
+)
+from ...._base_client import make_request_options
+from ....types.cloud.gpu_virtual_clusters.gpu_virtual_interface_list import GPUVirtualInterfaceList
+
+__all__ = ["InterfacesResource", "AsyncInterfacesResource"]
+
+
+class InterfacesResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> InterfacesResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers
+ """
+ return InterfacesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> InterfacesResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response
+ """
+ return InterfacesResourceWithStreamingResponse(self)
+
+ def list(
+ self,
+ cluster_id: str,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ # 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,
+ ) -> GPUVirtualInterfaceList:
+ """
+ List all network interfaces for servers in a virtual GPU cluster.
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ cluster_id: Cluster 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}")
+ return self._get(
+ f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters/{cluster_id}/interfaces",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=GPUVirtualInterfaceList,
+ )
+
+
+class AsyncInterfacesResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncInterfacesResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncInterfacesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncInterfacesResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response
+ """
+ return AsyncInterfacesResourceWithStreamingResponse(self)
+
+ async def list(
+ self,
+ cluster_id: str,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ # 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,
+ ) -> GPUVirtualInterfaceList:
+ """
+ List all network interfaces for servers in a virtual GPU cluster.
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ cluster_id: Cluster 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}")
+ return await self._get(
+ f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters/{cluster_id}/interfaces",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=GPUVirtualInterfaceList,
+ )
+
+
+class InterfacesResourceWithRawResponse:
+ def __init__(self, interfaces: InterfacesResource) -> None:
+ self._interfaces = interfaces
+
+ self.list = to_raw_response_wrapper(
+ interfaces.list,
+ )
+
+
+class AsyncInterfacesResourceWithRawResponse:
+ def __init__(self, interfaces: AsyncInterfacesResource) -> None:
+ self._interfaces = interfaces
+
+ self.list = async_to_raw_response_wrapper(
+ interfaces.list,
+ )
+
+
+class InterfacesResourceWithStreamingResponse:
+ def __init__(self, interfaces: InterfacesResource) -> None:
+ self._interfaces = interfaces
+
+ self.list = to_streamed_response_wrapper(
+ interfaces.list,
+ )
+
+
+class AsyncInterfacesResourceWithStreamingResponse:
+ def __init__(self, interfaces: AsyncInterfacesResource) -> None:
+ self._interfaces = interfaces
+
+ self.list = async_to_streamed_response_wrapper(
+ interfaces.list,
+ )
diff --git a/src/gcore/resources/cloud/gpu_virtual_clusters/servers.py b/src/gcore/resources/cloud/gpu_virtual_clusters/servers.py
new file mode 100644
index 00000000..a0176570
--- /dev/null
+++ b/src/gcore/resources/cloud/gpu_virtual_clusters/servers.py
@@ -0,0 +1,506 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from datetime import datetime
+from typing_extensions import Literal
+
+import httpx
+
+from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given
+from ...._utils import maybe_transform, async_maybe_transform
+from ...._compat import cached_property
+from ...._resource import SyncAPIResource, AsyncAPIResource
+from ...._response import (
+ to_raw_response_wrapper,
+ to_streamed_response_wrapper,
+ async_to_raw_response_wrapper,
+ async_to_streamed_response_wrapper,
+)
+from ...._base_client import make_request_options
+from ....types.cloud.task_id_list import TaskIDList
+from ....types.cloud.gpu_virtual_clusters import server_list_params, server_delete_params
+from ....types.cloud.gpu_virtual_clusters.gpu_virtual_cluster_server_list import GPUVirtualClusterServerList
+
+__all__ = ["ServersResource", "AsyncServersResource"]
+
+
+class ServersResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> ServersResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers
+ """
+ return ServersResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> ServersResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response
+ """
+ return ServersResourceWithStreamingResponse(self)
+
+ def list(
+ self,
+ cluster_id: str,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ changed_before: Union[str, datetime] | Omit = omit,
+ changed_since: Union[str, datetime] | Omit = omit,
+ ip_address: str | Omit = omit,
+ limit: int | Omit = omit,
+ name: str | Omit = omit,
+ offset: int | Omit = omit,
+ order_by: Literal["created_at.asc", "created_at.desc", "status.asc", "status.desc"] | Omit = omit,
+ status: Literal[
+ "ACTIVE",
+ "BUILD",
+ "ERROR",
+ "HARD_REBOOT",
+ "MIGRATING",
+ "PAUSED",
+ "REBOOT",
+ "REBUILD",
+ "RESIZE",
+ "REVERT_RESIZE",
+ "SHELVED",
+ "SHELVED_OFFLOADED",
+ "SHUTOFF",
+ "SOFT_DELETED",
+ "SUSPENDED",
+ "VERIFY_RESIZE",
+ ]
+ | Omit = omit,
+ uuids: SequenceNotStr[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,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> GPUVirtualClusterServerList:
+ """
+ List all servers in a virtual GPU cluster.
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ cluster_id: Cluster unique identifier
+
+ changed_before: Filters the results to include only servers whose last change timestamp is less
+ than the specified datetime. Format: ISO 8601.
+
+ changed_since: Filters the results to include only servers whose last change timestamp is
+ greater than or equal to the specified datetime. Format: ISO 8601.
+
+ ip_address: Filter servers by ip address.
+
+ limit: Limit of items on a single page
+
+ name: Filter servers by name. You can provide a full or partial name, servers with
+ matching names will be returned. For example, entering 'test' will return all
+ servers that contain 'test' in their name.
+
+ offset: Offset in results list
+
+ order_by: Order field
+
+ status: Filters servers by status.
+
+ uuids: Filter servers by uuid.
+
+ 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._get(
+ f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters/{cluster_id}/servers",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "changed_before": changed_before,
+ "changed_since": changed_since,
+ "ip_address": ip_address,
+ "limit": limit,
+ "name": name,
+ "offset": offset,
+ "order_by": order_by,
+ "status": status,
+ "uuids": uuids,
+ },
+ server_list_params.ServerListParams,
+ ),
+ ),
+ cast_to=GPUVirtualClusterServerList,
+ )
+
+ def delete(
+ self,
+ server_id: str,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ cluster_id: str,
+ all_floating_ips: bool | Omit = omit,
+ all_reserved_fixed_ips: bool | Omit = omit,
+ all_volumes: bool | Omit = omit,
+ floating_ip_ids: SequenceNotStr[str] | Omit = omit,
+ reserved_fixed_ip_ids: SequenceNotStr[str] | Omit = omit,
+ volume_ids: SequenceNotStr[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,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> TaskIDList:
+ """
+ Delete a server from a virtual GPU cluster and its associated resources.
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ cluster_id: Cluster unique identifier
+
+ server_id: Server unique identifier
+
+ all_floating_ips: Flag indicating whether the floating ips associated with server / cluster are
+ deleted
+
+ all_reserved_fixed_ips: Flag indicating whether the reserved fixed ips associated with server / cluster
+ are deleted
+
+ all_volumes: Flag indicating whether all attached volumes are deleted
+
+ floating_ip_ids: Optional list of floating ips to be deleted
+
+ reserved_fixed_ip_ids: Optional list of reserved fixed ips to be deleted
+
+ volume_ids: Optional list of volumes to be deleted
+
+ 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._delete(
+ f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters/{cluster_id}/servers/{server_id}",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "all_floating_ips": all_floating_ips,
+ "all_reserved_fixed_ips": all_reserved_fixed_ips,
+ "all_volumes": all_volumes,
+ "floating_ip_ids": floating_ip_ids,
+ "reserved_fixed_ip_ids": reserved_fixed_ip_ids,
+ "volume_ids": volume_ids,
+ },
+ server_delete_params.ServerDeleteParams,
+ ),
+ ),
+ cast_to=TaskIDList,
+ )
+
+
+class AsyncServersResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncServersResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncServersResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncServersResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response
+ """
+ return AsyncServersResourceWithStreamingResponse(self)
+
+ async def list(
+ self,
+ cluster_id: str,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ changed_before: Union[str, datetime] | Omit = omit,
+ changed_since: Union[str, datetime] | Omit = omit,
+ ip_address: str | Omit = omit,
+ limit: int | Omit = omit,
+ name: str | Omit = omit,
+ offset: int | Omit = omit,
+ order_by: Literal["created_at.asc", "created_at.desc", "status.asc", "status.desc"] | Omit = omit,
+ status: Literal[
+ "ACTIVE",
+ "BUILD",
+ "ERROR",
+ "HARD_REBOOT",
+ "MIGRATING",
+ "PAUSED",
+ "REBOOT",
+ "REBUILD",
+ "RESIZE",
+ "REVERT_RESIZE",
+ "SHELVED",
+ "SHELVED_OFFLOADED",
+ "SHUTOFF",
+ "SOFT_DELETED",
+ "SUSPENDED",
+ "VERIFY_RESIZE",
+ ]
+ | Omit = omit,
+ uuids: SequenceNotStr[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,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> GPUVirtualClusterServerList:
+ """
+ List all servers in a virtual GPU cluster.
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ cluster_id: Cluster unique identifier
+
+ changed_before: Filters the results to include only servers whose last change timestamp is less
+ than the specified datetime. Format: ISO 8601.
+
+ changed_since: Filters the results to include only servers whose last change timestamp is
+ greater than or equal to the specified datetime. Format: ISO 8601.
+
+ ip_address: Filter servers by ip address.
+
+ limit: Limit of items on a single page
+
+ name: Filter servers by name. You can provide a full or partial name, servers with
+ matching names will be returned. For example, entering 'test' will return all
+ servers that contain 'test' in their name.
+
+ offset: Offset in results list
+
+ order_by: Order field
+
+ status: Filters servers by status.
+
+ uuids: Filter servers by uuid.
+
+ 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._get(
+ f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters/{cluster_id}/servers",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "changed_before": changed_before,
+ "changed_since": changed_since,
+ "ip_address": ip_address,
+ "limit": limit,
+ "name": name,
+ "offset": offset,
+ "order_by": order_by,
+ "status": status,
+ "uuids": uuids,
+ },
+ server_list_params.ServerListParams,
+ ),
+ ),
+ cast_to=GPUVirtualClusterServerList,
+ )
+
+ async def delete(
+ self,
+ server_id: str,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ cluster_id: str,
+ all_floating_ips: bool | Omit = omit,
+ all_reserved_fixed_ips: bool | Omit = omit,
+ all_volumes: bool | Omit = omit,
+ floating_ip_ids: SequenceNotStr[str] | Omit = omit,
+ reserved_fixed_ip_ids: SequenceNotStr[str] | Omit = omit,
+ volume_ids: SequenceNotStr[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,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> TaskIDList:
+ """
+ Delete a server from a virtual GPU cluster and its associated resources.
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ cluster_id: Cluster unique identifier
+
+ server_id: Server unique identifier
+
+ all_floating_ips: Flag indicating whether the floating ips associated with server / cluster are
+ deleted
+
+ all_reserved_fixed_ips: Flag indicating whether the reserved fixed ips associated with server / cluster
+ are deleted
+
+ all_volumes: Flag indicating whether all attached volumes are deleted
+
+ floating_ip_ids: Optional list of floating ips to be deleted
+
+ reserved_fixed_ip_ids: Optional list of reserved fixed ips to be deleted
+
+ volume_ids: Optional list of volumes to be deleted
+
+ 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._delete(
+ f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters/{cluster_id}/servers/{server_id}",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "all_floating_ips": all_floating_ips,
+ "all_reserved_fixed_ips": all_reserved_fixed_ips,
+ "all_volumes": all_volumes,
+ "floating_ip_ids": floating_ip_ids,
+ "reserved_fixed_ip_ids": reserved_fixed_ip_ids,
+ "volume_ids": volume_ids,
+ },
+ server_delete_params.ServerDeleteParams,
+ ),
+ ),
+ cast_to=TaskIDList,
+ )
+
+
+class ServersResourceWithRawResponse:
+ def __init__(self, servers: ServersResource) -> None:
+ self._servers = servers
+
+ self.list = to_raw_response_wrapper(
+ servers.list,
+ )
+ self.delete = to_raw_response_wrapper(
+ servers.delete,
+ )
+
+
+class AsyncServersResourceWithRawResponse:
+ def __init__(self, servers: AsyncServersResource) -> None:
+ self._servers = servers
+
+ self.list = async_to_raw_response_wrapper(
+ servers.list,
+ )
+ self.delete = async_to_raw_response_wrapper(
+ servers.delete,
+ )
+
+
+class ServersResourceWithStreamingResponse:
+ def __init__(self, servers: ServersResource) -> None:
+ self._servers = servers
+
+ self.list = to_streamed_response_wrapper(
+ servers.list,
+ )
+ self.delete = to_streamed_response_wrapper(
+ servers.delete,
+ )
+
+
+class AsyncServersResourceWithStreamingResponse:
+ def __init__(self, servers: AsyncServersResource) -> None:
+ self._servers = servers
+
+ self.list = async_to_streamed_response_wrapper(
+ servers.list,
+ )
+ self.delete = async_to_streamed_response_wrapper(
+ servers.delete,
+ )
diff --git a/src/gcore/resources/cloud/gpu_virtual_clusters/volumes.py b/src/gcore/resources/cloud/gpu_virtual_clusters/volumes.py
new file mode 100644
index 00000000..390e7cf9
--- /dev/null
+++ b/src/gcore/resources/cloud/gpu_virtual_clusters/volumes.py
@@ -0,0 +1,187 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from ...._types import Body, Query, Headers, NotGiven, not_given
+from ...._compat import cached_property
+from ...._resource import SyncAPIResource, AsyncAPIResource
+from ...._response import (
+ to_raw_response_wrapper,
+ to_streamed_response_wrapper,
+ async_to_raw_response_wrapper,
+ async_to_streamed_response_wrapper,
+)
+from ...._base_client import make_request_options
+from ....types.cloud.gpu_virtual_clusters.gpu_virtual_cluster_volume_list import GPUVirtualClusterVolumeList
+
+__all__ = ["VolumesResource", "AsyncVolumesResource"]
+
+
+class VolumesResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> VolumesResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers
+ """
+ return VolumesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> VolumesResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response
+ """
+ return VolumesResourceWithStreamingResponse(self)
+
+ def list(
+ self,
+ cluster_id: str,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ # 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,
+ ) -> GPUVirtualClusterVolumeList:
+ """
+ List all volumes attached to servers in a virtual GPU cluster.
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ cluster_id: Cluster 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}")
+ return self._get(
+ f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters/{cluster_id}/volumes",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=GPUVirtualClusterVolumeList,
+ )
+
+
+class AsyncVolumesResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncVolumesResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncVolumesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncVolumesResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response
+ """
+ return AsyncVolumesResourceWithStreamingResponse(self)
+
+ async def list(
+ self,
+ cluster_id: str,
+ *,
+ project_id: int | None = None,
+ region_id: int | None = None,
+ # 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,
+ ) -> GPUVirtualClusterVolumeList:
+ """
+ List all volumes attached to servers in a virtual GPU cluster.
+
+ Args:
+ project_id: Project ID
+
+ region_id: Region ID
+
+ cluster_id: Cluster 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}")
+ return await self._get(
+ f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters/{cluster_id}/volumes",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=GPUVirtualClusterVolumeList,
+ )
+
+
+class VolumesResourceWithRawResponse:
+ def __init__(self, volumes: VolumesResource) -> None:
+ self._volumes = volumes
+
+ self.list = to_raw_response_wrapper(
+ volumes.list,
+ )
+
+
+class AsyncVolumesResourceWithRawResponse:
+ def __init__(self, volumes: AsyncVolumesResource) -> None:
+ self._volumes = volumes
+
+ self.list = async_to_raw_response_wrapper(
+ volumes.list,
+ )
+
+
+class VolumesResourceWithStreamingResponse:
+ def __init__(self, volumes: VolumesResource) -> None:
+ self._volumes = volumes
+
+ self.list = to_streamed_response_wrapper(
+ volumes.list,
+ )
+
+
+class AsyncVolumesResourceWithStreamingResponse:
+ def __init__(self, volumes: AsyncVolumesResource) -> None:
+ self._volumes = volumes
+
+ self.list = async_to_streamed_response_wrapper(
+ volumes.list,
+ )
diff --git a/src/gcore/types/cloud/__init__.py b/src/gcore/types/cloud/__init__.py
index 80b12b29..e97ac01a 100644
--- a/src/gcore/types/cloud/__init__.py
+++ b/src/gcore/types/cloud/__init__.py
@@ -64,6 +64,7 @@
from .billing_reservation import BillingReservation as BillingReservation
from .ddos_profile_status import DDOSProfileStatus as DDOSProfileStatus
from .fixed_address_short import FixedAddressShort as FixedAddressShort
+from .gpu_virtual_cluster import GPUVirtualCluster as GPUVirtualCluster
from .interface_ip_family import InterfaceIPFamily as InterfaceIPFamily
from .k8s_cluster_version import K8sClusterVersion as K8sClusterVersion
from .network_list_params import NetworkListParams as NetworkListParams
@@ -160,11 +161,16 @@
from .load_balancer_operating_status import LoadBalancerOperatingStatus as LoadBalancerOperatingStatus
from .billing_reservation_list_params import BillingReservationListParams as BillingReservationListParams
from .cost_report_get_detailed_params import CostReportGetDetailedParams as CostReportGetDetailedParams
+from .gpu_virtual_cluster_list_params import GPUVirtualClusterListParams as GPUVirtualClusterListParams
from .reserved_fixed_ip_create_params import ReservedFixedIPCreateParams as ReservedFixedIPCreateParams
from .reserved_fixed_ip_update_params import ReservedFixedIPUpdateParams as ReservedFixedIPUpdateParams
from .volume_attach_to_instance_params import VolumeAttachToInstanceParams as VolumeAttachToInstanceParams
from .cost_report_get_aggregated_params import CostReportGetAggregatedParams as CostReportGetAggregatedParams
from .gpu_baremetal_cluster_list_params import GPUBaremetalClusterListParams as GPUBaremetalClusterListParams
+from .gpu_virtual_cluster_action_params import GPUVirtualClusterActionParams as GPUVirtualClusterActionParams
+from .gpu_virtual_cluster_create_params import GPUVirtualClusterCreateParams as GPUVirtualClusterCreateParams
+from .gpu_virtual_cluster_delete_params import GPUVirtualClusterDeleteParams as GPUVirtualClusterDeleteParams
+from .gpu_virtual_cluster_update_params import GPUVirtualClusterUpdateParams as GPUVirtualClusterUpdateParams
from .laas_index_retention_policy_param import LaasIndexRetentionPolicyParam as LaasIndexRetentionPolicyParam
from .load_balancer_member_connectivity import LoadBalancerMemberConnectivity as LoadBalancerMemberConnectivity
from .volume_detach_from_instance_params import VolumeDetachFromInstanceParams as VolumeDetachFromInstanceParams
diff --git a/src/gcore/types/cloud/gpu_virtual_cluster.py b/src/gcore/types/cloud/gpu_virtual_cluster.py
new file mode 100644
index 00000000..28d58c1e
--- /dev/null
+++ b/src/gcore/types/cloud/gpu_virtual_cluster.py
@@ -0,0 +1,189 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Union, Optional
+from datetime import datetime
+from typing_extensions import Literal, Annotated, TypeAlias
+
+from .tag import Tag
+from ..._utils import PropertyInfo
+from ..._models import BaseModel
+
+__all__ = [
+ "GPUVirtualCluster",
+ "ServersSettings",
+ "ServersSettingsFileShare",
+ "ServersSettingsInterface",
+ "ServersSettingsInterfaceExternalInterfaceOutputSerializer",
+ "ServersSettingsInterfaceSubnetInterfaceOutputSerializer",
+ "ServersSettingsInterfaceSubnetInterfaceOutputSerializerFloatingIP",
+ "ServersSettingsInterfaceAnySubnetInterfaceOutputSerializer",
+ "ServersSettingsInterfaceAnySubnetInterfaceOutputSerializerFloatingIP",
+ "ServersSettingsSecurityGroup",
+ "ServersSettingsVolume",
+]
+
+
+class ServersSettingsFileShare(BaseModel):
+ id: str
+ """Unique identifier of the file share in UUID format."""
+
+ mount_path: str
+ """Absolute mount path inside the system where the file share will be mounted."""
+
+
+class ServersSettingsInterfaceExternalInterfaceOutputSerializer(BaseModel):
+ ip_family: Literal["dual", "ipv4", "ipv6"]
+ """Which subnets should be selected: IPv4, IPv6, or use dual stack."""
+
+ name: Optional[str] = None
+ """Interface name"""
+
+ type: Literal["external"]
+
+
+class ServersSettingsInterfaceSubnetInterfaceOutputSerializerFloatingIP(BaseModel):
+ source: Literal["new"]
+
+
+class ServersSettingsInterfaceSubnetInterfaceOutputSerializer(BaseModel):
+ floating_ip: Optional[ServersSettingsInterfaceSubnetInterfaceOutputSerializerFloatingIP] = None
+ """Floating IP config for this subnet attachment"""
+
+ name: Optional[str] = None
+ """Interface name"""
+
+ network_id: str
+ """Network ID the subnet belongs to. Port will be plugged in this network"""
+
+ subnet_id: str
+ """Port is assigned an IP address from this subnet"""
+
+ type: Literal["subnet"]
+
+
+class ServersSettingsInterfaceAnySubnetInterfaceOutputSerializerFloatingIP(BaseModel):
+ source: Literal["new"]
+
+
+class ServersSettingsInterfaceAnySubnetInterfaceOutputSerializer(BaseModel):
+ floating_ip: Optional[ServersSettingsInterfaceAnySubnetInterfaceOutputSerializerFloatingIP] = None
+ """Floating IP config for this subnet attachment"""
+
+ ip_address: Optional[str] = None
+ """Fixed IP address"""
+
+ ip_family: Literal["dual", "ipv4", "ipv6"]
+ """Which subnets should be selected: IPv4, IPv6, or use dual stack"""
+
+ name: Optional[str] = None
+ """Interface name"""
+
+ network_id: str
+ """Network ID the subnet belongs to. Port will be plugged in this network"""
+
+ type: Literal["any_subnet"]
+
+
+ServersSettingsInterface: TypeAlias = Annotated[
+ Union[
+ ServersSettingsInterfaceExternalInterfaceOutputSerializer,
+ ServersSettingsInterfaceSubnetInterfaceOutputSerializer,
+ ServersSettingsInterfaceAnySubnetInterfaceOutputSerializer,
+ ],
+ PropertyInfo(discriminator="type"),
+]
+
+
+class ServersSettingsSecurityGroup(BaseModel):
+ id: str
+ """Security group ID"""
+
+ name: str
+ """Security group name"""
+
+
+class ServersSettingsVolume(BaseModel):
+ boot_index: Optional[int] = None
+ """Boot index of the volume"""
+
+ delete_on_termination: bool
+ """Flag indicating whether the volume is deleted on instance termination"""
+
+ image_id: Optional[str] = None
+ """Image ID for the volume"""
+
+ name: str
+ """Volume name"""
+
+ size: int
+ """Volume size in GiB"""
+
+ tags: List[Tag]
+ """List of key-value tags associated with the resource.
+
+ A tag is a key-value pair that can be associated with a resource, enabling
+ efficient filtering and grouping for better organization and management. Some
+ tags are read-only and cannot be modified by the user. Tags are also integrated
+ with cost reports, allowing cost data to be filtered based on tag keys or
+ values.
+ """
+
+ type: Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"]
+ """Volume type"""
+
+
+class ServersSettings(BaseModel):
+ file_shares: List[ServersSettingsFileShare]
+ """List of file shares mounted across the cluster."""
+
+ interfaces: List[ServersSettingsInterface]
+
+ security_groups: List[ServersSettingsSecurityGroup]
+ """Security groups"""
+
+ ssh_key_name: Optional[str] = None
+ """SSH key name"""
+
+ user_data: Optional[str] = None
+ """Optional custom user data"""
+
+ volumes: List[ServersSettingsVolume]
+ """List of volumes"""
+
+
+class GPUVirtualCluster(BaseModel):
+ id: str
+ """Cluster unique identifier"""
+
+ created_at: datetime
+ """Cluster creation date time"""
+
+ flavor: str
+ """Cluster flavor name"""
+
+ name: str
+ """Cluster name"""
+
+ servers_count: int
+ """Cluster servers count"""
+
+ servers_ids: List[str]
+ """List of cluster nodes"""
+
+ servers_settings: ServersSettings
+
+ status: Literal["active", "deleting", "error", "new", "resizing"]
+ """Cluster status"""
+
+ tags: List[Tag]
+ """List of key-value tags associated with the resource.
+
+ A tag is a key-value pair that can be associated with a resource, enabling
+ efficient filtering and grouping for better organization and management. Some
+ tags are read-only and cannot be modified by the user. Tags are also integrated
+ with cost reports, allowing cost data to be filtered based on tag keys or
+ values.
+ """
+
+ updated_at: Optional[datetime] = None
+ """Cluster update date time"""
diff --git a/src/gcore/types/cloud/gpu_virtual_cluster_action_params.py b/src/gcore/types/cloud/gpu_virtual_cluster_action_params.py
new file mode 100644
index 00000000..0c5f99b8
--- /dev/null
+++ b/src/gcore/types/cloud/gpu_virtual_cluster_action_params.py
@@ -0,0 +1,122 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union, Optional
+from typing_extensions import Literal, Required, TypeAlias, TypedDict
+
+from .tag_update_map_param import TagUpdateMapParam
+
+__all__ = [
+ "GPUVirtualClusterActionParams",
+ "StartVirtualGPUClusterSerializer",
+ "StopVirtualGPUClusterSerializer",
+ "SoftRebootVirtualGPUClusterSerializer",
+ "HardRebootVirtualGPUClusterSerializer",
+ "UpdateTagsGPUClusterSerializer",
+ "ResizeVirtualGPUClusterSerializer",
+]
+
+
+class StartVirtualGPUClusterSerializer(TypedDict, total=False):
+ project_id: int
+ """Project ID"""
+
+ region_id: int
+ """Region ID"""
+
+ action: Required[Literal["start"]]
+ """Action name"""
+
+
+class StopVirtualGPUClusterSerializer(TypedDict, total=False):
+ project_id: int
+ """Project ID"""
+
+ region_id: int
+ """Region ID"""
+
+ action: Required[Literal["stop"]]
+ """Action name"""
+
+
+class SoftRebootVirtualGPUClusterSerializer(TypedDict, total=False):
+ project_id: int
+ """Project ID"""
+
+ region_id: int
+ """Region ID"""
+
+ action: Required[Literal["soft_reboot"]]
+ """Action name"""
+
+
+class HardRebootVirtualGPUClusterSerializer(TypedDict, total=False):
+ project_id: int
+ """Project ID"""
+
+ region_id: int
+ """Region ID"""
+
+ action: Required[Literal["hard_reboot"]]
+ """Action name"""
+
+
+class UpdateTagsGPUClusterSerializer(TypedDict, total=False):
+ project_id: int
+ """Project ID"""
+
+ region_id: int
+ """Region ID"""
+
+ action: Required[Literal["update_tags"]]
+ """Action name"""
+
+ tags: Required[Optional[TagUpdateMapParam]]
+ """Update key-value tags using JSON Merge Patch semantics (RFC 7386).
+
+ Provide key-value pairs to add or update tags. Set tag values to `null` to
+ remove tags. Unspecified tags remain unchanged. Read-only tags are always
+ preserved and cannot be modified.
+
+ **Examples:**
+
+ - **Add/update tags:**
+ `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or
+ updates existing ones.
+ - **Delete tags:** `{'tags': {'`old_tag`': null}}` removes specific tags.
+ - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only
+ tags are preserved).
+ - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates
+ specified tags.
+ - **Mixed operations:**
+ `{'tags': {'environment': 'production', '`cost_center`': 'engineering', '`deprecated_tag`': null}}`
+ adds/updates 'environment' and '`cost_center`' while removing
+ '`deprecated_tag`', preserving other existing tags.
+ - **Replace all:** first delete existing tags with null values, then add new
+ ones in the same request.
+ """
+
+
+class ResizeVirtualGPUClusterSerializer(TypedDict, total=False):
+ project_id: int
+ """Project ID"""
+
+ region_id: int
+ """Region ID"""
+
+ action: Required[Literal["resize"]]
+ """Action name"""
+
+ servers_count: Required[int]
+ """Requested servers count"""
+
+
+GPUVirtualClusterActionParams: TypeAlias = Union[
+ StartVirtualGPUClusterSerializer,
+ StopVirtualGPUClusterSerializer,
+ SoftRebootVirtualGPUClusterSerializer,
+ HardRebootVirtualGPUClusterSerializer,
+ UpdateTagsGPUClusterSerializer,
+ ResizeVirtualGPUClusterSerializer,
+]
diff --git a/src/gcore/types/cloud/gpu_virtual_cluster_create_params.py b/src/gcore/types/cloud/gpu_virtual_cluster_create_params.py
new file mode 100644
index 00000000..acf172b3
--- /dev/null
+++ b/src/gcore/types/cloud/gpu_virtual_cluster_create_params.py
@@ -0,0 +1,213 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Dict, Union, Iterable
+from typing_extensions import Literal, Required, TypeAlias, TypedDict
+
+__all__ = [
+ "GPUVirtualClusterCreateParams",
+ "ServersSettings",
+ "ServersSettingsInterface",
+ "ServersSettingsInterfaceExternalInterfaceInputSerializer",
+ "ServersSettingsInterfaceSubnetInterfaceInputSerializer",
+ "ServersSettingsInterfaceSubnetInterfaceInputSerializerFloatingIP",
+ "ServersSettingsInterfaceAnySubnetInterfaceInputSerializer",
+ "ServersSettingsInterfaceAnySubnetInterfaceInputSerializerFloatingIP",
+ "ServersSettingsVolume",
+ "ServersSettingsVolumeNewVolumeInputSerializer",
+ "ServersSettingsVolumeImageVolumeInputSerializer",
+ "ServersSettingsCredentials",
+ "ServersSettingsFileShare",
+ "ServersSettingsSecurityGroup",
+]
+
+
+class GPUVirtualClusterCreateParams(TypedDict, total=False):
+ project_id: int
+ """Project ID"""
+
+ region_id: int
+ """Region ID"""
+
+ flavor: Required[str]
+ """Cluster flavor ID"""
+
+ name: Required[str]
+ """Cluster name"""
+
+ servers_count: Required[int]
+ """Number of servers in the cluster"""
+
+ servers_settings: Required[ServersSettings]
+ """Configuration settings for the servers in the cluster"""
+
+ 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
+ efficient filtering and grouping for better organization and management. Some
+ tags are read-only and cannot be modified by the user. Tags are also integrated
+ with cost reports, allowing cost data to be filtered based on tag keys or
+ values.
+ """
+
+
+class ServersSettingsInterfaceExternalInterfaceInputSerializer(TypedDict, total=False):
+ type: Required[Literal["external"]]
+
+ ip_family: Literal["dual", "ipv4", "ipv6"]
+ """Which subnets should be selected: IPv4, IPv6, or use dual stack."""
+
+ name: str
+ """Interface name"""
+
+
+class ServersSettingsInterfaceSubnetInterfaceInputSerializerFloatingIP(TypedDict, total=False):
+ source: Required[Literal["new"]]
+
+
+class ServersSettingsInterfaceSubnetInterfaceInputSerializer(TypedDict, total=False):
+ network_id: Required[str]
+ """Network ID the subnet belongs to. Port will be plugged in this network"""
+
+ subnet_id: Required[str]
+ """Port is assigned an IP address from this subnet"""
+
+ type: Required[Literal["subnet"]]
+
+ floating_ip: ServersSettingsInterfaceSubnetInterfaceInputSerializerFloatingIP
+ """Floating IP config for this subnet attachment"""
+
+ name: str
+ """Interface name"""
+
+
+class ServersSettingsInterfaceAnySubnetInterfaceInputSerializerFloatingIP(TypedDict, total=False):
+ source: Required[Literal["new"]]
+
+
+class ServersSettingsInterfaceAnySubnetInterfaceInputSerializer(TypedDict, total=False):
+ network_id: Required[str]
+ """Network ID the subnet belongs to. Port will be plugged in this network"""
+
+ type: Required[Literal["any_subnet"]]
+
+ floating_ip: ServersSettingsInterfaceAnySubnetInterfaceInputSerializerFloatingIP
+ """Floating IP config for this subnet attachment"""
+
+ ip_family: Literal["dual", "ipv4", "ipv6"]
+ """Which subnets should be selected: IPv4, IPv6, or use dual stack"""
+
+ name: str
+ """Interface name"""
+
+
+ServersSettingsInterface: TypeAlias = Union[
+ ServersSettingsInterfaceExternalInterfaceInputSerializer,
+ ServersSettingsInterfaceSubnetInterfaceInputSerializer,
+ ServersSettingsInterfaceAnySubnetInterfaceInputSerializer,
+]
+
+
+class ServersSettingsVolumeNewVolumeInputSerializer(TypedDict, total=False):
+ boot_index: Required[int]
+ """Boot index of the volume"""
+
+ name: Required[str]
+ """Volume name"""
+
+ size: Required[int]
+ """Volume size in GiB"""
+
+ source: Required[Literal["new"]]
+
+ type: Required[Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"]]
+ """Volume type"""
+
+ delete_on_termination: bool
+ """Flag indicating whether the volume is deleted on instance termination"""
+
+ tags: Dict[str, str]
+ """Tags associated with the volume"""
+
+
+class ServersSettingsVolumeImageVolumeInputSerializer(TypedDict, total=False):
+ boot_index: Required[int]
+ """Boot index of the volume"""
+
+ image_id: Required[str]
+ """Image ID for the volume"""
+
+ name: Required[str]
+ """Volume name"""
+
+ size: Required[int]
+ """Volume size in GiB"""
+
+ source: Required[Literal["image"]]
+
+ type: Required[Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"]]
+ """Volume type"""
+
+ delete_on_termination: bool
+ """Flag indicating whether the volume is deleted on instance termination"""
+
+ tags: Dict[str, str]
+ """Tags associated with the volume"""
+
+
+ServersSettingsVolume: TypeAlias = Union[
+ ServersSettingsVolumeNewVolumeInputSerializer, ServersSettingsVolumeImageVolumeInputSerializer
+]
+
+
+class ServersSettingsCredentials(TypedDict, total=False):
+ password: str
+ """Used to set the password for the specified 'username' on Linux instances.
+
+ If 'username' is not provided, the password is applied to the default user of
+ the image. Mutually exclusive with '`user_data`' - only one can be specified.
+ """
+
+ 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).
+ """
+
+ username: str
+ """The 'username' and 'password' fields create a new user on the system"""
+
+
+class ServersSettingsFileShare(TypedDict, total=False):
+ id: Required[str]
+ """Unique identifier of the file share in UUID format."""
+
+ mount_path: Required[str]
+ """Absolute mount path inside the system where the file share will be mounted."""
+
+
+class ServersSettingsSecurityGroup(TypedDict, total=False):
+ id: Required[str]
+ """Resource ID"""
+
+
+class ServersSettings(TypedDict, total=False):
+ interfaces: Required[Iterable[ServersSettingsInterface]]
+ """Subnet IPs and floating IPs"""
+
+ volumes: Required[Iterable[ServersSettingsVolume]]
+ """List of volumes"""
+
+ credentials: ServersSettingsCredentials
+ """Optional server access credentials"""
+
+ file_shares: Iterable[ServersSettingsFileShare]
+ """List of file shares to be mounted across the cluster."""
+
+ security_groups: Iterable[ServersSettingsSecurityGroup]
+ """List of security groups UUIDs"""
+
+ user_data: str
+ """Optional custom user data (Base64-encoded)"""
diff --git a/src/gcore/types/cloud/gpu_virtual_cluster_delete_params.py b/src/gcore/types/cloud/gpu_virtual_cluster_delete_params.py
new file mode 100644
index 00000000..3cd9988b
--- /dev/null
+++ b/src/gcore/types/cloud/gpu_virtual_cluster_delete_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
+
+from ..._types import SequenceNotStr
+
+__all__ = ["GPUVirtualClusterDeleteParams"]
+
+
+class GPUVirtualClusterDeleteParams(TypedDict, total=False):
+ project_id: int
+ """Project ID"""
+
+ region_id: int
+ """Region ID"""
+
+ all_floating_ips: bool
+ """
+ Flag indicating whether the floating ips associated with server / cluster are
+ deleted
+ """
+
+ all_reserved_fixed_ips: bool
+ """
+ Flag indicating whether the reserved fixed ips associated with server / cluster
+ are deleted
+ """
+
+ all_volumes: bool
+ """Flag indicating whether all attached volumes are deleted"""
+
+ floating_ip_ids: SequenceNotStr[str]
+ """Optional list of floating ips to be deleted"""
+
+ reserved_fixed_ip_ids: SequenceNotStr[str]
+ """Optional list of reserved fixed ips to be deleted"""
+
+ volume_ids: SequenceNotStr[str]
+ """Optional list of volumes to be deleted"""
diff --git a/src/gcore/types/cloud/gpu_virtual_cluster_list_params.py b/src/gcore/types/cloud/gpu_virtual_cluster_list_params.py
new file mode 100644
index 00000000..ff0dba49
--- /dev/null
+++ b/src/gcore/types/cloud/gpu_virtual_cluster_list_params.py
@@ -0,0 +1,21 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import TypedDict
+
+__all__ = ["GPUVirtualClusterListParams"]
+
+
+class GPUVirtualClusterListParams(TypedDict, total=False):
+ project_id: int
+ """Project ID"""
+
+ region_id: int
+ """Region ID"""
+
+ limit: int
+ """Limit of items on a single page"""
+
+ offset: int
+ """Offset in results list"""
diff --git a/src/gcore/types/cloud/gpu_virtual_cluster_update_params.py b/src/gcore/types/cloud/gpu_virtual_cluster_update_params.py
new file mode 100644
index 00000000..790bbf88
--- /dev/null
+++ b/src/gcore/types/cloud/gpu_virtual_cluster_update_params.py
@@ -0,0 +1,18 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, TypedDict
+
+__all__ = ["GPUVirtualClusterUpdateParams"]
+
+
+class GPUVirtualClusterUpdateParams(TypedDict, total=False):
+ project_id: int
+ """Project ID"""
+
+ region_id: int
+ """Region ID"""
+
+ name: Required[str]
+ """Cluster name"""
diff --git a/src/gcore/types/cloud/gpu_virtual_clusters/__init__.py b/src/gcore/types/cloud/gpu_virtual_clusters/__init__.py
new file mode 100644
index 00000000..df222501
--- /dev/null
+++ b/src/gcore/types/cloud/gpu_virtual_clusters/__init__.py
@@ -0,0 +1,16 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from .flavor_list_params import FlavorListParams as FlavorListParams
+from .gpu_virtual_flavor import GPUVirtualFlavor as GPUVirtualFlavor
+from .server_list_params import ServerListParams as ServerListParams
+from .image_upload_params import ImageUploadParams as ImageUploadParams
+from .server_delete_params import ServerDeleteParams as ServerDeleteParams
+from .gpu_virtual_interface import GPUVirtualInterface as GPUVirtualInterface
+from .gpu_virtual_flavor_list import GPUVirtualFlavorList as GPUVirtualFlavorList
+from .gpu_virtual_cluster_server import GPUVirtualClusterServer as GPUVirtualClusterServer
+from .gpu_virtual_cluster_volume import GPUVirtualClusterVolume as GPUVirtualClusterVolume
+from .gpu_virtual_interface_list import GPUVirtualInterfaceList as GPUVirtualInterfaceList
+from .gpu_virtual_cluster_server_list import GPUVirtualClusterServerList as GPUVirtualClusterServerList
+from .gpu_virtual_cluster_volume_list import GPUVirtualClusterVolumeList as GPUVirtualClusterVolumeList
diff --git a/src/gcore/types/cloud/gpu_virtual_clusters/flavor_list_params.py b/src/gcore/types/cloud/gpu_virtual_clusters/flavor_list_params.py
new file mode 100644
index 00000000..febeb592
--- /dev/null
+++ b/src/gcore/types/cloud/gpu_virtual_clusters/flavor_list_params.py
@@ -0,0 +1,21 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import TypedDict
+
+__all__ = ["FlavorListParams"]
+
+
+class FlavorListParams(TypedDict, total=False):
+ project_id: int
+ """Project ID"""
+
+ region_id: int
+ """Region ID"""
+
+ hide_disabled: bool
+ """Set to `true` to remove the disabled flavors from the response."""
+
+ include_prices: bool
+ """Set to `true` if the response should include flavor prices."""
diff --git a/src/gcore/types/cloud/gpu_virtual_clusters/gpu_virtual_cluster_server.py b/src/gcore/types/cloud/gpu_virtual_clusters/gpu_virtual_cluster_server.py
new file mode 100644
index 00000000..b1b8b52f
--- /dev/null
+++ b/src/gcore/types/cloud/gpu_virtual_clusters/gpu_virtual_cluster_server.py
@@ -0,0 +1,77 @@
+# 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 Literal
+
+from ..tag import Tag
+from ...._models import BaseModel
+
+__all__ = ["GPUVirtualClusterServer", "SecurityGroup"]
+
+
+class SecurityGroup(BaseModel):
+ id: str
+ """Security group ID"""
+
+ name: str
+ """Security group name"""
+
+
+class GPUVirtualClusterServer(BaseModel):
+ id: str
+ """Server unique identifier"""
+
+ created_at: datetime
+ """Server creation date and time"""
+
+ flavor: str
+ """Unique flavor identifier"""
+
+ image_id: Optional[str] = None
+ """Server's image UUID"""
+
+ ip_addresses: List[str]
+ """List of IP addresses"""
+
+ name: str
+ """Server's name generated using cluster's name"""
+
+ security_groups: List[SecurityGroup]
+ """Security groups"""
+
+ ssh_key_name: Optional[str] = None
+ """SSH key pair assigned to the server"""
+
+ status: Literal[
+ "ACTIVE",
+ "BUILD",
+ "DELETED",
+ "ERROR",
+ "HARD_REBOOT",
+ "MIGRATING",
+ "PASSWORD",
+ "PAUSED",
+ "REBOOT",
+ "REBUILD",
+ "RESCUE",
+ "RESIZE",
+ "REVERT_RESIZE",
+ "SHELVED",
+ "SHELVED_OFFLOADED",
+ "SHUTOFF",
+ "SOFT_DELETED",
+ "SUSPENDED",
+ "UNKNOWN",
+ "VERIFY_RESIZE",
+ ]
+ """Current server status"""
+
+ tags: List[Tag]
+ """User defined tags"""
+
+ task_id: Optional[str] = None
+ """Identifier of the task currently modifying the GPU cluster"""
+
+ updated_at: datetime
+ """Server update date and time"""
diff --git a/src/gcore/types/cloud/gpu_virtual_clusters/gpu_virtual_cluster_server_list.py b/src/gcore/types/cloud/gpu_virtual_clusters/gpu_virtual_cluster_server_list.py
new file mode 100644
index 00000000..d9cdad5a
--- /dev/null
+++ b/src/gcore/types/cloud/gpu_virtual_clusters/gpu_virtual_cluster_server_list.py
@@ -0,0 +1,16 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List
+
+from ...._models import BaseModel
+from .gpu_virtual_cluster_server import GPUVirtualClusterServer
+
+__all__ = ["GPUVirtualClusterServerList"]
+
+
+class GPUVirtualClusterServerList(BaseModel):
+ count: int
+ """Number of objects"""
+
+ results: List[GPUVirtualClusterServer]
+ """Objects"""
diff --git a/src/gcore/types/cloud/gpu_virtual_clusters/gpu_virtual_cluster_volume.py b/src/gcore/types/cloud/gpu_virtual_clusters/gpu_virtual_cluster_volume.py
new file mode 100644
index 00000000..06653cde
--- /dev/null
+++ b/src/gcore/types/cloud/gpu_virtual_clusters/gpu_virtual_cluster_volume.py
@@ -0,0 +1,64 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List
+from datetime import datetime
+from typing_extensions import Literal
+
+from ..tag import Tag
+from ...._models import BaseModel
+
+__all__ = ["GPUVirtualClusterVolume"]
+
+
+class GPUVirtualClusterVolume(BaseModel):
+ id: str
+ """Volume unique identifier"""
+
+ bootable: bool
+ """True if this is bootable volume"""
+
+ created_at: datetime
+ """Volume creation date and time"""
+
+ name: str
+ """User defined name"""
+
+ root_fs: bool
+ """True if this volume contains root file system"""
+
+ server_id: str
+ """Server UUID"""
+
+ size: int
+ """Volume size in GiB"""
+
+ status: Literal[
+ "attaching",
+ "available",
+ "awaiting-transfer",
+ "backing-up",
+ "creating",
+ "deleting",
+ "detaching",
+ "downloading",
+ "error",
+ "error_backing-up",
+ "error_deleting",
+ "error_extending",
+ "error_restoring",
+ "extending",
+ "in-use",
+ "maintenance",
+ "reserved",
+ "restoring-backup",
+ "retyping",
+ "reverting",
+ "uploading",
+ ]
+ """Current volume status"""
+
+ tags: List[Tag]
+ """User defined tags"""
+
+ type: str
+ """Volume type"""
diff --git a/src/gcore/types/cloud/gpu_virtual_clusters/gpu_virtual_cluster_volume_list.py b/src/gcore/types/cloud/gpu_virtual_clusters/gpu_virtual_cluster_volume_list.py
new file mode 100644
index 00000000..feb8afbc
--- /dev/null
+++ b/src/gcore/types/cloud/gpu_virtual_clusters/gpu_virtual_cluster_volume_list.py
@@ -0,0 +1,16 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List
+
+from ...._models import BaseModel
+from .gpu_virtual_cluster_volume import GPUVirtualClusterVolume
+
+__all__ = ["GPUVirtualClusterVolumeList"]
+
+
+class GPUVirtualClusterVolumeList(BaseModel):
+ count: int
+ """Number of objects"""
+
+ results: List[GPUVirtualClusterVolume]
+ """Objects"""
diff --git a/src/gcore/types/cloud/gpu_virtual_clusters/gpu_virtual_flavor.py b/src/gcore/types/cloud/gpu_virtual_clusters/gpu_virtual_flavor.py
new file mode 100644
index 00000000..cd90cda1
--- /dev/null
+++ b/src/gcore/types/cloud/gpu_virtual_clusters/gpu_virtual_flavor.py
@@ -0,0 +1,155 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Union, Optional
+from typing_extensions import Literal, TypeAlias
+
+from ...._models import BaseModel
+
+__all__ = [
+ "GPUVirtualFlavor",
+ "GPUVirtualFlavorSerializerWithoutPrice",
+ "GPUVirtualFlavorSerializerWithoutPriceHardwareDescription",
+ "GPUVirtualFlavorSerializerWithoutPriceHardwareProperties",
+ "GPUVirtualFlavorSerializerWithoutPriceSupportedFeatures",
+ "GPUVirtualFlavorSerializerWithPrices",
+ "GPUVirtualFlavorSerializerWithPricesHardwareDescription",
+ "GPUVirtualFlavorSerializerWithPricesHardwareProperties",
+ "GPUVirtualFlavorSerializerWithPricesPrice",
+ "GPUVirtualFlavorSerializerWithPricesSupportedFeatures",
+]
+
+
+class GPUVirtualFlavorSerializerWithoutPriceHardwareDescription(BaseModel):
+ gpu: Optional[str] = None
+ """Human-readable GPU description"""
+
+ local_storage: Optional[int] = None
+ """Local storage capacity in GiB"""
+
+ ram: Optional[int] = None
+ """RAM size in MiB"""
+
+ vcpus: Optional[int] = None
+ """Virtual CPU count"""
+
+
+class GPUVirtualFlavorSerializerWithoutPriceHardwareProperties(BaseModel):
+ gpu_count: Optional[int] = None
+ """The total count of available GPUs."""
+
+ gpu_manufacturer: Optional[str] = None
+ """The manufacturer of the graphics processing GPU"""
+
+ gpu_model: Optional[str] = None
+ """GPU model"""
+
+ nic_eth: Optional[str] = None
+ """The configuration of the Ethernet ports"""
+
+ nic_ib: Optional[str] = None
+ """The configuration of the InfiniBand ports"""
+
+
+class GPUVirtualFlavorSerializerWithoutPriceSupportedFeatures(BaseModel):
+ security_groups: bool
+
+
+class GPUVirtualFlavorSerializerWithoutPrice(BaseModel):
+ architecture: Optional[str] = None
+ """Flavor architecture type"""
+
+ capacity: int
+ """Number of available instances of given flavor"""
+
+ disabled: bool
+ """If the flavor is disabled, new resources cannot be created using this flavor."""
+
+ hardware_description: GPUVirtualFlavorSerializerWithoutPriceHardwareDescription
+ """Additional virtual hardware description"""
+
+ hardware_properties: GPUVirtualFlavorSerializerWithoutPriceHardwareProperties
+ """Additional virtual hardware properties"""
+
+ name: str
+ """Flavor name"""
+
+ supported_features: GPUVirtualFlavorSerializerWithoutPriceSupportedFeatures
+ """Set of enabled features based on the flavor's type and configuration"""
+
+
+class GPUVirtualFlavorSerializerWithPricesHardwareDescription(BaseModel):
+ gpu: Optional[str] = None
+ """Human-readable GPU description"""
+
+ local_storage: Optional[int] = None
+ """Local storage capacity in GiB"""
+
+ ram: Optional[int] = None
+ """RAM size in MiB"""
+
+ vcpus: Optional[int] = None
+ """Virtual CPU count"""
+
+
+class GPUVirtualFlavorSerializerWithPricesHardwareProperties(BaseModel):
+ gpu_count: Optional[int] = None
+ """The total count of available GPUs."""
+
+ gpu_manufacturer: Optional[str] = None
+ """The manufacturer of the graphics processing GPU"""
+
+ gpu_model: Optional[str] = None
+ """GPU model"""
+
+ nic_eth: Optional[str] = None
+ """The configuration of the Ethernet ports"""
+
+ nic_ib: Optional[str] = None
+ """The configuration of the InfiniBand ports"""
+
+
+class GPUVirtualFlavorSerializerWithPricesPrice(BaseModel):
+ currency_code: Optional[str] = None
+ """Currency code. Shown if the `include_prices` query parameter if set to true"""
+
+ price_per_hour: Optional[float] = None
+ """Price per hour. Shown if the `include_prices` query parameter if set to true"""
+
+ price_per_month: Optional[float] = None
+ """Price per month. Shown if the `include_prices` query parameter if set to true"""
+
+ price_status: Optional[Literal["error", "hide", "show"]] = None
+ """Price status for the UI"""
+
+
+class GPUVirtualFlavorSerializerWithPricesSupportedFeatures(BaseModel):
+ security_groups: bool
+
+
+class GPUVirtualFlavorSerializerWithPrices(BaseModel):
+ architecture: Optional[str] = None
+ """Flavor architecture type"""
+
+ capacity: int
+ """Number of available instances of given flavor"""
+
+ disabled: bool
+ """If the flavor is disabled, new resources cannot be created using this flavor."""
+
+ hardware_description: GPUVirtualFlavorSerializerWithPricesHardwareDescription
+ """Additional virtual hardware description"""
+
+ hardware_properties: GPUVirtualFlavorSerializerWithPricesHardwareProperties
+ """Additional virtual hardware properties"""
+
+ name: str
+ """Flavor name"""
+
+ price: GPUVirtualFlavorSerializerWithPricesPrice
+ """Flavor price."""
+
+ supported_features: GPUVirtualFlavorSerializerWithPricesSupportedFeatures
+ """Set of enabled features based on the flavor's type and configuration"""
+
+
+GPUVirtualFlavor: TypeAlias = Union[GPUVirtualFlavorSerializerWithoutPrice, GPUVirtualFlavorSerializerWithPrices]
diff --git a/src/gcore/types/cloud/gpu_virtual_clusters/gpu_virtual_flavor_list.py b/src/gcore/types/cloud/gpu_virtual_clusters/gpu_virtual_flavor_list.py
new file mode 100644
index 00000000..fdfab090
--- /dev/null
+++ b/src/gcore/types/cloud/gpu_virtual_clusters/gpu_virtual_flavor_list.py
@@ -0,0 +1,16 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List
+
+from ...._models import BaseModel
+from .gpu_virtual_flavor import GPUVirtualFlavor
+
+__all__ = ["GPUVirtualFlavorList"]
+
+
+class GPUVirtualFlavorList(BaseModel):
+ count: int
+ """Number of objects"""
+
+ results: List[GPUVirtualFlavor]
+ """Objects"""
diff --git a/src/gcore/types/cloud/gpu_virtual_clusters/gpu_virtual_interface.py b/src/gcore/types/cloud/gpu_virtual_clusters/gpu_virtual_interface.py
new file mode 100644
index 00000000..fbac34d7
--- /dev/null
+++ b/src/gcore/types/cloud/gpu_virtual_clusters/gpu_virtual_interface.py
@@ -0,0 +1,190 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from datetime import datetime
+
+from ..tag import Tag
+from ..route import Route
+from ...._models import BaseModel
+from ..ip_version import IPVersion
+from ..floating_ip_status import FloatingIPStatus
+
+__all__ = ["GPUVirtualInterface", "FloatingIP", "IPAssignment", "Network", "NetworkSubnet"]
+
+
+class FloatingIP(BaseModel):
+ id: str
+ """Floating IP ID"""
+
+ created_at: datetime
+ """Datetime when the floating IP was created"""
+
+ fixed_ip_address: Optional[str] = None
+ """IP address of the port the floating IP is attached to"""
+
+ floating_ip_address: Optional[str] = None
+ """IP Address of the floating IP"""
+
+ port_id: Optional[str] = None
+ """Port ID the floating IP is attached to.
+
+ The `fixed_ip_address` is the IP address of the port.
+ """
+
+ router_id: Optional[str] = None
+ """Router ID"""
+
+ status: Optional[FloatingIPStatus] = None
+ """Floating IP status"""
+
+ tags: List[Tag]
+ """List of key-value tags associated with the resource.
+
+ A tag is a key-value pair that can be associated with a resource, enabling
+ efficient filtering and grouping for better organization and management. Some
+ tags are read-only and cannot be modified by the user. Tags are also integrated
+ with cost reports, allowing cost data to be filtered based on tag keys or
+ values.
+ """
+
+ updated_at: datetime
+ """Datetime when the floating IP was last updated"""
+
+
+class IPAssignment(BaseModel):
+ ip_address: str
+ """The IP address assigned to the port from the specified subnet"""
+
+ subnet_id: str
+ """ID of the subnet that allocated the IP"""
+
+
+class NetworkSubnet(BaseModel):
+ id: str
+ """Subnet id."""
+
+ available_ips: Optional[int] = None
+ """Number of available ips in subnet"""
+
+ cidr: str
+ """CIDR"""
+
+ created_at: datetime
+ """Datetime when the subnet was created"""
+
+ dns_nameservers: Optional[List[str]] = None
+ """List IP addresses of a DNS resolver reachable from the network"""
+
+ enable_dhcp: bool
+ """Indicates whether DHCP is enabled for this subnet.
+
+ If true, IP addresses will be assigned automatically
+ """
+
+ gateway_ip: Optional[str] = None
+ """Default GW IPv4 address, advertised in DHCP routes of this subnet.
+
+ If null, no gateway is advertised by this subnet.
+ """
+
+ has_router: bool
+ """Deprecated. Always returns `false`."""
+
+ host_routes: Optional[List[Route]] = None
+ """List of custom static routes to advertise via DHCP."""
+
+ ip_version: IPVersion
+ """IP version used by the subnet (IPv4 or IPv6)"""
+
+ name: str
+ """Subnet name"""
+
+ network_id: str
+ """Network ID"""
+
+ tags: List[Tag]
+ """List of key-value tags associated with the resource.
+
+ A tag is a key-value pair that can be associated with a resource, enabling
+ efficient filtering and grouping for better organization and management. Some
+ tags are read-only and cannot be modified by the user. Tags are also integrated
+ with cost reports, allowing cost data to be filtered based on tag keys or
+ values.
+ """
+
+ total_ips: Optional[int] = None
+ """Total number of ips in subnet"""
+
+ updated_at: datetime
+ """Datetime when the subnet was last updated"""
+
+
+class Network(BaseModel):
+ id: str
+ """Network ID"""
+
+ created_at: datetime
+ """Datetime when the network was created"""
+
+ external: bool
+ """True if the network `router:external` attribute"""
+
+ mtu: int
+ """MTU (maximum transmission unit)"""
+
+ name: str
+ """Network name"""
+
+ port_security_enabled: bool
+ """
+ Indicates `port_security_enabled` status of all newly created in the network
+ ports.
+ """
+
+ segmentation_id: Optional[int] = None
+ """Id of network segment"""
+
+ shared: bool
+ """True when the network is shared with your project by external owner"""
+
+ subnets: Optional[List[NetworkSubnet]] = None
+ """List of subnetworks"""
+
+ tags: List[Tag]
+ """List of key-value tags associated with the resource.
+
+ A tag is a key-value pair that can be associated with a resource, enabling
+ efficient filtering and grouping for better organization and management. Some
+ tags are read-only and cannot be modified by the user. Tags are also integrated
+ with cost reports, allowing cost data to be filtered based on tag keys or
+ values.
+ """
+
+ type: str
+ """Network type (vlan, vxlan)"""
+
+ updated_at: datetime
+ """Datetime when the network was last updated"""
+
+
+class GPUVirtualInterface(BaseModel):
+ floating_ips: List[FloatingIP]
+ """Bodies of floatingips that are NAT-ing ips of this port"""
+
+ ip_assignments: List[IPAssignment]
+ """IP addresses assigned to this port"""
+
+ mac_address: Optional[str] = None
+ """MAC address of the virtual port"""
+
+ network: Network
+ """Body of the network this port is attached to"""
+
+ network_id: str
+ """ID of the network the port is attached to"""
+
+ port_id: str
+ """ID of virtual ethernet port object"""
+
+ port_security_enabled: bool
+ """Port security status"""
diff --git a/src/gcore/types/cloud/gpu_virtual_clusters/gpu_virtual_interface_list.py b/src/gcore/types/cloud/gpu_virtual_clusters/gpu_virtual_interface_list.py
new file mode 100644
index 00000000..ae39f4cf
--- /dev/null
+++ b/src/gcore/types/cloud/gpu_virtual_clusters/gpu_virtual_interface_list.py
@@ -0,0 +1,16 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List
+
+from ...._models import BaseModel
+from .gpu_virtual_interface import GPUVirtualInterface
+
+__all__ = ["GPUVirtualInterfaceList"]
+
+
+class GPUVirtualInterfaceList(BaseModel):
+ count: int
+ """Number of objects"""
+
+ results: List[GPUVirtualInterface]
+ """Objects"""
diff --git a/src/gcore/types/cloud/gpu_virtual_clusters/image_upload_params.py b/src/gcore/types/cloud/gpu_virtual_clusters/image_upload_params.py
new file mode 100644
index 00000000..c83f5687
--- /dev/null
+++ b/src/gcore/types/cloud/gpu_virtual_clusters/image_upload_params.py
@@ -0,0 +1,56 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Dict, Optional
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["ImageUploadParams"]
+
+
+class ImageUploadParams(TypedDict, total=False):
+ project_id: int
+ """Project ID"""
+
+ region_id: int
+ """Region ID"""
+
+ name: Required[str]
+ """Image name"""
+
+ url: Required[str]
+ """Image URL"""
+
+ architecture: Optional[Literal["aarch64", "x86_64"]]
+ """Image architecture type: aarch64, `x86_64`"""
+
+ cow_format: bool
+ """
+ When True, image cannot be deleted unless all volumes, created from it, are
+ deleted.
+ """
+
+ hw_firmware_type: Optional[Literal["bios", "uefi"]]
+ """Specifies the type of firmware with which to boot the guest."""
+
+ os_distro: Optional[str]
+ """OS Distribution, i.e. Debian, CentOS, Ubuntu, CoreOS etc."""
+
+ os_type: Optional[Literal["linux", "windows"]]
+ """The operating system installed on the image. Linux by default"""
+
+ os_version: Optional[str]
+ """OS version, i.e. 19.04 (for Ubuntu) or 9.4 for Debian"""
+
+ ssh_key: Literal["allow", "deny", "required"]
+ """Permission to use a ssh key in instances"""
+
+ 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
+ efficient filtering and grouping for better organization and management. Some
+ tags are read-only and cannot be modified by the user. Tags are also integrated
+ with cost reports, allowing cost data to be filtered based on tag keys or
+ values.
+ """
diff --git a/src/gcore/types/cloud/gpu_virtual_clusters/server_delete_params.py b/src/gcore/types/cloud/gpu_virtual_clusters/server_delete_params.py
new file mode 100644
index 00000000..714cb4bb
--- /dev/null
+++ b/src/gcore/types/cloud/gpu_virtual_clusters/server_delete_params.py
@@ -0,0 +1,44 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, TypedDict
+
+from ...._types import SequenceNotStr
+
+__all__ = ["ServerDeleteParams"]
+
+
+class ServerDeleteParams(TypedDict, total=False):
+ project_id: int
+ """Project ID"""
+
+ region_id: int
+ """Region ID"""
+
+ cluster_id: Required[str]
+ """Cluster unique identifier"""
+
+ all_floating_ips: bool
+ """
+ Flag indicating whether the floating ips associated with server / cluster are
+ deleted
+ """
+
+ all_reserved_fixed_ips: bool
+ """
+ Flag indicating whether the reserved fixed ips associated with server / cluster
+ are deleted
+ """
+
+ all_volumes: bool
+ """Flag indicating whether all attached volumes are deleted"""
+
+ floating_ip_ids: SequenceNotStr[str]
+ """Optional list of floating ips to be deleted"""
+
+ reserved_fixed_ip_ids: SequenceNotStr[str]
+ """Optional list of reserved fixed ips to be deleted"""
+
+ volume_ids: SequenceNotStr[str]
+ """Optional list of volumes to be deleted"""
diff --git a/src/gcore/types/cloud/gpu_virtual_clusters/server_list_params.py b/src/gcore/types/cloud/gpu_virtual_clusters/server_list_params.py
new file mode 100644
index 00000000..35c7f374
--- /dev/null
+++ b/src/gcore/types/cloud/gpu_virtual_clusters/server_list_params.py
@@ -0,0 +1,75 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from datetime import datetime
+from typing_extensions import Literal, Annotated, TypedDict
+
+from ...._types import SequenceNotStr
+from ...._utils import PropertyInfo
+
+__all__ = ["ServerListParams"]
+
+
+class ServerListParams(TypedDict, total=False):
+ project_id: int
+ """Project ID"""
+
+ region_id: int
+ """Region ID"""
+
+ changed_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]
+ """
+ Filters the results to include only servers whose last change timestamp is less
+ than the specified datetime. Format: ISO 8601.
+ """
+
+ changed_since: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]
+ """
+ Filters the results to include only servers whose last change timestamp is
+ greater than or equal to the specified datetime. Format: ISO 8601.
+ """
+
+ ip_address: str
+ """Filter servers by ip address."""
+
+ limit: int
+ """Limit of items on a single page"""
+
+ name: str
+ """Filter servers by name.
+
+ You can provide a full or partial name, servers with matching names will be
+ returned. For example, entering 'test' will return all servers that contain
+ 'test' in their name.
+ """
+
+ offset: int
+ """Offset in results list"""
+
+ order_by: Literal["created_at.asc", "created_at.desc", "status.asc", "status.desc"]
+ """Order field"""
+
+ status: Literal[
+ "ACTIVE",
+ "BUILD",
+ "ERROR",
+ "HARD_REBOOT",
+ "MIGRATING",
+ "PAUSED",
+ "REBOOT",
+ "REBUILD",
+ "RESIZE",
+ "REVERT_RESIZE",
+ "SHELVED",
+ "SHELVED_OFFLOADED",
+ "SHUTOFF",
+ "SOFT_DELETED",
+ "SUSPENDED",
+ "VERIFY_RESIZE",
+ ]
+ """Filters servers by status."""
+
+ uuids: SequenceNotStr[str]
+ """Filter servers by uuid."""
diff --git a/tests/api_resources/cloud/gpu_virtual_clusters/__init__.py b/tests/api_resources/cloud/gpu_virtual_clusters/__init__.py
new file mode 100644
index 00000000..fd8019a9
--- /dev/null
+++ b/tests/api_resources/cloud/gpu_virtual_clusters/__init__.py
@@ -0,0 +1 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
diff --git a/tests/api_resources/cloud/gpu_virtual_clusters/test_flavors.py b/tests/api_resources/cloud/gpu_virtual_clusters/test_flavors.py
new file mode 100644
index 00000000..89b949ed
--- /dev/null
+++ b/tests/api_resources/cloud/gpu_virtual_clusters/test_flavors.py
@@ -0,0 +1,112 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import os
+from typing import Any, cast
+
+import pytest
+
+from gcore import Gcore, AsyncGcore
+from tests.utils import assert_matches_type
+from gcore.types.cloud.gpu_virtual_clusters import GPUVirtualFlavorList
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestFlavors:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_list(self, client: Gcore) -> None:
+ flavor = client.cloud.gpu_virtual_clusters.flavors.list(
+ project_id=1,
+ region_id=7,
+ )
+ assert_matches_type(GPUVirtualFlavorList, flavor, path=["response"])
+
+ @parametrize
+ def test_method_list_with_all_params(self, client: Gcore) -> None:
+ flavor = client.cloud.gpu_virtual_clusters.flavors.list(
+ project_id=1,
+ region_id=7,
+ hide_disabled=True,
+ include_prices=True,
+ )
+ assert_matches_type(GPUVirtualFlavorList, flavor, path=["response"])
+
+ @parametrize
+ def test_raw_response_list(self, client: Gcore) -> None:
+ response = client.cloud.gpu_virtual_clusters.flavors.with_raw_response.list(
+ project_id=1,
+ region_id=7,
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ flavor = response.parse()
+ assert_matches_type(GPUVirtualFlavorList, flavor, path=["response"])
+
+ @parametrize
+ def test_streaming_response_list(self, client: Gcore) -> None:
+ with client.cloud.gpu_virtual_clusters.flavors.with_streaming_response.list(
+ project_id=1,
+ region_id=7,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ flavor = response.parse()
+ assert_matches_type(GPUVirtualFlavorList, flavor, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+
+class TestAsyncFlavors:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_list(self, async_client: AsyncGcore) -> None:
+ flavor = await async_client.cloud.gpu_virtual_clusters.flavors.list(
+ project_id=1,
+ region_id=7,
+ )
+ assert_matches_type(GPUVirtualFlavorList, flavor, path=["response"])
+
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None:
+ flavor = await async_client.cloud.gpu_virtual_clusters.flavors.list(
+ project_id=1,
+ region_id=7,
+ hide_disabled=True,
+ include_prices=True,
+ )
+ assert_matches_type(GPUVirtualFlavorList, flavor, path=["response"])
+
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncGcore) -> None:
+ response = await async_client.cloud.gpu_virtual_clusters.flavors.with_raw_response.list(
+ project_id=1,
+ region_id=7,
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ flavor = await response.parse()
+ assert_matches_type(GPUVirtualFlavorList, flavor, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncGcore) -> None:
+ async with async_client.cloud.gpu_virtual_clusters.flavors.with_streaming_response.list(
+ project_id=1,
+ region_id=7,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ flavor = await response.parse()
+ assert_matches_type(GPUVirtualFlavorList, flavor, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/cloud/gpu_virtual_clusters/test_images.py b/tests/api_resources/cloud/gpu_virtual_clusters/test_images.py
new file mode 100644
index 00000000..7312ccb7
--- /dev/null
+++ b/tests/api_resources/cloud/gpu_virtual_clusters/test_images.py
@@ -0,0 +1,392 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import os
+from typing import Any, cast
+
+import pytest
+
+from gcore import Gcore, AsyncGcore
+from tests.utils import assert_matches_type
+from gcore.types.cloud import GPUImage, TaskIDList, GPUImageList
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestImages:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_list(self, client: Gcore) -> None:
+ image = client.cloud.gpu_virtual_clusters.images.list(
+ project_id=1,
+ region_id=7,
+ )
+ assert_matches_type(GPUImageList, image, path=["response"])
+
+ @parametrize
+ def test_raw_response_list(self, client: Gcore) -> None:
+ response = client.cloud.gpu_virtual_clusters.images.with_raw_response.list(
+ project_id=1,
+ region_id=7,
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ image = response.parse()
+ assert_matches_type(GPUImageList, image, path=["response"])
+
+ @parametrize
+ def test_streaming_response_list(self, client: Gcore) -> None:
+ with client.cloud.gpu_virtual_clusters.images.with_streaming_response.list(
+ project_id=1,
+ region_id=7,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ image = response.parse()
+ assert_matches_type(GPUImageList, image, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_method_delete(self, client: Gcore) -> None:
+ image = client.cloud.gpu_virtual_clusters.images.delete(
+ image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6",
+ project_id=1,
+ region_id=7,
+ )
+ assert_matches_type(TaskIDList, image, path=["response"])
+
+ @parametrize
+ def test_raw_response_delete(self, client: Gcore) -> None:
+ response = client.cloud.gpu_virtual_clusters.images.with_raw_response.delete(
+ image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6",
+ project_id=1,
+ region_id=7,
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ image = response.parse()
+ assert_matches_type(TaskIDList, image, path=["response"])
+
+ @parametrize
+ def test_streaming_response_delete(self, client: Gcore) -> None:
+ with client.cloud.gpu_virtual_clusters.images.with_streaming_response.delete(
+ image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6",
+ project_id=1,
+ region_id=7,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ image = response.parse()
+ assert_matches_type(TaskIDList, image, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_delete(self, client: Gcore) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `image_id` but received ''"):
+ client.cloud.gpu_virtual_clusters.images.with_raw_response.delete(
+ image_id="",
+ project_id=1,
+ region_id=7,
+ )
+
+ @parametrize
+ def test_method_get(self, client: Gcore) -> None:
+ image = client.cloud.gpu_virtual_clusters.images.get(
+ image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6",
+ project_id=1,
+ region_id=7,
+ )
+ assert_matches_type(GPUImage, image, path=["response"])
+
+ @parametrize
+ def test_raw_response_get(self, client: Gcore) -> None:
+ response = client.cloud.gpu_virtual_clusters.images.with_raw_response.get(
+ image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6",
+ project_id=1,
+ region_id=7,
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ image = response.parse()
+ assert_matches_type(GPUImage, image, path=["response"])
+
+ @parametrize
+ def test_streaming_response_get(self, client: Gcore) -> None:
+ with client.cloud.gpu_virtual_clusters.images.with_streaming_response.get(
+ image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6",
+ project_id=1,
+ region_id=7,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ image = response.parse()
+ assert_matches_type(GPUImage, image, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_get(self, client: Gcore) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `image_id` but received ''"):
+ client.cloud.gpu_virtual_clusters.images.with_raw_response.get(
+ image_id="",
+ project_id=1,
+ region_id=7,
+ )
+
+ @parametrize
+ def test_method_upload(self, client: Gcore) -> None:
+ image = client.cloud.gpu_virtual_clusters.images.upload(
+ project_id=1,
+ region_id=7,
+ name="ubuntu-23.10-x64",
+ url="http://mirror.noris.net/cirros/0.4.0/cirros-0.4.0-x86_64-disk.img",
+ )
+ assert_matches_type(TaskIDList, image, path=["response"])
+
+ @parametrize
+ def test_method_upload_with_all_params(self, client: Gcore) -> None:
+ image = client.cloud.gpu_virtual_clusters.images.upload(
+ project_id=1,
+ region_id=7,
+ name="ubuntu-23.10-x64",
+ url="http://mirror.noris.net/cirros/0.4.0/cirros-0.4.0-x86_64-disk.img",
+ architecture="x86_64",
+ cow_format=True,
+ hw_firmware_type="bios",
+ os_distro="os_distro",
+ os_type="linux",
+ os_version="19.04",
+ ssh_key="allow",
+ tags={"my-tag": "my-tag-value"},
+ )
+ assert_matches_type(TaskIDList, image, path=["response"])
+
+ @parametrize
+ def test_raw_response_upload(self, client: Gcore) -> None:
+ response = client.cloud.gpu_virtual_clusters.images.with_raw_response.upload(
+ project_id=1,
+ region_id=7,
+ name="ubuntu-23.10-x64",
+ url="http://mirror.noris.net/cirros/0.4.0/cirros-0.4.0-x86_64-disk.img",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ image = response.parse()
+ assert_matches_type(TaskIDList, image, path=["response"])
+
+ @parametrize
+ def test_streaming_response_upload(self, client: Gcore) -> None:
+ with client.cloud.gpu_virtual_clusters.images.with_streaming_response.upload(
+ project_id=1,
+ region_id=7,
+ name="ubuntu-23.10-x64",
+ url="http://mirror.noris.net/cirros/0.4.0/cirros-0.4.0-x86_64-disk.img",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ image = response.parse()
+ assert_matches_type(TaskIDList, image, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+
+class TestAsyncImages:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_list(self, async_client: AsyncGcore) -> None:
+ image = await async_client.cloud.gpu_virtual_clusters.images.list(
+ project_id=1,
+ region_id=7,
+ )
+ assert_matches_type(GPUImageList, image, path=["response"])
+
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncGcore) -> None:
+ response = await async_client.cloud.gpu_virtual_clusters.images.with_raw_response.list(
+ project_id=1,
+ region_id=7,
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ image = await response.parse()
+ assert_matches_type(GPUImageList, image, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncGcore) -> None:
+ async with async_client.cloud.gpu_virtual_clusters.images.with_streaming_response.list(
+ project_id=1,
+ region_id=7,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ image = await response.parse()
+ assert_matches_type(GPUImageList, image, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_method_delete(self, async_client: AsyncGcore) -> None:
+ image = await async_client.cloud.gpu_virtual_clusters.images.delete(
+ image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6",
+ project_id=1,
+ region_id=7,
+ )
+ assert_matches_type(TaskIDList, image, path=["response"])
+
+ @parametrize
+ async def test_raw_response_delete(self, async_client: AsyncGcore) -> None:
+ response = await async_client.cloud.gpu_virtual_clusters.images.with_raw_response.delete(
+ image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6",
+ project_id=1,
+ region_id=7,
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ image = await response.parse()
+ assert_matches_type(TaskIDList, image, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None:
+ async with async_client.cloud.gpu_virtual_clusters.images.with_streaming_response.delete(
+ image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6",
+ project_id=1,
+ region_id=7,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ image = await response.parse()
+ assert_matches_type(TaskIDList, image, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_delete(self, async_client: AsyncGcore) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `image_id` but received ''"):
+ await async_client.cloud.gpu_virtual_clusters.images.with_raw_response.delete(
+ image_id="",
+ project_id=1,
+ region_id=7,
+ )
+
+ @parametrize
+ async def test_method_get(self, async_client: AsyncGcore) -> None:
+ image = await async_client.cloud.gpu_virtual_clusters.images.get(
+ image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6",
+ project_id=1,
+ region_id=7,
+ )
+ assert_matches_type(GPUImage, image, path=["response"])
+
+ @parametrize
+ async def test_raw_response_get(self, async_client: AsyncGcore) -> None:
+ response = await async_client.cloud.gpu_virtual_clusters.images.with_raw_response.get(
+ image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6",
+ project_id=1,
+ region_id=7,
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ image = await response.parse()
+ assert_matches_type(GPUImage, image, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_get(self, async_client: AsyncGcore) -> None:
+ async with async_client.cloud.gpu_virtual_clusters.images.with_streaming_response.get(
+ image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6",
+ project_id=1,
+ region_id=7,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ image = await response.parse()
+ assert_matches_type(GPUImage, image, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_get(self, async_client: AsyncGcore) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `image_id` but received ''"):
+ await async_client.cloud.gpu_virtual_clusters.images.with_raw_response.get(
+ image_id="",
+ project_id=1,
+ region_id=7,
+ )
+
+ @parametrize
+ async def test_method_upload(self, async_client: AsyncGcore) -> None:
+ image = await async_client.cloud.gpu_virtual_clusters.images.upload(
+ project_id=1,
+ region_id=7,
+ name="ubuntu-23.10-x64",
+ url="http://mirror.noris.net/cirros/0.4.0/cirros-0.4.0-x86_64-disk.img",
+ )
+ assert_matches_type(TaskIDList, image, path=["response"])
+
+ @parametrize
+ async def test_method_upload_with_all_params(self, async_client: AsyncGcore) -> None:
+ image = await async_client.cloud.gpu_virtual_clusters.images.upload(
+ project_id=1,
+ region_id=7,
+ name="ubuntu-23.10-x64",
+ url="http://mirror.noris.net/cirros/0.4.0/cirros-0.4.0-x86_64-disk.img",
+ architecture="x86_64",
+ cow_format=True,
+ hw_firmware_type="bios",
+ os_distro="os_distro",
+ os_type="linux",
+ os_version="19.04",
+ ssh_key="allow",
+ tags={"my-tag": "my-tag-value"},
+ )
+ assert_matches_type(TaskIDList, image, path=["response"])
+
+ @parametrize
+ async def test_raw_response_upload(self, async_client: AsyncGcore) -> None:
+ response = await async_client.cloud.gpu_virtual_clusters.images.with_raw_response.upload(
+ project_id=1,
+ region_id=7,
+ name="ubuntu-23.10-x64",
+ url="http://mirror.noris.net/cirros/0.4.0/cirros-0.4.0-x86_64-disk.img",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ image = await response.parse()
+ assert_matches_type(TaskIDList, image, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_upload(self, async_client: AsyncGcore) -> None:
+ async with async_client.cloud.gpu_virtual_clusters.images.with_streaming_response.upload(
+ project_id=1,
+ region_id=7,
+ name="ubuntu-23.10-x64",
+ url="http://mirror.noris.net/cirros/0.4.0/cirros-0.4.0-x86_64-disk.img",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ image = await response.parse()
+ assert_matches_type(TaskIDList, image, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/cloud/gpu_virtual_clusters/test_interfaces.py b/tests/api_resources/cloud/gpu_virtual_clusters/test_interfaces.py
new file mode 100644
index 00000000..c36ac28b
--- /dev/null
+++ b/tests/api_resources/cloud/gpu_virtual_clusters/test_interfaces.py
@@ -0,0 +1,116 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import os
+from typing import Any, cast
+
+import pytest
+
+from gcore import Gcore, AsyncGcore
+from tests.utils import assert_matches_type
+from gcore.types.cloud.gpu_virtual_clusters import GPUVirtualInterfaceList
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestInterfaces:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_list(self, client: Gcore) -> None:
+ interface = client.cloud.gpu_virtual_clusters.interfaces.list(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ )
+ assert_matches_type(GPUVirtualInterfaceList, interface, path=["response"])
+
+ @parametrize
+ def test_raw_response_list(self, client: Gcore) -> None:
+ response = client.cloud.gpu_virtual_clusters.interfaces.with_raw_response.list(
+ 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"
+ interface = response.parse()
+ assert_matches_type(GPUVirtualInterfaceList, interface, path=["response"])
+
+ @parametrize
+ def test_streaming_response_list(self, client: Gcore) -> None:
+ with client.cloud.gpu_virtual_clusters.interfaces.with_streaming_response.list(
+ 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"
+
+ interface = response.parse()
+ assert_matches_type(GPUVirtualInterfaceList, interface, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_list(self, client: Gcore) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"):
+ client.cloud.gpu_virtual_clusters.interfaces.with_raw_response.list(
+ cluster_id="",
+ project_id=1,
+ region_id=7,
+ )
+
+
+class TestAsyncInterfaces:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_list(self, async_client: AsyncGcore) -> None:
+ interface = await async_client.cloud.gpu_virtual_clusters.interfaces.list(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ )
+ assert_matches_type(GPUVirtualInterfaceList, interface, path=["response"])
+
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncGcore) -> None:
+ response = await async_client.cloud.gpu_virtual_clusters.interfaces.with_raw_response.list(
+ 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"
+ interface = await response.parse()
+ assert_matches_type(GPUVirtualInterfaceList, interface, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncGcore) -> None:
+ async with async_client.cloud.gpu_virtual_clusters.interfaces.with_streaming_response.list(
+ 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"
+
+ interface = await response.parse()
+ assert_matches_type(GPUVirtualInterfaceList, interface, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_list(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_virtual_clusters.interfaces.with_raw_response.list(
+ cluster_id="",
+ project_id=1,
+ region_id=7,
+ )
diff --git a/tests/api_resources/cloud/gpu_virtual_clusters/test_servers.py b/tests/api_resources/cloud/gpu_virtual_clusters/test_servers.py
new file mode 100644
index 00000000..6e341c99
--- /dev/null
+++ b/tests/api_resources/cloud/gpu_virtual_clusters/test_servers.py
@@ -0,0 +1,302 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import os
+from typing import Any, cast
+
+import pytest
+
+from gcore import Gcore, AsyncGcore
+from tests.utils import assert_matches_type
+from gcore._utils import parse_datetime
+from gcore.types.cloud import TaskIDList
+from gcore.types.cloud.gpu_virtual_clusters import GPUVirtualClusterServerList
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestServers:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_list(self, client: Gcore) -> None:
+ server = client.cloud.gpu_virtual_clusters.servers.list(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ )
+ assert_matches_type(GPUVirtualClusterServerList, server, path=["response"])
+
+ @parametrize
+ def test_method_list_with_all_params(self, client: Gcore) -> None:
+ server = client.cloud.gpu_virtual_clusters.servers.list(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ changed_before=parse_datetime("2025-10-01T12:00:00Z"),
+ changed_since=parse_datetime("2025-10-01T12:00:00Z"),
+ ip_address="237.84.2.178",
+ limit=10,
+ name="name",
+ offset=0,
+ order_by="created_at.asc",
+ status="ACTIVE",
+ uuids=["string"],
+ )
+ assert_matches_type(GPUVirtualClusterServerList, server, path=["response"])
+
+ @parametrize
+ def test_raw_response_list(self, client: Gcore) -> None:
+ response = client.cloud.gpu_virtual_clusters.servers.with_raw_response.list(
+ 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"
+ server = response.parse()
+ assert_matches_type(GPUVirtualClusterServerList, server, path=["response"])
+
+ @parametrize
+ def test_streaming_response_list(self, client: Gcore) -> None:
+ with client.cloud.gpu_virtual_clusters.servers.with_streaming_response.list(
+ 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"
+
+ server = response.parse()
+ assert_matches_type(GPUVirtualClusterServerList, server, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_list(self, client: Gcore) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"):
+ client.cloud.gpu_virtual_clusters.servers.with_raw_response.list(
+ cluster_id="",
+ project_id=1,
+ region_id=7,
+ )
+
+ @parametrize
+ def test_method_delete(self, client: Gcore) -> None:
+ server = client.cloud.gpu_virtual_clusters.servers.delete(
+ 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_method_delete_with_all_params(self, client: Gcore) -> None:
+ server = client.cloud.gpu_virtual_clusters.servers.delete(
+ server_id="f1c1eeb6-1834-48c9-a7b0-daafce64872b",
+ project_id=1,
+ region_id=7,
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ all_floating_ips=True,
+ all_reserved_fixed_ips=True,
+ all_volumes=True,
+ floating_ip_ids=["e4a01208-d6ac-4304-bf86-3028154b070a"],
+ reserved_fixed_ip_ids=["a29b8e1e-08d3-4cec-91fb-06e81e5f46d5"],
+ volume_ids=["1333c684-c3da-4b91-ac9e-a92706aa2824"],
+ )
+ assert_matches_type(TaskIDList, server, path=["response"])
+
+ @parametrize
+ def test_raw_response_delete(self, client: Gcore) -> None:
+ response = client.cloud.gpu_virtual_clusters.servers.with_raw_response.delete(
+ 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_delete(self, client: Gcore) -> None:
+ with client.cloud.gpu_virtual_clusters.servers.with_streaming_response.delete(
+ 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_delete(self, client: Gcore) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"):
+ client.cloud.gpu_virtual_clusters.servers.with_raw_response.delete(
+ 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_virtual_clusters.servers.with_raw_response.delete(
+ server_id="",
+ project_id=1,
+ region_id=7,
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ )
+
+
+class TestAsyncServers:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_list(self, async_client: AsyncGcore) -> None:
+ server = await async_client.cloud.gpu_virtual_clusters.servers.list(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ )
+ assert_matches_type(GPUVirtualClusterServerList, server, path=["response"])
+
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None:
+ server = await async_client.cloud.gpu_virtual_clusters.servers.list(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ changed_before=parse_datetime("2025-10-01T12:00:00Z"),
+ changed_since=parse_datetime("2025-10-01T12:00:00Z"),
+ ip_address="237.84.2.178",
+ limit=10,
+ name="name",
+ offset=0,
+ order_by="created_at.asc",
+ status="ACTIVE",
+ uuids=["string"],
+ )
+ assert_matches_type(GPUVirtualClusterServerList, server, path=["response"])
+
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncGcore) -> None:
+ response = await async_client.cloud.gpu_virtual_clusters.servers.with_raw_response.list(
+ 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"
+ server = await response.parse()
+ assert_matches_type(GPUVirtualClusterServerList, server, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncGcore) -> None:
+ async with async_client.cloud.gpu_virtual_clusters.servers.with_streaming_response.list(
+ 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"
+
+ server = await response.parse()
+ assert_matches_type(GPUVirtualClusterServerList, server, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_list(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_virtual_clusters.servers.with_raw_response.list(
+ cluster_id="",
+ project_id=1,
+ region_id=7,
+ )
+
+ @parametrize
+ async def test_method_delete(self, async_client: AsyncGcore) -> None:
+ server = await async_client.cloud.gpu_virtual_clusters.servers.delete(
+ 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_method_delete_with_all_params(self, async_client: AsyncGcore) -> None:
+ server = await async_client.cloud.gpu_virtual_clusters.servers.delete(
+ server_id="f1c1eeb6-1834-48c9-a7b0-daafce64872b",
+ project_id=1,
+ region_id=7,
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ all_floating_ips=True,
+ all_reserved_fixed_ips=True,
+ all_volumes=True,
+ floating_ip_ids=["e4a01208-d6ac-4304-bf86-3028154b070a"],
+ reserved_fixed_ip_ids=["a29b8e1e-08d3-4cec-91fb-06e81e5f46d5"],
+ volume_ids=["1333c684-c3da-4b91-ac9e-a92706aa2824"],
+ )
+ assert_matches_type(TaskIDList, server, path=["response"])
+
+ @parametrize
+ async def test_raw_response_delete(self, async_client: AsyncGcore) -> None:
+ response = await async_client.cloud.gpu_virtual_clusters.servers.with_raw_response.delete(
+ 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_delete(self, async_client: AsyncGcore) -> None:
+ async with async_client.cloud.gpu_virtual_clusters.servers.with_streaming_response.delete(
+ 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_delete(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_virtual_clusters.servers.with_raw_response.delete(
+ 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_virtual_clusters.servers.with_raw_response.delete(
+ server_id="",
+ project_id=1,
+ region_id=7,
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ )
diff --git a/tests/api_resources/cloud/gpu_virtual_clusters/test_volumes.py b/tests/api_resources/cloud/gpu_virtual_clusters/test_volumes.py
new file mode 100644
index 00000000..294f4466
--- /dev/null
+++ b/tests/api_resources/cloud/gpu_virtual_clusters/test_volumes.py
@@ -0,0 +1,116 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import os
+from typing import Any, cast
+
+import pytest
+
+from gcore import Gcore, AsyncGcore
+from tests.utils import assert_matches_type
+from gcore.types.cloud.gpu_virtual_clusters import GPUVirtualClusterVolumeList
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestVolumes:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_list(self, client: Gcore) -> None:
+ volume = client.cloud.gpu_virtual_clusters.volumes.list(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ )
+ assert_matches_type(GPUVirtualClusterVolumeList, volume, path=["response"])
+
+ @parametrize
+ def test_raw_response_list(self, client: Gcore) -> None:
+ response = client.cloud.gpu_virtual_clusters.volumes.with_raw_response.list(
+ 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"
+ volume = response.parse()
+ assert_matches_type(GPUVirtualClusterVolumeList, volume, path=["response"])
+
+ @parametrize
+ def test_streaming_response_list(self, client: Gcore) -> None:
+ with client.cloud.gpu_virtual_clusters.volumes.with_streaming_response.list(
+ 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"
+
+ volume = response.parse()
+ assert_matches_type(GPUVirtualClusterVolumeList, volume, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_list(self, client: Gcore) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"):
+ client.cloud.gpu_virtual_clusters.volumes.with_raw_response.list(
+ cluster_id="",
+ project_id=1,
+ region_id=7,
+ )
+
+
+class TestAsyncVolumes:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_list(self, async_client: AsyncGcore) -> None:
+ volume = await async_client.cloud.gpu_virtual_clusters.volumes.list(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ )
+ assert_matches_type(GPUVirtualClusterVolumeList, volume, path=["response"])
+
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncGcore) -> None:
+ response = await async_client.cloud.gpu_virtual_clusters.volumes.with_raw_response.list(
+ 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"
+ volume = await response.parse()
+ assert_matches_type(GPUVirtualClusterVolumeList, volume, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncGcore) -> None:
+ async with async_client.cloud.gpu_virtual_clusters.volumes.with_streaming_response.list(
+ 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"
+
+ volume = await response.parse()
+ assert_matches_type(GPUVirtualClusterVolumeList, volume, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_list(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_virtual_clusters.volumes.with_raw_response.list(
+ cluster_id="",
+ project_id=1,
+ region_id=7,
+ )
diff --git a/tests/api_resources/cloud/test_gpu_virtual_clusters.py b/tests/api_resources/cloud/test_gpu_virtual_clusters.py
new file mode 100644
index 00000000..6f3758e5
--- /dev/null
+++ b/tests/api_resources/cloud/test_gpu_virtual_clusters.py
@@ -0,0 +1,1294 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import os
+from typing import Any, cast
+
+import pytest
+
+from gcore import Gcore, AsyncGcore
+from tests.utils import assert_matches_type
+from gcore.pagination import SyncOffsetPage, AsyncOffsetPage
+from gcore.types.cloud import (
+ TaskIDList,
+ GPUVirtualCluster,
+)
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestGPUVirtualClusters:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_create(self, client: Gcore) -> None:
+ gpu_virtual_cluster = client.cloud.gpu_virtual_clusters.create(
+ project_id=1,
+ region_id=7,
+ flavor="g3-ai-32-192-1500-l40s-48-1",
+ name="gpu-cluster-1",
+ servers_count=3,
+ servers_settings={
+ "interfaces": [{"type": "external"}],
+ "volumes": [
+ {
+ "boot_index": 1,
+ "name": "my-data-disk",
+ "size": 100,
+ "source": "new",
+ "type": "cold",
+ }
+ ],
+ },
+ )
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ def test_method_create_with_all_params(self, client: Gcore) -> None:
+ gpu_virtual_cluster = client.cloud.gpu_virtual_clusters.create(
+ project_id=1,
+ region_id=7,
+ flavor="g3-ai-32-192-1500-l40s-48-1",
+ name="gpu-cluster-1",
+ servers_count=3,
+ servers_settings={
+ "interfaces": [
+ {
+ "type": "external",
+ "ip_family": "ipv4",
+ "name": "eth0",
+ }
+ ],
+ "volumes": [
+ {
+ "boot_index": 1,
+ "name": "my-data-disk",
+ "size": 100,
+ "source": "new",
+ "type": "cold",
+ "delete_on_termination": True,
+ "tags": {"key1": "value1"},
+ }
+ ],
+ "credentials": {
+ "password": "securepassword",
+ "ssh_key_name": "my-ssh-key",
+ "username": "admin",
+ },
+ "file_shares": [
+ {
+ "id": "a3f2d1b8-45e6-4f8a-bb5d-19dbf2cd7e9a",
+ "mount_path": "/mnt/vast",
+ }
+ ],
+ "security_groups": [{"id": "b4849ffa-89f2-45a1-951f-0ae5b7809d98"}],
+ "user_data": "eyJ0ZXN0IjogImRhdGEifQ==",
+ },
+ tags={"my-tag": "my-tag-value"},
+ )
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ def test_raw_response_create(self, client: Gcore) -> None:
+ response = client.cloud.gpu_virtual_clusters.with_raw_response.create(
+ project_id=1,
+ region_id=7,
+ flavor="g3-ai-32-192-1500-l40s-48-1",
+ name="gpu-cluster-1",
+ servers_count=3,
+ servers_settings={
+ "interfaces": [{"type": "external"}],
+ "volumes": [
+ {
+ "boot_index": 1,
+ "name": "my-data-disk",
+ "size": 100,
+ "source": "new",
+ "type": "cold",
+ }
+ ],
+ },
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ gpu_virtual_cluster = response.parse()
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ def test_streaming_response_create(self, client: Gcore) -> None:
+ with client.cloud.gpu_virtual_clusters.with_streaming_response.create(
+ project_id=1,
+ region_id=7,
+ flavor="g3-ai-32-192-1500-l40s-48-1",
+ name="gpu-cluster-1",
+ servers_count=3,
+ servers_settings={
+ "interfaces": [{"type": "external"}],
+ "volumes": [
+ {
+ "boot_index": 1,
+ "name": "my-data-disk",
+ "size": 100,
+ "source": "new",
+ "type": "cold",
+ }
+ ],
+ },
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ gpu_virtual_cluster = response.parse()
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_method_update(self, client: Gcore) -> None:
+ gpu_virtual_cluster = client.cloud.gpu_virtual_clusters.update(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ name="gpu-cluster-1",
+ )
+ assert_matches_type(GPUVirtualCluster, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ def test_raw_response_update(self, client: Gcore) -> None:
+ response = client.cloud.gpu_virtual_clusters.with_raw_response.update(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ name="gpu-cluster-1",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ gpu_virtual_cluster = response.parse()
+ assert_matches_type(GPUVirtualCluster, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ def test_streaming_response_update(self, client: Gcore) -> None:
+ with client.cloud.gpu_virtual_clusters.with_streaming_response.update(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ name="gpu-cluster-1",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ gpu_virtual_cluster = response.parse()
+ assert_matches_type(GPUVirtualCluster, gpu_virtual_cluster, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_update(self, client: Gcore) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"):
+ client.cloud.gpu_virtual_clusters.with_raw_response.update(
+ cluster_id="",
+ project_id=1,
+ region_id=7,
+ name="gpu-cluster-1",
+ )
+
+ @parametrize
+ def test_method_list(self, client: Gcore) -> None:
+ gpu_virtual_cluster = client.cloud.gpu_virtual_clusters.list(
+ project_id=1,
+ region_id=7,
+ )
+ assert_matches_type(SyncOffsetPage[GPUVirtualCluster], gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ def test_method_list_with_all_params(self, client: Gcore) -> None:
+ gpu_virtual_cluster = client.cloud.gpu_virtual_clusters.list(
+ project_id=1,
+ region_id=7,
+ limit=10,
+ offset=0,
+ )
+ assert_matches_type(SyncOffsetPage[GPUVirtualCluster], gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ def test_raw_response_list(self, client: Gcore) -> None:
+ response = client.cloud.gpu_virtual_clusters.with_raw_response.list(
+ project_id=1,
+ region_id=7,
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ gpu_virtual_cluster = response.parse()
+ assert_matches_type(SyncOffsetPage[GPUVirtualCluster], gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ def test_streaming_response_list(self, client: Gcore) -> None:
+ with client.cloud.gpu_virtual_clusters.with_streaming_response.list(
+ project_id=1,
+ region_id=7,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ gpu_virtual_cluster = response.parse()
+ assert_matches_type(SyncOffsetPage[GPUVirtualCluster], gpu_virtual_cluster, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_method_delete(self, client: Gcore) -> None:
+ gpu_virtual_cluster = client.cloud.gpu_virtual_clusters.delete(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ )
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ def test_method_delete_with_all_params(self, client: Gcore) -> None:
+ gpu_virtual_cluster = client.cloud.gpu_virtual_clusters.delete(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ all_floating_ips=True,
+ all_reserved_fixed_ips=True,
+ all_volumes=True,
+ floating_ip_ids=["e4a01208-d6ac-4304-bf86-3028154b070a"],
+ reserved_fixed_ip_ids=["a29b8e1e-08d3-4cec-91fb-06e81e5f46d5"],
+ volume_ids=["1333c684-c3da-4b91-ac9e-a92706aa2824"],
+ )
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ def test_raw_response_delete(self, client: Gcore) -> None:
+ response = client.cloud.gpu_virtual_clusters.with_raw_response.delete(
+ 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"
+ gpu_virtual_cluster = response.parse()
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ def test_streaming_response_delete(self, client: Gcore) -> None:
+ with client.cloud.gpu_virtual_clusters.with_streaming_response.delete(
+ 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"
+
+ gpu_virtual_cluster = response.parse()
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_delete(self, client: Gcore) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"):
+ client.cloud.gpu_virtual_clusters.with_raw_response.delete(
+ cluster_id="",
+ project_id=1,
+ region_id=7,
+ )
+
+ @parametrize
+ def test_method_action_overload_1(self, client: Gcore) -> None:
+ gpu_virtual_cluster = client.cloud.gpu_virtual_clusters.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="start",
+ )
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ def test_raw_response_action_overload_1(self, client: Gcore) -> None:
+ response = client.cloud.gpu_virtual_clusters.with_raw_response.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="start",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ gpu_virtual_cluster = response.parse()
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ def test_streaming_response_action_overload_1(self, client: Gcore) -> None:
+ with client.cloud.gpu_virtual_clusters.with_streaming_response.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="start",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ gpu_virtual_cluster = response.parse()
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_action_overload_1(self, client: Gcore) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"):
+ client.cloud.gpu_virtual_clusters.with_raw_response.action(
+ cluster_id="",
+ project_id=1,
+ region_id=7,
+ action="start",
+ )
+
+ @parametrize
+ def test_method_action_overload_2(self, client: Gcore) -> None:
+ gpu_virtual_cluster = client.cloud.gpu_virtual_clusters.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="stop",
+ )
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ def test_raw_response_action_overload_2(self, client: Gcore) -> None:
+ response = client.cloud.gpu_virtual_clusters.with_raw_response.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="stop",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ gpu_virtual_cluster = response.parse()
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ def test_streaming_response_action_overload_2(self, client: Gcore) -> None:
+ with client.cloud.gpu_virtual_clusters.with_streaming_response.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="stop",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ gpu_virtual_cluster = response.parse()
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_action_overload_2(self, client: Gcore) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"):
+ client.cloud.gpu_virtual_clusters.with_raw_response.action(
+ cluster_id="",
+ project_id=1,
+ region_id=7,
+ action="stop",
+ )
+
+ @parametrize
+ def test_method_action_overload_3(self, client: Gcore) -> None:
+ gpu_virtual_cluster = client.cloud.gpu_virtual_clusters.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="soft_reboot",
+ )
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ def test_raw_response_action_overload_3(self, client: Gcore) -> None:
+ response = client.cloud.gpu_virtual_clusters.with_raw_response.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="soft_reboot",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ gpu_virtual_cluster = response.parse()
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ def test_streaming_response_action_overload_3(self, client: Gcore) -> None:
+ with client.cloud.gpu_virtual_clusters.with_streaming_response.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="soft_reboot",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ gpu_virtual_cluster = response.parse()
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_action_overload_3(self, client: Gcore) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"):
+ client.cloud.gpu_virtual_clusters.with_raw_response.action(
+ cluster_id="",
+ project_id=1,
+ region_id=7,
+ action="soft_reboot",
+ )
+
+ @parametrize
+ def test_method_action_overload_4(self, client: Gcore) -> None:
+ gpu_virtual_cluster = client.cloud.gpu_virtual_clusters.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="hard_reboot",
+ )
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ def test_raw_response_action_overload_4(self, client: Gcore) -> None:
+ response = client.cloud.gpu_virtual_clusters.with_raw_response.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="hard_reboot",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ gpu_virtual_cluster = response.parse()
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ def test_streaming_response_action_overload_4(self, client: Gcore) -> None:
+ with client.cloud.gpu_virtual_clusters.with_streaming_response.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="hard_reboot",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ gpu_virtual_cluster = response.parse()
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_action_overload_4(self, client: Gcore) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"):
+ client.cloud.gpu_virtual_clusters.with_raw_response.action(
+ cluster_id="",
+ project_id=1,
+ region_id=7,
+ action="hard_reboot",
+ )
+
+ @parametrize
+ def test_method_action_overload_5(self, client: Gcore) -> None:
+ gpu_virtual_cluster = client.cloud.gpu_virtual_clusters.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="update_tags",
+ tags={"foo": "my-tag-value"},
+ )
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ def test_raw_response_action_overload_5(self, client: Gcore) -> None:
+ response = client.cloud.gpu_virtual_clusters.with_raw_response.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="update_tags",
+ tags={"foo": "my-tag-value"},
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ gpu_virtual_cluster = response.parse()
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ def test_streaming_response_action_overload_5(self, client: Gcore) -> None:
+ with client.cloud.gpu_virtual_clusters.with_streaming_response.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="update_tags",
+ tags={"foo": "my-tag-value"},
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ gpu_virtual_cluster = response.parse()
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_action_overload_5(self, client: Gcore) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"):
+ client.cloud.gpu_virtual_clusters.with_raw_response.action(
+ cluster_id="",
+ project_id=1,
+ region_id=7,
+ action="update_tags",
+ tags={"foo": "my-tag-value"},
+ )
+
+ @parametrize
+ def test_method_action_overload_6(self, client: Gcore) -> None:
+ gpu_virtual_cluster = client.cloud.gpu_virtual_clusters.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="resize",
+ servers_count=5,
+ )
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ def test_raw_response_action_overload_6(self, client: Gcore) -> None:
+ response = client.cloud.gpu_virtual_clusters.with_raw_response.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="resize",
+ servers_count=5,
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ gpu_virtual_cluster = response.parse()
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ def test_streaming_response_action_overload_6(self, client: Gcore) -> None:
+ with client.cloud.gpu_virtual_clusters.with_streaming_response.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="resize",
+ servers_count=5,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ gpu_virtual_cluster = response.parse()
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_action_overload_6(self, client: Gcore) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"):
+ client.cloud.gpu_virtual_clusters.with_raw_response.action(
+ cluster_id="",
+ project_id=1,
+ region_id=7,
+ action="resize",
+ servers_count=5,
+ )
+
+ @parametrize
+ def test_method_get(self, client: Gcore) -> None:
+ gpu_virtual_cluster = client.cloud.gpu_virtual_clusters.get(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ )
+ assert_matches_type(GPUVirtualCluster, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ def test_raw_response_get(self, client: Gcore) -> None:
+ response = client.cloud.gpu_virtual_clusters.with_raw_response.get(
+ 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"
+ gpu_virtual_cluster = response.parse()
+ assert_matches_type(GPUVirtualCluster, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ def test_streaming_response_get(self, client: Gcore) -> None:
+ with client.cloud.gpu_virtual_clusters.with_streaming_response.get(
+ 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"
+
+ gpu_virtual_cluster = response.parse()
+ assert_matches_type(GPUVirtualCluster, gpu_virtual_cluster, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_get(self, client: Gcore) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"):
+ client.cloud.gpu_virtual_clusters.with_raw_response.get(
+ cluster_id="",
+ project_id=1,
+ region_id=7,
+ )
+
+
+class TestAsyncGPUVirtualClusters:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_create(self, async_client: AsyncGcore) -> None:
+ gpu_virtual_cluster = await async_client.cloud.gpu_virtual_clusters.create(
+ project_id=1,
+ region_id=7,
+ flavor="g3-ai-32-192-1500-l40s-48-1",
+ name="gpu-cluster-1",
+ servers_count=3,
+ servers_settings={
+ "interfaces": [{"type": "external"}],
+ "volumes": [
+ {
+ "boot_index": 1,
+ "name": "my-data-disk",
+ "size": 100,
+ "source": "new",
+ "type": "cold",
+ }
+ ],
+ },
+ )
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None:
+ gpu_virtual_cluster = await async_client.cloud.gpu_virtual_clusters.create(
+ project_id=1,
+ region_id=7,
+ flavor="g3-ai-32-192-1500-l40s-48-1",
+ name="gpu-cluster-1",
+ servers_count=3,
+ servers_settings={
+ "interfaces": [
+ {
+ "type": "external",
+ "ip_family": "ipv4",
+ "name": "eth0",
+ }
+ ],
+ "volumes": [
+ {
+ "boot_index": 1,
+ "name": "my-data-disk",
+ "size": 100,
+ "source": "new",
+ "type": "cold",
+ "delete_on_termination": True,
+ "tags": {"key1": "value1"},
+ }
+ ],
+ "credentials": {
+ "password": "securepassword",
+ "ssh_key_name": "my-ssh-key",
+ "username": "admin",
+ },
+ "file_shares": [
+ {
+ "id": "a3f2d1b8-45e6-4f8a-bb5d-19dbf2cd7e9a",
+ "mount_path": "/mnt/vast",
+ }
+ ],
+ "security_groups": [{"id": "b4849ffa-89f2-45a1-951f-0ae5b7809d98"}],
+ "user_data": "eyJ0ZXN0IjogImRhdGEifQ==",
+ },
+ tags={"my-tag": "my-tag-value"},
+ )
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ async def test_raw_response_create(self, async_client: AsyncGcore) -> None:
+ response = await async_client.cloud.gpu_virtual_clusters.with_raw_response.create(
+ project_id=1,
+ region_id=7,
+ flavor="g3-ai-32-192-1500-l40s-48-1",
+ name="gpu-cluster-1",
+ servers_count=3,
+ servers_settings={
+ "interfaces": [{"type": "external"}],
+ "volumes": [
+ {
+ "boot_index": 1,
+ "name": "my-data-disk",
+ "size": 100,
+ "source": "new",
+ "type": "cold",
+ }
+ ],
+ },
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ gpu_virtual_cluster = await response.parse()
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_create(self, async_client: AsyncGcore) -> None:
+ async with async_client.cloud.gpu_virtual_clusters.with_streaming_response.create(
+ project_id=1,
+ region_id=7,
+ flavor="g3-ai-32-192-1500-l40s-48-1",
+ name="gpu-cluster-1",
+ servers_count=3,
+ servers_settings={
+ "interfaces": [{"type": "external"}],
+ "volumes": [
+ {
+ "boot_index": 1,
+ "name": "my-data-disk",
+ "size": 100,
+ "source": "new",
+ "type": "cold",
+ }
+ ],
+ },
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ gpu_virtual_cluster = await response.parse()
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_method_update(self, async_client: AsyncGcore) -> None:
+ gpu_virtual_cluster = await async_client.cloud.gpu_virtual_clusters.update(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ name="gpu-cluster-1",
+ )
+ assert_matches_type(GPUVirtualCluster, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ async def test_raw_response_update(self, async_client: AsyncGcore) -> None:
+ response = await async_client.cloud.gpu_virtual_clusters.with_raw_response.update(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ name="gpu-cluster-1",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ gpu_virtual_cluster = await response.parse()
+ assert_matches_type(GPUVirtualCluster, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_update(self, async_client: AsyncGcore) -> None:
+ async with async_client.cloud.gpu_virtual_clusters.with_streaming_response.update(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ name="gpu-cluster-1",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ gpu_virtual_cluster = await response.parse()
+ assert_matches_type(GPUVirtualCluster, gpu_virtual_cluster, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_update(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_virtual_clusters.with_raw_response.update(
+ cluster_id="",
+ project_id=1,
+ region_id=7,
+ name="gpu-cluster-1",
+ )
+
+ @parametrize
+ async def test_method_list(self, async_client: AsyncGcore) -> None:
+ gpu_virtual_cluster = await async_client.cloud.gpu_virtual_clusters.list(
+ project_id=1,
+ region_id=7,
+ )
+ assert_matches_type(AsyncOffsetPage[GPUVirtualCluster], gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None:
+ gpu_virtual_cluster = await async_client.cloud.gpu_virtual_clusters.list(
+ project_id=1,
+ region_id=7,
+ limit=10,
+ offset=0,
+ )
+ assert_matches_type(AsyncOffsetPage[GPUVirtualCluster], gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncGcore) -> None:
+ response = await async_client.cloud.gpu_virtual_clusters.with_raw_response.list(
+ project_id=1,
+ region_id=7,
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ gpu_virtual_cluster = await response.parse()
+ assert_matches_type(AsyncOffsetPage[GPUVirtualCluster], gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncGcore) -> None:
+ async with async_client.cloud.gpu_virtual_clusters.with_streaming_response.list(
+ project_id=1,
+ region_id=7,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ gpu_virtual_cluster = await response.parse()
+ assert_matches_type(AsyncOffsetPage[GPUVirtualCluster], gpu_virtual_cluster, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_method_delete(self, async_client: AsyncGcore) -> None:
+ gpu_virtual_cluster = await async_client.cloud.gpu_virtual_clusters.delete(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ )
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ async def test_method_delete_with_all_params(self, async_client: AsyncGcore) -> None:
+ gpu_virtual_cluster = await async_client.cloud.gpu_virtual_clusters.delete(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ all_floating_ips=True,
+ all_reserved_fixed_ips=True,
+ all_volumes=True,
+ floating_ip_ids=["e4a01208-d6ac-4304-bf86-3028154b070a"],
+ reserved_fixed_ip_ids=["a29b8e1e-08d3-4cec-91fb-06e81e5f46d5"],
+ volume_ids=["1333c684-c3da-4b91-ac9e-a92706aa2824"],
+ )
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ async def test_raw_response_delete(self, async_client: AsyncGcore) -> None:
+ response = await async_client.cloud.gpu_virtual_clusters.with_raw_response.delete(
+ 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"
+ gpu_virtual_cluster = await response.parse()
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None:
+ async with async_client.cloud.gpu_virtual_clusters.with_streaming_response.delete(
+ 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"
+
+ gpu_virtual_cluster = await response.parse()
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_delete(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_virtual_clusters.with_raw_response.delete(
+ cluster_id="",
+ project_id=1,
+ region_id=7,
+ )
+
+ @parametrize
+ async def test_method_action_overload_1(self, async_client: AsyncGcore) -> None:
+ gpu_virtual_cluster = await async_client.cloud.gpu_virtual_clusters.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="start",
+ )
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ async def test_raw_response_action_overload_1(self, async_client: AsyncGcore) -> None:
+ response = await async_client.cloud.gpu_virtual_clusters.with_raw_response.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="start",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ gpu_virtual_cluster = await response.parse()
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_action_overload_1(self, async_client: AsyncGcore) -> None:
+ async with async_client.cloud.gpu_virtual_clusters.with_streaming_response.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="start",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ gpu_virtual_cluster = await response.parse()
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_action_overload_1(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_virtual_clusters.with_raw_response.action(
+ cluster_id="",
+ project_id=1,
+ region_id=7,
+ action="start",
+ )
+
+ @parametrize
+ async def test_method_action_overload_2(self, async_client: AsyncGcore) -> None:
+ gpu_virtual_cluster = await async_client.cloud.gpu_virtual_clusters.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="stop",
+ )
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ async def test_raw_response_action_overload_2(self, async_client: AsyncGcore) -> None:
+ response = await async_client.cloud.gpu_virtual_clusters.with_raw_response.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="stop",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ gpu_virtual_cluster = await response.parse()
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_action_overload_2(self, async_client: AsyncGcore) -> None:
+ async with async_client.cloud.gpu_virtual_clusters.with_streaming_response.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="stop",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ gpu_virtual_cluster = await response.parse()
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_action_overload_2(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_virtual_clusters.with_raw_response.action(
+ cluster_id="",
+ project_id=1,
+ region_id=7,
+ action="stop",
+ )
+
+ @parametrize
+ async def test_method_action_overload_3(self, async_client: AsyncGcore) -> None:
+ gpu_virtual_cluster = await async_client.cloud.gpu_virtual_clusters.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="soft_reboot",
+ )
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ async def test_raw_response_action_overload_3(self, async_client: AsyncGcore) -> None:
+ response = await async_client.cloud.gpu_virtual_clusters.with_raw_response.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="soft_reboot",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ gpu_virtual_cluster = await response.parse()
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_action_overload_3(self, async_client: AsyncGcore) -> None:
+ async with async_client.cloud.gpu_virtual_clusters.with_streaming_response.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="soft_reboot",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ gpu_virtual_cluster = await response.parse()
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_action_overload_3(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_virtual_clusters.with_raw_response.action(
+ cluster_id="",
+ project_id=1,
+ region_id=7,
+ action="soft_reboot",
+ )
+
+ @parametrize
+ async def test_method_action_overload_4(self, async_client: AsyncGcore) -> None:
+ gpu_virtual_cluster = await async_client.cloud.gpu_virtual_clusters.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="hard_reboot",
+ )
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ async def test_raw_response_action_overload_4(self, async_client: AsyncGcore) -> None:
+ response = await async_client.cloud.gpu_virtual_clusters.with_raw_response.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="hard_reboot",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ gpu_virtual_cluster = await response.parse()
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_action_overload_4(self, async_client: AsyncGcore) -> None:
+ async with async_client.cloud.gpu_virtual_clusters.with_streaming_response.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="hard_reboot",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ gpu_virtual_cluster = await response.parse()
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_action_overload_4(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_virtual_clusters.with_raw_response.action(
+ cluster_id="",
+ project_id=1,
+ region_id=7,
+ action="hard_reboot",
+ )
+
+ @parametrize
+ async def test_method_action_overload_5(self, async_client: AsyncGcore) -> None:
+ gpu_virtual_cluster = await async_client.cloud.gpu_virtual_clusters.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="update_tags",
+ tags={"foo": "my-tag-value"},
+ )
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ async def test_raw_response_action_overload_5(self, async_client: AsyncGcore) -> None:
+ response = await async_client.cloud.gpu_virtual_clusters.with_raw_response.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="update_tags",
+ tags={"foo": "my-tag-value"},
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ gpu_virtual_cluster = await response.parse()
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_action_overload_5(self, async_client: AsyncGcore) -> None:
+ async with async_client.cloud.gpu_virtual_clusters.with_streaming_response.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="update_tags",
+ tags={"foo": "my-tag-value"},
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ gpu_virtual_cluster = await response.parse()
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_action_overload_5(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_virtual_clusters.with_raw_response.action(
+ cluster_id="",
+ project_id=1,
+ region_id=7,
+ action="update_tags",
+ tags={"foo": "my-tag-value"},
+ )
+
+ @parametrize
+ async def test_method_action_overload_6(self, async_client: AsyncGcore) -> None:
+ gpu_virtual_cluster = await async_client.cloud.gpu_virtual_clusters.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="resize",
+ servers_count=5,
+ )
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ async def test_raw_response_action_overload_6(self, async_client: AsyncGcore) -> None:
+ response = await async_client.cloud.gpu_virtual_clusters.with_raw_response.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="resize",
+ servers_count=5,
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ gpu_virtual_cluster = await response.parse()
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_action_overload_6(self, async_client: AsyncGcore) -> None:
+ async with async_client.cloud.gpu_virtual_clusters.with_streaming_response.action(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ action="resize",
+ servers_count=5,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ gpu_virtual_cluster = await response.parse()
+ assert_matches_type(TaskIDList, gpu_virtual_cluster, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_action_overload_6(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_virtual_clusters.with_raw_response.action(
+ cluster_id="",
+ project_id=1,
+ region_id=7,
+ action="resize",
+ servers_count=5,
+ )
+
+ @parametrize
+ async def test_method_get(self, async_client: AsyncGcore) -> None:
+ gpu_virtual_cluster = await async_client.cloud.gpu_virtual_clusters.get(
+ cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4",
+ project_id=1,
+ region_id=7,
+ )
+ assert_matches_type(GPUVirtualCluster, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ async def test_raw_response_get(self, async_client: AsyncGcore) -> None:
+ response = await async_client.cloud.gpu_virtual_clusters.with_raw_response.get(
+ 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"
+ gpu_virtual_cluster = await response.parse()
+ assert_matches_type(GPUVirtualCluster, gpu_virtual_cluster, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_get(self, async_client: AsyncGcore) -> None:
+ async with async_client.cloud.gpu_virtual_clusters.with_streaming_response.get(
+ 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"
+
+ gpu_virtual_cluster = await response.parse()
+ assert_matches_type(GPUVirtualCluster, gpu_virtual_cluster, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_get(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_virtual_clusters.with_raw_response.get(
+ cluster_id="",
+ project_id=1,
+ region_id=7,
+ )
From 70e1cc8404668e008c236881c5819eeff91725d6 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 11 Nov 2025 14:36:33 +0000
Subject: [PATCH 5/6] fix(compat): update signatures of `model_dump` and
`model_dump_json` for Pydantic v1
---
src/gcore/_models.py | 41 +++++++++++++++++++++++++++++------------
1 file changed, 29 insertions(+), 12 deletions(-)
diff --git a/src/gcore/_models.py b/src/gcore/_models.py
index fcec2cf9..ca9500b2 100644
--- a/src/gcore/_models.py
+++ b/src/gcore/_models.py
@@ -257,15 +257,16 @@ def model_dump(
mode: Literal["json", "python"] | str = "python",
include: IncEx | None = None,
exclude: IncEx | None = None,
+ context: Any | None = None,
by_alias: bool | None = None,
exclude_unset: bool = False,
exclude_defaults: bool = False,
exclude_none: bool = False,
+ exclude_computed_fields: bool = False,
round_trip: bool = False,
warnings: bool | Literal["none", "warn", "error"] = True,
- context: dict[str, Any] | None = None,
- serialize_as_any: bool = False,
fallback: Callable[[Any], Any] | None = None,
+ serialize_as_any: bool = False,
) -> dict[str, Any]:
"""Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump
@@ -273,16 +274,24 @@ def model_dump(
Args:
mode: The mode in which `to_python` should run.
- If mode is 'json', the dictionary will only contain JSON serializable types.
- If mode is 'python', the dictionary may contain any Python objects.
- include: A list of fields to include in the output.
- exclude: A list of fields to exclude from the output.
+ If mode is 'json', the output will only contain JSON serializable types.
+ If mode is 'python', the output may contain non-JSON-serializable Python objects.
+ include: A set of fields to include in the output.
+ exclude: A set of fields to exclude from the output.
+ context: Additional context to pass to the serializer.
by_alias: Whether to use the field's alias in the dictionary key if defined.
- exclude_unset: Whether to exclude fields that are unset or None from the output.
- exclude_defaults: Whether to exclude fields that are set to their default value from the output.
- exclude_none: Whether to exclude fields that have a value of `None` from the output.
- round_trip: Whether to enable serialization and deserialization round-trip support.
- warnings: Whether to log warnings when invalid fields are encountered.
+ exclude_unset: Whether to exclude fields that have not been explicitly set.
+ exclude_defaults: Whether to exclude fields that are set to their default value.
+ exclude_none: Whether to exclude fields that have a value of `None`.
+ exclude_computed_fields: Whether to exclude computed fields.
+ While this can be useful for round-tripping, it is usually recommended to use the dedicated
+ `round_trip` parameter instead.
+ round_trip: If True, dumped values should be valid as input for non-idempotent types such as Json[T].
+ warnings: How to handle serialization errors. False/"none" ignores them, True/"warn" logs errors,
+ "error" raises a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError].
+ fallback: A function to call when an unknown value is encountered. If not provided,
+ a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] error is raised.
+ serialize_as_any: Whether to serialize fields with duck-typing serialization behavior.
Returns:
A dictionary representation of the model.
@@ -299,6 +308,8 @@ def model_dump(
raise ValueError("serialize_as_any is only supported in Pydantic v2")
if fallback is not None:
raise ValueError("fallback is only supported in Pydantic v2")
+ if exclude_computed_fields != False:
+ raise ValueError("exclude_computed_fields is only supported in Pydantic v2")
dumped = super().dict( # pyright: ignore[reportDeprecated]
include=include,
exclude=exclude,
@@ -315,15 +326,17 @@ def model_dump_json(
self,
*,
indent: int | None = None,
+ ensure_ascii: bool = False,
include: IncEx | None = None,
exclude: IncEx | None = None,
+ context: Any | None = None,
by_alias: bool | None = None,
exclude_unset: bool = False,
exclude_defaults: bool = False,
exclude_none: bool = False,
+ exclude_computed_fields: bool = False,
round_trip: bool = False,
warnings: bool | Literal["none", "warn", "error"] = True,
- context: dict[str, Any] | None = None,
fallback: Callable[[Any], Any] | None = None,
serialize_as_any: bool = False,
) -> str:
@@ -355,6 +368,10 @@ def model_dump_json(
raise ValueError("serialize_as_any is only supported in Pydantic v2")
if fallback is not None:
raise ValueError("fallback is only supported in Pydantic v2")
+ if ensure_ascii != False:
+ raise ValueError("ensure_ascii is only supported in Pydantic v2")
+ if exclude_computed_fields != False:
+ raise ValueError("exclude_computed_fields is only supported in Pydantic v2")
return super().json( # type: ignore[reportDeprecated]
indent=indent,
include=include,
From 252e0871bba968b0b7abe66b0d86c4dfa1e14f72 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 11 Nov 2025 14:37:16 +0000
Subject: [PATCH 6/6] release: 0.20.0
---
.release-please-manifest.json | 2 +-
CHANGELOG.md | 20 ++++++++++++++++++++
pyproject.toml | 2 +-
src/gcore/_version.py | 2 +-
4 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index e7562934..0c2ecec6 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.19.0"
+ ".": "0.20.0"
}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 658b8393..c8ad9677 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,25 @@
# Changelog
+## 0.20.0 (2025-11-11)
+
+Full Changelog: [v0.19.0...v0.20.0](https://github.com/G-Core/gcore-python/compare/v0.19.0...v0.20.0)
+
+### Features
+
+* **api:** aggregated API specs update ([767fdd5](https://github.com/G-Core/gcore-python/commit/767fdd5d74846369e3331efba210aff12a43e802))
+* **cloud:** add support for GPU virtual clusters ([c406d97](https://github.com/G-Core/gcore-python/commit/c406d97d04db03f5c4d105f2e9761e9b8c2d96c8))
+
+
+### Bug Fixes
+
+* compat with Python 3.14 ([90bfffe](https://github.com/G-Core/gcore-python/commit/90bfffeed8b28a360e1489162d4dc6a28745b411))
+* **compat:** update signatures of `model_dump` and `model_dump_json` for Pydantic v1 ([70e1cc8](https://github.com/G-Core/gcore-python/commit/70e1cc8404668e008c236881c5819eeff91725d6))
+
+
+### Chores
+
+* **package:** drop Python 3.8 support ([99955b9](https://github.com/G-Core/gcore-python/commit/99955b9208b2810fcbafbf5f8d941b5981faebbe))
+
## 0.19.0 (2025-11-07)
Full Changelog: [v0.18.0...v0.19.0](https://github.com/G-Core/gcore-python/compare/v0.18.0...v0.19.0)
diff --git a/pyproject.toml b/pyproject.toml
index 6aeac16c..6b4e68cb 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "gcore"
-version = "0.19.0"
+version = "0.20.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 54b67f1e..0013e79a 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.19.0" # x-release-please-version
+__version__ = "0.20.0" # x-release-please-version