kaqing 2.0.186__py3-none-any.whl → 2.0.200__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 (77) hide show
  1. adam/app_session.py +1 -1
  2. adam/batch.py +6 -6
  3. adam/commands/bash/bash.py +1 -1
  4. adam/commands/bash/utils_bash.py +1 -1
  5. adam/commands/cassandra/__init__.py +0 -0
  6. adam/commands/cassandra/download_cassandra_log.py +45 -0
  7. adam/commands/cassandra/nodetool.py +64 -0
  8. adam/commands/cassandra/nodetool_commands.py +120 -0
  9. adam/commands/cassandra/restart_cluster.py +47 -0
  10. adam/commands/cassandra/restart_node.py +51 -0
  11. adam/commands/cassandra/restart_nodes.py +47 -0
  12. adam/commands/cassandra/rollout.py +88 -0
  13. adam/commands/cat.py +2 -2
  14. adam/commands/cd.py +2 -2
  15. adam/commands/command.py +1 -1
  16. adam/commands/commands_utils.py +8 -13
  17. adam/commands/cql/alter_tables.py +66 -0
  18. adam/commands/cql/completions_c.py +1 -0
  19. adam/commands/cql/utils_cql.py +5 -5
  20. adam/commands/debug/__init__.py +0 -0
  21. adam/commands/debug/debug.py +22 -0
  22. adam/commands/debug/debug_completes.py +35 -0
  23. adam/commands/debug/debug_timings.py +35 -0
  24. adam/commands/devices/devices.py +1 -1
  25. adam/commands/download_cassandra_log.py +45 -0
  26. adam/commands/download_file.py +3 -3
  27. adam/commands/export/export_sessions.py +1 -1
  28. adam/commands/export/exporter.py +1 -1
  29. adam/commands/find_processes.py +2 -2
  30. adam/commands/generate_report.py +52 -0
  31. adam/commands/head.py +2 -2
  32. adam/commands/ls.py +2 -2
  33. adam/commands/medusa/medusa_restore.py +0 -16
  34. adam/commands/nodetool.py +1 -1
  35. adam/commands/os/__init__.py +0 -0
  36. adam/commands/os/cat.py +36 -0
  37. adam/commands/os/download_file.py +47 -0
  38. adam/commands/os/find_files.py +51 -0
  39. adam/commands/os/find_processes.py +76 -0
  40. adam/commands/os/head.py +36 -0
  41. adam/commands/os/shell.py +41 -0
  42. adam/commands/postgres/postgres_databases.py +2 -3
  43. adam/commands/preview_table.py +1 -1
  44. adam/commands/restart_cluster.py +47 -0
  45. adam/commands/restart_node.py +51 -0
  46. adam/commands/restart_nodes.py +47 -0
  47. adam/commands/show/show_cli_commands.py +1 -1
  48. adam/config.py +4 -6
  49. adam/embedded_params.py +1 -1
  50. adam/repl.py +5 -3
  51. adam/repl_commands.py +11 -6
  52. adam/repl_session.py +4 -3
  53. adam/repl_state.py +6 -0
  54. adam/sql/async_executor.py +44 -0
  55. adam/sql/lark_completer.py +15 -9
  56. adam/sql/qingl.lark +1076 -0
  57. adam/utils.py +95 -23
  58. adam/utils_k8s/app_clusters.py +1 -1
  59. adam/utils_k8s/app_pods.py +2 -3
  60. adam/utils_k8s/cassandra_clusters.py +7 -3
  61. adam/utils_k8s/cassandra_nodes.py +8 -5
  62. adam/utils_k8s/kube_context.py +1 -4
  63. adam/utils_k8s/pods.py +55 -1
  64. adam/utils_repl/repl_completer.py +4 -87
  65. adam/version.py +1 -1
  66. {kaqing-2.0.186.dist-info → kaqing-2.0.200.dist-info}/METADATA +1 -1
  67. {kaqing-2.0.186.dist-info → kaqing-2.0.200.dist-info}/RECORD +73 -46
  68. kaqing-2.0.200.dist-info/top_level.txt +2 -0
  69. teddy/__init__.py +0 -0
  70. teddy/lark_parser.py +436 -0
  71. teddy/lark_parser2.py +618 -0
  72. adam/commands/logs.py +0 -37
  73. adam/commands/report.py +0 -61
  74. adam/commands/restart.py +0 -60
  75. kaqing-2.0.186.dist-info/top_level.txt +0 -1
  76. {kaqing-2.0.186.dist-info → kaqing-2.0.200.dist-info}/WHEEL +0 -0
  77. {kaqing-2.0.186.dist-info → kaqing-2.0.200.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,66 @@
1
+ from adam.commands import extract_options, validate_args
2
+ from adam.commands.command import Command
3
+ from adam.commands.cql.utils_cql import cassandra, cassandra_tables as get_tables
4
+ from adam.config import Config
5
+ from adam.repl_state import ReplState, RequiredState
6
+ from adam.utils import log2, log_exc
7
+
8
+ class AlterTables(Command):
9
+ COMMAND = 'alter tables with'
10
+
11
+ # the singleton pattern
12
+ def __new__(cls, *args, **kwargs):
13
+ if not hasattr(cls, 'instance'): cls.instance = super(AlterTables, cls).__new__(cls)
14
+
15
+ return cls.instance
16
+
17
+ def __init__(self, successor: Command=None):
18
+ super().__init__(successor)
19
+
20
+ def required(self):
21
+ return RequiredState.CLUSTER
22
+
23
+ def command(self):
24
+ return AlterTables.COMMAND
25
+
26
+ def run(self, cmd: str, state: ReplState):
27
+ if not(args := self.args(cmd)):
28
+ return super().run(cmd, state)
29
+
30
+ with self.validate(args, state) as (args, state):
31
+ with extract_options(args, '--include-reaper') as (args, include_reaper):
32
+ with validate_args(args, state, name='gc grace in seconds') as arg_str:
33
+ excludes = [e.strip(' \r\n') for e in Config().get(
34
+ 'cql.alter-tables.excludes',
35
+ 'system_auth,system_traces,reaper_db,system_distributed,system_views,system,system_schema,system_virtual_schema').split(',')]
36
+ batching = Config().get('cql.alter-tables.batching', True)
37
+ tables = get_tables(state, on_any=True)
38
+ for k, v in tables.items():
39
+ if k not in excludes or k == 'reaper_db' and include_reaper:
40
+ if batching:
41
+ # alter table <table_name> with GC_GRACE_SECONDS = <timeout>;
42
+ cql = ';\n'.join([f'alter table {k}.{t} with {arg_str}' for t in v])
43
+ with log_exc(True):
44
+ with cassandra(state) as pods:
45
+ pods.cql(cql, show_out=Config().is_debug(), show_query=not Config().is_debug(), on_any=True)
46
+ continue
47
+ else:
48
+ for t in v:
49
+ with log_exc(True):
50
+ # alter table <table_name> with GC_GRACE_SECONDS = <timeout>;
51
+ cql = f'alter table {k}.{t} with {arg_str}'
52
+ with cassandra(state) as pods:
53
+ pods.cql(show_out=Config().is_debug(), show_query=not Config().is_debug(), on_any=True)
54
+ continue
55
+
56
+ log2(f'{len(v)} tables altered in {k}.')
57
+
58
+ # do not continue to cql route
59
+ return state
60
+
61
+ def completion(self, _: ReplState) -> dict[str, any]:
62
+ # auto completion is taken care of by lark completer
63
+ return {}
64
+
65
+ def help(self, _: ReplState) -> str:
66
+ return f'{AlterTables.COMMAND} <param = value> [--include-reaper] \t alter schema on all tables'
@@ -18,6 +18,7 @@ def completions_c(state: ReplState) -> dict[str, any]:
18
18
  'table-props': lambda x: {
19
19
  'GC_GRACE_SECONDS': ps
20
20
  },
21
+ 'table-props-value': lambda x: {'GC_GRACE_SECONDS': ps}[x],
21
22
  'export-database-types': lambda x: ['athena', 'sqlite', 'csv'],
22
23
  'export-databases': lambda x: ExportDatabases.database_names(),
23
24
  'export-sessions': lambda x: ExportSessions.export_session_names(state.sts, state.pod, state.namespace),
@@ -55,7 +55,7 @@ def table_spec(state: ReplState, table: str, on_any=False) -> 'TableSpec':
55
55
 
56
56
  return parse_cql_desc_table(r.stdout if state.pod else r[0].stdout)
57
57
 
58
- def run_cql(state: ReplState, cql: str, opts: list = [], show_out = False, show_query = False, use_single_quotes = False, on_any = False, backgrounded=False, log_file=None) -> list[PodExecResult]:
58
+ def run_cql(state: ReplState, cql: str, opts: list = [], show_out = False, show_query = False, use_single_quotes = False, on_any = False, backgrounded=False, log_file=None, via_sh=True) -> list[PodExecResult]:
59
59
  if show_query:
60
60
  log2(cql)
61
61
 
@@ -69,7 +69,7 @@ def run_cql(state: ReplState, cql: str, opts: list = [], show_out = False, show_
69
69
 
70
70
  with log_timing(cql):
71
71
  with cassandra(state) as pods:
72
- return pods.exec(command, action='cql', show_out=show_out, on_any=on_any, backgrounded=backgrounded, log_file=log_file)
72
+ return pods.exec(command, action='cql', show_out=show_out, on_any=on_any, backgrounded=backgrounded, log_file=log_file, via_sh=via_sh)
73
73
 
74
74
  def parse_cql_desc_tables(out: str):
75
75
  # Keyspace data_endpoint_auth
@@ -227,16 +227,16 @@ class CassandraPodService:
227
227
  def __init__(self, handler: 'CassandraExecHandler'):
228
228
  self.handler = handler
229
229
 
230
- def exec(self, command: str, action='bash', show_out = True, on_any = False, throw_err = False, shell = '/bin/sh', backgrounded = False, log_file = None) -> Union[PodExecResult, list[PodExecResult]]:
230
+ def exec(self, command: str, action='bash', show_out = True, on_any = False, throw_err = False, shell = '/bin/sh', backgrounded = False, log_file = None, via_sh = True) -> Union[PodExecResult, list[PodExecResult]]:
231
231
  state = self.handler.state
232
232
  pod = self.handler.pod
233
233
 
234
234
  if pod:
235
235
  return CassandraNodes.exec(pod, state.namespace, command,
236
- show_out=show_out, throw_err=throw_err, shell=shell, backgrounded=backgrounded, log_file=log_file)
236
+ show_out=show_out, throw_err=throw_err, shell=shell, backgrounded=backgrounded, log_file=log_file, via_sh=via_sh)
237
237
  elif state.sts:
238
238
  return CassandraClusters.exec(state.sts, state.namespace, command, action=action,
239
- show_out=show_out, on_any=on_any, shell=shell, backgrounded=backgrounded, log_file=log_file)
239
+ show_out=show_out, on_any=on_any, shell=shell, backgrounded=backgrounded, log_file=log_file, via_sh=via_sh)
240
240
 
241
241
  return []
242
242
 
File without changes
@@ -0,0 +1,22 @@
1
+ from adam.commands.command import Command
2
+ from adam.commands.debug.debug_completes import DebugCompletes
3
+ from adam.commands.debug.debug_timings import DebugTimings
4
+ from adam.commands.intermediate_command import IntermediateCommand
5
+
6
+ class Debug(IntermediateCommand):
7
+ COMMAND = 'debug'
8
+
9
+ # the singleton pattern
10
+ def __new__(cls, *args, **kwargs):
11
+ if not hasattr(cls, 'instance'): cls.instance = super(Debug, cls).__new__(cls)
12
+
13
+ return cls.instance
14
+
15
+ def __init__(self, successor: Command=None):
16
+ super().__init__(successor)
17
+
18
+ def command(self):
19
+ return Debug.COMMAND
20
+
21
+ def cmd_list(self):
22
+ return [DebugTimings(), DebugCompletes()]
@@ -0,0 +1,35 @@
1
+ from adam.commands import validate_args
2
+ from adam.commands.command import Command
3
+ from adam.config import Config
4
+ from adam.repl_state import ReplState
5
+
6
+ class DebugCompletes(Command):
7
+ COMMAND = 'debug completes'
8
+
9
+ # the singleton pattern
10
+ def __new__(cls, *args, **kwargs):
11
+ if not hasattr(cls, 'instance'): cls.instance = super(DebugCompletes, cls).__new__(cls)
12
+
13
+ return cls.instance
14
+
15
+ def __init__(self, successor: Command=None):
16
+ super().__init__(successor)
17
+
18
+ def command(self):
19
+ return DebugCompletes.COMMAND
20
+
21
+ def run(self, cmd: str, state: ReplState):
22
+ if not(args := self.args(cmd)):
23
+ return super().run(cmd, state)
24
+
25
+ with self.validate(args, state) as (args, state):
26
+ with validate_args(args, state, name='on, off or file') as args:
27
+ Config().set('debugs.complete', args)
28
+
29
+ return state
30
+
31
+ def completion(self, state: ReplState):
32
+ return super().completion(state, {f: None for f in ['on', 'off', 'file']})
33
+
34
+ def help(self, _: ReplState):
35
+ return f'{DebugCompletes.COMMAND} on|off|file\t turn auto complete debug on or off'
@@ -0,0 +1,35 @@
1
+ from adam.commands import validate_args
2
+ from adam.commands.command import Command
3
+ from adam.config import Config
4
+ from adam.repl_state import ReplState
5
+
6
+ class DebugTimings(Command):
7
+ COMMAND = 'debug timings'
8
+
9
+ # the singleton pattern
10
+ def __new__(cls, *args, **kwargs):
11
+ if not hasattr(cls, 'instance'): cls.instance = super(DebugTimings, cls).__new__(cls)
12
+
13
+ return cls.instance
14
+
15
+ def __init__(self, successor: Command=None):
16
+ super().__init__(successor)
17
+
18
+ def command(self):
19
+ return DebugTimings.COMMAND
20
+
21
+ def run(self, cmd: str, state: ReplState):
22
+ if not(args := self.args(cmd)):
23
+ return super().run(cmd, state)
24
+
25
+ with self.validate(args, state) as (args, state):
26
+ with validate_args(args, state, name='on, off or file') as args:
27
+ Config().set('debugs.timings', args)
28
+
29
+ return state
30
+
31
+ def completion(self, state: ReplState):
32
+ return super().completion(state, {f: None for f in ['on', 'off', 'file']})
33
+
34
+ def help(self, _: ReplState):
35
+ return f'{DebugTimings.COMMAND} on|off|file\t turn timing debug on or off'
@@ -7,7 +7,7 @@ from adam.commands.devices.device_postgres import DevicePostgres
7
7
  from adam.repl_state import ReplState
8
8
 
9
9
  class Devices:
10
- def device(state: ReplState) -> Device:
10
+ def of(state: ReplState) -> Device:
11
11
  if state.device == ReplState.A:
12
12
  return DeviceApp()
13
13
  elif state.device == ReplState.C:
@@ -0,0 +1,45 @@
1
+ from adam.commands.command import Command
2
+ from adam.commands.devices.devices import Devices
3
+ from adam.config import Config
4
+ from adam.pod_exec_result import PodExecResult
5
+ from adam.utils import log2
6
+ from adam.utils_k8s.cassandra_nodes import CassandraNodes
7
+ from adam.repl_state import ReplState, RequiredState
8
+ from adam.utils_k8s.pods import Pods
9
+
10
+ class DownloadCassandraLog(Command):
11
+ COMMAND = 'download cassandra log'
12
+
13
+ # the singleton pattern
14
+ def __new__(cls, *args, **kwargs):
15
+ if not hasattr(cls, 'instance'): cls.instance = super(DownloadCassandraLog, cls).__new__(cls)
16
+
17
+ return cls.instance
18
+
19
+ def __init__(self, successor: Command=None):
20
+ super().__init__(successor)
21
+
22
+ def command(self):
23
+ return DownloadCassandraLog.COMMAND
24
+
25
+ def required(self):
26
+ return RequiredState.POD
27
+
28
+ def run(self, cmd: str, state: ReplState):
29
+ if not(args := self.args(cmd)):
30
+ return super().run(cmd, state)
31
+
32
+ with self.validate(args, state) as (args, state):
33
+ path = Config().get('logs.path', '/c3/cassandra/logs/system.log')
34
+ r: PodExecResult = CassandraNodes.exec(state.pod, state.namespace, f'cat {path}', backgrounded=True, no_history=True)
35
+
36
+ to_file = Pods.download_file(state.pod, 'cassandra', state.namespace, path)
37
+ log2(f'Downloaded to {to_file}.')
38
+
39
+ return r
40
+
41
+ def completion(self, state: ReplState):
42
+ return super().completion(state, pods=Devices.of(state).pods(state, '-'), auto='jit')
43
+
44
+ def help(self, _: ReplState):
45
+ return f'{DownloadCassandraLog.COMMAND}\t download cassandra system log'
@@ -31,8 +31,8 @@ class DownloadFile(Command):
31
31
 
32
32
  with self.validate(args, state) as (args, state):
33
33
  with validate_args(args, state, name='file'):
34
- to_file = Pods.download_file(Devices.device(state).pod(state),
35
- Devices.device(state).default_container(state),
34
+ to_file = Pods.download_file(Devices.of(state).pod(state),
35
+ Devices.of(state).default_container(state),
36
36
  state.namespace,
37
37
  args[0],
38
38
  args[1] if len(args) > 1 else None)
@@ -41,7 +41,7 @@ class DownloadFile(Command):
41
41
  return state
42
42
 
43
43
  def completion(self, state: ReplState):
44
- return super().completion(state, lambda: {f: None for f in Devices.device(state).files(state)}, pods=Devices.device(state).pods(state, '-'), auto='jit')
44
+ return super().completion(state, lambda: {f: None for f in Devices.of(state).files(state)}, pods=Devices.of(state).pods(state, '-'), auto='jit')
45
45
 
46
46
  def help(self, _: ReplState):
47
47
  return f'{DownloadFile.COMMAND} from-file [to-file]\t download file from pod'
@@ -42,7 +42,7 @@ class ExportSessions:
42
42
  return {}
43
43
 
44
44
  for log_file in log_files[:limit]:
45
- m = re.match(f'{log_prefix()}-(.*?)_.*\.log?(.*)', log_file)
45
+ m = re.match(f'{log_prefix()}-([ces].*?)_.*\.log?(.*)', log_file)
46
46
  if m:
47
47
  s = m.group(1)
48
48
  state = m.group(2) # '', '.pending_import', '.done'
@@ -221,7 +221,7 @@ class Exporter:
221
221
  queries.append(f"COPY {spec.keyspace}.{table}({columns}) TO '{csv_file}' WITH HEADER = TRUE")
222
222
  r: PodExecResult = ing(
223
223
  f'[{session}] Dumping table {spec.keyspace}.{table}{f" with consistency {consistency}" if consistency else ""}',
224
- lambda: run_cql(state, ';'.join(queries), show_out=Config().is_debug(), backgrounded=True, log_file=log_file),
224
+ lambda: run_cql(state, ';'.join(queries), show_out=Config().is_debug(), backgrounded=True, log_file=log_file, via_sh=False),
225
225
  suppress_log=suppress_ing_log)
226
226
 
227
227
  return log_file
@@ -32,7 +32,7 @@ class FindProcesses(Command):
32
32
  with validate_args(args, state, name='words to look for'):
33
33
  arg = ' | '.join([f'grep {a}' for a in args])
34
34
  awk = "awk '{ print $1, $2, $8, $NF }'"
35
- rs = Devices.device(state).bash(state, state, f"ps -ef | grep -v grep | {arg} | {awk}".split(' '))
35
+ rs = Devices.of(state).bash(state, state, f"ps -ef | grep -v grep | {arg} | {awk}".split(' '))
36
36
 
37
37
  lines: list[list[str]] = []
38
38
  for r in rs:
@@ -65,7 +65,7 @@ class FindProcesses(Command):
65
65
  log2(f'@{pod} bash kill -9 {pid}')
66
66
 
67
67
  with state_with_pod(state, pod) as state1:
68
- Devices.device(state).bash(state, state1, ['kill', '-9', pid])
68
+ Devices.of(state).bash(state, state1, ['kill', '-9', pid])
69
69
 
70
70
  return rs
71
71
 
@@ -0,0 +1,52 @@
1
+ import click
2
+ import json
3
+
4
+ from adam.checks.check_result import CheckResult
5
+ from adam.checks.check_utils import run_checks
6
+ from adam.commands import extract_options
7
+ from adam.commands.command import Command
8
+ from adam.commands.commands_utils import kaqing_log_file
9
+ from adam.repl_state import ReplState
10
+ from adam.utils import log2
11
+
12
+ class GenerateReport(Command):
13
+ COMMAND = 'generate report'
14
+
15
+ # the singleton pattern
16
+ def __new__(cls, *args, **kwargs):
17
+ if not hasattr(cls, 'instance'): cls.instance = super(GenerateReport, cls).__new__(cls)
18
+
19
+ return cls.instance
20
+
21
+ def __init__(self, successor: Command=None):
22
+ super().__init__(successor)
23
+
24
+ def command(self):
25
+ return GenerateReport.COMMAND
26
+
27
+ def required(self):
28
+ return ReplState.NON_L
29
+
30
+ def run(self, cmd: str, state: ReplState):
31
+ if not(args := self.args(cmd)):
32
+ return super().run(cmd, state)
33
+
34
+ with self.validate(args, state) as (args, state):
35
+ with extract_options(args, ['-s', '--show']) as (args, show_out):
36
+ results = run_checks(state.sts, state.namespace, state.pod, show_out=show_out)
37
+ output = CheckResult.report(results)
38
+
39
+ if state.in_repl:
40
+ with kaqing_log_file() as json_file:
41
+ json.dump(output, json_file, indent=2)
42
+ log2(f'Report stored in {json_file.name}.')
43
+ else:
44
+ click.echo(json.dumps(output, indent=2))
45
+
46
+ return output
47
+
48
+ def completion(self, state: ReplState):
49
+ return super().completion(state, {'-s': None})
50
+
51
+ def help(self, _: ReplState):
52
+ return f"{GenerateReport.COMMAND} [-s]\t generate report"
adam/commands/head.py CHANGED
@@ -27,10 +27,10 @@ class Head(Command):
27
27
 
28
28
  with self.validate(args, state) as (args, state):
29
29
  with validate_args(args, state, name='file'):
30
- return Devices.device(state).bash(state, state, cmd.split(' '))
30
+ return Devices.of(state).bash(state, state, cmd.split(' '))
31
31
 
32
32
  def completion(self, state: ReplState):
33
- return super().completion(state, lambda: {f: None for f in Devices.device(state).files(state)}, pods=Devices.device(state).pods(state, '-'), auto='jit')
33
+ return super().completion(state, lambda: {f: None for f in Devices.of(state).files(state)}, pods=Devices.of(state).pods(state, '-'), auto='jit')
34
34
 
35
35
  def help(self, _: ReplState):
36
36
  return f'{Head.COMMAND} file [&]\t run head command on the pod'
adam/commands/ls.py CHANGED
@@ -30,12 +30,12 @@ class Ls(Command):
30
30
  state = copy.copy(state)
31
31
  state.device = arg.replace(':', '')
32
32
 
33
- Devices.device(state).ls(cmd, state)
33
+ Devices.of(state).ls(cmd, state)
34
34
 
35
35
  return state
36
36
 
37
37
  def completion(self, state: ReplState):
38
- return super().completion(state, {'&': None}, pods=Devices.device(state).pods(state, '-'))
38
+ return super().completion(state, {'&': None}, pods=Devices.of(state).pods(state, '-'))
39
39
 
40
40
  def help(self, _: ReplState):
41
41
  return f'{Ls.COMMAND} [device:]\t list apps, envs, clusters, nodes, pg hosts/databases or export databases'
@@ -1,4 +1,3 @@
1
- from collections.abc import Callable
2
1
  from datetime import datetime
3
2
  from functools import partial
4
3
 
@@ -8,7 +7,6 @@ from adam.commands.medusa.utils_medusa import medusa_backup_names
8
7
  from adam.utils_k8s.statefulsets import StatefulSets
9
8
  from adam.repl_state import ReplState, RequiredState
10
9
  from adam.utils_k8s.custom_resources import CustomResources
11
- from adam.config import Config
12
10
  from adam.utils import tabulize, log2, log_exc
13
11
 
14
12
  class MedusaRestore(Command):
@@ -69,20 +67,6 @@ class MedusaRestore(Command):
69
67
 
70
68
  def completion(self, state: ReplState):
71
69
  return super().completion(state, lambda: {id: None for id in medusa_backup_names(state)}, auto_key='medusa.backups')
72
- # if sc := super().completion(state):
73
- # ns = state.namespace
74
- # dc: str = StatefulSets.get_datacenter(state.sts, ns)
75
- # if not dc:
76
- # return {}
77
-
78
- # if Config().get('medusa.restore-auto-complete', False):
79
- # leaf = {id: None for id in [f"{x['metadata']['name']}" for x in CustomResources.medusa_show_backupjobs(dc, ns)]}
80
-
81
- # return super().completion(state, leaf)
82
- # else:
83
- # return sc
84
-
85
- return {}
86
70
 
87
71
  def help(self, _: ReplState):
88
72
  return f'{MedusaRestore.COMMAND}\t start a restore job'
adam/commands/nodetool.py CHANGED
@@ -38,7 +38,7 @@ class NodeTool(Command):
38
38
  return state
39
39
 
40
40
  def completion(self, state: ReplState):
41
- return super().completion(state, {c: {'&': None} for c in NODETOOL_COMMANDS}, pods=Devices.device(state).pods(state, '-'))
41
+ return super().completion(state, {c: {'&': None} for c in NODETOOL_COMMANDS}, pods=Devices.of(state).pods(state, '-'))
42
42
 
43
43
  def help(self, _: ReplState):
44
44
  return f'{NodeTool.COMMAND} <sub-command> [&]\t run nodetool with arguments'
File without changes
@@ -0,0 +1,36 @@
1
+ from adam.commands import validate_args
2
+ from adam.commands.command import Command
3
+ from adam.commands.devices.devices import Devices
4
+ from adam.repl_state import ReplState, RequiredState
5
+
6
+ class Cat(Command):
7
+ COMMAND = 'cat'
8
+
9
+ # the singleton pattern
10
+ def __new__(cls, *args, **kwargs):
11
+ if not hasattr(cls, 'instance'): cls.instance = super(Cat, cls).__new__(cls)
12
+
13
+ return cls.instance
14
+
15
+ def __init__(self, successor: Command=None):
16
+ super().__init__(successor)
17
+
18
+ def command(self):
19
+ return Cat.COMMAND
20
+
21
+ def required(self):
22
+ return [RequiredState.CLUSTER_OR_POD, RequiredState.APP_APP, ReplState.P]
23
+
24
+ def run(self, cmd: str, state: ReplState):
25
+ if not(args := self.args(cmd)):
26
+ return super().run(cmd, state)
27
+
28
+ with self.validate(args, state) as (args, state):
29
+ with validate_args(args, state, name='file'):
30
+ return Devices.of(state).bash(state, state, cmd.split(' '))
31
+
32
+ def completion(self, state: ReplState):
33
+ return super().completion(state, lambda: {f: None for f in Devices.of(state).files(state)}, pods=Devices.of(state).pods(state, '-'), auto='jit')
34
+
35
+ def help(self, _: ReplState):
36
+ return f'{Cat.COMMAND} file [&]\t run cat command on the pod'
@@ -0,0 +1,47 @@
1
+ from adam.commands import validate_args
2
+ from adam.commands.command import Command
3
+ from adam.commands.devices.devices import Devices
4
+ from adam.config import Config
5
+ from adam.pod_exec_result import PodExecResult
6
+ from adam.repl_state import ReplState, RequiredState
7
+ from adam.utils import log2
8
+ from adam.utils_k8s.pods import Pods
9
+
10
+ class DownloadFile(Command):
11
+ COMMAND = 'download file'
12
+
13
+ # the singleton pattern
14
+ def __new__(cls, *args, **kwargs):
15
+ if not hasattr(cls, 'instance'): cls.instance = super(DownloadFile, cls).__new__(cls)
16
+
17
+ return cls.instance
18
+
19
+ def __init__(self, successor: Command=None):
20
+ super().__init__(successor)
21
+
22
+ def command(self):
23
+ return DownloadFile.COMMAND
24
+
25
+ def required(self):
26
+ return [RequiredState.CLUSTER_OR_POD, RequiredState.APP_APP, ReplState.P]
27
+
28
+ def run(self, cmd: str, state: ReplState):
29
+ if not(args := self.args(cmd)):
30
+ return super().run(cmd, state)
31
+
32
+ with self.validate(args, state) as (args, state):
33
+ with validate_args(args, state, name='file'):
34
+ to_file = Pods.download_file(Devices.of(state).pod(state),
35
+ Devices.of(state).default_container(state),
36
+ state.namespace,
37
+ args[0],
38
+ args[1] if len(args) > 1 else None)
39
+ log2(f'Downloaded to {to_file}.')
40
+
41
+ return state
42
+
43
+ def completion(self, state: ReplState):
44
+ return super().completion(state, lambda: {f: None for f in Devices.of(state).files(state)}, pods=Devices.of(state).pods(state, '-'), auto='jit')
45
+
46
+ def help(self, _: ReplState):
47
+ return f'{DownloadFile.COMMAND} from-file [to-file]\t download file from pod'
@@ -0,0 +1,51 @@
1
+ import os
2
+
3
+ from adam.commands.command import Command
4
+ from adam.repl_state import ReplState
5
+ from adam.utils import log2
6
+ from adam.utils_local import local_tmp_dir
7
+
8
+ class FindLocalFiles(Command):
9
+ COMMAND = 'find local'
10
+
11
+ # the singleton pattern
12
+ def __new__(cls, *args, **kwargs):
13
+ if not hasattr(cls, 'instance'): cls.instance = super(FindLocalFiles, cls).__new__(cls)
14
+
15
+ return cls.instance
16
+
17
+ def __init__(self, successor: Command=None):
18
+ super().__init__(successor)
19
+
20
+ def command(self):
21
+ return FindLocalFiles.COMMAND
22
+
23
+ def run(self, cmd: str, state: ReplState):
24
+ if not(args := self.args(cmd)):
25
+ return super().run(cmd, state)
26
+
27
+ with self.validate(args, state) as (args, state):
28
+ cmd = 'find'
29
+
30
+ if not args:
31
+ cmd = f'find {local_tmp_dir()}'
32
+ elif len(args) == 1:
33
+ cmd = f"find {local_tmp_dir()} -name '{args[0]}'"
34
+ else:
35
+ new_args = [f"'{arg}'" if '*' in arg else arg for arg in args]
36
+ cmd = 'find ' + ' '.join(new_args)
37
+
38
+ log2(cmd)
39
+ os.system(cmd)
40
+
41
+ return state
42
+
43
+ def completion(self, state: ReplState):
44
+ return super().completion(state, {
45
+ '*.csv': None,
46
+ '*.db': None,
47
+ '*': None
48
+ })
49
+
50
+ def help(self, _: ReplState):
51
+ return f'{FindLocalFiles.COMMAND} [linux-find-arguments]\t find files from local machine'