meerschaum 2.3.5.dev0__py3-none-any.whl → 2.4.0.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- meerschaum/_internal/arguments/__init__.py +2 -1
- meerschaum/_internal/arguments/_parse_arguments.py +86 -7
- meerschaum/_internal/entry.py +29 -13
- meerschaum/actions/api.py +16 -16
- meerschaum/actions/bootstrap.py +36 -10
- meerschaum/actions/start.py +16 -15
- meerschaum/api/_events.py +11 -7
- meerschaum/api/dash/__init__.py +7 -6
- meerschaum/api/dash/callbacks/__init__.py +1 -0
- meerschaum/api/dash/callbacks/dashboard.py +7 -5
- meerschaum/api/dash/callbacks/pipes.py +42 -0
- meerschaum/api/dash/pages/__init__.py +1 -0
- meerschaum/api/dash/pages/pipes.py +16 -0
- meerschaum/api/dash/pipes.py +79 -47
- meerschaum/api/dash/users.py +19 -6
- meerschaum/api/routes/_actions.py +0 -98
- meerschaum/api/routes/_jobs.py +38 -18
- meerschaum/api/routes/_login.py +4 -4
- meerschaum/api/routes/_pipes.py +3 -3
- meerschaum/config/_default.py +9 -2
- meerschaum/config/_version.py +1 -1
- meerschaum/config/stack/__init__.py +59 -18
- meerschaum/config/static/__init__.py +2 -0
- meerschaum/connectors/Connector.py +19 -13
- meerschaum/connectors/__init__.py +9 -5
- meerschaum/connectors/api/_actions.py +22 -36
- meerschaum/connectors/api/_jobs.py +1 -0
- meerschaum/connectors/poll.py +30 -24
- meerschaum/connectors/sql/_pipes.py +126 -154
- meerschaum/connectors/sql/_plugins.py +45 -43
- meerschaum/connectors/sql/_users.py +46 -38
- meerschaum/connectors/valkey/ValkeyConnector.py +535 -0
- meerschaum/connectors/valkey/__init__.py +8 -0
- meerschaum/connectors/valkey/_fetch.py +75 -0
- meerschaum/connectors/valkey/_pipes.py +839 -0
- meerschaum/connectors/valkey/_plugins.py +265 -0
- meerschaum/connectors/valkey/_users.py +305 -0
- meerschaum/core/Pipe/__init__.py +2 -0
- meerschaum/core/Pipe/_attributes.py +1 -2
- meerschaum/core/Pipe/_drop.py +4 -4
- meerschaum/core/Pipe/_dtypes.py +14 -14
- meerschaum/core/Pipe/_edit.py +15 -14
- meerschaum/core/Pipe/_sync.py +134 -51
- meerschaum/core/User/_User.py +14 -12
- meerschaum/jobs/_Job.py +26 -8
- meerschaum/jobs/systemd.py +20 -8
- meerschaum/plugins/_Plugin.py +17 -13
- meerschaum/utils/_get_pipes.py +14 -20
- meerschaum/utils/dataframe.py +288 -101
- meerschaum/utils/dtypes/__init__.py +31 -6
- meerschaum/utils/dtypes/sql.py +4 -4
- meerschaum/utils/misc.py +3 -3
- meerschaum/utils/packages/_packages.py +1 -0
- meerschaum/utils/prompt.py +1 -1
- {meerschaum-2.3.5.dev0.dist-info → meerschaum-2.4.0.dev0.dist-info}/METADATA +3 -1
- {meerschaum-2.3.5.dev0.dist-info → meerschaum-2.4.0.dev0.dist-info}/RECORD +62 -54
- {meerschaum-2.3.5.dev0.dist-info → meerschaum-2.4.0.dev0.dist-info}/WHEEL +1 -1
- {meerschaum-2.3.5.dev0.dist-info → meerschaum-2.4.0.dev0.dist-info}/LICENSE +0 -0
- {meerschaum-2.3.5.dev0.dist-info → meerschaum-2.4.0.dev0.dist-info}/NOTICE +0 -0
- {meerschaum-2.3.5.dev0.dist-info → meerschaum-2.4.0.dev0.dist-info}/entry_points.txt +0 -0
- {meerschaum-2.3.5.dev0.dist-info → meerschaum-2.4.0.dev0.dist-info}/top_level.txt +0 -0
- {meerschaum-2.3.5.dev0.dist-info → meerschaum-2.4.0.dev0.dist-info}/zip-safe +0 -0
@@ -31,15 +31,23 @@ db_host = 'MRSM{stack:' + str(STACK_COMPOSE_FILENAME) + ':services:db:hostname}'
|
|
31
31
|
api_port = "MRSM{meerschaum:connectors:api:main:port}"
|
32
32
|
api_host = "api"
|
33
33
|
|
34
|
+
valkey_hostname = "valkey"
|
35
|
+
valkey_host = 'MRSM{stack:' + str(STACK_COMPOSE_FILENAME) + ':services:valkey:hostname}'
|
36
|
+
valkey_port = "MRSM{meerschaum:connectors:valkey:main:port}"
|
37
|
+
valkey_username = 'MRSM{meerschaum:connectors:valkey:main:username}'
|
38
|
+
valkey_password = 'MRSM{meerschaum:connectors:valkey:main:password}'
|
39
|
+
|
34
40
|
env_dict = {
|
35
|
-
'COMPOSE_PROJECT_NAME'
|
36
|
-
'TIMESCALEDB_VERSION'
|
37
|
-
'POSTGRES_USER'
|
38
|
-
'POSTGRES_PASSWORD'
|
39
|
-
'POSTGRES_DB'
|
40
|
-
'
|
41
|
-
'
|
42
|
-
'
|
41
|
+
'COMPOSE_PROJECT_NAME': 'mrsm',
|
42
|
+
'TIMESCALEDB_VERSION': 'latest-pg16-oss',
|
43
|
+
'POSTGRES_USER': db_user,
|
44
|
+
'POSTGRES_PASSWORD': db_pass,
|
45
|
+
'POSTGRES_DB': db_base,
|
46
|
+
'VALKEY_USERNAME': valkey_username,
|
47
|
+
'VALKEY_PASSWORD': valkey_password,
|
48
|
+
'MEERSCHAUM_API_HOSTNAME': api_host,
|
49
|
+
'ALLOW_IP_RANGE': '0.0.0.0/0',
|
50
|
+
'MEERSCHAUM_API_CONFIG_RESOURCES': '/meerschaum',
|
43
51
|
}
|
44
52
|
### apply patch to host config to change hostname to the Docker service name
|
45
53
|
env_dict['MEERSCHAUM_API_CONFIG'] = json.dumps(
|
@@ -56,9 +64,9 @@ env_dict['MEERSCHAUM_API_CONFIG'] = json.dumps(
|
|
56
64
|
|
57
65
|
volumes = {
|
58
66
|
'api_root': '/meerschaum',
|
59
|
-
'api_user_local': '/home/meerschaum/.local',
|
60
67
|
'meerschaum_db_data': '/var/lib/postgresql/data',
|
61
68
|
'grafana_storage': '/var/lib/grafana',
|
69
|
+
'valkey_data': '/bitnami/valkey/data',
|
62
70
|
}
|
63
71
|
networks = {
|
64
72
|
'frontend': None,
|
@@ -77,10 +85,14 @@ env_dict['MEERSCHAUM_API_PATCH'] = json.dumps(
|
|
77
85
|
'database': volumes['api_root'] + '/sqlite/mrsm_local.db'
|
78
86
|
},
|
79
87
|
},
|
88
|
+
'valkey': {
|
89
|
+
'host': valkey_host,
|
90
|
+
'port': 6379,
|
91
|
+
},
|
80
92
|
},
|
81
93
|
},
|
82
94
|
},
|
83
|
-
indent
|
95
|
+
indent=4,
|
84
96
|
)
|
85
97
|
|
86
98
|
compose_header = """
|
@@ -114,19 +126,19 @@ default_docker_compose_config = {
|
|
114
126
|
],
|
115
127
|
'interval': '5s',
|
116
128
|
'timeout': '3s',
|
117
|
-
'retries':
|
129
|
+
'retries': 5
|
118
130
|
},
|
119
131
|
'restart': 'always',
|
120
|
-
'image'
|
121
|
-
'ports'
|
132
|
+
'image': 'timescale/timescaledb:' + env_dict['TIMESCALEDB_VERSION'],
|
133
|
+
'ports': [
|
122
134
|
f'{db_port}:5432',
|
123
135
|
],
|
124
|
-
'hostname'
|
125
|
-
'volumes'
|
136
|
+
'hostname': f'{db_hostname}',
|
137
|
+
'volumes': [
|
126
138
|
'meerschaum_db_data:' + volumes['meerschaum_db_data'],
|
127
139
|
],
|
128
140
|
'shm_size': '1024m',
|
129
|
-
'networks'
|
141
|
+
'networks': [
|
130
142
|
'backend',
|
131
143
|
],
|
132
144
|
},
|
@@ -157,10 +169,39 @@ default_docker_compose_config = {
|
|
157
169
|
'db': {
|
158
170
|
'condition': 'service_healthy',
|
159
171
|
},
|
172
|
+
'valkey': {
|
173
|
+
'condition': 'service_healthy',
|
174
|
+
},
|
160
175
|
},
|
161
|
-
'volumes'
|
176
|
+
'volumes': [
|
162
177
|
'api_root:' + volumes['api_root'],
|
163
|
-
|
178
|
+
],
|
179
|
+
},
|
180
|
+
'valkey': {
|
181
|
+
'image': 'bitnami/valkey',
|
182
|
+
'restart': 'always',
|
183
|
+
'environment': {
|
184
|
+
'VALKEY_PASSWORD': '<DOLLAR>VALKEY_PASSWORD',
|
185
|
+
'VALKEY_RDB_POLICY_DISABLED': 'no',
|
186
|
+
'VALKEY_RDB_POLICY': '900#1 600#5 300#10 120#50 60#1000 30#10000',
|
187
|
+
},
|
188
|
+
'hostname': valkey_hostname,
|
189
|
+
'ports': [
|
190
|
+
f'{valkey_port}:6379',
|
191
|
+
],
|
192
|
+
'volumes': [
|
193
|
+
'valkey_data:' + volumes['valkey_data'],
|
194
|
+
],
|
195
|
+
'healthcheck': {
|
196
|
+
'test': [
|
197
|
+
'CMD', 'valkey-cli', 'ping',
|
198
|
+
],
|
199
|
+
'interval': '5s',
|
200
|
+
'timeout': '3s',
|
201
|
+
'retries': 5,
|
202
|
+
},
|
203
|
+
'networks': [
|
204
|
+
'backend',
|
164
205
|
],
|
165
206
|
},
|
166
207
|
'grafana': {
|
@@ -46,6 +46,7 @@ STATIC_CONFIG: Dict[str, Any] = {
|
|
46
46
|
'stdin_message': 'MRSM_STDIN',
|
47
47
|
'stop_message': 'MRSM_STOP',
|
48
48
|
'metadata_cache_seconds': 5,
|
49
|
+
'temp_prefix': '.api-temp-',
|
49
50
|
},
|
50
51
|
},
|
51
52
|
'sql': {
|
@@ -73,6 +74,7 @@ STATIC_CONFIG: Dict[str, Any] = {
|
|
73
74
|
'systemd_log_path': 'MRSM_SYSTEMD_LOG_PATH',
|
74
75
|
'systemd_stdin_path': 'MRSM_SYSTEMD_STDIN_PATH',
|
75
76
|
'systemd_result_path': 'MRSM_SYSTEMD_RESULT_PATH',
|
77
|
+
'systemd_delete_job': 'MRSM_SYSTEMD_DELETE_JOB',
|
76
78
|
'uri_regex': r'MRSM_([a-zA-Z0-9]*)_(\d*[a-zA-Z][a-zA-Z0-9-_+]*$)',
|
77
79
|
'prefix': 'MRSM_',
|
78
80
|
},
|
@@ -53,17 +53,23 @@ class Connector(metaclass=abc.ABCMeta):
|
|
53
53
|
"""
|
54
54
|
self._original_dict = copy.deepcopy(self.__dict__)
|
55
55
|
self._set_attributes(type=type, label=label, **kw)
|
56
|
-
|
56
|
+
|
57
|
+
### NOTE: Override `REQUIRED_ATTRIBUTES` if `uri` is set.
|
58
|
+
self.verify_attributes(
|
59
|
+
['uri']
|
60
|
+
if 'uri' in self.__dict__
|
61
|
+
else getattr(self, 'REQUIRED_ATTRIBUTES', None)
|
62
|
+
)
|
57
63
|
|
58
64
|
def _reset_attributes(self):
|
59
65
|
self.__dict__ = self._original_dict
|
60
66
|
|
61
67
|
def _set_attributes(
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
68
|
+
self,
|
69
|
+
*args,
|
70
|
+
inherit_default: bool = True,
|
71
|
+
**kw: Any
|
72
|
+
):
|
67
73
|
from meerschaum.config.static import STATIC_CONFIG
|
68
74
|
from meerschaum.utils.warnings import error
|
69
75
|
|
@@ -114,12 +120,11 @@ class Connector(metaclass=abc.ABCMeta):
|
|
114
120
|
### finally, update __dict__ with _attributes.
|
115
121
|
self.__dict__.update(self._attributes)
|
116
122
|
|
117
|
-
|
118
123
|
def verify_attributes(
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
124
|
+
self,
|
125
|
+
required_attributes: Optional[List[str]] = None,
|
126
|
+
debug: bool = False,
|
127
|
+
) -> None:
|
123
128
|
"""
|
124
129
|
Ensure that the required attributes have been met.
|
125
130
|
|
@@ -147,6 +152,7 @@ class Connector(metaclass=abc.ABCMeta):
|
|
147
152
|
from meerschaum.utils.misc import items_str
|
148
153
|
if required_attributes is None:
|
149
154
|
required_attributes = ['label']
|
155
|
+
|
150
156
|
missing_attributes = set()
|
151
157
|
for a in required_attributes:
|
152
158
|
if a not in self.__dict__:
|
@@ -158,8 +164,8 @@ class Connector(metaclass=abc.ABCMeta):
|
|
158
164
|
+ f"for connector '{self.type}:{self.label}'."
|
159
165
|
),
|
160
166
|
InvalidAttributesError,
|
161
|
-
silent
|
162
|
-
stack
|
167
|
+
silent=True,
|
168
|
+
stack=False
|
163
169
|
)
|
164
170
|
|
165
171
|
|
@@ -39,6 +39,7 @@ connectors: Dict[str, Dict[str, Connector]] = {
|
|
39
39
|
'api' : {},
|
40
40
|
'sql' : {},
|
41
41
|
'plugin' : {},
|
42
|
+
'valkey' : {},
|
42
43
|
}
|
43
44
|
instance_types: List[str] = ['sql', 'api']
|
44
45
|
_locks: Dict[str, RLock] = {
|
@@ -164,13 +165,15 @@ def get_connector(
|
|
164
165
|
|
165
166
|
if 'sql' not in types:
|
166
167
|
from meerschaum.connectors.plugin import PluginConnector
|
168
|
+
from meerschaum.connectors.valkey import ValkeyConnector
|
167
169
|
with _locks['types']:
|
168
170
|
types.update({
|
169
|
-
'api'
|
170
|
-
'sql'
|
171
|
+
'api': APIConnector,
|
172
|
+
'sql': SQLConnector,
|
171
173
|
'plugin': PluginConnector,
|
174
|
+
'valkey': ValkeyConnector,
|
172
175
|
})
|
173
|
-
|
176
|
+
|
174
177
|
### determine if we need to call the constructor
|
175
178
|
if not refresh:
|
176
179
|
### see if any user-supplied arguments differ from the existing instance
|
@@ -273,7 +276,7 @@ def is_connected(keys: str, **kw) -> bool:
|
|
273
276
|
with warnings.catch_warnings():
|
274
277
|
warnings.filterwarnings('ignore')
|
275
278
|
return conn.test_connection(**kw)
|
276
|
-
except Exception
|
279
|
+
except Exception:
|
277
280
|
return False
|
278
281
|
|
279
282
|
|
@@ -340,7 +343,7 @@ def load_plugin_connectors():
|
|
340
343
|
to_import.append(plugin.name)
|
341
344
|
if not to_import:
|
342
345
|
return
|
343
|
-
import_plugins(*to_import)
|
346
|
+
import_plugins(*to_import)
|
344
347
|
|
345
348
|
|
346
349
|
def get_connector_plugin(
|
@@ -378,3 +381,4 @@ def _load_builtin_custom_connectors():
|
|
378
381
|
Import custom connectors decorated with `@make_connector` or `@make_executor`.
|
379
382
|
"""
|
380
383
|
import meerschaum.jobs.systemd
|
384
|
+
import meerschaum.connectors.valkey
|
@@ -17,6 +17,7 @@ from meerschaum.utils.typing import SuccessTuple, List, Callable, Optional
|
|
17
17
|
from meerschaum.config.static import STATIC_CONFIG
|
18
18
|
|
19
19
|
ACTIONS_ENDPOINT: str = STATIC_CONFIG['api']['endpoints']['actions']
|
20
|
+
TEMP_PREFIX: str = STATIC_CONFIG['api']['jobs']['temp_prefix']
|
20
21
|
|
21
22
|
|
22
23
|
def get_actions(self):
|
@@ -37,43 +38,28 @@ async def do_action_async(
|
|
37
38
|
callback_function: Callable[[str], None] = partial(print, end=''),
|
38
39
|
) -> SuccessTuple:
|
39
40
|
"""
|
40
|
-
|
41
|
+
Execute an action as a temporary remote job.
|
41
42
|
"""
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
while True:
|
64
|
-
try:
|
65
|
-
line = await websocket.recv()
|
66
|
-
if asyncio.iscoroutinefunction(callback_function):
|
67
|
-
await callback_function(line)
|
68
|
-
else:
|
69
|
-
callback_function(line)
|
70
|
-
except KeyboardInterrupt:
|
71
|
-
await websocket.close()
|
72
|
-
break
|
73
|
-
except websockets_exceptions.ConnectionClosedOK:
|
74
|
-
break
|
75
|
-
|
76
|
-
return True, "Success"
|
43
|
+
from meerschaum._internal.arguments import remove_api_executor_keys
|
44
|
+
from meerschaum.utils.misc import generate_password
|
45
|
+
sysargs = remove_api_executor_keys(sysargs)
|
46
|
+
|
47
|
+
job_name = TEMP_PREFIX + generate_password(12)
|
48
|
+
job = mrsm.Job(job_name, sysargs, executor_keys=str(self))
|
49
|
+
|
50
|
+
start_success, start_msg = job.start()
|
51
|
+
if not start_success:
|
52
|
+
return start_success, start_msg
|
53
|
+
|
54
|
+
await job.monitor_logs_async(
|
55
|
+
callback_function=callback_function,
|
56
|
+
stop_on_exit=True,
|
57
|
+
strip_timestamps=True,
|
58
|
+
)
|
59
|
+
|
60
|
+
success, msg = job.result
|
61
|
+
job.delete()
|
62
|
+
return success, msg
|
77
63
|
|
78
64
|
|
79
65
|
def do_action_legacy(
|
@@ -277,6 +277,7 @@ async def monitor_logs_async(
|
|
277
277
|
"""
|
278
278
|
Monitor a job's log files and await a callback with the changes.
|
279
279
|
"""
|
280
|
+
import traceback
|
280
281
|
from meerschaum.jobs import StopMonitoringLogs
|
281
282
|
from meerschaum.utils.formatting._jobs import strip_timestamp_from_line
|
282
283
|
|
meerschaum/connectors/poll.py
CHANGED
@@ -9,16 +9,16 @@ Poll database and API connections.
|
|
9
9
|
from meerschaum.utils.typing import InstanceConnector, Union, Optional, Dict, Any
|
10
10
|
|
11
11
|
def retry_connect(
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
12
|
+
connector: Union[InstanceConnector, None] = None,
|
13
|
+
max_retries: int = 50,
|
14
|
+
retry_wait: int = 3,
|
15
|
+
workers: int = 1,
|
16
|
+
warn: bool = True,
|
17
|
+
print_on_connect: bool = False,
|
18
|
+
enforce_chaining: bool = True,
|
19
|
+
enforce_login: bool = True,
|
20
|
+
debug: bool = False,
|
21
|
+
) -> bool:
|
22
22
|
"""
|
23
23
|
Keep trying to connect to the database.
|
24
24
|
|
@@ -85,16 +85,16 @@ def retry_connect(
|
|
85
85
|
|
86
86
|
|
87
87
|
def _wrap_retry_connect(
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
88
|
+
connector_meta: Dict[str, Any],
|
89
|
+
max_retries: int = 50,
|
90
|
+
retry_wait: int = 3,
|
91
|
+
workers: int = 1,
|
92
|
+
print_on_connect: bool = False,
|
93
|
+
warn: bool = True,
|
94
|
+
enforce_chaining: bool = True,
|
95
|
+
enforce_login: bool = True,
|
96
|
+
debug: bool = False,
|
97
|
+
) -> bool:
|
98
98
|
"""
|
99
99
|
Keep trying to connect to the database.
|
100
100
|
|
@@ -144,8 +144,6 @@ def _wrap_retry_connect(
|
|
144
144
|
import time
|
145
145
|
|
146
146
|
connector = get_connector(**connector_meta)
|
147
|
-
if connector.type not in instance_types:
|
148
|
-
return None
|
149
147
|
|
150
148
|
if not hasattr(connector, 'test_connection'):
|
151
149
|
return True
|
@@ -157,7 +155,15 @@ def _wrap_retry_connect(
|
|
157
155
|
dprint(f"Trying to connect to '{connector}'...")
|
158
156
|
dprint(f"Attempt ({retries + 1} / {max_retries})")
|
159
157
|
|
160
|
-
if connector.type
|
158
|
+
if connector.type not in ('sql', 'api'):
|
159
|
+
try:
|
160
|
+
connected = connector.test_connection()
|
161
|
+
except Exception as e:
|
162
|
+
if warn:
|
163
|
+
print(e)
|
164
|
+
connected = False
|
165
|
+
|
166
|
+
elif connector.type == 'sql':
|
161
167
|
|
162
168
|
def _connect(_connector):
|
163
169
|
### Test queries like `SELECT 1`.
|
@@ -185,7 +191,7 @@ def _wrap_retry_connect(
|
|
185
191
|
_warn(
|
186
192
|
f"Meerschaum instance '{connector}' does not allow chaining " +
|
187
193
|
"and cannot be used as the parent for this instance.",
|
188
|
-
stack
|
194
|
+
stack=False,
|
189
195
|
)
|
190
196
|
return False
|
191
197
|
|