Skip to content

Commit 8ca2353

Browse files
authored
Merge pull request #18 from DataCrunch-io/feature/CLOUD-141-update-the-python-sdk-to-the-n
Feature/cloud 141 update the python sdk to the new location code parameter
2 parents cc7e752 + 6590458 commit 8ca2353

File tree

8 files changed

+109
-33
lines changed

8 files changed

+109
-33
lines changed

CHANGELOG.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
Changelog
22
=========
33

4+
* Added location constants
5+
* Refactored the code to send `location_code` instead of `location` when creating an instance or a volume
6+
47
v1.4.1 (2023-06-20)
58
-------------------
69

datacrunch/constants.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,14 @@ def __init__(self):
5555
return
5656

5757

58+
class Locations:
59+
FIN_01 = "FIN-01"
60+
ICE_01 = "ICE-01"
61+
62+
def __init__(self):
63+
return
64+
65+
5866
class ErrorCodes:
5967
INVALID_REQUEST = "invalid_request"
6068
UNAUTHORIZED_REQUEST = "unauthorized_request"
@@ -85,6 +93,9 @@ def __init__(self, base_url, version):
8593
self.volume_types: VolumeTypes = VolumeTypes()
8694
"""Available volume types"""
8795

96+
self.locations: Locations = Locations()
97+
"""Available locations"""
98+
8899
self.error_codes: ErrorCodes = ErrorCodes()
89100
"""Available error codes"""
90101

datacrunch/instances/instances.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from typing import List, Union, Optional, Dict
22
from datacrunch.helpers import stringify_class_object_properties
3+
from datacrunch.constants import Locations
34

45
INSTANCES_ENDPOINT = '/instances'
56

@@ -24,7 +25,7 @@ def __init__(self,
2425
storage: dict,
2526
os_volume_id: str,
2627
gpu_memory: dict,
27-
location: str = "FIN1",
28+
location: str = Locations.FIN_01,
2829
startup_script_id: str = None,
2930
is_spot: bool = False
3031
) -> None:
@@ -62,7 +63,7 @@ def __init__(self,
6263
:type id: str
6364
:param memory: gpu memory details
6465
:type memory: dict
65-
:param location: datacenter location, defaults to "FIN1"
66+
:param location: datacenter location, defaults to "FIN-01"
6667
:type location: str, optional
6768
:param startup_script_id: startup script id, defaults to None
6869
:type startup_script_id: str, optional
@@ -268,6 +269,7 @@ def __str__(self) -> str:
268269
"""
269270
return stringify_class_object_properties(self)
270271

272+
271273
class InstancesService:
272274
"""A service for interacting with the instances endpoint"""
273275

@@ -295,7 +297,8 @@ def get(self, status: str = None) -> List[Instance]:
295297
ip=instance_dict['ip'],
296298
status=instance_dict['status'],
297299
created_at=instance_dict['created_at'],
298-
ssh_key_ids=instance_dict['ssh_key_ids'] if 'ssh_key_ids' in instance_dict else [],
300+
ssh_key_ids=instance_dict['ssh_key_ids'] if 'ssh_key_ids' in instance_dict else [
301+
],
299302
startup_script_id=instance_dict['startup_script_id'] if 'startup_script_id' in instance_dict else None,
300303
cpu=instance_dict['cpu'],
301304
gpu=instance_dict['gpu'],
@@ -328,7 +331,8 @@ def get_by_id(self, id: str) -> Instance:
328331
ip=instance_dict['ip'],
329332
status=instance_dict['status'],
330333
created_at=instance_dict['created_at'],
331-
ssh_key_ids=instance_dict['ssh_key_ids'] if 'ssh_key_ids' in instance_dict else [],
334+
ssh_key_ids=instance_dict['ssh_key_ids'] if 'ssh_key_ids' in instance_dict else [
335+
],
332336
startup_script_id=instance_dict['startup_script_id'] if 'startup_script_id' in instance_dict else None,
333337
cpu=instance_dict['cpu'],
334338
gpu=instance_dict['gpu'],
@@ -346,7 +350,7 @@ def create(self,
346350
hostname: str,
347351
description: str,
348352
ssh_key_ids: list = [],
349-
location: str = "FIN1",
353+
location: str = Locations.FIN_01,
350354
startup_script_id: str = None,
351355
volumes: List[Dict] = None,
352356
existing_volumes: List[str] = None,
@@ -365,7 +369,7 @@ def create(self,
365369
:type hostname: str
366370
:param description: instance description
367371
:type description: str
368-
:param location: datacenter location, defaults to "FIN1"
372+
:param location: datacenter location, defaults to "FIN-01"
369373
:type location: str, optional
370374
:param startup_script_id: startup script id, defaults to None
371375
:type startup_script_id: str, optional
@@ -389,7 +393,7 @@ def create(self,
389393
"startup_script_id": startup_script_id,
390394
"hostname": hostname,
391395
"description": description,
392-
"location": location,
396+
"location_code": location,
393397
"os_volume": os_volume,
394398
"volumes": volumes,
395399
"existing_volumes": existing_volumes,

datacrunch/volumes/volumes.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from typing import List, Union, Optional
2-
from datacrunch.constants import VolumeActions
2+
from datacrunch.constants import VolumeActions, Locations
33
from datacrunch.helpers import stringify_class_object_properties
44

55
VOLUMES_ENDPOINT = '/volumes'
@@ -17,7 +17,7 @@ def __init__(self,
1717
is_os_volume: bool,
1818
created_at: str,
1919
target: str = None,
20-
location: str = "FIN1",
20+
location: str = Locations.FIN_01,
2121
instance_id: str = None,
2222
ssh_key_ids: List[str] = [],
2323
deleted_at: str = None,
@@ -40,7 +40,7 @@ def __init__(self,
4040
:type created_at: str
4141
:param target: target device e.g. vda
4242
:type target: str, optional
43-
:param location: datacenter location, defaults to "FIN1"
43+
:param location: datacenter location, defaults to "FIN-01"
4444
:type location: str, optional
4545
:param instance_id: the instance id the volume is attached to, None if detached
4646
:type instance_id: str
@@ -238,7 +238,7 @@ def create(self,
238238
name: str,
239239
size: int,
240240
instance_id: str = None,
241-
location: str = "FIN1",
241+
location: str = Locations.FIN_01,
242242
) -> Volume:
243243
"""Create new volume
244244
@@ -250,7 +250,7 @@ def create(self,
250250
:type size: int
251251
:param instance_id: Instance id to be attached to, defaults to None
252252
:type instance_id: str, optional
253-
:param location: datacenter location, defaults to "FIN1"
253+
:param location: datacenter location, defaults to "FIN-01"
254254
:type location: str, optional
255255
:return: the new volume object
256256
:rtype: Volume
@@ -260,7 +260,7 @@ def create(self,
260260
"name": name,
261261
"size": size,
262262
"instance_id": instance_id,
263-
"location": location
263+
"location_code": location
264264
}
265265
id = self._http_client.post(VOLUMES_ENDPOINT, json=payload).text
266266
volume = self.get_by_id(id)
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import os
2+
import pytest
3+
from datacrunch.datacrunch import DataCrunchClient
4+
from datacrunch.constants import Locations
5+
6+
IN_GITHUB_ACTIONS = os.getenv("GITHUB_ACTIONS") == "true"
7+
8+
9+
@pytest.mark.skipif(IN_GITHUB_ACTIONS, reason="Test doesn't work in Github Actions.")
10+
@pytest.mark.withoutresponses
11+
class TestInstances():
12+
13+
def test_create_instance(self, datacrunch_client: DataCrunchClient):
14+
# get ssh key
15+
ssh_key = datacrunch_client.ssh_keys.get()[0]
16+
17+
# create instance
18+
instance = datacrunch_client.instances.create(
19+
hostname="test-instance",
20+
location=Locations.FIN_01,
21+
instance_type='CPU.4V',
22+
description="test instance",
23+
image="ubuntu-18.04",
24+
ssh_key_ids=[ssh_key.id])
25+
26+
# assert instance is created
27+
assert instance.id is not None
28+
assert instance.status == datacrunch_client.constants.instance_status.PROVISIONING
29+
30+
# delete instance
31+
datacrunch_client.instances.action(instance.id, "delete")
32+
33+
# permanently delete all volumes in trash
34+
trash = datacrunch_client.volumes.get_in_trash()
35+
for volume in trash:
36+
datacrunch_client.volumes.delete(volume.id, is_permanent=True)

tests/integration_tests/test_volumes.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
import os
22
import pytest
33
from datacrunch.datacrunch import DataCrunchClient
4+
from datacrunch.constants import Locations, VolumeTypes, VolumeStatus
45

56
IN_GITHUB_ACTIONS = os.getenv("GITHUB_ACTIONS") == "true"
67

78

9+
NVMe = VolumeTypes.NVMe
10+
11+
812
@pytest.mark.skipif(IN_GITHUB_ACTIONS, reason="Test doesn't work in Github Actions.")
913
@pytest.mark.withoutresponses
1014
class TestVolumes():
1115

1216
def test_get_volumes_from_trash(self, datacrunch_client: DataCrunchClient):
1317
# create new volume
1418
volume = datacrunch_client.volumes.create(
15-
type=datacrunch_client.constants.volume_types.NVMe, name="test_volume", size=100)
19+
type=NVMe, name="test_volume", size=100)
1620

1721
# delete volume
1822
datacrunch_client.volumes.delete(volume.id)
@@ -29,7 +33,7 @@ def test_get_volumes_from_trash(self, datacrunch_client: DataCrunchClient):
2933
def test_permanently_delete_detached_volumes(seld, datacrunch_client):
3034
# create new volume
3135
volume = datacrunch_client.volumes.create(
32-
type=datacrunch_client.constants.volume_types.NVMe, name="test_volume", size=100)
36+
type=NVMe, name="test_volume", size=100)
3337

3438
# permanently delete the detached volume
3539
datacrunch_client.volumes.delete(volume.id, is_permanent=True)
@@ -49,7 +53,7 @@ def test_permanently_delete_detached_volumes(seld, datacrunch_client):
4953
def test_permanently_delete_a_deleted_volume_from_trash(self, datacrunch_client):
5054
# create new volume
5155
volume = datacrunch_client.volumes.create(
52-
type=datacrunch_client.constants.volume_types.NVMe, name="test_volume", size=100)
56+
type=NVMe, name="test_volume", size=100)
5357

5458
# delete volume
5559
datacrunch_client.volumes.delete(volume.id)
@@ -68,3 +72,16 @@ def test_permanently_delete_a_deleted_volume_from_trash(self, datacrunch_client)
6872

6973
# assert volume is not in trash
7074
assert volume.id not in [v.id for v in volumes]
75+
76+
def test_create_volume(self, datacrunch_client):
77+
# create new volume
78+
volume = datacrunch_client.volumes.create(
79+
type=NVMe, name="test_volume", size=100, location=Locations.FIN_01)
80+
81+
# assert volume is created
82+
assert volume.id is not None
83+
assert volume.location == Locations.FIN_01
84+
assert volume.status == VolumeStatus.ORDERED or volume.status == VolumeStatus.DETACHED
85+
86+
# cleaning: delete volume
87+
datacrunch_client.volumes.delete(volume.id, is_permanent=True)

tests/unit_tests/instances/test_instances.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from datacrunch.exceptions import APIException
55
from datacrunch.instances.instances import InstancesService, Instance
6-
from datacrunch.constants import Actions, ErrorCodes
6+
from datacrunch.constants import Actions, ErrorCodes, Locations
77

88
INVALID_REQUEST = ErrorCodes.INVALID_REQUEST
99
INVALID_REQUEST_MESSAGE = 'Your existence is invalid'
@@ -18,7 +18,7 @@
1818
INSTANCE_DESCRIPTION = "hope you enjoy your GPU"
1919
INSTANCE_STATUS = 'running'
2020
INSTANCE_PRICE_PER_HOUR = 0.60
21-
INSTANCE_LOCATION = 'FIN1'
21+
INSTANCE_LOCATION = Locations.FIN_01
2222
INSTANCE_IP = '1.2.3.4'
2323
INSTANCE_CREATED_AT = "whatchalookingatboy?"
2424
INSTANCE_OS_VOLUME = {"name": "os volume", "size": 50}
@@ -63,6 +63,7 @@
6363
PAYLOAD_SPOT = PAYLOAD
6464
PAYLOAD_SPOT[0]["is_spot"] = True
6565

66+
6667
class TestInstancesService:
6768
@pytest.fixture
6869
def instances_service(self, http_client):
@@ -397,7 +398,8 @@ def test_action_successful(self, instances_service, endpoint):
397398
)
398399

399400
# act
400-
result = instances_service.action(id_list=[INSTANCE_ID], action=Actions.SHUTDOWN)
401+
result = instances_service.action(
402+
id_list=[INSTANCE_ID], action=Actions.SHUTDOWN)
401403

402404
# assert
403405
assert result is None
@@ -415,7 +417,8 @@ def test_action_failed(self, instances_service, endpoint):
415417

416418
# act
417419
with pytest.raises(APIException) as excinfo:
418-
instances_service.action(id_list=[INSTANCE_ID], action="fluxturcate")
420+
instances_service.action(
421+
id_list=[INSTANCE_ID], action="fluxturcate")
419422

420423
# assert
421424
assert excinfo.value.code == INVALID_REQUEST
@@ -424,7 +427,8 @@ def test_action_failed(self, instances_service, endpoint):
424427

425428
def test_is_available_successful(self, instances_service):
426429
# arrange - add response mock
427-
url = instances_service._http_client._base_url + '/instance-availability/' + INSTANCE_TYPE
430+
url = instances_service._http_client._base_url + \
431+
'/instance-availability/' + INSTANCE_TYPE
428432
responses.add(
429433
responses.GET,
430434
url,
@@ -441,7 +445,8 @@ def test_is_available_successful(self, instances_service):
441445

442446
def test_is_spot_available_successful(self, instances_service):
443447
# arrange - add response mock
444-
url = instances_service._http_client._base_url + '/instance-availability/' + INSTANCE_TYPE + '?isSpot=true'
448+
url = instances_service._http_client._base_url + \
449+
'/instance-availability/' + INSTANCE_TYPE + '?isSpot=true'
445450
responses.add(
446451
responses.GET,
447452
url,
@@ -450,7 +455,8 @@ def test_is_spot_available_successful(self, instances_service):
450455
)
451456

452457
# act
453-
is_available = instances_service.is_available(INSTANCE_TYPE, is_spot=True)
458+
is_available = instances_service.is_available(
459+
INSTANCE_TYPE, is_spot=True)
454460

455461
# assert
456462
assert is_available is True
@@ -473,4 +479,4 @@ def test_is_available_failed(self, instances_service):
473479
# assert
474480
assert excinfo.value.code == INVALID_REQUEST
475481
assert excinfo.value.message == INVALID_REQUEST_MESSAGE
476-
assert responses.assert_call_count(url, 1) is True
482+
assert responses.assert_call_count(url, 1) is True

0 commit comments

Comments
 (0)