meerschaum 2.2.6__py3-none-any.whl → 2.3.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 +6 -1
- meerschaum/__main__.py +9 -9
- meerschaum/_internal/arguments/__init__.py +1 -1
- meerschaum/_internal/arguments/_parse_arguments.py +72 -6
- meerschaum/_internal/arguments/_parser.py +45 -15
- meerschaum/_internal/docs/index.py +265 -8
- meerschaum/_internal/entry.py +167 -37
- meerschaum/_internal/shell/Shell.py +290 -99
- meerschaum/_internal/shell/updates.py +175 -0
- meerschaum/actions/__init__.py +29 -17
- meerschaum/actions/api.py +12 -12
- meerschaum/actions/attach.py +113 -0
- meerschaum/actions/copy.py +68 -41
- meerschaum/actions/delete.py +112 -50
- meerschaum/actions/edit.py +3 -3
- meerschaum/actions/install.py +40 -32
- meerschaum/actions/pause.py +44 -27
- meerschaum/actions/register.py +19 -5
- meerschaum/actions/restart.py +107 -0
- meerschaum/actions/show.py +130 -159
- meerschaum/actions/start.py +161 -100
- meerschaum/actions/stop.py +78 -42
- meerschaum/actions/sync.py +3 -3
- meerschaum/actions/upgrade.py +28 -36
- meerschaum/api/_events.py +25 -1
- meerschaum/api/_oauth2.py +2 -0
- meerschaum/api/_websockets.py +2 -2
- meerschaum/api/dash/callbacks/jobs.py +36 -44
- meerschaum/api/dash/jobs.py +89 -78
- meerschaum/api/routes/__init__.py +1 -0
- meerschaum/api/routes/_actions.py +148 -17
- meerschaum/api/routes/_jobs.py +407 -0
- meerschaum/api/routes/_pipes.py +25 -25
- meerschaum/config/_default.py +1 -0
- meerschaum/config/_formatting.py +1 -0
- meerschaum/config/_jobs.py +1 -1
- meerschaum/config/_paths.py +11 -0
- meerschaum/config/_shell.py +84 -67
- meerschaum/config/_version.py +1 -1
- meerschaum/config/static/__init__.py +18 -0
- meerschaum/connectors/Connector.py +13 -7
- meerschaum/connectors/__init__.py +28 -15
- meerschaum/connectors/api/APIConnector.py +27 -1
- meerschaum/connectors/api/_actions.py +71 -6
- meerschaum/connectors/api/_jobs.py +368 -0
- meerschaum/connectors/api/_misc.py +1 -1
- meerschaum/connectors/api/_pipes.py +85 -84
- meerschaum/connectors/api/_request.py +13 -9
- meerschaum/connectors/parse.py +27 -15
- meerschaum/core/Pipe/_bootstrap.py +16 -8
- meerschaum/core/Pipe/_sync.py +3 -0
- meerschaum/jobs/_Executor.py +69 -0
- meerschaum/jobs/_Job.py +899 -0
- meerschaum/jobs/__init__.py +396 -0
- meerschaum/jobs/systemd.py +694 -0
- meerschaum/plugins/__init__.py +97 -12
- meerschaum/utils/daemon/Daemon.py +352 -147
- meerschaum/utils/daemon/FileDescriptorInterceptor.py +19 -10
- meerschaum/utils/daemon/RotatingFile.py +22 -8
- meerschaum/utils/daemon/StdinFile.py +121 -0
- meerschaum/utils/daemon/__init__.py +42 -27
- meerschaum/utils/daemon/_names.py +15 -13
- meerschaum/utils/formatting/__init__.py +83 -37
- meerschaum/utils/formatting/_jobs.py +146 -55
- meerschaum/utils/formatting/_shell.py +6 -0
- meerschaum/utils/misc.py +41 -22
- meerschaum/utils/packages/__init__.py +21 -15
- meerschaum/utils/packages/_packages.py +9 -6
- meerschaum/utils/process.py +9 -9
- meerschaum/utils/prompt.py +20 -7
- meerschaum/utils/schedule.py +21 -15
- meerschaum/utils/venv/__init__.py +2 -2
- {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dist-info}/METADATA +22 -25
- {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dist-info}/RECORD +80 -70
- {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dist-info}/WHEEL +1 -1
- {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dist-info}/LICENSE +0 -0
- {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dist-info}/NOTICE +0 -0
- {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dist-info}/entry_points.txt +0 -0
- {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dist-info}/top_level.txt +0 -0
- {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dist-info}/zip-safe +0 -0
meerschaum/config/_paths.py
CHANGED
@@ -123,6 +123,10 @@ paths = {
|
|
123
123
|
'PERMANENT_PATCH_DIR_PATH' : ('{ROOT_DIR_PATH}', 'permanent_patch_config'),
|
124
124
|
'INTERNAL_RESOURCES_PATH' : ('{ROOT_DIR_PATH}', '.internal'),
|
125
125
|
|
126
|
+
'UPDATES_RESOURCES_PATH' : ('{INTERNAL_RESOURCES_PATH}', 'updates'),
|
127
|
+
'UPDATES_CACHE_PATH' : ('{UPDATES_RESOURCES_PATH}', 'cache.json'),
|
128
|
+
'UPDATES_LOCK_PATH' : ('{UPDATES_RESOURCES_PATH}', '.updates.lock'),
|
129
|
+
|
126
130
|
'STACK_RESOURCES_PATH' : ('{ROOT_DIR_PATH}', 'stack'),
|
127
131
|
'STACK_COMPOSE_FILENAME' : 'docker-compose.yaml',
|
128
132
|
'STACK_COMPOSE_PATH' : ('{STACK_RESOURCES_PATH}', '{STACK_COMPOSE_FILENAME}'),
|
@@ -176,6 +180,13 @@ paths = {
|
|
176
180
|
'DAEMON_RESOURCES_PATH' : ('{ROOT_DIR_PATH}', 'jobs'),
|
177
181
|
'LOGS_RESOURCES_PATH' : ('{ROOT_DIR_PATH}', 'logs'),
|
178
182
|
'DAEMON_ERROR_LOG_PATH' : ('{ROOT_DIR_PATH}', 'daemon_errors.log'),
|
183
|
+
'CHECK_JOBS_LOCK_PATH' : ('{INTERNAL_RESOURCES_PATH}', 'check-jobs.lock'),
|
184
|
+
|
185
|
+
'SYSTEMD_RESOURCES_PATH' : ('{DOT_CONFIG_DIR_PATH}', 'systemd'),
|
186
|
+
'SYSTEMD_USER_RESOURCES_PATH' : ('{SYSTEMD_RESOURCES_PATH}', 'user'),
|
187
|
+
'SYSTEMD_ROOT_RESOURCES_PATH' : ('{ROOT_DIR_PATH}', 'systemd'),
|
188
|
+
'SYSTEMD_JOBS_RESOURCES_PATH' : ('{SYSTEMD_ROOT_RESOURCES_PATH}', 'services'),
|
189
|
+
'SYSTEMD_LOGS_RESOURCES_PATH' : ('{SYSTEMD_ROOT_RESOURCES_PATH}', 'logs'),
|
179
190
|
}
|
180
191
|
|
181
192
|
def set_root(root: Union[Path, str]):
|
meerschaum/config/_shell.py
CHANGED
@@ -6,127 +6,144 @@
|
|
6
6
|
Default configuration for the Meerschaum shell.
|
7
7
|
"""
|
8
8
|
|
9
|
-
# import platform
|
10
|
-
# default_cmd = 'cmd' if platform.system() != 'Windows' else 'cmd2'
|
11
9
|
default_cmd = 'cmd'
|
12
10
|
|
13
11
|
default_shell_config = {
|
14
|
-
'ansi'
|
15
|
-
'intro'
|
16
|
-
'rich'
|
17
|
-
'style'
|
12
|
+
'ansi' : {
|
13
|
+
'intro' : {
|
14
|
+
'rich' : {
|
15
|
+
'style' : "bold bright_blue",
|
18
16
|
},
|
19
|
-
'color'
|
17
|
+
'color' : [
|
20
18
|
'bold',
|
21
19
|
'bright blue',
|
22
20
|
],
|
23
21
|
},
|
24
|
-
'close_message': {
|
25
|
-
'rich'
|
26
|
-
'style'
|
22
|
+
'close_message' : {
|
23
|
+
'rich' : {
|
24
|
+
'style' : 'bright_blue',
|
27
25
|
},
|
28
|
-
'color'
|
26
|
+
'color' : [
|
29
27
|
'bright blue',
|
30
28
|
],
|
31
29
|
},
|
32
|
-
'doc_header': {
|
33
|
-
'rich'
|
34
|
-
'style'
|
30
|
+
'doc_header' : {
|
31
|
+
'rich' : {
|
32
|
+
'style' : 'bright_blue',
|
35
33
|
},
|
36
|
-
'color'
|
34
|
+
'color' : [
|
37
35
|
'bright blue',
|
38
36
|
],
|
39
37
|
},
|
40
|
-
'undoc_header': {
|
41
|
-
'rich'
|
42
|
-
'style'
|
38
|
+
'undoc_header' : {
|
39
|
+
'rich' : {
|
40
|
+
'style' : 'bright_blue',
|
43
41
|
},
|
44
|
-
'color'
|
42
|
+
'color' : [
|
45
43
|
'bright blue',
|
46
44
|
],
|
47
45
|
},
|
48
|
-
'ruler': {
|
49
|
-
'rich'
|
50
|
-
'style'
|
46
|
+
'ruler' : {
|
47
|
+
'rich' : {
|
48
|
+
'style' : 'bold bright_blue',
|
51
49
|
},
|
52
|
-
'color'
|
50
|
+
'color' : [
|
53
51
|
'bold',
|
54
52
|
'bright blue',
|
55
53
|
],
|
56
54
|
},
|
57
|
-
'prompt': {
|
58
|
-
'rich'
|
59
|
-
'style'
|
55
|
+
'prompt' : {
|
56
|
+
'rich' : {
|
57
|
+
'style' : 'green',
|
60
58
|
},
|
61
|
-
'color'
|
59
|
+
'color' : [
|
62
60
|
'green',
|
63
61
|
],
|
64
62
|
},
|
65
|
-
'instance'
|
66
|
-
'rich'
|
67
|
-
'style'
|
63
|
+
'instance' : {
|
64
|
+
'rich' : {
|
65
|
+
'style' : 'cyan',
|
68
66
|
},
|
69
|
-
'color'
|
67
|
+
'color' : [
|
70
68
|
'cyan',
|
71
69
|
],
|
72
70
|
},
|
73
|
-
'repo'
|
74
|
-
'rich': {
|
75
|
-
'style': 'magenta',
|
71
|
+
'repo' : {
|
72
|
+
'rich' : {
|
73
|
+
'style' : 'magenta',
|
76
74
|
},
|
77
|
-
'color': [
|
75
|
+
'color' : [
|
78
76
|
'magenta',
|
79
77
|
],
|
80
78
|
},
|
81
|
-
'
|
82
|
-
'rich'
|
83
|
-
'style'
|
79
|
+
'executor' : {
|
80
|
+
'rich' : {
|
81
|
+
'style' : 'yellow',
|
84
82
|
},
|
85
|
-
|
83
|
+
},
|
84
|
+
'username' : {
|
85
|
+
'rich' : {
|
86
|
+
'style' : 'white',
|
87
|
+
},
|
88
|
+
'color' : [
|
86
89
|
'white',
|
87
90
|
],
|
88
91
|
},
|
89
|
-
'connected'
|
90
|
-
'rich'
|
91
|
-
'style'
|
92
|
+
'connected' : {
|
93
|
+
'rich' : {
|
94
|
+
'style' : 'green',
|
92
95
|
},
|
93
|
-
'color'
|
96
|
+
'color' : [
|
94
97
|
'green',
|
95
98
|
],
|
96
99
|
},
|
97
|
-
'disconnected'
|
98
|
-
'rich'
|
99
|
-
'style'
|
100
|
+
'disconnected' : {
|
101
|
+
'rich' : {
|
102
|
+
'style' : 'red',
|
100
103
|
},
|
101
|
-
'color'
|
104
|
+
'color' : [
|
105
|
+
'red',
|
106
|
+
],
|
107
|
+
},
|
108
|
+
'update_message' : {
|
109
|
+
'rich' : {
|
110
|
+
'style' : 'red',
|
111
|
+
},
|
112
|
+
'color' : [
|
102
113
|
'red',
|
103
114
|
],
|
104
115
|
},
|
105
116
|
},
|
106
|
-
'ascii'
|
107
|
-
'intro'
|
117
|
+
'ascii' : {
|
118
|
+
'intro' : r""" ___ ___ __ __ __
|
108
119
|
|\/| |__ |__ |__) /__` / ` |__| /\ | | |\/|
|
109
|
-
| | |___ |___ | \ .__/ \__, | | /~~\ \__/ |
|
110
|
-
'prompt'
|
111
|
-
'ruler'
|
112
|
-
'close_message': 'Thank you for using Meerschaum!',
|
113
|
-
'doc_header'
|
114
|
-
'undoc_header'
|
120
|
+
| | |___ |___ | \ .__/ \__, | | /~~\ \__/ | |""" + '\n',
|
121
|
+
'prompt' : '\n [ {username}@{instance} | {executor_keys} ] > ',
|
122
|
+
'ruler' : '-',
|
123
|
+
'close_message' : 'Thank you for using Meerschaum!',
|
124
|
+
'doc_header' : 'Meerschaum actions (`help <action>` for usage):',
|
125
|
+
'undoc_header' : 'Unimplemented actions:',
|
126
|
+
'update_message' : "Update available!",
|
115
127
|
},
|
116
|
-
'unicode'
|
117
|
-
'intro'
|
128
|
+
'unicode' : {
|
129
|
+
'intro' : """
|
118
130
|
█▄ ▄█ ██▀ ██▀ █▀▄ ▄▀▀ ▄▀▀ █▄█ ▄▀▄ █ █ █▄ ▄█
|
119
131
|
█ ▀ █ █▄▄ █▄▄ █▀▄ ▄██ ▀▄▄ █ █ █▀█ ▀▄█ █ ▀ █\n""",
|
120
|
-
'prompt'
|
121
|
-
'ruler'
|
122
|
-
'close_message': ' MRSM{formatting:emoji:hand} Thank you for using Meerschaum! ',
|
123
|
-
'doc_header'
|
124
|
-
'undoc_header'
|
132
|
+
'prompt' : '\n [ {username}@{instance} | {executor_keys} ] ➤ ',
|
133
|
+
'ruler' : '─',
|
134
|
+
'close_message' : ' MRSM{formatting:emoji:hand} Thank you for using Meerschaum! ',
|
135
|
+
'doc_header' : 'Meerschaum actions (`help <action>` for usage):',
|
136
|
+
'undoc_header' : 'Unimplemented actions:',
|
137
|
+
'update_message' : "MRSM{formatting:emoji:announcement} Update available!",
|
138
|
+
},
|
139
|
+
'timeout' : 60,
|
140
|
+
'max_history' : 1000,
|
141
|
+
'clear_screen' : True,
|
142
|
+
'bottom_toolbar' : {
|
143
|
+
'enabled' : True,
|
125
144
|
},
|
126
|
-
'
|
127
|
-
|
128
|
-
|
129
|
-
'bottom_toolbar' : {
|
130
|
-
'enabled' : True,
|
145
|
+
'updates' : {
|
146
|
+
'check_remote' : True,
|
147
|
+
'refresh_minutes': 180,
|
131
148
|
},
|
132
149
|
}
|
meerschaum/config/_version.py
CHANGED
@@ -23,6 +23,8 @@ STATIC_CONFIG: Dict[str, Any] = {
|
|
23
23
|
'pipes': '/pipes',
|
24
24
|
'metadata': '/metadata',
|
25
25
|
'actions': '/actions',
|
26
|
+
'jobs': '/jobs',
|
27
|
+
'logs': '/logs',
|
26
28
|
'users': '/users',
|
27
29
|
'login': '/login',
|
28
30
|
'connectors': '/connectors',
|
@@ -39,6 +41,12 @@ STATIC_CONFIG: Dict[str, Any] = {
|
|
39
41
|
'token_expires_minutes': 720,
|
40
42
|
},
|
41
43
|
'webterm_job_name': '_webterm',
|
44
|
+
'default_timeout': 600,
|
45
|
+
'jobs': {
|
46
|
+
'stdin_message': 'MRSM_STDIN',
|
47
|
+
'stop_message': 'MRSM_STOP',
|
48
|
+
'metadata_cache_seconds': 5,
|
49
|
+
},
|
42
50
|
},
|
43
51
|
'sql': {
|
44
52
|
'internal_schema': '_mrsm_internal',
|
@@ -62,6 +70,9 @@ STATIC_CONFIG: Dict[str, Any] = {
|
|
62
70
|
'noask': 'MRSM_NOASK',
|
63
71
|
'id': 'MRSM_SERVER_ID',
|
64
72
|
'daemon_id': 'MRSM_DAEMON_ID',
|
73
|
+
'systemd_log_path': 'MRSM_SYSTEMD_LOG_PATH',
|
74
|
+
'systemd_stdin_path': 'MRSM_SYSTEMD_STDIN_PATH',
|
75
|
+
'systemd_result_path': 'MRSM_SYSTEMD_RESULT_PATH',
|
65
76
|
'uri_regex': r'MRSM_([a-zA-Z0-9]*)_(\d*[a-zA-Z][a-zA-Z0-9-_+]*$)',
|
66
77
|
'prefix': 'MRSM_',
|
67
78
|
},
|
@@ -77,6 +88,10 @@ STATIC_CONFIG: Dict[str, Any] = {
|
|
77
88
|
),
|
78
89
|
'underscore_standin': '<UNDERSCORE>', ### Temporary replacement for parsing.
|
79
90
|
'failure_key': '_argparse_exception',
|
91
|
+
'and_key': '+',
|
92
|
+
'escaped_and_key': '++',
|
93
|
+
'pipeline_key': ':',
|
94
|
+
'escaped_pipeline_key': '::',
|
80
95
|
},
|
81
96
|
'urls': {
|
82
97
|
'get-pip.py': 'https://bootstrap.pypa.io/get-pip.py',
|
@@ -128,6 +143,9 @@ STATIC_CONFIG: Dict[str, Any] = {
|
|
128
143
|
},
|
129
144
|
'exists_timeout_seconds': 5.0,
|
130
145
|
},
|
146
|
+
'jobs': {
|
147
|
+
'check_restart_seconds': 1.0,
|
148
|
+
},
|
131
149
|
'setup': {
|
132
150
|
'name': 'meerschaum',
|
133
151
|
'formal_name': 'Meerschaum',
|
@@ -21,11 +21,11 @@ class Connector(metaclass=abc.ABCMeta):
|
|
21
21
|
The base connector class to hold connection attributes.
|
22
22
|
"""
|
23
23
|
def __init__(
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
24
|
+
self,
|
25
|
+
type: Optional[str] = None,
|
26
|
+
label: Optional[str] = None,
|
27
|
+
**kw: Any
|
28
|
+
):
|
29
29
|
"""
|
30
30
|
Set the given keyword arguments as attributes.
|
31
31
|
|
@@ -101,7 +101,7 @@ class Connector(metaclass=abc.ABCMeta):
|
|
101
101
|
|
102
102
|
### load user config into self._attributes
|
103
103
|
if self.type in conn_configs and self.label in conn_configs[self.type]:
|
104
|
-
self._attributes.update(conn_configs[self.type][self.label])
|
104
|
+
self._attributes.update(conn_configs[self.type][self.label] or {})
|
105
105
|
|
106
106
|
### load system config into self._sys_config
|
107
107
|
### (deep copy so future Connectors don't inherit changes)
|
@@ -200,7 +200,13 @@ class Connector(metaclass=abc.ABCMeta):
|
|
200
200
|
_type = self.__dict__.get('type', None)
|
201
201
|
if _type is None:
|
202
202
|
import re
|
203
|
-
|
203
|
+
is_executor = self.__class__.__name__.lower().endswith('executor')
|
204
|
+
suffix_regex = (
|
205
|
+
r'connector$'
|
206
|
+
if not is_executor
|
207
|
+
else r'executor$'
|
208
|
+
)
|
209
|
+
_type = re.sub(suffix_regex, '', self.__class__.__name__.lower())
|
204
210
|
self.__dict__['type'] = _type
|
205
211
|
return _type
|
206
212
|
|
@@ -36,9 +36,9 @@ __all__ = (
|
|
36
36
|
### store connectors partitioned by
|
37
37
|
### type, label for reuse
|
38
38
|
connectors: Dict[str, Dict[str, Connector]] = {
|
39
|
-
'api'
|
40
|
-
'sql'
|
41
|
-
'plugin': {},
|
39
|
+
'api' : {},
|
40
|
+
'sql' : {},
|
41
|
+
'plugin' : {},
|
42
42
|
}
|
43
43
|
instance_types: List[str] = ['sql', 'api']
|
44
44
|
_locks: Dict[str, RLock] = {
|
@@ -70,12 +70,12 @@ _loaded_plugin_connectors: bool = False
|
|
70
70
|
|
71
71
|
|
72
72
|
def get_connector(
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
73
|
+
type: str = None,
|
74
|
+
label: str = None,
|
75
|
+
refresh: bool = False,
|
76
|
+
debug: bool = False,
|
77
|
+
**kw: Any
|
78
|
+
) -> Connector:
|
79
79
|
"""
|
80
80
|
Return existing connector or create new connection and store for reuse.
|
81
81
|
|
@@ -127,10 +127,13 @@ def get_connector(
|
|
127
127
|
global _loaded_plugin_connectors
|
128
128
|
if isinstance(type, str) and not label and ':' in type:
|
129
129
|
type, label = type.split(':', maxsplit=1)
|
130
|
+
|
130
131
|
with _locks['_loaded_plugin_connectors']:
|
131
132
|
if not _loaded_plugin_connectors:
|
132
133
|
load_plugin_connectors()
|
134
|
+
_load_builtin_custom_connectors()
|
133
135
|
_loaded_plugin_connectors = True
|
136
|
+
|
134
137
|
if type is None and label is None:
|
135
138
|
default_instance_keys = get_config('meerschaum', 'instance', patch=True)
|
136
139
|
### recursive call to get_connector
|
@@ -274,9 +277,7 @@ def is_connected(keys: str, **kw) -> bool:
|
|
274
277
|
return False
|
275
278
|
|
276
279
|
|
277
|
-
def make_connector(
|
278
|
-
cls,
|
279
|
-
):
|
280
|
+
def make_connector(cls, _is_executor: bool = False):
|
280
281
|
"""
|
281
282
|
Register a class as a `Connector`.
|
282
283
|
The `type` will be the lower case of the class name, without the suffix `connector`.
|
@@ -302,7 +303,12 @@ def make_connector(
|
|
302
303
|
>>>
|
303
304
|
"""
|
304
305
|
import re
|
305
|
-
|
306
|
+
suffix_regex = (
|
307
|
+
r'connector$'
|
308
|
+
if not _is_executor
|
309
|
+
else r'executor$'
|
310
|
+
)
|
311
|
+
typ = re.sub(suffix_regex, '', cls.__name__.lower())
|
306
312
|
with _locks['types']:
|
307
313
|
types[typ] = cls
|
308
314
|
with _locks['custom_types']:
|
@@ -338,8 +344,8 @@ def load_plugin_connectors():
|
|
338
344
|
|
339
345
|
|
340
346
|
def get_connector_plugin(
|
341
|
-
|
342
|
-
|
347
|
+
connector: Connector,
|
348
|
+
) -> Union[str, None, mrsm.Plugin]:
|
343
349
|
"""
|
344
350
|
Determine the plugin for a connector.
|
345
351
|
This is useful for handling virtual environments for custom instance connectors.
|
@@ -365,3 +371,10 @@ def get_connector_plugin(
|
|
365
371
|
)
|
366
372
|
plugin = mrsm.Plugin(plugin_name)
|
367
373
|
return plugin if plugin.is_installed() else None
|
374
|
+
|
375
|
+
|
376
|
+
def _load_builtin_custom_connectors():
|
377
|
+
"""
|
378
|
+
Import custom connectors decorated with `@make_connector` or `@make_executor`.
|
379
|
+
"""
|
380
|
+
import meerschaum.jobs.systemd
|
@@ -33,7 +33,12 @@ class APIConnector(Connector):
|
|
33
33
|
delete,
|
34
34
|
wget,
|
35
35
|
)
|
36
|
-
from ._actions import
|
36
|
+
from ._actions import (
|
37
|
+
get_actions,
|
38
|
+
do_action,
|
39
|
+
do_action_async,
|
40
|
+
do_action_legacy,
|
41
|
+
)
|
37
42
|
from ._misc import get_mrsm_version, get_chaining_status
|
38
43
|
from ._pipes import (
|
39
44
|
register_pipe,
|
@@ -72,6 +77,27 @@ class APIConnector(Connector):
|
|
72
77
|
get_user_attributes,
|
73
78
|
)
|
74
79
|
from ._uri import from_uri
|
80
|
+
from ._jobs import (
|
81
|
+
get_jobs,
|
82
|
+
get_job,
|
83
|
+
get_job_metadata,
|
84
|
+
get_job_properties,
|
85
|
+
get_job_exists,
|
86
|
+
delete_job,
|
87
|
+
start_job,
|
88
|
+
create_job,
|
89
|
+
stop_job,
|
90
|
+
pause_job,
|
91
|
+
get_logs,
|
92
|
+
get_job_stop_time,
|
93
|
+
monitor_logs,
|
94
|
+
monitor_logs_async,
|
95
|
+
get_job_is_blocking_on_stdin,
|
96
|
+
get_job_began,
|
97
|
+
get_job_ended,
|
98
|
+
get_job_paused,
|
99
|
+
get_job_status,
|
100
|
+
)
|
75
101
|
|
76
102
|
def __init__(
|
77
103
|
self,
|
@@ -7,22 +7,87 @@ Functions to interact with /mrsm/actions
|
|
7
7
|
"""
|
8
8
|
|
9
9
|
from __future__ import annotations
|
10
|
-
from meerschaum.utils.typing import SuccessTuple, Optional, List
|
11
10
|
|
12
|
-
|
11
|
+
import json
|
12
|
+
import asyncio
|
13
|
+
from functools import partial
|
14
|
+
|
15
|
+
import meerschaum as mrsm
|
16
|
+
from meerschaum.utils.typing import SuccessTuple, List, Callable, Optional
|
17
|
+
from meerschaum.config.static import STATIC_CONFIG
|
18
|
+
|
19
|
+
ACTIONS_ENDPOINT: str = STATIC_CONFIG['api']['endpoints']['actions']
|
20
|
+
|
21
|
+
|
22
|
+
def get_actions(self):
|
13
23
|
"""Get available actions from the API instance."""
|
14
|
-
|
15
|
-
|
24
|
+
return self.get(ACTIONS_ENDPOINT)
|
25
|
+
|
26
|
+
|
27
|
+
def do_action(self, sysargs: List[str]) -> SuccessTuple:
|
28
|
+
"""
|
29
|
+
Execute a Meerschaum action remotely.
|
30
|
+
"""
|
31
|
+
return asyncio.run(self.do_action_async(sysargs))
|
32
|
+
|
33
|
+
|
34
|
+
async def do_action_async(
|
35
|
+
self,
|
36
|
+
sysargs: List[str],
|
37
|
+
callback_function: Callable[[str], None] = partial(print, end=''),
|
38
|
+
) -> SuccessTuple:
|
39
|
+
"""
|
40
|
+
Monitor a job's log files and await a callback with the changes.
|
41
|
+
"""
|
42
|
+
websockets, websockets_exceptions = mrsm.attempt_import('websockets', 'websockets.exceptions')
|
43
|
+
protocol = 'ws' if self.URI.startswith('http://') else 'wss'
|
44
|
+
port = self.port if 'port' in self.__dict__ else ''
|
45
|
+
uri = f"{protocol}://{self.host}:{port}{ACTIONS_ENDPOINT}/ws"
|
46
|
+
if sysargs and sysargs[0] == 'api' and len(sysargs) > 2:
|
47
|
+
sysargs = sysargs[2:]
|
48
|
+
|
49
|
+
sysargs_str = json.dumps(sysargs)
|
50
|
+
|
51
|
+
async with websockets.connect(uri) as websocket:
|
52
|
+
try:
|
53
|
+
await websocket.send(self.token or 'no-login')
|
54
|
+
response = await websocket.recv()
|
55
|
+
init_data = json.loads(response)
|
56
|
+
if not init_data.get('is_authenticated'):
|
57
|
+
return False, "Cannot authenticate with actions endpoint."
|
16
58
|
|
59
|
+
await websocket.send(sysargs_str)
|
60
|
+
except websockets_exceptions.ConnectionClosedOK:
|
61
|
+
return False, "Connection was closed."
|
17
62
|
|
18
|
-
|
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"
|
77
|
+
|
78
|
+
|
79
|
+
def do_action_legacy(
|
19
80
|
self,
|
20
81
|
action: Optional[List[str]] = None,
|
21
82
|
sysargs: Optional[List[str]] = None,
|
22
83
|
debug: bool = False,
|
23
84
|
**kw
|
24
85
|
) -> SuccessTuple:
|
25
|
-
"""
|
86
|
+
"""
|
87
|
+
NOTE: This method is deprecated.
|
88
|
+
Please use `do_action()` or `do_action_async()`.
|
89
|
+
|
90
|
+
Execute a Meerschaum action remotely.
|
26
91
|
|
27
92
|
If `sysargs` are provided, parse those instead.
|
28
93
|
Otherwise infer everything from keyword arguments.
|