meerschaum 2.3.0.dev3__py3-none-any.whl → 2.3.0rc2__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 +3 -2
- meerschaum/__main__.py +0 -5
- meerschaum/_internal/arguments/__init__.py +1 -1
- meerschaum/_internal/arguments/_parse_arguments.py +56 -2
- meerschaum/_internal/arguments/_parser.py +6 -2
- meerschaum/_internal/entry.py +94 -23
- meerschaum/_internal/shell/Shell.py +112 -35
- meerschaum/actions/attach.py +12 -7
- meerschaum/actions/copy.py +68 -41
- meerschaum/actions/delete.py +75 -26
- meerschaum/actions/edit.py +3 -3
- meerschaum/actions/install.py +40 -32
- meerschaum/actions/pause.py +44 -27
- meerschaum/actions/restart.py +107 -0
- meerschaum/actions/show.py +8 -8
- meerschaum/actions/start.py +27 -46
- meerschaum/actions/stop.py +11 -4
- meerschaum/api/_events.py +10 -3
- meerschaum/api/dash/jobs.py +69 -70
- meerschaum/api/routes/_actions.py +8 -3
- meerschaum/api/routes/_jobs.py +37 -19
- meerschaum/config/_default.py +1 -1
- meerschaum/config/_paths.py +5 -0
- meerschaum/config/_version.py +1 -1
- meerschaum/config/static/__init__.py +5 -0
- meerschaum/connectors/Connector.py +13 -7
- meerschaum/connectors/__init__.py +21 -5
- meerschaum/connectors/api/APIConnector.py +3 -0
- meerschaum/connectors/api/_jobs.py +30 -3
- meerschaum/connectors/parse.py +10 -14
- meerschaum/core/Pipe/_bootstrap.py +16 -8
- meerschaum/jobs/_Executor.py +69 -0
- meerschaum/{utils/jobs → jobs}/_Job.py +169 -21
- meerschaum/jobs/_LocalExecutor.py +88 -0
- meerschaum/jobs/_SystemdExecutor.py +613 -0
- meerschaum/jobs/__init__.py +388 -0
- meerschaum/plugins/__init__.py +6 -6
- meerschaum/utils/daemon/Daemon.py +7 -0
- meerschaum/utils/daemon/RotatingFile.py +5 -2
- meerschaum/utils/daemon/StdinFile.py +12 -2
- meerschaum/utils/daemon/__init__.py +2 -0
- meerschaum/utils/formatting/_jobs.py +49 -25
- meerschaum/utils/misc.py +23 -5
- meerschaum/utils/packages/_packages.py +7 -4
- meerschaum/utils/process.py +9 -9
- meerschaum/utils/venv/__init__.py +2 -2
- {meerschaum-2.3.0.dev3.dist-info → meerschaum-2.3.0rc2.dist-info}/METADATA +14 -17
- {meerschaum-2.3.0.dev3.dist-info → meerschaum-2.3.0rc2.dist-info}/RECORD +54 -50
- meerschaum/utils/jobs/__init__.py +0 -245
- {meerschaum-2.3.0.dev3.dist-info → meerschaum-2.3.0rc2.dist-info}/LICENSE +0 -0
- {meerschaum-2.3.0.dev3.dist-info → meerschaum-2.3.0rc2.dist-info}/NOTICE +0 -0
- {meerschaum-2.3.0.dev3.dist-info → meerschaum-2.3.0rc2.dist-info}/WHEEL +0 -0
- {meerschaum-2.3.0.dev3.dist-info → meerschaum-2.3.0rc2.dist-info}/entry_points.txt +0 -0
- {meerschaum-2.3.0.dev3.dist-info → meerschaum-2.3.0rc2.dist-info}/top_level.txt +0 -0
- {meerschaum-2.3.0.dev3.dist-info → meerschaum-2.3.0rc2.dist-info}/zip-safe +0 -0
meerschaum/api/routes/_jobs.py
CHANGED
@@ -19,7 +19,12 @@ from functools import partial
|
|
19
19
|
from fastapi import WebSocket, WebSocketDisconnect
|
20
20
|
|
21
21
|
from meerschaum.utils.typing import Dict, Any, SuccessTuple, List, Optional, Union
|
22
|
-
from meerschaum.
|
22
|
+
from meerschaum.jobs import (
|
23
|
+
get_jobs as _get_jobs,
|
24
|
+
Job,
|
25
|
+
StopMonitoringLogs,
|
26
|
+
get_executor_keys_from_context,
|
27
|
+
)
|
23
28
|
from meerschaum.utils.warnings import warn
|
24
29
|
|
25
30
|
from meerschaum.api import (
|
@@ -35,6 +40,7 @@ from meerschaum.config.static import STATIC_CONFIG
|
|
35
40
|
|
36
41
|
JOBS_STDIN_MESSAGE: str = STATIC_CONFIG['api']['jobs']['stdin_message']
|
37
42
|
JOBS_STOP_MESSAGE: str = STATIC_CONFIG['api']['jobs']['stop_message']
|
43
|
+
EXECUTOR_KEYS: str = get_executor_keys_from_context()
|
38
44
|
|
39
45
|
|
40
46
|
@app.get(endpoints['jobs'], tags=['Jobs'])
|
@@ -46,15 +52,21 @@ def get_jobs(
|
|
46
52
|
"""
|
47
53
|
Return metadata about the current jobs.
|
48
54
|
"""
|
49
|
-
jobs = _get_jobs()
|
55
|
+
jobs = _get_jobs(executor_keys=EXECUTOR_KEYS, combine_local_and_systemd=False)
|
50
56
|
return {
|
51
57
|
name: {
|
52
58
|
'sysargs': job.sysargs,
|
53
59
|
'result': job.result,
|
60
|
+
'restart': job.restart,
|
61
|
+
'status': job.status,
|
54
62
|
'daemon': {
|
55
|
-
'status': job.daemon.status,
|
56
|
-
'pid': job.
|
57
|
-
'properties':
|
63
|
+
'status': job.daemon.status if job.executor_keys is None else job.status,
|
64
|
+
'pid': job.pid,
|
65
|
+
'properties': (
|
66
|
+
job.daemon.properties
|
67
|
+
if job.executor is None
|
68
|
+
else job.executor.get_job_properties(name)
|
69
|
+
),
|
58
70
|
},
|
59
71
|
}
|
60
72
|
for name, job in jobs.items()
|
@@ -71,7 +83,7 @@ def get_job(
|
|
71
83
|
"""
|
72
84
|
Return metadata for a single job.
|
73
85
|
"""
|
74
|
-
job = Job(name)
|
86
|
+
job = Job(name, executor_keys=EXECUTOR_KEYS)
|
75
87
|
if not job.exists():
|
76
88
|
raise fastapi.HTTPException(
|
77
89
|
status_code=404,
|
@@ -81,10 +93,16 @@ def get_job(
|
|
81
93
|
return {
|
82
94
|
'sysargs': job.sysargs,
|
83
95
|
'result': job.result,
|
96
|
+
'restart': job.restart,
|
97
|
+
'status': job.status,
|
84
98
|
'daemon': {
|
85
|
-
'status': job.daemon.status,
|
86
|
-
'pid': job.
|
87
|
-
'properties':
|
99
|
+
'status': job.daemon.status if job.executor_keys is None else job.status,
|
100
|
+
'pid': job.pid,
|
101
|
+
'properties': (
|
102
|
+
job.daemon.properties
|
103
|
+
if job.executor is None
|
104
|
+
else job.executor.get_job_properties(job.name)
|
105
|
+
),
|
88
106
|
},
|
89
107
|
}
|
90
108
|
|
@@ -100,7 +118,7 @@ def create_job(
|
|
100
118
|
"""
|
101
119
|
Create and start a new job.
|
102
120
|
"""
|
103
|
-
job = Job(name, sysargs)
|
121
|
+
job = Job(name, sysargs, executor_keys=EXECUTOR_KEYS)
|
104
122
|
if job.exists():
|
105
123
|
raise fastapi.HTTPException(
|
106
124
|
status_code=409,
|
@@ -120,7 +138,7 @@ def delete_job(
|
|
120
138
|
"""
|
121
139
|
Delete a job.
|
122
140
|
"""
|
123
|
-
job = Job(name)
|
141
|
+
job = Job(name, executor_keys=EXECUTOR_KEYS)
|
124
142
|
return job.delete()
|
125
143
|
|
126
144
|
|
@@ -134,7 +152,7 @@ def get_job_exists(
|
|
134
152
|
"""
|
135
153
|
Return whether a job exists.
|
136
154
|
"""
|
137
|
-
job = Job(name)
|
155
|
+
job = Job(name, executor_keys=EXECUTOR_KEYS)
|
138
156
|
return job.exists()
|
139
157
|
|
140
158
|
|
@@ -149,7 +167,7 @@ def get_logs(
|
|
149
167
|
Return a job's log text.
|
150
168
|
To stream log text, connect to the WebSocket endpoint `/logs/{name}/ws`.
|
151
169
|
"""
|
152
|
-
job = Job(name)
|
170
|
+
job = Job(name, executor_keys=EXECUTOR_KEYS)
|
153
171
|
if not job.exists():
|
154
172
|
raise fastapi.HTTPException(
|
155
173
|
status_code=404,
|
@@ -169,7 +187,7 @@ def start_job(
|
|
169
187
|
"""
|
170
188
|
Start a job if stopped.
|
171
189
|
"""
|
172
|
-
job = Job(name)
|
190
|
+
job = Job(name, executor_keys=EXECUTOR_KEYS)
|
173
191
|
if not job.exists():
|
174
192
|
raise fastapi.HTTPException(
|
175
193
|
status_code=404,
|
@@ -188,7 +206,7 @@ def stop_job(
|
|
188
206
|
"""
|
189
207
|
Stop a job if running.
|
190
208
|
"""
|
191
|
-
job = Job(name)
|
209
|
+
job = Job(name, executor_keys=EXECUTOR_KEYS)
|
192
210
|
if not job.exists():
|
193
211
|
raise fastapi.HTTPException(
|
194
212
|
status_code=404,
|
@@ -207,7 +225,7 @@ def pause_job(
|
|
207
225
|
"""
|
208
226
|
Pause a job if running.
|
209
227
|
"""
|
210
|
-
job = Job(name)
|
228
|
+
job = Job(name, executor_keys=EXECUTOR_KEYS)
|
211
229
|
if not job.exists():
|
212
230
|
raise fastapi.HTTPException(
|
213
231
|
status_code=404,
|
@@ -226,7 +244,7 @@ def get_stop_time(
|
|
226
244
|
"""
|
227
245
|
Get the timestamp when the job was manually stopped.
|
228
246
|
"""
|
229
|
-
job = Job(name)
|
247
|
+
job = Job(name, executor_keys=EXECUTOR_KEYS)
|
230
248
|
return job.stop_time
|
231
249
|
|
232
250
|
|
@@ -240,7 +258,7 @@ def get_is_blocking_on_stdin(
|
|
240
258
|
"""
|
241
259
|
Return whether a job is blocking on stdin.
|
242
260
|
"""
|
243
|
-
job = Job(name)
|
261
|
+
job = Job(name, executor_keys=EXECUTOR_KEYS)
|
244
262
|
return job.is_blocking_on_stdin()
|
245
263
|
|
246
264
|
|
@@ -314,7 +332,7 @@ async def logs_websocket(name: str, websocket: WebSocket):
|
|
314
332
|
Stream logs from a job over a websocket.
|
315
333
|
"""
|
316
334
|
await websocket.accept()
|
317
|
-
job = Job(name)
|
335
|
+
job = Job(name, executor_keys=EXECUTOR_KEYS)
|
318
336
|
_job_clients[name].append(websocket)
|
319
337
|
|
320
338
|
async def monitor_logs():
|
meerschaum/config/_default.py
CHANGED
@@ -16,7 +16,7 @@ default_meerschaum_config = {
|
|
16
16
|
'api_instance': 'MRSM{meerschaum:instance}',
|
17
17
|
'web_instance': 'MRSM{meerschaum:instance}',
|
18
18
|
'default_repository': 'api:mrsm',
|
19
|
-
'default_executor': 'local',
|
19
|
+
# 'default_executor': 'local',
|
20
20
|
'connectors': {
|
21
21
|
'sql': {
|
22
22
|
'default': {},
|
meerschaum/config/_paths.py
CHANGED
@@ -181,6 +181,11 @@ paths = {
|
|
181
181
|
'LOGS_RESOURCES_PATH' : ('{ROOT_DIR_PATH}', 'logs'),
|
182
182
|
'DAEMON_ERROR_LOG_PATH' : ('{ROOT_DIR_PATH}', 'daemon_errors.log'),
|
183
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_LOGS_RESOURCES_PATH' : ('{SYSTEMD_ROOT_RESOURCES_PATH}', 'logs'),
|
184
189
|
}
|
185
190
|
|
186
191
|
def set_root(root: Union[Path, str]):
|
meerschaum/config/_version.py
CHANGED
@@ -70,6 +70,9 @@ STATIC_CONFIG: Dict[str, Any] = {
|
|
70
70
|
'noask': 'MRSM_NOASK',
|
71
71
|
'id': 'MRSM_SERVER_ID',
|
72
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',
|
73
76
|
'uri_regex': r'MRSM_([a-zA-Z0-9]*)_(\d*[a-zA-Z][a-zA-Z0-9-_+]*$)',
|
74
77
|
'prefix': 'MRSM_',
|
75
78
|
},
|
@@ -85,6 +88,8 @@ STATIC_CONFIG: Dict[str, Any] = {
|
|
85
88
|
),
|
86
89
|
'underscore_standin': '<UNDERSCORE>', ### Temporary replacement for parsing.
|
87
90
|
'failure_key': '_argparse_exception',
|
91
|
+
'and_key': '+',
|
92
|
+
'escaped_and_key': '++',
|
88
93
|
},
|
89
94
|
'urls': {
|
90
95
|
'get-pip.py': 'https://bootstrap.pypa.io/get-pip.py',
|
@@ -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] = {
|
@@ -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,7 +277,7 @@ def is_connected(keys: str, **kw) -> bool:
|
|
274
277
|
return False
|
275
278
|
|
276
279
|
|
277
|
-
def make_connector(cls):
|
280
|
+
def make_connector(cls, _is_executor: bool = False):
|
278
281
|
"""
|
279
282
|
Register a class as a `Connector`.
|
280
283
|
The `type` will be the lower case of the class name, without the suffix `connector`.
|
@@ -300,7 +303,12 @@ def make_connector(cls):
|
|
300
303
|
>>>
|
301
304
|
"""
|
302
305
|
import re
|
303
|
-
|
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())
|
304
312
|
with _locks['types']:
|
305
313
|
types[typ] = cls
|
306
314
|
with _locks['custom_types']:
|
@@ -363,3 +371,11 @@ def get_connector_plugin(
|
|
363
371
|
)
|
364
372
|
plugin = mrsm.Plugin(plugin_name)
|
365
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._SystemdExecutor
|
381
|
+
# import meerschaum.jobs._LocalExecutor
|
@@ -13,7 +13,7 @@ from datetime import datetime
|
|
13
13
|
|
14
14
|
import meerschaum as mrsm
|
15
15
|
from meerschaum.utils.typing import Dict, Any, SuccessTuple, List, Union, Callable
|
16
|
-
from meerschaum.
|
16
|
+
from meerschaum.jobs import Job
|
17
17
|
from meerschaum.config.static import STATIC_CONFIG
|
18
18
|
from meerschaum.utils.warnings import warn, dprint
|
19
19
|
|
@@ -98,7 +98,6 @@ def get_job_metadata(self, name: str, debug: bool = False) -> Dict[str, Any]:
|
|
98
98
|
}
|
99
99
|
return metadata
|
100
100
|
|
101
|
-
|
102
101
|
def get_job_properties(self, name: str, debug: bool = False) -> Dict[str, Any]:
|
103
102
|
"""
|
104
103
|
Return the daemon properties for a single job.
|
@@ -106,6 +105,34 @@ def get_job_properties(self, name: str, debug: bool = False) -> Dict[str, Any]:
|
|
106
105
|
metadata = self.get_job_metadata(name, debug=debug)
|
107
106
|
return metadata.get('daemon', {}).get('properties', {})
|
108
107
|
|
108
|
+
def get_job_status(self, name: str, debug: bool = False) -> str:
|
109
|
+
"""
|
110
|
+
Return the job's status.
|
111
|
+
"""
|
112
|
+
metadata = self.get_job_metadata(name, debug=debug)
|
113
|
+
return metadata.get('status', 'stopped')
|
114
|
+
|
115
|
+
def get_job_began(self, name: str, debug: bool = False) -> str:
|
116
|
+
"""
|
117
|
+
Return a job's `began` timestamp, if it exists.
|
118
|
+
"""
|
119
|
+
properties = self.get_job_properties(name, debug=debug)
|
120
|
+
began_str = properties.get('daemon', {}).get('began', None)
|
121
|
+
if began_str is None:
|
122
|
+
return None
|
123
|
+
|
124
|
+
return began_str
|
125
|
+
|
126
|
+
def get_job_ended(self, name: str, debug: bool = False) -> str:
|
127
|
+
"""
|
128
|
+
Return a job's `ended` timestamp, if it exists.
|
129
|
+
"""
|
130
|
+
properties = self.get_job_properties(name, debug=debug)
|
131
|
+
ended_str = properties.get('daemon', {}).get('ended', None)
|
132
|
+
if ended_str is None:
|
133
|
+
return None
|
134
|
+
|
135
|
+
return ended_str
|
109
136
|
|
110
137
|
def get_job_exists(self, name: str, debug: bool = False) -> bool:
|
111
138
|
"""
|
@@ -226,7 +253,7 @@ async def monitor_logs_async(
|
|
226
253
|
"""
|
227
254
|
Monitor a job's log files and await a callback with the changes.
|
228
255
|
"""
|
229
|
-
from meerschaum.
|
256
|
+
from meerschaum.jobs import StopMonitoringLogs
|
230
257
|
from meerschaum.utils.formatting._jobs import strip_timestamp_from_line
|
231
258
|
|
232
259
|
websockets, websockets_exceptions = mrsm.attempt_import('websockets', 'websockets.exceptions')
|
meerschaum/connectors/parse.py
CHANGED
@@ -87,19 +87,17 @@ def parse_connector_keys(
|
|
87
87
|
|
88
88
|
|
89
89
|
def parse_instance_keys(
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
90
|
+
keys: Optional[str],
|
91
|
+
construct: bool = True,
|
92
|
+
as_tuple: bool = False,
|
93
|
+
**kw
|
94
|
+
):
|
95
95
|
"""
|
96
96
|
Parse the Meerschaum instance value into a Connector object.
|
97
97
|
"""
|
98
98
|
from meerschaum.utils.warnings import warn
|
99
99
|
from meerschaum.config import get_config
|
100
100
|
|
101
|
-
### TODO Check for valid types? Not sure how to do that if construct = False.
|
102
|
-
|
103
101
|
if keys is None:
|
104
102
|
keys = get_config('meerschaum', 'instance')
|
105
103
|
keys = str(keys)
|
@@ -120,25 +118,23 @@ def parse_repo_keys(keys: Optional[str] = None, **kw):
|
|
120
118
|
|
121
119
|
|
122
120
|
def parse_executor_keys(keys: Optional[str] = None, **kw):
|
123
|
-
"""Parse the executor keys into an APIConnector or
|
124
|
-
from meerschaum.
|
121
|
+
"""Parse the executor keys into an APIConnector or string."""
|
122
|
+
from meerschaum.jobs import get_executor_keys_from_context
|
125
123
|
if keys is None:
|
126
|
-
keys =
|
124
|
+
keys = get_executor_keys_from_context()
|
127
125
|
|
128
126
|
if keys is None or keys == 'local':
|
129
127
|
return 'local'
|
130
128
|
|
131
129
|
keys = str(keys)
|
132
|
-
if ':' not in keys:
|
133
|
-
keys = 'api:' + keys
|
134
|
-
|
135
130
|
return parse_connector_keys(keys, **kw)
|
136
131
|
|
137
132
|
|
138
133
|
def is_valid_connector_keys(
|
139
134
|
keys: str
|
140
135
|
) -> bool:
|
141
|
-
"""
|
136
|
+
"""
|
137
|
+
Verify a connector_keys string references a valid connector.
|
142
138
|
"""
|
143
139
|
try:
|
144
140
|
success = parse_connector_keys(keys, construct=False) is not None
|
@@ -88,21 +88,29 @@ def bootstrap(
|
|
88
88
|
|
89
89
|
try:
|
90
90
|
if yes_no(
|
91
|
-
f"Would you like to edit the definition for {self}?",
|
91
|
+
f"Would you like to edit the definition for {self}?",
|
92
|
+
yes=yes,
|
93
|
+
noask=noask,
|
94
|
+
default='n',
|
92
95
|
):
|
93
96
|
edit_tuple = self.edit_definition(debug=debug)
|
94
97
|
if not edit_tuple[0]:
|
95
98
|
return edit_tuple
|
96
99
|
|
97
|
-
if yes_no(
|
100
|
+
if yes_no(
|
101
|
+
f"Would you like to try syncing {self} now?",
|
102
|
+
yes=yes,
|
103
|
+
noask=noask,
|
104
|
+
default='n',
|
105
|
+
):
|
98
106
|
sync_tuple = actions['sync'](
|
99
107
|
['pipes'],
|
100
|
-
connector_keys
|
101
|
-
metric_keys
|
102
|
-
location_keys
|
103
|
-
mrsm_instance
|
104
|
-
debug
|
105
|
-
shell
|
108
|
+
connector_keys=[self.connector_keys],
|
109
|
+
metric_keys=[self.metric_key],
|
110
|
+
location_keys=[self.location_key],
|
111
|
+
mrsm_instance=str(self.instance_connector),
|
112
|
+
debug=debug,
|
113
|
+
shell=shell,
|
106
114
|
)
|
107
115
|
if not sync_tuple[0]:
|
108
116
|
return sync_tuple
|
@@ -0,0 +1,69 @@
|
|
1
|
+
#! /usr/bin/env python3
|
2
|
+
# vim:fenc=utf-8
|
3
|
+
|
4
|
+
"""
|
5
|
+
Define the base class for a Job executor.
|
6
|
+
"""
|
7
|
+
|
8
|
+
from __future__ import annotations
|
9
|
+
|
10
|
+
from abc import abstractmethod
|
11
|
+
|
12
|
+
from meerschaum.connectors import Connector
|
13
|
+
from meerschaum.utils.typing import List, Dict, SuccessTuple, TYPE_CHECKING
|
14
|
+
|
15
|
+
if TYPE_CHECKING:
|
16
|
+
from meerschaum.jobs import Job
|
17
|
+
|
18
|
+
class Executor(Connector):
|
19
|
+
"""
|
20
|
+
Define the methods for managing jobs.
|
21
|
+
"""
|
22
|
+
|
23
|
+
@abstractmethod
|
24
|
+
def get_job_exists(self, name: str, debug: bool = False) -> bool:
|
25
|
+
"""
|
26
|
+
Return whether a job exists.
|
27
|
+
"""
|
28
|
+
|
29
|
+
@abstractmethod
|
30
|
+
def get_jobs(self) -> Dict[str, Job]:
|
31
|
+
"""
|
32
|
+
Return a dictionary of names -> Jobs.
|
33
|
+
"""
|
34
|
+
|
35
|
+
@abstractmethod
|
36
|
+
def create_job(self, name: str, sysargs: List[str], debug: bool = False) -> SuccessTuple:
|
37
|
+
"""
|
38
|
+
Create a new job.
|
39
|
+
"""
|
40
|
+
|
41
|
+
@abstractmethod
|
42
|
+
def start_job(self, name: str, debug: bool = False) -> SuccessTuple:
|
43
|
+
"""
|
44
|
+
Start a job.
|
45
|
+
"""
|
46
|
+
|
47
|
+
@abstractmethod
|
48
|
+
def stop_job(self, name: str, debug: bool = False) -> SuccessTuple:
|
49
|
+
"""
|
50
|
+
Stop a job.
|
51
|
+
"""
|
52
|
+
|
53
|
+
@abstractmethod
|
54
|
+
def pause_job(self, name: str, debug: bool = False) -> SuccessTuple:
|
55
|
+
"""
|
56
|
+
Pause a job.
|
57
|
+
"""
|
58
|
+
|
59
|
+
@abstractmethod
|
60
|
+
def delete_job(self, name: str, debug: bool = False) -> SuccessTuple:
|
61
|
+
"""
|
62
|
+
Delete a job.
|
63
|
+
"""
|
64
|
+
|
65
|
+
@abstractmethod
|
66
|
+
def get_logs(self, name: str, debug: bool = False) -> str:
|
67
|
+
"""
|
68
|
+
Return a job's log output.
|
69
|
+
"""
|