dtlpy 1.107.8__py3-none-any.whl → 1.109.19__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.
- dtlpy/__init__.py +1 -7
- dtlpy/__version__.py +1 -1
- dtlpy/entities/__init__.py +5 -4
- dtlpy/entities/annotation.py +28 -57
- dtlpy/entities/annotation_definitions/base_annotation_definition.py +6 -14
- dtlpy/entities/app.py +1 -1
- dtlpy/entities/command.py +10 -7
- dtlpy/entities/compute.py +77 -94
- dtlpy/entities/dataset.py +29 -14
- dtlpy/entities/dpk.py +1 -0
- dtlpy/entities/filters.py +7 -6
- dtlpy/entities/item.py +7 -14
- dtlpy/entities/node.py +0 -12
- dtlpy/entities/service.py +0 -9
- dtlpy/entities/service_driver.py +118 -0
- dtlpy/entities/trigger.py +1 -1
- dtlpy/new_instance.py +1 -1
- dtlpy/repositories/__init__.py +2 -1
- dtlpy/repositories/apps.py +8 -4
- dtlpy/repositories/collections.py +86 -34
- dtlpy/repositories/commands.py +14 -4
- dtlpy/repositories/computes.py +173 -127
- dtlpy/repositories/datasets.py +20 -9
- dtlpy/repositories/downloader.py +20 -8
- dtlpy/repositories/dpks.py +26 -1
- dtlpy/repositories/items.py +5 -2
- dtlpy/repositories/service_drivers.py +213 -0
- dtlpy/repositories/services.py +6 -0
- dtlpy/repositories/uploader.py +4 -0
- dtlpy-1.109.19.dist-info/METADATA +172 -0
- {dtlpy-1.107.8.dist-info → dtlpy-1.109.19.dist-info}/RECORD +39 -37
- tests/features/environment.py +16 -15
- dtlpy-1.107.8.dist-info/METADATA +0 -69
- {dtlpy-1.107.8.data → dtlpy-1.109.19.data}/scripts/dlp +0 -0
- {dtlpy-1.107.8.data → dtlpy-1.109.19.data}/scripts/dlp.bat +0 -0
- {dtlpy-1.107.8.data → dtlpy-1.109.19.data}/scripts/dlp.py +0 -0
- {dtlpy-1.107.8.dist-info → dtlpy-1.109.19.dist-info}/LICENSE +0 -0
- {dtlpy-1.107.8.dist-info → dtlpy-1.109.19.dist-info}/WHEEL +0 -0
- {dtlpy-1.107.8.dist-info → dtlpy-1.109.19.dist-info}/entry_points.txt +0 -0
- {dtlpy-1.107.8.dist-info → dtlpy-1.109.19.dist-info}/top_level.txt +0 -0
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
from
|
|
2
|
-
from
|
|
3
|
-
from dtlpy.entities.dataset import Dataset
|
|
4
|
-
from dtlpy.entities.filters import FiltersMethod
|
|
5
|
-
from dtlpy.services.api_client import ApiClient
|
|
1
|
+
from .. import entities, exceptions
|
|
2
|
+
from ..services.api_client import ApiClient
|
|
6
3
|
from typing import List
|
|
7
4
|
|
|
8
5
|
class Collections:
|
|
@@ -15,6 +12,26 @@ class Collections:
|
|
|
15
12
|
self._dataset = dataset
|
|
16
13
|
self._item = item
|
|
17
14
|
|
|
15
|
+
@property
|
|
16
|
+
def dataset(self) -> entities.Dataset:
|
|
17
|
+
if self._dataset is None:
|
|
18
|
+
raise ValueError("Must set dataset for this action.")
|
|
19
|
+
return self._dataset
|
|
20
|
+
|
|
21
|
+
@dataset.setter
|
|
22
|
+
def dataset(self, dataset: entities.Dataset):
|
|
23
|
+
self._dataset = dataset
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def item(self) -> entities.Item:
|
|
27
|
+
if self._item is None:
|
|
28
|
+
raise ValueError("Must set item for this action.")
|
|
29
|
+
return self._item
|
|
30
|
+
|
|
31
|
+
@item.setter
|
|
32
|
+
def item(self, item: entities.Item):
|
|
33
|
+
self._item = item
|
|
34
|
+
|
|
18
35
|
def create(self, name: str) -> entities.Collection:
|
|
19
36
|
"""
|
|
20
37
|
Creates a new collection in the dataset.
|
|
@@ -22,12 +39,11 @@ class Collections:
|
|
|
22
39
|
:param name: The name of the new collection.
|
|
23
40
|
:return: The created collection details.
|
|
24
41
|
"""
|
|
25
|
-
dataset_id = self._dataset.id
|
|
26
42
|
self.validate_max_collections()
|
|
27
43
|
self.validate_collection_name(name)
|
|
28
44
|
payload = {"name": name}
|
|
29
45
|
success, response = self._client_api.gen_request(
|
|
30
|
-
req_type="post", path=f"/datasets/{
|
|
46
|
+
req_type="post", path=f"/datasets/{self.dataset.id}/items/collections", json_req=payload
|
|
31
47
|
)
|
|
32
48
|
if success:
|
|
33
49
|
collection_json = self._single_collection(data=response.json(), name=name)
|
|
@@ -43,11 +59,10 @@ class Collections:
|
|
|
43
59
|
:param new_name: The new name for the collection.
|
|
44
60
|
:return: The updated collection details.
|
|
45
61
|
"""
|
|
46
|
-
dataset_id = self._dataset.id
|
|
47
62
|
self.validate_collection_name(new_name)
|
|
48
63
|
payload = {"name": new_name}
|
|
49
64
|
success, response = self._client_api.gen_request(
|
|
50
|
-
req_type="patch", path=f"/datasets/{
|
|
65
|
+
req_type="patch", path=f"/datasets/{self.dataset.id}/items/collections/{collection_name}", json_req=payload
|
|
51
66
|
)
|
|
52
67
|
if success:
|
|
53
68
|
collection_json = self._single_collection(data=response.json(), name=new_name)
|
|
@@ -61,9 +76,8 @@ class Collections:
|
|
|
61
76
|
|
|
62
77
|
:param collection_name: The name of the collection to delete.
|
|
63
78
|
"""
|
|
64
|
-
dataset_id = self._dataset.id
|
|
65
79
|
success, response = self._client_api.gen_request(
|
|
66
|
-
req_type="delete", path=f"/datasets/{
|
|
80
|
+
req_type="delete", path=f"/datasets/{self.dataset.id}/items/collections/{collection_name}"
|
|
67
81
|
)
|
|
68
82
|
if success:
|
|
69
83
|
# Wait for the split operation to complete
|
|
@@ -74,7 +88,7 @@ class Collections:
|
|
|
74
88
|
else:
|
|
75
89
|
raise exceptions.PlatformException(response)
|
|
76
90
|
|
|
77
|
-
def clone(self, collection_name: str) ->
|
|
91
|
+
def clone(self, collection_name: str) -> entities.Collection:
|
|
78
92
|
"""
|
|
79
93
|
Clones an existing collection, creating a new one with a unique name.
|
|
80
94
|
|
|
@@ -99,7 +113,10 @@ class Collections:
|
|
|
99
113
|
|
|
100
114
|
# Create the cloned collection
|
|
101
115
|
cloned_collection = self.create(name=clone_name)
|
|
102
|
-
|
|
116
|
+
filters = entities.Filters()
|
|
117
|
+
filters.add(field=f'metadata.system.collections.{original_collection["key"]}', values=True)
|
|
118
|
+
self.assign(collections=[cloned_collection.name],
|
|
119
|
+
filters=filters)
|
|
103
120
|
return cloned_collection
|
|
104
121
|
|
|
105
122
|
|
|
@@ -109,9 +126,8 @@ class Collections:
|
|
|
109
126
|
|
|
110
127
|
:return: A list of collections in the dataset.
|
|
111
128
|
"""
|
|
112
|
-
dataset_id = self._dataset.id
|
|
113
129
|
success, response = self._client_api.gen_request(
|
|
114
|
-
req_type="GET", path=f"/datasets/{
|
|
130
|
+
req_type="GET", path=f"/datasets/{self.dataset.id}/items/collections"
|
|
115
131
|
)
|
|
116
132
|
if success:
|
|
117
133
|
data = response.json()
|
|
@@ -140,6 +156,17 @@ class Collections:
|
|
|
140
156
|
if len(collections) >= 10:
|
|
141
157
|
raise ValueError("The dataset already has the maximum number of collections (10).")
|
|
142
158
|
|
|
159
|
+
def list_missing_collections(self) -> List[str]:
|
|
160
|
+
"""
|
|
161
|
+
List all items in the dataset that are not assigned to any collection.
|
|
162
|
+
|
|
163
|
+
:return: A list of item IDs that are not part of any collection.
|
|
164
|
+
"""
|
|
165
|
+
filters = entities.Filters()
|
|
166
|
+
filters.add(field='metadata.system.collections', values=None)
|
|
167
|
+
filters.add(field='datasetId', values=self._dataset.id)
|
|
168
|
+
return self._dataset.items.list(filters=filters)
|
|
169
|
+
|
|
143
170
|
def list_unassigned_items(self) -> list:
|
|
144
171
|
"""
|
|
145
172
|
List unassigned items in a dataset (items where all collection fields are false).
|
|
@@ -147,7 +174,7 @@ class Collections:
|
|
|
147
174
|
:return: List of unassigned item IDs
|
|
148
175
|
:rtype: list
|
|
149
176
|
"""
|
|
150
|
-
filters = entities.Filters(method=FiltersMethod.AND) # Use AND method for all conditions
|
|
177
|
+
filters = entities.Filters(method=entities.FiltersMethod.AND) # Use AND method for all conditions
|
|
151
178
|
collection_fields = [
|
|
152
179
|
"collections0",
|
|
153
180
|
"collections1",
|
|
@@ -163,7 +190,7 @@ class Collections:
|
|
|
163
190
|
|
|
164
191
|
# Add each field to the filter with a value of False
|
|
165
192
|
for field in collection_fields:
|
|
166
|
-
filters.add(field=field, values=False, method=FiltersMethod.AND)
|
|
193
|
+
filters.add(field=field, values=False, method=entities.FiltersMethod.AND)
|
|
167
194
|
|
|
168
195
|
missing_ids = []
|
|
169
196
|
pages = self._dataset.items.list(filters=filters)
|
|
@@ -176,31 +203,33 @@ class Collections:
|
|
|
176
203
|
|
|
177
204
|
def assign(
|
|
178
205
|
self,
|
|
179
|
-
dataset_id: str,
|
|
180
206
|
collections: List[str],
|
|
207
|
+
dataset_id: str = None,
|
|
181
208
|
item_id: str = None,
|
|
182
|
-
|
|
209
|
+
filters: entities.Filters = None
|
|
183
210
|
) -> bool:
|
|
184
211
|
"""
|
|
185
212
|
Assign an item to a collection. Creates the collection if it does not exist.
|
|
186
213
|
|
|
187
|
-
:param dataset_id: ID of the dataset.
|
|
188
214
|
:param collections: List of the collections to assign the item to.
|
|
215
|
+
:param dataset_id: ID of the dataset.
|
|
189
216
|
:param item_id: (Optional) ID of the item to assign. If not provided, all items in the dataset will be updated.
|
|
190
|
-
:param
|
|
217
|
+
:param filters: (Optional) Filters of items to assign to the collections.
|
|
191
218
|
:return: True if the assignment was successful, otherwise raises an exception.
|
|
192
219
|
"""
|
|
220
|
+
if not isinstance(collections, list):
|
|
221
|
+
raise ValueError("collections must be a list.")
|
|
222
|
+
if dataset_id is None and self._dataset is not None:
|
|
223
|
+
dataset_id = self.dataset.id
|
|
224
|
+
if item_id is None and self._item is not None:
|
|
225
|
+
item_id = self.item.id
|
|
193
226
|
# Build the query structure
|
|
194
|
-
if
|
|
195
|
-
query = {
|
|
196
|
-
"filter": {
|
|
197
|
-
f"metadata.system.collections.{collection_key}": True
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
elif item_id:
|
|
227
|
+
if item_id is not None:
|
|
201
228
|
query = {
|
|
202
229
|
"id": {"$eq": item_id}
|
|
203
230
|
}
|
|
231
|
+
elif filters is not None:
|
|
232
|
+
query = filters.prepare().get("filter")
|
|
204
233
|
else:
|
|
205
234
|
raise ValueError("Either collection_key or item_id must be provided.")
|
|
206
235
|
|
|
@@ -226,16 +255,39 @@ class Collections:
|
|
|
226
255
|
raise exceptions.PlatformException(f"Failed to assign item to collections: {response}")
|
|
227
256
|
|
|
228
257
|
|
|
229
|
-
def unassign(self,
|
|
258
|
+
def unassign(self,
|
|
259
|
+
collections: List[str],
|
|
260
|
+
dataset_id: str = None,
|
|
261
|
+
item_id: str = None,
|
|
262
|
+
filters: entities.Filters = None) -> bool:
|
|
230
263
|
"""
|
|
231
264
|
Unassign an item from a collection.
|
|
232
|
-
:param item_id: ID of the item.
|
|
233
265
|
:param collections: List of collection names to unassign.
|
|
266
|
+
:param dataset_id: ID of the dataset.
|
|
267
|
+
:param item_id: ID of the item.
|
|
268
|
+
:param filters: (Optional) Filters of items to unassign from the collections.
|
|
234
269
|
"""
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
270
|
+
if not isinstance(collections, list):
|
|
271
|
+
raise ValueError("collections must be a list.")
|
|
272
|
+
# build the context
|
|
273
|
+
if dataset_id is None and self._dataset is not None:
|
|
274
|
+
dataset_id = self._dataset.id
|
|
275
|
+
if item_id is None and self._item is not None:
|
|
276
|
+
item_id = self._item.id
|
|
277
|
+
|
|
278
|
+
# build the payload
|
|
279
|
+
if item_id is not None and filters is None:
|
|
280
|
+
payload = {
|
|
281
|
+
"query": {"id": {"$eq": item_id}},
|
|
282
|
+
"collections": collections,
|
|
283
|
+
}
|
|
284
|
+
elif filters is not None and item_id is None:
|
|
285
|
+
payload = {
|
|
286
|
+
"query": filters.prepare().get("filter"),
|
|
287
|
+
"collections": collections,
|
|
288
|
+
}
|
|
289
|
+
else:
|
|
290
|
+
raise ValueError("Either item_id or filters must be provided but not both.")
|
|
239
291
|
success, response = self._client_api.gen_request(
|
|
240
292
|
req_type="post",
|
|
241
293
|
path=f"/datasets/{dataset_id}/items/collections/bulk-remove",
|
dtlpy/repositories/commands.py
CHANGED
|
@@ -70,7 +70,7 @@ class Commands:
|
|
|
70
70
|
return entities.Command.from_json(client_api=self._client_api,
|
|
71
71
|
_json=response.json())
|
|
72
72
|
|
|
73
|
-
def wait(self, command_id, timeout=0, step=None, url=None, backoff_factor=1):
|
|
73
|
+
def wait(self, command_id, timeout=0, step=None, url=None, backoff_factor=1, iteration_callback=None):
|
|
74
74
|
"""
|
|
75
75
|
Wait for command to finish
|
|
76
76
|
|
|
@@ -84,6 +84,7 @@ class Commands:
|
|
|
84
84
|
:param int timeout: int, seconds to wait until TimeoutError is raised. if 0 - wait until done
|
|
85
85
|
:param int step: int, seconds between polling
|
|
86
86
|
:param str url: url to the command
|
|
87
|
+
:param function iteration_callback: function to call on each iteration
|
|
87
88
|
:param float backoff_factor: A backoff factor to apply between attempts after the second try
|
|
88
89
|
:return: Command object
|
|
89
90
|
"""
|
|
@@ -112,9 +113,18 @@ class Commands:
|
|
|
112
113
|
elapsed = time.time() - start
|
|
113
114
|
sleep_time = np.min([timeout - elapsed, backoff_factor * (2 ** num_tries), MAX_SLEEP_TIME])
|
|
114
115
|
num_tries += 1
|
|
115
|
-
logger.debug(
|
|
116
|
-
|
|
117
|
-
|
|
116
|
+
logger.debug(
|
|
117
|
+
"Command {!r} is running for {:.2f}[s] and now Going to sleep {:.2f}[s]".format(
|
|
118
|
+
command.id,
|
|
119
|
+
elapsed,
|
|
120
|
+
sleep_time
|
|
121
|
+
)
|
|
122
|
+
)
|
|
123
|
+
if iteration_callback is not None:
|
|
124
|
+
try:
|
|
125
|
+
iteration_callback()
|
|
126
|
+
except Exception as e:
|
|
127
|
+
logger.warning('iteration_callback failed: {}'.format(e.__str__()))
|
|
118
128
|
time.sleep(sleep_time)
|
|
119
129
|
pbar.close()
|
|
120
130
|
if command is None:
|
dtlpy/repositories/computes.py
CHANGED
|
@@ -2,11 +2,16 @@ import base64
|
|
|
2
2
|
import datetime
|
|
3
3
|
import json
|
|
4
4
|
|
|
5
|
+
from dtlpy import miscellaneous
|
|
6
|
+
|
|
5
7
|
from ..services.api_client import ApiClient
|
|
6
8
|
from .. import exceptions, entities, repositories
|
|
7
9
|
from typing import List, Optional, Dict
|
|
8
|
-
from ..entities import ComputeCluster, ComputeContext, ComputeType
|
|
10
|
+
from ..entities import ComputeCluster, ComputeContext, ComputeType
|
|
9
11
|
from ..entities.integration import IntegrationType
|
|
12
|
+
import logging
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(name='dtlpy')
|
|
10
15
|
|
|
11
16
|
|
|
12
17
|
class Computes:
|
|
@@ -17,6 +22,7 @@ class Computes:
|
|
|
17
22
|
self._commands = None
|
|
18
23
|
self._projects = None
|
|
19
24
|
self._organizations = None
|
|
25
|
+
self.log_cache = dict()
|
|
20
26
|
|
|
21
27
|
@property
|
|
22
28
|
def commands(self) -> repositories.Commands:
|
|
@@ -46,7 +52,8 @@ class Computes:
|
|
|
46
52
|
is_global: Optional[bool] = False,
|
|
47
53
|
features: Optional[Dict] = None,
|
|
48
54
|
wait=True,
|
|
49
|
-
status: entities.ComputeStatus = None
|
|
55
|
+
status: entities.ComputeStatus = None,
|
|
56
|
+
settings: entities.ComputeSettings = None
|
|
50
57
|
):
|
|
51
58
|
"""
|
|
52
59
|
Create a new compute
|
|
@@ -60,18 +67,25 @@ class Computes:
|
|
|
60
67
|
:param features: Features
|
|
61
68
|
:param wait: Wait for compute creation
|
|
62
69
|
:param status: Compute status
|
|
70
|
+
:param settings: Compute settings
|
|
63
71
|
:return: Compute
|
|
72
|
+
:rtype: dl.entities.compute.Compute
|
|
64
73
|
"""
|
|
65
74
|
|
|
75
|
+
shared_contexts_json = []
|
|
76
|
+
for shared_context in shared_contexts:
|
|
77
|
+
src_json = shared_context.to_json() if isinstance(shared_context, entities.ComputeContext) else shared_context
|
|
78
|
+
shared_contexts_json.append(src_json)
|
|
66
79
|
payload = {
|
|
67
80
|
'name': name,
|
|
68
81
|
'context': context.to_json(),
|
|
69
82
|
'type': type.value,
|
|
70
83
|
'global': is_global,
|
|
71
84
|
'features': features,
|
|
72
|
-
'
|
|
85
|
+
'sharedContexts': shared_contexts_json,
|
|
73
86
|
'cluster': cluster.to_json(),
|
|
74
|
-
'status': status
|
|
87
|
+
'status': status,
|
|
88
|
+
"settings": settings.to_json() if isinstance(settings, entities.ComputeSettings) else settings
|
|
75
89
|
}
|
|
76
90
|
|
|
77
91
|
# request
|
|
@@ -84,26 +98,69 @@ class Computes:
|
|
|
84
98
|
if not success:
|
|
85
99
|
raise exceptions.PlatformException(response)
|
|
86
100
|
|
|
87
|
-
compute =
|
|
88
|
-
_json=response.json(),
|
|
89
|
-
client_api=self._client_api
|
|
90
|
-
)
|
|
101
|
+
compute = self._build_compute_by_type(response.json())
|
|
91
102
|
|
|
92
103
|
if wait:
|
|
93
104
|
command_id = compute.metadata.get('system', {}).get('commands', {}).get('create', None)
|
|
94
105
|
if command_id is not None:
|
|
95
106
|
command = self.commands.get(command_id=command_id, url='api/v1/commands/faas/{}'.format(command_id))
|
|
96
|
-
|
|
107
|
+
try:
|
|
108
|
+
command.wait(iteration_callback=self.__get_log_compute_progress_callback(compute.id))
|
|
109
|
+
except Exception as e:
|
|
110
|
+
self.log_cache.pop(compute.id, None)
|
|
111
|
+
raise e
|
|
97
112
|
compute = self.get(compute_id=compute.id)
|
|
98
113
|
|
|
99
114
|
return compute
|
|
100
115
|
|
|
116
|
+
def _build_compute_by_type(self, _json):
|
|
117
|
+
if _json.get('type') == 'kubernetes':
|
|
118
|
+
compute = entities.KubernetesCompute.from_json(
|
|
119
|
+
_json=_json,
|
|
120
|
+
client_api=self._client_api
|
|
121
|
+
)
|
|
122
|
+
else:
|
|
123
|
+
compute = entities.Compute.from_json(
|
|
124
|
+
_json=_json,
|
|
125
|
+
client_api=self._client_api
|
|
126
|
+
)
|
|
127
|
+
return compute
|
|
128
|
+
|
|
129
|
+
def __get_log_compute_progress_callback(self, compute_id: str):
|
|
130
|
+
def func():
|
|
131
|
+
compute = self.get(compute_id=compute_id)
|
|
132
|
+
bootstrap_progress = compute.metadata.get('system', {}).get('bootstrapProcess', {}).get('progress', None)
|
|
133
|
+
bootstrap_logs = compute.metadata.get('system', {}).get('bootstrapProcess', {}).get('logs', None)
|
|
134
|
+
validation_progress = compute.metadata.get('system', {}).get('validation', {}).get('progress', None)
|
|
135
|
+
validation_logs = compute.metadata.get('system', {}).get('validation', {}).get('logs', None)
|
|
136
|
+
if bootstrap_progress not in [None, 100]:
|
|
137
|
+
logger.info(f"Bootstrap in progress: {bootstrap_progress}%")
|
|
138
|
+
last_index = len(self.log_cache.get(compute_id, {}).get('bootstrap', []))
|
|
139
|
+
new_logs = bootstrap_logs[last_index:]
|
|
140
|
+
if new_logs:
|
|
141
|
+
logger.info("Bootstrap Logs: {}".format('\n'.join(new_logs)))
|
|
142
|
+
if compute_id not in self.log_cache:
|
|
143
|
+
self.log_cache[compute_id] = {}
|
|
144
|
+
self.log_cache[compute_id]['bootstrap'] = bootstrap_logs
|
|
145
|
+
if validation_progress not in [None, 100]:
|
|
146
|
+
logger.info(f"Validating created compute. Progress: {validation_progress}%")
|
|
147
|
+
last_index = len(self.log_cache.get(compute_id, {}).get('validation', []))
|
|
148
|
+
new_logs = validation_logs[last_index:]
|
|
149
|
+
if new_logs:
|
|
150
|
+
logger.info("Validation Logs: {}".format('\n'.join(new_logs)))
|
|
151
|
+
if compute_id not in self.log_cache:
|
|
152
|
+
self.log_cache[compute_id] = {}
|
|
153
|
+
self.log_cache[compute_id]['validation'] = validation_logs
|
|
154
|
+
return func
|
|
155
|
+
|
|
156
|
+
|
|
101
157
|
def get(self, compute_id: str):
|
|
102
158
|
"""
|
|
103
159
|
Get a compute
|
|
104
160
|
|
|
105
161
|
:param compute_id: Compute ID
|
|
106
162
|
:return: Compute
|
|
163
|
+
:rtype: dl.entities.compute.Compute
|
|
107
164
|
"""
|
|
108
165
|
|
|
109
166
|
# request
|
|
@@ -115,10 +172,7 @@ class Computes:
|
|
|
115
172
|
if not success:
|
|
116
173
|
raise exceptions.PlatformException(response)
|
|
117
174
|
|
|
118
|
-
compute =
|
|
119
|
-
_json=response.json(),
|
|
120
|
-
client_api=self._client_api
|
|
121
|
-
)
|
|
175
|
+
compute = self._build_compute_by_type(response.json())
|
|
122
176
|
|
|
123
177
|
return compute
|
|
124
178
|
|
|
@@ -128,6 +182,7 @@ class Computes:
|
|
|
128
182
|
|
|
129
183
|
:param compute: Compute
|
|
130
184
|
:return: Compute
|
|
185
|
+
:rtype: dl.entities.compute.Compute
|
|
131
186
|
"""
|
|
132
187
|
|
|
133
188
|
# request
|
|
@@ -140,10 +195,7 @@ class Computes:
|
|
|
140
195
|
if not success:
|
|
141
196
|
raise exceptions.PlatformException(response)
|
|
142
197
|
|
|
143
|
-
compute =
|
|
144
|
-
_json=response.json(),
|
|
145
|
-
client_api=self._client_api
|
|
146
|
-
)
|
|
198
|
+
compute = self._build_compute_by_type(response.json())
|
|
147
199
|
|
|
148
200
|
return compute
|
|
149
201
|
|
|
@@ -165,6 +217,60 @@ class Computes:
|
|
|
165
217
|
|
|
166
218
|
return True
|
|
167
219
|
|
|
220
|
+
def validate(self, compute_id: str, wait: bool = True):
|
|
221
|
+
"""
|
|
222
|
+
Validate a compute
|
|
223
|
+
|
|
224
|
+
:param str compute_id: Compute ID
|
|
225
|
+
:param bool wait: Wait for validation
|
|
226
|
+
:return: Compute
|
|
227
|
+
:rtype: dl.entities.compute.Compute
|
|
228
|
+
"""
|
|
229
|
+
|
|
230
|
+
# request
|
|
231
|
+
success, response = self._client_api.gen_request(
|
|
232
|
+
req_type='post',
|
|
233
|
+
path=self._base_url + '/{}/validate'.format(compute_id)
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
if not success:
|
|
237
|
+
raise exceptions.PlatformException(response)
|
|
238
|
+
|
|
239
|
+
compute = self._build_compute_by_type(response.json())
|
|
240
|
+
|
|
241
|
+
if wait:
|
|
242
|
+
command_id = compute.metadata.get('system', {}).get('commands', {}).get('validate', None)
|
|
243
|
+
if command_id is not None:
|
|
244
|
+
command = self.commands.get(command_id=command_id, url='api/v1/commands/faas/{}'.format(command_id))
|
|
245
|
+
try:
|
|
246
|
+
command.wait(iteration_callback=self.__get_log_compute_progress_callback(compute.id))
|
|
247
|
+
except Exception as e:
|
|
248
|
+
self.log_cache.pop(compute.id, None)
|
|
249
|
+
raise e
|
|
250
|
+
compute = self.get(compute_id=compute.id)
|
|
251
|
+
|
|
252
|
+
return compute
|
|
253
|
+
|
|
254
|
+
def list_global(self):
|
|
255
|
+
"""
|
|
256
|
+
List computes
|
|
257
|
+
|
|
258
|
+
:return: List of computes
|
|
259
|
+
:rtype: list[str]
|
|
260
|
+
"""
|
|
261
|
+
|
|
262
|
+
# request
|
|
263
|
+
success, response = self._client_api.gen_request(
|
|
264
|
+
req_type='get',
|
|
265
|
+
path=self._base_url + '/globals',
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
if not success:
|
|
269
|
+
raise exceptions.PlatformException(response)
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
return response.json()
|
|
273
|
+
|
|
168
274
|
@staticmethod
|
|
169
275
|
def read_file(file_path):
|
|
170
276
|
try:
|
|
@@ -205,7 +311,9 @@ class Computes:
|
|
|
205
311
|
[],
|
|
206
312
|
cluster,
|
|
207
313
|
ComputeType.KUBERNETES,
|
|
208
|
-
status=config['config'].get('status', None)
|
|
314
|
+
status=config['config'].get('status', None),
|
|
315
|
+
settings=config['config'].get('settings', None))
|
|
316
|
+
|
|
209
317
|
return compute
|
|
210
318
|
|
|
211
319
|
def create_from_config_file(self, config_file_path, org_id, project_name: Optional[str] = None):
|
|
@@ -221,121 +329,59 @@ class Computes:
|
|
|
221
329
|
return compute
|
|
222
330
|
|
|
223
331
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
def create(
|
|
231
|
-
self,
|
|
232
|
-
name: str,
|
|
233
|
-
compute_id: str,
|
|
234
|
-
context: entities.ComputeContext
|
|
235
|
-
):
|
|
236
|
-
"""
|
|
237
|
-
Create a new service driver
|
|
238
|
-
|
|
239
|
-
:param name: Service driver name
|
|
240
|
-
:param compute_id: Compute ID
|
|
241
|
-
:param context: Compute context
|
|
242
|
-
:return: Service driver
|
|
243
|
-
|
|
244
|
-
"""
|
|
245
|
-
|
|
246
|
-
payload = {
|
|
247
|
-
'name': name,
|
|
248
|
-
'computeId': compute_id,
|
|
249
|
-
'context': context.to_json()
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
# request
|
|
253
|
-
success, response = self._client_api.gen_request(
|
|
254
|
-
req_type='post',
|
|
255
|
-
path=self._base_url,
|
|
256
|
-
json_req=payload
|
|
257
|
-
)
|
|
258
|
-
|
|
259
|
-
if not success:
|
|
260
|
-
raise exceptions.PlatformException(response)
|
|
261
|
-
|
|
262
|
-
service_driver = entities.ServiceDriver.from_json(
|
|
263
|
-
_json=response.json(),
|
|
264
|
-
client_api=self._client_api
|
|
265
|
-
)
|
|
266
|
-
|
|
267
|
-
return service_driver
|
|
268
|
-
|
|
269
|
-
def get(self, service_driver_id: str):
|
|
270
|
-
"""
|
|
271
|
-
Get a service driver
|
|
272
|
-
|
|
273
|
-
:param service_driver_id: Service driver ID
|
|
274
|
-
:return: Service driver
|
|
275
|
-
"""
|
|
276
|
-
|
|
277
|
-
# request
|
|
278
|
-
success, response = self._client_api.gen_request(
|
|
279
|
-
req_type='get',
|
|
280
|
-
path=self._base_url + '/{}'.format(service_driver_id)
|
|
281
|
-
)
|
|
282
|
-
|
|
332
|
+
def _list(self, filters: entities.Filters):
|
|
333
|
+
url = self._base_url + '/query'
|
|
334
|
+
success, response = self._client_api.gen_request(req_type='POST',
|
|
335
|
+
path=url,
|
|
336
|
+
json_req=filters.prepare())
|
|
283
337
|
if not success:
|
|
284
338
|
raise exceptions.PlatformException(response)
|
|
285
339
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
)
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
340
|
+
return response.json()
|
|
341
|
+
|
|
342
|
+
def _build_entities_from_response(self, response_items) -> miscellaneous.List[entities.Compute]:
|
|
343
|
+
pool = self._client_api.thread_pools(pool_name='entity.create')
|
|
344
|
+
jobs = [None for _ in range(len(response_items))]
|
|
345
|
+
for i_item, item in enumerate(response_items):
|
|
346
|
+
jobs[i_item] = pool.submit(entities.Compute._protected_from_json,
|
|
347
|
+
**{'client_api': self._client_api,
|
|
348
|
+
'_json': item})
|
|
349
|
+
results = [j.result() for j in jobs]
|
|
350
|
+
_ = [logger.warning(r[1]) for r in results if r[0] is False]
|
|
351
|
+
items = miscellaneous.List([r[1] for r in results if r[0] is True])
|
|
352
|
+
return items
|
|
353
|
+
|
|
354
|
+
def list(self, filters: entities.Filters = None) -> entities.PagedEntities:
|
|
294
355
|
"""
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
:param service_driver_id: Service driver ID
|
|
298
|
-
"""
|
|
299
|
-
|
|
300
|
-
# request
|
|
301
|
-
success, response = self._client_api.gen_request(
|
|
302
|
-
req_type='delete',
|
|
303
|
-
path=self._base_url + '/{}'.format(service_driver_id)
|
|
304
|
-
)
|
|
305
|
-
|
|
306
|
-
if not success:
|
|
307
|
-
raise exceptions.PlatformException(response)
|
|
356
|
+
List all services drivers
|
|
308
357
|
|
|
309
|
-
|
|
358
|
+
:param dtlpy.entities.filters.Filters filters: Filters entity or a dictionary containing filters parameters
|
|
359
|
+
:return: Paged entity
|
|
360
|
+
:rtype: dtlpy.entities.paged_entities.PagedEntities
|
|
310
361
|
|
|
311
|
-
|
|
312
|
-
"""
|
|
313
|
-
Set a service driver as default
|
|
362
|
+
**Example**:
|
|
314
363
|
|
|
315
|
-
|
|
316
|
-
:param org_id: Organization ID
|
|
317
|
-
:param update_existing_services: Update existing services
|
|
364
|
+
.. code-block:: python
|
|
318
365
|
|
|
319
|
-
|
|
366
|
+
services = dl.service_drivers.list()
|
|
320
367
|
"""
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
'
|
|
328
|
-
'
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
)
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
)
|
|
340
|
-
|
|
341
|
-
return service_driver
|
|
368
|
+
# default filters
|
|
369
|
+
if filters is None:
|
|
370
|
+
filters = entities.Filters(resource=entities.FiltersResource.COMPUTE)
|
|
371
|
+
|
|
372
|
+
if filters.resource != entities.FiltersResource.COMPUTE:
|
|
373
|
+
raise exceptions.PlatformException(
|
|
374
|
+
error='400',
|
|
375
|
+
message='Filters resource must to be FiltersResource.COMPUTE. Got: {!r}'.format(
|
|
376
|
+
filters.resource))
|
|
377
|
+
|
|
378
|
+
if not isinstance(filters, entities.Filters):
|
|
379
|
+
raise exceptions.PlatformException('400', 'Unknown filters type')
|
|
380
|
+
|
|
381
|
+
paged = entities.PagedEntities(items_repository=self,
|
|
382
|
+
filters=filters,
|
|
383
|
+
page_offset=filters.page,
|
|
384
|
+
page_size=filters.page_size,
|
|
385
|
+
client_api=self._client_api)
|
|
386
|
+
paged.get_page()
|
|
387
|
+
return paged
|