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.

Files changed (54) hide show
  1. adam/commands/__init__.py +6 -2
  2. adam/commands/alter_tables.py +24 -35
  3. adam/commands/cat.py +3 -13
  4. adam/commands/cd.py +6 -8
  5. adam/commands/check.py +9 -17
  6. adam/commands/command.py +39 -5
  7. adam/commands/cp.py +24 -32
  8. adam/commands/cql/cql_completions.py +3 -4
  9. adam/commands/cql/utils_cql.py +0 -2
  10. adam/commands/devices/device_app.py +2 -2
  11. adam/commands/devices/device_cass.py +2 -2
  12. adam/commands/devices/device_export.py +7 -9
  13. adam/commands/devices/device_postgres.py +2 -2
  14. adam/commands/export/clean_up_all_export_sessions.py +3 -3
  15. adam/commands/export/clean_up_export_sessions.py +8 -15
  16. adam/commands/export/drop_export_database.py +6 -22
  17. adam/commands/export/drop_export_databases.py +3 -9
  18. adam/commands/export/export.py +1 -1
  19. adam/commands/export/export_databases.py +70 -15
  20. adam/commands/export/export_select.py +12 -23
  21. adam/commands/export/export_select_x.py +3 -3
  22. adam/commands/export/export_sessions.py +124 -0
  23. adam/commands/export/export_use.py +0 -6
  24. adam/commands/export/exporter.py +61 -120
  25. adam/commands/export/import_session.py +4 -4
  26. adam/commands/export/importer.py +12 -5
  27. adam/commands/export/importer_athena.py +17 -13
  28. adam/commands/export/importer_sqlite.py +20 -17
  29. adam/commands/export/show_column_counts.py +5 -14
  30. adam/commands/export/show_export_databases.py +2 -1
  31. adam/commands/export/show_export_session.py +5 -13
  32. adam/commands/export/show_export_sessions.py +2 -2
  33. adam/commands/export/utils_export.py +5 -3
  34. adam/commands/medusa/medusa_backup.py +1 -2
  35. adam/commands/medusa/medusa_restore.py +21 -19
  36. adam/commands/param_get.py +8 -9
  37. adam/commands/param_set.py +7 -10
  38. adam/commands/postgres/postgres.py +13 -21
  39. adam/commands/postgres/utils_postgres.py +5 -1
  40. adam/commands/preview_table.py +1 -1
  41. adam/commands/reaper/reaper_run_abort.py +4 -10
  42. adam/commands/reaper/reaper_schedule_activate.py +6 -10
  43. adam/commands/reaper/reaper_schedule_start.py +6 -10
  44. adam/commands/reaper/reaper_schedule_stop.py +6 -10
  45. adam/repl.py +5 -3
  46. adam/utils_k8s/k8s.py +5 -5
  47. adam/utils_sqlite.py +13 -13
  48. adam/version.py +1 -1
  49. {kaqing-2.0.172.dist-info → kaqing-2.0.174.dist-info}/METADATA +1 -1
  50. {kaqing-2.0.172.dist-info → kaqing-2.0.174.dist-info}/RECORD +53 -53
  51. adam/commands/export/export_handlers.py +0 -71
  52. {kaqing-2.0.172.dist-info → kaqing-2.0.174.dist-info}/WHEEL +0 -0
  53. {kaqing-2.0.172.dist-info → kaqing-2.0.174.dist-info}/entry_points.txt +0 -0
  54. {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, pod: str, namespace: str, to_session: str, from_session: str, keyspace: str, table: str, target_table: str, columns: str, multi_tables = True, create_db = False):
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
- db = self.db(to_session, keyspace)
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/{db}/{keyspace}/{target_table}/{table}.csv')
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 {db}"
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 {db};'
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, db)
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/{db}/{keyspace}/{target_table}'\n" + \
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, db)
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(pod, namespace, to_session, from_session, keyspace, target_table)
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(pod, namespace, from_session, table, target_table, multi_tables)
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
- query = f'select * from {target_table} limit 10'
76
- log2(query)
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, pod: str, namespace: str, to_session: str, from_session: str, keyspace: str, table: str, target_table: str, columns: str, multi_tables = True, create_db = False):
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
- with sqlite(to_session, keyspace) as conn:
18
- try:
19
- with ing(f'[{to_session}] Uploading to Sqlite', suppress_log=multi_tables):
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
- to, _ = self.move_to_done(pod, namespace, to_session, from_session, keyspace, target_table)
30
+ to, _ = self.move_to_done(state, from_session, keyspace, target_table)
26
31
 
27
- succeeded = True
32
+ succeeded = True
28
33
 
29
- return to, to_session
30
- finally:
31
- if succeeded:
32
- self.remove_csv(pod, namespace, from_session, table, target_table, multi_tables)
33
- SQLite.clear_cache()
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
- if not multi_tables:
36
- with sqlite(to_session) as conn:
37
- query = f'select * from {keyspace}.{target_table} limit 10'
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
- if not args:
31
- if state.in_repl:
32
- log2('Use a SQL statement.')
33
- else:
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
- DeviceExport().show_export_databases()
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.exporter import Exporter
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
- if not args:
31
- if state.in_repl:
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 Exporter.export_session_names(state.sts, state.pod, state.namespace)})
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.exporter import Exporter
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] = Exporter.find_export_sessions(pod, state.namespace)
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 PodHandler:
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.state.pop()
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 PodHandler(state)
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
- groups = re.match(r'^(.*?-.*?-).*', sts)
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.command import Command
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
- if len(args) == 1:
39
- bkname = args[0]
40
- job = CustomResources.medusa_get_backupjob(dc, ns, bkname)
41
- if not job:
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
- return state
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
- now_dtformat = datetime.now().strftime("%Y-%m-%d.%H.%M.%S")
58
- rtname = 'medusa-' + now_dtformat + '-restore-from-' + bkname
59
- with log_exc(lambda e: "Exception: MedusaRestore failed: %s\n" % e):
60
- CustomResources.create_medusa_restorejob(rtname, bkname, dc, ns)
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
- return state
64
+ return state
63
65
 
64
66
  def completion(self, state: ReplState):
65
67
  if sc := super().completion(state):
@@ -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
- if len(args) < 1:
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
- return state
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
- key = args[0]
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()}}
@@ -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
- if len(args) < 2:
27
- log2('set <key> <value>')
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
- return 'invalid args'
32
+ log(Config().get(key, None))
30
33
 
31
- key = args[0]
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
- if not args:
36
- if state.in_repl:
37
- log2('Please use SQL statement. e.g. pg \l')
38
- else:
39
- log2('* Command or SQL statements is missing.')
40
- Command.display_help()
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
- return 'command-missing'
42
+ return state
43
43
 
44
- if not state.pg_path:
45
44
  if state.in_repl:
46
- log2('Enter "use <pg-name>" first.')
47
- else:
48
- log2('* pg-name is missing.')
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
- PostgresContext.apply(state.namespace, state.pg_path).run_sql(' '.join(args), background=background)
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):
@@ -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
- if not args:
30
- if state.in_repl:
31
- log2('Specify run id to abort.')
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
- if not args:
30
- log2('Specify schedule to activate.')
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 state
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
- if not args:
30
- log2('Specify schedule to activate.')
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 state
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
- if not args:
30
- log2('Specify run schedule to stop.')
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 state
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, InvalidState
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, debug, debug_trace, deep_merge_dicts, deep_sort_dict, lines_to_tabular, log2, log_exc, log_timing
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 InvalidState:
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: