kaqing 2.0.184__py3-none-any.whl → 2.0.214__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 (152) hide show
  1. adam/app_session.py +1 -1
  2. adam/batch.py +15 -15
  3. adam/commands/app/app.py +2 -2
  4. adam/commands/app/show_app_actions.py +1 -1
  5. adam/commands/{show → app}/show_login.py +1 -1
  6. adam/commands/app/utils_app.py +9 -1
  7. adam/commands/audit/audit.py +6 -20
  8. adam/commands/audit/audit_repair_tables.py +1 -1
  9. adam/commands/audit/audit_run.py +1 -1
  10. adam/commands/audit/completions_l.py +15 -0
  11. adam/commands/audit/show_last10.py +0 -1
  12. adam/commands/bash/bash.py +1 -1
  13. adam/commands/bash/utils_bash.py +1 -1
  14. adam/commands/cassandra/download_cassandra_log.py +45 -0
  15. adam/commands/cassandra/restart_cluster.py +47 -0
  16. adam/commands/cassandra/restart_node.py +51 -0
  17. adam/commands/cassandra/restart_nodes.py +47 -0
  18. adam/commands/{rollout.py → cassandra/rollout.py} +1 -1
  19. adam/commands/{show → cassandra}/show_cassandra_repairs.py +5 -3
  20. adam/commands/{show → cassandra}/show_cassandra_status.py +22 -15
  21. adam/commands/cassandra/show_processes.py +50 -0
  22. adam/commands/{show → cassandra}/show_storage.py +10 -8
  23. adam/commands/cli/__init__.py +0 -0
  24. adam/commands/{cli_commands.py → cli/cli_commands.py} +6 -1
  25. adam/commands/{clipboard_copy.py → cli/clipboard_copy.py} +2 -2
  26. adam/commands/{show/show_commands.py → cli/show_cli_commands.py} +2 -2
  27. adam/commands/command.py +22 -9
  28. adam/commands/commands_utils.py +14 -6
  29. adam/commands/config/__init__.py +0 -0
  30. adam/commands/{show → config}/show_params.py +1 -1
  31. adam/commands/{alter_tables.py → cql/alter_tables.py} +1 -1
  32. adam/commands/cql/completions_c.py +29 -0
  33. adam/commands/cql/cqlsh.py +2 -6
  34. adam/commands/cql/utils_cql.py +26 -17
  35. adam/commands/debug/__init__.py +0 -0
  36. adam/commands/debug/debug.py +22 -0
  37. adam/commands/debug/debug_completes.py +35 -0
  38. adam/commands/debug/debug_timings.py +35 -0
  39. adam/commands/debug/show_offloaded_completes.py +45 -0
  40. adam/commands/devices/device.py +30 -4
  41. adam/commands/devices/device_app.py +1 -1
  42. adam/commands/devices/device_export.py +5 -2
  43. adam/commands/devices/device_postgres.py +13 -3
  44. adam/commands/devices/devices.py +1 -1
  45. adam/commands/diag/__init__.py +0 -0
  46. adam/commands/{check.py → diag/check.py} +1 -1
  47. adam/commands/diag/generate_report.py +52 -0
  48. adam/commands/export/completions_x.py +11 -0
  49. adam/commands/export/download_export_session.py +2 -1
  50. adam/commands/export/export.py +0 -16
  51. adam/commands/export/export_databases.py +16 -10
  52. adam/commands/export/export_select.py +8 -33
  53. adam/commands/export/export_sessions.py +12 -11
  54. adam/commands/export/export_use.py +3 -3
  55. adam/commands/export/export_x_select.py +48 -0
  56. adam/commands/export/exporter.py +140 -53
  57. adam/commands/export/import_files.py +2 -2
  58. adam/commands/export/import_session.py +0 -4
  59. adam/commands/export/importer.py +11 -11
  60. adam/commands/export/importer_athena.py +15 -35
  61. adam/commands/export/importer_sqlite.py +19 -8
  62. adam/commands/export/show_column_counts.py +10 -10
  63. adam/commands/export/show_export_databases.py +2 -1
  64. adam/commands/export/show_export_session.py +1 -1
  65. adam/commands/export/show_export_sessions.py +1 -1
  66. adam/commands/export/utils_export.py +38 -15
  67. adam/commands/fs/__init__.py +0 -0
  68. adam/commands/{cat.py → fs/cat.py} +2 -2
  69. adam/commands/fs/cat_local.py +42 -0
  70. adam/commands/{cd.py → fs/cd.py} +2 -2
  71. adam/commands/{download_file.py → fs/download_file.py} +5 -5
  72. adam/commands/{find_files.py → fs/find_files.py} +4 -4
  73. adam/commands/{find_processes.py → fs/find_processes.py} +3 -3
  74. adam/commands/{head.py → fs/head.py} +2 -2
  75. adam/commands/{ls.py → fs/ls.py} +2 -2
  76. adam/commands/fs/ls_local.py +40 -0
  77. adam/commands/fs/rm.py +18 -0
  78. adam/commands/fs/rm_downloads.py +39 -0
  79. adam/commands/fs/rm_logs.py +38 -0
  80. adam/commands/{show → fs}/show_adam.py +1 -1
  81. adam/commands/intermediate_command.py +3 -0
  82. adam/commands/medusa/medusa_restore.py +2 -16
  83. adam/commands/medusa/utils_medusa.py +15 -0
  84. adam/commands/nodetool/__init__.py +0 -0
  85. adam/commands/{nodetool.py → nodetool/nodetool.py} +3 -8
  86. adam/commands/postgres/completions_p.py +22 -0
  87. adam/commands/postgres/postgres.py +7 -14
  88. adam/commands/postgres/postgres_databases.py +3 -3
  89. adam/commands/postgres/postgres_ls.py +1 -1
  90. adam/commands/postgres/utils_postgres.py +12 -2
  91. adam/commands/preview_table.py +1 -1
  92. adam/commands/reaper/reaper_schedule_activate.py +6 -2
  93. adam/commands/reaper/reaper_schedule_start.py +1 -2
  94. adam/commands/reaper/reaper_schedule_stop.py +1 -2
  95. adam/commands/reaper/utils_reaper.py +10 -1
  96. adam/commands/repair/repair_scan.py +0 -2
  97. adam/commands/repair/repair_stop.py +0 -1
  98. adam/commands/{show/show.py → show.py} +12 -11
  99. adam/config.py +4 -5
  100. adam/embedded_params.py +1 -1
  101. adam/repl.py +22 -9
  102. adam/repl_commands.py +50 -42
  103. adam/repl_session.py +9 -1
  104. adam/repl_state.py +16 -1
  105. adam/sql/async_executor.py +62 -0
  106. adam/sql/lark_completer.py +286 -0
  107. adam/sql/lark_parser.py +604 -0
  108. adam/sql/qingl.lark +1076 -0
  109. adam/sso/cred_cache.py +2 -5
  110. adam/utils.py +216 -79
  111. adam/utils_k8s/app_clusters.py +11 -4
  112. adam/utils_k8s/app_pods.py +10 -5
  113. adam/utils_k8s/cassandra_clusters.py +8 -4
  114. adam/utils_k8s/cassandra_nodes.py +14 -5
  115. adam/utils_k8s/k8s.py +9 -0
  116. adam/utils_k8s/kube_context.py +1 -4
  117. adam/{pod_exec_result.py → utils_k8s/pod_exec_result.py} +8 -2
  118. adam/utils_k8s/pods.py +83 -24
  119. adam/utils_k8s/statefulsets.py +5 -2
  120. adam/utils_local.py +78 -2
  121. adam/utils_repl/appendable_completer.py +6 -0
  122. adam/utils_repl/repl_completer.py +51 -4
  123. adam/utils_sqlite.py +3 -8
  124. adam/version.py +1 -1
  125. {kaqing-2.0.184.dist-info → kaqing-2.0.214.dist-info}/METADATA +1 -1
  126. kaqing-2.0.214.dist-info/RECORD +272 -0
  127. kaqing-2.0.214.dist-info/top_level.txt +2 -0
  128. teddy/__init__.py +0 -0
  129. teddy/lark_parser.py +436 -0
  130. teddy/lark_parser2.py +618 -0
  131. adam/commands/cql/cql_completions.py +0 -32
  132. adam/commands/export/export_select_x.py +0 -54
  133. adam/commands/logs.py +0 -37
  134. adam/commands/postgres/psql_completions.py +0 -11
  135. adam/commands/report.py +0 -61
  136. adam/commands/restart.py +0 -60
  137. adam/commands/show/show_processes.py +0 -49
  138. kaqing-2.0.184.dist-info/RECORD +0 -244
  139. kaqing-2.0.184.dist-info/top_level.txt +0 -1
  140. /adam/commands/{login.py → app/login.py} +0 -0
  141. /adam/commands/{show → cassandra}/__init__.py +0 -0
  142. /adam/commands/{show → cassandra}/show_cassandra_version.py +0 -0
  143. /adam/commands/{watch.py → cassandra/watch.py} +0 -0
  144. /adam/commands/{param_get.py → config/param_get.py} +0 -0
  145. /adam/commands/{param_set.py → config/param_set.py} +0 -0
  146. /adam/commands/{issues.py → diag/issues.py} +0 -0
  147. /adam/commands/{pwd.py → fs/pwd.py} +0 -0
  148. /adam/commands/{shell.py → fs/shell.py} +0 -0
  149. /adam/commands/{show → fs}/show_host.py +0 -0
  150. /adam/commands/{nodetool_commands.py → nodetool/nodetool_commands.py} +0 -0
  151. {kaqing-2.0.184.dist-info → kaqing-2.0.214.dist-info}/WHEEL +0 -0
  152. {kaqing-2.0.184.dist-info → kaqing-2.0.214.dist-info}/entry_points.txt +0 -0
@@ -1,12 +1,13 @@
1
1
  import io
2
+ import os
2
3
  import re
3
4
 
4
5
  from adam.config import Config
5
- from adam.pod_exec_result import PodExecResult
6
+ from adam.utils import ExecResult, creating_dir, log2
6
7
  from adam.repl_state import ReplState
7
8
  from adam.utils_k8s.cassandra_nodes import CassandraNodes
8
- from adam.utils_k8s.pods import log_prefix
9
9
  from adam.utils_k8s.statefulsets import StatefulSets
10
+ from adam.utils_local import local_exec
10
11
 
11
12
  class ImportSpec:
12
13
  def __init__(self, table_name: str, session: str = None, files: list[str] = None, importer: str = None):
@@ -196,7 +197,7 @@ class ExportTableStatus:
196
197
  statuses: list[ExportTableStatus] = []
197
198
 
198
199
  status_in_whole = 'done'
199
- log_files: list[str] = find_files(pod, namespace, f'{log_prefix()}-{export_session}_*.log*')
200
+ log_files: list[str] = find_files(pod, namespace, f'{export_log_dir()}/{export_session}_*.log*')
200
201
 
201
202
  for log_file in log_files:
202
203
  status: ExportTableStatus = ExportTableStatus.from_log_file(pod, namespace, export_session, log_file)
@@ -211,7 +212,7 @@ class ExportTableStatus:
211
212
  def get_csv_files_n_table(target_table: str):
212
213
  db = f'{copy_session}_{target_table}'
213
214
  csv_file = f'{csv_dir()}/{db}/*.csv'
214
- csv_files: list[str] = find_files(pod, namespace, csv_file)
215
+ csv_files: list[str] = find_files(pod, namespace, csv_file, remote=True)
215
216
  if csv_files:
216
217
  table = target_table
217
218
  m = re.match(f'{csv_dir()}/{db}/(.*).csv', csv_files[0])
@@ -221,7 +222,7 @@ class ExportTableStatus:
221
222
 
222
223
  return csv_files, target_table
223
224
 
224
- m = re.match(f'{log_prefix()}-{copy_session}_(.*?)\.(.*?)\.log(.*)', log_file)
225
+ m = re.match(f'{export_log_dir()}/{copy_session}_(.*?)\.(.*?)\.log(.*)', log_file)
225
226
  if m:
226
227
  keyspace = m.group(1)
227
228
  target_table = m.group(2)
@@ -234,7 +235,8 @@ class ExportTableStatus:
234
235
 
235
236
  # 4 rows exported to 1 files in 0 day, 0 hour, 0 minute, and 1.335 seconds.
236
237
  pattern = 'rows exported to'
237
- r: PodExecResult = CassandraNodes.exec(pod, namespace, f"grep '{pattern}' {log_file}", show_out=Config().is_debug(), shell='bash')
238
+ r: ExecResult = local_exec(['grep', pattern, log_file], show_out=Config().is_debug())
239
+
238
240
  if r.exit_code() == 0:
239
241
  csv_files, table = get_csv_files_n_table(target_table)
240
242
  if csv_files:
@@ -246,17 +248,26 @@ class ExportTableStatus:
246
248
 
247
249
  return ExportTableStatus(None, None, 'unknown')
248
250
 
249
- def csv_dir():
250
- return Config().get('export.csv_dir', '/c3/cassandra/tmp')
251
-
252
- def find_files(pod: str, namespace: str, pattern: str, mmin: int = 0):
253
- if mmin:
254
- r = CassandraNodes.exec(pod, namespace, f'find {pattern} -mmin -{mmin}', show_out=Config().is_debug(), shell='bash')
251
+ def find_files(pod: str, namespace: str, pattern: str, mmin: int = 0, remote = False):
252
+ stdout = ''
253
+ if not remote:
254
+ # find . -maxdepth 1 -type f -name '*'
255
+ dir = os.path.dirname(pattern)
256
+ base = os.path.basename(pattern)
257
+ cmd = ['find', dir, '-name', base]
258
+ if mmin:
259
+ cmd += ['-mmin', f'-{mmin}']
260
+
261
+ stdout = local_exec(cmd, show_out=Config().is_debug()).stdout
255
262
  else:
256
- r = CassandraNodes.exec(pod, namespace, f'find {pattern}', show_out=Config().is_debug(), shell='bash')
263
+ cmd = f'find {pattern}'
264
+ if mmin:
265
+ cmd = f'{cmd} -mmin -{mmin}'
266
+
267
+ stdout = CassandraNodes.exec(pod, namespace, cmd, show_out=Config().is_debug(), shell='bash').stdout
257
268
 
258
269
  log_files = []
259
- for line in r.stdout.split('\n'):
270
+ for line in stdout.split('\n'):
260
271
  line = line.strip(' \r')
261
272
  if line:
262
273
  log_files.append(line)
@@ -325,6 +336,7 @@ class PodPushHandler:
325
336
  state = self.state
326
337
 
327
338
  if not state.pod:
339
+ self.pushed = True
328
340
  state.push()
329
341
 
330
342
  if not self.pod:
@@ -340,4 +352,15 @@ class PodPushHandler:
340
352
  return False
341
353
 
342
354
  def state_with_pod(state: ReplState, pod: str = None):
343
- return PodPushHandler(state, pod=pod)
355
+ return PodPushHandler(state, pod=pod)
356
+
357
+ def os_system_exec(cmd: str, show_out = False):
358
+ if show_out: log2(cmd)
359
+
360
+ os.system(cmd)
361
+
362
+ def csv_dir():
363
+ return Config().get('export.csv_dir', '/c3/cassandra/tmp')
364
+
365
+ def export_log_dir():
366
+ return creating_dir(Config().get('export.log-dir', '/tmp/qing-db/q/export/logs'))
File without changes
@@ -27,10 +27,10 @@ class Cat(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, pods=Devices.device(state).pods(state))
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'{Cat.COMMAND} file [&]\t run cat command on the pod'
@@ -0,0 +1,42 @@
1
+ import os
2
+
3
+ from adam.commands import validate_args
4
+ from adam.commands.command import Command
5
+ from adam.repl_state import ReplState, RequiredState
6
+ from adam.utils import log2
7
+ from adam.utils_local import find_local_files
8
+
9
+ class CatLocal(Command):
10
+ COMMAND = ':cat'
11
+
12
+ # the singleton pattern
13
+ def __new__(cls, *args, **kwargs):
14
+ if not hasattr(cls, 'instance'): cls.instance = super(CatLocal, cls).__new__(cls)
15
+
16
+ return cls.instance
17
+
18
+ def __init__(self, successor: Command=None):
19
+ super().__init__(successor)
20
+
21
+ def command(self):
22
+ return CatLocal.COMMAND
23
+
24
+ def required(self):
25
+ return [RequiredState.CLUSTER_OR_POD, RequiredState.APP_APP, ReplState.P]
26
+
27
+ def run(self, cmd: str, state: ReplState):
28
+ if not(args := self.args(cmd)):
29
+ return super().run(cmd, state)
30
+
31
+ with self.validate(args, state) as (args, state):
32
+ with validate_args(args, state, name='file') as args:
33
+ os.system(f'cat {args}')
34
+ log2()
35
+
36
+ return state
37
+
38
+ def completion(self, state: ReplState):
39
+ return super().completion(state, lambda: {n: None for n in find_local_files(file_type='f', max_depth=1)}, auto='jit')
40
+
41
+ def help(self, _: ReplState):
42
+ return f'{CatLocal.COMMAND} file\t run cat command on local system'
@@ -28,14 +28,14 @@ class Cd(Command):
28
28
 
29
29
  with self.validate(args, state, apply=False) as (args, state):
30
30
  with validate_args(args, state, name='directory') as arg_str:
31
- device: Device = Devices.device(state)
31
+ device: Device = Devices.of(state)
32
32
  for dir in arg_str.split('/'):
33
33
  device.cd(dir, state)
34
34
 
35
35
  return state
36
36
 
37
37
  def completion(self, state: ReplState):
38
- return Devices.device(state).cd_completion(Cd.COMMAND, state, default = {})
38
+ return Devices.of(state).cd_completion(Cd.COMMAND, state, default = {})
39
39
 
40
40
  def help(self, _: ReplState):
41
41
  return f'{Cd.COMMAND} <path> | .. \t move around on the operational device hierarchy'
@@ -1,6 +1,8 @@
1
1
  from adam.commands import validate_args
2
2
  from adam.commands.command import Command
3
3
  from adam.commands.devices.devices import Devices
4
+ from adam.config import Config
5
+ from adam.utils_k8s.pod_exec_result import PodExecResult
4
6
  from adam.repl_state import ReplState, RequiredState
5
7
  from adam.utils import log2
6
8
  from adam.utils_k8s.pods import Pods
@@ -29,8 +31,8 @@ class DownloadFile(Command):
29
31
 
30
32
  with self.validate(args, state) as (args, state):
31
33
  with validate_args(args, state, name='file'):
32
- to_file = Pods.download_file(state.pod,
33
- Devices.device(state).default_container(state),
34
+ to_file = Pods.download_file(Devices.of(state).pod(state),
35
+ Devices.of(state).default_container(state),
34
36
  state.namespace,
35
37
  args[0],
36
38
  args[1] if len(args) > 1 else None)
@@ -39,9 +41,7 @@ class DownloadFile(Command):
39
41
  return state
40
42
 
41
43
  def completion(self, state: ReplState):
42
- return super().completion(state, pods=Devices.device(state).pods(state))
43
-
44
- return {}
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'
@@ -3,10 +3,10 @@ import os
3
3
  from adam.commands.command import Command
4
4
  from adam.repl_state import ReplState
5
5
  from adam.utils import log2
6
- from adam.utils_local import local_tmp_dir
6
+ from adam.utils_local import local_qing_dir
7
7
 
8
8
  class FindLocalFiles(Command):
9
- COMMAND = 'find local'
9
+ COMMAND = ':find file'
10
10
 
11
11
  # the singleton pattern
12
12
  def __new__(cls, *args, **kwargs):
@@ -28,9 +28,9 @@ class FindLocalFiles(Command):
28
28
  cmd = 'find'
29
29
 
30
30
  if not args:
31
- cmd = f'find {local_tmp_dir()}'
31
+ cmd = f'find {local_qing_dir()}'
32
32
  elif len(args) == 1:
33
- cmd = f"find {local_tmp_dir()} -name '{args[0]}'"
33
+ cmd = f"find {local_qing_dir()} -name '{args[0]}'"
34
34
  else:
35
35
  new_args = [f"'{arg}'" if '*' in arg else arg for arg in args]
36
36
  cmd = 'find ' + ' '.join(new_args)
@@ -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:
@@ -62,10 +62,10 @@ class FindProcesses(Command):
62
62
 
63
63
  pod = pid_n_pod[1]
64
64
 
65
- log2(f'@{pod} kill -9 {pid}')
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
 
@@ -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, pods=Devices.device(state).pods(state))
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'
@@ -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 Devices.device(state).ls_completion(Ls.COMMAND, state, default = super().completion(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'
@@ -0,0 +1,40 @@
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_qing_dir
7
+
8
+ class LsLocal(Command):
9
+ COMMAND = ':ls'
10
+
11
+ # the singleton pattern
12
+ def __new__(cls, *args, **kwargs):
13
+ if not hasattr(cls, 'instance'): cls.instance = super(LsLocal, 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 LsLocal.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
+ if args:
29
+ os.system(f'ls {args}')
30
+ else:
31
+ os.system(f'ls {local_qing_dir()}')
32
+ log2()
33
+
34
+ return state
35
+
36
+ def completion(self, state: ReplState):
37
+ return super().completion(state)
38
+
39
+ def help(self, _: ReplState):
40
+ return f'{LsLocal.COMMAND} [dir]\t list files on local system'
adam/commands/fs/rm.py ADDED
@@ -0,0 +1,18 @@
1
+ from adam.commands.fs.rm_downloads import RmDownloads
2
+ from adam.commands.fs.rm_logs import RmLogs
3
+ from adam.commands.intermediate_command import IntermediateCommand
4
+
5
+ class RmLocal(IntermediateCommand):
6
+ COMMAND = ':rm'
7
+
8
+ # the singleton pattern
9
+ def __new__(cls, *args, **kwargs):
10
+ if not hasattr(cls, 'instance'): cls.instance = super(RmLocal, cls).__new__(cls)
11
+
12
+ return cls.instance
13
+
14
+ def command(self):
15
+ return RmLocal.COMMAND
16
+
17
+ def cmd_list(self):
18
+ return [RmDownloads(), RmLogs()]
@@ -0,0 +1,39 @@
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_downloads_dir
7
+
8
+ class RmDownloads(Command):
9
+ COMMAND = ':rm downloads'
10
+
11
+ # the singleton pattern
12
+ def __new__(cls, *args, **kwargs):
13
+ if not hasattr(cls, 'instance'): cls.instance = super(RmDownloads, 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 RmDownloads.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 = f'rm -rf {local_downloads_dir()}/*'
29
+ log2(cmd)
30
+ os.system(cmd)
31
+ log2()
32
+
33
+ return state
34
+
35
+ def completion(self, state: ReplState):
36
+ return super().completion(state)
37
+
38
+ def help(self, _: ReplState):
39
+ return f'{RmDownloads.COMMAND}\t remove all downloads files under {local_downloads_dir()}'
@@ -0,0 +1,38 @@
1
+ import os
2
+
3
+ from adam.commands.command import Command
4
+ from adam.repl_state import ReplState
5
+ from adam.utils import log2, log_dir
6
+
7
+ class RmLogs(Command):
8
+ COMMAND = ':rm logs'
9
+
10
+ # the singleton pattern
11
+ def __new__(cls, *args, **kwargs):
12
+ if not hasattr(cls, 'instance'): cls.instance = super(RmLogs, cls).__new__(cls)
13
+
14
+ return cls.instance
15
+
16
+ def __init__(self, successor: Command=None):
17
+ super().__init__(successor)
18
+
19
+ def command(self):
20
+ return RmLogs.COMMAND
21
+
22
+ def run(self, cmd: str, state: ReplState):
23
+ if not(args := self.args(cmd)):
24
+ return super().run(cmd, state)
25
+
26
+ with self.validate(args, state) as (args, state):
27
+ cmd = f'rm -rf {log_dir()}/*'
28
+ log2(cmd)
29
+ os.system(cmd)
30
+ log2()
31
+
32
+ return state
33
+
34
+ def completion(self, state: ReplState):
35
+ return super().completion(state)
36
+
37
+ def help(self, _: ReplState):
38
+ return f'{RmLogs.COMMAND}\t remove all qing log files under {log_dir()}'
@@ -1,7 +1,7 @@
1
1
  import sys
2
2
  import os
3
3
 
4
- from adam.utils import tabulize, log2
4
+ from adam.utils import tabulize
5
5
 
6
6
  current_dir = os.path.dirname(os.path.abspath(__file__))
7
7
 
@@ -12,6 +12,9 @@ class IntermediateCommand(Command):
12
12
 
13
13
  return self.intermediate_run(cmd, state, args, self.cmd_list())
14
14
 
15
+ def completion(self, state: ReplState):
16
+ return {}
17
+
15
18
  @abstractmethod
16
19
  def cmd_list(self):
17
20
  pass
@@ -1,13 +1,12 @@
1
- from collections.abc import Callable
2
1
  from datetime import datetime
3
2
  from functools import partial
4
3
 
5
4
  from adam.commands import validate_args
6
5
  from adam.commands.command import Command, InvalidArgumentsException
6
+ from adam.commands.medusa.utils_medusa import medusa_backup_names
7
7
  from adam.utils_k8s.statefulsets import StatefulSets
8
8
  from adam.repl_state import ReplState, RequiredState
9
9
  from adam.utils_k8s.custom_resources import CustomResources
10
- from adam.config import Config
11
10
  from adam.utils import tabulize, log2, log_exc
12
11
 
13
12
  class MedusaRestore(Command):
@@ -67,20 +66,7 @@ class MedusaRestore(Command):
67
66
  return state
68
67
 
69
68
  def completion(self, state: ReplState):
70
- if sc := super().completion(state):
71
- ns = state.namespace
72
- dc: str = StatefulSets.get_datacenter(state.sts, ns)
73
- if not dc:
74
- return {}
75
-
76
- if Config().get('medusa.restore-auto-complete', False):
77
- leaf = {id: None for id in [f"{x['metadata']['name']}" for x in CustomResources.medusa_show_backupjobs(dc, ns)]}
78
-
79
- return super().completion(state, leaf)
80
- else:
81
- return sc
82
-
83
- return {}
69
+ return super().completion(state, lambda: {id: None for id in medusa_backup_names(state)}, auto_key='medusa.backups')
84
70
 
85
71
  def help(self, _: ReplState):
86
72
  return f'{MedusaRestore.COMMAND}\t start a restore job'
@@ -0,0 +1,15 @@
1
+ from adam.config import Config
2
+ from adam.repl_state import ReplState
3
+ from adam.utils_k8s.custom_resources import CustomResources
4
+ from adam.utils_k8s.statefulsets import StatefulSets
5
+
6
+ def medusa_backup_names(state: ReplState, warm=False):
7
+ if warm and (auto := Config().get('medusa.restore-auto-complete', 'off')) in ['off', 'jit', 'lazy']:
8
+ return {}
9
+
10
+ ns = state.namespace
11
+ dc: str = StatefulSets.get_datacenter(state.sts, ns)
12
+ if not dc:
13
+ return {}
14
+
15
+ return {id: None for id in [f"{x['metadata']['name']}" for x in CustomResources.medusa_show_backupjobs(dc, ns)]}
File without changes
@@ -3,11 +3,11 @@ import click
3
3
  from adam.commands.command import Command
4
4
  from adam.commands.command_helpers import ClusterOrPodCommandHelper
5
5
  from adam.commands.cql.utils_cql import cassandra
6
- from adam.commands.nodetool_commands import NODETOOL_COMMANDS
6
+ from adam.commands.devices.devices import Devices
7
+ from adam.commands.nodetool.nodetool_commands import NODETOOL_COMMANDS
7
8
  from adam.config import Config
8
9
  from adam.repl_state import ReplState, RequiredState
9
10
  from adam.utils import log
10
- from adam.utils_k8s.statefulsets import StatefulSets
11
11
 
12
12
  class NodeTool(Command):
13
13
  COMMAND = 'nodetool'
@@ -38,12 +38,7 @@ class NodeTool(Command):
38
38
  return state
39
39
 
40
40
  def completion(self, state: ReplState):
41
- if super().completion(state):
42
- d = {c: {'&': None} for c in NODETOOL_COMMANDS}
43
- return {NodeTool.COMMAND: {'help': None} | d} | \
44
- {f'@{p}': {NodeTool.COMMAND: d} for p in StatefulSets.pod_names(state.sts, state.namespace)}
45
-
46
- return {}
41
+ return super().completion(state, {c: {'&': None} for c in NODETOOL_COMMANDS}, pods=Devices.of(state).pods(state, '-'))
47
42
 
48
43
  def help(self, _: ReplState):
49
44
  return f'{NodeTool.COMMAND} <sub-command> [&]\t run nodetool with arguments'
@@ -0,0 +1,22 @@
1
+ from adam.commands.postgres.postgres_databases import PostgresDatabases
2
+ from adam.commands.postgres.utils_postgres import pg_table_names
3
+ from adam.repl_state import ReplState
4
+ from adam.sql.lark_completer import LarkCompleter
5
+
6
+ def completions_p(state: ReplState):
7
+ return {
8
+ '\h': None,
9
+ '\d': None,
10
+ '\dt': None,
11
+ '\du': None
12
+ } | LarkCompleter(expandables={
13
+ 'tables': lambda x: pg_table_names(state),
14
+ 'columns': ['id'],
15
+ 'hosts': ['@' + PostgresDatabases.pod_and_container(state.namespace)[0]],
16
+ }, variant=ReplState.P).completions_for_nesting()
17
+
18
+ def psql0_completions(state: ReplState):
19
+ return {
20
+ '\h': None,
21
+ '\l': None,
22
+ }
@@ -4,12 +4,12 @@ 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.postgres_databases import pg_path
7
- from adam.commands.postgres.psql_completions import psql_completions
7
+ from adam.commands.postgres.completions_p import psql0_completions, completions_p
8
8
  from adam.commands.postgres.utils_postgres import pg_table_names, postgres
9
9
  from .postgres_ls import PostgresLs
10
10
  from .postgres_preview import PostgresPreview
11
11
  from adam.repl_state import ReplState
12
- from adam.utils import log, log2
12
+ from adam.utils import log, log2, log_timing
13
13
 
14
14
  class Postgres(IntermediateCommand):
15
15
  COMMAND = 'pg'
@@ -55,24 +55,17 @@ class Postgres(IntermediateCommand):
55
55
 
56
56
  def completion(self, state: ReplState):
57
57
  if state.device != state.P:
58
- # conflicts with cql completions
59
58
  return {}
60
59
 
61
- leaf = {}
62
60
  with pg_path(state) as (host, database):
63
61
  if database:
64
62
  if pg_table_names(state):
65
- leaf = psql_completions(state)
63
+ with log_timing('psql_completions'):
64
+ return completions_p(state)
66
65
  elif host:
67
- leaf = {
68
- '\h': None,
69
- '\l': None,
70
- }
71
-
72
- if state.pg_path:
73
- return super().completion(state, leaf) | leaf
74
- else:
75
- return {}
66
+ return psql0_completions(state)
67
+
68
+ return {}
76
69
 
77
70
  def help(self, _: ReplState):
78
71
  return f'<sql-statements> [&]\t run queries on Postgres databases'
@@ -144,12 +144,12 @@ class PostgresDatabases:
144
144
  env_prefix = f'PGPASSWORD="{password}"'
145
145
 
146
146
  r = Pods.exec(pod_name, container_name, state.namespace, cmd, show_out=show_out, backgrounded=backgrounded, env_prefix=env_prefix)
147
- if r and Config().get('repl.history.push-cat-remote-log-file', True):
148
- if r.log_file and ReplSession().prompt_session:
149
- ReplSession().prompt_session.history.append_string(f'@{r.pod} cat {r.log_file}')
147
+ if r and r.log_file:
148
+ ReplSession().append_history(f':cat {r.log_file}')
150
149
 
151
150
  return r
152
151
 
152
+ @functools.lru_cache()
153
153
  def pod_and_container(namespace: str):
154
154
  container_name = Config().get('pg.agent.name', 'ops-pg-agent')
155
155
 
@@ -1,5 +1,5 @@
1
1
  from adam.commands.command import Command
2
- from adam.commands.ls import Ls
2
+ from adam.commands.fs.ls import Ls
3
3
  from adam.repl_state import ReplState, RequiredState
4
4
 
5
5
  class PostgresLs(Command):