meerschaum 2.9.5__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 +198 -118
- 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 +382 -95
- 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/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 +46 -21
- 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 +479 -81
- meerschaum/utils/debug.py +49 -19
- meerschaum/utils/dtypes/__init__.py +476 -34
- 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 +134 -47
- 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.5.dist-info → meerschaum-3.0.0.dist-info}/METADATA +94 -96
- meerschaum-3.0.0.dist-info/RECORD +289 -0
- {meerschaum-2.9.5.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.5.dist-info/RECORD +0 -263
- {meerschaum-2.9.5.dist-info → meerschaum-3.0.0.dist-info}/entry_points.txt +0 -0
- {meerschaum-2.9.5.dist-info → meerschaum-3.0.0.dist-info}/licenses/LICENSE +0 -0
- {meerschaum-2.9.5.dist-info → meerschaum-3.0.0.dist-info}/top_level.txt +0 -0
- {meerschaum-2.9.5.dist-info → meerschaum-3.0.0.dist-info}/zip-safe +0 -0
meerschaum/actions/api.py
CHANGED
@@ -6,7 +6,10 @@ Start the Meerschaum WebAPI with the `api` action.
|
|
6
6
|
"""
|
7
7
|
|
8
8
|
from __future__ import annotations
|
9
|
+
|
9
10
|
import os
|
11
|
+
|
12
|
+
import meerschaum as mrsm
|
10
13
|
from meerschaum.utils.typing import SuccessTuple, Optional, List, Any
|
11
14
|
|
12
15
|
|
@@ -93,9 +96,11 @@ def _api_start(
|
|
93
96
|
action: Optional[List[str]] = None,
|
94
97
|
host: Optional[str] = None,
|
95
98
|
port: Optional[int] = None,
|
99
|
+
webterm_port: Optional[int] = None,
|
96
100
|
workers: Optional[int] = None,
|
97
101
|
mrsm_instance: Optional[str] = None,
|
98
102
|
no_dash: bool = False,
|
103
|
+
no_webterm: bool = False,
|
99
104
|
no_auth: bool = False,
|
100
105
|
private: bool = False,
|
101
106
|
secure: bool = False,
|
@@ -118,6 +123,10 @@ def _api_start(
|
|
118
123
|
The address to bind to.
|
119
124
|
If `None`, use '0.0.0.0'.
|
120
125
|
|
126
|
+
webterm_port: Optional[int], default None
|
127
|
+
Port to bind the webterm server to.
|
128
|
+
If `None`, use 8765.
|
129
|
+
|
121
130
|
workers: Optional[int], default None
|
122
131
|
How many worker threads to run.
|
123
132
|
If `None`, defaults to the number of CPU cores or 1 on Android.
|
@@ -148,8 +157,6 @@ def _api_start(
|
|
148
157
|
|
149
158
|
from meerschaum.utils.packages import (
|
150
159
|
attempt_import,
|
151
|
-
venv_contains_package,
|
152
|
-
pip_install,
|
153
160
|
run_python_package,
|
154
161
|
)
|
155
162
|
from meerschaum.utils.misc import is_int, filter_keywords
|
@@ -163,10 +170,11 @@ def _api_start(
|
|
163
170
|
API_UVICORN_CONFIG_PATH,
|
164
171
|
CACHE_RESOURCES_PATH,
|
165
172
|
PACKAGE_ROOT_PATH,
|
173
|
+
ROOT_DIR_PATH,
|
166
174
|
)
|
167
175
|
from meerschaum.config._patch import apply_patch_to_config
|
168
|
-
from meerschaum.config.
|
169
|
-
from meerschaum.
|
176
|
+
from meerschaum.config.environment import get_env_vars
|
177
|
+
from meerschaum._internal.static import STATIC_CONFIG, SERVER_ID
|
170
178
|
from meerschaum.connectors.parse import parse_instance_keys
|
171
179
|
from meerschaum.utils.pool import get_pool
|
172
180
|
|
@@ -186,9 +194,9 @@ def _api_start(
|
|
186
194
|
uvicorn_config_path = API_UVICORN_RESOURCES_PATH / SERVER_ID / 'config.json'
|
187
195
|
uvicorn_env_path = API_UVICORN_RESOURCES_PATH / SERVER_ID / 'uvicorn.env'
|
188
196
|
|
189
|
-
api_config = deepcopy(get_config('
|
197
|
+
api_config = deepcopy(get_config('api'))
|
190
198
|
cf = _config()
|
191
|
-
forwarded_allow_ips = get_config('
|
199
|
+
forwarded_allow_ips = get_config('api', 'uvicorn', 'forwarded_allow_ips')
|
192
200
|
uvicorn_config = api_config['uvicorn']
|
193
201
|
if port is None:
|
194
202
|
### default
|
@@ -222,7 +230,7 @@ def _api_start(
|
|
222
230
|
instance_connector = parse_instance_keys(mrsm_instance, debug=debug)
|
223
231
|
if instance_connector.type == 'api' and instance_connector.protocol != 'https':
|
224
232
|
allow_http_parent = get_config(
|
225
|
-
'
|
233
|
+
'api', 'permissions', 'chaining', 'insecure_parent_instance'
|
226
234
|
)
|
227
235
|
if not allow_http_parent:
|
228
236
|
return False, (
|
@@ -232,7 +240,7 @@ def _api_start(
|
|
232
240
|
f" - Ensure that '{instance_connector}' is available over HTTPS, " +
|
233
241
|
"and with `edit config`,\n" +
|
234
242
|
f" change the `protocol` for '{instance_connector}' to 'https'.\n\n" +
|
235
|
-
" - Run `edit config
|
243
|
+
" - Run `edit config api` and search for `permissions`.\n" +
|
236
244
|
" Under `api:permissions:chaining`, change the value of " +
|
237
245
|
"`insecure_parent_instance` to `true`,\n" +
|
238
246
|
" then restart the API process."
|
@@ -243,7 +251,9 @@ def _api_start(
|
|
243
251
|
'host': host,
|
244
252
|
'env_file': str(uvicorn_env_path.as_posix()),
|
245
253
|
'mrsm_instance': mrsm_instance,
|
254
|
+
'webterm_port': webterm_port,
|
246
255
|
'no_dash': no_dash,
|
256
|
+
'no_webterm': no_webterm or no_auth,
|
247
257
|
'no_auth': no_auth,
|
248
258
|
'private': private,
|
249
259
|
'production': production,
|
@@ -259,11 +269,33 @@ def _api_start(
|
|
259
269
|
uvicorn_config['use_colors'] = (not nopretty) if nopretty else ANSI
|
260
270
|
|
261
271
|
api_config['uvicorn'] = uvicorn_config
|
262
|
-
cf['
|
272
|
+
cf['api']['uvicorn'] = uvicorn_config
|
263
273
|
if secure:
|
264
|
-
cf['
|
274
|
+
cf['api']['permissions']['actions']['non_admin'] = False
|
275
|
+
|
276
|
+
if not uvicorn_config['no_webterm']:
|
277
|
+
from meerschaum._internal.term.tools import is_webterm_running
|
278
|
+
if webterm_port is None:
|
279
|
+
webterm_port = int(mrsm.get_config('api', 'webterm', 'port'))
|
280
|
+
if is_webterm_running(port=webterm_port):
|
281
|
+
return (
|
282
|
+
False,
|
283
|
+
(
|
284
|
+
f"Webterm is running on port {webterm_port}. "
|
285
|
+
"Start the API again with `--webterm-port`."
|
286
|
+
)
|
287
|
+
)
|
265
288
|
|
266
|
-
custom_keys = [
|
289
|
+
custom_keys = [
|
290
|
+
'mrsm_instance',
|
291
|
+
'no_dash',
|
292
|
+
'no_webterm',
|
293
|
+
'no_auth',
|
294
|
+
'private',
|
295
|
+
'debug',
|
296
|
+
'production',
|
297
|
+
'webterm_port',
|
298
|
+
]
|
267
299
|
|
268
300
|
### write config to a temporary file to communicate with uvicorn threads
|
269
301
|
try:
|
@@ -289,6 +321,7 @@ def _api_start(
|
|
289
321
|
MRSM_SERVER_ID: SERVER_ID,
|
290
322
|
MRSM_RUNTIME: 'api',
|
291
323
|
MRSM_CONFIG: json.loads(os.environ.get(MRSM_CONFIG, '{}')),
|
324
|
+
MRSM_ROOT_DIR: ROOT_DIR_PATH.as_posix(),
|
292
325
|
'FORWARDED_ALLOW_IPS': forwarded_allow_ips,
|
293
326
|
'TERM': os.environ.get('TERM', 'screen-256color'),
|
294
327
|
'SHELL': os.environ.get('SHELL', '/bin/bash'),
|
@@ -302,6 +335,8 @@ def _api_start(
|
|
302
335
|
)
|
303
336
|
),
|
304
337
|
'HOSTNAME': os.environ.get('HOSTNAME', 'api'),
|
338
|
+
'XDG_RUNTIME_DIR': os.environ.get('XDG_RUNTIME_DIR', ''),
|
339
|
+
'DBUS_SESSION_BUS_ADDRESS': os.environ.get('DBUS_SESSION_BUS_ADDRESS', ''),
|
305
340
|
})
|
306
341
|
for env_var in get_env_vars():
|
307
342
|
if env_var in env_dict:
|
@@ -316,10 +351,10 @@ def _api_start(
|
|
316
351
|
env_text = ''
|
317
352
|
for key, val in env_dict.items():
|
318
353
|
value = str(
|
319
|
-
json.dumps(val, default=json_serialize_value)
|
354
|
+
json.dumps(val, default=json_serialize_value, separators=(',', ':'))
|
320
355
|
if isinstance(val, (dict))
|
321
356
|
else val
|
322
|
-
).replace('\\', '\\\\').replace("'", "
|
357
|
+
).replace('\\', '\\\\').replace("'", "\\'")
|
323
358
|
env_text += f"{key}='{value}'\n"
|
324
359
|
with open(uvicorn_env_path, 'w+', encoding='utf-8') as f:
|
325
360
|
if debug:
|
@@ -384,11 +419,16 @@ def _api_start(
|
|
384
419
|
except KeyboardInterrupt:
|
385
420
|
pass
|
386
421
|
|
422
|
+
old_stdin = sys.stdin
|
423
|
+
sys.stdin = None
|
424
|
+
|
387
425
|
if production:
|
388
426
|
_run_gunicorn()
|
389
427
|
else:
|
390
428
|
_run_uvicorn()
|
391
429
|
|
430
|
+
sys.stdin = old_stdin
|
431
|
+
|
392
432
|
### Cleanup
|
393
433
|
if uvicorn_config_path.parent.exists():
|
394
434
|
shutil.rmtree(uvicorn_config_path.parent)
|
meerschaum/actions/attach.py
CHANGED
meerschaum/actions/bootstrap.py
CHANGED
@@ -10,7 +10,7 @@ Functions for bootstrapping elements
|
|
10
10
|
from __future__ import annotations
|
11
11
|
|
12
12
|
import meerschaum as mrsm
|
13
|
-
from meerschaum.utils.typing import Union, Any,
|
13
|
+
from meerschaum.utils.typing import Union, Any, SuccessTuple, Optional, Tuple, List
|
14
14
|
|
15
15
|
|
16
16
|
def bootstrap(
|
@@ -249,7 +249,7 @@ def _bootstrap_connectors(
|
|
249
249
|
from meerschaum.config._edit import write_config
|
250
250
|
from meerschaum.utils.formatting import pprint
|
251
251
|
from meerschaum.utils.formatting._shell import clear_screen
|
252
|
-
from meerschaum.
|
252
|
+
from meerschaum.config._default import CONNECTOR_ATTRIBUTES
|
253
253
|
from meerschaum.utils.warnings import warn, info
|
254
254
|
from meerschaum.utils.misc import is_int
|
255
255
|
|
@@ -314,7 +314,7 @@ def _bootstrap_connectors(
|
|
314
314
|
cls_required_attrs = getattr(cls, 'REQUIRED_ATTRIBUTES', [])
|
315
315
|
cls_optional_attrs = getattr(cls, 'OPTIONAL_ATTRIBUTES', [])
|
316
316
|
cls_default_attrs = getattr(cls, 'DEFAULT_ATTRIBUTES', {})
|
317
|
-
type_attributes =
|
317
|
+
type_attributes = CONNECTOR_ATTRIBUTES.get(
|
318
318
|
_type,
|
319
319
|
{
|
320
320
|
'required': cls_required_attrs,
|
@@ -330,16 +330,16 @@ def _bootstrap_connectors(
|
|
330
330
|
f"Flavor for connector '{_type}:{_label}':",
|
331
331
|
sorted(list(type_attributes['flavors'])),
|
332
332
|
default = (
|
333
|
-
'
|
334
|
-
if '
|
333
|
+
'postgresql'
|
334
|
+
if 'postgresql' in type_attributes['flavors']
|
335
335
|
else None
|
336
336
|
)
|
337
337
|
)
|
338
338
|
except KeyboardInterrupt:
|
339
339
|
return abort_tuple
|
340
340
|
new_attributes['flavor'] = flavor
|
341
|
-
required = sorted(list(
|
342
|
-
optional = sorted(list(
|
341
|
+
required = sorted(list(CONNECTOR_ATTRIBUTES[_type]['flavors'][flavor]['requirements']))
|
342
|
+
optional = sorted(list(CONNECTOR_ATTRIBUTES[_type]['flavors'][flavor].get('optional', {})))
|
343
343
|
default = type_attributes['flavors'][flavor].get('defaults', {})
|
344
344
|
else:
|
345
345
|
required = sorted(list(type_attributes.get('required', {})))
|
@@ -429,7 +429,7 @@ def _bootstrap_plugins(
|
|
429
429
|
action = [prompt("Enter the name of your new plugin:")]
|
430
430
|
|
431
431
|
for plugin_name in action:
|
432
|
-
bootstrap_success, bootstrap_msg = bootstrap_plugin(plugin_name)
|
432
|
+
bootstrap_success, bootstrap_msg = bootstrap_plugin(plugin_name, debug=debug)
|
433
433
|
if not bootstrap_success:
|
434
434
|
return bootstrap_success, bootstrap_msg
|
435
435
|
|
meerschaum/actions/delete.py
CHANGED
@@ -18,7 +18,7 @@ def delete(
|
|
18
18
|
Delete an element.
|
19
19
|
|
20
20
|
Command:
|
21
|
-
`delete {config, pipes, plugins, users, connectors, jobs}`
|
21
|
+
`delete {config, pipes, plugins, users, connectors, jobs, venvs}`
|
22
22
|
|
23
23
|
"""
|
24
24
|
from meerschaum.actions import choose_subaction
|
@@ -159,7 +159,9 @@ def _delete_config(
|
|
159
159
|
answer = yes_no(
|
160
160
|
"Are you sure you want to delete the following configuration files?" +
|
161
161
|
f"{sep + sep.join([str(p) for p in paths])}\n",
|
162
|
-
default='n',
|
162
|
+
default='n',
|
163
|
+
noask=noask,
|
164
|
+
yes=yes,
|
163
165
|
)
|
164
166
|
|
165
167
|
if answer or force:
|
meerschaum/actions/edit.py
CHANGED
@@ -27,6 +27,7 @@ def edit(
|
|
27
27
|
'users' : _edit_users,
|
28
28
|
'plugins' : _edit_plugins,
|
29
29
|
'jobs' : _edit_jobs,
|
30
|
+
'tokens' : _edit_tokens,
|
30
31
|
}
|
31
32
|
return choose_subaction(action, options, **kw)
|
32
33
|
|
@@ -66,7 +67,12 @@ def _complete_edit(
|
|
66
67
|
return default_action_completer(action=(['edit'] + action), **kw)
|
67
68
|
|
68
69
|
|
69
|
-
def _edit_config(
|
70
|
+
def _edit_config(
|
71
|
+
action: Optional[List[str]] = None,
|
72
|
+
noask: bool = False,
|
73
|
+
debug: bool = False,
|
74
|
+
**kwargs: Any
|
75
|
+
) -> SuccessTuple:
|
70
76
|
"""
|
71
77
|
Edit Meerschaum configuration files.
|
72
78
|
|
@@ -86,11 +92,26 @@ def _edit_config(action: Optional[List[str]] = None, **kw : Any) -> SuccessTuple
|
|
86
92
|
```
|
87
93
|
"""
|
88
94
|
from meerschaum.config._edit import edit_config
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
95
|
+
from meerschaum.config._read_config import get_possible_keys
|
96
|
+
from meerschaum.actions import actions
|
97
|
+
from meerschaum.utils.prompt import choose
|
98
|
+
|
99
|
+
if not action:
|
100
|
+
action = [
|
101
|
+
choose(
|
102
|
+
"Choose a configuration file to edit:",
|
103
|
+
get_possible_keys(),
|
104
|
+
default='meerschaum',
|
105
|
+
noask=noask,
|
106
|
+
)
|
107
|
+
]
|
108
|
+
|
109
|
+
edit_success, edit_msg = edit_config(keys=action, debug=debug, **kwargs)
|
110
|
+
if not edit_success:
|
111
|
+
return edit_success, edit_msg
|
112
|
+
|
113
|
+
return actions['reload'](debug=debug)
|
114
|
+
|
94
115
|
|
95
116
|
def _complete_edit_config(action: Optional[List[str]] = None, **kw: Any) -> List[str]:
|
96
117
|
from meerschaum.config._read_config import get_possible_keys
|
@@ -104,14 +125,14 @@ def _complete_edit_config(action: Optional[List[str]] = None, **kw: Any) -> List
|
|
104
125
|
return possibilities
|
105
126
|
|
106
127
|
def _edit_pipes(
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
128
|
+
action: Optional[List[str]] = None,
|
129
|
+
params: Optional[Dict[str, Any]] = None,
|
130
|
+
yes: bool = False,
|
131
|
+
force: bool = False,
|
132
|
+
noask: bool = False,
|
133
|
+
debug: bool = False,
|
134
|
+
**kw: Any
|
135
|
+
) -> SuccessTuple:
|
115
136
|
"""
|
116
137
|
Open and edit pipes' configuration files.
|
117
138
|
|
@@ -218,7 +239,7 @@ def _edit_users(
|
|
218
239
|
from meerschaum.utils.prompt import prompt, yes_no, get_password, get_email
|
219
240
|
from meerschaum.utils.misc import edit_file
|
220
241
|
from meerschaum.config._paths import USERS_CACHE_RESOURCES_PATH
|
221
|
-
from meerschaum.
|
242
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
222
243
|
from meerschaum.utils.yaml import yaml
|
223
244
|
import os, pathlib
|
224
245
|
instance_connector = parse_instance_keys(mrsm_instance)
|
@@ -235,7 +256,7 @@ def _edit_users(
|
|
235
256
|
minimum_length = STATIC_CONFIG['users']['min_password_length'],
|
236
257
|
)
|
237
258
|
|
238
|
-
|
259
|
+
### Make an admin
|
239
260
|
_type = ''
|
240
261
|
if yes_no(f"Change the user type for user '{username}'?", default='n', yes=yes, noask=noask):
|
241
262
|
is_admin = yes_no(
|
@@ -248,15 +269,34 @@ def _edit_users(
|
|
248
269
|
if yes_no(f"Change the email for user '{username}'?", default='n', yes=yes, noask=noask):
|
249
270
|
email = get_email(username)
|
250
271
|
|
272
|
+
attributes = {}
|
273
|
+
### Change the scopes.
|
274
|
+
attributes['scopes'] = prompt(
|
275
|
+
f"Scopes for user '{username}' (`*` to grant all scopes):",
|
276
|
+
default_editable=' '.join(User(
|
277
|
+
username,
|
278
|
+
instance=instance_connector,
|
279
|
+
).get_scopes(refresh=True, debug=debug)),
|
280
|
+
).split()
|
281
|
+
if attributes['scopes'] == ['*']:
|
282
|
+
attributes['scopes'] = list(STATIC_CONFIG['tokens']['scopes'])
|
283
|
+
|
251
284
|
### Change the attributes
|
252
|
-
attributes = None
|
253
285
|
if yes_no(
|
254
|
-
|
255
|
-
|
286
|
+
f"Edit the attributes YAML file for user '{username}'?",
|
287
|
+
default='n',
|
288
|
+
yes=yes,
|
289
|
+
noask=noask,
|
256
290
|
):
|
257
291
|
attr_path = pathlib.Path(os.path.join(USERS_CACHE_RESOURCES_PATH, f'{username}.yaml'))
|
258
292
|
try:
|
259
|
-
existing_attrs = instance_connector.get_user_attributes(
|
293
|
+
existing_attrs = instance_connector.get_user_attributes(
|
294
|
+
User(
|
295
|
+
username,
|
296
|
+
instance=instance_connector,
|
297
|
+
),
|
298
|
+
debug=debug,
|
299
|
+
)
|
260
300
|
with open(attr_path, 'w+') as f:
|
261
301
|
yaml.dump(existing_attrs, stream=f, sort_keys=False)
|
262
302
|
edit_file(attr_path)
|
@@ -271,7 +311,14 @@ def _edit_users(
|
|
271
311
|
attributes = None
|
272
312
|
|
273
313
|
### Submit changes
|
274
|
-
return User(
|
314
|
+
return User(
|
315
|
+
username,
|
316
|
+
password,
|
317
|
+
email=email,
|
318
|
+
type=_type,
|
319
|
+
attributes=attributes,
|
320
|
+
instance=instance_connector,
|
321
|
+
)
|
275
322
|
|
276
323
|
if not action:
|
277
324
|
return False, "No users to edit."
|
@@ -301,14 +348,14 @@ def _edit_users(
|
|
301
348
|
f" ({succeeded} succeeded, {failed} failed)."
|
302
349
|
)
|
303
350
|
info(msg)
|
304
|
-
return
|
351
|
+
return succeeded > 0, msg
|
305
352
|
|
306
353
|
|
307
354
|
def _edit_plugins(
|
308
355
|
action: Optional[List[str]] = None,
|
309
356
|
debug: bool = False,
|
310
357
|
**kwargs: Any
|
311
|
-
):
|
358
|
+
) -> mrsm.SuccessTuple:
|
312
359
|
"""
|
313
360
|
Edit a plugin's source code.
|
314
361
|
"""
|
@@ -316,7 +363,6 @@ def _edit_plugins(
|
|
316
363
|
from meerschaum.utils.warnings import warn
|
317
364
|
from meerschaum.utils.prompt import prompt, yes_no
|
318
365
|
from meerschaum.utils.misc import edit_file
|
319
|
-
from meerschaum.utils.packages import reload_meerschaum
|
320
366
|
from meerschaum.actions import actions
|
321
367
|
|
322
368
|
if not action:
|
@@ -349,7 +395,7 @@ def _edit_plugins(
|
|
349
395
|
continue
|
350
396
|
|
351
397
|
edit_file(plugin_file_path)
|
352
|
-
|
398
|
+
actions['reload'](debug=debug)
|
353
399
|
|
354
400
|
return True, "Success"
|
355
401
|
|
@@ -507,6 +553,106 @@ def _edit_jobs(
|
|
507
553
|
return True, msg
|
508
554
|
|
509
555
|
|
556
|
+
def _edit_tokens(
|
557
|
+
action: Optional[List[str]] = None,
|
558
|
+
mrsm_instance: Optional[str] = None,
|
559
|
+
debug: bool = False,
|
560
|
+
) -> mrsm.SuccessTuple:
|
561
|
+
"""
|
562
|
+
Edit tokens registered to an instance.
|
563
|
+
"""
|
564
|
+
import uuid
|
565
|
+
from meerschaum.utils.warnings import warn
|
566
|
+
from meerschaum.utils.misc import is_uuid
|
567
|
+
from meerschaum.core import Token
|
568
|
+
from meerschaum.connectors.parse import parse_instance_keys
|
569
|
+
from meerschaum.utils.prompt import prompt, yes_no
|
570
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
571
|
+
dateutil_parser = mrsm.attempt_import('dateutil.parser')
|
572
|
+
|
573
|
+
if not action:
|
574
|
+
return (
|
575
|
+
False, (
|
576
|
+
"Provide token labels or IDs for the tokens to edit\n"
|
577
|
+
" (run `show tokens` to see registered tokens)."
|
578
|
+
)
|
579
|
+
)
|
580
|
+
|
581
|
+
conn = parse_instance_keys(mrsm_instance)
|
582
|
+
|
583
|
+
labels = [
|
584
|
+
label
|
585
|
+
for label in (action or [])
|
586
|
+
if not is_uuid(label)
|
587
|
+
]
|
588
|
+
potential_token_ids = [
|
589
|
+
uuid.UUID(potential_id)
|
590
|
+
for potential_id in (action or [])
|
591
|
+
if is_uuid(potential_id)
|
592
|
+
]
|
593
|
+
|
594
|
+
tokens = conn.get_tokens(
|
595
|
+
labels=(labels or None),
|
596
|
+
ids=(potential_token_ids or None),
|
597
|
+
debug=debug,
|
598
|
+
)
|
599
|
+
|
600
|
+
num_edited = 0
|
601
|
+
for token in tokens:
|
602
|
+
token_model = token.to_model(refresh=True)
|
603
|
+
if token_model is None:
|
604
|
+
warn(f"Token '{token.id}' does not exist.", stack=False)
|
605
|
+
continue
|
606
|
+
|
607
|
+
new_attrs = {}
|
608
|
+
|
609
|
+
new_attrs['label'] = prompt("Label:", default_editable=token_model.label)
|
610
|
+
new_expiration_str = prompt(
|
611
|
+
"Expiration (empty for no expiration):",
|
612
|
+
default_editable=('' if token.expiration is None else str(token_model.expiration)),
|
613
|
+
)
|
614
|
+
new_attrs['expiration'] = (
|
615
|
+
dateutil_parser.parse(new_expiration_str)
|
616
|
+
if new_expiration_str
|
617
|
+
else None
|
618
|
+
)
|
619
|
+
new_scopes_str = prompt(
|
620
|
+
"Scope (`*` to grant all permissions):",
|
621
|
+
default_editable=' '.join(token_model.scopes),
|
622
|
+
)
|
623
|
+
new_attrs['scopes'] = (
|
624
|
+
new_scopes_str.split(' ')
|
625
|
+
if new_scopes_str != '*'
|
626
|
+
else list(STATIC_CONFIG['tokens']['scopes'])
|
627
|
+
)
|
628
|
+
invalidate = (
|
629
|
+
yes_no("Do you want to invalidate this token?", default='n')
|
630
|
+
if token_model.is_valid
|
631
|
+
else True
|
632
|
+
)
|
633
|
+
new_attrs['is_valid'] = token_model.is_valid and not invalidate
|
634
|
+
|
635
|
+
new_token = Token(**{**dict(token_model), **new_attrs})
|
636
|
+
edit_success, edit_msg = new_token.edit(debug=debug)
|
637
|
+
if not edit_success:
|
638
|
+
return False, edit_msg
|
639
|
+
|
640
|
+
if invalidate:
|
641
|
+
invalidate_success, invalidate_msg = new_token.invalidate(debug=debug)
|
642
|
+
if not invalidate_success:
|
643
|
+
return False, invalidate_msg
|
644
|
+
|
645
|
+
num_edited += 1
|
646
|
+
|
647
|
+
msg = (
|
648
|
+
f"Successfully edited {num_edited} token"
|
649
|
+
+ ('s' if num_edited != 1 else '')
|
650
|
+
+ '.'
|
651
|
+
)
|
652
|
+
|
653
|
+
return True, msg
|
654
|
+
|
655
|
+
|
510
656
|
### NOTE: This must be the final statement of the module.
|
511
657
|
### Any subactions added below these lines will not
|
512
658
|
### be added to the `help` docstring.
|
meerschaum/actions/login.py
CHANGED
@@ -10,13 +10,13 @@ from __future__ import annotations
|
|
10
10
|
from meerschaum.utils.typing import SuccessTuple, Optional, List, Any
|
11
11
|
|
12
12
|
def login(
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
13
|
+
action: Optional[List[str]] = None,
|
14
|
+
connector_keys: Optional[List[str]] = None,
|
15
|
+
yes: bool = False,
|
16
|
+
noask: bool = False,
|
17
|
+
debug: bool = False,
|
18
|
+
**kw: Any
|
19
|
+
) -> SuccessTuple:
|
20
20
|
"""
|
21
21
|
Log into a Meerschaum API instance.
|
22
22
|
"""
|
@@ -56,7 +56,7 @@ def login(
|
|
56
56
|
for k in _keys:
|
57
57
|
try:
|
58
58
|
_connectors.append(parse_instance_keys(k))
|
59
|
-
except Exception
|
59
|
+
except Exception:
|
60
60
|
warn(f"Unable to build connector '{k}'. Is it registered?", stack=False)
|
61
61
|
|
62
62
|
meerschaum_config = get_config('meerschaum')
|