qarnot 2.18.0__tar.gz → 2.20.1__tar.gz
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.
- {qarnot-2.18.0/qarnot.egg-info → qarnot-2.20.1}/PKG-INFO +1 -1
- {qarnot-2.18.0 → qarnot-2.20.1}/qarnot/__init__.py +1 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/qarnot/_version.py +3 -3
- {qarnot-2.18.0 → qarnot-2.20.1}/qarnot/computing_quotas.py +16 -4
- {qarnot-2.18.0 → qarnot-2.20.1}/qarnot/forced_network_rule.py +41 -14
- qarnot-2.20.1/qarnot/multi_slots_settings.py +48 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/qarnot/pool.py +52 -0
- qarnot-2.20.1/qarnot/snapshot.py +244 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/qarnot/task.py +122 -6
- {qarnot-2.18.0 → qarnot-2.20.1/qarnot.egg-info}/PKG-INFO +1 -1
- {qarnot-2.18.0 → qarnot-2.20.1}/qarnot.egg-info/SOURCES.txt +3 -0
- qarnot-2.20.1/requirements.txt +6 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/test/test_pool.py +40 -1
- qarnot-2.20.1/test/test_snapshot_status.py +74 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/test/test_task.py +13 -1
- qarnot-2.18.0/requirements.txt +0 -6
- {qarnot-2.18.0 → qarnot-2.20.1}/LICENSE +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/MANIFEST.in +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/README.rst +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/doc/Makefile +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/doc/make.bat +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/doc/source/_static/qarnot.png +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/doc/source/api/compute/carbon_facts.rst +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/doc/source/api/compute/computeindex.rst +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/doc/source/api/compute/computing_quotas.rst +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/doc/source/api/compute/forced_network_rule.rst +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/doc/source/api/compute/hardware_constraint.rst +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/doc/source/api/compute/job.rst +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/doc/source/api/compute/paginate.rst +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/doc/source/api/compute/pool.rst +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/doc/source/api/compute/privileges.rst +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/doc/source/api/compute/retry_settings.rst +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/doc/source/api/compute/scheduling_type.rst +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/doc/source/api/compute/secrets.rst +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/doc/source/api/compute/status.rst +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/doc/source/api/compute/task.rst +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/doc/source/api/connection.rst +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/doc/source/api/exceptions.rst +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/doc/source/api/storage/advanced_bucket.rst +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/doc/source/api/storage/bucket.rst +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/doc/source/api/storage/storage.rst +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/doc/source/api/storage/storageindex.rst +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/doc/source/basic.rst +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/doc/source/conf.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/doc/source/index.rst +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/doc/source/installation.rst +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/doc/source/qarnot.rst +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/pyproject.toml +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/qarnot/_filter.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/qarnot/_retry.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/qarnot/_util.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/qarnot/advanced_bucket.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/qarnot/bucket.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/qarnot/carbon_facts.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/qarnot/connection.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/qarnot/error.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/qarnot/exceptions.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/qarnot/forced_constant.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/qarnot/hardware_constraint.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/qarnot/helper.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/qarnot/job.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/qarnot/paginate.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/qarnot/privileges.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/qarnot/retry_settings.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/qarnot/scheduling_type.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/qarnot/secrets.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/qarnot/status.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/qarnot/storage.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/qarnot.egg-info/dependency_links.txt +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/qarnot.egg-info/requires.txt +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/qarnot.egg-info/top_level.txt +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/requirements-doc.txt +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/requirements-lint.txt +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/requirements-optional.txt +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/requirements-test.txt +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/setup.cfg +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/setup.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/test/test_advanced_bucket.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/test/test_bucket.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/test/test_carbon_facts.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/test/test_connection.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/test/test_hardware_constraints.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/test/test_import.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/test/test_job.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/test/test_paginate.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/test/test_retry.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/test/test_secrets.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/test/test_status.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/test/test_util.py +0 -0
- {qarnot-2.18.0 → qarnot-2.20.1}/versioneer.py +0 -0
|
@@ -62,6 +62,7 @@ def get_url(key, **kwargs):
|
|
|
62
62
|
'task update': '/tasks/{uuid}', # GET->result; DELETE -> abort, PATCH -> update resources
|
|
63
63
|
'task snapshot': '/tasks/{uuid}/snapshot/periodic', # POST -> snapshots
|
|
64
64
|
'task instant': '/tasks/{uuid}/snapshot', # POST -> get a snapshot
|
|
65
|
+
'task instant status': '/tasks/{uuid}/snapshot/{snapshotId}', # GET -> get a snapshot status
|
|
65
66
|
'task stdout': '/tasks/{uuid}/stdout', # GET -> task stdout
|
|
66
67
|
'task stderr': '/tasks/{uuid}/stderr', # GET -> task stderr
|
|
67
68
|
'task instance stdout': '/tasks/{uuid}/stdout/{instanceId}', # GET -> task instance stdout
|
|
@@ -8,11 +8,11 @@ import json
|
|
|
8
8
|
|
|
9
9
|
version_json = '''
|
|
10
10
|
{
|
|
11
|
-
"date": "
|
|
11
|
+
"date": "2026-02-06T11:26:35+0100",
|
|
12
12
|
"dirty": false,
|
|
13
13
|
"error": null,
|
|
14
|
-
"full-revisionid": "
|
|
15
|
-
"version": "v2.
|
|
14
|
+
"full-revisionid": "a21d5058a77a68da123d95dd64550400fafb2bd2",
|
|
15
|
+
"version": "v2.20.1"
|
|
16
16
|
}
|
|
17
17
|
''' # END VERSION_JSON
|
|
18
18
|
|
|
@@ -70,7 +70,7 @@ class UserReservedSchedulingQuota(UserSchedulingQuota):
|
|
|
70
70
|
"""Describes a reserved scheduling quota for the user.
|
|
71
71
|
"""
|
|
72
72
|
|
|
73
|
-
def __init__(self, machine_key: str, max_cores: int, running_cores_count: int, max_instances: int, running_instances_count: int):
|
|
73
|
+
def __init__(self, reservation_name: str, machine_key: str, max_cores: int, running_cores_count: int, max_instances: int, running_instances_count: int):
|
|
74
74
|
"""Create a new UserReservedSchedulingQuota object describing a reserved scheduling quota for the user.
|
|
75
75
|
|
|
76
76
|
:param str machine_key: Machine key of the reservation.
|
|
@@ -86,6 +86,11 @@ class UserReservedSchedulingQuota(UserSchedulingQuota):
|
|
|
86
86
|
|
|
87
87
|
Machine key of the reservation.
|
|
88
88
|
"""
|
|
89
|
+
self.reservation_name = reservation_name
|
|
90
|
+
""":type: :class:`str`
|
|
91
|
+
|
|
92
|
+
Name of the reservation.
|
|
93
|
+
"""
|
|
89
94
|
|
|
90
95
|
@classmethod
|
|
91
96
|
def from_json(cls, json: Dict[str, Any]):
|
|
@@ -97,6 +102,7 @@ class UserReservedSchedulingQuota(UserSchedulingQuota):
|
|
|
97
102
|
if json is None:
|
|
98
103
|
return None
|
|
99
104
|
return cls(
|
|
105
|
+
json.get('reservationName'),
|
|
100
106
|
json.get('machineKey'),
|
|
101
107
|
json.get('maxCores'),
|
|
102
108
|
json.get('runningCoresCount'),
|
|
@@ -142,7 +148,7 @@ class UserComputingQuotas(object):
|
|
|
142
148
|
return cls(
|
|
143
149
|
UserSchedulingQuota.from_json(json.get('flex')),
|
|
144
150
|
UserSchedulingQuota.from_json(json.get('onDemand')),
|
|
145
|
-
[UserReservedSchedulingQuota.from_json(v) for v in json.get('reserved'
|
|
151
|
+
[UserReservedSchedulingQuota.from_json(v) for v in (json.get('reserved') if json.get('reserved') is not None else []) if v is not None]
|
|
146
152
|
)
|
|
147
153
|
|
|
148
154
|
|
|
@@ -201,7 +207,7 @@ class OrganizationReservedSchedulingQuota(OrganizationSchedulingQuota):
|
|
|
201
207
|
"""Describes a reserved scheduling quota for the organization.
|
|
202
208
|
"""
|
|
203
209
|
|
|
204
|
-
def __init__(self, machine_key: str, max_cores: int, running_cores_count: int, max_instances: int, running_instances_count: int):
|
|
210
|
+
def __init__(self, reservation_name: str, machine_key: str, max_cores: int, running_cores_count: int, max_instances: int, running_instances_count: int):
|
|
205
211
|
"""Create a new OrganizationReservedSchedulingQuota object describing a reserved scheduling quota for the organization.
|
|
206
212
|
|
|
207
213
|
:param str machine_key: Machine key of the reservation.
|
|
@@ -217,6 +223,11 @@ class OrganizationReservedSchedulingQuota(OrganizationSchedulingQuota):
|
|
|
217
223
|
|
|
218
224
|
Machine key of the reservation.
|
|
219
225
|
"""
|
|
226
|
+
self.reservation_name = reservation_name
|
|
227
|
+
""":type: :class:`str`
|
|
228
|
+
|
|
229
|
+
Name of the reservation.
|
|
230
|
+
"""
|
|
220
231
|
|
|
221
232
|
@classmethod
|
|
222
233
|
def from_json(cls, json: Dict[str, Any]):
|
|
@@ -228,6 +239,7 @@ class OrganizationReservedSchedulingQuota(OrganizationSchedulingQuota):
|
|
|
228
239
|
if json is None:
|
|
229
240
|
return None
|
|
230
241
|
return cls(
|
|
242
|
+
json.get('reservationName'),
|
|
231
243
|
json.get('machineKey'),
|
|
232
244
|
json.get('maxCores'),
|
|
233
245
|
json.get('runningCoresCount'),
|
|
@@ -279,7 +291,7 @@ class OrganizationComputingQuotas(object):
|
|
|
279
291
|
json.get('name'),
|
|
280
292
|
OrganizationSchedulingQuota.from_json(json.get('flex')),
|
|
281
293
|
OrganizationSchedulingQuota.from_json(json.get('onDemand')),
|
|
282
|
-
[OrganizationReservedSchedulingQuota.from_json(v) for v in json.get('reserved'
|
|
294
|
+
[OrganizationReservedSchedulingQuota.from_json(v) for v in (json.get('reserved') if json.get('reserved') is not None else []) if v is not None]
|
|
283
295
|
)
|
|
284
296
|
|
|
285
297
|
|
|
@@ -20,7 +20,18 @@ class ForcedNetworkRule(object):
|
|
|
20
20
|
priority: str = None,
|
|
21
21
|
description: str = None,
|
|
22
22
|
to_qbox: Optional[bool] = None,
|
|
23
|
-
to_payload: Optional[bool] = None
|
|
23
|
+
to_payload: Optional[bool] = None,
|
|
24
|
+
name: str = None,
|
|
25
|
+
application_type: str = None):
|
|
26
|
+
|
|
27
|
+
self.name = name
|
|
28
|
+
""":type: :class:`str`
|
|
29
|
+
|
|
30
|
+
Name of the associated rule."""
|
|
31
|
+
self.application_type = application_type
|
|
32
|
+
""":type: :class:`str`
|
|
33
|
+
|
|
34
|
+
Application layer protocol used / hint about it (e.g. ssh, http, https...)."""
|
|
24
35
|
self.inbound = inbound
|
|
25
36
|
""":type: :class:`bool`
|
|
26
37
|
|
|
@@ -84,6 +95,14 @@ class ForcedNetworkRule(object):
|
|
|
84
95
|
:returns: The created :class:`~qarnot.forced_network_rule.ForcedNetworkRule`
|
|
85
96
|
"""
|
|
86
97
|
|
|
98
|
+
name: str = None
|
|
99
|
+
if 'name' in json:
|
|
100
|
+
name = str(json.get("name"))
|
|
101
|
+
|
|
102
|
+
application_type: str = None
|
|
103
|
+
if 'applicationType' in json:
|
|
104
|
+
application_type = str(json.get("applicationType"))
|
|
105
|
+
|
|
87
106
|
inbound: bool = bool(json.get("inbound"))
|
|
88
107
|
proto: str = str(json.get("proto"))
|
|
89
108
|
|
|
@@ -96,12 +115,12 @@ class ForcedNetworkRule(object):
|
|
|
96
115
|
to = str(json.get("to"))
|
|
97
116
|
|
|
98
117
|
public_host: str = None
|
|
99
|
-
if '
|
|
100
|
-
public_host = str(json.get("
|
|
118
|
+
if 'publicHost' in json:
|
|
119
|
+
public_host = str(json.get("publicHost"))
|
|
101
120
|
|
|
102
121
|
public_port: str = None
|
|
103
|
-
if '
|
|
104
|
-
public_port = str(json.get("
|
|
122
|
+
if 'publicPort' in json:
|
|
123
|
+
public_port = str(json.get("publicPort"))
|
|
105
124
|
|
|
106
125
|
forwarder: str = None
|
|
107
126
|
if 'forwarder' in json:
|
|
@@ -116,12 +135,12 @@ class ForcedNetworkRule(object):
|
|
|
116
135
|
description = str(json.get("description"))
|
|
117
136
|
|
|
118
137
|
to_qbox: Optional[bool] = None
|
|
119
|
-
if '
|
|
120
|
-
to_qbox = bool(json.get("
|
|
138
|
+
if 'toQBox' in json:
|
|
139
|
+
to_qbox = bool(json.get("toQBox"))
|
|
121
140
|
|
|
122
141
|
to_payload: Optional[bool] = None
|
|
123
|
-
if '
|
|
124
|
-
to_payload = bool(json.get("
|
|
142
|
+
if 'toPayload' in json:
|
|
143
|
+
to_payload = bool(json.get("toPayload"))
|
|
125
144
|
|
|
126
145
|
return ForcedNetworkRule(
|
|
127
146
|
inbound,
|
|
@@ -134,7 +153,9 @@ class ForcedNetworkRule(object):
|
|
|
134
153
|
priority,
|
|
135
154
|
description,
|
|
136
155
|
to_qbox,
|
|
137
|
-
to_payload
|
|
156
|
+
to_payload,
|
|
157
|
+
name,
|
|
158
|
+
application_type)
|
|
138
159
|
|
|
139
160
|
def to_json(self):
|
|
140
161
|
result: Dict[str, Union[str, bool]] = {
|
|
@@ -142,6 +163,12 @@ class ForcedNetworkRule(object):
|
|
|
142
163
|
"proto": self.proto,
|
|
143
164
|
}
|
|
144
165
|
|
|
166
|
+
if self.name is not None:
|
|
167
|
+
result["name"] = self.name
|
|
168
|
+
|
|
169
|
+
if self.application_type is not None:
|
|
170
|
+
result["applicationType"] = self.application_type
|
|
171
|
+
|
|
145
172
|
if self.port is not None:
|
|
146
173
|
result["port"] = self.port
|
|
147
174
|
|
|
@@ -149,10 +176,10 @@ class ForcedNetworkRule(object):
|
|
|
149
176
|
result["to"] = self.to
|
|
150
177
|
|
|
151
178
|
if self.public_host is not None:
|
|
152
|
-
result["
|
|
179
|
+
result["publicHost"] = self.public_host
|
|
153
180
|
|
|
154
181
|
if self.public_port is not None:
|
|
155
|
-
result["
|
|
182
|
+
result["publicPort"] = self.public_port
|
|
156
183
|
|
|
157
184
|
if self.forwarder is not None:
|
|
158
185
|
result["forwarder"] = self.forwarder
|
|
@@ -164,9 +191,9 @@ class ForcedNetworkRule(object):
|
|
|
164
191
|
result["description"] = self.description
|
|
165
192
|
|
|
166
193
|
if self.to_qbox is not None:
|
|
167
|
-
result["
|
|
194
|
+
result["toQBox"] = self.to_qbox
|
|
168
195
|
|
|
169
196
|
if self.to_payload is not None:
|
|
170
|
-
result["
|
|
197
|
+
result["toPayload"] = self.to_payload
|
|
171
198
|
|
|
172
199
|
return result
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""Multi Slots Settings that can be used when creating a pool"""
|
|
2
|
+
|
|
3
|
+
from typing import Dict
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class MultiSlotsSettings(object):
|
|
7
|
+
"""Represents task multi slots settings."""
|
|
8
|
+
|
|
9
|
+
_slotsPerNode: int = None
|
|
10
|
+
|
|
11
|
+
def __init__(self, slotsPerNode: int = None):
|
|
12
|
+
"""Create a new :class:`~qarnot.multi_slots_settings.MultiSlotsSettings`.
|
|
13
|
+
|
|
14
|
+
:param slotsPerNode: slots per node
|
|
15
|
+
:type slotsPerNode: int
|
|
16
|
+
"""
|
|
17
|
+
self._slotsPerNode = slotsPerNode
|
|
18
|
+
|
|
19
|
+
@classmethod
|
|
20
|
+
def from_json(cls, json: Dict[str, int]):
|
|
21
|
+
"""Create the multi slots settings from json.
|
|
22
|
+
|
|
23
|
+
:param dict json: Dictionary representing the multi slots settings
|
|
24
|
+
:returns: The created :class:`~qarnot.multi_slots_settings.MultiSlotsSettings`
|
|
25
|
+
"""
|
|
26
|
+
slotsPerNode: int = json.get("slotsPerNode")
|
|
27
|
+
return MultiSlotsSettings(slotsPerNode)
|
|
28
|
+
|
|
29
|
+
def to_json(self) -> Dict[str, int]:
|
|
30
|
+
"""Get a dict ready to be json packed.
|
|
31
|
+
|
|
32
|
+
:return: the json elements of the class.
|
|
33
|
+
:rtype: `dict`
|
|
34
|
+
"""
|
|
35
|
+
return {
|
|
36
|
+
"slotsPerNode": self._slotsPerNode
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
def __eq__(self, other):
|
|
40
|
+
if other is None or not isinstance(other, MultiSlotsSettings):
|
|
41
|
+
return False
|
|
42
|
+
return self._slotsPerNode == other._slotsPerNode
|
|
43
|
+
|
|
44
|
+
def __str__(self) -> str:
|
|
45
|
+
return "multi slots settings: slotsPerNode {}.".format(self._slotsPerNode)
|
|
46
|
+
|
|
47
|
+
def __repr__(self) -> str:
|
|
48
|
+
return "multi_slots_settings.MultiSlotsSettings(slotsPerNode: {})".format(self._slotsPerNode)
|
|
@@ -19,6 +19,7 @@ from typing import Dict, List, Optional
|
|
|
19
19
|
|
|
20
20
|
from qarnot.carbon_facts import CarbonClient, CarbonFacts
|
|
21
21
|
from qarnot.retry_settings import RetrySettings
|
|
22
|
+
from qarnot.multi_slots_settings import MultiSlotsSettings
|
|
22
23
|
from qarnot.forced_network_rule import ForcedNetworkRule
|
|
23
24
|
from qarnot.secrets import SecretsAccessRights
|
|
24
25
|
|
|
@@ -86,6 +87,7 @@ class Pool(object):
|
|
|
86
87
|
self._update_cache_time = 5
|
|
87
88
|
self._scheduling_type = scheduling_type
|
|
88
89
|
self._targeted_reserved_machine_key: str = None
|
|
90
|
+
self._targeted_reservation_name: str = None
|
|
89
91
|
|
|
90
92
|
self._last_cache = time.time()
|
|
91
93
|
self._instancecount = instancecount
|
|
@@ -128,6 +130,7 @@ class Pool(object):
|
|
|
128
130
|
self._default_resources_cache_ttl_sec: Optional[int] = None
|
|
129
131
|
self._privileges: Privileges = Privileges()
|
|
130
132
|
self._default_retry_settings: RetrySettings = RetrySettings()
|
|
133
|
+
self._multi_slots_settings: Optional[MultiSlotsSettings] = None
|
|
131
134
|
self._forced_network_rules: List[ForcedNetworkRule] = []
|
|
132
135
|
self._secrets_access_rights: SecretsAccessRights = SecretsAccessRights()
|
|
133
136
|
|
|
@@ -238,10 +241,13 @@ class Pool(object):
|
|
|
238
241
|
self._hardware_constraints = [HardwareConstraint.from_json(hw_constraint_dict) for hw_constraint_dict in json_pool.get("hardwareConstraints", [])]
|
|
239
242
|
self._default_resources_cache_ttl_sec = json_pool.get("defaultResourcesCacheTTLSec", None)
|
|
240
243
|
self._targeted_reserved_machine_key = json_pool.get("targetedReservedMachineKey", None)
|
|
244
|
+
self._targeted_reservation_name = json_pool.get("targetedReservationName", None)
|
|
241
245
|
if 'privileges' in json_pool:
|
|
242
246
|
self._privileges = Privileges.from_json(json_pool.get("privileges"))
|
|
243
247
|
if 'defaultRetrySettings' in json_pool:
|
|
244
248
|
self._default_retry_settings = RetrySettings.from_json(json_pool.get("defaultRetrySettings"))
|
|
249
|
+
if 'multiSlotsSettings' in json_pool:
|
|
250
|
+
self._multi_slots_settings = MultiSlotsSettings.from_json(json_pool.get("multiSlotsSettings"))
|
|
245
251
|
if 'schedulingType' in json_pool:
|
|
246
252
|
self._scheduling_type = SchedulingType.from_string(json_pool.get("schedulingType"))
|
|
247
253
|
self._forced_network_rules = [ForcedNetworkRule.from_json(forced_network_dict) for forced_network_dict in json_pool.get("forcedNetworkRules", [])]
|
|
@@ -309,12 +315,18 @@ class Pool(object):
|
|
|
309
315
|
if self._targeted_reserved_machine_key is not None:
|
|
310
316
|
json_pool['targetedReservedMachineKey'] = self._targeted_reserved_machine_key
|
|
311
317
|
|
|
318
|
+
if self._targeted_reservation_name is not None:
|
|
319
|
+
json_pool['targetedReservationName'] = self._targeted_reservation_name
|
|
320
|
+
|
|
312
321
|
if self._forced_network_rules is not None:
|
|
313
322
|
json_pool['forcedNetworkRules'] = [x.to_json() for x in self._forced_network_rules]
|
|
314
323
|
|
|
315
324
|
if self._secrets_access_rights:
|
|
316
325
|
json_pool['secretsAccessRights'] = self._secrets_access_rights.to_json()
|
|
317
326
|
|
|
327
|
+
if self._multi_slots_settings:
|
|
328
|
+
json_pool['multiSlotsSettings'] = self._multi_slots_settings.to_json()
|
|
329
|
+
|
|
318
330
|
return json_pool
|
|
319
331
|
|
|
320
332
|
def submit(self):
|
|
@@ -1279,6 +1291,24 @@ class Pool(object):
|
|
|
1279
1291
|
raise AttributeError("can't set attribute on a submitted job")
|
|
1280
1292
|
self._completion_time_to_live = _util.parse_to_timespan_string(value)
|
|
1281
1293
|
|
|
1294
|
+
@property
|
|
1295
|
+
def multi_slots_settings(self):
|
|
1296
|
+
"""
|
|
1297
|
+
:getter: Returns this pool's multi slots settings.
|
|
1298
|
+
:type: :class:`~qarnot.multi_slots_settings.MultiSlotsSettings`
|
|
1299
|
+
:default_value: None
|
|
1300
|
+
"""
|
|
1301
|
+
self._update_if_summary()
|
|
1302
|
+
return self._multi_slots_settings
|
|
1303
|
+
|
|
1304
|
+
@multi_slots_settings.setter
|
|
1305
|
+
def multi_slots_settings(self, value):
|
|
1306
|
+
"""Setter for multi_slots_settings, this can only be set before pool's submission"""
|
|
1307
|
+
self._update_if_summary()
|
|
1308
|
+
if self._multi_slots_settings is not None:
|
|
1309
|
+
raise AttributeError("can't set attribute on a submitted pool")
|
|
1310
|
+
self._multi_slots_settings = value
|
|
1311
|
+
|
|
1282
1312
|
@property
|
|
1283
1313
|
def previous_state(self):
|
|
1284
1314
|
"""
|
|
@@ -1497,6 +1527,9 @@ class Pool(object):
|
|
|
1497
1527
|
|
|
1498
1528
|
:getter: The reserved machine key when using the "reserved" scheduling type
|
|
1499
1529
|
|
|
1530
|
+
.. deprecated:: v2.19.0
|
|
1531
|
+
Use `self.targeted_reservation_name` instead.
|
|
1532
|
+
|
|
1500
1533
|
:raises AttributeError: trying to set this after the pool is submitted
|
|
1501
1534
|
"""
|
|
1502
1535
|
return self._targeted_reserved_machine_key
|
|
@@ -1510,6 +1543,25 @@ class Pool(object):
|
|
|
1510
1543
|
|
|
1511
1544
|
self._targeted_reserved_machine_key = value
|
|
1512
1545
|
|
|
1546
|
+
@property
|
|
1547
|
+
def targeted_reservation_name(self) -> str:
|
|
1548
|
+
""":type: :class:`str`
|
|
1549
|
+
|
|
1550
|
+
:getter: The name of the reservation that describes the targeted machines when using the "reserved" scheduling type
|
|
1551
|
+
|
|
1552
|
+
:raises AttributeError: trying to set this after the task is submitted
|
|
1553
|
+
"""
|
|
1554
|
+
return self._targeted_reservation_name
|
|
1555
|
+
|
|
1556
|
+
@targeted_reservation_name.setter
|
|
1557
|
+
def targeted_reservation_name(self, value: str):
|
|
1558
|
+
"""Setted for targeted_reservation_name
|
|
1559
|
+
"""
|
|
1560
|
+
if self.uuid is not None:
|
|
1561
|
+
raise AttributeError("can't set attribute on a launched task")
|
|
1562
|
+
|
|
1563
|
+
self._targeted_reservation_name = value
|
|
1564
|
+
|
|
1513
1565
|
def __repr__(self):
|
|
1514
1566
|
return '{0} - {1} - {2} - {3} - {5} - InstanceCount : {4} - Resources : {6} '\
|
|
1515
1567
|
'Tag {7} - IsElastic {8} - ElasticMin {9} - ElasticMax {10} - ElasticMinIdle {11} -'\
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
"""Module to handle snapshot"""
|
|
2
|
+
|
|
3
|
+
# Copyright 2017 Qarnot computing
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
from datetime import datetime
|
|
18
|
+
from typing import Optional, Dict, Any, Union
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class SnapshotConfiguration():
|
|
22
|
+
"""Configuration used for a task snapshot"""
|
|
23
|
+
|
|
24
|
+
_whitelist: Optional[str] = None
|
|
25
|
+
_blacklist: Optional[str] = None
|
|
26
|
+
_bucket_name: Optional[str] = None
|
|
27
|
+
_bucket_prefix: Optional[str] = None
|
|
28
|
+
|
|
29
|
+
def __init__(self,
|
|
30
|
+
whitelist: Optional[str] = None,
|
|
31
|
+
blacklist: Optional[str] = None,
|
|
32
|
+
bucket_name: Optional[str] = None,
|
|
33
|
+
bucket_prefix: Optional[str] = None):
|
|
34
|
+
"""The SnapshotConfiguration constructor.
|
|
35
|
+
|
|
36
|
+
:param str whitelist: Whitelist filter for the snapshot.
|
|
37
|
+
:param str blacklist: Blacklist filter for the snapshot.
|
|
38
|
+
:param str bucket_name: Name of the bucket in which to upload the snapshot.
|
|
39
|
+
:param str bucket_prefix: Prefix added to the files uploaded for the snapshot.
|
|
40
|
+
:returns: The created :class:`~qarnot.snapshot.SnapshotConfiguration`.
|
|
41
|
+
"""
|
|
42
|
+
self._whitelist = whitelist
|
|
43
|
+
self._blacklist = blacklist
|
|
44
|
+
self._bucket_name = bucket_name
|
|
45
|
+
self._bucket_prefix = bucket_prefix
|
|
46
|
+
|
|
47
|
+
def to_json(self) -> Dict[str, Optional[Union[str, int]]]:
|
|
48
|
+
"""Get a SnapshotConfiguration ready to be json packed.
|
|
49
|
+
|
|
50
|
+
:return: the json representation of a snapshot configuration.
|
|
51
|
+
:rtype: Dict[str, Optional[str|int]]
|
|
52
|
+
"""
|
|
53
|
+
return {
|
|
54
|
+
"whitelist": self._whitelist,
|
|
55
|
+
"blacklist": self._blacklist,
|
|
56
|
+
"bucket": self._bucket_name,
|
|
57
|
+
"bucketPrefix": self._bucket_prefix
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
@classmethod
|
|
61
|
+
def from_json(cls, json: Dict[str, Optional[str]]):
|
|
62
|
+
"""Create a SnapshotConfiguration from a json representation
|
|
63
|
+
|
|
64
|
+
:param json: the json to use to create the SnapshotConfiguration object.
|
|
65
|
+
:type json: `Dict[str, Optional[str]]`
|
|
66
|
+
:returns: The created :class:`~qarnot.snapshot.SnapshotConfiguration`.
|
|
67
|
+
"""
|
|
68
|
+
if json is None:
|
|
69
|
+
return None
|
|
70
|
+
|
|
71
|
+
whitelist = json.get("whitelist")
|
|
72
|
+
blacklist = json.get("blacklist")
|
|
73
|
+
bucket_name = json.get("bucket")
|
|
74
|
+
bucket_prefix = json.get("bucketPrefix")
|
|
75
|
+
|
|
76
|
+
return SnapshotConfiguration(whitelist, blacklist, bucket_name, bucket_prefix)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class PeriodicSnapshotConfiguration(SnapshotConfiguration):
|
|
80
|
+
"""Configuration used for a task periodic snapshot"""
|
|
81
|
+
_interval: int = None
|
|
82
|
+
|
|
83
|
+
def __init__(self,
|
|
84
|
+
interval: int,
|
|
85
|
+
whitelist: Optional[str] = None,
|
|
86
|
+
blacklist: Optional[str] = None,
|
|
87
|
+
bucket_name: Optional[str] = None,
|
|
88
|
+
bucket_prefix: Optional[str] = None):
|
|
89
|
+
"""The PeriodicSnapshotConfiguration constructor.
|
|
90
|
+
|
|
91
|
+
:param int interval: Interval (in seconds) between two periodic snapshots.
|
|
92
|
+
:param str whitelist: Whitelist filter for the snapshot.
|
|
93
|
+
:param str blacklist: Blacklist filter for the snapshot.
|
|
94
|
+
:param str bucket_name: Bucket where to upload the snapshot.
|
|
95
|
+
:param str bucket_prefix: Prefix added to the files uploaded for the snapshot.
|
|
96
|
+
:returns: The created :class:`~qarnot.snapshot.SnapshotConfiguration`.
|
|
97
|
+
"""
|
|
98
|
+
super().__init__(whitelist, blacklist, bucket_name, bucket_prefix)
|
|
99
|
+
self._interval = interval
|
|
100
|
+
|
|
101
|
+
def to_json(self) -> Dict[str, Optional[Union[str, int]]]:
|
|
102
|
+
"""Get a PeriodicSnapshotConfiguration ready to be json packed.
|
|
103
|
+
|
|
104
|
+
:return: the json representation of a periodic snapshot configuration.
|
|
105
|
+
:rtype: Dict[str, Optional[str|int]]
|
|
106
|
+
"""
|
|
107
|
+
json: Dict[str, Optional[Union[str, int]]] = super().to_json()
|
|
108
|
+
json["interval"] = int(self._interval)
|
|
109
|
+
return json
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class SnapshotStatus():
|
|
113
|
+
"""Represents a Snapshot of a task."""
|
|
114
|
+
status: str = None
|
|
115
|
+
is_completed: bool = False
|
|
116
|
+
|
|
117
|
+
@classmethod
|
|
118
|
+
def from_string(cls, status: str):
|
|
119
|
+
"""Create a snapshot status from string.
|
|
120
|
+
|
|
121
|
+
:returns: The created :class:`~qarnot.snapshot.SnapshotStatus`.
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
if status is None:
|
|
125
|
+
return TriggeredStatus()
|
|
126
|
+
|
|
127
|
+
status = str(status)
|
|
128
|
+
|
|
129
|
+
if status.lower() == TriggeredStatus.status.lower():
|
|
130
|
+
return TriggeredStatus()
|
|
131
|
+
elif status.lower() == InProgressStatus.status.lower():
|
|
132
|
+
return InProgressStatus()
|
|
133
|
+
elif status.lower() == SuccessStatus.status.lower():
|
|
134
|
+
return SuccessStatus()
|
|
135
|
+
elif status.lower() == FailedStatus.status.lower():
|
|
136
|
+
return FailedStatus()
|
|
137
|
+
else:
|
|
138
|
+
return TriggeredStatus()
|
|
139
|
+
|
|
140
|
+
def __str__(self) -> str:
|
|
141
|
+
return "snapshot status {}.".format(self.status)
|
|
142
|
+
|
|
143
|
+
def __repr__(self) -> str:
|
|
144
|
+
return str(self.status)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class TriggeredStatus(SnapshotStatus):
|
|
148
|
+
"""Represents a snapshot triggered status """
|
|
149
|
+
status: str = "Triggered"
|
|
150
|
+
is_completed: bool = False
|
|
151
|
+
|
|
152
|
+
def __init__(self):
|
|
153
|
+
""" Create a new snapshot triggered status."""
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
class InProgressStatus(SnapshotStatus):
|
|
157
|
+
"""Represents a snapshot in progress status"""
|
|
158
|
+
status: str = "InProgress"
|
|
159
|
+
is_completed: bool = False
|
|
160
|
+
|
|
161
|
+
def __init__(self):
|
|
162
|
+
""" Create a new snapshot in progress status."""
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
class SuccessStatus(SnapshotStatus):
|
|
166
|
+
"""Represents a snapshot success status"""
|
|
167
|
+
status: str = "Success"
|
|
168
|
+
is_completed: bool = True
|
|
169
|
+
|
|
170
|
+
def __init__(self):
|
|
171
|
+
""" Create a new snapshot success status."""
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
class FailedStatus(SnapshotStatus):
|
|
175
|
+
"""Represents snapshot failed status"""
|
|
176
|
+
status: str = "Failure"
|
|
177
|
+
is_completed: bool = True
|
|
178
|
+
|
|
179
|
+
def __init__(self):
|
|
180
|
+
""" Create a new snapshot failed status."""
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
class Snapshot():
|
|
184
|
+
"""Represents a Snapshot of a task."""
|
|
185
|
+
_id: str = None
|
|
186
|
+
_task_uuid: str = None
|
|
187
|
+
_trigger_date: datetime = None
|
|
188
|
+
_last_update_date: Optional[datetime] = None
|
|
189
|
+
_snapshot_config: SnapshotConfiguration = None
|
|
190
|
+
_status: SnapshotStatus = None
|
|
191
|
+
_size_to_upload: Optional[int] = None
|
|
192
|
+
_transferred_size: Optional[int] = None
|
|
193
|
+
|
|
194
|
+
def __init__(self,
|
|
195
|
+
uid: str = None,
|
|
196
|
+
task_uuid: str = None,
|
|
197
|
+
trigger_date: datetime = None,
|
|
198
|
+
last_update_date: Optional[datetime] = None,
|
|
199
|
+
snapshot_config: SnapshotConfiguration = None,
|
|
200
|
+
status: SnapshotStatus = None,
|
|
201
|
+
size_to_upload: Optional[int] = None,
|
|
202
|
+
transferred_size: Optional[int] = None):
|
|
203
|
+
"""The Snapshot constructor.
|
|
204
|
+
|
|
205
|
+
:param str uid: identifier of the snapshot.
|
|
206
|
+
:param str task_uuid: identifier of the task hat have been snapshoted.
|
|
207
|
+
:param datetime trigger_date: the date (utc) when the snapshot was requested.
|
|
208
|
+
:param datetime last_update_date: date (utc) of the last update of the current state of the snapshot.
|
|
209
|
+
:param `~qarnot.snapshot.SnapshotConfiguration` snapshot_config: the filter and output configuration of the snapshot.
|
|
210
|
+
:param `~qarnot.snapshot.SnapshotStatus` status: Current progress status of the snapshot.
|
|
211
|
+
:param int size_to_upload: total size (in bytes) expected to upload for the snapshot.
|
|
212
|
+
:param int transferred_size: current size (in bytes) of the upload for the snapshot.
|
|
213
|
+
:returns: The created :class:`~qarnot.snapshot.Snapshot`.
|
|
214
|
+
"""
|
|
215
|
+
self._id = uid
|
|
216
|
+
self._task_uuid = task_uuid
|
|
217
|
+
self._trigger_date = trigger_date
|
|
218
|
+
self._last_update_date = last_update_date
|
|
219
|
+
self._snapshot_config = snapshot_config
|
|
220
|
+
self._status = status
|
|
221
|
+
self._size_to_upload = size_to_upload
|
|
222
|
+
self._transferred_size = transferred_size
|
|
223
|
+
|
|
224
|
+
@classmethod
|
|
225
|
+
def from_json(cls, json: Dict[str, Any]):
|
|
226
|
+
"""Create a Snapshot from a json representation
|
|
227
|
+
|
|
228
|
+
:param json: the json to use to create the Snapshot object.
|
|
229
|
+
:type json: `Dict[str, Any]`
|
|
230
|
+
:returns: The created :class:`~qarnot.snapshot.Snapshot`.
|
|
231
|
+
"""
|
|
232
|
+
if json is None:
|
|
233
|
+
return None
|
|
234
|
+
|
|
235
|
+
uid = json.get("id")
|
|
236
|
+
task_uuid = json.get("taskUuid")
|
|
237
|
+
trigger_date = json.get("triggerDate")
|
|
238
|
+
last_update_date = json.get("lastUpdateDate")
|
|
239
|
+
snapshot_config = SnapshotConfiguration.from_json(json.get("snapshotConfig"))
|
|
240
|
+
status = SnapshotStatus.from_string(json.get("status"))
|
|
241
|
+
size_to_upload = json.get("sizeToUpload")
|
|
242
|
+
transferred_size = json.get("transferredSize")
|
|
243
|
+
|
|
244
|
+
return Snapshot(uid, task_uuid, trigger_date, last_update_date, snapshot_config, status, size_to_upload, transferred_size)
|