datacrunch 1.16.0__py3-none-any.whl → 1.17.2__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.
Files changed (49) hide show
  1. datacrunch/InferenceClient/__init__.py +1 -1
  2. datacrunch/InferenceClient/inference_client.py +1 -514
  3. datacrunch/__init__.py +52 -2
  4. datacrunch/authentication.py +1 -0
  5. datacrunch/balance.py +1 -0
  6. datacrunch/constants.py +1 -109
  7. datacrunch/containers.py +1 -0
  8. datacrunch/datacrunch.py +44 -81
  9. datacrunch/exceptions.py +1 -29
  10. datacrunch/helpers.py +1 -18
  11. datacrunch/http_client.py +1 -0
  12. datacrunch/images.py +1 -0
  13. datacrunch/instance_types.py +1 -0
  14. datacrunch/instances.py +1 -0
  15. datacrunch/locations.py +1 -0
  16. datacrunch/ssh_keys.py +1 -0
  17. datacrunch/startup_scripts.py +1 -0
  18. datacrunch/volume_types.py +1 -0
  19. datacrunch/volumes.py +1 -0
  20. datacrunch-1.17.2.dist-info/METADATA +30 -0
  21. datacrunch-1.17.2.dist-info/RECORD +22 -0
  22. {datacrunch-1.16.0.dist-info → datacrunch-1.17.2.dist-info}/WHEEL +1 -1
  23. datacrunch/_version.py +0 -6
  24. datacrunch/authentication/__init__.py +0 -0
  25. datacrunch/authentication/authentication.py +0 -105
  26. datacrunch/balance/__init__.py +0 -0
  27. datacrunch/balance/balance.py +0 -50
  28. datacrunch/containers/__init__.py +0 -33
  29. datacrunch/containers/containers.py +0 -1109
  30. datacrunch/http_client/__init__.py +0 -0
  31. datacrunch/http_client/http_client.py +0 -241
  32. datacrunch/images/__init__.py +0 -0
  33. datacrunch/images/images.py +0 -93
  34. datacrunch/instance_types/__init__.py +0 -0
  35. datacrunch/instance_types/instance_types.py +0 -195
  36. datacrunch/instances/__init__.py +0 -0
  37. datacrunch/instances/instances.py +0 -259
  38. datacrunch/locations/__init__.py +0 -0
  39. datacrunch/locations/locations.py +0 -15
  40. datacrunch/ssh_keys/__init__.py +0 -0
  41. datacrunch/ssh_keys/ssh_keys.py +0 -111
  42. datacrunch/startup_scripts/__init__.py +0 -0
  43. datacrunch/startup_scripts/startup_scripts.py +0 -115
  44. datacrunch/volume_types/__init__.py +0 -0
  45. datacrunch/volume_types/volume_types.py +0 -68
  46. datacrunch/volumes/__init__.py +0 -0
  47. datacrunch/volumes/volumes.py +0 -385
  48. datacrunch-1.16.0.dist-info/METADATA +0 -182
  49. datacrunch-1.16.0.dist-info/RECORD +0 -35
@@ -1,259 +0,0 @@
1
- import time
2
- import itertools
3
- from typing import List, Union, Optional, Dict, Literal
4
- from dataclasses import dataclass
5
- from dataclasses_json import dataclass_json
6
- from datacrunch.constants import Locations, InstanceStatus
7
-
8
- INSTANCES_ENDPOINT = '/instances'
9
-
10
- Contract = Literal['LONG_TERM', 'PAY_AS_YOU_GO', 'SPOT']
11
- Pricing = Literal['DYNAMIC_PRICE', 'FIXED_PRICE']
12
-
13
-
14
- @dataclass_json
15
- @dataclass
16
- class Instance:
17
- """Represents a cloud instance with its configuration and state.
18
-
19
- Attributes:
20
- id: Unique identifier for the instance.
21
- instance_type: Type of the instance (e.g., '8V100.48V').
22
- price_per_hour: Cost per hour of running the instance.
23
- hostname: Network hostname of the instance.
24
- description: Human-readable description of the instance.
25
- status: Current operational status of the instance.
26
- created_at: Timestamp of instance creation.
27
- ssh_key_ids: List of SSH key IDs associated with the instance.
28
- cpu: CPU configuration details.
29
- gpu: GPU configuration details.
30
- memory: Memory configuration details.
31
- storage: Storage configuration details.
32
- gpu_memory: GPU memory configuration details.
33
- ip: IP address assigned to the instance.
34
- os_volume_id: ID of the operating system volume.
35
- location: Datacenter location code (default: Locations.FIN_03).
36
- image: Image ID or type used for the instance.
37
- startup_script_id: ID of the startup script to run.
38
- is_spot: Whether the instance is a spot instance.
39
- contract: Contract type for the instance. (e.g. 'LONG_TERM', 'PAY_AS_YOU_GO', 'SPOT')
40
- pricing: Pricing model for the instance. (e.g. 'DYNAMIC_PRICE', 'FIXED_PRICE')
41
- """
42
-
43
- id: str
44
- instance_type: str
45
- price_per_hour: float
46
- hostname: str
47
- description: str
48
- status: str
49
- created_at: str
50
- ssh_key_ids: List[str]
51
- cpu: dict
52
- gpu: dict
53
- memory: dict
54
- storage: dict
55
- gpu_memory: dict
56
- # Can be None if instance is still not provisioned
57
- ip: Optional[str] = None
58
- # Can be None if instance is still not provisioned
59
- os_volume_id: Optional[str] = None
60
- location: str = Locations.FIN_03
61
- image: Optional[str] = None
62
- startup_script_id: Optional[str] = None
63
- is_spot: bool = False
64
- contract: Optional[Contract] = None
65
- pricing: Optional[Pricing] = None
66
-
67
-
68
- class InstancesService:
69
- """Service for managing cloud instances through the API.
70
-
71
- This service provides methods to create, retrieve, and manage cloud instances
72
- through the DataCrunch API.
73
- """
74
-
75
- def __init__(self, http_client) -> None:
76
- """Initializes the InstancesService with an HTTP client.
77
-
78
- Args:
79
- http_client: HTTP client for making API requests.
80
- """
81
- self._http_client = http_client
82
-
83
- def get(self, status: Optional[str] = None) -> List[Instance]:
84
- """Retrieves all non-deleted instances or instances with specific status.
85
-
86
- Args:
87
- status: Optional status filter for instances. If None, returns all
88
- non-deleted instances.
89
-
90
- Returns:
91
- List of instance objects matching the criteria.
92
- """
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
- ]
98
-
99
- def get_by_id(self, id: str) -> Instance:
100
- """Retrieves a specific instance by its ID.
101
-
102
- Args:
103
- id: Unique identifier of the instance to retrieve.
104
-
105
- Returns:
106
- Instance object with the specified ID.
107
-
108
- Raises:
109
- HTTPError: If the instance is not found or other API error occurs.
110
- """
111
- instance_dict = self._http_client.get(INSTANCES_ENDPOINT + f'/{id}').json()
112
- return Instance.from_dict(instance_dict, infer_missing=True)
113
-
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:
136
- """Creates and deploys a new cloud instance.
137
-
138
- Args:
139
- instance_type: Type of instance to create (e.g., '8V100.48V').
140
- image: Image type or existing OS volume ID for the instance.
141
- hostname: Network hostname for the instance.
142
- description: Human-readable description of the instance.
143
- ssh_key_ids: List of SSH key IDs to associate with the instance.
144
- location: Datacenter location code (default: Locations.FIN_03).
145
- startup_script_id: Optional ID of startup script to run.
146
- volumes: Optional list of volume configurations to create.
147
- existing_volumes: Optional list of existing volume IDs to attach.
148
- os_volume: Optional OS volume configuration details.
149
- is_spot: Whether to create a spot instance.
150
- contract: Optional contract type for the instance.
151
- pricing: Optional pricing model for the instance.
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)
157
-
158
- Returns:
159
- The newly created instance object.
160
-
161
- Raises:
162
- HTTPError: If instance creation fails or other API error occurs.
163
- """
164
- payload = {
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,
177
- }
178
- if contract:
179
- payload['contract'] = contract
180
- if pricing:
181
- payload['pricing'] = pricing
182
- id = self._http_client.post(INSTANCES_ENDPOINT, json=payload).text
183
-
184
- # Wait for instance to enter provisioning state with timeout
185
- deadline = time.monotonic() + max_wait_time
186
- for i in itertools.count():
187
- instance = self.get_by_id(id)
188
- if instance.status != InstanceStatus.ORDERED:
189
- return instance
190
-
191
- now = time.monotonic()
192
- if now >= deadline:
193
- raise TimeoutError(
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:
206
- """Performs an action on one or more instances.
207
-
208
- Args:
209
- id_list: Single instance ID or list of instance IDs to act upon.
210
- action: Action to perform on the instances.
211
- volume_ids: Optional list of volume IDs to delete.
212
-
213
- Raises:
214
- HTTPError: If the action fails or other API error occurs.
215
- """
216
- if type(id_list) is str:
217
- id_list = [id_list]
218
-
219
- payload = {'id': id_list, 'action': action, 'volume_ids': volume_ids}
220
-
221
- self._http_client.put(INSTANCES_ENDPOINT, json=payload)
222
- return
223
-
224
- def is_available(
225
- self,
226
- instance_type: str,
227
- is_spot: bool = False,
228
- location_code: Optional[str] = None,
229
- ) -> bool:
230
- """Checks if a specific instance type is available for deployment.
231
-
232
- Args:
233
- instance_type: Type of instance to check availability for.
234
- is_spot: Whether to check spot instance availability.
235
- location_code: Optional datacenter location code.
236
-
237
- Returns:
238
- True if the instance type is available, False otherwise.
239
- """
240
- is_spot = str(is_spot).lower()
241
- query_params = {'isSpot': is_spot, 'location_code': location_code}
242
- url = f'/instance-availability/{instance_type}'
243
- return self._http_client.get(url, query_params).json()
244
-
245
- def get_availabilities(
246
- self, is_spot: Optional[bool] = None, location_code: Optional[str] = None
247
- ) -> List[Dict]:
248
- """Retrieves a list of available instance types across locations.
249
-
250
- Args:
251
- is_spot: Optional flag to filter spot instance availability.
252
- location_code: Optional datacenter location code to filter by.
253
-
254
- Returns:
255
- List of available instance types and their details.
256
- """
257
- is_spot = str(is_spot).lower() if is_spot is not None else None
258
- query_params = {'isSpot': is_spot, 'locationCode': location_code}
259
- return self._http_client.get('/instance-availability', params=query_params).json()
File without changes
@@ -1,15 +0,0 @@
1
- from typing import List
2
-
3
- LOCATIONS_ENDPOINT = '/locations'
4
-
5
-
6
- class LocationsService:
7
- """A service for interacting with the locations endpoint"""
8
-
9
- def __init__(self, http_client) -> None:
10
- self._http_client = http_client
11
-
12
- def get(self) -> List[dict]:
13
- """Get all locations"""
14
- locations = self._http_client.get(LOCATIONS_ENDPOINT).json()
15
- return locations
File without changes
@@ -1,111 +0,0 @@
1
- from typing import List
2
-
3
- SSHKEYS_ENDPOINT = '/sshkeys'
4
-
5
-
6
- class SSHKey:
7
- """An SSH key model class"""
8
-
9
- def __init__(self, id: str, name: str, public_key: str) -> None:
10
- """Initialize a new SSH key object
11
-
12
- :param id: SSH key id
13
- :type id: str
14
- :param name: SSH key name
15
- :type name: str
16
- :param public_key: SSH key public key
17
- :type public_key: str
18
- """
19
- self._id = id
20
- self._name = name
21
- self._public_key = public_key
22
-
23
- @property
24
- def id(self) -> str:
25
- """Get the SSH key id
26
-
27
- :return: SSH key id
28
- :rtype: str
29
- """
30
- return self._id
31
-
32
- @property
33
- def name(self) -> str:
34
- """Get the SSH key name
35
-
36
- :return: SSH key name
37
- :rtype: str
38
- """
39
- return self._name
40
-
41
- @property
42
- def public_key(self) -> str:
43
- """Get the SSH key public key value
44
-
45
- :return: public SSH key
46
- :rtype: str
47
- """
48
- return self._public_key
49
-
50
-
51
- class SSHKeysService:
52
- """A service for interacting with the SSH keys endpoint"""
53
-
54
- def __init__(self, http_client) -> None:
55
- self._http_client = http_client
56
-
57
- def get(self) -> List[SSHKey]:
58
- """Get all of the client's SSH keys
59
-
60
- :return: list of SSH keys objects
61
- :rtype: List[SSHKey]
62
- """
63
- keys = self._http_client.get(SSHKEYS_ENDPOINT).json()
64
- keys_object_list = list(map(lambda key: SSHKey(key['id'], key['name'], key['key']), keys))
65
-
66
- return keys_object_list
67
-
68
- def get_by_id(self, id: str) -> SSHKey:
69
- """Get a specific SSH key by id.
70
-
71
- :param id: SSH key id
72
- :type id: str
73
- :return: SSHKey object
74
- :rtype: SSHKey
75
- """
76
- key_dict = self._http_client.get(SSHKEYS_ENDPOINT + f'/{id}').json()[0]
77
- key_object = SSHKey(key_dict['id'], key_dict['name'], key_dict['key'])
78
- return key_object
79
-
80
- def delete(self, id_list: List[str]) -> None:
81
- """Delete multiple SSH keys by id
82
-
83
- :param id_list: list of SSH keys ids
84
- :type id_list: List[str]
85
- """
86
- payload = {'keys': id_list}
87
- self._http_client.delete(SSHKEYS_ENDPOINT, json=payload)
88
- return
89
-
90
- def delete_by_id(self, id: str) -> None:
91
- """Delete a single SSH key by id
92
-
93
- :param id: SSH key id
94
- :type id: str
95
- """
96
- self._http_client.delete(SSHKEYS_ENDPOINT + f'/{id}')
97
- return
98
-
99
- def create(self, name: str, key: str) -> SSHKey:
100
- """Create a new SSH key
101
-
102
- :param name: SSH key name
103
- :type name: str
104
- :param key: public SSH key value
105
- :type key: str
106
- :return: new SSH key object
107
- :rtype: SSHKey
108
- """
109
- payload = {'name': name, 'key': key}
110
- id = self._http_client.post(SSHKEYS_ENDPOINT, json=payload).text
111
- return SSHKey(id, name, key)
File without changes
@@ -1,115 +0,0 @@
1
- from typing import List
2
-
3
- STARTUP_SCRIPTS_ENDPOINT = '/scripts'
4
-
5
-
6
- class StartupScript:
7
- """A startup script model class"""
8
-
9
- def __init__(self, id: str, name: str, script: str) -> None:
10
- """Initialize a new startup script object
11
-
12
- :param id: startup script id
13
- :type id: str
14
- :param name: startup script name
15
- :type name: str
16
- :param script: the actual script
17
- :type script: str
18
- """
19
- self._id = id
20
- self._name = name
21
- self._script = script
22
-
23
- @property
24
- def id(self) -> str:
25
- """Get the startup script id
26
-
27
- :return: startup script id
28
- :rtype: str
29
- """
30
- return self._id
31
-
32
- @property
33
- def name(self) -> str:
34
- """Get the startup script name
35
-
36
- :return: startup script name
37
- :rtype: str
38
- """
39
- return self._name
40
-
41
- @property
42
- def script(self) -> str:
43
- """Get the actual startup script code
44
-
45
- :return: startup script text
46
- :rtype: str
47
- """
48
- return self._script
49
-
50
-
51
- class StartupScriptsService:
52
- """A service for interacting with the startup scripts endpoint"""
53
-
54
- def __init__(self, http_client) -> None:
55
- self._http_client = http_client
56
-
57
- def get(self) -> List[StartupScript]:
58
- """Get all of the client's startup scripts
59
-
60
- :return: list of startup script objects
61
- :rtype: List[StartupScript]
62
- """
63
- scripts = self._http_client.get(STARTUP_SCRIPTS_ENDPOINT).json()
64
- scripts_objects = list(
65
- map(
66
- lambda script: StartupScript(script['id'], script['name'], script['script']),
67
- scripts,
68
- )
69
- )
70
- return scripts_objects
71
-
72
- def get_by_id(self, id) -> StartupScript:
73
- """Get a specific startup script by id.
74
-
75
- :param id: startup script id
76
- :type id: str
77
- :return: startup script object
78
- :rtype: StartupScript
79
- """
80
- script = self._http_client.get(STARTUP_SCRIPTS_ENDPOINT + f'/{id}').json()[0]
81
-
82
- return StartupScript(script['id'], script['name'], script['script'])
83
-
84
- def delete(self, id_list: List[str]) -> None:
85
- """Delete multiple startup scripts by id
86
-
87
- :param id_list: list of startup scripts ids
88
- :type id_list: List[str]
89
- """
90
- payload = {'scripts': id_list}
91
- self._http_client.delete(STARTUP_SCRIPTS_ENDPOINT, json=payload)
92
- return
93
-
94
- def delete_by_id(self, id: str) -> None:
95
- """Delete a single startup script by id
96
-
97
- :param id: startup script id
98
- :type id: str
99
- """
100
- self._http_client.delete(STARTUP_SCRIPTS_ENDPOINT + f'/{id}')
101
- return
102
-
103
- def create(self, name: str, script: str) -> StartupScript:
104
- """Create a new startup script
105
-
106
- :param name: startup script name
107
- :type name: str
108
- :param script: startup script value
109
- :type script: str
110
- :return: the new startup script's id
111
- :rtype: str
112
- """
113
- payload = {'name': name, 'script': script}
114
- id = self._http_client.post(STARTUP_SCRIPTS_ENDPOINT, json=payload).text
115
- return StartupScript(id, name, script)
File without changes
@@ -1,68 +0,0 @@
1
- from typing import List
2
-
3
- VOLUME_TYPES_ENDPOINT = '/volume-types'
4
-
5
-
6
- class VolumeType:
7
- def __init__(self, type: str, price_per_month_per_gb: float) -> None:
8
- """Initialize a volume type object
9
-
10
- :param type: volume type name
11
- :type type: str
12
- :param price_per_month_per_gb: price per month per gb of storage
13
- :type price_per_month_per_gb: float
14
- """
15
- self._type = type
16
- self._price_per_month_per_gb = price_per_month_per_gb
17
-
18
- @property
19
- def type(self) -> str:
20
- """Get the volume type
21
-
22
- :return: volume type
23
- :rtype: str
24
- """
25
- return self._type
26
-
27
- @property
28
- def price_per_month_per_gb(self) -> str:
29
- """Get the volume price_per_month_per_gb
30
-
31
- :return: volume price_per_month_per_gb
32
- :rtype: str
33
- """
34
- return self._price_per_month_per_gb
35
-
36
- def __str__(self) -> str:
37
- """Prints the volume type
38
-
39
- :return: volume type string representation
40
- :rtype: str
41
- """
42
- return f'type: {self._type}\nprice_per_month_per_gb: ${self._price_per_month_per_gb}'
43
-
44
-
45
- class VolumeTypesService:
46
- """A service for interacting with the volume-types endpoint"""
47
-
48
- def __init__(self, http_client) -> None:
49
- self._http_client = http_client
50
-
51
- def get(self) -> List[VolumeType]:
52
- """Get all volume types
53
-
54
- :return: list of volume type objects
55
- :rtype: List[VolumesType]
56
- """
57
- volume_types = self._http_client.get(VOLUME_TYPES_ENDPOINT).json()
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
- )
67
-
68
- return volume_type_objects
File without changes