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/commands/issues.py CHANGED
@@ -1,10 +1,9 @@
1
1
  from adam.checks.check_result import CheckResult
2
2
  from adam.checks.check_utils import run_checks
3
- from adam.checks.issue import Issue
3
+ from adam.commands import extract_options
4
4
  from adam.commands.command import Command
5
- from adam.repl_session import ReplSession
6
5
  from adam.repl_state import ReplState
7
- from adam.utils import lines_to_tabular, log, log2
6
+ from adam.utils_issues import IssuesUtils
8
7
 
9
8
  class Issues(Command):
10
9
  COMMAND = 'issues'
@@ -21,49 +20,24 @@ class Issues(Command):
21
20
  def command(self):
22
21
  return Issues.COMMAND
23
22
 
23
+ def required(self):
24
+ return ReplState.NON_L
25
+
24
26
  def run(self, cmd: str, state: ReplState):
25
27
  if not(args := self.args(cmd)):
26
28
  return super().run(cmd, state)
27
29
 
28
- state, args = self.apply_state(args, state)
29
- args, show = Command.extract_options(args, ['-s', '--show'])
30
-
31
- results = run_checks(state.sts, state.namespace, state.pod, show_output=show)
32
-
33
- issues = CheckResult.collect_issues(results)
34
- Issues.show_issues(issues, in_repl=state.in_repl)
35
-
36
- return issues if issues else 'issues'
37
-
38
- def show(check_results: list[CheckResult], in_repl = False):
39
- Issues.show_issues(CheckResult.collect_issues(check_results), in_repl=in_repl)
30
+ with self.validate(args, state) as (args, state):
31
+ with extract_options(args, ['-s', '--show']) as (args, show_out):
32
+ results = run_checks(state.sts, state.namespace, state.pod, show_out=show_out)
40
33
 
41
- def show_issues(issues: list[Issue], in_repl = False):
42
- if not issues:
43
- log2('No issues found.')
44
- else:
45
- suggested = 0
46
- log2(f'* {len(issues)} issues found.')
47
- lines = []
48
- for i, issue in enumerate(issues, start=1):
49
- lines.append(f"{i}||{issue.category}||{issue.desc}")
50
- lines.append(f"||statefulset||{issue.statefulset}@{issue.namespace}")
51
- lines.append(f"||pod||{issue.pod}@{issue.namespace}")
52
- if issue.details:
53
- lines.append(f"||details||{issue.details}")
34
+ issues = CheckResult.collect_issues(results)
35
+ IssuesUtils.show_issues(issues, in_repl=state.in_repl)
54
36
 
55
- if issue.suggestion:
56
- lines.append(f'||suggestion||{issue.suggestion}')
57
- if in_repl:
58
- ReplSession().prompt_session.history.append_string(issue.suggestion)
59
- suggested += 1
60
- log(lines_to_tabular(lines, separator='||'))
61
- if suggested:
62
- log2()
63
- log2(f'* {suggested} suggested commands are added to history. Press <Up> arrow to access them.')
37
+ return issues if issues else 'issues'
64
38
 
65
- def completion(self, _: ReplState):
66
- return {Issues.COMMAND: None}
39
+ def completion(self, state: ReplState):
40
+ return super().completion(state, {'-s': None})
67
41
 
68
42
  def help(self, _: ReplState):
69
- return f'{Issues.COMMAND}\t find all issues'
43
+ return f'{Issues.COMMAND} [-s]\t find all issues'
@@ -0,0 +1,38 @@
1
+ import subprocess
2
+
3
+ from adam.commands.command import Command
4
+ from adam.repl_state import ReplState, RequiredState
5
+
6
+ class Kubectl(Command):
7
+ COMMAND = 'k'
8
+
9
+ # the singleton pattern
10
+ def __new__(cls, *args, **kwargs):
11
+ if not hasattr(cls, 'instance'): cls.instance = super(Kubectl, 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 Kubectl.COMMAND
20
+
21
+ def required(self):
22
+ return RequiredState.NAMESPACE
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
+ subprocess.run(["kubectl"] + args)
30
+
31
+ return state
32
+
33
+ def completion(self, state: ReplState):
34
+ return super().completion(state)
35
+
36
+
37
+ def help(self, _: ReplState):
38
+ return f'{Kubectl.COMMAND} \t run a kubectl command'
adam/commands/login.py CHANGED
@@ -1,15 +1,15 @@
1
1
  import os
2
2
  import signal
3
- import traceback
4
3
 
5
4
  from adam.app_session import AppSession
6
5
  from adam.apps import Apps
6
+ from adam.commands import extract_options
7
7
  from adam.config import Config
8
8
  from adam.sso.idp import Idp
9
9
  from adam.sso.idp_login import IdpLogin
10
10
  from adam.commands.command import Command
11
11
  from adam.repl_state import ReplState
12
- from adam.utils import log, log2
12
+ from adam.utils import log, log2, log_exc
13
13
 
14
14
  class Login(Command):
15
15
  COMMAND = 'login'
@@ -26,41 +26,42 @@ class Login(Command):
26
26
  def command(self):
27
27
  return Login.COMMAND
28
28
 
29
+ def required(self):
30
+ return ReplState.NON_L
31
+
29
32
  def run(self, cmd: str, state: ReplState):
33
+ if not(args := self.args(cmd)):
34
+ return super().run(cmd, state)
35
+
30
36
  def custom_handler(signum, frame):
31
37
  AppSession.ctrl_c_entered = True
32
38
 
33
39
  signal.signal(signal.SIGINT, custom_handler)
34
40
 
35
- if not(args := self.args(cmd)):
36
- return super().run(cmd, state)
37
-
38
- state, args = self.apply_state(args, state)
39
- args, debug = Command.extract_options(args, ['d'])
40
- if debug:
41
- Config().set('debug', True)
41
+ with self.validate(args, state) as (args, state):
42
+ with extract_options(args, 'd') as (args, debug):
43
+ if debug:
44
+ Config().set('debug', True)
42
45
 
43
- username: str = os.getenv('USERNAME')
44
- if len(args) > 0:
45
- username = args[0]
46
+ username: str = os.getenv('USERNAME')
47
+ if len(args) > 0:
48
+ username = args[0]
46
49
 
47
- login: IdpLogin = None
48
- try:
49
- if not(host := Apps.app_host('c3', 'c3', state.namespace)):
50
- log2('Cannot locate ingress for app.')
51
- return state
50
+ login: IdpLogin = None
51
+ with log_exc(True):
52
+ if not(host := Apps.app_host('c3', 'c3', state.namespace)):
53
+ log2('Cannot locate ingress for app.')
54
+ return state
52
55
 
53
- if not (login := Idp.login(host, username=username, use_token_from_env=False)):
54
- log2('Invalid username/password. Please try again.')
55
- except:
56
- log2(traceback.format_exc())
56
+ if not (login := Idp.login(host, username=username, use_token_from_env=False)):
57
+ log2('Invalid username/password. Please try again.')
57
58
 
58
- log(f'IDP_TOKEN={login.ser() if login else ""}')
59
+ log(f'IDP_TOKEN={login.ser() if login else ""}')
59
60
 
60
- return state
61
+ return state
61
62
 
62
- def completion(self, _: ReplState):
63
- return {}
63
+ def completion(self, state: ReplState):
64
+ return super().completion(state)
64
65
 
65
66
  def help(self, _: ReplState):
66
67
  return f'{Login.COMMAND}\t SSO login'
adam/commands/ls.py CHANGED
@@ -1,20 +1,8 @@
1
1
  import copy
2
2
 
3
3
  from adam.commands.command import Command
4
- from adam.commands.commands_utils import show_pods, show_rollout
5
- from adam.commands.cql.cqlsh import Cqlsh
6
- from adam.commands.postgres.postgres_utils import pg_database_names, pg_table_names
7
- from adam.commands.postgres.postgres_session import PostgresSession
8
- from adam.config import Config
9
- from adam.utils_k8s.custom_resources import CustomResources
10
- from adam.utils_k8s.ingresses import Ingresses
11
- from adam.utils_k8s.kube_context import KubeContext
12
- from adam.utils_k8s.statefulsets import StatefulSets
13
- from adam.pod_exec_result import PodExecResult
4
+ from adam.commands.devices.devices import Devices
14
5
  from adam.repl_state import ReplState
15
- from adam.utils import lines_to_tabular, log, log2
16
- from adam.apps import Apps
17
- from adam.utils_athena import audit_table_names
18
6
 
19
7
  class Ls(Command):
20
8
  COMMAND = 'ls'
@@ -35,112 +23,19 @@ class Ls(Command):
35
23
  if not(args := self.args(cmd)):
36
24
  return super().run(cmd, state)
37
25
 
38
- state, args = self.apply_state(args, state)
26
+ with self.validate(args, state) as (args, state):
27
+ if len(args) > 0:
28
+ arg = args[0]
29
+ if arg in ['p:', 'c:'] and arg != f'{state.device}:':
30
+ state = copy.copy(state)
31
+ state.device = arg.replace(':', '')
39
32
 
40
- if len(args) > 0:
41
- arg = args[0]
42
- if arg in ['p:', 'c:'] and arg != f'{state.device}:':
43
- state = copy.copy(state)
44
- state.device = arg.replace(':', '')
33
+ Devices.of(state).ls(cmd, state)
45
34
 
46
- if state.device == ReplState.P:
47
- if state.pg_path:
48
- pg = PostgresSession(state.namespace, state.pg_path)
49
- if pg.db:
50
- self.show_pg_tables(pg)
51
- else:
52
- self.show_pg_databases(pg)
53
- else:
54
- self.show_pg_hosts(state)
55
- elif state.device == ReplState.A:
56
- if state.app_env:
57
- def line(n: str, ns: str):
58
- host = Ingresses.get_host(Config().get('app.login.ingress', '{app_id}-k8singr-appleader-001').replace('{app_id}', f'{ns}-{n}'), ns)
59
- if not host:
60
- return None
61
-
62
- endpoint = Config().get('app.login.url', 'https://{host}/{env}/{app}').replace('{host}', host).replace('{env}', state.app_env).replace('{app}', 'c3')
63
- if not endpoint:
64
- return None
65
-
66
- return f"{n.split('-')[1]},{Ingresses.get_host(f'{ns}-{n}-k8singr-appleader-001', ns)},{endpoint}"
67
-
68
- svcs = [l for l in [line(n, ns) for n, ns in Apps.apps(state.app_env)] if l]
69
-
70
- log(lines_to_tabular(svcs, 'APP,HOST,ENDPOINT', separator=','))
71
- else:
72
- svcs = [n for n, ns in Apps.envs()]
73
-
74
- log(lines_to_tabular(svcs, 'ENV', separator=','))
75
- elif state.device == ReplState.L:
76
- self.show_audit_log_tables()
77
- else:
78
- if state.pod:
79
- r: PodExecResult = Cqlsh().run(f'cql describe tables', state)
80
- if r.stderr:
81
- log(r.stderr)
82
- log(r.stdout)
83
- elif state.sts and state.namespace:
84
- show_pods(StatefulSets.pods(state.sts, state.namespace), state.namespace, show_namespace=not KubeContext.in_cluster_namespace())
85
- show_rollout(state.sts, state.namespace)
86
- else:
87
- self.show_statefulsets()
88
-
89
- return state
90
-
91
- def show_statefulsets(self):
92
- ss = StatefulSets.list_sts_names()
93
- if len(ss) == 0:
94
- log2('No cassandra statefulsets found.')
95
- return
96
-
97
- app_ids = CustomResources.get_app_ids()
98
- list = []
99
- for s in ss:
100
- cr_name = CustomResources.get_cr_name(s)
101
- app_id = 'Unknown'
102
- if cr_name in app_ids:
103
- app_id = app_ids[cr_name]
104
- list.append(f"{s} {app_id}")
105
-
106
- header = 'STATEFULSET_NAME@NAMESPACE APP_ID'
107
- if KubeContext.in_cluster_namespace():
108
- header = 'STATEFULSET_NAME APP_ID'
109
- log(lines_to_tabular(list, header))
110
-
111
- def show_pg_hosts(self, state: ReplState):
112
- if state.namespace:
113
- def line(pg: PostgresSession):
114
- return f'{pg.directory()},{pg.endpoint()}:{pg.port()},{pg.username()},{pg.password()}'
115
-
116
- lines = [line(PostgresSession(state.namespace, pg)) for pg in PostgresSession.hosts(state.namespace)]
117
-
118
- log(lines_to_tabular(lines, 'NAME,ENDPOINT,USERNAME,PASSWORD', separator=','))
119
- else:
120
- def line(pg: PostgresSession):
121
- return f'{pg.directory()},{pg.namespace},{pg.endpoint()}:{pg.port()},{pg.username()},{pg.password()}'
122
-
123
- lines = [line(PostgresSession(state.namespace, pg)) for pg in PostgresSession.hosts(state.namespace)]
124
-
125
- log(lines_to_tabular(lines, 'NAME,NAMESPACE,ENDPOINT,USERNAME,PASSWORD', separator=','))
126
-
127
- def show_pg_databases(self, pg: PostgresSession):
128
- log(lines_to_tabular(pg_database_names(pg.namespace, pg.directory()), 'DATABASE', separator=','))
129
-
130
- def show_pg_tables(self, pg: PostgresSession):
131
- log(lines_to_tabular(pg_table_names(pg.namespace, pg.directory()), 'NAME', separator=','))
132
-
133
- def show_audit_log_tables(self):
134
- log(lines_to_tabular(audit_table_names(), 'NAME', separator=','))
35
+ return state
135
36
 
136
37
  def completion(self, state: ReplState):
137
- if state.pod:
138
- return {}
139
-
140
- if state.device == ReplState.C and not state.sts:
141
- return {Ls.COMMAND: {n: None for n in StatefulSets.list_sts_names()}}
142
-
143
- return {Ls.COMMAND: None}
38
+ return super().completion(state, {'&': None}, pods=Devices.of(state).pods(state, '-'))
144
39
 
145
40
  def help(self, _: ReplState):
146
- return f'{Ls.COMMAND} [device:]\t list apps, envs, clusters, nodes, pg hosts or pg databases'
41
+ return f'{Ls.COMMAND} [device:]\t list apps, envs, clusters, nodes, pg hosts/databases or export databases'
@@ -1,13 +1,13 @@
1
1
  import click
2
2
 
3
3
  from adam.commands.command import Command
4
+ from adam.commands.intermediate_command import IntermediateCommand
4
5
  from .medusa_backup import MedusaBackup
5
6
  from .medusa_restore import MedusaRestore
6
7
  from .medusa_show_backupjobs import MedusaShowBackupJobs
7
8
  from .medusa_show_restorejobs import MedusaShowRestoreJobs
8
- from adam.repl_state import ReplState, RequiredState
9
9
 
10
- class Medusa(Command):
10
+ class Medusa(IntermediateCommand):
11
11
  COMMAND = 'medusa'
12
12
 
13
13
  # the singleton pattern
@@ -16,30 +16,12 @@ class Medusa(Command):
16
16
 
17
17
  return cls.instance
18
18
 
19
- def __init__(self, successor: Command=None):
20
- super().__init__(successor)
21
-
22
19
  def command(self):
23
20
  return Medusa.COMMAND
24
21
 
25
- def required(self):
26
- return RequiredState.CLUSTER
27
-
28
- def run(self, cmd: str, state: ReplState):
29
- if not(args := self.args(cmd)):
30
- return super().run(cmd, state)
31
-
32
- return super().intermediate_run(cmd, state, args, Medusa.cmd_list())
33
-
34
- def cmd_list():
22
+ def cmd_list(self):
35
23
  return [MedusaBackup(), MedusaRestore(), MedusaShowBackupJobs(), MedusaShowRestoreJobs()]
36
24
 
37
- def completion(self, state: ReplState):
38
- if state.sts:
39
- return super().completion(state)
40
-
41
- return {}
42
-
43
25
  class MedusaCommandHelper(click.Command):
44
26
  def get_help(self, ctx: click.Context):
45
- Command.intermediate_help(super().get_help(ctx), Medusa.COMMAND, Medusa.cmd_list(), show_cluster_help=True)
27
+ IntermediateCommand.intermediate_help(super().get_help(ctx), Medusa.COMMAND, Medusa().cmd_list(), show_cluster_help=True)
@@ -1,13 +1,12 @@
1
1
  from datetime import datetime
2
- import re
3
2
 
3
+ from adam.commands import validate_args
4
4
  from adam.commands.command import Command
5
5
  from adam.utils_k8s.statefulsets import StatefulSets
6
6
  from adam.repl_state import ReplState, RequiredState
7
7
  from adam.utils_k8s.custom_resources import CustomResources
8
8
  from adam.utils import log2
9
9
 
10
-
11
10
  class MedusaBackup(Command):
12
11
  COMMAND = 'backup'
13
12
 
@@ -29,33 +28,27 @@ class MedusaBackup(Command):
29
28
  def run(self, cmd: str, state: ReplState):
30
29
  if not(args := self.args(cmd)):
31
30
  return super().run(cmd, state)
32
- state, args = self.apply_state(args, state)
33
- if not self.validate_state(state):
34
- return state
35
-
36
- ns = state.namespace
37
- sts = state.sts
38
- now_dtformat = datetime.now().strftime("%Y-%m-%d.%H.%M.%S")
39
- bkname = 'medusa-' + now_dtformat + 'full-backup-' + sts
40
- if len(args) == 1:
41
- bkname = str(args[0])
42
- groups = re.match(r'^(.*?-.*?-).*', sts)
43
- dc = StatefulSets.get_datacenter(state.sts, ns)
44
- if not dc:
45
- return state
46
-
47
- try:
48
- CustomResources.create_medusa_backupjob(bkname, dc, ns)
49
- except Exception as e:
50
- log2("Exception: MedusaBackup failed: %s\n" % e)
51
-
52
- return state
53
31
 
54
- def completion(self, state: ReplState):
55
- if state.sts:
56
- return super().completion(state)
32
+ with self.validate(args, state) as (args, state):
33
+ ns = state.namespace
34
+ sts = state.sts
35
+ now_dtformat = datetime.now().strftime("%Y-%m-%d.%H.%M.%S")
36
+ with validate_args(args, state, default='medusa-' + now_dtformat + 'full-backup-' + sts) as bkname:
37
+ dc = StatefulSets.get_datacenter(state.sts, ns)
38
+ if not dc:
39
+ return state
40
+
41
+ try:
42
+ CustomResources.create_medusa_backupjob(bkname, dc, ns)
43
+ except Exception as e:
44
+ log2("Exception: MedusaBackup failed: %s\n" % e)
45
+ finally:
46
+ CustomResources.clear_caches()
57
47
 
58
- return {}
48
+ return state
49
+
50
+ def completion(self, state: ReplState):
51
+ return super().completion(state)
59
52
 
60
53
  def help(self, _: ReplState):
61
54
  return f'{MedusaBackup.COMMAND}\t start a backup job'
@@ -1,11 +1,13 @@
1
1
  from datetime import datetime
2
+ from functools import partial
2
3
 
3
- from adam.commands.command import Command
4
+ from adam.commands import validate_args
5
+ from adam.commands.command import Command, InvalidArgumentsException
6
+ from adam.commands.medusa.utils_medusa import medusa_backup_names
4
7
  from adam.utils_k8s.statefulsets import StatefulSets
5
8
  from adam.repl_state import ReplState, RequiredState
6
9
  from adam.utils_k8s.custom_resources import CustomResources
7
- from adam.config import Config
8
- from adam.utils import lines_to_tabular, log2
10
+ from adam.utils import tabulize, log2, log_exc
9
11
 
10
12
  class MedusaRestore(Command):
11
13
  COMMAND = 'restore'
@@ -28,58 +30,43 @@ class MedusaRestore(Command):
28
30
  def run(self, cmd: str, state: ReplState):
29
31
  if not(args := self.args(cmd)):
30
32
  return super().run(cmd, state)
31
- state, args = self.apply_state(args, state)
32
- if not self.validate_state(state):
33
- return state
34
-
35
- ns = state.namespace
36
- dc = StatefulSets.get_datacenter(state.sts, ns)
37
- if not dc:
38
- return state
39
-
40
- if len(args) == 1:
41
- bkname = args[0]
42
- job = CustomResources.medusa_get_backupjob(dc, ns, bkname)
43
- if not job:
44
- log2('\n* Backup job name is not valid.')
45
- bklist = [f"{x['metadata']['name']}\t{x['metadata']['creationTimestamp']}\t{x['status'].get('finishTime', '')}" for x in CustomResources.medusa_show_backupjobs(dc, ns)]
46
- log2(lines_to_tabular(bklist, 'NAME\tCREATED\tFINISHED', separator='\t'))
47
33
 
34
+ with self.validate(args, state) as (args, state):
35
+ ns = state.namespace
36
+ dc: str = StatefulSets.get_datacenter(state.sts, ns)
37
+ if not dc:
48
38
  return state
49
39
 
50
- if not input(f"Restoring from {bkname} created at {job['metadata']['creationTimestamp']}. Please enter Yes to continue: ").lower() in ['y', 'yes']:
51
- return state
52
- else:
53
- bklist = [f"{x['metadata']['name']}\t{x['metadata']['creationTimestamp']}\t{x['status'].get('finishTime', '')}" for x in CustomResources.medusa_show_backupjobs(dc, ns)]
54
- log2('\n* Missing Backup Name')
55
- log2('Usage: qing medusa restore <backup> <sts@name_space>\n')
56
- log2(lines_to_tabular(bklist, 'NAME\tCREATED\tFINISHED', separator='\t'))
57
- return state
58
-
59
- now_dtformat = datetime.now().strftime("%Y-%m-%d.%H.%M.%S")
60
- rtname = 'medusa-' + now_dtformat + '-restore-from-' + bkname
61
- try:
62
- CustomResources.create_medusa_restorejob(rtname, bkname, dc, ns)
63
- except Exception as e:
64
- log2("Exception: MedusaRestore failed: %s\n" % e)
65
-
66
- return state
40
+ def msg(missing: bool):
41
+ if missing:
42
+ log2('\n* Missing Backup Name')
43
+ log2('Usage: qing restore <backup> <sts@name_space>\n')
44
+ else:
45
+ log2('\n* Backup job name is not valid.')
67
46
 
68
- def completion(self, state: ReplState):
69
- if state.sts:
70
- ns = state.namespace
71
- dc = StatefulSets.get_datacenter(state.sts, ns)
72
- if not dc:
73
- return {}
47
+ tabulize(CustomResources.medusa_show_backupjobs(dc, ns),
48
+ lambda x: f"{x['metadata']['name']}\t{x['metadata']['creationTimestamp']}\t{x['status'].get('finishTime', '')}",
49
+ header='NAME\tCREATED\tFINISHED',
50
+ separator='\t',
51
+ to=2)
52
+
53
+ with validate_args(args, state, msg=partial(msg, True)) as bkname:
54
+ if not (job := CustomResources.medusa_get_backupjob(dc, ns, bkname)):
55
+ msg(False)
56
+ raise InvalidArgumentsException()
74
57
 
75
- if Config().get('medusa.restore-auto-complete', False):
76
- leaf = {id: None for id in [f"{x['metadata']['name']}" for x in CustomResources.medusa_show_backupjobs(dc, ns)]}
58
+ if not input(f"Restoring from {bkname} created at {job['metadata']['creationTimestamp']}. Please enter Yes to continue: ").lower() in ['y', 'yes']:
59
+ return state
77
60
 
78
- return super().completion(state, leaf)
79
- else:
80
- return super().completion(state)
61
+ with log_exc(lambda e: "Exception: MedusaRestore failed: %s\n" % e):
62
+ now_dtformat = datetime.now().strftime("%Y-%m-%d.%H.%M.%S")
63
+ rtname = 'medusa-' + now_dtformat + '-restore-from-' + bkname
64
+ CustomResources.create_medusa_restorejob(rtname, bkname, dc, ns)
81
65
 
82
- return {}
66
+ return state
67
+
68
+ def completion(self, state: ReplState):
69
+ return super().completion(state, lambda: {id: None for id in medusa_backup_names(state)}, auto_key='medusa.backups')
83
70
 
84
71
  def help(self, _: ReplState):
85
72
  return f'{MedusaRestore.COMMAND}\t start a restore job'
@@ -2,7 +2,7 @@ from adam.commands.command import Command
2
2
  from adam.utils_k8s.statefulsets import StatefulSets
3
3
  from adam.repl_state import ReplState, RequiredState
4
4
  from adam.utils_k8s.custom_resources import CustomResources
5
- from adam.utils import lines_to_tabular, log2
5
+ from adam.utils import tabulize, log_exc
6
6
 
7
7
 
8
8
  class MedusaShowBackupJobs(Command):
@@ -26,27 +26,26 @@ class MedusaShowBackupJobs(Command):
26
26
  def run(self, cmd: str, state: ReplState):
27
27
  if not(args := self.args(cmd)):
28
28
  return super().run(cmd, state)
29
- state, args = self.apply_state(args, state)
30
- if not self.validate_state(state):
31
- return state
32
- ns = state.namespace
33
- dc = StatefulSets.get_datacenter(state.sts, ns)
34
- if not dc:
35
- return state
36
29
 
37
- try:
38
- bklist = [f"{x['metadata']['name']}\t{x['metadata']['creationTimestamp']}\t{x['status'].get('finishTime', '')}" for x in CustomResources.medusa_show_backupjobs(dc, ns)]
39
- log2(lines_to_tabular(bklist, 'NAME\tCREATED\tFINISHED', separator='\t'))
40
- except Exception as e:
41
- log2("Exception: MedusaShowBackupJobs failed: %s\n" % e)
30
+ with self.validate(args, state) as (args, state):
31
+ ns = state.namespace
32
+ dc = StatefulSets.get_datacenter(state.sts, ns)
33
+ if not dc:
34
+ return state
42
35
 
43
- return state
36
+ with log_exc(lambda e: "Exception: MedusaShowBackupJobs failed: %s\n" % e):
37
+ CustomResources.clear_caches()
44
38
 
45
- def completion(self, state: ReplState):
46
- if state.sts:
47
- return super().completion(state)
39
+ tabulize(CustomResources.medusa_show_backupjobs(dc, ns),
40
+ lambda x: f"{x['metadata']['name']}\t{x['metadata']['creationTimestamp']}\t{x['status'].get('finishTime', '') if 'status' in x else 'unknown'}",
41
+ header='NAME\tCREATED\tFINISHED',
42
+ separator='\t',
43
+ to=2)
48
44
 
49
- return {}
45
+ return state
46
+
47
+ def completion(self, state: ReplState):
48
+ return super().completion(state)
50
49
 
51
50
  def help(self, _: ReplState):
52
51
  return f'{MedusaShowBackupJobs.COMMAND}\t show Medusa backups'
@@ -2,7 +2,7 @@ from adam.commands.command import Command
2
2
  from adam.utils_k8s.statefulsets import StatefulSets
3
3
  from adam.repl_state import ReplState, RequiredState
4
4
  from adam.utils_k8s.custom_resources import CustomResources
5
- from adam.utils import lines_to_tabular, log2
5
+ from adam.utils import tabulize, log_exc
6
6
 
7
7
  class MedusaShowRestoreJobs(Command):
8
8
  COMMAND = 'show restores'
@@ -25,28 +25,23 @@ class MedusaShowRestoreJobs(Command):
25
25
  def run(self, cmd: str, state: ReplState):
26
26
  if not(args := self.args(cmd)):
27
27
  return super().run(cmd, state)
28
- state, args = self.apply_state(args, state)
29
- if not self.validate_state(state):
30
- return state
31
28
 
32
- ns = state.namespace
33
- dc = StatefulSets.get_datacenter(state.sts, ns)
34
- if not dc:
35
- return state
29
+ with self.validate(args, state) as (args, state):
30
+ ns = state.namespace
31
+ dc = StatefulSets.get_datacenter(state.sts, ns)
32
+ if not dc:
33
+ return state
36
34
 
37
- try:
38
- rtlist = CustomResources.medusa_show_restorejobs(dc, ns)
39
- log2(lines_to_tabular(rtlist, 'NAME\tCREATED\tFINISHED', separator='\t'))
40
- except Exception as e:
41
- log2("Exception: MedusaShowRestoreJobs failed: %s\n" % e)
35
+ with log_exc(lambda e: "Exception: MedusaShowRestoreJobs failed: %s\n" % e):
36
+ tabulize(CustomResources.medusa_show_restorejobs(dc, ns),
37
+ header='NAME\tCREATED\tFINISHED',
38
+ separator='\t',
39
+ to=2)
42
40
 
43
- return state
41
+ return state
44
42
 
45
43
  def completion(self, state: ReplState):
46
- if state.sts:
47
- return super().completion(state)
48
-
49
- return {}
44
+ return super().completion(state)
50
45
 
51
46
  def help(self, _: ReplState):
52
47
  return f'{MedusaShowRestoreJobs.COMMAND}\t show Medusa restores'