meerschaum 2.3.5.dev0__py3-none-any.whl → 2.3.6__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.
- meerschaum/_internal/arguments/__init__.py +2 -1
- meerschaum/_internal/arguments/_parse_arguments.py +86 -7
- meerschaum/_internal/entry.py +29 -13
- meerschaum/actions/api.py +16 -16
- meerschaum/actions/start.py +3 -1
- meerschaum/api/_events.py +11 -7
- meerschaum/api/routes/_actions.py +0 -98
- meerschaum/api/routes/_jobs.py +38 -18
- meerschaum/config/_default.py +0 -1
- meerschaum/config/_version.py +1 -1
- meerschaum/config/stack/__init__.py +0 -2
- meerschaum/config/static/__init__.py +2 -0
- meerschaum/connectors/api/_actions.py +22 -36
- meerschaum/connectors/api/_jobs.py +1 -0
- meerschaum/jobs/_Job.py +26 -8
- meerschaum/jobs/systemd.py +20 -8
- meerschaum/utils/prompt.py +1 -1
- {meerschaum-2.3.5.dev0.dist-info → meerschaum-2.3.6.dist-info}/METADATA +1 -1
- {meerschaum-2.3.5.dev0.dist-info → meerschaum-2.3.6.dist-info}/RECORD +25 -25
- {meerschaum-2.3.5.dev0.dist-info → meerschaum-2.3.6.dist-info}/WHEEL +1 -1
- {meerschaum-2.3.5.dev0.dist-info → meerschaum-2.3.6.dist-info}/LICENSE +0 -0
- {meerschaum-2.3.5.dev0.dist-info → meerschaum-2.3.6.dist-info}/NOTICE +0 -0
- {meerschaum-2.3.5.dev0.dist-info → meerschaum-2.3.6.dist-info}/entry_points.txt +0 -0
- {meerschaum-2.3.5.dev0.dist-info → meerschaum-2.3.6.dist-info}/top_level.txt +0 -0
- {meerschaum-2.3.5.dev0.dist-info → meerschaum-2.3.6.dist-info}/zip-safe +0 -0
@@ -9,7 +9,8 @@ This package includes argument parsing utilities.
|
|
9
9
|
from meerschaum._internal.arguments._parse_arguments import (
|
10
10
|
parse_arguments, parse_line, remove_leading_action,
|
11
11
|
parse_dict_to_sysargs, split_chained_sysargs, split_pipeline_sysargs,
|
12
|
-
sysargs_has_api_executor_keys,
|
12
|
+
sysargs_has_api_executor_keys, get_pipeline_sysargs,
|
13
|
+
compress_pipeline_sysargs, remove_api_executor_keys,
|
13
14
|
)
|
14
15
|
from meerschaum._internal.arguments._parser import parser
|
15
16
|
from meerschaum.plugins import add_plugin_argument
|
@@ -424,12 +424,91 @@ def sysargs_has_api_executor_keys(sysargs: List[str]) -> bool:
|
|
424
424
|
if '-e' not in sysargs and '--executor-keys' not in sysargs:
|
425
425
|
return False
|
426
426
|
|
427
|
-
|
428
|
-
|
429
|
-
|
427
|
+
for i, arg in enumerate(sysargs):
|
428
|
+
if arg not in ('-e', '--executor-keys'):
|
429
|
+
continue
|
430
430
|
|
431
|
-
|
432
|
-
|
431
|
+
executor_keys_ix = i + 1
|
432
|
+
if len(sysargs) <= executor_keys_ix:
|
433
|
+
return False
|
434
|
+
|
435
|
+
executor_keys = sysargs[executor_keys_ix]
|
436
|
+
if executor_keys.startswith('api:'):
|
437
|
+
return True
|
438
|
+
|
439
|
+
return False
|
440
|
+
|
441
|
+
|
442
|
+
def remove_api_executor_keys(sysargs: List[str]) -> List[str]:
|
443
|
+
"""
|
444
|
+
Remove any api executor keys from `sysargs`.
|
445
|
+
"""
|
446
|
+
from meerschaum.utils.misc import flatten_list
|
447
|
+
|
448
|
+
if not sysargs_has_api_executor_keys(sysargs):
|
449
|
+
return sysargs
|
450
|
+
|
451
|
+
skip_indices = set(flatten_list(
|
452
|
+
[
|
453
|
+
[i, i+1]
|
454
|
+
for i, arg in enumerate(sysargs)
|
455
|
+
if arg in ('-e', '--executor-keys')
|
456
|
+
]
|
457
|
+
))
|
458
|
+
|
459
|
+
return [
|
460
|
+
arg
|
461
|
+
for i, arg in enumerate(sysargs)
|
462
|
+
if i not in skip_indices
|
463
|
+
]
|
433
464
|
|
434
|
-
|
435
|
-
|
465
|
+
|
466
|
+
def get_pipeline_sysargs(
|
467
|
+
sysargs: List[str],
|
468
|
+
pipeline_args: List[str],
|
469
|
+
_patch_args: Optional[Dict[str, Any]] = None,
|
470
|
+
) -> List[str]:
|
471
|
+
"""
|
472
|
+
Parse `sysargs` and `pipeline_args` into a single `start pipeline` sysargs.
|
473
|
+
"""
|
474
|
+
import shlex
|
475
|
+
start_pipeline_params = {
|
476
|
+
'sub_args_line': shlex.join(sysargs),
|
477
|
+
'patch_args': _patch_args,
|
478
|
+
}
|
479
|
+
return (
|
480
|
+
['start', 'pipeline']
|
481
|
+
+ [str(arg) for arg in pipeline_args]
|
482
|
+
+ ['-P', json.dumps(start_pipeline_params, separators=(',', ':'))]
|
483
|
+
)
|
484
|
+
|
485
|
+
|
486
|
+
def compress_pipeline_sysargs(pipeline_sysargs: List[str]) -> List[str]:
|
487
|
+
"""
|
488
|
+
Given a `start pipeline` sysargs, return a condensed syntax rendition.
|
489
|
+
"""
|
490
|
+
import shlex
|
491
|
+
|
492
|
+
if pipeline_sysargs[:2] != ['start', 'pipeline']:
|
493
|
+
return pipeline_sysargs
|
494
|
+
|
495
|
+
if '-P' not in pipeline_sysargs:
|
496
|
+
return pipeline_sysargs
|
497
|
+
|
498
|
+
params_ix = pipeline_sysargs.index('-P')
|
499
|
+
pipeline_args = pipeline_sysargs[2:params_ix]
|
500
|
+
params_str = pipeline_sysargs[-1]
|
501
|
+
try:
|
502
|
+
start_pipeline_params = json.loads(params_str)
|
503
|
+
except Exception:
|
504
|
+
return pipeline_sysargs
|
505
|
+
|
506
|
+
sub_args_line = start_pipeline_params.get('sub_args_line', None)
|
507
|
+
if not sub_args_line:
|
508
|
+
return pipeline_sysargs
|
509
|
+
|
510
|
+
return (
|
511
|
+
shlex.split(sub_args_line)
|
512
|
+
+ [':']
|
513
|
+
+ pipeline_args
|
514
|
+
)
|
meerschaum/_internal/entry.py
CHANGED
@@ -11,6 +11,8 @@ from __future__ import annotations
|
|
11
11
|
|
12
12
|
import os
|
13
13
|
import sys
|
14
|
+
import pathlib
|
15
|
+
|
14
16
|
from meerschaum.utils.typing import SuccessTuple, List, Optional, Dict, Callable, Any
|
15
17
|
from meerschaum.config.static import STATIC_CONFIG as _STATIC_CONFIG
|
16
18
|
|
@@ -19,8 +21,17 @@ if (_STATIC_CONFIG['environment']['systemd_log_path']) in os.environ:
|
|
19
21
|
from meerschaum.utils.daemon import RotatingFile as _RotatingFile, StdinFile as _StdinFile
|
20
22
|
from meerschaum.config import get_config as _get_config
|
21
23
|
|
22
|
-
_systemd_result_path =
|
23
|
-
|
24
|
+
_systemd_result_path = pathlib.Path(
|
25
|
+
os.environ[_STATIC_CONFIG['environment']['systemd_result_path']]
|
26
|
+
)
|
27
|
+
_systemd_log_path = pathlib.Path(
|
28
|
+
os.environ[_STATIC_CONFIG['environment']['systemd_log_path']]
|
29
|
+
)
|
30
|
+
_systemd_delete_job = (
|
31
|
+
(os.environ.get(_STATIC_CONFIG['environment']['systemd_delete_job'], None) or '0')
|
32
|
+
not in (None, '0', 'false')
|
33
|
+
)
|
34
|
+
_job_name = os.environ[_STATIC_CONFIG['environment']['daemon_id']]
|
24
35
|
_systemd_log = _RotatingFile(
|
25
36
|
_systemd_log_path,
|
26
37
|
write_timestamps=True,
|
@@ -51,6 +62,7 @@ def entry(
|
|
51
62
|
split_chained_sysargs,
|
52
63
|
split_pipeline_sysargs,
|
53
64
|
sysargs_has_api_executor_keys,
|
65
|
+
get_pipeline_sysargs,
|
54
66
|
)
|
55
67
|
from meerschaum.config.static import STATIC_CONFIG
|
56
68
|
if sysargs is None:
|
@@ -72,15 +84,7 @@ def entry(
|
|
72
84
|
else split_chained_sysargs(sysargs)
|
73
85
|
)
|
74
86
|
if pipeline_args:
|
75
|
-
|
76
|
-
'sub_args_line': shlex.join(sysargs),
|
77
|
-
'patch_args': _patch_args,
|
78
|
-
}
|
79
|
-
chained_sysargs = [
|
80
|
-
['start', 'pipeline']
|
81
|
-
+ [str(arg) for arg in pipeline_args]
|
82
|
-
+ ['-P', json.dumps(start_pipeline_params, separators=(',', ':'))]
|
83
|
-
]
|
87
|
+
chained_sysargs = [get_pipeline_sysargs(sysargs, pipeline_args, _patch_args=_patch_args)]
|
84
88
|
|
85
89
|
results: List[SuccessTuple] = []
|
86
90
|
|
@@ -169,8 +173,20 @@ def entry(
|
|
169
173
|
|
170
174
|
if _systemd_result_path:
|
171
175
|
import json
|
172
|
-
|
173
|
-
|
176
|
+
from meerschaum.utils.warnings import warn
|
177
|
+
import meerschaum as mrsm
|
178
|
+
|
179
|
+
job = mrsm.Job(_job_name, executor_keys='systemd')
|
180
|
+
if job.delete_after_completion:
|
181
|
+
delete_success, delete_msg = job.delete()
|
182
|
+
mrsm.pprint((delete_success, delete_msg))
|
183
|
+
else:
|
184
|
+
try:
|
185
|
+
if _systemd_result_path.parent.exists():
|
186
|
+
with open(_systemd_result_path, 'w+', encoding='utf-8') as f:
|
187
|
+
json.dump((success, msg), f)
|
188
|
+
except Exception as e:
|
189
|
+
warn(f"Failed to write job result:\n{e}")
|
174
190
|
|
175
191
|
return success, msg
|
176
192
|
|
meerschaum/actions/api.py
CHANGED
@@ -89,22 +89,22 @@ def api(
|
|
89
89
|
return success, message
|
90
90
|
|
91
91
|
def _api_start(
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
92
|
+
action: Optional[List[str]] = None,
|
93
|
+
host: Optional[str] = None,
|
94
|
+
port: Optional[int] = None,
|
95
|
+
workers: Optional[int] = None,
|
96
|
+
mrsm_instance: Optional[str] = None,
|
97
|
+
no_dash: bool = False,
|
98
|
+
no_auth: bool = False,
|
99
|
+
private: bool = False,
|
100
|
+
secure: bool = False,
|
101
|
+
debug: bool = False,
|
102
|
+
nopretty: bool = False,
|
103
|
+
production: bool = False,
|
104
|
+
keyfile: Optional[str] = None,
|
105
|
+
certfile: Optional[str] = None,
|
106
|
+
**kw: Any
|
107
|
+
) -> SuccessTuple:
|
108
108
|
"""Start the API server.
|
109
109
|
|
110
110
|
Parameters
|
meerschaum/actions/start.py
CHANGED
@@ -89,6 +89,7 @@ def _start_jobs(
|
|
89
89
|
name: Optional[str] = None,
|
90
90
|
sysargs: Optional[List[str]] = None,
|
91
91
|
executor_keys: Optional[str] = None,
|
92
|
+
rm: bool = False,
|
92
93
|
debug: bool = False,
|
93
94
|
**kw
|
94
95
|
) -> SuccessTuple:
|
@@ -210,7 +211,7 @@ def _start_jobs(
|
|
210
211
|
|
211
212
|
def _run_new_job(name: Optional[str] = None):
|
212
213
|
name = name or get_new_daemon_name()
|
213
|
-
job = Job(name, sysargs, executor_keys=executor_keys)
|
214
|
+
job = Job(name, sysargs, executor_keys=executor_keys, delete_after_completion=rm)
|
214
215
|
return job.start(debug=debug), name
|
215
216
|
|
216
217
|
def _run_existing_job(name: str):
|
@@ -568,6 +569,7 @@ def _start_pipeline(
|
|
568
569
|
else 1
|
569
570
|
)
|
570
571
|
|
572
|
+
params = params or {}
|
571
573
|
sub_args_line = params.get('sub_args_line', None)
|
572
574
|
patch_args = params.get('patch_args', None)
|
573
575
|
|
meerschaum/api/_events.py
CHANGED
@@ -20,12 +20,14 @@ from meerschaum.connectors.poll import retry_connect
|
|
20
20
|
from meerschaum.utils.warnings import warn
|
21
21
|
from meerschaum._internal.term.tools import is_webterm_running
|
22
22
|
from meerschaum.jobs import (
|
23
|
+
get_jobs,
|
23
24
|
start_check_jobs_thread,
|
24
25
|
stop_check_jobs_thread,
|
25
26
|
get_executor_keys_from_context,
|
26
27
|
)
|
28
|
+
from meerschaum.config.static import STATIC_CONFIG
|
27
29
|
|
28
|
-
|
30
|
+
TEMP_PREFIX: str = STATIC_CONFIG['api']['jobs']['temp_prefix']
|
29
31
|
|
30
32
|
@app.on_event("startup")
|
31
33
|
async def startup():
|
@@ -51,8 +53,7 @@ async def startup():
|
|
51
53
|
await shutdown()
|
52
54
|
os._exit(1)
|
53
55
|
|
54
|
-
|
55
|
-
start_check_jobs_thread()
|
56
|
+
start_check_jobs_thread()
|
56
57
|
|
57
58
|
|
58
59
|
@app.on_event("shutdown")
|
@@ -65,11 +66,14 @@ async def shutdown():
|
|
65
66
|
if get_api_connector().type == 'sql':
|
66
67
|
get_api_connector().engine.dispose()
|
67
68
|
|
68
|
-
|
69
|
-
stop_check_jobs_thread()
|
69
|
+
stop_check_jobs_thread()
|
70
70
|
|
71
|
-
|
72
|
-
|
71
|
+
temp_jobs = {
|
72
|
+
name: job
|
73
|
+
for name, job in get_jobs(include_hidden=True).items()
|
74
|
+
if name.startswith(TEMP_PREFIX)
|
75
|
+
}
|
76
|
+
for job in temp_jobs.values():
|
73
77
|
job.delete()
|
74
78
|
|
75
79
|
### Terminate any running jobs left over.
|
@@ -67,104 +67,6 @@ def get_actions(
|
|
67
67
|
return list(actions)
|
68
68
|
|
69
69
|
|
70
|
-
async def notify_client(client, content: str):
|
71
|
-
"""
|
72
|
-
Send a line of text to a client.
|
73
|
-
"""
|
74
|
-
try:
|
75
|
-
await client.send_text(content)
|
76
|
-
except (RuntimeError, WebSocketDisconnect, Exception):
|
77
|
-
raise StopMonitoringLogs
|
78
|
-
|
79
|
-
_temp_jobs = {}
|
80
|
-
@app.websocket(actions_endpoint + '/ws')
|
81
|
-
async def do_action_websocket(websocket: WebSocket):
|
82
|
-
"""
|
83
|
-
Execute an action and stream the output to the client.
|
84
|
-
"""
|
85
|
-
await websocket.accept()
|
86
|
-
|
87
|
-
stop_event = asyncio.Event()
|
88
|
-
job_name = '.' + generate_password(12)
|
89
|
-
job = None
|
90
|
-
|
91
|
-
async def monitor_logs(job):
|
92
|
-
success, msg = job.start()
|
93
|
-
await job.monitor_logs_async(
|
94
|
-
partial(notify_client, websocket),
|
95
|
-
stop_event=stop_event,
|
96
|
-
stop_on_exit=True,
|
97
|
-
)
|
98
|
-
|
99
|
-
try:
|
100
|
-
token = await websocket.receive_text()
|
101
|
-
user = await manager.get_current_user(token) if not no_auth else None
|
102
|
-
if user is None and not no_auth:
|
103
|
-
stop_event.set()
|
104
|
-
if job is not None:
|
105
|
-
job.delete()
|
106
|
-
_ = _temp_jobs.pop(job_name, None)
|
107
|
-
raise fastapi.HTTPException(
|
108
|
-
status_code=401,
|
109
|
-
detail="Invalid credentials.",
|
110
|
-
)
|
111
|
-
|
112
|
-
auth_success, auth_msg = (
|
113
|
-
is_user_allowed_to_execute(user)
|
114
|
-
if not no_auth
|
115
|
-
else (True, "Success")
|
116
|
-
)
|
117
|
-
auth_payload = {
|
118
|
-
'is_authenticated': auth_success,
|
119
|
-
'timestamp': datetime.now(timezone.utc).isoformat(),
|
120
|
-
}
|
121
|
-
await websocket.send_json(auth_payload)
|
122
|
-
if not auth_success:
|
123
|
-
stop_event.set()
|
124
|
-
job.stop()
|
125
|
-
await websocket.close()
|
126
|
-
|
127
|
-
sysargs = clean_sysargs(await websocket.receive_json())
|
128
|
-
job = Job(
|
129
|
-
job_name,
|
130
|
-
sysargs,
|
131
|
-
executor_keys='local',
|
132
|
-
_properties={
|
133
|
-
'logs': {
|
134
|
-
'write_timestamps': False,
|
135
|
-
},
|
136
|
-
},
|
137
|
-
)
|
138
|
-
_temp_jobs[job_name] = job
|
139
|
-
monitor_task = asyncio.create_task(monitor_logs(job))
|
140
|
-
|
141
|
-
### NOTE: Await incoming text to trigger `WebSocketDisconnect`.
|
142
|
-
while True:
|
143
|
-
await websocket.receive_text()
|
144
|
-
|
145
|
-
except fastapi.HTTPException:
|
146
|
-
await websocket.send_text("Invalid credentials.")
|
147
|
-
await websocket.close()
|
148
|
-
except (WebSocketDisconnect, asyncio.CancelledError):
|
149
|
-
stop_event.set()
|
150
|
-
job.stop()
|
151
|
-
except Exception:
|
152
|
-
stop_event.set()
|
153
|
-
job.stop()
|
154
|
-
warn(f"Error in logs websocket:\n{traceback.format_exc()}")
|
155
|
-
finally:
|
156
|
-
stop_event.set()
|
157
|
-
job.stop()
|
158
|
-
monitor_task.cancel()
|
159
|
-
if job is not None:
|
160
|
-
job.delete()
|
161
|
-
_ = _temp_jobs.pop(job_name, None)
|
162
|
-
try:
|
163
|
-
await websocket.close()
|
164
|
-
except RuntimeError:
|
165
|
-
pass
|
166
|
-
|
167
|
-
|
168
70
|
@app.post(actions_endpoint + "/{action}", tags=['Actions'])
|
169
71
|
def do_action_legacy(
|
170
72
|
action: str,
|
meerschaum/api/routes/_jobs.py
CHANGED
@@ -40,7 +40,15 @@ from meerschaum.config.static import STATIC_CONFIG
|
|
40
40
|
|
41
41
|
JOBS_STDIN_MESSAGE: str = STATIC_CONFIG['api']['jobs']['stdin_message']
|
42
42
|
JOBS_STOP_MESSAGE: str = STATIC_CONFIG['api']['jobs']['stop_message']
|
43
|
-
EXECUTOR_KEYS: str =
|
43
|
+
EXECUTOR_KEYS: str = 'local'
|
44
|
+
|
45
|
+
|
46
|
+
def _get_job(name: str):
|
47
|
+
systemd_job = Job(name, executor_keys='systemd')
|
48
|
+
if systemd_job.exists():
|
49
|
+
return systemd_job
|
50
|
+
|
51
|
+
return Job(name, executor_keys=EXECUTOR_KEYS)
|
44
52
|
|
45
53
|
|
46
54
|
@app.get(endpoints['jobs'], tags=['Jobs'])
|
@@ -52,7 +60,7 @@ def get_jobs(
|
|
52
60
|
"""
|
53
61
|
Return metadata about the current jobs.
|
54
62
|
"""
|
55
|
-
jobs = _get_jobs(executor_keys=EXECUTOR_KEYS, combine_local_and_systemd=
|
63
|
+
jobs = _get_jobs(executor_keys=EXECUTOR_KEYS, combine_local_and_systemd=True)
|
56
64
|
return {
|
57
65
|
name: {
|
58
66
|
'sysargs': job.sysargs,
|
@@ -83,7 +91,7 @@ def get_job(
|
|
83
91
|
"""
|
84
92
|
Return metadata for a single job.
|
85
93
|
"""
|
86
|
-
job =
|
94
|
+
job = _get_job(name)
|
87
95
|
if not job.exists():
|
88
96
|
raise fastapi.HTTPException(
|
89
97
|
status_code=404,
|
@@ -163,7 +171,7 @@ def delete_job(
|
|
163
171
|
"""
|
164
172
|
Delete a job.
|
165
173
|
"""
|
166
|
-
job =
|
174
|
+
job = _get_job(name)
|
167
175
|
return job.delete()
|
168
176
|
|
169
177
|
|
@@ -177,7 +185,7 @@ def get_job_exists(
|
|
177
185
|
"""
|
178
186
|
Return whether a job exists.
|
179
187
|
"""
|
180
|
-
job =
|
188
|
+
job = _get_job(name)
|
181
189
|
return job.exists()
|
182
190
|
|
183
191
|
|
@@ -192,7 +200,7 @@ def get_logs(
|
|
192
200
|
Return a job's log text.
|
193
201
|
To stream log text, connect to the WebSocket endpoint `/logs/{name}/ws`.
|
194
202
|
"""
|
195
|
-
job =
|
203
|
+
job = _get_job(name)
|
196
204
|
if not job.exists():
|
197
205
|
raise fastapi.HTTPException(
|
198
206
|
status_code=404,
|
@@ -212,7 +220,7 @@ def start_job(
|
|
212
220
|
"""
|
213
221
|
Start a job if stopped.
|
214
222
|
"""
|
215
|
-
job =
|
223
|
+
job = _get_job(name)
|
216
224
|
if not job.exists():
|
217
225
|
raise fastapi.HTTPException(
|
218
226
|
status_code=404,
|
@@ -231,7 +239,7 @@ def stop_job(
|
|
231
239
|
"""
|
232
240
|
Stop a job if running.
|
233
241
|
"""
|
234
|
-
job =
|
242
|
+
job = _get_job(name)
|
235
243
|
if not job.exists():
|
236
244
|
raise fastapi.HTTPException(
|
237
245
|
status_code=404,
|
@@ -250,7 +258,7 @@ def pause_job(
|
|
250
258
|
"""
|
251
259
|
Pause a job if running.
|
252
260
|
"""
|
253
|
-
job =
|
261
|
+
job = _get_job(name)
|
254
262
|
if not job.exists():
|
255
263
|
raise fastapi.HTTPException(
|
256
264
|
status_code=404,
|
@@ -269,7 +277,7 @@ def get_stop_time(
|
|
269
277
|
"""
|
270
278
|
Get the timestamp when the job was manually stopped.
|
271
279
|
"""
|
272
|
-
job =
|
280
|
+
job = _get_job(name)
|
273
281
|
return job.stop_time
|
274
282
|
|
275
283
|
|
@@ -283,12 +291,13 @@ def get_is_blocking_on_stdin(
|
|
283
291
|
"""
|
284
292
|
Return whether a job is blocking on stdin.
|
285
293
|
"""
|
286
|
-
job =
|
294
|
+
job = _get_job(name)
|
287
295
|
return job.is_blocking_on_stdin()
|
288
296
|
|
289
297
|
|
290
298
|
_job_clients = defaultdict(lambda: [])
|
291
299
|
_job_stop_events = defaultdict(lambda: asyncio.Event())
|
300
|
+
_job_queues = defaultdict(lambda: asyncio.Queue())
|
292
301
|
async def notify_clients(name: str, websocket: WebSocket, content: str):
|
293
302
|
"""
|
294
303
|
Write the given content to all connected clients.
|
@@ -315,12 +324,16 @@ async def get_input_from_clients(name: str, websocket: WebSocket) -> str:
|
|
315
324
|
async def _read_client(client):
|
316
325
|
try:
|
317
326
|
await client.send_text(JOBS_STDIN_MESSAGE)
|
318
|
-
data = await
|
327
|
+
data = await _job_queues[name].get()
|
319
328
|
except WebSocketDisconnect:
|
320
329
|
if client in _job_clients[name]:
|
321
330
|
_job_clients[name].remove(client)
|
331
|
+
if not _job_clients[name]:
|
332
|
+
_job_stop_events[name].set()
|
322
333
|
except Exception:
|
323
334
|
pass
|
335
|
+
finally:
|
336
|
+
_job_queues[name].task_done()
|
324
337
|
return data
|
325
338
|
|
326
339
|
read_tasks = [
|
@@ -357,10 +370,12 @@ async def logs_websocket(name: str, websocket: WebSocket):
|
|
357
370
|
Stream logs from a job over a websocket.
|
358
371
|
"""
|
359
372
|
await websocket.accept()
|
360
|
-
job =
|
373
|
+
job = _get_job(name)
|
361
374
|
_job_clients[name].append(websocket)
|
362
375
|
|
376
|
+
_task = None
|
363
377
|
async def monitor_logs():
|
378
|
+
nonlocal _task
|
364
379
|
try:
|
365
380
|
callback_function = partial(
|
366
381
|
notify_clients,
|
@@ -377,16 +392,17 @@ async def logs_websocket(name: str, websocket: WebSocket):
|
|
377
392
|
name,
|
378
393
|
websocket,
|
379
394
|
)
|
380
|
-
|
395
|
+
_task = asyncio.create_task(job.monitor_logs_async(
|
381
396
|
callback_function=callback_function,
|
382
397
|
input_callback_function=input_callback_function,
|
383
398
|
stop_callback_function=stop_callback_function,
|
384
399
|
stop_event=_job_stop_events[name],
|
385
400
|
stop_on_exit=True,
|
386
401
|
accept_input=True,
|
387
|
-
)
|
402
|
+
))
|
388
403
|
except Exception:
|
389
404
|
warn(traceback.format_exc())
|
405
|
+
_task.cancel()
|
390
406
|
|
391
407
|
try:
|
392
408
|
token = await websocket.receive_text()
|
@@ -397,13 +413,17 @@ async def logs_websocket(name: str, websocket: WebSocket):
|
|
397
413
|
detail="Invalid credentials.",
|
398
414
|
)
|
399
415
|
monitor_task = asyncio.create_task(monitor_logs())
|
400
|
-
|
416
|
+
while True:
|
417
|
+
text = await websocket.receive_text()
|
418
|
+
await _job_queues[name].put(text)
|
419
|
+
|
401
420
|
except fastapi.HTTPException:
|
402
421
|
await websocket.send_text("Invalid credentials.")
|
403
422
|
await websocket.close()
|
404
423
|
except WebSocketDisconnect:
|
405
|
-
|
406
|
-
|
424
|
+
if not _job_clients[name]:
|
425
|
+
_job_stop_events[name].set()
|
426
|
+
monitor_task.cancel()
|
407
427
|
except asyncio.CancelledError:
|
408
428
|
pass
|
409
429
|
except Exception:
|
meerschaum/config/_default.py
CHANGED
meerschaum/config/_version.py
CHANGED
@@ -56,7 +56,6 @@ env_dict['MEERSCHAUM_API_CONFIG'] = json.dumps(
|
|
56
56
|
|
57
57
|
volumes = {
|
58
58
|
'api_root': '/meerschaum',
|
59
|
-
'api_user_local': '/home/meerschaum/.local',
|
60
59
|
'meerschaum_db_data': '/var/lib/postgresql/data',
|
61
60
|
'grafana_storage': '/var/lib/grafana',
|
62
61
|
}
|
@@ -160,7 +159,6 @@ default_docker_compose_config = {
|
|
160
159
|
},
|
161
160
|
'volumes' : [
|
162
161
|
'api_root:' + volumes['api_root'],
|
163
|
-
'api_user_local:' + volumes['api_user_local'],
|
164
162
|
],
|
165
163
|
},
|
166
164
|
'grafana': {
|
@@ -46,6 +46,7 @@ STATIC_CONFIG: Dict[str, Any] = {
|
|
46
46
|
'stdin_message': 'MRSM_STDIN',
|
47
47
|
'stop_message': 'MRSM_STOP',
|
48
48
|
'metadata_cache_seconds': 5,
|
49
|
+
'temp_prefix': '.api-temp-',
|
49
50
|
},
|
50
51
|
},
|
51
52
|
'sql': {
|
@@ -73,6 +74,7 @@ STATIC_CONFIG: Dict[str, Any] = {
|
|
73
74
|
'systemd_log_path': 'MRSM_SYSTEMD_LOG_PATH',
|
74
75
|
'systemd_stdin_path': 'MRSM_SYSTEMD_STDIN_PATH',
|
75
76
|
'systemd_result_path': 'MRSM_SYSTEMD_RESULT_PATH',
|
77
|
+
'systemd_delete_job': 'MRSM_SYSTEMD_DELETE_JOB',
|
76
78
|
'uri_regex': r'MRSM_([a-zA-Z0-9]*)_(\d*[a-zA-Z][a-zA-Z0-9-_+]*$)',
|
77
79
|
'prefix': 'MRSM_',
|
78
80
|
},
|
@@ -17,6 +17,7 @@ from meerschaum.utils.typing import SuccessTuple, List, Callable, Optional
|
|
17
17
|
from meerschaum.config.static import STATIC_CONFIG
|
18
18
|
|
19
19
|
ACTIONS_ENDPOINT: str = STATIC_CONFIG['api']['endpoints']['actions']
|
20
|
+
TEMP_PREFIX: str = STATIC_CONFIG['api']['jobs']['temp_prefix']
|
20
21
|
|
21
22
|
|
22
23
|
def get_actions(self):
|
@@ -37,43 +38,28 @@ async def do_action_async(
|
|
37
38
|
callback_function: Callable[[str], None] = partial(print, end=''),
|
38
39
|
) -> SuccessTuple:
|
39
40
|
"""
|
40
|
-
|
41
|
+
Execute an action as a temporary remote job.
|
41
42
|
"""
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
while True:
|
64
|
-
try:
|
65
|
-
line = await websocket.recv()
|
66
|
-
if asyncio.iscoroutinefunction(callback_function):
|
67
|
-
await callback_function(line)
|
68
|
-
else:
|
69
|
-
callback_function(line)
|
70
|
-
except KeyboardInterrupt:
|
71
|
-
await websocket.close()
|
72
|
-
break
|
73
|
-
except websockets_exceptions.ConnectionClosedOK:
|
74
|
-
break
|
75
|
-
|
76
|
-
return True, "Success"
|
43
|
+
from meerschaum._internal.arguments import remove_api_executor_keys
|
44
|
+
from meerschaum.utils.misc import generate_password
|
45
|
+
sysargs = remove_api_executor_keys(sysargs)
|
46
|
+
|
47
|
+
job_name = TEMP_PREFIX + generate_password(12)
|
48
|
+
job = mrsm.Job(job_name, sysargs, executor_keys=str(self))
|
49
|
+
|
50
|
+
start_success, start_msg = job.start()
|
51
|
+
if not start_success:
|
52
|
+
return start_success, start_msg
|
53
|
+
|
54
|
+
await job.monitor_logs_async(
|
55
|
+
callback_function=callback_function,
|
56
|
+
stop_on_exit=True,
|
57
|
+
strip_timestamps=True,
|
58
|
+
)
|
59
|
+
|
60
|
+
success, msg = job.result
|
61
|
+
job.delete()
|
62
|
+
return success, msg
|
77
63
|
|
78
64
|
|
79
65
|
def do_action_legacy(
|
@@ -277,6 +277,7 @@ async def monitor_logs_async(
|
|
277
277
|
"""
|
278
278
|
Monitor a job's log files and await a callback with the changes.
|
279
279
|
"""
|
280
|
+
import traceback
|
280
281
|
from meerschaum.jobs import StopMonitoringLogs
|
281
282
|
from meerschaum.utils.formatting._jobs import strip_timestamp_from_line
|
282
283
|
|
meerschaum/jobs/_Job.py
CHANGED
@@ -60,9 +60,10 @@ class Job:
|
|
60
60
|
sysargs: Union[List[str], str, None] = None,
|
61
61
|
env: Optional[Dict[str, str]] = None,
|
62
62
|
executor_keys: Optional[str] = None,
|
63
|
+
delete_after_completion: bool = False,
|
63
64
|
_properties: Optional[Dict[str, Any]] = None,
|
64
|
-
_rotating_log
|
65
|
-
_stdin_file
|
65
|
+
_rotating_log=None,
|
66
|
+
_stdin_file=None,
|
66
67
|
_status_hook: Optional[Callable[[], str]] = None,
|
67
68
|
_result_hook: Optional[Callable[[], SuccessTuple]] = None,
|
68
69
|
_externally_managed: bool = False,
|
@@ -85,6 +86,9 @@ class Job:
|
|
85
86
|
executor_keys: Optional[str], default None
|
86
87
|
If provided, execute the job remotely on an API instance, e.g. 'api:main'.
|
87
88
|
|
89
|
+
delete_after_completion: bool, default False
|
90
|
+
If `True`, delete this job when it has finished executing.
|
91
|
+
|
88
92
|
_properties: Optional[Dict[str, Any]], default None
|
89
93
|
If provided, use this to patch the daemon's properties.
|
90
94
|
"""
|
@@ -146,6 +150,9 @@ class Job:
|
|
146
150
|
if env:
|
147
151
|
self._properties_patch.update({'env': env})
|
148
152
|
|
153
|
+
if delete_after_completion:
|
154
|
+
self._properties_patch.update({'delete_after_completion': delete_after_completion})
|
155
|
+
|
149
156
|
daemon_sysargs = (
|
150
157
|
self._daemon.properties.get('target', {}).get('args', [None])[0]
|
151
158
|
if self._daemon is not None
|
@@ -245,7 +252,7 @@ class Job:
|
|
245
252
|
return True, f"{self} is already running."
|
246
253
|
|
247
254
|
success, msg = self.daemon.run(
|
248
|
-
keep_daemon_output=
|
255
|
+
keep_daemon_output=(not self.delete_after_completion),
|
249
256
|
allow_dirty_run=True,
|
250
257
|
)
|
251
258
|
if not success:
|
@@ -407,7 +414,6 @@ class Job:
|
|
407
414
|
)
|
408
415
|
return asyncio.run(monitor_logs_coroutine)
|
409
416
|
|
410
|
-
|
411
417
|
async def monitor_logs_async(
|
412
418
|
self,
|
413
419
|
callback_function: Callable[[str], None] = partial(print, end='', flush=True),
|
@@ -418,8 +424,8 @@ class Job:
|
|
418
424
|
strip_timestamps: bool = False,
|
419
425
|
accept_input: bool = True,
|
420
426
|
_logs_path: Optional[pathlib.Path] = None,
|
421
|
-
_log
|
422
|
-
_stdin_file
|
427
|
+
_log=None,
|
428
|
+
_stdin_file=None,
|
423
429
|
debug: bool = False,
|
424
430
|
):
|
425
431
|
"""
|
@@ -466,6 +472,7 @@ class Job:
|
|
466
472
|
input_callback_function=input_callback_function,
|
467
473
|
stop_callback_function=stop_callback_function,
|
468
474
|
stop_on_exit=stop_on_exit,
|
475
|
+
strip_timestamps=strip_timestamps,
|
469
476
|
accept_input=accept_input,
|
470
477
|
debug=debug,
|
471
478
|
)
|
@@ -557,7 +564,6 @@ class Job:
|
|
557
564
|
for task in pending:
|
558
565
|
task.cancel()
|
559
566
|
except asyncio.exceptions.CancelledError:
|
560
|
-
print('cancelled?')
|
561
567
|
pass
|
562
568
|
finally:
|
563
569
|
combined_event.set()
|
@@ -870,7 +876,9 @@ class Job:
|
|
870
876
|
"""
|
871
877
|
Return the job's Daemon label (joined sysargs).
|
872
878
|
"""
|
873
|
-
|
879
|
+
from meerschaum._internal.arguments import compress_pipeline_sysargs
|
880
|
+
sysargs = compress_pipeline_sysargs(self.sysargs)
|
881
|
+
return shlex.join(sysargs).replace(' + ', '\n+ ')
|
874
882
|
|
875
883
|
@property
|
876
884
|
def _externally_managed_file(self) -> pathlib.Path:
|
@@ -916,6 +924,16 @@ class Job:
|
|
916
924
|
self._env = {**default_env, **_env}
|
917
925
|
return self._env
|
918
926
|
|
927
|
+
@property
|
928
|
+
def delete_after_completion(self) -> bool:
|
929
|
+
"""
|
930
|
+
Return whether this job is configured to delete itself after completion.
|
931
|
+
"""
|
932
|
+
if '_delete_after_completion' in self.__dict__:
|
933
|
+
return self.__dict__.get('_delete_after_completion', False)
|
934
|
+
|
935
|
+
self._delete_after_completion = self.daemon.properties.get('delete_after_completion', False)
|
936
|
+
return self._delete_after_completion
|
919
937
|
|
920
938
|
def __str__(self) -> str:
|
921
939
|
sysargs = self.sysargs
|
meerschaum/jobs/systemd.py
CHANGED
@@ -42,7 +42,12 @@ class SystemdExecutor(Executor):
|
|
42
42
|
return [
|
43
43
|
service_name[len('mrsm-'):(-1 * len('.service'))]
|
44
44
|
for service_name in os.listdir(SYSTEMD_USER_RESOURCES_PATH)
|
45
|
-
if
|
45
|
+
if (
|
46
|
+
service_name.startswith('mrsm-')
|
47
|
+
and service_name.endswith('.service')
|
48
|
+
### Check for broken symlinks.
|
49
|
+
and (SYSTEMD_USER_RESOURCES_PATH / service_name).exists()
|
50
|
+
)
|
46
51
|
]
|
47
52
|
|
48
53
|
def get_job_exists(self, name: str, debug: bool = False) -> bool:
|
@@ -146,6 +151,11 @@ class SystemdExecutor(Executor):
|
|
146
151
|
STATIC_CONFIG['environment']['systemd_log_path']: service_logs_path.as_posix(),
|
147
152
|
STATIC_CONFIG['environment']['systemd_result_path']: result_path.as_posix(),
|
148
153
|
STATIC_CONFIG['environment']['systemd_stdin_path']: socket_path.as_posix(),
|
154
|
+
STATIC_CONFIG['environment']['systemd_delete_job']: (
|
155
|
+
'1'
|
156
|
+
if job.delete_after_completion
|
157
|
+
else '0',
|
158
|
+
),
|
149
159
|
})
|
150
160
|
|
151
161
|
### Allow for user-defined environment variables.
|
@@ -603,7 +613,8 @@ class SystemdExecutor(Executor):
|
|
603
613
|
|
604
614
|
check_timeout_interval = get_config('jobs', 'check_timeout_interval_seconds')
|
605
615
|
loop_start = time.perf_counter()
|
606
|
-
|
616
|
+
timeout_seconds = get_config('jobs', 'timeout_seconds')
|
617
|
+
while (time.perf_counter() - loop_start) < timeout_seconds:
|
607
618
|
if self.get_job_status(name, debug=debug) == 'stopped':
|
608
619
|
return True, 'Success'
|
609
620
|
|
@@ -630,12 +641,14 @@ class SystemdExecutor(Executor):
|
|
630
641
|
Delete a job's service.
|
631
642
|
"""
|
632
643
|
from meerschaum.config.paths import SYSTEMD_LOGS_RESOURCES_PATH
|
644
|
+
job = self.get_hidden_job(name, debug=debug)
|
633
645
|
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
646
|
+
if not job.delete_after_completion:
|
647
|
+
_ = self.stop_job(name, debug=debug)
|
648
|
+
_ = self.run_command(
|
649
|
+
['disable', self.get_service_name(name, debug=debug)],
|
650
|
+
debug=debug,
|
651
|
+
)
|
639
652
|
|
640
653
|
service_job_path = self.get_service_job_path(name, debug=debug)
|
641
654
|
try:
|
@@ -666,7 +679,6 @@ class SystemdExecutor(Executor):
|
|
666
679
|
warn(e)
|
667
680
|
return False, str(e)
|
668
681
|
|
669
|
-
job = self.get_hidden_job(name, debug=debug)
|
670
682
|
_ = job.delete()
|
671
683
|
|
672
684
|
return self.run_command(['daemon-reload'], debug=debug)
|
meerschaum/utils/prompt.py
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
meerschaum/__init__.py,sha256=6bn5zz7VInDP4fE_FGBMzJYrM6rQhBMJNQqsf1pU7eI,1701
|
2
2
|
meerschaum/__main__.py,sha256=r5UjYxH1WA6dGG9YGBPul5xOdgF3Iwl0X4dWDtXU-30,2646
|
3
3
|
meerschaum/_internal/__init__.py,sha256=ilC7utfKtin7GAvuN34fKyUQYfPyqH0Mm3MJF5iyEf4,169
|
4
|
-
meerschaum/_internal/entry.py,sha256=
|
5
|
-
meerschaum/_internal/arguments/__init__.py,sha256=
|
6
|
-
meerschaum/_internal/arguments/_parse_arguments.py,sha256=
|
4
|
+
meerschaum/_internal/entry.py,sha256=XtGl-PPg9dLFlfbh_Wd5DUAdpjxqwQCxQxDrVf18QEE,12026
|
5
|
+
meerschaum/_internal/arguments/__init__.py,sha256=_nSKKVLXNsJeSv-buxEZsx8_c0BAbkhRyE4nT6Bv6q0,541
|
6
|
+
meerschaum/_internal/arguments/_parse_arguments.py,sha256=dtGjoyuKpQJtABdkQPzK1OM3Hd9JqlL-aQl_046tNa0,15976
|
7
7
|
meerschaum/_internal/arguments/_parser.py,sha256=LfiVDTr1akj5D31qpJAAXKxMcnLQiD3jRpZtvvHWrAo,14917
|
8
8
|
meerschaum/_internal/docs/__init__.py,sha256=ZQYHWo6n0kfLLkyG36YXqTYvv2Pc7it5HZHMylT6cBA,126
|
9
9
|
meerschaum/_internal/docs/index.py,sha256=LOxk1p_ChRkijfRGOB6UnoUEzt-SvtnMO56fTcSIMsU,24390
|
@@ -22,7 +22,7 @@ meerschaum/_internal/term/TermPageHandler.py,sha256=Rt5S47Pr_3HLJc8xIXpZUczYE_Dw
|
|
22
22
|
meerschaum/_internal/term/__init__.py,sha256=eXjfRzpnASWomB4xpY2AfzC_CLenkInNnVWSLZEexlg,1638
|
23
23
|
meerschaum/_internal/term/tools.py,sha256=dXVAimKD-Yv2fg2WOTr0YGBY7XDKjQqw-RizcS65YVI,727
|
24
24
|
meerschaum/actions/__init__.py,sha256=MHPs8aRBhbZQXnqd_6tVtisTrNCgPAPgnNcXYbn0zP8,11640
|
25
|
-
meerschaum/actions/api.py,sha256=
|
25
|
+
meerschaum/actions/api.py,sha256=nRHGeMTy0njI9Qec_606GwSS0AnoxiGJodOS8uWpjfU,12539
|
26
26
|
meerschaum/actions/attach.py,sha256=UV19d9W_2WYcrf7BRz7k3mriDoX1V4rA4AKvbLdor0o,3106
|
27
27
|
meerschaum/actions/bootstrap.py,sha256=9D3cBHzgZbZyWy-Y7iQgk9bpTbKEhumFKbIIThZgPXI,14058
|
28
28
|
meerschaum/actions/clear.py,sha256=OoFZE0bK5m8s3GLNZcixuVT0DMj1izXVxGCATcmUGbI,4851
|
@@ -44,7 +44,7 @@ meerschaum/actions/sh.py,sha256=fLfTJaacKu4sjLTRqEzzYlT2WbbdZBEczsKb6F-qAek,2026
|
|
44
44
|
meerschaum/actions/show.py,sha256=Ij6v5so9GHUrYVi7AhPfhHGjABBofXTPAljLFa2xuWA,28141
|
45
45
|
meerschaum/actions/sql.py,sha256=wYofwk1vGO96U2ncigGEfMtYMZeprz2FR1PRRZhkAPI,4311
|
46
46
|
meerschaum/actions/stack.py,sha256=7ODAxzmCx8i9AHxvkbr5ZtzUNPpY-iqlSVo4rZHMOw4,5900
|
47
|
-
meerschaum/actions/start.py,sha256=
|
47
|
+
meerschaum/actions/start.py,sha256=eYk4rUo8LijxK-GLbuH4j0dapv4BqzE5xw7-KaVcV2M,19419
|
48
48
|
meerschaum/actions/stop.py,sha256=5fdUw70YN-yuUWrC-NhA88cxr9FZ5NbssbQ8xXO8nFU,4632
|
49
49
|
meerschaum/actions/sync.py,sha256=AkH-1O5bkUC-UElQGr0lRhrX-z18ZY2nBPSy9EsW1Kc,17506
|
50
50
|
meerschaum/actions/tag.py,sha256=SJf5qFW0ccLXjqlTdkK_0MCcrCMdg6xhYrhKdco0hdA,3053
|
@@ -53,7 +53,7 @@ meerschaum/actions/upgrade.py,sha256=uhFhAPmguGDgxLa1UkVZnPQ-JRcbmOdExE38v-HrLvo
|
|
53
53
|
meerschaum/actions/verify.py,sha256=tY5slGpHiWiE0v9TDnjbmxSKn86zBnu9WBpixUgKNQU,4885
|
54
54
|
meerschaum/api/__init__.py,sha256=tjxyG8SQR_ymYuj3YUaadlguXBj-edL4kY_CxWYrYHk,7449
|
55
55
|
meerschaum/api/_chain.py,sha256=h8-WXUGXX6AqzdALfsBC5uv0FkAcLdHJXCGzqzuq89k,875
|
56
|
-
meerschaum/api/_events.py,sha256=
|
56
|
+
meerschaum/api/_events.py,sha256=6Bgch1x-R82tmnixLMYunqv8NumlkOn9ergBRU5-vdI,2247
|
57
57
|
meerschaum/api/_oauth2.py,sha256=SDdFbssy-9QoFBkuZZmep7mCX7jsn_zjqCbMXiksEVg,1647
|
58
58
|
meerschaum/api/_websockets.py,sha256=Rso85r4Yj8yUB-Oh8T8bGBvO5vCzZboryOjY-VnxdZQ,1601
|
59
59
|
meerschaum/api/dash/__init__.py,sha256=NkqnUP77c02J6sjWp5PGw48Hz9Dhov7gBO5f2mK2b40,2198
|
@@ -115,10 +115,10 @@ meerschaum/api/resources/templates/old_index.html,sha256=BDeOlcXhSsBH3-NaRtuX4Z1
|
|
115
115
|
meerschaum/api/resources/templates/secret.html,sha256=0QWkm4ZoN81Aw1pd2-62rGCvx3nXPHfFUoegj3Iy8Ls,141
|
116
116
|
meerschaum/api/resources/templates/termpage.html,sha256=qspXRuOkzqOn2mXw9mmUldzsvOHq_LyaywQ29CUevp0,4527
|
117
117
|
meerschaum/api/routes/__init__.py,sha256=jbkeFNl51Tg8aT5gWe560ZLZLojFJsLMe5IENRjRkb0,606
|
118
|
-
meerschaum/api/routes/_actions.py,sha256=
|
118
|
+
meerschaum/api/routes/_actions.py,sha256=9vRu4dsBfIBrfhkVWurvk8n-ClerlHxggiPgQhwP1Oo,3701
|
119
119
|
meerschaum/api/routes/_connectors.py,sha256=NNbcn5xWhKqw2PqueSEaqRaZ95hFGDKazG5lE7gsssc,1849
|
120
120
|
meerschaum/api/routes/_index.py,sha256=QI6CBo6pI2Zi0a6fJHDjZfiLa9f4okb0BGe3A_JD0kM,578
|
121
|
-
meerschaum/api/routes/_jobs.py,sha256=
|
121
|
+
meerschaum/api/routes/_jobs.py,sha256=znS8Pt5kvrRpv_ZOwRftbvQ1jpNfQ1-ngMy7kPgI5iM,11567
|
122
122
|
meerschaum/api/routes/_login.py,sha256=psPKmFkXgYVX83NepqwIhaLsQ5uWgOc4F2QZtPGxY1A,2482
|
123
123
|
meerschaum/api/routes/_misc.py,sha256=05--9ZVFeaCgZrHER2kA3SYdK4TyfkEXOCjLvPbum-w,2469
|
124
124
|
meerschaum/api/routes/_pipes.py,sha256=1gBuE4E-QvIK_kmbmiw7uLcXjnIobFI1t4tb2skpp6E,21592
|
@@ -129,7 +129,7 @@ meerschaum/api/routes/_webterm.py,sha256=7eilgDXckpEc2LyeNmJS5YO6HxlyMkwPnAMWd7e
|
|
129
129
|
meerschaum/api/tables/__init__.py,sha256=e2aNC0CdlWICTUMx1i9RauF8Pm426J0RZJbsJWv4SWo,482
|
130
130
|
meerschaum/config/__init__.py,sha256=jZgQSjvbOWyvGouqRgIeYBg9Pp343_9CDsCWWpwYDGY,11577
|
131
131
|
meerschaum/config/_dash.py,sha256=BJHl4xMrQB-YHUEU7ldEW8q_nOPoIRSOqLrfGElc6Dw,187
|
132
|
-
meerschaum/config/_default.py,sha256=
|
132
|
+
meerschaum/config/_default.py,sha256=LuPp-se3DsUglYRRr88nqU7PCdsMllbRuAJvtaogQu8,5313
|
133
133
|
meerschaum/config/_edit.py,sha256=_kabgFbJdI5kcLs-JIsoaTo0JdyxnPnBdrlTyTAgPm8,8236
|
134
134
|
meerschaum/config/_environment.py,sha256=Vv4DLDfc2vKLbCLsMvkQDj77K4kEvHKEBmUBo-wCrgo,4419
|
135
135
|
meerschaum/config/_formatting.py,sha256=OMuqS1EWOsj_34wSs2tOqGIWci3bTMIZ5l-uelZgsIM,6672
|
@@ -140,24 +140,24 @@ meerschaum/config/_preprocess.py,sha256=-AEA8m_--KivZwTQ1sWN6LTn5sio_fUr2XZ51BO6
|
|
140
140
|
meerschaum/config/_read_config.py,sha256=WFZKIXZMDe_ca0ES7ivgM_mnwShvFxLdoeisT_X5-h0,14720
|
141
141
|
meerschaum/config/_shell.py,sha256=46_m49Txc5q1rGfCgO49ca48BODx45DQJi8D0zz1R18,4245
|
142
142
|
meerschaum/config/_sync.py,sha256=oK2ZujO2T1he08BXCFyiniBUevNGWSQKXLcS_jRv_7Y,4155
|
143
|
-
meerschaum/config/_version.py,sha256=
|
143
|
+
meerschaum/config/_version.py,sha256=5vwwTic_40GgjRL5Yt4nGmmLyCYvMKKKyfPqYmEzffQ,71
|
144
144
|
meerschaum/config/paths.py,sha256=JjibeGN3YAdSNceRwsd42aNmeUrIgM6ndzC8qZAmNI0,621
|
145
145
|
meerschaum/config/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
146
|
-
meerschaum/config/stack/__init__.py,sha256=
|
146
|
+
meerschaum/config/stack/__init__.py,sha256=WNcVSaMbIcSYi75hn2kRQeJ0j1ZGjjBvsZVTQwD50sA,9002
|
147
147
|
meerschaum/config/stack/grafana/__init__.py,sha256=LNXQw2FvHKrD68RDhqDmi2wJjAHaKw9IWx8rNuyWEPo,2010
|
148
148
|
meerschaum/config/stack/mosquitto/__init__.py,sha256=-OwOjq8KiBoSH_pmgCAAF3Dp3CRD4KgAEdimZSadROs,186
|
149
149
|
meerschaum/config/stack/mosquitto/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
150
150
|
meerschaum/config/stack/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
151
|
-
meerschaum/config/static/__init__.py,sha256=
|
151
|
+
meerschaum/config/static/__init__.py,sha256=SLAcxX69MFiZBbonn3YiBxOHtdkPoz5Sbtz0Tt9CjKY,5225
|
152
152
|
meerschaum/connectors/Connector.py,sha256=utNV3Fy5DhUVbQE-vtm7enH5rH2gxQERmgmP7PUzH30,6682
|
153
153
|
meerschaum/connectors/__init__.py,sha256=fLoatCZV2hsDffYEg2aBzqPLzM_2o1_Z3X2iZvLwoqA,12503
|
154
154
|
meerschaum/connectors/parse.py,sha256=sDeI2OIS9Inwhbn9jkFAXxOPnmmAHqsuHiiHfWjVnSA,4307
|
155
155
|
meerschaum/connectors/poll.py,sha256=gIY9TvFBqMvMNQvR0O2No7koLLz2PjfExBr_Dsosgpg,7363
|
156
156
|
meerschaum/connectors/api/APIConnector.py,sha256=MPYeImCBAeSpueYis5CxkfT7kkV82MnGKDLoNE8uOVw,5017
|
157
157
|
meerschaum/connectors/api/__init__.py,sha256=JwKrGtuE5aOd2VnsRwudFBYyBf5IxczOwPVdNvCUgSQ,205
|
158
|
-
meerschaum/connectors/api/_actions.py,sha256=
|
158
|
+
meerschaum/connectors/api/_actions.py,sha256=gd3F8i5BvN8XRvMcPvPVR8sc1DeLzgoBHdDhc8PtACE,3966
|
159
159
|
meerschaum/connectors/api/_fetch.py,sha256=Khq9AFr1nk8Dsmcedb77aWhAuHw0JGgVeahDG95Q5MQ,2072
|
160
|
-
meerschaum/connectors/api/_jobs.py,sha256=
|
160
|
+
meerschaum/connectors/api/_jobs.py,sha256=N5lpHFGG10jlVgaJeWAOTuLBQw3AdgjXsEPpp1YwZQE,11270
|
161
161
|
meerschaum/connectors/api/_login.py,sha256=5GsD-B214vr5EYfM3XrTUs1sTFApxZA-9dNxq8oNSyg,2050
|
162
162
|
meerschaum/connectors/api/_misc.py,sha256=OZRZBYOokKIEjmQaR8jUYgu6ZRn9VzXBChzR8CfDv_w,1092
|
163
163
|
meerschaum/connectors/api/_pipes.py,sha256=Nnc-IShiTkCia548dePymKosQCcl2InFCyUX3Q-Xx6Q,20604
|
@@ -201,9 +201,9 @@ meerschaum/core/Plugin/__init__.py,sha256=UXg64EvJPgI1PCxkY_KM02-ZmBm4FZpLPIQR_u
|
|
201
201
|
meerschaum/core/User/_User.py,sha256=CApB7Y0QJL6S9QOCCfrG4SbPuPXJ9AsAYQ5pASMP_Aw,6527
|
202
202
|
meerschaum/core/User/__init__.py,sha256=lJ7beIZTG9sO4dAi3367fFBl17dXYEWHKi7HoaPlDyk,193
|
203
203
|
meerschaum/jobs/_Executor.py,sha256=qM62BhFTM4tyJ7p90KOM0y3qyeRY9k3ZV_aTDJMHnO8,1682
|
204
|
-
meerschaum/jobs/_Job.py,sha256=
|
204
|
+
meerschaum/jobs/_Job.py,sha256=XnvS-qN12907t23OG1suBJ5k_TDuXkS1diNE_1xNAF0,32152
|
205
205
|
meerschaum/jobs/__init__.py,sha256=ieruFbPxozkgyYMEO5wWQ4OXqfD5Pw9VtFWGub6DQxs,11970
|
206
|
-
meerschaum/jobs/systemd.py,sha256=
|
206
|
+
meerschaum/jobs/systemd.py,sha256=Rq-tsDPslG17ZhpKMrVJ5r8Z0IPr6DEc9APObfIoXCg,24614
|
207
207
|
meerschaum/plugins/_Plugin.py,sha256=p6j39tm-xrZENBq-eGtixBuXxLLddtEKWRCRFNqpRu0,34086
|
208
208
|
meerschaum/plugins/__init__.py,sha256=trMQ53qgP7ikJhhV_uXzqJw6X1NDz2rPOGXFk40bb1Y,26190
|
209
209
|
meerschaum/plugins/bootstrap.py,sha256=qg9MQ1YAU8ShwGqWDl38WjiXLIxDPl95pSIGDLN9rOw,11423
|
@@ -216,7 +216,7 @@ meerschaum/utils/misc.py,sha256=2f0wLQ0ymdOh5-5iP-jlyUxSUStvQAn5ot5_0GZTg-8,4638
|
|
216
216
|
meerschaum/utils/networking.py,sha256=Sr_eYUGW8_UV9-k9LqRFf7xLtbUcsDucODyLCRsFRUc,1006
|
217
217
|
meerschaum/utils/pool.py,sha256=vkE42af4fjrTEJTxf6Ek3xGucm1MtEkpsSEiaVzNKHs,2655
|
218
218
|
meerschaum/utils/process.py,sha256=o7UtTQX87YGkg2dItPhlvN7gNQPkElXTYSzKf5Ro8Uc,7474
|
219
|
-
meerschaum/utils/prompt.py,sha256=
|
219
|
+
meerschaum/utils/prompt.py,sha256=0asF_ndumQIN7p5kEOzK-ldsdE4m8FFapcT3-4wgPi8,19010
|
220
220
|
meerschaum/utils/schedule.py,sha256=WSJ0eDGvCVxkQwbUc_7vNm0uuKf9WJcY2NCZZdbnZrk,10837
|
221
221
|
meerschaum/utils/sql.py,sha256=4sCNEpgUd6uFz6ySs4nnUMVaOT0YAvPM1ZlQYJTSF-0,46656
|
222
222
|
meerschaum/utils/threading.py,sha256=3N8JXPAnwqJiSjuQcbbJg3Rv9-CCUMJpeQRfKFR7MaA,2489
|
@@ -241,11 +241,11 @@ meerschaum/utils/packages/_packages.py,sha256=GzbJ0kxW_EQogXmY4vguRkUyad42cshFs7
|
|
241
241
|
meerschaum/utils/packages/lazy_loader.py,sha256=VHnph3VozH29R4JnSSBfwtA5WKZYZQFT_GeQSShCnuc,2540
|
242
242
|
meerschaum/utils/venv/_Venv.py,sha256=sBnlmxHdAh2bx8btfVoD79-H9-cYsv5lP02IIXkyECs,3553
|
243
243
|
meerschaum/utils/venv/__init__.py,sha256=bLAWnllKDuE_z6bLk7gLh4mI3Sp1j5hsboTqPKOQq84,24361
|
244
|
-
meerschaum-2.3.
|
245
|
-
meerschaum-2.3.
|
246
|
-
meerschaum-2.3.
|
247
|
-
meerschaum-2.3.
|
248
|
-
meerschaum-2.3.
|
249
|
-
meerschaum-2.3.
|
250
|
-
meerschaum-2.3.
|
251
|
-
meerschaum-2.3.
|
244
|
+
meerschaum-2.3.6.dist-info/LICENSE,sha256=jG2zQEdRNt88EgHUWPpXVWmOrOduUQRx7MnYV9YIPaw,11359
|
245
|
+
meerschaum-2.3.6.dist-info/METADATA,sha256=tyAwvxygzzfTbfg_HW3zlWQ_08IDqb0HDSswLfVzbiM,24006
|
246
|
+
meerschaum-2.3.6.dist-info/NOTICE,sha256=OTA9Fcthjf5BRvWDDIcBC_xfLpeDV-RPZh3M-HQBRtQ,114
|
247
|
+
meerschaum-2.3.6.dist-info/WHEEL,sha256=HiCZjzuy6Dw0hdX5R3LCFPDmFS4BWl8H-8W39XfmgX4,91
|
248
|
+
meerschaum-2.3.6.dist-info/entry_points.txt,sha256=5YBVzibw-0rNA_1VjB16z5GABsOGf-CDhW4yqH8C7Gc,88
|
249
|
+
meerschaum-2.3.6.dist-info/top_level.txt,sha256=bNoSiDj0El6buocix-FRoAtJOeq1qOF5rRm2u9i7Q6A,11
|
250
|
+
meerschaum-2.3.6.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
251
|
+
meerschaum-2.3.6.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|