manta-node 0.5b0.dev9__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.
- manta_node/__init__.py +5 -0
- manta_node/__main__.py +57 -0
- manta_node/cli/__init__.py +6 -0
- manta_node/cli/commands/__init__.py +21 -0
- manta_node/cli/commands/cluster.py +419 -0
- manta_node/cli/commands/config.py +490 -0
- manta_node/cli/commands/logs.py +168 -0
- manta_node/cli/commands/start.py +459 -0
- manta_node/cli/commands/status.py +204 -0
- manta_node/cli/commands/stop.py +253 -0
- manta_node/cli/config_manager.py +139 -0
- manta_node/cli/main.py +133 -0
- manta_node/cli/version.py +106 -0
- manta_node/domain/__init__.py +8 -0
- manta_node/domain/task_lifecycle.py +83 -0
- manta_node/infrastructure/__init__.py +13 -0
- manta_node/infrastructure/config/__init__.py +31 -0
- manta_node/infrastructure/config/node_config_manager.py +918 -0
- manta_node/infrastructure/container/__init__.py +9 -0
- manta_node/infrastructure/container/docker_adapter.py +253 -0
- manta_node/infrastructure/container/manager.py +536 -0
- manta_node/infrastructure/filesystem/__init__.py +7 -0
- manta_node/infrastructure/filesystem/dataset_manager.py +469 -0
- manta_node/infrastructure/grpc/__init__.py +11 -0
- manta_node/infrastructure/grpc/client.py +373 -0
- manta_node/infrastructure/grpc/local_servicer.py +151 -0
- manta_node/infrastructure/grpc/world_servicer.py +284 -0
- manta_node/infrastructure/metrics/__init__.py +10 -0
- manta_node/infrastructure/metrics/collector.py +94 -0
- manta_node/infrastructure/metrics/metrics_collector.py +351 -0
- manta_node/infrastructure/mqtt/__init__.py +7 -0
- manta_node/infrastructure/mqtt/command_handler.py +315 -0
- manta_node/node_orchestrator.py +462 -0
- manta_node/task_manager.py +519 -0
- manta_node/tasks.py +272 -0
- manta_node/utils.py +52 -0
- manta_node-0.5b0.dev9.dist-info/METADATA +799 -0
- manta_node-0.5b0.dev9.dist-info/RECORD +42 -0
- manta_node-0.5b0.dev9.dist-info/WHEEL +5 -0
- manta_node-0.5b0.dev9.dist-info/entry_points.txt +2 -0
- manta_node-0.5b0.dev9.dist-info/licenses/LICENSE +683 -0
- manta_node-0.5b0.dev9.dist-info/top_level.txt +1 -0
manta_node/tasks.py
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Callable, Iterable, Iterator, List, Tuple
|
|
4
|
+
|
|
5
|
+
from manta_common.build.common.tasks import MqttTask, TaskStatus, TaskUpdate
|
|
6
|
+
from manta_common.conversions import ID, TupleID
|
|
7
|
+
from .domain.task_lifecycle import TaskLifecycleService, TaskTransitionRule
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TaskProgression:
|
|
11
|
+
"""
|
|
12
|
+
Task progression is a data structure which holds :
|
|
13
|
+
|
|
14
|
+
* a task update
|
|
15
|
+
* a module file
|
|
16
|
+
* a start time
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
__slots__ = ["task_update", "module_file", "start_time"]
|
|
20
|
+
|
|
21
|
+
def __init__(
|
|
22
|
+
self, task_update: TaskUpdate, module_file: Path, start_time: datetime
|
|
23
|
+
):
|
|
24
|
+
self.task_update = task_update
|
|
25
|
+
self.module_file = module_file
|
|
26
|
+
self.start_time = start_time
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def task_id(self) -> ID:
|
|
30
|
+
"""
|
|
31
|
+
Get Task ID
|
|
32
|
+
|
|
33
|
+
Returns
|
|
34
|
+
-------
|
|
35
|
+
ID
|
|
36
|
+
Task ID
|
|
37
|
+
"""
|
|
38
|
+
return ID(self.task_update.task_id)
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def swarm_id(self) -> ID:
|
|
42
|
+
"""
|
|
43
|
+
Get Swarm ID
|
|
44
|
+
|
|
45
|
+
Returns
|
|
46
|
+
-------
|
|
47
|
+
ID
|
|
48
|
+
Swarm ID
|
|
49
|
+
"""
|
|
50
|
+
return ID(self.task_update.swarm_id)
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def task_status(self) -> TaskStatus:
|
|
54
|
+
"""
|
|
55
|
+
Get Task Status
|
|
56
|
+
|
|
57
|
+
Returns
|
|
58
|
+
-------
|
|
59
|
+
TaskStatus
|
|
60
|
+
Task Status
|
|
61
|
+
"""
|
|
62
|
+
return self.task_update.task_status
|
|
63
|
+
|
|
64
|
+
@task_status.setter
|
|
65
|
+
def task_status(self, task_status: TaskStatus):
|
|
66
|
+
"""
|
|
67
|
+
Set a new task status
|
|
68
|
+
|
|
69
|
+
Parameters
|
|
70
|
+
----------
|
|
71
|
+
task_status : TaskStatus
|
|
72
|
+
Task Status to set
|
|
73
|
+
"""
|
|
74
|
+
self.task_update.task_status = task_status
|
|
75
|
+
|
|
76
|
+
def unlink(self, missing_ok: bool = True):
|
|
77
|
+
"""
|
|
78
|
+
Unlink module file
|
|
79
|
+
|
|
80
|
+
Parameters
|
|
81
|
+
----------
|
|
82
|
+
missing_ok : bool
|
|
83
|
+
Extra parameter from :code:`Path.unlink`
|
|
84
|
+
"""
|
|
85
|
+
self.module_file.unlink(missing_ok)
|
|
86
|
+
|
|
87
|
+
def is_active_task(self) -> bool:
|
|
88
|
+
"""
|
|
89
|
+
Check if is an active task
|
|
90
|
+
|
|
91
|
+
Returns
|
|
92
|
+
-------
|
|
93
|
+
bool
|
|
94
|
+
Is active task
|
|
95
|
+
"""
|
|
96
|
+
# Use domain service for business logic
|
|
97
|
+
return TaskLifecycleService.is_active(self.task_status)
|
|
98
|
+
|
|
99
|
+
def is_finished_task(self) -> bool:
|
|
100
|
+
"""
|
|
101
|
+
Check if is a finished task
|
|
102
|
+
|
|
103
|
+
Returns
|
|
104
|
+
-------
|
|
105
|
+
bool
|
|
106
|
+
Is a finished task
|
|
107
|
+
"""
|
|
108
|
+
# Use domain rule for terminal state check
|
|
109
|
+
return TaskTransitionRule.is_finished(self.task_status)
|
|
110
|
+
|
|
111
|
+
def compare_iteration(self, mqtt_task: MqttTask) -> bool:
|
|
112
|
+
"""
|
|
113
|
+
Compare iteration between a task from MQTT and itself
|
|
114
|
+
|
|
115
|
+
Parameters
|
|
116
|
+
----------
|
|
117
|
+
mqtt_task : MqttTask
|
|
118
|
+
Task from MQTT
|
|
119
|
+
|
|
120
|
+
Returns
|
|
121
|
+
-------
|
|
122
|
+
bool
|
|
123
|
+
Same iteration
|
|
124
|
+
"""
|
|
125
|
+
return (
|
|
126
|
+
self.task_update.iteration == mqtt_task.iteration
|
|
127
|
+
and self.task_update.circular == mqtt_task.circular
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class TaskProgressions:
|
|
132
|
+
"""
|
|
133
|
+
List of Task Progression used in Task Manager and World Servicer
|
|
134
|
+
"""
|
|
135
|
+
|
|
136
|
+
__slots__ = ["_tasks", "_env_ids"]
|
|
137
|
+
|
|
138
|
+
def __init__(self):
|
|
139
|
+
self._tasks: List[TaskProgression] = []
|
|
140
|
+
self._env_ids: List[Tuple[TupleID, TupleID]] = []
|
|
141
|
+
|
|
142
|
+
def __iter__(self) -> Iterator[TaskProgression]:
|
|
143
|
+
"""
|
|
144
|
+
Iterate over tasks
|
|
145
|
+
|
|
146
|
+
Returns
|
|
147
|
+
-------
|
|
148
|
+
Iterator[TaskProgression]
|
|
149
|
+
Iterator of task progressions
|
|
150
|
+
"""
|
|
151
|
+
return iter(self._tasks)
|
|
152
|
+
|
|
153
|
+
def __getitem__(self, env_id: Tuple[TupleID, TupleID]) -> TaskProgression:
|
|
154
|
+
"""
|
|
155
|
+
Return the task progression given the task ID
|
|
156
|
+
|
|
157
|
+
Parameters
|
|
158
|
+
----------
|
|
159
|
+
env_id : str
|
|
160
|
+
Task and Swarms IDs in a tuple
|
|
161
|
+
|
|
162
|
+
Returns
|
|
163
|
+
-------
|
|
164
|
+
TaskProgression
|
|
165
|
+
Task Progression
|
|
166
|
+
"""
|
|
167
|
+
if env_id not in self._env_ids:
|
|
168
|
+
raise KeyError(
|
|
169
|
+
f"Cannot get task due to {env_id} not found in tasks {self._env_ids}"
|
|
170
|
+
)
|
|
171
|
+
return self._tasks[self._env_ids.index(env_id)]
|
|
172
|
+
|
|
173
|
+
def __contains__(self, env_id: Tuple[TupleID, TupleID]) -> bool:
|
|
174
|
+
"""
|
|
175
|
+
Check if the task ID exists in itself
|
|
176
|
+
|
|
177
|
+
Parameters
|
|
178
|
+
----------
|
|
179
|
+
env_id : Tuple[TupleID, TupleID]
|
|
180
|
+
Task and Swarms IDs in a tuple
|
|
181
|
+
|
|
182
|
+
Returns
|
|
183
|
+
-------
|
|
184
|
+
bool
|
|
185
|
+
It contains the task ID
|
|
186
|
+
"""
|
|
187
|
+
return env_id in self._env_ids
|
|
188
|
+
|
|
189
|
+
def append(self, task_progression: TaskProgression):
|
|
190
|
+
"""
|
|
191
|
+
Append a task progression
|
|
192
|
+
|
|
193
|
+
Parameters
|
|
194
|
+
----------
|
|
195
|
+
task_progression : TaskProgression
|
|
196
|
+
Task Progression
|
|
197
|
+
"""
|
|
198
|
+
self._tasks.append(task_progression)
|
|
199
|
+
self._env_ids.append(
|
|
200
|
+
(
|
|
201
|
+
ID(task_progression.task_update.swarm_id).tid,
|
|
202
|
+
task_progression.task_id.tid,
|
|
203
|
+
)
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
def filter(
|
|
207
|
+
self, condition: Callable[[TaskProgression], bool]
|
|
208
|
+
) -> Iterable[TaskProgression]:
|
|
209
|
+
"""
|
|
210
|
+
Filter keys given the condition function
|
|
211
|
+
|
|
212
|
+
Parameters
|
|
213
|
+
----------
|
|
214
|
+
condition : Callable[[TaskProgression], bool]
|
|
215
|
+
Condition function
|
|
216
|
+
|
|
217
|
+
Returns
|
|
218
|
+
-------
|
|
219
|
+
Iterable[TaskProgression]
|
|
220
|
+
Filtered keys
|
|
221
|
+
"""
|
|
222
|
+
return filter(condition, self._tasks)
|
|
223
|
+
|
|
224
|
+
def pop(self, env_id: Tuple[TupleID, TupleID]) -> TaskProgression:
|
|
225
|
+
"""
|
|
226
|
+
Pop a task progression given the task ID
|
|
227
|
+
|
|
228
|
+
Parameters
|
|
229
|
+
----------
|
|
230
|
+
task_id : Tuple[TupleID, TupleID]
|
|
231
|
+
Task and Swarms IDs in a tuple
|
|
232
|
+
|
|
233
|
+
Returns
|
|
234
|
+
-------
|
|
235
|
+
TaskProgression
|
|
236
|
+
Task progression popped
|
|
237
|
+
"""
|
|
238
|
+
if env_id not in self._env_ids:
|
|
239
|
+
raise KeyError(f"Cannot pop task due to {env_id} not found in tasks")
|
|
240
|
+
index = self._env_ids.index(env_id)
|
|
241
|
+
self._env_ids.pop(index)
|
|
242
|
+
return self._tasks.pop(index)
|
|
243
|
+
|
|
244
|
+
def active_tasks(self) -> Iterable[TaskProgression]:
|
|
245
|
+
"""
|
|
246
|
+
Return an iterable of active tasks
|
|
247
|
+
|
|
248
|
+
Returns
|
|
249
|
+
-------
|
|
250
|
+
Iterable[TaskProgression]
|
|
251
|
+
Active task progressions
|
|
252
|
+
"""
|
|
253
|
+
return (
|
|
254
|
+
task_progression
|
|
255
|
+
for task_progression in self._tasks
|
|
256
|
+
if task_progression.is_active_task()
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
def finished_tasks(self) -> Iterable[TaskProgression]:
|
|
260
|
+
"""
|
|
261
|
+
Return an iterable of finished tasks
|
|
262
|
+
|
|
263
|
+
Returns
|
|
264
|
+
-------
|
|
265
|
+
Iterable[TaskProgression]
|
|
266
|
+
Finished task progressions
|
|
267
|
+
"""
|
|
268
|
+
return (
|
|
269
|
+
task_progression
|
|
270
|
+
for task_progression in self._tasks
|
|
271
|
+
if task_progression.is_finished_task()
|
|
272
|
+
)
|
manta_node/utils.py
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import List
|
|
3
|
+
|
|
4
|
+
from manta_common.build.common.informations import Overview
|
|
5
|
+
|
|
6
|
+
__all__ = ["collect_dataset_overviews"]
|
|
7
|
+
|
|
8
|
+
DTYPES = {
|
|
9
|
+
".txt": "text",
|
|
10
|
+
".csv": "csv",
|
|
11
|
+
".npx": "numpy",
|
|
12
|
+
".npy": "numpy",
|
|
13
|
+
".npz": "numpy",
|
|
14
|
+
".np": "numpy",
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def collect_dataset_overviews(data_folder: Path) -> List[Overview]:
|
|
19
|
+
"""
|
|
20
|
+
Collect dataset overviews including :
|
|
21
|
+
|
|
22
|
+
- name of a dataset
|
|
23
|
+
- its description
|
|
24
|
+
- its dtype (numpy, pytorch ...)
|
|
25
|
+
|
|
26
|
+
Parameters
|
|
27
|
+
----------
|
|
28
|
+
data_folder: Path
|
|
29
|
+
Data folder
|
|
30
|
+
|
|
31
|
+
Returns
|
|
32
|
+
-------
|
|
33
|
+
List[Overview]
|
|
34
|
+
List of dataset overviews
|
|
35
|
+
"""
|
|
36
|
+
overviews = []
|
|
37
|
+
# Check if the file exists in the data_folder
|
|
38
|
+
if not data_folder.exists():
|
|
39
|
+
# Create the data folder
|
|
40
|
+
data_folder.mkdir(exist_ok=True)
|
|
41
|
+
return overviews
|
|
42
|
+
|
|
43
|
+
# Get the list of files in the data_folder
|
|
44
|
+
overviews = [
|
|
45
|
+
Overview(
|
|
46
|
+
name=file.name,
|
|
47
|
+
description="No description available",
|
|
48
|
+
dtype=DTYPES.get(file.suffix, "binary") if file.is_file() else "folder",
|
|
49
|
+
)
|
|
50
|
+
for file in data_folder.iterdir()
|
|
51
|
+
]
|
|
52
|
+
return overviews
|