kaqing 2.0.172__py3-none-any.whl → 2.0.174__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.
Potentially problematic release.
This version of kaqing might be problematic. Click here for more details.
- adam/commands/__init__.py +6 -2
- adam/commands/alter_tables.py +24 -35
- adam/commands/cat.py +3 -13
- adam/commands/cd.py +6 -8
- adam/commands/check.py +9 -17
- adam/commands/command.py +39 -5
- adam/commands/cp.py +24 -32
- adam/commands/cql/cql_completions.py +3 -4
- adam/commands/cql/utils_cql.py +0 -2
- adam/commands/devices/device_app.py +2 -2
- adam/commands/devices/device_cass.py +2 -2
- adam/commands/devices/device_export.py +7 -9
- adam/commands/devices/device_postgres.py +2 -2
- adam/commands/export/clean_up_all_export_sessions.py +3 -3
- adam/commands/export/clean_up_export_sessions.py +8 -15
- adam/commands/export/drop_export_database.py +6 -22
- adam/commands/export/drop_export_databases.py +3 -9
- adam/commands/export/export.py +1 -1
- adam/commands/export/export_databases.py +70 -15
- adam/commands/export/export_select.py +12 -23
- adam/commands/export/export_select_x.py +3 -3
- adam/commands/export/export_sessions.py +124 -0
- adam/commands/export/export_use.py +0 -6
- adam/commands/export/exporter.py +61 -120
- adam/commands/export/import_session.py +4 -4
- adam/commands/export/importer.py +12 -5
- adam/commands/export/importer_athena.py +17 -13
- adam/commands/export/importer_sqlite.py +20 -17
- adam/commands/export/show_column_counts.py +5 -14
- adam/commands/export/show_export_databases.py +2 -1
- adam/commands/export/show_export_session.py +5 -13
- adam/commands/export/show_export_sessions.py +2 -2
- adam/commands/export/utils_export.py +5 -3
- adam/commands/medusa/medusa_backup.py +1 -2
- adam/commands/medusa/medusa_restore.py +21 -19
- adam/commands/param_get.py +8 -9
- adam/commands/param_set.py +7 -10
- adam/commands/postgres/postgres.py +13 -21
- adam/commands/postgres/utils_postgres.py +5 -1
- adam/commands/preview_table.py +1 -1
- adam/commands/reaper/reaper_run_abort.py +4 -10
- adam/commands/reaper/reaper_schedule_activate.py +6 -10
- adam/commands/reaper/reaper_schedule_start.py +6 -10
- adam/commands/reaper/reaper_schedule_stop.py +6 -10
- adam/repl.py +5 -3
- adam/utils_k8s/k8s.py +5 -5
- adam/utils_sqlite.py +13 -13
- adam/version.py +1 -1
- {kaqing-2.0.172.dist-info → kaqing-2.0.174.dist-info}/METADATA +1 -1
- {kaqing-2.0.172.dist-info → kaqing-2.0.174.dist-info}/RECORD +53 -53
- adam/commands/export/export_handlers.py +0 -71
- {kaqing-2.0.172.dist-info → kaqing-2.0.174.dist-info}/WHEEL +0 -0
- {kaqing-2.0.172.dist-info → kaqing-2.0.174.dist-info}/entry_points.txt +0 -0
- {kaqing-2.0.172.dist-info → kaqing-2.0.174.dist-info}/top_level.txt +0 -0
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import boto3
|
|
2
2
|
|
|
3
|
+
from adam.commands.export.export_databases import export_db
|
|
3
4
|
from adam.commands.export.importer import Importer
|
|
4
5
|
from adam.commands.export.utils_export import GeneratorStream
|
|
5
6
|
from adam.config import Config
|
|
7
|
+
from adam.repl_state import ReplState
|
|
6
8
|
from adam.utils import debug, log2, ing
|
|
7
9
|
from adam.utils_athena import Athena
|
|
8
10
|
from adam.utils_k8s.pods import Pods
|
|
@@ -17,9 +19,12 @@ class AthenaImporter(Importer):
|
|
|
17
19
|
def prefix(self):
|
|
18
20
|
return 'e'
|
|
19
21
|
|
|
20
|
-
def import_from_csv(self,
|
|
22
|
+
def import_from_csv(self, state: ReplState, from_session: str, keyspace: str, table: str, target_table: str, columns: str, multi_tables = True, create_db = False):
|
|
21
23
|
csv_file = self.csv_file(from_session, table, target_table)
|
|
22
|
-
|
|
24
|
+
pod = state.pod
|
|
25
|
+
namespace = state.namespace
|
|
26
|
+
to_session = state.export_session
|
|
27
|
+
database = self.db(to_session, keyspace)
|
|
23
28
|
|
|
24
29
|
succeeded = False
|
|
25
30
|
try:
|
|
@@ -29,21 +34,21 @@ class AthenaImporter(Importer):
|
|
|
29
34
|
bytes = Pods.read_file(pod, 'cassandra', namespace, csv_file)
|
|
30
35
|
|
|
31
36
|
s3 = boto3.client('s3')
|
|
32
|
-
s3.upload_fileobj(GeneratorStream(bytes), bucket, f'export/{
|
|
37
|
+
s3.upload_fileobj(GeneratorStream(bytes), bucket, f'export/{database}/{keyspace}/{target_table}/{table}.csv')
|
|
33
38
|
|
|
34
39
|
msg: str = None
|
|
35
40
|
if create_db:
|
|
36
|
-
msg = f"[{to_session}] Creating database {
|
|
41
|
+
msg = f"[{to_session}] Creating database {database}"
|
|
37
42
|
else:
|
|
38
43
|
msg = f"[{to_session}] Creating table {target_table}"
|
|
39
44
|
with ing(msg, suppress_log=multi_tables):
|
|
40
|
-
query = f'CREATE DATABASE IF NOT EXISTS {
|
|
45
|
+
query = f'CREATE DATABASE IF NOT EXISTS {database};'
|
|
41
46
|
debug(query)
|
|
42
47
|
Athena.query(query, 'default')
|
|
43
48
|
|
|
44
49
|
query = f'DROP TABLE IF EXISTS {target_table};'
|
|
45
50
|
debug(query)
|
|
46
|
-
Athena.query(query,
|
|
51
|
+
Athena.query(query, database)
|
|
47
52
|
|
|
48
53
|
athena_columns = ', '.join([f'{c} string' for c in columns.split(',')])
|
|
49
54
|
query = f'CREATE EXTERNAL TABLE IF NOT EXISTS {target_table}(\n' + \
|
|
@@ -52,26 +57,25 @@ class AthenaImporter(Importer):
|
|
|
52
57
|
'WITH SERDEPROPERTIES (\n' + \
|
|
53
58
|
' "separatorChar" = ",",\n' + \
|
|
54
59
|
' "quoteChar" = "\\"")\n' + \
|
|
55
|
-
f"LOCATION 's3://{bucket}/export/{
|
|
60
|
+
f"LOCATION 's3://{bucket}/export/{database}/{keyspace}/{target_table}'\n" + \
|
|
56
61
|
'TBLPROPERTIES ("skip.header.line.count"="1");'
|
|
57
62
|
debug(query)
|
|
58
63
|
try:
|
|
59
|
-
Athena.query(query,
|
|
64
|
+
Athena.query(query, database)
|
|
60
65
|
except Exception as e:
|
|
61
66
|
log2(f'*** Failed query:\n{query}')
|
|
62
67
|
raise e
|
|
63
68
|
|
|
64
|
-
to, _ = self.move_to_done(
|
|
69
|
+
to, _ = self.move_to_done(state, from_session, keyspace, target_table)
|
|
65
70
|
|
|
66
71
|
succeeded = True
|
|
67
72
|
|
|
68
73
|
return to, to_session
|
|
69
74
|
finally:
|
|
70
75
|
if succeeded:
|
|
71
|
-
self.remove_csv(
|
|
76
|
+
self.remove_csv(state, from_session, table, target_table, multi_tables)
|
|
72
77
|
Athena.clear_cache()
|
|
73
78
|
|
|
74
79
|
if not multi_tables:
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
Athena.run_query(query, db)
|
|
80
|
+
with export_db(state) as dbms:
|
|
81
|
+
dbms.sql(f'select * from {database}.{target_table} limit 10')
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import pandas
|
|
2
2
|
|
|
3
|
+
from adam.commands.export.export_databases import export_db
|
|
3
4
|
from adam.commands.export.importer import Importer
|
|
4
5
|
from adam.commands.export.utils_export import GeneratorStream
|
|
6
|
+
from adam.repl_state import ReplState
|
|
5
7
|
from adam.utils import log2, ing
|
|
6
8
|
from adam.utils_k8s.pods import Pods
|
|
7
9
|
from adam.utils_sqlite import SQLite, sqlite
|
|
@@ -10,30 +12,31 @@ class SqliteImporter(Importer):
|
|
|
10
12
|
def prefix(self):
|
|
11
13
|
return 's'
|
|
12
14
|
|
|
13
|
-
def import_from_csv(self,
|
|
15
|
+
def import_from_csv(self, state: ReplState, from_session: str, keyspace: str, table: str, target_table: str, columns: str, multi_tables = True, create_db = False):
|
|
14
16
|
csv_file = self.csv_file(from_session, table, target_table)
|
|
17
|
+
pod = state.pod
|
|
18
|
+
namespace = state.namespace
|
|
19
|
+
to_session = state.export_session
|
|
15
20
|
|
|
16
21
|
succeeded = False
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
22
|
+
try:
|
|
23
|
+
with ing(f'[{to_session}] Uploading to Sqlite', suppress_log=multi_tables):
|
|
24
|
+
# create a connection to single keyspace
|
|
25
|
+
with sqlite(to_session, keyspace) as conn:
|
|
20
26
|
bytes = Pods.read_file(pod, 'cassandra', namespace, csv_file)
|
|
21
27
|
df = pandas.read_csv(GeneratorStream(bytes))
|
|
22
|
-
|
|
23
28
|
df.to_sql(target_table, conn, index=False, if_exists='replace')
|
|
24
29
|
|
|
25
|
-
|
|
30
|
+
to, _ = self.move_to_done(state, from_session, keyspace, target_table)
|
|
26
31
|
|
|
27
|
-
|
|
32
|
+
succeeded = True
|
|
28
33
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
return to, to_session
|
|
35
|
+
finally:
|
|
36
|
+
if succeeded:
|
|
37
|
+
self.remove_csv(state, from_session, table, target_table, multi_tables)
|
|
38
|
+
SQLite.clear_cache()
|
|
34
39
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
log2(query)
|
|
39
|
-
SQLite.run_query_with_conn(conn, query)
|
|
40
|
+
if not multi_tables:
|
|
41
|
+
with export_db(state) as dbms:
|
|
42
|
+
dbms.sql(f'select * from {keyspace}.{target_table} limit 10')
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from adam.commands import validate_args
|
|
1
2
|
from adam.commands.command import Command
|
|
2
3
|
from adam.commands.export.export_databases import ExportDatabases
|
|
3
4
|
from adam.config import Config
|
|
@@ -27,20 +28,10 @@ class ShowColumnCounts(Command):
|
|
|
27
28
|
return super().run(cmd, state)
|
|
28
29
|
|
|
29
30
|
with self.validate(args, state) as (args, state):
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
log2('* SQL statement is missing.')
|
|
35
|
-
|
|
36
|
-
Command.display_help()
|
|
37
|
-
|
|
38
|
-
return 'command-missing'
|
|
39
|
-
|
|
40
|
-
table = args[0]
|
|
41
|
-
query = Config().get(f'export.column_counts_query', 'select id, count(id) as columns from {table} group by id')
|
|
42
|
-
query = query.replace('{table}', table)
|
|
43
|
-
ExportDatabases.run_query(query, state.export_session)
|
|
31
|
+
with validate_args(args, state, name='SQL statement') as table:
|
|
32
|
+
query = Config().get(f'export.column_counts_query', 'select id, count(id) as columns from {table} group by id')
|
|
33
|
+
query = query.replace('{table}', table)
|
|
34
|
+
ExportDatabases.run_query(query, state.export_session)
|
|
44
35
|
|
|
45
36
|
return state
|
|
46
37
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from adam.commands.command import Command
|
|
2
2
|
from adam.commands.devices.device_export import DeviceExport
|
|
3
|
+
from adam.commands.export.export_databases import ExportDatabases
|
|
3
4
|
from adam.repl_state import ReplState
|
|
4
5
|
|
|
5
6
|
class ShowExportDatabases(Command):
|
|
@@ -25,7 +26,7 @@ class ShowExportDatabases(Command):
|
|
|
25
26
|
return super().run(cmd, state)
|
|
26
27
|
|
|
27
28
|
with self.validate(args, state) as (args, state):
|
|
28
|
-
|
|
29
|
+
ExportDatabases.show_databases()
|
|
29
30
|
|
|
30
31
|
return state
|
|
31
32
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
from adam.commands import validate_args
|
|
1
2
|
from adam.commands.command import Command
|
|
2
3
|
from adam.commands.export.export_databases import ExportDatabases
|
|
3
|
-
from adam.commands.export.
|
|
4
|
+
from adam.commands.export.export_sessions import ExportSessions
|
|
4
5
|
from adam.repl_state import ReplState, RequiredState
|
|
5
6
|
from adam.utils import log2
|
|
6
7
|
|
|
@@ -27,22 +28,13 @@ class ShowExportSession(Command):
|
|
|
27
28
|
return super().run(cmd, state)
|
|
28
29
|
|
|
29
30
|
with self.validate(args, state) as (args, state):
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
log2('Specify export database name.')
|
|
33
|
-
else:
|
|
34
|
-
log2('* Database name is missing.')
|
|
35
|
-
|
|
36
|
-
Command.display_help()
|
|
37
|
-
|
|
38
|
-
return 'command-missing'
|
|
39
|
-
|
|
40
|
-
ExportDatabases.disply_export_session(state.sts, state.pod, state.namespace, args[0])
|
|
31
|
+
with validate_args(args, state, name='database name'):
|
|
32
|
+
ExportSessions.disply_export_session(state.sts, state.pod, state.namespace, args[0])
|
|
41
33
|
|
|
42
34
|
return state
|
|
43
35
|
|
|
44
36
|
def completion(self, state: ReplState):
|
|
45
|
-
return super().completion(state, {session: None for session in
|
|
37
|
+
return super().completion(state, {session: None for session in ExportSessions.export_session_names(state.sts, state.pod, state.namespace)})
|
|
46
38
|
|
|
47
39
|
def help(self, _: ReplState):
|
|
48
40
|
return f'{ShowExportSession.COMMAND} <export-session-name>\t show export session'
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from adam.commands.command import Command
|
|
2
|
-
from adam.commands.export.
|
|
2
|
+
from adam.commands.export.export_sessions import ExportSessions
|
|
3
3
|
from adam.repl_state import ReplState, RequiredState
|
|
4
4
|
from adam.utils import lines_to_tabular, log
|
|
5
5
|
from adam.utils_k8s.statefulsets import StatefulSets
|
|
@@ -31,7 +31,7 @@ class ShowExportSessions(Command):
|
|
|
31
31
|
if not pod:
|
|
32
32
|
pod = StatefulSets.pod_names(state.sts, state.namespace)[0]
|
|
33
33
|
|
|
34
|
-
sessions: dict[str, str] =
|
|
34
|
+
sessions: dict[str, str] = ExportSessions.find_export_sessions(pod, state.namespace)
|
|
35
35
|
log(lines_to_tabular([f'{session}\t{export_state}' for session, export_state in sorted(sessions.items(), reverse=True)],
|
|
36
36
|
header='EXPORT_SESSION\tSTATUS', separator='\t'))
|
|
37
37
|
|
|
@@ -292,9 +292,10 @@ class GeneratorStream(io.RawIOBase):
|
|
|
292
292
|
self._buffer = self._buffer[size:]
|
|
293
293
|
return data
|
|
294
294
|
|
|
295
|
-
class
|
|
295
|
+
class PodPushHandler:
|
|
296
296
|
def __init__(self, state: ReplState):
|
|
297
297
|
self.state = state
|
|
298
|
+
self.pushed = False
|
|
298
299
|
|
|
299
300
|
def __enter__(self):
|
|
300
301
|
state = self.state
|
|
@@ -306,9 +307,10 @@ class PodHandler:
|
|
|
306
307
|
return state
|
|
307
308
|
|
|
308
309
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
309
|
-
self.
|
|
310
|
+
if self.pushed:
|
|
311
|
+
self.state.pop()
|
|
310
312
|
|
|
311
313
|
return False
|
|
312
314
|
|
|
313
315
|
def state_with_pod(state: ReplState):
|
|
314
|
-
return
|
|
316
|
+
return PodPushHandler(state)
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
|
-
import re
|
|
3
2
|
|
|
4
3
|
from adam.commands.command import Command
|
|
5
4
|
from adam.utils_k8s.statefulsets import StatefulSets
|
|
@@ -36,7 +35,7 @@ class MedusaBackup(Command):
|
|
|
36
35
|
bkname = 'medusa-' + now_dtformat + 'full-backup-' + sts
|
|
37
36
|
if len(args) == 1:
|
|
38
37
|
bkname = str(args[0])
|
|
39
|
-
|
|
38
|
+
|
|
40
39
|
dc = StatefulSets.get_datacenter(state.sts, ns)
|
|
41
40
|
if not dc:
|
|
42
41
|
return state
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
1
2
|
from datetime import datetime
|
|
3
|
+
from functools import partial
|
|
2
4
|
|
|
3
|
-
from adam.commands
|
|
5
|
+
from adam.commands import validate_args
|
|
6
|
+
from adam.commands.command import Command, InvalidArgumentsException
|
|
4
7
|
from adam.utils_k8s.statefulsets import StatefulSets
|
|
5
8
|
from adam.repl_state import ReplState, RequiredState
|
|
6
9
|
from adam.utils_k8s.custom_resources import CustomResources
|
|
@@ -35,31 +38,30 @@ class MedusaRestore(Command):
|
|
|
35
38
|
if not dc:
|
|
36
39
|
return state
|
|
37
40
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
def msg(missing: bool):
|
|
42
|
+
if missing:
|
|
43
|
+
log2('\n* Missing Backup Name')
|
|
44
|
+
log2('Usage: qing restore <backup> <sts@name_space>\n')
|
|
45
|
+
else:
|
|
42
46
|
log2('\n* Backup job name is not valid.')
|
|
43
|
-
bklist = [f"{x['metadata']['name']}\t{x['metadata']['creationTimestamp']}\t{x['status'].get('finishTime', '')}" for x in CustomResources.medusa_show_backupjobs(dc, ns)]
|
|
44
|
-
log2(lines_to_tabular(bklist, 'NAME\tCREATED\tFINISHED', separator='\t'))
|
|
45
47
|
|
|
46
|
-
|
|
48
|
+
bklist = [f"{x['metadata']['name']}\t{x['metadata']['creationTimestamp']}\t{x['status'].get('finishTime', '')}" for x in CustomResources.medusa_show_backupjobs(dc, ns)]
|
|
49
|
+
log2(lines_to_tabular(bklist, 'NAME\tCREATED\tFINISHED', separator='\t'))
|
|
50
|
+
|
|
51
|
+
with validate_args(args, state, msg=partial(msg, True)) as bkname:
|
|
52
|
+
if not (job := CustomResources.medusa_get_backupjob(dc, ns, bkname)):
|
|
53
|
+
msg(False)
|
|
54
|
+
raise InvalidArgumentsException()
|
|
47
55
|
|
|
48
56
|
if not input(f"Restoring from {bkname} created at {job['metadata']['creationTimestamp']}. Please enter Yes to continue: ").lower() in ['y', 'yes']:
|
|
49
57
|
return state
|
|
50
|
-
else:
|
|
51
|
-
bklist = [f"{x['metadata']['name']}\t{x['metadata']['creationTimestamp']}\t{x['status'].get('finishTime', '')}" for x in CustomResources.medusa_show_backupjobs(dc, ns)]
|
|
52
|
-
log2('\n* Missing Backup Name')
|
|
53
|
-
log2('Usage: qing medusa restore <backup> <sts@name_space>\n')
|
|
54
|
-
log2(lines_to_tabular(bklist, 'NAME\tCREATED\tFINISHED', separator='\t'))
|
|
55
|
-
return state
|
|
56
58
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
with log_exc(lambda e: "Exception: MedusaRestore failed: %s\n" % e):
|
|
60
|
+
now_dtformat = datetime.now().strftime("%Y-%m-%d.%H.%M.%S")
|
|
61
|
+
rtname = 'medusa-' + now_dtformat + '-restore-from-' + bkname
|
|
62
|
+
CustomResources.create_medusa_restorejob(rtname, bkname, dc, ns)
|
|
61
63
|
|
|
62
|
-
|
|
64
|
+
return state
|
|
63
65
|
|
|
64
66
|
def completion(self, state: ReplState):
|
|
65
67
|
if sc := super().completion(state):
|
adam/commands/param_get.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from adam.commands import validate_args
|
|
1
2
|
from adam.commands.command import Command
|
|
2
3
|
from adam.config import Config
|
|
3
4
|
from adam.repl_state import ReplState
|
|
@@ -23,19 +24,17 @@ class GetParam(Command):
|
|
|
23
24
|
return super().run(cmd, state)
|
|
24
25
|
|
|
25
26
|
with self.validate(args, state) as (args, state):
|
|
26
|
-
|
|
27
|
+
def msg():
|
|
27
28
|
lines = [f'{key}\t{Config().get(key, None)}' for key in Config().keys()]
|
|
28
29
|
log(lines_to_tabular(lines, separator='\t'))
|
|
29
30
|
|
|
30
|
-
|
|
31
|
+
with validate_args(args, state, msg=msg) as key:
|
|
32
|
+
if v := Config().get(key, None):
|
|
33
|
+
log(v)
|
|
34
|
+
else:
|
|
35
|
+
log2(f'{key} is not set.')
|
|
31
36
|
|
|
32
|
-
|
|
33
|
-
if v := Config().get(key, None):
|
|
34
|
-
log(v)
|
|
35
|
-
else:
|
|
36
|
-
log2(f'{key} is not set.')
|
|
37
|
-
|
|
38
|
-
return v if v else state
|
|
37
|
+
return v if v else state
|
|
39
38
|
|
|
40
39
|
def completion(self, _: ReplState):
|
|
41
40
|
return {GetParam.COMMAND: {key: None for key in Config().keys()}}
|
adam/commands/param_set.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from adam.commands import validate_args
|
|
1
2
|
from adam.commands.command import Command
|
|
2
3
|
from adam.config import Config
|
|
3
4
|
from adam.repl_state import ReplState
|
|
@@ -23,18 +24,14 @@ class SetParam(Command):
|
|
|
23
24
|
return super().run(cmd, state)
|
|
24
25
|
|
|
25
26
|
with self.validate(args, state) as (args, state):
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
with validate_args(args, state, count_at_least=2, msg=lambda: log2('set <key> <value>')):
|
|
28
|
+
key = args[0]
|
|
29
|
+
value = args[1]
|
|
30
|
+
Config().set(key, value)
|
|
28
31
|
|
|
29
|
-
|
|
32
|
+
log(Config().get(key, None))
|
|
30
33
|
|
|
31
|
-
|
|
32
|
-
value = args[1]
|
|
33
|
-
Config().set(key, value)
|
|
34
|
-
|
|
35
|
-
log(Config().get(key, None))
|
|
36
|
-
|
|
37
|
-
return value
|
|
34
|
+
return value
|
|
38
35
|
|
|
39
36
|
def completion(self, _: ReplState):
|
|
40
37
|
return {SetParam.COMMAND: {key: ({'true': None, 'false': None} if Config().get(key, None) in [True, False] else None) for key in Config().keys()}}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import click
|
|
2
2
|
|
|
3
|
-
from adam.commands import extract_trailing_options
|
|
3
|
+
from adam.commands import extract_trailing_options, validate_args
|
|
4
4
|
from adam.commands.command import Command
|
|
5
5
|
from adam.commands.intermediate_command import IntermediateCommand
|
|
6
6
|
from adam.commands.postgres.psql_completions import psql_completions
|
|
@@ -32,32 +32,24 @@ class Postgres(IntermediateCommand):
|
|
|
32
32
|
|
|
33
33
|
with self.validate(args, state) as (args, state):
|
|
34
34
|
with extract_trailing_options(args, '&') as (args, backgrounded):
|
|
35
|
-
|
|
36
|
-
if state.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
with validate_args(args, state, name='SQL statement') as sql:
|
|
36
|
+
if not state.pg_path:
|
|
37
|
+
if state.in_repl:
|
|
38
|
+
log2('Enter "use <pg-name>" first.')
|
|
39
|
+
else:
|
|
40
|
+
log2('* pg-name is missing.')
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
return state
|
|
43
43
|
|
|
44
|
-
if not state.pg_path:
|
|
45
44
|
if state.in_repl:
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
with postgres(state) as pod:
|
|
46
|
+
pod.sql(args, background=backgrounded)
|
|
47
|
+
elif not self.run_subcommand(cmd, state):
|
|
48
|
+
with postgres(state) as pod:
|
|
49
|
+
pod.sql(args, background=backgrounded)
|
|
49
50
|
|
|
50
51
|
return state
|
|
51
52
|
|
|
52
|
-
if state.in_repl:
|
|
53
|
-
with postgres(state) as pod:
|
|
54
|
-
pod.sql(args, background=backgrounded)
|
|
55
|
-
elif not self.run_subcommand(cmd, state):
|
|
56
|
-
with postgres(state) as pod:
|
|
57
|
-
pod.sql(args, background=backgrounded)
|
|
58
|
-
|
|
59
|
-
return state
|
|
60
|
-
|
|
61
53
|
def cmd_list(self):
|
|
62
54
|
return [PostgresLs(), PostgresPreview(), PostgresPg()]
|
|
63
55
|
|
|
@@ -49,7 +49,11 @@ class PostgresPodService:
|
|
|
49
49
|
def sql(self, args: list[str], background=False):
|
|
50
50
|
state = self.handler.state
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
query = args
|
|
53
|
+
if isinstance(args, list):
|
|
54
|
+
query = ' '.join(args)
|
|
55
|
+
|
|
56
|
+
PostgresContext.apply(state.namespace, state.pg_path).run_sql(query, background=background)
|
|
53
57
|
|
|
54
58
|
class PostgresExecHandler:
|
|
55
59
|
def __init__(self, state: ReplState, background=False):
|
adam/commands/preview_table.py
CHANGED
|
@@ -18,7 +18,7 @@ class PreviewTable(Command):
|
|
|
18
18
|
return PreviewTable.COMMAND
|
|
19
19
|
|
|
20
20
|
def required(self):
|
|
21
|
-
return [RequiredState.CLUSTER_OR_POD, RequiredState.PG_DATABASE, ReplState.L]
|
|
21
|
+
return [RequiredState.CLUSTER_OR_POD, RequiredState.PG_DATABASE, ReplState.L, RequiredState.EXPORT_DB]
|
|
22
22
|
|
|
23
23
|
def run(self, cmd: str, state: ReplState):
|
|
24
24
|
if not(args := self.args(cmd)):
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from adam.commands import validate_args
|
|
1
2
|
from adam.commands.command import Command
|
|
2
3
|
from adam.commands.reaper.utils_reaper import reaper
|
|
3
4
|
from adam.repl_state import ReplState, RequiredState
|
|
@@ -26,19 +27,12 @@ class ReaperRunAbort(Command):
|
|
|
26
27
|
return super().run(cmd, state)
|
|
27
28
|
|
|
28
29
|
with self.validate(args, state) as (args, state):
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
else:
|
|
33
|
-
Command.display_help()
|
|
30
|
+
with validate_args(args, state, name='run id') as run_id:
|
|
31
|
+
with reaper(state) as http:
|
|
32
|
+
http.put(f'repair_run/{run_id}/state/ABORTED')
|
|
34
33
|
|
|
35
34
|
return state
|
|
36
35
|
|
|
37
|
-
with reaper(state) as http:
|
|
38
|
-
http.put(f'repair_run/{args[0]}/state/ABORTED')
|
|
39
|
-
|
|
40
|
-
return state
|
|
41
|
-
|
|
42
36
|
def completion(self, state: ReplState):
|
|
43
37
|
return super().completion(state)
|
|
44
38
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from adam.commands import validate_args
|
|
1
2
|
from adam.commands.command import Command
|
|
2
3
|
from adam.commands.reaper.utils_reaper import Reapers, reaper
|
|
3
4
|
from adam.repl_state import ReplState, RequiredState
|
|
@@ -26,17 +27,12 @@ class ReaperScheduleActivate(Command):
|
|
|
26
27
|
return super().run(cmd, state)
|
|
27
28
|
|
|
28
29
|
with self.validate(args, state) as (args, state):
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
with validate_args(args, state, name='schedule') as schedule_id:
|
|
31
|
+
with reaper(state) as http:
|
|
32
|
+
http.put(f'repair_schedule/{schedule_id}?state=ACTIVE')
|
|
33
|
+
Reapers.show_schedule(state, schedule_id)
|
|
31
34
|
|
|
32
|
-
return
|
|
33
|
-
|
|
34
|
-
schedule_id = args[0]
|
|
35
|
-
with reaper(state) as http:
|
|
36
|
-
http.put(f'repair_schedule/{schedule_id}?state=ACTIVE')
|
|
37
|
-
Reapers.show_schedule(state, schedule_id)
|
|
38
|
-
|
|
39
|
-
return schedule_id
|
|
35
|
+
return schedule_id
|
|
40
36
|
|
|
41
37
|
def completion(self, state: ReplState):
|
|
42
38
|
return super().completion(state, lambda: {id: None for id in Reapers.cached_schedule_ids(state)})
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from adam.commands import validate_args
|
|
1
2
|
from adam.commands.command import Command
|
|
2
3
|
from adam.commands.reaper.utils_reaper import Reapers, reaper
|
|
3
4
|
from adam.repl_state import ReplState, RequiredState
|
|
@@ -26,17 +27,12 @@ class ReaperScheduleStart(Command):
|
|
|
26
27
|
return super().run(cmd, state)
|
|
27
28
|
|
|
28
29
|
with self.validate(args, state) as (args, state):
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
with validate_args(args, state, name='schedule') as schedule_id:
|
|
31
|
+
with reaper(state) as http:
|
|
32
|
+
http.post(f'repair_schedule/start/{schedule_id}')
|
|
33
|
+
Reapers.show_schedule(state, schedule_id)
|
|
31
34
|
|
|
32
|
-
return
|
|
33
|
-
|
|
34
|
-
schedule_id = args[0]
|
|
35
|
-
with reaper(state) as http:
|
|
36
|
-
http.post(f'repair_schedule/start/{schedule_id}')
|
|
37
|
-
Reapers.show_schedule(state, schedule_id)
|
|
38
|
-
|
|
39
|
-
return schedule_id
|
|
35
|
+
return schedule_id
|
|
40
36
|
|
|
41
37
|
def completion(self, state: ReplState):
|
|
42
38
|
return super().completion(state, lambda: {id: None for id in Reapers.cached_schedule_ids(state)})
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from adam.commands import validate_args
|
|
1
2
|
from adam.commands.command import Command
|
|
2
3
|
from adam.commands.reaper.utils_reaper import Reapers, reaper
|
|
3
4
|
from adam.repl_state import ReplState, RequiredState
|
|
@@ -26,17 +27,12 @@ class ReaperScheduleStop(Command):
|
|
|
26
27
|
return super().run(cmd, state)
|
|
27
28
|
|
|
28
29
|
with self.validate(args, state) as (args, state):
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
with validate_args(args, state, name='schedule') as schedule_id:
|
|
31
|
+
with reaper(state) as http:
|
|
32
|
+
http.put(f'repair_schedule/{schedule_id}?state=PAUSED')
|
|
33
|
+
Reapers.show_schedule(state, schedule_id)
|
|
31
34
|
|
|
32
|
-
return
|
|
33
|
-
|
|
34
|
-
with reaper(state) as http:
|
|
35
|
-
schedule_id = args[0]
|
|
36
|
-
http.put(f'repair_schedule/{schedule_id}?state=PAUSED')
|
|
37
|
-
Reapers.show_schedule(state, schedule_id)
|
|
38
|
-
|
|
39
|
-
return schedule_id
|
|
35
|
+
return schedule_id
|
|
40
36
|
|
|
41
37
|
def completion(self, state: ReplState):
|
|
42
38
|
return super().completion(state, lambda: {id: None for id in Reapers.cached_schedule_ids(state)})
|
adam/repl.py
CHANGED
|
@@ -5,7 +5,7 @@ import click
|
|
|
5
5
|
from prompt_toolkit.key_binding import KeyBindings
|
|
6
6
|
|
|
7
7
|
from adam.cli_group import cli
|
|
8
|
-
from adam.commands.command import Command,
|
|
8
|
+
from adam.commands.command import Command, InvalidArgumentsException, InvalidStateException
|
|
9
9
|
from adam.commands.command_helpers import ClusterCommandHelper
|
|
10
10
|
from adam.commands.devices.devices import Devices
|
|
11
11
|
from adam.commands.help import Help
|
|
@@ -16,7 +16,7 @@ from adam.log import Log
|
|
|
16
16
|
from adam.repl_commands import ReplCommands
|
|
17
17
|
from adam.repl_session import ReplSession
|
|
18
18
|
from adam.repl_state import ReplState
|
|
19
|
-
from adam.utils import clear_wait_log_flag,
|
|
19
|
+
from adam.utils import clear_wait_log_flag, debug_trace, deep_merge_dicts, deep_sort_dict, lines_to_tabular, log2, log_exc, log_timing
|
|
20
20
|
from adam.apps import Apps
|
|
21
21
|
from adam.utils_repl.repl_completer import ReplCompleter
|
|
22
22
|
from . import __version__
|
|
@@ -109,7 +109,9 @@ def enter_repl(state: ReplState):
|
|
|
109
109
|
try:
|
|
110
110
|
if cmd and cmd.strip(' ') and not (result := cmds.run(cmd, target)):
|
|
111
111
|
result = try_device_default_action(target, cmds, cmd_list, cmd)
|
|
112
|
-
except
|
|
112
|
+
except InvalidStateException:
|
|
113
|
+
pass
|
|
114
|
+
except InvalidArgumentsException:
|
|
113
115
|
pass
|
|
114
116
|
|
|
115
117
|
if result and type(result) is ReplState and (s := cast(ReplState, result).export_session) != state.export_session:
|