Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions datacrunch_compat/datacrunch/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@
__version__,
authentication,
balance,
cluster_types,
constants,
container_types,
containers,
exceptions,
helpers,
http_client,
images,
instance_types,
instances,
job_deployments,
locations,
ssh_keys,
startup_scripts,
Expand All @@ -28,7 +31,9 @@
'__version__',
'authentication',
'balance',
'cluster_types',
'constants',
'container_types',
'containers',
'datacrunch',
'exceptions',
Expand All @@ -37,6 +42,7 @@
'images',
'instance_types',
'instances',
'job_deployments',
'locations',
'ssh_keys',
'startup_scripts',
Expand Down
6 changes: 6 additions & 0 deletions datacrunch_compat/datacrunch/datacrunch.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@
from verda._version import __version__
from verda.authentication import AuthenticationService
from verda.balance import BalanceService
from verda.cluster_types import ClusterTypesService
from verda.constants import Constants
from verda.container_types import ContainerTypesService
from verda.containers import ContainersService
from verda.http_client import HTTPClient
from verda.images import ImagesService
from verda.instance_types import InstanceTypesService
from verda.instances import InstancesService
from verda.job_deployments import JobDeploymentsService
from verda.locations import LocationsService
from verda.ssh_keys import SSHKeysService
from verda.startup_scripts import StartupScriptsService
Expand All @@ -20,13 +23,16 @@
__all__ = [
'AuthenticationService',
'BalanceService',
'ClusterTypesService',
'Constants',
'ContainerTypesService',
'ContainersService',
'DataCrunchClient',
'HTTPClient',
'ImagesService',
'InstanceTypesService',
'InstancesService',
'JobDeploymentsService',
'LocationsService',
'SSHKeysService',
'StartupScriptsService',
Expand Down
8 changes: 8 additions & 0 deletions docs/source/api/services/cluster_types.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Cluster Types
=============

.. autoclass:: verda.cluster_types.ClusterTypesService
:members:

.. autoclass:: verda.cluster_types.ClusterType
:members:
8 changes: 8 additions & 0 deletions docs/source/api/services/container_types.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Container Types
===============

.. autoclass:: verda.container_types.ContainerTypesService
:members:

.. autoclass:: verda.container_types.ContainerType
:members:
14 changes: 14 additions & 0 deletions docs/source/api/services/job_deployments.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Job Deployments
===============

.. autoclass:: verda.job_deployments.JobDeploymentsService
:members:

.. autoclass:: verda.job_deployments.JobDeployment
:members:

.. autoclass:: verda.job_deployments.JobDeploymentSummary
:members:

.. autoclass:: verda.job_deployments.JobScalingOptions
:members:
51 changes: 51 additions & 0 deletions tests/unit_tests/cluster_types/test_cluster_types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import responses # https://github.com/getsentry/responses

from verda.cluster_types import ClusterType, ClusterTypesService

CLUSTER_TYPE_ID = 'cluster-c0de-a5d2-4972-ae4e-d429115d055b'


@responses.activate
def test_cluster_types(http_client):
endpoint = http_client._base_url + '/cluster-types?currency=usd'
responses.add(
responses.GET,
endpoint,
json=[
{
'id': CLUSTER_TYPE_ID,
'model': 'H200',
'name': 'H200 Cluster',
'cluster_type': '16H200',
'cpu': {'description': '64 CPU', 'number_of_cores': 64},
'gpu': {'description': '16x H200', 'number_of_gpus': 16},
'gpu_memory': {'description': '2.2TB VRAM', 'size_in_gigabytes': 2200},
'memory': {'description': '4TB RAM', 'size_in_gigabytes': 4096},
'price_per_hour': '45.50',
'currency': 'usd',
'manufacturer': 'NVIDIA',
'node_details': ['2x 8 GPU nodes'],
'supported_os': ['ubuntu-24.04-cuda-12.8-cluster'],
}
],
status=200,
)

service = ClusterTypesService(http_client)

cluster_types = service.get()
cluster_type = cluster_types[0]

assert isinstance(cluster_types, list)
assert len(cluster_types) == 1
assert isinstance(cluster_type, ClusterType)
assert cluster_type.id == CLUSTER_TYPE_ID
assert cluster_type.model == 'H200'
assert cluster_type.name == 'H200 Cluster'
assert cluster_type.cluster_type == '16H200'
assert cluster_type.price_per_hour == 45.5
assert cluster_type.currency == 'usd'
assert cluster_type.manufacturer == 'NVIDIA'
assert cluster_type.node_details == ['2x 8 GPU nodes']
assert cluster_type.supported_os == ['ubuntu-24.04-cuda-12.8-cluster']
assert responses.assert_call_count(endpoint, 1) is True
49 changes: 49 additions & 0 deletions tests/unit_tests/container_types/test_container_types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import responses # https://github.com/getsentry/responses

from verda.container_types import ContainerType, ContainerTypesService

CONTAINER_TYPE_ID = 'type-c0de-a5d2-4972-ae4e-d429115d055b'


@responses.activate
def test_container_types(http_client):
endpoint = http_client._base_url + '/container-types?currency=eur'
responses.add(
responses.GET,
endpoint,
json=[
{
'id': CONTAINER_TYPE_ID,
'model': 'H100',
'name': 'H100 SXM5 80GB',
'instance_type': '1H100.80S.22V',
'cpu': {'description': '22 CPU', 'number_of_cores': 22},
'gpu': {'description': '1x H100 SXM5 80GB', 'number_of_gpus': 1},
'gpu_memory': {'description': '80GB GPU RAM', 'size_in_gigabytes': 80},
'memory': {'description': '187GB RAM', 'size_in_gigabytes': 187},
'serverless_price': '1.75',
'serverless_spot_price': '0.87',
'currency': 'eur',
'manufacturer': 'NVIDIA',
}
],
status=200,
)

service = ContainerTypesService(http_client)

container_types = service.get(currency='eur')
container_type = container_types[0]

assert isinstance(container_types, list)
assert len(container_types) == 1
assert isinstance(container_type, ContainerType)
assert container_type.id == CONTAINER_TYPE_ID
assert container_type.model == 'H100'
assert container_type.name == 'H100 SXM5 80GB'
assert container_type.instance_type == '1H100.80S.22V'
assert container_type.serverless_price == 1.75
assert container_type.serverless_spot_price == 0.87
assert container_type.currency == 'eur'
assert container_type.manufacturer == 'NVIDIA'
assert responses.assert_call_count(endpoint, 1) is True
37 changes: 35 additions & 2 deletions tests/unit_tests/instance_types/test_instance_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,36 @@
STORAGE_DESCRIPTION = '1800GB NVME'
STORAGE_SIZE = 1800
INSTANCE_TYPE_DESCRIPTION = 'Dedicated Bare metal Server'
BEST_FOR = ['Large model inference', 'Multi-GPU training']
MODEL = 'V100'
NAME = 'Tesla V100'
P2P = '300 GB/s'
PRICE_PER_HOUR = 5.0
SPOT_PRICE_PER_HOUR = 2.5
SERVERLESS_PRICE = 1.25
SERVERLESS_SPOT_PRICE = 0.75
INSTANCE_TYPE = '8V100.48M'
CURRENCY = 'eur'
MANUFACTURER = 'NVIDIA'
DISPLAY_NAME = 'NVIDIA Tesla V100'
SUPPORTED_OS = ['ubuntu-24.04-cuda-12.8-open-docker']


@responses.activate
def test_instance_types(http_client):
# arrange - add response mock
responses.add(
responses.GET,
http_client._base_url + '/instance-types',
http_client._base_url + '/instance-types?currency=eur',
json=[
{
'id': TYPE_ID,
'best_for': BEST_FOR,
'cpu': {
'description': CPU_DESCRIPTION,
'number_of_cores': NUMBER_OF_CORES,
},
'deploy_warning': 'Use updated drivers',
'gpu': {
'description': GPU_DESCRIPTION,
'number_of_gpus': NUMBER_OF_GPUS,
Expand All @@ -48,9 +61,18 @@ def test_instance_types(http_client):
'size_in_gigabytes': STORAGE_SIZE,
},
'description': INSTANCE_TYPE_DESCRIPTION,
'model': MODEL,
'name': NAME,
'p2p': P2P,
'price_per_hour': '5.00',
'spot_price': '2.50',
'serverless_price': '1.25',
'serverless_spot_price': '0.75',
'instance_type': INSTANCE_TYPE,
'currency': CURRENCY,
'manufacturer': MANUFACTURER,
'display_name': DISPLAY_NAME,
'supported_os': SUPPORTED_OS,
}
],
status=200,
Expand All @@ -59,7 +81,7 @@ def test_instance_types(http_client):
instance_types_service = InstanceTypesService(http_client)

# act
instance_types = instance_types_service.get()
instance_types = instance_types_service.get(currency='eur')
instance_type = instance_types[0]

# assert
Expand All @@ -71,6 +93,17 @@ def test_instance_types(http_client):
assert instance_type.price_per_hour == PRICE_PER_HOUR
assert instance_type.spot_price_per_hour == SPOT_PRICE_PER_HOUR
assert instance_type.instance_type == INSTANCE_TYPE
assert instance_type.best_for == BEST_FOR
assert instance_type.model == MODEL
assert instance_type.name == NAME
assert instance_type.p2p == P2P
assert instance_type.currency == CURRENCY
assert instance_type.manufacturer == MANUFACTURER
assert instance_type.display_name == DISPLAY_NAME
assert instance_type.supported_os == SUPPORTED_OS
assert instance_type.deploy_warning == 'Use updated drivers'
assert instance_type.serverless_price == SERVERLESS_PRICE
assert instance_type.serverless_spot_price == SERVERLESS_SPOT_PRICE
assert isinstance(instance_type.cpu, dict)
assert isinstance(instance_type.gpu, dict)
assert isinstance(instance_type.memory, dict)
Expand Down
Loading
Loading