kaqing 2.0.98__py3-none-any.whl → 2.0.203__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.
Files changed (254) hide show
  1. adam/__init__.py +0 -2
  2. adam/app_session.py +9 -12
  3. adam/apps.py +18 -4
  4. adam/batch.py +11 -25
  5. adam/checks/check_utils.py +16 -46
  6. adam/checks/cpu.py +7 -1
  7. adam/checks/cpu_metrics.py +52 -0
  8. adam/checks/disk.py +2 -3
  9. adam/columns/columns.py +3 -1
  10. adam/columns/cpu.py +3 -1
  11. adam/columns/cpu_metrics.py +22 -0
  12. adam/columns/memory.py +3 -4
  13. adam/commands/__init__.py +24 -0
  14. adam/commands/alter_tables.py +37 -63
  15. adam/commands/app/app.py +38 -0
  16. adam/commands/{app_ping.py → app/app_ping.py} +8 -14
  17. adam/commands/app/show_app_actions.py +49 -0
  18. adam/commands/{show → app}/show_app_id.py +8 -11
  19. adam/commands/{show → app}/show_app_queues.py +8 -14
  20. adam/commands/app/utils_app.py +106 -0
  21. adam/commands/audit/audit.py +31 -35
  22. adam/commands/audit/audit_repair_tables.py +26 -48
  23. adam/commands/audit/audit_run.py +50 -0
  24. adam/commands/audit/completions_l.py +15 -0
  25. adam/commands/audit/show_last10.py +36 -0
  26. adam/commands/audit/show_slow10.py +36 -0
  27. adam/commands/audit/show_top10.py +36 -0
  28. adam/commands/audit/utils_show_top10.py +71 -0
  29. adam/commands/bash/__init__.py +5 -0
  30. adam/commands/bash/bash.py +36 -0
  31. adam/commands/bash/bash_completer.py +93 -0
  32. adam/commands/bash/utils_bash.py +16 -0
  33. adam/commands/cassandra/__init__.py +0 -0
  34. adam/commands/cassandra/download_cassandra_log.py +45 -0
  35. adam/commands/cassandra/nodetool.py +64 -0
  36. adam/commands/cassandra/nodetool_commands.py +120 -0
  37. adam/commands/{restart.py → cassandra/restart_cluster.py} +12 -26
  38. adam/commands/cassandra/restart_node.py +51 -0
  39. adam/commands/cassandra/restart_nodes.py +47 -0
  40. adam/commands/cassandra/rollout.py +88 -0
  41. adam/commands/cat.py +36 -0
  42. adam/commands/cd.py +14 -92
  43. adam/commands/check.py +18 -21
  44. adam/commands/cli_commands.py +8 -4
  45. adam/commands/clipboard_copy.py +87 -0
  46. adam/commands/code.py +57 -0
  47. adam/commands/command.py +212 -39
  48. adam/commands/commands_utils.py +20 -28
  49. adam/commands/cql/alter_tables.py +66 -0
  50. adam/commands/cql/completions_c.py +29 -0
  51. adam/commands/cql/cqlsh.py +10 -29
  52. adam/commands/cql/utils_cql.py +305 -0
  53. adam/commands/debug/__init__.py +0 -0
  54. adam/commands/debug/debug.py +22 -0
  55. adam/commands/debug/debug_completes.py +35 -0
  56. adam/commands/debug/debug_timings.py +35 -0
  57. adam/commands/deploy/code_start.py +7 -10
  58. adam/commands/deploy/code_stop.py +4 -21
  59. adam/commands/deploy/code_utils.py +3 -3
  60. adam/commands/deploy/deploy.py +4 -21
  61. adam/commands/deploy/deploy_frontend.py +14 -17
  62. adam/commands/deploy/deploy_pg_agent.py +3 -6
  63. adam/commands/deploy/deploy_pod.py +65 -73
  64. adam/commands/deploy/deploy_utils.py +14 -24
  65. adam/commands/deploy/undeploy.py +4 -21
  66. adam/commands/deploy/undeploy_frontend.py +4 -7
  67. adam/commands/deploy/undeploy_pg_agent.py +6 -8
  68. adam/commands/deploy/undeploy_pod.py +11 -12
  69. adam/commands/devices/__init__.py +0 -0
  70. adam/commands/devices/device.py +149 -0
  71. adam/commands/devices/device_app.py +163 -0
  72. adam/commands/devices/device_auit_log.py +49 -0
  73. adam/commands/devices/device_cass.py +179 -0
  74. adam/commands/devices/device_export.py +87 -0
  75. adam/commands/devices/device_postgres.py +160 -0
  76. adam/commands/devices/devices.py +25 -0
  77. adam/commands/download_cassandra_log.py +45 -0
  78. adam/commands/download_file.py +47 -0
  79. adam/commands/exit.py +1 -4
  80. adam/commands/export/__init__.py +0 -0
  81. adam/commands/export/clean_up_all_export_sessions.py +37 -0
  82. adam/commands/export/clean_up_export_sessions.py +39 -0
  83. adam/commands/export/completions_x.py +11 -0
  84. adam/commands/export/download_export_session.py +40 -0
  85. adam/commands/export/drop_export_database.py +39 -0
  86. adam/commands/export/drop_export_databases.py +37 -0
  87. adam/commands/export/export.py +37 -0
  88. adam/commands/export/export_databases.py +247 -0
  89. adam/commands/export/export_select.py +34 -0
  90. adam/commands/export/export_sessions.py +211 -0
  91. adam/commands/export/export_use.py +49 -0
  92. adam/commands/export/export_x_select.py +48 -0
  93. adam/commands/export/exporter.py +361 -0
  94. adam/commands/export/import_files.py +44 -0
  95. adam/commands/export/import_session.py +44 -0
  96. adam/commands/export/importer.py +82 -0
  97. adam/commands/export/importer_athena.py +150 -0
  98. adam/commands/export/importer_sqlite.py +69 -0
  99. adam/commands/export/show_column_counts.py +45 -0
  100. adam/commands/export/show_export_databases.py +39 -0
  101. adam/commands/export/show_export_session.py +39 -0
  102. adam/commands/export/show_export_sessions.py +37 -0
  103. adam/commands/export/utils_export.py +366 -0
  104. adam/commands/find_files.py +51 -0
  105. adam/commands/find_processes.py +76 -0
  106. adam/commands/generate_report.py +52 -0
  107. adam/commands/head.py +36 -0
  108. adam/commands/help.py +12 -8
  109. adam/commands/intermediate_command.py +52 -0
  110. adam/commands/issues.py +14 -40
  111. adam/commands/kubectl.py +38 -0
  112. adam/commands/login.py +26 -25
  113. adam/commands/ls.py +11 -116
  114. adam/commands/medusa/medusa.py +4 -22
  115. adam/commands/medusa/medusa_backup.py +20 -27
  116. adam/commands/medusa/medusa_restore.py +35 -48
  117. adam/commands/medusa/medusa_show_backupjobs.py +17 -18
  118. adam/commands/medusa/medusa_show_restorejobs.py +13 -18
  119. adam/commands/medusa/utils_medusa.py +15 -0
  120. adam/commands/nodetool.py +8 -19
  121. adam/commands/os/__init__.py +0 -0
  122. adam/commands/os/cat.py +36 -0
  123. adam/commands/os/download_file.py +47 -0
  124. adam/commands/os/find_files.py +51 -0
  125. adam/commands/os/find_processes.py +76 -0
  126. adam/commands/os/head.py +36 -0
  127. adam/commands/os/shell.py +41 -0
  128. adam/commands/param_get.py +11 -14
  129. adam/commands/param_set.py +8 -12
  130. adam/commands/postgres/completions_p.py +22 -0
  131. adam/commands/postgres/postgres.py +47 -55
  132. adam/commands/postgres/postgres_databases.py +269 -0
  133. adam/commands/postgres/postgres_ls.py +4 -8
  134. adam/commands/postgres/postgres_preview.py +5 -9
  135. adam/commands/postgres/utils_postgres.py +79 -0
  136. adam/commands/preview_table.py +10 -61
  137. adam/commands/pwd.py +14 -46
  138. adam/commands/reaper/reaper.py +4 -24
  139. adam/commands/reaper/reaper_forward.py +49 -56
  140. adam/commands/reaper/reaper_forward_session.py +6 -0
  141. adam/commands/reaper/reaper_forward_stop.py +10 -16
  142. adam/commands/reaper/reaper_restart.py +7 -14
  143. adam/commands/reaper/reaper_run_abort.py +8 -33
  144. adam/commands/reaper/reaper_runs.py +43 -58
  145. adam/commands/reaper/reaper_runs_abort.py +29 -49
  146. adam/commands/reaper/reaper_schedule_activate.py +14 -33
  147. adam/commands/reaper/reaper_schedule_start.py +9 -33
  148. adam/commands/reaper/reaper_schedule_stop.py +9 -33
  149. adam/commands/reaper/reaper_schedules.py +4 -14
  150. adam/commands/reaper/reaper_status.py +8 -16
  151. adam/commands/reaper/utils_reaper.py +203 -0
  152. adam/commands/repair/repair.py +4 -22
  153. adam/commands/repair/repair_log.py +5 -11
  154. adam/commands/repair/repair_run.py +27 -34
  155. adam/commands/repair/repair_scan.py +32 -40
  156. adam/commands/repair/repair_stop.py +5 -12
  157. adam/commands/restart_cluster.py +47 -0
  158. adam/commands/restart_node.py +51 -0
  159. adam/commands/restart_nodes.py +47 -0
  160. adam/commands/rollout.py +19 -24
  161. adam/commands/shell.py +12 -4
  162. adam/commands/show/show.py +10 -23
  163. adam/commands/show/show_adam.py +3 -3
  164. adam/commands/show/show_cassandra_repairs.py +37 -0
  165. adam/commands/show/show_cassandra_status.py +47 -51
  166. adam/commands/show/show_cassandra_version.py +5 -18
  167. adam/commands/show/show_cli_commands.py +56 -0
  168. adam/commands/show/show_host.py +1 -1
  169. adam/commands/show/show_login.py +23 -27
  170. adam/commands/show/show_params.py +2 -5
  171. adam/commands/show/show_processes.py +18 -21
  172. adam/commands/show/show_storage.py +11 -20
  173. adam/commands/watch.py +26 -29
  174. adam/config.py +5 -15
  175. adam/embedded_params.py +1 -1
  176. adam/log.py +4 -4
  177. adam/repl.py +105 -133
  178. adam/repl_commands.py +68 -28
  179. adam/repl_session.py +9 -1
  180. adam/repl_state.py +300 -62
  181. adam/sql/async_executor.py +44 -0
  182. adam/sql/lark_completer.py +286 -0
  183. adam/sql/lark_parser.py +604 -0
  184. adam/sql/qingl.lark +1076 -0
  185. adam/sql/sql_completer.py +104 -64
  186. adam/sql/sql_state_machine.py +630 -0
  187. adam/sql/term_completer.py +3 -0
  188. adam/sso/authn_ad.py +6 -8
  189. adam/sso/authn_okta.py +4 -6
  190. adam/sso/cred_cache.py +3 -5
  191. adam/sso/idp.py +9 -12
  192. adam/utils.py +640 -10
  193. adam/utils_athena.py +140 -87
  194. adam/utils_audits.py +102 -0
  195. adam/utils_issues.py +32 -0
  196. adam/utils_k8s/app_clusters.py +28 -0
  197. adam/utils_k8s/app_pods.py +35 -0
  198. adam/utils_k8s/cassandra_clusters.py +34 -21
  199. adam/utils_k8s/cassandra_nodes.py +9 -6
  200. adam/utils_k8s/custom_resources.py +16 -17
  201. adam/utils_k8s/ingresses.py +2 -2
  202. adam/utils_k8s/jobs.py +7 -11
  203. adam/utils_k8s/k8s.py +96 -0
  204. adam/utils_k8s/kube_context.py +3 -6
  205. adam/{pod_exec_result.py → utils_k8s/pod_exec_result.py} +11 -5
  206. adam/utils_k8s/pods.py +146 -75
  207. adam/utils_k8s/secrets.py +4 -4
  208. adam/utils_k8s/service_accounts.py +5 -4
  209. adam/utils_k8s/services.py +2 -2
  210. adam/utils_k8s/statefulsets.py +6 -14
  211. adam/utils_local.py +42 -0
  212. adam/utils_net.py +4 -4
  213. adam/utils_repl/__init__.py +0 -0
  214. adam/utils_repl/appendable_completer.py +6 -0
  215. adam/utils_repl/automata_completer.py +48 -0
  216. adam/utils_repl/repl_completer.py +89 -0
  217. adam/utils_repl/state_machine.py +173 -0
  218. adam/utils_sqlite.py +137 -0
  219. adam/version.py +1 -1
  220. {kaqing-2.0.98.dist-info → kaqing-2.0.203.dist-info}/METADATA +1 -1
  221. kaqing-2.0.203.dist-info/RECORD +277 -0
  222. kaqing-2.0.203.dist-info/top_level.txt +2 -0
  223. teddy/__init__.py +0 -0
  224. teddy/lark_parser.py +436 -0
  225. teddy/lark_parser2.py +618 -0
  226. adam/commands/app.py +0 -67
  227. adam/commands/bash.py +0 -92
  228. adam/commands/cp.py +0 -95
  229. adam/commands/cql/cql_completions.py +0 -11
  230. adam/commands/cql/cql_table_completer.py +0 -8
  231. adam/commands/cql/cql_utils.py +0 -115
  232. adam/commands/describe/describe.py +0 -47
  233. adam/commands/describe/describe_keyspace.py +0 -60
  234. adam/commands/describe/describe_keyspaces.py +0 -49
  235. adam/commands/describe/describe_schema.py +0 -49
  236. adam/commands/describe/describe_table.py +0 -60
  237. adam/commands/describe/describe_tables.py +0 -49
  238. adam/commands/devices.py +0 -118
  239. adam/commands/logs.py +0 -39
  240. adam/commands/postgres/postgres_session.py +0 -240
  241. adam/commands/postgres/postgres_utils.py +0 -31
  242. adam/commands/postgres/psql_completions.py +0 -10
  243. adam/commands/postgres/psql_table_completer.py +0 -11
  244. adam/commands/reaper/reaper_session.py +0 -159
  245. adam/commands/report.py +0 -57
  246. adam/commands/show/show_app_actions.py +0 -53
  247. adam/commands/show/show_commands.py +0 -61
  248. adam/commands/show/show_repairs.py +0 -47
  249. adam/sql/state_machine.py +0 -460
  250. kaqing-2.0.98.dist-info/RECORD +0 -191
  251. kaqing-2.0.98.dist-info/top_level.txt +0 -1
  252. /adam/commands/{describe → app}/__init__.py +0 -0
  253. {kaqing-2.0.98.dist-info → kaqing-2.0.203.dist-info}/WHEEL +0 -0
  254. {kaqing-2.0.98.dist-info → kaqing-2.0.203.dist-info}/entry_points.txt +0 -0
adam/repl.py CHANGED
@@ -1,31 +1,31 @@
1
- import getpass
2
1
  import os
3
- import re
4
2
  import time
5
- import traceback
3
+ from typing import cast
6
4
  import click
7
- import concurrent
8
- from prompt_toolkit.completion import NestedCompleter
9
5
  from prompt_toolkit.key_binding import KeyBindings
10
- import requests
11
6
 
12
7
  from adam.cli_group import cli
13
- from adam.commands.command import Command
8
+ from adam.commands.command import Command, InvalidArgumentsException, InvalidStateException
14
9
  from adam.commands.command_helpers import ClusterCommandHelper
10
+ from adam.commands.devices.devices import Devices
15
11
  from adam.commands.help import Help
16
- from adam.commands.postgres.postgres_session import PostgresSession
17
12
  from adam.config import Config
13
+ from adam.utils_audits import Audits
18
14
  from adam.utils_k8s.kube_context import KubeContext
19
- from adam.utils_k8s.statefulsets import StatefulSets
20
15
  from adam.log import Log
21
16
  from adam.repl_commands import ReplCommands
22
17
  from adam.repl_session import ReplSession
23
18
  from adam.repl_state import ReplState
24
- from adam.utils import deep_merge_dicts, deep_sort_dict, lines_to_tabular, log2
19
+ from adam.utils import CommandLog, clear_wait_log_flag, debug_trace, deep_sort_dict, tabulize, log2, log_exc, log_timing
25
20
  from adam.apps import Apps
26
- from adam.utils_net import get_my_host
21
+ from adam.utils_repl.repl_completer import ReplCompleter, merge_completions
27
22
  from . import __version__
28
23
 
24
+ import nest_asyncio
25
+ nest_asyncio.apply()
26
+
27
+ import asyncio
28
+
29
29
  def enter_repl(state: ReplState):
30
30
  if os.getenv('QING_DROPPED', 'false') == 'true':
31
31
  log2('You have dropped to bash from another qing instance. Please enter "exit" to go back to qing.')
@@ -37,65 +37,13 @@ def enter_repl(state: ReplState):
37
37
  session = ReplSession().prompt_session
38
38
 
39
39
  def prompt_msg():
40
- msg = ''
41
- if state.device == ReplState.P:
42
- msg = f'{ReplState.P}:'
43
- pg = PostgresSession(state.namespace, state.pg_path) if state.pg_path else None
44
- if pg and pg.db:
45
- msg += pg.db
46
- elif pg and pg.host:
47
- msg += pg.host
48
- elif state.device == ReplState.A:
49
- msg = f'{ReplState.A}:'
50
- if state.app_env:
51
- msg += state.app_env
52
- if state.app_app:
53
- msg += f'/{state.app_app}'
54
- elif state.device == ReplState.L:
55
- msg = f'{ReplState.L}:'
56
- else:
57
- msg = f'{ReplState.C}:'
58
- if state.pod:
59
- # cs-d0767a536f-cs-d0767a536f-default-sts-0
60
- group = re.match(r".*?-.*?-(.*)", state.pod)
61
- msg += group[1]
62
- elif state.sts:
63
- # cs-d0767a536f-cs-d0767a536f-default-sts
64
- group = re.match(r".*?-.*?-(.*)", state.sts)
65
- msg += group[1]
40
+ msg = state.__str__()
66
41
 
67
42
  return f"{msg}$ " if state.bash_session else f"{msg}> "
68
43
 
69
44
  Log.log2(f'kaqing {__version__}')
70
45
 
71
- if state.device == ReplState.C:
72
- auto_enter = Config().get('repl.auto-enter-only-cluster', 'cluster')
73
- ss = StatefulSets.list_sts_name_and_ns()
74
- if not ss:
75
- raise Exception("no Cassandra clusters found")
76
- elif not state.sts and len(ss) == 1 and auto_enter in ['cluster', 'first-pod']:
77
- cluster = ss[0]
78
- state.sts = cluster[0]
79
- state.namespace = cluster[1]
80
- if auto_enter == 'first-pod':
81
- state.pod = f'{state.sts}-0'
82
- if KubeContext().in_cluster_namespace:
83
- Config().wait_log(f'Moving to the only Cassandra cluster: {state.sts}...')
84
- else:
85
- Config().wait_log(f'Moving to the only Cassandra cluster: {state.sts}@{state.namespace}...')
86
- elif state.device == ReplState.A:
87
- if not state.app_env:
88
- if app := Config().get('repl.auto-enter-app', 'c3/c3'):
89
- if app != 'no':
90
- ea = app.split('/')
91
- state.app_env = ea[0]
92
- if len(ea) > 1:
93
- state.app_app = ea[1]
94
- Config().wait_log(f'Moving to {state.app_env}/{state.app_app}...')
95
- else:
96
- Config().wait_log(f'Moving to {state.app_env}...')
97
- elif state.device == ReplState.P:
98
- Config().wait_log('Inspecting postgres database instances...')
46
+ Devices.of(state).enter(state)
99
47
 
100
48
  kb = KeyBindings()
101
49
 
@@ -103,31 +51,32 @@ def enter_repl(state: ReplState):
103
51
  def _(event):
104
52
  event.app.current_buffer.text = ''
105
53
 
106
- with concurrent.futures.ThreadPoolExecutor(max_workers=Config().get('audit.workers', 3)) as executor:
54
+ with Audits.offload() as exec:
107
55
  # warm up AWS lambda - this log line may timeout and get lost, which is fine
108
- executor.submit(audit_log, 'entering kaqing repl', state)
56
+ exec.submit(Audits.log, 'entering kaqing repl', state.namespace, 'z', 0.0)
57
+
58
+ s0 = time.time()
109
59
 
110
60
  # use sorted command list only for auto-completion
111
61
  sorted_cmds = sorted(cmd_list, key=lambda cmd: cmd.command())
112
62
  while True:
63
+ cmd: str = None
64
+ result = None
113
65
  try:
114
- completer = NestedCompleter.from_nested_dict({})
66
+ completer = ReplCompleter.from_nested_dict({})
115
67
  if not state.bash_session:
116
- completions = {}
117
- # app commands are available only on a: drive
118
- if state.device == ReplState.A and state.app_app:
119
- completions = Apps(path='apps.yaml').commands()
120
-
121
- for cmd in sorted_cmds:
122
- s1 = time.time()
123
- try:
124
- completions = deep_sort_dict(deep_merge_dicts(completions, cmd.completion(state)))
125
- finally:
126
- if Config().get('debugs.timings', False):
127
- log2(f'Timing auto-completion-calc {cmd.command()}: {time.time() - s1:.2f}')
128
-
129
- # print(json.dumps(completions, indent=4))
130
- completer = NestedCompleter.from_nested_dict(completions)
68
+ with log_timing('completion-calcs'):
69
+ completions = {}
70
+ # app commands are available only on a: drive
71
+ if state.device == ReplState.A and state.app_app:
72
+ completions = log_timing('actions', lambda: Apps(path='apps.yaml').commands())
73
+
74
+ for c in sorted_cmds:
75
+ with log_exc(f'* {c.command()} command returned None completions.'):
76
+ completions = log_timing(c.command(), lambda: deep_sort_dict(merge_completions(completions, c.completion(state))))
77
+
78
+ # print(json.dumps(completions, indent=4))
79
+ completer = ReplCompleter.from_nested_dict(completions)
131
80
 
132
81
  cmd = session.prompt(prompt_msg(), completer=completer, key_bindings=kb)
133
82
  s0 = time.time()
@@ -139,33 +88,40 @@ def enter_repl(state: ReplState):
139
88
 
140
89
  cmd = f'bash {cmd}'
141
90
 
142
- if cmd and cmd.strip(' ') and not cmds.run(cmd, state):
143
- c_sql_tried = False
144
- if state.device == ReplState.P:
145
- pg = PostgresSession(state.namespace, state.pg_path)
146
- if pg.db:
147
- c_sql_tried = True
148
- cmd = f'pg {cmd}'
149
- cmds.run(cmd, state)
150
- elif state.device == ReplState.A:
151
- if state.app_app:
152
- c_sql_tried = True
153
- cmd = f'app {cmd}'
154
- cmds.run(cmd, state)
155
- elif state.device == ReplState.L:
156
- c_sql_tried = True
157
- cmd = f'audit {cmd}'
158
- cmds.run(cmd, state)
91
+ def targetted(state: ReplState, cmd: str):
92
+ if not (cmd.startswith('@') and len(arry := cmd.split(' ')) > 1):
93
+ return state, cmd
94
+
95
+ if state.device == ReplState.A and state.app_app or state.device == ReplState.P:
96
+ state.push(pod_targetted=True)
97
+
98
+ state.app_pod = arry[0].strip('@')
99
+ cmd = ' '.join(arry[1:])
100
+ elif state.device == ReplState.P:
101
+ state.push(pod_targetted=True)
102
+
103
+ state.app_pod = arry[0].strip('@')
104
+ cmd = ' '.join(arry[1:])
159
105
  elif state.sts:
160
- c_sql_tried = True
161
- cmd = f'cql {cmd}'
162
- cmds.run(cmd, state)
163
-
164
- if not c_sql_tried:
165
- log2(f'* Invalid command: {cmd}')
166
- log2()
167
- lines = [c.help(state) for c in cmd_list if c.help(state)]
168
- log2(lines_to_tabular(lines, separator='\t'))
106
+ state.push(pod_targetted=True)
107
+
108
+ state.pod = arry[0].strip('@')
109
+ cmd = ' '.join(arry[1:])
110
+
111
+ return (state, cmd)
112
+
113
+ target, cmd = targetted(state, cmd)
114
+ try:
115
+ if cmd and cmd.strip(' ') and not (result := cmds.run(cmd, target)):
116
+ result = try_device_default_action(target, cmds, cmd_list, cmd)
117
+ except InvalidStateException:
118
+ pass
119
+ except InvalidArgumentsException:
120
+ pass
121
+
122
+ if result and type(result) is ReplState and (s := cast(ReplState, result).export_session) != state.export_session:
123
+ state.export_session = s
124
+
169
125
  except EOFError: # Handle Ctrl+D (EOF) for graceful exit
170
126
  break
171
127
  except Exception as e:
@@ -173,33 +129,46 @@ def enter_repl(state: ReplState):
173
129
  raise e
174
130
  else:
175
131
  log2(e)
176
- Config().debug(traceback.format_exc())
132
+ debug_trace()
177
133
  finally:
178
- Config().clear_wait_log_flag()
179
- if Config().get('debugs.timings', False) and 'cmd' in locals() and 's0' in locals():
180
- log2(f'Timing command {cmd}: {time.time() - s0:.2f}')
134
+ if not state.bash_session:
135
+ state.pop()
136
+
137
+ clear_wait_log_flag()
138
+ if cmd:
139
+ log_timing(f'command {cmd}', s0=s0)
181
140
 
182
141
  # offload audit logging
183
142
  if cmd and (state.device != ReplState.L or Config().get('audit.log-audit-queries', False)):
184
- executor.submit(audit_log, cmd, state)
185
-
186
- def audit_log(cmd: str, state: ReplState):
187
- payload = {
188
- 'cluster': state.namespace if state.namespace else 'NA',
189
- 'ts': time.time(),
190
- 'host': get_my_host(),
191
- 'user': getpass.getuser(),
192
- 'line': cmd.replace('"', '""').replace('\n', ' '),
193
- }
194
- audit_endpoint = Config().get("audit.endpoint", "https://4psvtaxlcb.execute-api.us-west-2.amazonaws.com/prod/")
195
- try:
196
- response = requests.post(audit_endpoint, json=payload, timeout=Config().get("audit.timeout", 10))
197
- if response.status_code in [200, 201]:
198
- Config().debug(response.text)
199
- else:
200
- log2(f"Error: {response.status_code} {response.text}")
201
- except requests.exceptions.Timeout as e:
202
- log2(f"Timeout occurred: {e}")
143
+ exec.submit(Audits.log, cmd, state.namespace, state.device, time.time() - s0, get_audit_extra(result))
144
+
145
+ CommandLog.close_log_file()
146
+
147
+ def try_device_default_action(state: ReplState, cmds: Command, cmd_list: list[Command], cmd: str):
148
+ action_taken, result = Devices.of(state).try_fallback_action(cmds, state, cmd)
149
+
150
+ if not action_taken:
151
+ log2(f'* Invalid command: {cmd}')
152
+ log2()
153
+ tabulize([c.help(state) for c in cmd_list if c.help(state)], separator='\t', to=2)
154
+
155
+ return result
156
+
157
+ def get_audit_extra(result: any):
158
+ if not result:
159
+ return None
160
+
161
+ if type(result) is list:
162
+ extras = set()
163
+
164
+ for r in result:
165
+ if hasattr(r, '__audit_extra__') and (x := r.__audit_extra__()):
166
+ extras.add(x)
167
+
168
+ return ','.join(list(extras))
169
+
170
+ if hasattr(result, '__audit_extra__') and (x := result.__audit_extra__()):
171
+ return x
203
172
 
204
173
  @cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=ClusterCommandHelper, help="Enter interactive shell.")
205
174
  @click.option('--kubeconfig', '-k', required=False, metavar='path', help='path to kubeconfig file')
@@ -213,6 +182,9 @@ def repl(kubeconfig: str, config: str, param: list[str], cluster:str, namespace:
213
182
  if not KubeContext.init_params(config, param):
214
183
  return
215
184
 
216
- state = ReplState(device=Config().get('repl.start-drive', 'a'), ns_sts=cluster, namespace=namespace, in_repl=True)
185
+ state = ReplState(ns_sts=cluster, namespace=namespace, in_repl=True)
217
186
  state, _ = state.apply_device_arg(extra_args)
187
+ if not state.device:
188
+ state.device=Config().get('repl.start-drive', 'a')
189
+
218
190
  enter_repl(state)
adam/repl_commands.py CHANGED
@@ -1,8 +1,16 @@
1
1
  from adam.commands.alter_tables import AlterTables
2
- from adam.commands.app import App
3
- from adam.commands.app_ping import AppPing
2
+ from adam.commands.app.app import App
3
+ from adam.commands.app.app_ping import AppPing
4
+ from adam.commands.app.show_app_actions import ShowAppActions
5
+ from adam.commands.app.show_app_id import ShowAppId
6
+ from adam.commands.app.show_app_queues import ShowAppQueues
4
7
  from adam.commands.audit.audit import Audit
5
- from adam.commands.audit.audit_repair_tables import AuditRepairTables
8
+ from adam.commands.cat import Cat
9
+ from adam.commands.code import Code
10
+ from adam.commands.debug.debug import Debug
11
+ from adam.commands.debug.debug_timings import DebugTimings
12
+ from adam.commands.download_cassandra_log import DownloadCassandraLog
13
+ from adam.commands.download_file import DownloadFile
6
14
  from adam.commands.deploy.code_start import CodeStart
7
15
  from adam.commands.deploy.code_stop import CodeStop
8
16
  from adam.commands.deploy.deploy import Deploy
@@ -13,52 +21,73 @@ from adam.commands.deploy.undeploy import Undeploy
13
21
  from adam.commands.deploy.undeploy_frontend import UndeployFrontend
14
22
  from adam.commands.deploy.undeploy_pg_agent import UndeployPgAgent
15
23
  from adam.commands.deploy.undeploy_pod import UndeployPod
16
- from adam.commands.describe.describe import Describe
24
+ from adam.commands.devices.device_app import DeviceApp
25
+ from adam.commands.devices.device_auit_log import DeviceAuditLog
26
+ from adam.commands.devices.device_cass import DeviceCass
27
+ from adam.commands.devices.device_export import DeviceExport
28
+ from adam.commands.devices.device_postgres import DevicePostgres
29
+ from adam.commands.export.download_export_session import DownloadExportSession
30
+ from adam.commands.export.drop_export_database import DropExportDatabase
31
+ from adam.commands.export.export import ExportTables
32
+ from adam.commands.export.import_files import ImportCSVFiles
33
+ from adam.commands.export.import_session import ImportSession
34
+ from adam.commands.export.clean_up_export_sessions import CleanUpExportSessions
35
+ from adam.commands.export.clean_up_all_export_sessions import CleanUpAllExportSessions
36
+ from adam.commands.export.drop_export_databases import DropExportDatabases
37
+ from adam.commands.export.export_x_select import ExportXSelect
38
+ from adam.commands.export.export_use import ExportUse
39
+ from adam.commands.export.export_select import ExportSelect
40
+ from adam.commands.export.show_column_counts import ShowColumnCounts
41
+ from adam.commands.export.show_export_databases import ShowExportDatabases
42
+ from adam.commands.export.show_export_session import ShowExportSession
43
+ from adam.commands.export.show_export_sessions import ShowExportSessions
44
+ from adam.commands.find_files import FindLocalFiles
45
+ from adam.commands.find_processes import FindProcesses
46
+ from adam.commands.head import Head
47
+ from adam.commands.kubectl import Kubectl
48
+ from adam.commands.restart_cluster import RestartCluster
49
+ from adam.commands.restart_node import RestartNode
17
50
  from adam.commands.shell import Shell
18
- from adam.commands.show.show_app_queues import ShowAppQueues
19
- from adam.commands.cp import ClipboardCopy
20
- from adam.commands.bash import Bash
51
+ from adam.commands.clipboard_copy import ClipboardCopy
52
+ from adam.commands.bash.bash import Bash
21
53
  from adam.commands.cd import Cd
22
54
  from adam.commands.check import Check
23
55
  from adam.commands.command import Command
24
56
  from adam.commands.cql.cqlsh import Cqlsh
25
- from adam.commands.devices import DeviceApp, DeviceAuditLog, DeviceCass, DevicePostgres
26
57
  from adam.commands.exit import Exit
27
58
  from adam.commands.medusa.medusa import Medusa
28
59
  from adam.commands.param_get import GetParam
29
60
  from adam.commands.issues import Issues
30
61
  from adam.commands.ls import Ls
31
62
  from adam.commands.nodetool import NodeTool
32
- from adam.commands.postgres.postgres import Postgres
63
+ from adam.commands.postgres.postgres import Postgres, PostgresPg
33
64
  from adam.commands.preview_table import PreviewTable
34
65
  from adam.commands.pwd import Pwd
35
66
  from adam.commands.reaper.reaper import Reaper
36
67
  from adam.commands.repair.repair import Repair
37
- from adam.commands.report import Report
38
- from adam.commands.restart import Restart
68
+ from adam.commands.generate_report import GenerateReport
69
+ from adam.commands.restart_nodes import RestartNodes
39
70
  from adam.commands.rollout import RollOut
40
71
  from adam.commands.param_set import SetParam
41
72
  from adam.commands.show.show import Show
42
- from adam.commands.show.show_app_actions import ShowAppActions
43
- from adam.commands.show.show_app_id import ShowAppId
44
73
  from adam.commands.show.show_cassandra_status import ShowCassandraStatus
45
74
  from adam.commands.show.show_cassandra_version import ShowCassandraVersion
46
- from adam.commands.show.show_commands import ShowKubectlCommands
75
+ from adam.commands.show.show_cli_commands import ShowKubectlCommands
47
76
  from adam.commands.show.show_host import ShowHost
48
77
  from adam.commands.show.show_login import ShowLogin
49
78
  from adam.commands.show.show_params import ShowParams
50
79
  from adam.commands.show.show_processes import ShowProcesses
51
- from adam.commands.show.show_repairs import ShowRepairs
80
+ from adam.commands.show.show_cassandra_repairs import ShowCassandraRepairs
52
81
  from adam.commands.show.show_storage import ShowStorage
53
82
  from adam.commands.show.show_adam import ShowAdam
54
83
  from adam.commands.watch import Watch
55
84
 
56
85
  class ReplCommands:
57
86
  def repl_cmd_list() -> list[Command]:
58
- cmds: list[Command] = ReplCommands.navigation() + ReplCommands.cassandra_check() + ReplCommands.cassandra_ops() + \
59
- ReplCommands.tools() + ReplCommands.app() + ReplCommands.exit()
87
+ cmds: list[Command] = ReplCommands.navigation() + ReplCommands.cassandra_ops() + ReplCommands.postgres_ops() + \
88
+ ReplCommands.app_ops() + ReplCommands.audit_ops() + ReplCommands.export_ops() + ReplCommands.tools() + ReplCommands.exit()
60
89
 
61
- intermediate_cmds: list[Command] = [App(), Reaper(), Repair(), Deploy(), Describe(), Show(), Undeploy()]
90
+ intermediate_cmds: list[Command] = [App(), Audit(), Reaper(), Repair(), Debug(), Deploy(), Show(), Undeploy()]
62
91
  ic = [c.command() for c in intermediate_cmds]
63
92
  # 1. dedup commands
64
93
  deduped = []
@@ -75,22 +104,33 @@ class ReplCommands:
75
104
  return deduped
76
105
 
77
106
  def navigation() -> list[Command]:
78
- return [Ls(), PreviewTable(), DeviceApp(), DevicePostgres(), DeviceCass(), DeviceAuditLog(), Cd(), Pwd(), ClipboardCopy(),
107
+ return [Ls(), PreviewTable(), DeviceApp(), DevicePostgres(), DeviceCass(), DeviceAuditLog(), DeviceExport(),
108
+ Cd(), Cat(), Head(), DownloadFile(), FindLocalFiles(), FindProcesses(), Pwd(), ClipboardCopy(),
79
109
  GetParam(), SetParam(), ShowParams(), ShowKubectlCommands(), ShowLogin(), ShowAdam(), ShowHost()]
80
110
 
81
- def cassandra_check() -> list[Command]:
82
- return Describe.cmd_list() + [ShowCassandraStatus(),
83
- ShowCassandraVersion(), ShowRepairs(), ShowStorage(), ShowProcesses(), Check(), Issues(), NodeTool(), Report()]
84
-
85
111
  def cassandra_ops() -> list[Command]:
86
- return [AlterTables()] + Medusa.cmd_list() + [Restart(), RollOut(), Watch()] + Reaper.cmd_list() + Repair.cmd_list()
112
+ return [Cqlsh(), DownloadCassandraLog(), ShowCassandraStatus(), ShowCassandraVersion(), ShowCassandraRepairs(), ShowStorage(), ShowProcesses(),
113
+ Check(), Issues(), NodeTool(), GenerateReport(), AlterTables(), Bash(),
114
+ ExportTables(), ExportXSelect(), ExportUse(), ShowExportDatabases(), ShowColumnCounts(),
115
+ DropExportDatabase(), DropExportDatabases(),
116
+ ShowExportSessions(), ShowExportSession(), DownloadExportSession(),
117
+ CleanUpExportSessions(), CleanUpAllExportSessions(), ImportSession(), ImportCSVFiles()] + \
118
+ Medusa().cmd_list() + [RestartNodes(), RestartNode(), RestartCluster(), RollOut(), Watch()] + Reaper().cmd_list() + Repair().cmd_list() + Debug().cmd_list()
87
119
 
88
- def tools() -> list[Command]:
89
- return [Cqlsh(), Postgres(), Bash(), Shell(), CodeStart(), CodeStop(), DeployFrontend(), UndeployFrontend(),
90
- DeployPod(), UndeployPod(), DeployPgAgent(), UndeployPgAgent(), AuditRepairTables(), Audit()]
120
+ def postgres_ops() -> list[Command]:
121
+ return [Postgres(), DeployPgAgent(), UndeployPgAgent(), PostgresPg()]
91
122
 
92
- def app() -> list[Command]:
123
+ def app_ops() -> list[Command]:
93
124
  return [ShowAppActions(), ShowAppId(), ShowAppQueues(), AppPing(), App()]
94
125
 
126
+ def audit_ops() -> list[Command]:
127
+ return [Audit()] + Audit().cmd_list()
128
+
129
+ def export_ops() -> list[Command]:
130
+ return [ExportSelect(), DropExportDatabase(), DropExportDatabases(), ShowColumnCounts()]
131
+
132
+ def tools() -> list[Command]:
133
+ return [Shell(), CodeStart(), CodeStop(), DeployFrontend(), UndeployFrontend(), DeployPod(), UndeployPod(), Kubectl(), Code()]
134
+
95
135
  def exit() -> list[Command]:
96
136
  return [Exit()]
adam/repl_session.py CHANGED
@@ -1,6 +1,9 @@
1
1
  from prompt_toolkit import PromptSession
2
2
  from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
3
3
 
4
+ from adam.config import Config
5
+ from adam.utils import ConfigHolder
6
+
4
7
  class ReplSession:
5
8
  # the singleton pattern
6
9
  def __new__(cls, *args, **kwargs):
@@ -10,4 +13,9 @@ class ReplSession:
10
13
 
11
14
  def __init__(self):
12
15
  if not hasattr(self, 'prompt_session'):
13
- self.prompt_session = PromptSession(auto_suggest=AutoSuggestFromHistory())
16
+ self.prompt_session = PromptSession(auto_suggest=AutoSuggestFromHistory())
17
+ ConfigHolder().append_command_history = self.append_history
18
+
19
+ def append_history(self, entry: str):
20
+ if entry and self.prompt_session and Config().get('repl.history.push-cat-remote-log-file', True):
21
+ self.prompt_session.history.append_string(entry)