meerschaum 2.9.4__py3-none-any.whl → 3.0.0__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/__init__.py +5 -2
- meerschaum/_internal/__init__.py +1 -0
- meerschaum/_internal/arguments/_parse_arguments.py +4 -4
- meerschaum/_internal/arguments/_parser.py +33 -4
- meerschaum/_internal/cli/__init__.py +6 -0
- meerschaum/_internal/cli/daemons.py +103 -0
- meerschaum/_internal/cli/entry.py +220 -0
- meerschaum/_internal/cli/workers.py +435 -0
- meerschaum/_internal/docs/index.py +48 -2
- meerschaum/_internal/entry.py +50 -14
- meerschaum/_internal/shell/Shell.py +121 -29
- meerschaum/_internal/shell/__init__.py +4 -1
- meerschaum/_internal/static.py +359 -0
- meerschaum/_internal/term/TermPageHandler.py +1 -2
- meerschaum/_internal/term/__init__.py +40 -6
- meerschaum/_internal/term/tools.py +33 -8
- meerschaum/actions/__init__.py +6 -4
- meerschaum/actions/api.py +53 -13
- meerschaum/actions/attach.py +1 -0
- meerschaum/actions/bootstrap.py +8 -8
- meerschaum/actions/delete.py +4 -2
- meerschaum/actions/edit.py +171 -25
- meerschaum/actions/login.py +8 -8
- meerschaum/actions/register.py +143 -6
- meerschaum/actions/reload.py +22 -5
- meerschaum/actions/restart.py +14 -0
- meerschaum/actions/show.py +184 -31
- meerschaum/actions/start.py +166 -17
- meerschaum/actions/stop.py +38 -2
- meerschaum/actions/sync.py +7 -2
- meerschaum/actions/tag.py +9 -8
- meerschaum/actions/verify.py +5 -8
- meerschaum/api/__init__.py +45 -15
- meerschaum/api/_events.py +46 -4
- meerschaum/api/_oauth2.py +162 -9
- meerschaum/api/_tokens.py +102 -0
- meerschaum/api/dash/__init__.py +0 -3
- meerschaum/api/dash/callbacks/__init__.py +1 -0
- meerschaum/api/dash/callbacks/custom.py +4 -3
- meerschaum/api/dash/callbacks/dashboard.py +228 -117
- meerschaum/api/dash/callbacks/jobs.py +14 -7
- meerschaum/api/dash/callbacks/login.py +10 -1
- meerschaum/api/dash/callbacks/pipes.py +194 -14
- meerschaum/api/dash/callbacks/plugins.py +0 -1
- meerschaum/api/dash/callbacks/register.py +10 -3
- meerschaum/api/dash/callbacks/settings/password_reset.py +2 -2
- meerschaum/api/dash/callbacks/tokens.py +389 -0
- meerschaum/api/dash/components.py +36 -15
- meerschaum/api/dash/jobs.py +1 -1
- meerschaum/api/dash/keys.py +35 -93
- meerschaum/api/dash/pages/__init__.py +2 -1
- meerschaum/api/dash/pages/dashboard.py +1 -20
- meerschaum/api/dash/pages/{job.py → jobs.py} +10 -7
- meerschaum/api/dash/pages/login.py +2 -2
- meerschaum/api/dash/pages/pipes.py +16 -5
- meerschaum/api/dash/pages/settings/password_reset.py +1 -1
- meerschaum/api/dash/pages/tokens.py +53 -0
- meerschaum/api/dash/pipes.py +438 -88
- meerschaum/api/dash/sessions.py +12 -0
- meerschaum/api/dash/tokens.py +603 -0
- meerschaum/api/dash/websockets.py +1 -1
- meerschaum/api/dash/webterm.py +18 -6
- meerschaum/api/models/__init__.py +23 -3
- meerschaum/api/models/_actions.py +22 -0
- meerschaum/api/models/_pipes.py +91 -7
- meerschaum/api/models/_tokens.py +81 -0
- meerschaum/api/resources/static/css/dash.css +16 -0
- meerschaum/api/resources/static/js/terminado.js +3 -0
- meerschaum/api/resources/static/js/xterm-addon-unicode11.js +2 -0
- meerschaum/api/resources/templates/termpage.html +13 -0
- meerschaum/api/routes/__init__.py +1 -0
- meerschaum/api/routes/_actions.py +3 -4
- meerschaum/api/routes/_connectors.py +3 -7
- meerschaum/api/routes/_jobs.py +26 -35
- meerschaum/api/routes/_login.py +120 -15
- meerschaum/api/routes/_misc.py +5 -10
- meerschaum/api/routes/_pipes.py +178 -143
- meerschaum/api/routes/_plugins.py +38 -28
- meerschaum/api/routes/_tokens.py +236 -0
- meerschaum/api/routes/_users.py +47 -35
- meerschaum/api/routes/_version.py +3 -3
- meerschaum/api/routes/_webterm.py +3 -3
- meerschaum/config/__init__.py +100 -30
- meerschaum/config/_default.py +132 -64
- meerschaum/config/_edit.py +38 -32
- meerschaum/config/_formatting.py +2 -0
- meerschaum/config/_patch.py +10 -8
- meerschaum/config/_paths.py +133 -13
- meerschaum/config/_read_config.py +87 -36
- meerschaum/config/_sync.py +6 -3
- meerschaum/config/_version.py +1 -1
- meerschaum/config/environment.py +262 -0
- meerschaum/config/stack/__init__.py +37 -15
- meerschaum/config/static.py +18 -0
- meerschaum/connectors/_Connector.py +11 -6
- meerschaum/connectors/__init__.py +41 -22
- meerschaum/connectors/api/_APIConnector.py +34 -6
- meerschaum/connectors/api/_actions.py +2 -2
- meerschaum/connectors/api/_jobs.py +12 -1
- meerschaum/connectors/api/_login.py +33 -7
- meerschaum/connectors/api/_misc.py +2 -2
- meerschaum/connectors/api/_pipes.py +23 -32
- meerschaum/connectors/api/_plugins.py +2 -2
- meerschaum/connectors/api/_request.py +1 -1
- meerschaum/connectors/api/_tokens.py +146 -0
- meerschaum/connectors/api/_users.py +70 -58
- meerschaum/connectors/instance/_InstanceConnector.py +83 -0
- meerschaum/connectors/instance/__init__.py +10 -0
- meerschaum/connectors/instance/_pipes.py +442 -0
- meerschaum/connectors/instance/_plugins.py +159 -0
- meerschaum/connectors/instance/_tokens.py +317 -0
- meerschaum/connectors/instance/_users.py +188 -0
- meerschaum/connectors/parse.py +5 -2
- meerschaum/connectors/sql/_SQLConnector.py +22 -5
- meerschaum/connectors/sql/_cli.py +12 -11
- meerschaum/connectors/sql/_create_engine.py +12 -168
- meerschaum/connectors/sql/_fetch.py +2 -18
- meerschaum/connectors/sql/_pipes.py +295 -278
- meerschaum/connectors/sql/_plugins.py +29 -0
- meerschaum/connectors/sql/_sql.py +47 -22
- meerschaum/connectors/sql/_users.py +36 -2
- meerschaum/connectors/sql/tables/__init__.py +254 -122
- meerschaum/connectors/valkey/_ValkeyConnector.py +5 -7
- meerschaum/connectors/valkey/_pipes.py +60 -31
- meerschaum/connectors/valkey/_plugins.py +2 -26
- meerschaum/core/Pipe/__init__.py +115 -85
- meerschaum/core/Pipe/_attributes.py +425 -124
- meerschaum/core/Pipe/_bootstrap.py +54 -24
- meerschaum/core/Pipe/_cache.py +555 -0
- meerschaum/core/Pipe/_clear.py +0 -11
- meerschaum/core/Pipe/_data.py +96 -68
- meerschaum/core/Pipe/_deduplicate.py +0 -13
- meerschaum/core/Pipe/_delete.py +12 -21
- meerschaum/core/Pipe/_drop.py +11 -23
- meerschaum/core/Pipe/_dtypes.py +49 -19
- meerschaum/core/Pipe/_edit.py +14 -4
- meerschaum/core/Pipe/_fetch.py +1 -1
- meerschaum/core/Pipe/_index.py +8 -14
- meerschaum/core/Pipe/_show.py +5 -5
- meerschaum/core/Pipe/_sync.py +123 -204
- meerschaum/core/Pipe/_verify.py +4 -4
- meerschaum/{plugins → core/Plugin}/_Plugin.py +16 -12
- meerschaum/core/Plugin/__init__.py +1 -1
- meerschaum/core/Token/_Token.py +220 -0
- meerschaum/core/Token/__init__.py +12 -0
- meerschaum/core/User/_User.py +35 -10
- meerschaum/core/User/__init__.py +9 -1
- meerschaum/core/__init__.py +1 -0
- meerschaum/jobs/_Executor.py +88 -4
- meerschaum/jobs/_Job.py +149 -38
- meerschaum/jobs/__init__.py +3 -2
- meerschaum/jobs/systemd.py +8 -3
- meerschaum/models/__init__.py +35 -0
- meerschaum/models/pipes.py +247 -0
- meerschaum/models/tokens.py +38 -0
- meerschaum/models/users.py +26 -0
- meerschaum/plugins/__init__.py +301 -88
- meerschaum/plugins/bootstrap.py +510 -4
- meerschaum/utils/_get_pipes.py +97 -30
- meerschaum/utils/daemon/Daemon.py +199 -43
- meerschaum/utils/daemon/FileDescriptorInterceptor.py +0 -1
- meerschaum/utils/daemon/RotatingFile.py +63 -36
- meerschaum/utils/daemon/StdinFile.py +53 -13
- meerschaum/utils/daemon/__init__.py +47 -6
- meerschaum/utils/daemon/_names.py +6 -3
- meerschaum/utils/dataframe.py +480 -82
- meerschaum/utils/debug.py +49 -19
- meerschaum/utils/dtypes/__init__.py +478 -37
- meerschaum/utils/dtypes/sql.py +369 -29
- meerschaum/utils/formatting/__init__.py +5 -2
- meerschaum/utils/formatting/_jobs.py +1 -1
- meerschaum/utils/formatting/_pipes.py +52 -50
- meerschaum/utils/formatting/_pprint.py +1 -0
- meerschaum/utils/formatting/_shell.py +44 -18
- meerschaum/utils/misc.py +268 -186
- meerschaum/utils/packages/__init__.py +25 -40
- meerschaum/utils/packages/_packages.py +42 -34
- meerschaum/utils/pipes.py +213 -0
- meerschaum/utils/process.py +2 -2
- meerschaum/utils/prompt.py +175 -144
- meerschaum/utils/schedule.py +2 -1
- meerschaum/utils/sql.py +135 -49
- meerschaum/utils/threading.py +42 -0
- meerschaum/utils/typing.py +1 -4
- meerschaum/utils/venv/_Venv.py +2 -2
- meerschaum/utils/venv/__init__.py +7 -7
- meerschaum/utils/warnings.py +19 -13
- {meerschaum-2.9.4.dist-info → meerschaum-3.0.0.dist-info}/METADATA +94 -96
- meerschaum-3.0.0.dist-info/RECORD +289 -0
- {meerschaum-2.9.4.dist-info → meerschaum-3.0.0.dist-info}/WHEEL +1 -1
- meerschaum-3.0.0.dist-info/licenses/NOTICE +2 -0
- meerschaum/api/models/_interfaces.py +0 -15
- meerschaum/api/models/_locations.py +0 -15
- meerschaum/api/models/_metrics.py +0 -15
- meerschaum/config/_environment.py +0 -145
- meerschaum/config/static/__init__.py +0 -186
- meerschaum-2.9.4.dist-info/RECORD +0 -263
- {meerschaum-2.9.4.dist-info → meerschaum-3.0.0.dist-info}/entry_points.txt +0 -0
- {meerschaum-2.9.4.dist-info → meerschaum-3.0.0.dist-info}/licenses/LICENSE +0 -0
- {meerschaum-2.9.4.dist-info → meerschaum-3.0.0.dist-info}/top_level.txt +0 -0
- {meerschaum-2.9.4.dist-info → meerschaum-3.0.0.dist-info}/zip-safe +0 -0
meerschaum/actions/start.py
CHANGED
@@ -7,6 +7,8 @@ Start subsystems (API server, logging daemon, etc.).
|
|
7
7
|
"""
|
8
8
|
|
9
9
|
from __future__ import annotations
|
10
|
+
|
11
|
+
import meerschaum as mrsm
|
10
12
|
from meerschaum.utils.typing import SuccessTuple, Optional, List, Any, Union, Dict
|
11
13
|
|
12
14
|
|
@@ -25,6 +27,7 @@ def start(
|
|
25
27
|
'webterm': _start_webterm,
|
26
28
|
'connectors': _start_connectors,
|
27
29
|
'pipeline': _start_pipeline,
|
30
|
+
'daemons': _start_daemons,
|
28
31
|
}
|
29
32
|
return choose_subaction(action, options, **kw)
|
30
33
|
|
@@ -91,6 +94,7 @@ def _start_jobs(
|
|
91
94
|
sysargs: Optional[List[str]] = None,
|
92
95
|
executor_keys: Optional[str] = None,
|
93
96
|
rm: bool = False,
|
97
|
+
line: Optional[str] = None,
|
94
98
|
debug: bool = False,
|
95
99
|
**kw
|
96
100
|
) -> SuccessTuple:
|
@@ -122,6 +126,7 @@ def _start_jobs(
|
|
122
126
|
- `start job --name happy_seal`
|
123
127
|
Start the job 'happy_seal' but via the `--name` flag.
|
124
128
|
"""
|
129
|
+
import shlex
|
125
130
|
from meerschaum.utils.warnings import warn, info
|
126
131
|
from meerschaum.utils.daemon._names import get_new_daemon_name
|
127
132
|
from meerschaum.jobs import (
|
@@ -212,7 +217,29 @@ def _start_jobs(
|
|
212
217
|
|
213
218
|
def _run_new_job(name: Optional[str] = None):
|
214
219
|
name = name or get_new_daemon_name()
|
215
|
-
|
220
|
+
if len(sysargs or []) >= 2 and sysargs[0] == 'start' and sysargs[1].startswith('job'):
|
221
|
+
return (False, "Create a new job with `-d` / `--daemon`."), name
|
222
|
+
|
223
|
+
job_sysargs = (
|
224
|
+
shlex.join([a for a in sysargs if a not in ('-d', '--daemon')])
|
225
|
+
if not line
|
226
|
+
else line
|
227
|
+
)
|
228
|
+
job = Job(name, job_sysargs, executor_keys=executor_keys, delete_after_completion=rm)
|
229
|
+
|
230
|
+
if not job.exists():
|
231
|
+
try:
|
232
|
+
confirm = yes_no(
|
233
|
+
f"Create new job '{name}'?\n {job_sysargs}\n",
|
234
|
+
default='y',
|
235
|
+
yes=kw.get('yes', False),
|
236
|
+
noask=kw.get('noask', False),
|
237
|
+
)
|
238
|
+
except Exception:
|
239
|
+
confirm = True
|
240
|
+
if not confirm:
|
241
|
+
return (False, "Nothing changed."), name
|
242
|
+
|
216
243
|
return job.start(debug=debug), name
|
217
244
|
|
218
245
|
def _run_existing_job(name: str):
|
@@ -285,6 +312,7 @@ def _start_jobs(
|
|
285
312
|
if new_job
|
286
313
|
else _run_existing_job(_name)
|
287
314
|
)
|
315
|
+
|
288
316
|
if not kw.get('nopretty', False):
|
289
317
|
print_tuple(success_tuple)
|
290
318
|
|
@@ -300,7 +328,10 @@ def _start_jobs(
|
|
300
328
|
+ ("Failed to start job" + ("s" if len(_failures) != 1 else '')
|
301
329
|
+ f" {items_str(_failures)}." if _failures else '')
|
302
330
|
)
|
303
|
-
|
331
|
+
if not msg:
|
332
|
+
msg = "Nothing changed."
|
333
|
+
else:
|
334
|
+
_install_healthcheck_job()
|
304
335
|
return len(_failures) == 0, msg
|
305
336
|
|
306
337
|
|
@@ -308,6 +339,7 @@ def _start_gui(
|
|
308
339
|
action: Optional[List[str]] = None,
|
309
340
|
mrsm_instance: Optional[str] = None,
|
310
341
|
port: Optional[int] = None,
|
342
|
+
webterm_port: Optional[int] = None,
|
311
343
|
debug: bool = False,
|
312
344
|
**kw
|
313
345
|
) -> SuccessTuple:
|
@@ -321,7 +353,6 @@ def _start_gui(
|
|
321
353
|
|
322
354
|
from meerschaum.utils.venv import venv_exec
|
323
355
|
from meerschaum.utils.packages import attempt_import
|
324
|
-
from meerschaum.utils.warnings import warn
|
325
356
|
from meerschaum.utils.debug import dprint
|
326
357
|
from meerschaum.utils.networking import find_open_ports
|
327
358
|
from meerschaum.connectors.parse import parse_instance_keys
|
@@ -329,9 +360,10 @@ def _start_gui(
|
|
329
360
|
webview, requests = attempt_import('webview', 'requests')
|
330
361
|
|
331
362
|
success, msg = True, "Success"
|
332
|
-
host =
|
333
|
-
|
334
|
-
|
363
|
+
host = mrsm.get_config('webterm', 'host')
|
364
|
+
port = port or webterm_port
|
365
|
+
if not port:
|
366
|
+
port = mrsm.get_config('webterm', 'port')
|
335
367
|
|
336
368
|
if not is_webterm_running(host, port, session_id='mrsm'):
|
337
369
|
port = next(find_open_ports(port, 9000))
|
@@ -369,7 +401,7 @@ def _start_gui(
|
|
369
401
|
break
|
370
402
|
except Exception as e:
|
371
403
|
if debug:
|
372
|
-
dprint(e)
|
404
|
+
dprint(str(e))
|
373
405
|
continue
|
374
406
|
if starting_up is False:
|
375
407
|
return False, f"The webterm failed to start within {timeout} seconds."
|
@@ -417,7 +449,6 @@ def _start_webterm(
|
|
417
449
|
- `-i`, '--instance'
|
418
450
|
The default instance to use for the Webterm shell.
|
419
451
|
"""
|
420
|
-
import uuid
|
421
452
|
from meerschaum._internal.term import get_webterm_app_and_manager, tornado_ioloop
|
422
453
|
from meerschaum._internal.term.tools import (
|
423
454
|
is_webterm_running,
|
@@ -426,15 +457,17 @@ def _start_webterm(
|
|
426
457
|
)
|
427
458
|
from meerschaum.utils.networking import find_open_ports
|
428
459
|
from meerschaum.utils.warnings import info
|
460
|
+
from meerschaum.config.paths import WEBTERM_INTERNAL_RESOURCES_PATH
|
429
461
|
|
430
462
|
if host is None:
|
431
|
-
host =
|
463
|
+
host = mrsm.get_config('api', 'webterm', 'host')
|
432
464
|
if port is None:
|
433
|
-
port =
|
465
|
+
port = mrsm.get_config('api', 'webterm', 'port')
|
434
466
|
if sysargs is None:
|
435
467
|
sysargs = ['start', 'webterm']
|
436
468
|
session_id = 'mrsm'
|
437
|
-
|
469
|
+
|
470
|
+
env_path = WEBTERM_INTERNAL_RESOURCES_PATH / (str(port) + '.json')
|
438
471
|
|
439
472
|
if is_webterm_running(host, port, session_id=session_id):
|
440
473
|
if force:
|
@@ -445,11 +478,18 @@ def _start_webterm(
|
|
445
478
|
+ " Include `-f` to start another server on a new port\n"
|
446
479
|
+ " or specify a different port with `-p`."
|
447
480
|
)
|
481
|
+
|
482
|
+
tornado_app, term_manager = get_webterm_app_and_manager(
|
483
|
+
instance_keys=mrsm_instance,
|
484
|
+
port=port,
|
485
|
+
env_path=env_path,
|
486
|
+
)
|
448
487
|
if not nopretty:
|
449
488
|
info(
|
450
489
|
f"Starting the webterm at http://{host}:{port}/webterm/{session_id} ..."
|
451
490
|
"\n Press CTRL+C to quit."
|
452
491
|
)
|
492
|
+
|
453
493
|
tornado_app.listen(port, host)
|
454
494
|
loop = tornado_ioloop.IOLoop.instance()
|
455
495
|
try:
|
@@ -462,10 +502,15 @@ def _start_webterm(
|
|
462
502
|
term_manager.shutdown()
|
463
503
|
loop.close()
|
464
504
|
|
465
|
-
sessions = get_mrsm_tmux_sessions()
|
505
|
+
sessions = get_mrsm_tmux_sessions(port=port)
|
466
506
|
for session in sessions:
|
467
507
|
kill_tmux_session(session)
|
468
508
|
|
509
|
+
try:
|
510
|
+
env_path.unlink()
|
511
|
+
except Exception:
|
512
|
+
pass
|
513
|
+
|
469
514
|
return True, "Success"
|
470
515
|
|
471
516
|
|
@@ -483,7 +528,6 @@ def _start_connectors(
|
|
483
528
|
from meerschaum.connectors.parse import parse_instance_keys
|
484
529
|
from meerschaum.utils.pool import get_pool
|
485
530
|
from meerschaum.utils.warnings import warn
|
486
|
-
from meerschaum.utils.formatting import pprint
|
487
531
|
from meerschaum.utils.misc import items_str
|
488
532
|
if action is None:
|
489
533
|
action = []
|
@@ -575,7 +619,6 @@ def _start_pipeline(
|
|
575
619
|
"""
|
576
620
|
import json
|
577
621
|
import time
|
578
|
-
import sys
|
579
622
|
from meerschaum._internal.entry import entry
|
580
623
|
from meerschaum.utils.warnings import info, warn
|
581
624
|
from meerschaum.utils.misc import is_int
|
@@ -630,7 +673,7 @@ def _start_pipeline(
|
|
630
673
|
def do_entry() -> None:
|
631
674
|
nonlocal success, msg, proc
|
632
675
|
if timeout_seconds is None:
|
633
|
-
success, msg = entry(sub_args_line, _patch_args=patch_args)
|
676
|
+
success, msg = entry(sub_args_line, _patch_args=patch_args, _use_cli_daemon=False)
|
634
677
|
return
|
635
678
|
|
636
679
|
sub_args_line_escaped = sub_args_line.replace("'", "<QUOTE>")
|
@@ -640,7 +683,7 @@ def _start_pipeline(
|
|
640
683
|
"from meerschaum._internal.entry import entry\n\n"
|
641
684
|
f"sub_args_line = '{sub_args_line_escaped}'.replace(\"<QUOTE>\", \"'\")\n"
|
642
685
|
f"patch_args = json.loads('{patch_args_escaped_str}'.replace('<QUOTE>', \"'\"))\n"
|
643
|
-
"success, msg = entry(sub_args_line, _patch_args=patch_args)\n"
|
686
|
+
"success, msg = entry(sub_args_line, _patch_args=patch_args, _use_cli_daemon=False)\n"
|
644
687
|
f"print('{fence_begin}' + json.dumps((success, msg)) + '{fence_end}')"
|
645
688
|
)
|
646
689
|
proc = venv_exec(src, venv=None, as_proc=True)
|
@@ -676,7 +719,7 @@ def _start_pipeline(
|
|
676
719
|
|
677
720
|
try:
|
678
721
|
run_loop()
|
679
|
-
except KeyboardInterrupt:
|
722
|
+
except (KeyboardInterrupt, SystemExit):
|
680
723
|
warn("Cancelled pipeline.", stack=False)
|
681
724
|
if proc is not None:
|
682
725
|
_stop_process(proc)
|
@@ -688,6 +731,112 @@ def _start_pipeline(
|
|
688
731
|
return success, msg
|
689
732
|
|
690
733
|
|
734
|
+
def _start_daemons(
|
735
|
+
timeout_seconds: Union[int, float, None] = None,
|
736
|
+
yes: bool = False,
|
737
|
+
force: bool = False,
|
738
|
+
noask: bool = False,
|
739
|
+
debug: bool = False,
|
740
|
+
**kwargs
|
741
|
+
) -> SuccessTuple:
|
742
|
+
"""
|
743
|
+
Start the Meerschaum CLI daemon processes.
|
744
|
+
"""
|
745
|
+
from meerschaum.utils.warnings import warn, dprint
|
746
|
+
from meerschaum._internal.cli.daemons import (
|
747
|
+
get_cli_daemon,
|
748
|
+
get_cli_lock_path,
|
749
|
+
)
|
750
|
+
from meerschaum._internal.cli.workers import (
|
751
|
+
get_existing_cli_workers,
|
752
|
+
get_existing_cli_worker_indices,
|
753
|
+
)
|
754
|
+
from meerschaum.utils.prompt import yes_no
|
755
|
+
from meerschaum.actions import actions
|
756
|
+
|
757
|
+
workers = get_existing_cli_workers()
|
758
|
+
if not workers:
|
759
|
+
if debug:
|
760
|
+
dprint("No daemons are running, spawning a new process...")
|
761
|
+
workers = [get_cli_daemon()]
|
762
|
+
|
763
|
+
accepted_restart = False
|
764
|
+
any_daemons_are_running = any((worker.job.status == 'running') for worker in workers)
|
765
|
+
lock_paths = [get_cli_lock_path(ix) for ix in get_existing_cli_worker_indices()]
|
766
|
+
any_locks_exist = any(lock_path.exists() for lock_path in lock_paths)
|
767
|
+
|
768
|
+
if any_locks_exist:
|
769
|
+
warn(
|
770
|
+
"Locks are currently held by the CLI daemons.\n"
|
771
|
+
"Run again with `--force` to remove the locks.",
|
772
|
+
stack=False,
|
773
|
+
)
|
774
|
+
|
775
|
+
if not force:
|
776
|
+
return False, "Actions are currently running."
|
777
|
+
|
778
|
+
for lock_path in lock_paths:
|
779
|
+
try:
|
780
|
+
if lock_path.exists():
|
781
|
+
lock_path.unlink()
|
782
|
+
except Exception as e:
|
783
|
+
warn(f"Failed to release lock:\n{e}")
|
784
|
+
|
785
|
+
if any_daemons_are_running:
|
786
|
+
accepted_restart = force or yes_no(
|
787
|
+
"Restart running CLI daemons?",
|
788
|
+
yes=yes,
|
789
|
+
noask=noask,
|
790
|
+
default='n',
|
791
|
+
)
|
792
|
+
|
793
|
+
if not accepted_restart:
|
794
|
+
return True, "Daemons are already running; nothing to do."
|
795
|
+
|
796
|
+
stop_success, stop_msg = actions['stop'](
|
797
|
+
['daemons'],
|
798
|
+
timeout_seconds=timeout_seconds,
|
799
|
+
debug=debug,
|
800
|
+
)
|
801
|
+
if not stop_success:
|
802
|
+
return stop_success, stop_msg
|
803
|
+
|
804
|
+
worker = get_cli_daemon()
|
805
|
+
|
806
|
+
if debug:
|
807
|
+
dprint("Cleaning up CLI daemon...")
|
808
|
+
cleanup_success, cleanup_msg = worker.cleanup()
|
809
|
+
if not cleanup_success:
|
810
|
+
return cleanup_success, cleanup_msg
|
811
|
+
|
812
|
+
if debug:
|
813
|
+
dprint("Starting CLI daemon...")
|
814
|
+
|
815
|
+
start_success, start_msg = worker.job.start()
|
816
|
+
if not start_success:
|
817
|
+
return start_success, start_msg
|
818
|
+
|
819
|
+
return True, "Success"
|
820
|
+
|
821
|
+
|
822
|
+
def _start_worker(action: Optional[List[str]] = None, **kwargs: Any) -> SuccessTuple:
|
823
|
+
"""
|
824
|
+
Start a CLI worker process. This is intended for internal use only.
|
825
|
+
"""
|
826
|
+
from meerschaum._internal.cli.workers import ActionWorker
|
827
|
+
from meerschaum.utils.misc import is_int
|
828
|
+
|
829
|
+
if not action:
|
830
|
+
return False, "No worker index is provided."
|
831
|
+
|
832
|
+
if not is_int(action[0]):
|
833
|
+
return False, "Invalid worker index."
|
834
|
+
|
835
|
+
ix = int(action[0])
|
836
|
+
worker = ActionWorker(ix)
|
837
|
+
return worker.run()
|
838
|
+
|
839
|
+
|
691
840
|
### NOTE: This must be the final statement of the module.
|
692
841
|
### Any subactions added below these lines will not
|
693
842
|
### be added to the `help` docstring.
|
meerschaum/actions/stop.py
CHANGED
@@ -7,7 +7,8 @@ Stop running jobs that were started with `-d` or `start job`.
|
|
7
7
|
"""
|
8
8
|
|
9
9
|
from __future__ import annotations
|
10
|
-
from meerschaum.utils.typing import Optional, List,
|
10
|
+
from meerschaum.utils.typing import Optional, List, SuccessTuple, Any, Union
|
11
|
+
|
11
12
|
|
12
13
|
def stop(action: Optional[List[str]] = None, **kw) -> SuccessTuple:
|
13
14
|
"""
|
@@ -16,6 +17,7 @@ def stop(action: Optional[List[str]] = None, **kw) -> SuccessTuple:
|
|
16
17
|
from meerschaum.actions import choose_subaction
|
17
18
|
options = {
|
18
19
|
'jobs': _stop_jobs,
|
20
|
+
'daemons': _stop_daemons,
|
19
21
|
}
|
20
22
|
return choose_subaction(action, options, **kw)
|
21
23
|
|
@@ -52,7 +54,7 @@ def _complete_stop(
|
|
52
54
|
return options[sub](action=action, **kw)
|
53
55
|
|
54
56
|
from meerschaum._internal.shell import default_action_completer
|
55
|
-
return default_action_completer(action=(['
|
57
|
+
return default_action_completer(action=(['stop'] + action), **kw)
|
56
58
|
|
57
59
|
|
58
60
|
def _stop_jobs(
|
@@ -111,6 +113,8 @@ def _stop_jobs(
|
|
111
113
|
)
|
112
114
|
|
113
115
|
if not jobs_to_stop:
|
116
|
+
if jobs:
|
117
|
+
return True, "The selected jobs are currently stopped."
|
114
118
|
return False, "No running, paused or restarting jobs to stop."
|
115
119
|
|
116
120
|
if not action:
|
@@ -160,6 +164,38 @@ def _stop_jobs(
|
|
160
164
|
return success, msg
|
161
165
|
|
162
166
|
|
167
|
+
def _stop_daemons(
|
168
|
+
timeout_seconds: Union[int, float, None] = None,
|
169
|
+
debug: bool = False,
|
170
|
+
**kwargs
|
171
|
+
) -> SuccessTuple:
|
172
|
+
"""
|
173
|
+
Stop the Meerschaum CLI daemon.
|
174
|
+
"""
|
175
|
+
import shutil
|
176
|
+
from meerschaum._internal.cli.workers import get_existing_cli_workers
|
177
|
+
from meerschaum.config.paths import CLI_RESOURCES_PATH
|
178
|
+
workers = get_existing_cli_workers()
|
179
|
+
|
180
|
+
for worker in workers:
|
181
|
+
stop_success, stop_msg = worker.job.stop(timeout_seconds=timeout_seconds, debug=debug)
|
182
|
+
if not stop_success:
|
183
|
+
return stop_success, stop_msg
|
184
|
+
|
185
|
+
cleanup_success, cleanup_msg = worker.cleanup(debug=debug)
|
186
|
+
if not cleanup_success:
|
187
|
+
return cleanup_success, cleanup_msg
|
188
|
+
|
189
|
+
try:
|
190
|
+
if CLI_RESOURCES_PATH.exists():
|
191
|
+
shutil.rmtree(CLI_RESOURCES_PATH)
|
192
|
+
CLI_RESOURCES_PATH.mkdir(parents=True, exist_ok=True)
|
193
|
+
except Exception as e:
|
194
|
+
return False, f"Failed to clean up CLI resources directory.\n{e}"
|
195
|
+
|
196
|
+
return True, "Success"
|
197
|
+
|
198
|
+
|
163
199
|
### NOTE: This must be the final statement of the module.
|
164
200
|
### Any subactions added below these lines will not
|
165
201
|
### be added to the `help` docstring.
|
meerschaum/actions/sync.py
CHANGED
@@ -287,8 +287,9 @@ def _sync_pipes(
|
|
287
287
|
from meerschaum.utils.formatting._shell import progress
|
288
288
|
from meerschaum.utils.formatting._shell import clear_screen
|
289
289
|
from meerschaum.utils.formatting import print_pipes_results
|
290
|
-
from meerschaum.
|
290
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
291
291
|
from meerschaum.utils.misc import interval_str
|
292
|
+
from meerschaum.utils.daemon import running_in_daemon
|
292
293
|
|
293
294
|
noninteractive_val = os.environ.get(STATIC_CONFIG['environment']['noninteractive'], None)
|
294
295
|
noninteractive = str(noninteractive_val).lower() in ('1', 'true', 'yes')
|
@@ -301,7 +302,11 @@ def _sync_pipes(
|
|
301
302
|
cooldown = 2 * (min_seconds + 1)
|
302
303
|
success_pipes, failure_pipes = [], []
|
303
304
|
while run:
|
304
|
-
_progress =
|
305
|
+
_progress = (
|
306
|
+
progress()
|
307
|
+
if (shell and not noninteractive and not running_in_daemon())
|
308
|
+
else None
|
309
|
+
)
|
305
310
|
cm = _progress if _progress is not None else contextlib.nullcontext()
|
306
311
|
|
307
312
|
lap_begin = time.perf_counter()
|
meerschaum/actions/tag.py
CHANGED
@@ -8,12 +8,12 @@ Functions for editing elements belong here.
|
|
8
8
|
|
9
9
|
from __future__ import annotations
|
10
10
|
import meerschaum as mrsm
|
11
|
-
from meerschaum.utils.typing import List, Any, SuccessTuple, Optional
|
11
|
+
from meerschaum.utils.typing import List, Any, SuccessTuple, Optional
|
12
12
|
|
13
13
|
def tag(
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
action: Optional[List[str]] = None,
|
15
|
+
**kwargs: Any
|
16
|
+
) -> SuccessTuple:
|
17
17
|
"""
|
18
18
|
Edit an existing element.
|
19
19
|
"""
|
@@ -25,10 +25,10 @@ def tag(
|
|
25
25
|
|
26
26
|
|
27
27
|
def _tag_pipes(
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
28
|
+
action: Optional[List[str]] = None,
|
29
|
+
debug: bool = False,
|
30
|
+
**kwargs: Any
|
31
|
+
) -> SuccessTuple:
|
32
32
|
"""
|
33
33
|
Add or remove tags to registered pipes.
|
34
34
|
Prefix a tag with a leading underscore to remove it.
|
@@ -68,6 +68,7 @@ def _tag_pipes(
|
|
68
68
|
pipe_was_edited = True
|
69
69
|
|
70
70
|
if pipe_was_edited:
|
71
|
+
pipe.tags = pipe_tags
|
71
72
|
edited_pipes.append(pipe)
|
72
73
|
|
73
74
|
if not edited_pipes:
|
meerschaum/actions/verify.py
CHANGED
@@ -57,8 +57,11 @@ def _verify_packages(
|
|
57
57
|
Verify the versions of packages.
|
58
58
|
"""
|
59
59
|
from meerschaum.utils.packages import (
|
60
|
-
attempt_import,
|
61
|
-
|
60
|
+
attempt_import,
|
61
|
+
all_packages,
|
62
|
+
is_installed,
|
63
|
+
venv_contains_package,
|
64
|
+
manually_import_module,
|
62
65
|
)
|
63
66
|
|
64
67
|
venv_packages, base_packages, miss_packages = [], [], []
|
@@ -78,12 +81,6 @@ def _verify_packages(
|
|
78
81
|
)
|
79
82
|
_where_list.append(import_name)
|
80
83
|
|
81
|
-
if 'flask_compress' in venv_packages or 'dash' in venv_packages:
|
82
|
-
flask_compress = attempt_import('flask_compress', lazy=False, debug=debug)
|
83
|
-
_monkey_patch_get_distribution('flask-compress', flask_compress.__version__)
|
84
|
-
if 'flask_compress' in venv_packages:
|
85
|
-
venv_packages.remove('flask_compress')
|
86
|
-
|
87
84
|
for import_name in base_packages:
|
88
85
|
manually_import_module(import_name, debug=debug, venv=None)
|
89
86
|
for import_name in venv_packages:
|
meerschaum/api/__init__.py
CHANGED
@@ -14,14 +14,13 @@ from fnmatch import fnmatch
|
|
14
14
|
import meerschaum as mrsm
|
15
15
|
from meerschaum.utils.typing import Dict, Any, Optional, PipesDict
|
16
16
|
from meerschaum.config import get_config
|
17
|
-
from meerschaum.
|
17
|
+
from meerschaum._internal.static import STATIC_CONFIG, SERVER_ID
|
18
18
|
from meerschaum.utils.packages import attempt_import
|
19
19
|
from meerschaum.utils import get_pipes as _get_pipes
|
20
20
|
from meerschaum.config._paths import API_UVICORN_CONFIG_PATH, API_UVICORN_RESOURCES_PATH
|
21
21
|
from meerschaum.plugins import _api_plugins
|
22
22
|
from meerschaum.utils.warnings import warn, dprint
|
23
23
|
from meerschaum.utils.threading import RLock
|
24
|
-
from meerschaum.utils.misc import is_pipe_registered
|
25
24
|
from meerschaum.connectors.parse import parse_instance_keys
|
26
25
|
|
27
26
|
from meerschaum import __version__ as version
|
@@ -67,16 +66,13 @@ from meerschaum.api._exceptions import APIPermissionError
|
|
67
66
|
uvicorn_config_path = API_UVICORN_RESOURCES_PATH / SERVER_ID / 'config.json'
|
68
67
|
|
69
68
|
uvicorn_config = None
|
70
|
-
sys_config = get_config('
|
71
|
-
permissions_config = get_config('
|
69
|
+
sys_config = get_config('api')
|
70
|
+
permissions_config = get_config('api', 'permissions')
|
72
71
|
|
73
72
|
def get_uvicorn_config() -> Dict[str, Any]:
|
74
73
|
"""Read the Uvicorn configuration JSON and return a dictionary."""
|
75
74
|
global uvicorn_config
|
76
75
|
import json
|
77
|
-
runtime = os.environ.get(STATIC_CONFIG['environment']['runtime'], None)
|
78
|
-
if runtime == 'api':
|
79
|
-
return get_config('system', 'api', 'uvicorn')
|
80
76
|
_uvicorn_config = uvicorn_config
|
81
77
|
with _locks['uvicorn_config']:
|
82
78
|
if uvicorn_config is None:
|
@@ -85,6 +81,8 @@ def get_uvicorn_config() -> Dict[str, Any]:
|
|
85
81
|
uvicorn_config = json.load(f)
|
86
82
|
_uvicorn_config = uvicorn_config
|
87
83
|
except Exception:
|
84
|
+
import traceback
|
85
|
+
traceback.print_exc()
|
88
86
|
_uvicorn_config = sys_config.get('uvicorn', None)
|
89
87
|
|
90
88
|
if _uvicorn_config is None:
|
@@ -95,11 +93,17 @@ def get_uvicorn_config() -> Dict[str, Any]:
|
|
95
93
|
|
96
94
|
debug = get_uvicorn_config().get('debug', False)
|
97
95
|
no_dash = get_uvicorn_config().get('no_dash', False)
|
96
|
+
no_webterm = get_uvicorn_config().get('no_webterm', False)
|
98
97
|
no_auth = get_uvicorn_config().get('no_auth', False)
|
99
98
|
private = get_uvicorn_config().get('private', False)
|
100
99
|
production = get_uvicorn_config().get('production', False)
|
101
100
|
_include_dash = (not no_dash)
|
101
|
+
_include_webterm = (not no_webterm) and _include_dash
|
102
102
|
docs_enabled = not production or sys_config.get('endpoints', {}).get('docs_in_production', True)
|
103
|
+
webterm_port = (
|
104
|
+
get_uvicorn_config().get('webterm_port', None)
|
105
|
+
or mrsm.get_config('api', 'webterm', 'port')
|
106
|
+
)
|
103
107
|
|
104
108
|
default_instance_keys = None
|
105
109
|
_instance_connectors = defaultdict(lambda: None)
|
@@ -127,7 +131,7 @@ def get_api_connector(instance_keys: Optional[str] = None):
|
|
127
131
|
)
|
128
132
|
found_match: bool = False
|
129
133
|
for allowed_keys_pattern in allowed_instance_keys:
|
130
|
-
if fnmatch(instance_keys, allowed_keys_pattern):
|
134
|
+
if fnmatch(str(instance_keys), allowed_keys_pattern):
|
131
135
|
found_match = True
|
132
136
|
break
|
133
137
|
if not found_match:
|
@@ -139,7 +143,9 @@ def get_api_connector(instance_keys: Optional[str] = None):
|
|
139
143
|
if _instance_connectors[instance_keys] is None:
|
140
144
|
try:
|
141
145
|
is_valid_connector = True
|
142
|
-
|
146
|
+
instance_connector = parse_instance_keys(instance_keys, debug=debug)
|
147
|
+
instance_connector._cache_connector = get_cache_connector()
|
148
|
+
_instance_connectors[instance_keys] = instance_connector
|
143
149
|
except Exception:
|
144
150
|
is_valid_connector = False
|
145
151
|
|
@@ -166,7 +172,7 @@ def get_cache_connector(connector_keys: Optional[str] = None):
|
|
166
172
|
return None
|
167
173
|
|
168
174
|
connector_keys = connector_keys or get_config(
|
169
|
-
'
|
175
|
+
'api', 'cache', 'connector',
|
170
176
|
warn=False,
|
171
177
|
)
|
172
178
|
if connector_keys is None:
|
@@ -194,7 +200,11 @@ def pipes(instance_keys: Optional[str] = None, refresh: bool = False) -> PipesDi
|
|
194
200
|
with _locks['pipes-' + instance_keys]:
|
195
201
|
pipes = _instance_pipes[instance_keys]
|
196
202
|
if pipes is None or refresh:
|
197
|
-
pipes = _get_pipes(
|
203
|
+
pipes = _get_pipes(
|
204
|
+
mrsm_instance=instance_keys,
|
205
|
+
cache=True,
|
206
|
+
cache_connector_keys=get_cache_connector(),
|
207
|
+
)
|
198
208
|
_instance_pipes[instance_keys] = pipes
|
199
209
|
return pipes
|
200
210
|
|
@@ -210,9 +220,29 @@ def get_pipe(
|
|
210
220
|
if location_key in ('[None]', 'None', 'null'):
|
211
221
|
location_key = None
|
212
222
|
instance_keys = str(get_api_connector(instance_keys))
|
213
|
-
|
214
|
-
|
215
|
-
|
223
|
+
if connector_keys == 'mrsm':
|
224
|
+
raise fastapi.HTTPException(
|
225
|
+
status_code=403,
|
226
|
+
detail="Unable to serve any pipes with connector keys `mrsm` over the API.",
|
227
|
+
)
|
228
|
+
|
229
|
+
pipes_dict = pipes(instance_keys)
|
230
|
+
if (
|
231
|
+
not refresh
|
232
|
+
and connector_keys in pipes_dict
|
233
|
+
and metric_key in pipes_dict[connector_keys]
|
234
|
+
and location_key in pipes_dict[connector_keys][metric_key]
|
235
|
+
):
|
236
|
+
return pipes_dict[connector_keys][metric_key][location_key]
|
237
|
+
|
238
|
+
pipe = mrsm.Pipe(
|
239
|
+
connector_keys,
|
240
|
+
metric_key,
|
241
|
+
location_key,
|
242
|
+
mrsm_instance=instance_keys,
|
243
|
+
cache=True,
|
244
|
+
cache_connector_keys=get_cache_connector(),
|
245
|
+
)
|
216
246
|
return pipe
|
217
247
|
|
218
248
|
|
@@ -291,7 +321,7 @@ def __getattr__(name: str):
|
|
291
321
|
raise AttributeError(f"Could not import '{name}'.")
|
292
322
|
|
293
323
|
### Import everything else within the API.
|
294
|
-
from meerschaum.api._oauth2 import manager
|
324
|
+
from meerschaum.api._oauth2 import manager, ScopedAuth
|
295
325
|
import meerschaum.api.routes as routes
|
296
326
|
import meerschaum.api._events
|
297
327
|
import meerschaum.api._websockets
|