datacrunch 1.14.0__py3-none-any.whl → 1.16.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- datacrunch/InferenceClient/inference_client.py +200 -65
- datacrunch/__init__.py +2 -0
- datacrunch/_version.py +6 -0
- datacrunch/authentication/authentication.py +7 -14
- datacrunch/balance/balance.py +1 -3
- datacrunch/constants.py +19 -17
- datacrunch/containers/containers.py +151 -123
- datacrunch/datacrunch.py +18 -18
- datacrunch/helpers.py +7 -2
- datacrunch/http_client/http_client.py +14 -14
- datacrunch/images/images.py +9 -3
- datacrunch/instance_types/instance_types.py +42 -35
- datacrunch/instances/instances.py +74 -53
- datacrunch/locations/locations.py +1 -2
- datacrunch/ssh_keys/ssh_keys.py +3 -4
- datacrunch/startup_scripts/startup_scripts.py +10 -8
- datacrunch/volume_types/volume_types.py +10 -8
- datacrunch/volumes/volumes.py +60 -73
- {datacrunch-1.14.0.dist-info → datacrunch-1.16.0.dist-info}/METADATA +46 -72
- datacrunch-1.16.0.dist-info/RECORD +35 -0
- datacrunch-1.16.0.dist-info/WHEEL +4 -0
- datacrunch/__version__.py +0 -1
- datacrunch-1.14.0.dist-info/RECORD +0 -69
- datacrunch-1.14.0.dist-info/WHEEL +0 -5
- datacrunch-1.14.0.dist-info/licenses/LICENSE +0 -21
- datacrunch-1.14.0.dist-info/top_level.txt +0 -2
- tests/__init__.py +0 -0
- tests/integration_tests/__init__.py +0 -0
- tests/integration_tests/conftest.py +0 -20
- tests/integration_tests/test_instances.py +0 -36
- tests/integration_tests/test_locations.py +0 -65
- tests/integration_tests/test_volumes.py +0 -94
- tests/unit_tests/__init__.py +0 -0
- tests/unit_tests/authentication/__init__.py +0 -0
- tests/unit_tests/authentication/test_authentication.py +0 -202
- tests/unit_tests/balance/__init__.py +0 -0
- tests/unit_tests/balance/test_balance.py +0 -25
- tests/unit_tests/conftest.py +0 -21
- tests/unit_tests/containers/__init__.py +0 -1
- tests/unit_tests/containers/test_containers.py +0 -959
- tests/unit_tests/http_client/__init__.py +0 -0
- tests/unit_tests/http_client/test_http_client.py +0 -193
- tests/unit_tests/images/__init__.py +0 -0
- tests/unit_tests/images/test_images.py +0 -41
- tests/unit_tests/instance_types/__init__.py +0 -0
- tests/unit_tests/instance_types/test_instance_types.py +0 -87
- tests/unit_tests/instances/__init__.py +0 -0
- tests/unit_tests/instances/test_instances.py +0 -483
- tests/unit_tests/ssh_keys/__init__.py +0 -0
- tests/unit_tests/ssh_keys/test_ssh_keys.py +0 -198
- tests/unit_tests/startup_scripts/__init__.py +0 -0
- tests/unit_tests/startup_scripts/test_startup_scripts.py +0 -196
- tests/unit_tests/test_datacrunch.py +0 -65
- tests/unit_tests/test_exceptions.py +0 -33
- tests/unit_tests/volume_types/__init__.py +0 -0
- tests/unit_tests/volume_types/test_volume_types.py +0 -50
- tests/unit_tests/volumes/__init__.py +0 -0
- tests/unit_tests/volumes/test_volumes.py +0 -641
|
@@ -2,7 +2,7 @@ import requests
|
|
|
2
2
|
import json
|
|
3
3
|
|
|
4
4
|
from datacrunch.exceptions import APIException
|
|
5
|
-
from datacrunch.
|
|
5
|
+
from datacrunch._version import __version__
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
def handle_error(response: requests.Response) -> None:
|
|
@@ -27,7 +27,7 @@ class HTTPClient:
|
|
|
27
27
|
"""
|
|
28
28
|
|
|
29
29
|
def __init__(self, auth_service, base_url: str) -> None:
|
|
30
|
-
self._version =
|
|
30
|
+
self._version = __version__
|
|
31
31
|
self._base_url = base_url
|
|
32
32
|
self._auth_service = auth_service
|
|
33
33
|
self._auth_service.authenticate()
|
|
@@ -56,8 +56,7 @@ class HTTPClient:
|
|
|
56
56
|
url = self._add_base_url(url)
|
|
57
57
|
headers = self._generate_headers()
|
|
58
58
|
|
|
59
|
-
response = requests.post(
|
|
60
|
-
url, json=json, headers=headers, params=params, **kwargs)
|
|
59
|
+
response = requests.post(url, json=json, headers=headers, params=params, **kwargs)
|
|
61
60
|
handle_error(response)
|
|
62
61
|
|
|
63
62
|
return response
|
|
@@ -86,8 +85,7 @@ class HTTPClient:
|
|
|
86
85
|
url = self._add_base_url(url)
|
|
87
86
|
headers = self._generate_headers()
|
|
88
87
|
|
|
89
|
-
response = requests.put(
|
|
90
|
-
url, json=json, headers=headers, params=params, **kwargs)
|
|
88
|
+
response = requests.put(url, json=json, headers=headers, params=params, **kwargs)
|
|
91
89
|
handle_error(response)
|
|
92
90
|
|
|
93
91
|
return response
|
|
@@ -119,7 +117,9 @@ class HTTPClient:
|
|
|
119
117
|
|
|
120
118
|
return response
|
|
121
119
|
|
|
122
|
-
def patch(
|
|
120
|
+
def patch(
|
|
121
|
+
self, url: str, json: dict = None, params: dict = None, **kwargs
|
|
122
|
+
) -> requests.Response:
|
|
123
123
|
"""Sends a PATCH request.
|
|
124
124
|
|
|
125
125
|
A wrapper for the requests.patch method.
|
|
@@ -143,13 +143,14 @@ class HTTPClient:
|
|
|
143
143
|
url = self._add_base_url(url)
|
|
144
144
|
headers = self._generate_headers()
|
|
145
145
|
|
|
146
|
-
response = requests.patch(
|
|
147
|
-
url, json=json, headers=headers, params=params, **kwargs)
|
|
146
|
+
response = requests.patch(url, json=json, headers=headers, params=params, **kwargs)
|
|
148
147
|
handle_error(response)
|
|
149
148
|
|
|
150
149
|
return response
|
|
151
150
|
|
|
152
|
-
def delete(
|
|
151
|
+
def delete(
|
|
152
|
+
self, url: str, json: dict = None, params: dict = None, **kwargs
|
|
153
|
+
) -> requests.Response:
|
|
153
154
|
"""Sends a DELETE request.
|
|
154
155
|
|
|
155
156
|
A wrapper for the requests.delete method.
|
|
@@ -173,8 +174,7 @@ class HTTPClient:
|
|
|
173
174
|
url = self._add_base_url(url)
|
|
174
175
|
headers = self._generate_headers()
|
|
175
176
|
|
|
176
|
-
response = requests.delete(
|
|
177
|
-
url, headers=headers, json=json, params=params, **kwargs)
|
|
177
|
+
response = requests.delete(url, headers=headers, json=json, params=params, **kwargs)
|
|
178
178
|
handle_error(response)
|
|
179
179
|
|
|
180
180
|
return response
|
|
@@ -186,7 +186,7 @@ class HTTPClient:
|
|
|
186
186
|
|
|
187
187
|
:raises APIException: an api exception with message and error type code
|
|
188
188
|
"""
|
|
189
|
-
if
|
|
189
|
+
if self._auth_service.is_expired():
|
|
190
190
|
# try to refresh. if refresh token has expired, reauthenticate
|
|
191
191
|
try:
|
|
192
192
|
self._auth_service.refresh()
|
|
@@ -202,7 +202,7 @@ class HTTPClient:
|
|
|
202
202
|
headers = {
|
|
203
203
|
'Authorization': self._generate_bearer_header(),
|
|
204
204
|
'User-Agent': self._generate_user_agent(),
|
|
205
|
-
'Content-Type': 'application/json'
|
|
205
|
+
'Content-Type': 'application/json',
|
|
206
206
|
}
|
|
207
207
|
return headers
|
|
208
208
|
|
datacrunch/images/images.py
CHANGED
|
@@ -76,12 +76,18 @@ class ImagesService:
|
|
|
76
76
|
self._http_client = http_client
|
|
77
77
|
|
|
78
78
|
def get(self) -> List[Image]:
|
|
79
|
-
"""Get the available instance images
|
|
79
|
+
"""Get the available instance images
|
|
80
80
|
|
|
81
81
|
:return: list of images objects
|
|
82
82
|
:rtype: List[Image]
|
|
83
83
|
"""
|
|
84
84
|
images = self._http_client.get(IMAGES_ENDPOINT).json()
|
|
85
|
-
image_objects = list(
|
|
86
|
-
|
|
85
|
+
image_objects = list(
|
|
86
|
+
map(
|
|
87
|
+
lambda image: Image(
|
|
88
|
+
image['id'], image['name'], image['image_type'], image['details']
|
|
89
|
+
),
|
|
90
|
+
images,
|
|
91
|
+
)
|
|
92
|
+
)
|
|
87
93
|
return image_objects
|
|
@@ -4,18 +4,19 @@ INSTANCE_TYPES_ENDPOINT = '/instance-types'
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
class InstanceType:
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
7
|
+
def __init__(
|
|
8
|
+
self,
|
|
9
|
+
id: str,
|
|
10
|
+
instance_type: str,
|
|
11
|
+
price_per_hour: float,
|
|
12
|
+
spot_price_per_hour: float,
|
|
13
|
+
description: str,
|
|
14
|
+
cpu: dict,
|
|
15
|
+
gpu: dict,
|
|
16
|
+
memory: dict,
|
|
17
|
+
gpu_memory: dict,
|
|
18
|
+
storage: dict,
|
|
19
|
+
) -> None:
|
|
19
20
|
"""Initialize an instance type object
|
|
20
21
|
|
|
21
22
|
:param id: instance type id
|
|
@@ -146,17 +147,18 @@ class InstanceType:
|
|
|
146
147
|
:return: instance type string representation
|
|
147
148
|
:rtype: str
|
|
148
149
|
"""
|
|
149
|
-
return (
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
150
|
+
return (
|
|
151
|
+
f'id: {self._id}\n'
|
|
152
|
+
f'instance type: {self._instance_type}\n'
|
|
153
|
+
f'price_per_hour: ${self._price_per_hour}\n'
|
|
154
|
+
f'spot_price_per_hour: ${self._spot_price_per_hour}\n'
|
|
155
|
+
f'description: {self._description}\n'
|
|
156
|
+
f'cpu: {self._cpu}\n'
|
|
157
|
+
f'gpu: {self._gpu}\n'
|
|
158
|
+
f'memory :{self._memory}\n'
|
|
159
|
+
f'gpu_memory :{self._gpu_memory}\n'
|
|
160
|
+
f'storage :{self._storage}\n'
|
|
161
|
+
)
|
|
160
162
|
|
|
161
163
|
|
|
162
164
|
class InstanceTypesService:
|
|
@@ -172,17 +174,22 @@ class InstanceTypesService:
|
|
|
172
174
|
:rtype: List[InstanceType]
|
|
173
175
|
"""
|
|
174
176
|
instance_types = self._http_client.get(INSTANCE_TYPES_ENDPOINT).json()
|
|
175
|
-
instance_type_objects = list(
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
177
|
+
instance_type_objects = list(
|
|
178
|
+
map(
|
|
179
|
+
lambda instance_type: InstanceType(
|
|
180
|
+
id=instance_type['id'],
|
|
181
|
+
instance_type=instance_type['instance_type'],
|
|
182
|
+
price_per_hour=instance_type['price_per_hour'],
|
|
183
|
+
spot_price_per_hour=instance_type['spot_price'],
|
|
184
|
+
description=instance_type['description'],
|
|
185
|
+
cpu=instance_type['cpu'],
|
|
186
|
+
gpu=instance_type['gpu'],
|
|
187
|
+
memory=instance_type['memory'],
|
|
188
|
+
gpu_memory=instance_type['gpu_memory'],
|
|
189
|
+
storage=instance_type['storage'],
|
|
190
|
+
),
|
|
191
|
+
instance_types,
|
|
192
|
+
)
|
|
193
|
+
)
|
|
187
194
|
|
|
188
195
|
return instance_type_objects
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import time
|
|
2
|
+
import itertools
|
|
2
3
|
from typing import List, Union, Optional, Dict, Literal
|
|
3
4
|
from dataclasses import dataclass
|
|
4
5
|
from dataclasses_json import dataclass_json
|
|
@@ -31,7 +32,7 @@ class Instance:
|
|
|
31
32
|
gpu_memory: GPU memory configuration details.
|
|
32
33
|
ip: IP address assigned to the instance.
|
|
33
34
|
os_volume_id: ID of the operating system volume.
|
|
34
|
-
location: Datacenter location code (default: Locations.
|
|
35
|
+
location: Datacenter location code (default: Locations.FIN_03).
|
|
35
36
|
image: Image ID or type used for the instance.
|
|
36
37
|
startup_script_id: ID of the startup script to run.
|
|
37
38
|
is_spot: Whether the instance is a spot instance.
|
|
@@ -56,7 +57,7 @@ class Instance:
|
|
|
56
57
|
ip: Optional[str] = None
|
|
57
58
|
# Can be None if instance is still not provisioned
|
|
58
59
|
os_volume_id: Optional[str] = None
|
|
59
|
-
location: str = Locations.
|
|
60
|
+
location: str = Locations.FIN_03
|
|
60
61
|
image: Optional[str] = None
|
|
61
62
|
startup_script_id: Optional[str] = None
|
|
62
63
|
is_spot: bool = False
|
|
@@ -89,9 +90,11 @@ class InstancesService:
|
|
|
89
90
|
Returns:
|
|
90
91
|
List of instance objects matching the criteria.
|
|
91
92
|
"""
|
|
92
|
-
instances_dict = self._http_client.get(
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
instances_dict = self._http_client.get(INSTANCES_ENDPOINT, params={'status': status}).json()
|
|
94
|
+
return [
|
|
95
|
+
Instance.from_dict(instance_dict, infer_missing=True)
|
|
96
|
+
for instance_dict in instances_dict
|
|
97
|
+
]
|
|
95
98
|
|
|
96
99
|
def get_by_id(self, id: str) -> Instance:
|
|
97
100
|
"""Retrieves a specific instance by its ID.
|
|
@@ -105,25 +108,31 @@ class InstancesService:
|
|
|
105
108
|
Raises:
|
|
106
109
|
HTTPError: If the instance is not found or other API error occurs.
|
|
107
110
|
"""
|
|
108
|
-
instance_dict = self._http_client.get(
|
|
109
|
-
INSTANCES_ENDPOINT + f'/{id}').json()
|
|
111
|
+
instance_dict = self._http_client.get(INSTANCES_ENDPOINT + f'/{id}').json()
|
|
110
112
|
return Instance.from_dict(instance_dict, infer_missing=True)
|
|
111
113
|
|
|
112
|
-
def create(
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
114
|
+
def create(
|
|
115
|
+
self,
|
|
116
|
+
instance_type: str,
|
|
117
|
+
image: str,
|
|
118
|
+
hostname: str,
|
|
119
|
+
description: str,
|
|
120
|
+
ssh_key_ids: list = [],
|
|
121
|
+
location: str = Locations.FIN_03,
|
|
122
|
+
startup_script_id: Optional[str] = None,
|
|
123
|
+
volumes: Optional[List[Dict]] = None,
|
|
124
|
+
existing_volumes: Optional[List[str]] = None,
|
|
125
|
+
os_volume: Optional[Dict] = None,
|
|
126
|
+
is_spot: bool = False,
|
|
127
|
+
contract: Optional[Contract] = None,
|
|
128
|
+
pricing: Optional[Pricing] = None,
|
|
129
|
+
coupon: Optional[str] = None,
|
|
130
|
+
*,
|
|
131
|
+
max_wait_time: float = 180,
|
|
132
|
+
initial_interval: float = 0.5,
|
|
133
|
+
max_interval: float = 5,
|
|
134
|
+
backoff_coefficient: float = 2.0,
|
|
135
|
+
) -> Instance:
|
|
127
136
|
"""Creates and deploys a new cloud instance.
|
|
128
137
|
|
|
129
138
|
Args:
|
|
@@ -132,7 +141,7 @@ class InstancesService:
|
|
|
132
141
|
hostname: Network hostname for the instance.
|
|
133
142
|
description: Human-readable description of the instance.
|
|
134
143
|
ssh_key_ids: List of SSH key IDs to associate with the instance.
|
|
135
|
-
location: Datacenter location code (default: Locations.
|
|
144
|
+
location: Datacenter location code (default: Locations.FIN_03).
|
|
136
145
|
startup_script_id: Optional ID of startup script to run.
|
|
137
146
|
volumes: Optional list of volume configurations to create.
|
|
138
147
|
existing_volumes: Optional list of existing volume IDs to attach.
|
|
@@ -141,6 +150,10 @@ class InstancesService:
|
|
|
141
150
|
contract: Optional contract type for the instance.
|
|
142
151
|
pricing: Optional pricing model for the instance.
|
|
143
152
|
coupon: Optional coupon code for discounts.
|
|
153
|
+
max_wait_time: Maximum total wait for the instance to start provisioning, in seconds (default: 180)
|
|
154
|
+
initial_interval: Initial interval, in seconds (default: 0.5)
|
|
155
|
+
max_interval: The longest single delay allowed between retries, in seconds (default: 5)
|
|
156
|
+
backoff_coefficient: Coefficient to calculate the next retry interval (default 2.0)
|
|
144
157
|
|
|
145
158
|
Returns:
|
|
146
159
|
The newly created instance object.
|
|
@@ -149,18 +162,18 @@ class InstancesService:
|
|
|
149
162
|
HTTPError: If instance creation fails or other API error occurs.
|
|
150
163
|
"""
|
|
151
164
|
payload = {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
165
|
+
'instance_type': instance_type,
|
|
166
|
+
'image': image,
|
|
167
|
+
'ssh_key_ids': ssh_key_ids,
|
|
168
|
+
'startup_script_id': startup_script_id,
|
|
169
|
+
'hostname': hostname,
|
|
170
|
+
'description': description,
|
|
171
|
+
'location_code': location,
|
|
172
|
+
'os_volume': os_volume,
|
|
173
|
+
'volumes': volumes,
|
|
174
|
+
'existing_volumes': existing_volumes,
|
|
175
|
+
'is_spot': is_spot,
|
|
176
|
+
'coupon': coupon,
|
|
164
177
|
}
|
|
165
178
|
if contract:
|
|
166
179
|
payload['contract'] = contract
|
|
@@ -169,22 +182,27 @@ class InstancesService:
|
|
|
169
182
|
id = self._http_client.post(INSTANCES_ENDPOINT, json=payload).text
|
|
170
183
|
|
|
171
184
|
# Wait for instance to enter provisioning state with timeout
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
start_time = time.time()
|
|
176
|
-
while True:
|
|
185
|
+
deadline = time.monotonic() + max_wait_time
|
|
186
|
+
for i in itertools.count():
|
|
177
187
|
instance = self.get_by_id(id)
|
|
178
188
|
if instance.status != InstanceStatus.ORDERED:
|
|
179
189
|
return instance
|
|
180
190
|
|
|
181
|
-
|
|
191
|
+
now = time.monotonic()
|
|
192
|
+
if now >= deadline:
|
|
182
193
|
raise TimeoutError(
|
|
183
|
-
f
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
194
|
+
f'Instance {id} did not enter provisioning state within {max_wait_time:.1f} seconds'
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
interval = min(initial_interval * backoff_coefficient**i, max_interval, deadline - now)
|
|
198
|
+
time.sleep(interval)
|
|
199
|
+
|
|
200
|
+
def action(
|
|
201
|
+
self,
|
|
202
|
+
id_list: Union[List[str], str],
|
|
203
|
+
action: str,
|
|
204
|
+
volume_ids: Optional[List[str]] = None,
|
|
205
|
+
) -> None:
|
|
188
206
|
"""Performs an action on one or more instances.
|
|
189
207
|
|
|
190
208
|
Args:
|
|
@@ -198,16 +216,17 @@ class InstancesService:
|
|
|
198
216
|
if type(id_list) is str:
|
|
199
217
|
id_list = [id_list]
|
|
200
218
|
|
|
201
|
-
payload = {
|
|
202
|
-
"id": id_list,
|
|
203
|
-
"action": action,
|
|
204
|
-
"volume_ids": volume_ids
|
|
205
|
-
}
|
|
219
|
+
payload = {'id': id_list, 'action': action, 'volume_ids': volume_ids}
|
|
206
220
|
|
|
207
221
|
self._http_client.put(INSTANCES_ENDPOINT, json=payload)
|
|
208
222
|
return
|
|
209
223
|
|
|
210
|
-
def is_available(
|
|
224
|
+
def is_available(
|
|
225
|
+
self,
|
|
226
|
+
instance_type: str,
|
|
227
|
+
is_spot: bool = False,
|
|
228
|
+
location_code: Optional[str] = None,
|
|
229
|
+
) -> bool:
|
|
211
230
|
"""Checks if a specific instance type is available for deployment.
|
|
212
231
|
|
|
213
232
|
Args:
|
|
@@ -223,7 +242,9 @@ class InstancesService:
|
|
|
223
242
|
url = f'/instance-availability/{instance_type}'
|
|
224
243
|
return self._http_client.get(url, query_params).json()
|
|
225
244
|
|
|
226
|
-
def get_availabilities(
|
|
245
|
+
def get_availabilities(
|
|
246
|
+
self, is_spot: Optional[bool] = None, location_code: Optional[str] = None
|
|
247
|
+
) -> List[Dict]:
|
|
227
248
|
"""Retrieves a list of available instance types across locations.
|
|
228
249
|
|
|
229
250
|
Args:
|
datacrunch/ssh_keys/ssh_keys.py
CHANGED
|
@@ -61,8 +61,7 @@ class SSHKeysService:
|
|
|
61
61
|
:rtype: List[SSHKey]
|
|
62
62
|
"""
|
|
63
63
|
keys = self._http_client.get(SSHKEYS_ENDPOINT).json()
|
|
64
|
-
keys_object_list = list(map(lambda key: SSHKey(
|
|
65
|
-
key['id'], key['name'], key['key']), keys))
|
|
64
|
+
keys_object_list = list(map(lambda key: SSHKey(key['id'], key['name'], key['key']), keys))
|
|
66
65
|
|
|
67
66
|
return keys_object_list
|
|
68
67
|
|
|
@@ -84,7 +83,7 @@ class SSHKeysService:
|
|
|
84
83
|
:param id_list: list of SSH keys ids
|
|
85
84
|
:type id_list: List[str]
|
|
86
85
|
"""
|
|
87
|
-
payload = {
|
|
86
|
+
payload = {'keys': id_list}
|
|
88
87
|
self._http_client.delete(SSHKEYS_ENDPOINT, json=payload)
|
|
89
88
|
return
|
|
90
89
|
|
|
@@ -107,6 +106,6 @@ class SSHKeysService:
|
|
|
107
106
|
:return: new SSH key object
|
|
108
107
|
:rtype: SSHKey
|
|
109
108
|
"""
|
|
110
|
-
payload = {
|
|
109
|
+
payload = {'name': name, 'key': key}
|
|
111
110
|
id = self._http_client.post(SSHKEYS_ENDPOINT, json=payload).text
|
|
112
111
|
return SSHKey(id, name, key)
|
|
@@ -61,8 +61,12 @@ class StartupScriptsService:
|
|
|
61
61
|
:rtype: List[StartupScript]
|
|
62
62
|
"""
|
|
63
63
|
scripts = self._http_client.get(STARTUP_SCRIPTS_ENDPOINT).json()
|
|
64
|
-
scripts_objects = list(
|
|
65
|
-
|
|
64
|
+
scripts_objects = list(
|
|
65
|
+
map(
|
|
66
|
+
lambda script: StartupScript(script['id'], script['name'], script['script']),
|
|
67
|
+
scripts,
|
|
68
|
+
)
|
|
69
|
+
)
|
|
66
70
|
return scripts_objects
|
|
67
71
|
|
|
68
72
|
def get_by_id(self, id) -> StartupScript:
|
|
@@ -73,8 +77,7 @@ class StartupScriptsService:
|
|
|
73
77
|
:return: startup script object
|
|
74
78
|
:rtype: StartupScript
|
|
75
79
|
"""
|
|
76
|
-
script = self._http_client.get(
|
|
77
|
-
STARTUP_SCRIPTS_ENDPOINT + f'/{id}').json()[0]
|
|
80
|
+
script = self._http_client.get(STARTUP_SCRIPTS_ENDPOINT + f'/{id}').json()[0]
|
|
78
81
|
|
|
79
82
|
return StartupScript(script['id'], script['name'], script['script'])
|
|
80
83
|
|
|
@@ -84,7 +87,7 @@ class StartupScriptsService:
|
|
|
84
87
|
:param id_list: list of startup scripts ids
|
|
85
88
|
:type id_list: List[str]
|
|
86
89
|
"""
|
|
87
|
-
payload = {
|
|
90
|
+
payload = {'scripts': id_list}
|
|
88
91
|
self._http_client.delete(STARTUP_SCRIPTS_ENDPOINT, json=payload)
|
|
89
92
|
return
|
|
90
93
|
|
|
@@ -107,7 +110,6 @@ class StartupScriptsService:
|
|
|
107
110
|
:return: the new startup script's id
|
|
108
111
|
:rtype: str
|
|
109
112
|
"""
|
|
110
|
-
payload = {
|
|
111
|
-
id = self._http_client.post(
|
|
112
|
-
STARTUP_SCRIPTS_ENDPOINT, json=payload).text
|
|
113
|
+
payload = {'name': name, 'script': script}
|
|
114
|
+
id = self._http_client.post(STARTUP_SCRIPTS_ENDPOINT, json=payload).text
|
|
113
115
|
return StartupScript(id, name, script)
|
|
@@ -4,10 +4,7 @@ VOLUME_TYPES_ENDPOINT = '/volume-types'
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
class VolumeType:
|
|
7
|
-
|
|
8
|
-
def __init__(self,
|
|
9
|
-
type: str,
|
|
10
|
-
price_per_month_per_gb: float) -> None:
|
|
7
|
+
def __init__(self, type: str, price_per_month_per_gb: float) -> None:
|
|
11
8
|
"""Initialize a volume type object
|
|
12
9
|
|
|
13
10
|
:param type: volume type name
|
|
@@ -58,9 +55,14 @@ class VolumeTypesService:
|
|
|
58
55
|
:rtype: List[VolumesType]
|
|
59
56
|
"""
|
|
60
57
|
volume_types = self._http_client.get(VOLUME_TYPES_ENDPOINT).json()
|
|
61
|
-
volume_type_objects = list(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
58
|
+
volume_type_objects = list(
|
|
59
|
+
map(
|
|
60
|
+
lambda volume_type: VolumeType(
|
|
61
|
+
type=volume_type['type'],
|
|
62
|
+
price_per_month_per_gb=volume_type['price']['price_per_month_per_gb'],
|
|
63
|
+
),
|
|
64
|
+
volume_types,
|
|
65
|
+
)
|
|
66
|
+
)
|
|
65
67
|
|
|
66
68
|
return volume_type_objects
|