kaqing 2.0.98__py3-none-any.whl → 2.0.171__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 (194) hide show
  1. adam/__init__.py +0 -2
  2. adam/app_session.py +9 -7
  3. adam/batch.py +4 -18
  4. adam/checks/check_utils.py +14 -46
  5. adam/checks/cpu.py +7 -1
  6. adam/checks/cpu_metrics.py +52 -0
  7. adam/columns/columns.py +3 -1
  8. adam/columns/cpu.py +3 -1
  9. adam/columns/cpu_metrics.py +22 -0
  10. adam/commands/__init__.py +15 -0
  11. adam/commands/alter_tables.py +50 -61
  12. adam/commands/app_cmd.py +38 -0
  13. adam/commands/app_ping.py +8 -14
  14. adam/commands/audit/audit.py +43 -30
  15. adam/commands/audit/audit_repair_tables.py +26 -46
  16. adam/commands/audit/audit_run.py +50 -0
  17. adam/commands/audit/show_last10.py +48 -0
  18. adam/commands/audit/show_slow10.py +47 -0
  19. adam/commands/audit/show_top10.py +45 -0
  20. adam/commands/audit/utils_show_top10.py +59 -0
  21. adam/commands/bash/__init__.py +5 -0
  22. adam/commands/bash/bash.py +36 -0
  23. adam/commands/bash/bash_completer.py +93 -0
  24. adam/commands/bash/utils_bash.py +16 -0
  25. adam/commands/cat.py +50 -0
  26. adam/commands/cd.py +15 -91
  27. adam/commands/check.py +23 -18
  28. adam/commands/cli_commands.py +2 -3
  29. adam/commands/code.py +57 -0
  30. adam/commands/command.py +96 -40
  31. adam/commands/commands_utils.py +9 -19
  32. adam/commands/cp.py +33 -39
  33. adam/commands/cql/cql_completions.py +30 -8
  34. adam/commands/cql/cqlsh.py +12 -27
  35. adam/commands/cql/utils_cql.py +343 -0
  36. adam/commands/deploy/code_start.py +7 -10
  37. adam/commands/deploy/code_stop.py +4 -21
  38. adam/commands/deploy/code_utils.py +3 -3
  39. adam/commands/deploy/deploy.py +4 -21
  40. adam/commands/deploy/deploy_frontend.py +14 -17
  41. adam/commands/deploy/deploy_pg_agent.py +3 -6
  42. adam/commands/deploy/deploy_pod.py +67 -73
  43. adam/commands/deploy/deploy_utils.py +14 -24
  44. adam/commands/deploy/undeploy.py +4 -21
  45. adam/commands/deploy/undeploy_frontend.py +4 -7
  46. adam/commands/deploy/undeploy_pg_agent.py +6 -8
  47. adam/commands/deploy/undeploy_pod.py +11 -12
  48. adam/commands/devices/device.py +118 -0
  49. adam/commands/devices/device_app.py +173 -0
  50. adam/commands/devices/device_auit_log.py +49 -0
  51. adam/commands/devices/device_cass.py +185 -0
  52. adam/commands/devices/device_export.py +86 -0
  53. adam/commands/devices/device_postgres.py +144 -0
  54. adam/commands/devices/devices.py +25 -0
  55. adam/commands/exit.py +1 -4
  56. adam/commands/export/__init__.py +0 -0
  57. adam/commands/export/clean_up_all_export_sessions.py +37 -0
  58. adam/commands/export/clean_up_export_sessions.py +51 -0
  59. adam/commands/export/drop_export_database.py +55 -0
  60. adam/commands/export/drop_export_databases.py +43 -0
  61. adam/commands/export/export.py +53 -0
  62. adam/commands/export/export_databases.py +170 -0
  63. adam/commands/export/export_handlers.py +71 -0
  64. adam/commands/export/export_select.py +81 -0
  65. adam/commands/export/export_select_x.py +54 -0
  66. adam/commands/export/export_use.py +52 -0
  67. adam/commands/export/exporter.py +352 -0
  68. adam/commands/export/import_session.py +40 -0
  69. adam/commands/export/importer.py +67 -0
  70. adam/commands/export/importer_athena.py +80 -0
  71. adam/commands/export/importer_sqlite.py +47 -0
  72. adam/commands/export/show_column_counts.py +54 -0
  73. adam/commands/export/show_export_databases.py +36 -0
  74. adam/commands/export/show_export_session.py +48 -0
  75. adam/commands/export/show_export_sessions.py +44 -0
  76. adam/commands/export/utils_export.py +314 -0
  77. adam/commands/help.py +10 -6
  78. adam/commands/intermediate_command.py +49 -0
  79. adam/commands/issues.py +14 -40
  80. adam/commands/kubectl.py +38 -0
  81. adam/commands/login.py +28 -24
  82. adam/commands/logs.py +4 -6
  83. adam/commands/ls.py +11 -116
  84. adam/commands/medusa/medusa.py +4 -22
  85. adam/commands/medusa/medusa_backup.py +20 -24
  86. adam/commands/medusa/medusa_restore.py +30 -32
  87. adam/commands/medusa/medusa_show_backupjobs.py +16 -17
  88. adam/commands/medusa/medusa_show_restorejobs.py +12 -17
  89. adam/commands/nodetool.py +11 -17
  90. adam/commands/param_get.py +11 -12
  91. adam/commands/param_set.py +9 -10
  92. adam/commands/postgres/postgres.py +43 -36
  93. adam/commands/postgres/{postgres_session.py → postgres_context.py} +80 -46
  94. adam/commands/postgres/postgres_ls.py +4 -8
  95. adam/commands/postgres/postgres_preview.py +5 -9
  96. adam/commands/postgres/psql_completions.py +2 -2
  97. adam/commands/postgres/utils_postgres.py +66 -0
  98. adam/commands/preview_table.py +8 -61
  99. adam/commands/pwd.py +14 -44
  100. adam/commands/reaper/reaper.py +4 -24
  101. adam/commands/reaper/reaper_forward.py +48 -55
  102. adam/commands/reaper/reaper_forward_session.py +6 -0
  103. adam/commands/reaper/reaper_forward_stop.py +10 -16
  104. adam/commands/reaper/reaper_restart.py +7 -14
  105. adam/commands/reaper/reaper_run_abort.py +11 -30
  106. adam/commands/reaper/reaper_runs.py +42 -57
  107. adam/commands/reaper/reaper_runs_abort.py +29 -49
  108. adam/commands/reaper/reaper_schedule_activate.py +11 -30
  109. adam/commands/reaper/reaper_schedule_start.py +10 -29
  110. adam/commands/reaper/reaper_schedule_stop.py +10 -29
  111. adam/commands/reaper/reaper_schedules.py +4 -14
  112. adam/commands/reaper/reaper_status.py +8 -16
  113. adam/commands/reaper/utils_reaper.py +196 -0
  114. adam/commands/repair/repair.py +4 -22
  115. adam/commands/repair/repair_log.py +4 -7
  116. adam/commands/repair/repair_run.py +27 -29
  117. adam/commands/repair/repair_scan.py +31 -34
  118. adam/commands/repair/repair_stop.py +4 -7
  119. adam/commands/report.py +25 -21
  120. adam/commands/restart.py +25 -26
  121. adam/commands/rollout.py +19 -24
  122. adam/commands/shell.py +5 -4
  123. adam/commands/show/show.py +6 -19
  124. adam/commands/show/show_app_actions.py +26 -22
  125. adam/commands/show/show_app_id.py +8 -11
  126. adam/commands/show/show_app_queues.py +7 -10
  127. adam/commands/show/{show_repairs.py → show_cassandra_repairs.py} +8 -17
  128. adam/commands/show/show_cassandra_status.py +29 -33
  129. adam/commands/show/show_cassandra_version.py +4 -14
  130. adam/commands/show/show_commands.py +19 -21
  131. adam/commands/show/show_host.py +1 -1
  132. adam/commands/show/show_login.py +26 -24
  133. adam/commands/show/show_processes.py +16 -18
  134. adam/commands/show/show_storage.py +10 -20
  135. adam/commands/watch.py +26 -29
  136. adam/config.py +5 -14
  137. adam/embedded_params.py +1 -1
  138. adam/pod_exec_result.py +7 -1
  139. adam/repl.py +95 -131
  140. adam/repl_commands.py +48 -20
  141. adam/repl_state.py +270 -61
  142. adam/sql/sql_completer.py +105 -63
  143. adam/sql/sql_state_machine.py +618 -0
  144. adam/sql/term_completer.py +3 -0
  145. adam/sso/authn_ad.py +6 -5
  146. adam/sso/authn_okta.py +3 -3
  147. adam/sso/cred_cache.py +3 -2
  148. adam/sso/idp.py +3 -3
  149. adam/utils.py +439 -3
  150. adam/utils_app.py +98 -0
  151. adam/utils_athena.py +140 -87
  152. adam/utils_audits.py +106 -0
  153. adam/utils_issues.py +32 -0
  154. adam/utils_k8s/app_clusters.py +28 -0
  155. adam/utils_k8s/app_pods.py +33 -0
  156. adam/utils_k8s/cassandra_clusters.py +22 -20
  157. adam/utils_k8s/cassandra_nodes.py +4 -4
  158. adam/utils_k8s/custom_resources.py +5 -0
  159. adam/utils_k8s/ingresses.py +2 -2
  160. adam/utils_k8s/k8s.py +87 -0
  161. adam/utils_k8s/pods.py +77 -68
  162. adam/utils_k8s/secrets.py +4 -4
  163. adam/utils_k8s/service_accounts.py +5 -4
  164. adam/utils_k8s/services.py +2 -2
  165. adam/utils_k8s/statefulsets.py +1 -12
  166. adam/utils_net.py +4 -4
  167. adam/utils_repl/__init__.py +0 -0
  168. adam/utils_repl/automata_completer.py +48 -0
  169. adam/utils_repl/repl_completer.py +46 -0
  170. adam/utils_repl/state_machine.py +173 -0
  171. adam/utils_sqlite.py +109 -0
  172. adam/version.py +1 -1
  173. {kaqing-2.0.98.dist-info → kaqing-2.0.171.dist-info}/METADATA +1 -1
  174. kaqing-2.0.171.dist-info/RECORD +236 -0
  175. adam/commands/app.py +0 -67
  176. adam/commands/bash.py +0 -92
  177. adam/commands/cql/cql_table_completer.py +0 -8
  178. adam/commands/cql/cql_utils.py +0 -115
  179. adam/commands/describe/describe.py +0 -47
  180. adam/commands/describe/describe_keyspace.py +0 -60
  181. adam/commands/describe/describe_keyspaces.py +0 -49
  182. adam/commands/describe/describe_schema.py +0 -49
  183. adam/commands/describe/describe_table.py +0 -60
  184. adam/commands/describe/describe_tables.py +0 -49
  185. adam/commands/devices.py +0 -118
  186. adam/commands/postgres/postgres_utils.py +0 -31
  187. adam/commands/postgres/psql_table_completer.py +0 -11
  188. adam/commands/reaper/reaper_session.py +0 -159
  189. adam/sql/state_machine.py +0 -460
  190. kaqing-2.0.98.dist-info/RECORD +0 -191
  191. /adam/commands/{describe → devices}/__init__.py +0 -0
  192. {kaqing-2.0.98.dist-info → kaqing-2.0.171.dist-info}/WHEEL +0 -0
  193. {kaqing-2.0.98.dist-info → kaqing-2.0.171.dist-info}/entry_points.txt +0 -0
  194. {kaqing-2.0.98.dist-info → kaqing-2.0.171.dist-info}/top_level.txt +0 -0
adam/commands/logs.py CHANGED
@@ -25,14 +25,12 @@ class Logs(Command):
25
25
  if not(args := self.args(cmd)):
26
26
  return super().run(cmd, state)
27
27
 
28
- state, args = self.apply_state(args, state)
29
- if not self.validate_state(state):
30
- return state
31
-
32
- path = Config().get('logs.path', '/c3/cassandra/logs/system.log')
33
- return CassandraNodes.exec(state.pod, state.namespace, f'cat {path}')
28
+ with self.validate(args, state) as (args, state):
29
+ path = Config().get('logs.path', '/c3/cassandra/logs/system.log')
30
+ return CassandraNodes.exec(state.pod, state.namespace, f'cat {path}')
34
31
 
35
32
  def completion(self, _: ReplState):
33
+ # available only on cli
36
34
  return {}
37
35
 
38
36
  def help(self, _: ReplState):
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.device(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 Devices.device(state).ls_completion(Ls.COMMAND, state, default = super().completion(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)
@@ -7,7 +7,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,30 @@ 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
31
 
47
- try:
48
- CustomResources.create_medusa_backupjob(bkname, dc, ns)
49
- except Exception as e:
50
- log2("Exception: MedusaBackup failed: %s\n" % e)
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
+ bkname = 'medusa-' + now_dtformat + 'full-backup-' + sts
37
+ if len(args) == 1:
38
+ bkname = str(args[0])
39
+ groups = re.match(r'^(.*?-.*?-).*', sts)
40
+ dc = StatefulSets.get_datacenter(state.sts, ns)
41
+ if not dc:
42
+ return state
43
+
44
+ try:
45
+ CustomResources.create_medusa_backupjob(bkname, dc, ns)
46
+ except Exception as e:
47
+ log2("Exception: MedusaBackup failed: %s\n" % e)
48
+ finally:
49
+ CustomResources.clear_caches()
51
50
 
52
- return state
51
+ return state
53
52
 
54
53
  def completion(self, state: ReplState):
55
- if state.sts:
56
- return super().completion(state)
57
-
58
- return {}
54
+ return super().completion(state)
59
55
 
60
56
  def help(self, _: ReplState):
61
57
  return f'{MedusaBackup.COMMAND}\t start a backup job'
@@ -28,47 +28,45 @@ class MedusaRestore(Command):
28
28
  def run(self, cmd: str, state: ReplState):
29
29
  if not(args := self.args(cmd)):
30
30
  return super().run(cmd, state)
31
- state, args = self.apply_state(args, state)
32
- if not self.validate_state(state):
33
- return state
34
31
 
35
- ns = state.namespace
36
- dc = StatefulSets.get_datacenter(state.sts, ns)
37
- if not dc:
38
- return state
32
+ with self.validate(args, state) as (args, state):
33
+ ns = state.namespace
34
+ dc: str = StatefulSets.get_datacenter(state.sts, ns)
35
+ if not dc:
36
+ return state
39
37
 
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'))
38
+ if len(args) == 1:
39
+ bkname = args[0]
40
+ job = CustomResources.medusa_get_backupjob(dc, ns, bkname)
41
+ if not job:
42
+ log2('\n* Backup job name is not valid.')
43
+ bklist = [f"{x['metadata']['name']}\t{x['metadata']['creationTimestamp']}\t{x['status'].get('finishTime', '')}" for x in CustomResources.medusa_show_backupjobs(dc, ns)]
44
+ log2(lines_to_tabular(bklist, 'NAME\tCREATED\tFINISHED', separator='\t'))
47
45
 
48
- return state
46
+ return state
49
47
 
50
- if not input(f"Restoring from {bkname} created at {job['metadata']['creationTimestamp']}. Please enter Yes to continue: ").lower() in ['y', 'yes']:
48
+ if not input(f"Restoring from {bkname} created at {job['metadata']['creationTimestamp']}. Please enter Yes to continue: ").lower() in ['y', 'yes']:
49
+ return state
50
+ else:
51
+ bklist = [f"{x['metadata']['name']}\t{x['metadata']['creationTimestamp']}\t{x['status'].get('finishTime', '')}" for x in CustomResources.medusa_show_backupjobs(dc, ns)]
52
+ log2('\n* Missing Backup Name')
53
+ log2('Usage: qing medusa restore <backup> <sts@name_space>\n')
54
+ log2(lines_to_tabular(bklist, 'NAME\tCREATED\tFINISHED', separator='\t'))
51
55
  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
56
 
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)
57
+ now_dtformat = datetime.now().strftime("%Y-%m-%d.%H.%M.%S")
58
+ rtname = 'medusa-' + now_dtformat + '-restore-from-' + bkname
59
+ try:
60
+ CustomResources.create_medusa_restorejob(rtname, bkname, dc, ns)
61
+ except Exception as e:
62
+ log2("Exception: MedusaRestore failed: %s\n" % e)
65
63
 
66
- return state
64
+ return state
67
65
 
68
66
  def completion(self, state: ReplState):
69
- if state.sts:
67
+ if sc := super().completion(state):
70
68
  ns = state.namespace
71
- dc = StatefulSets.get_datacenter(state.sts, ns)
69
+ dc: str = StatefulSets.get_datacenter(state.sts, ns)
72
70
  if not dc:
73
71
  return {}
74
72
 
@@ -77,7 +75,7 @@ class MedusaRestore(Command):
77
75
 
78
76
  return super().completion(state, leaf)
79
77
  else:
80
- return super().completion(state)
78
+ return sc
81
79
 
82
80
  return {}
83
81
 
@@ -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
+ try:
37
+ # always show latest
38
+ CustomResources.clear_caches()
44
39
 
45
- def completion(self, state: ReplState):
46
- if state.sts:
47
- return super().completion(state)
40
+ bklist = [f"{x['metadata']['name']}\t{x['metadata']['creationTimestamp']}\t{x['status'].get('finishTime', '') if 'status' in x else 'unknown'}" for x in CustomResources.medusa_show_backupjobs(dc, ns)]
41
+ log2(lines_to_tabular(bklist, 'NAME\tCREATED\tFINISHED', separator='\t'))
42
+ except Exception as e:
43
+ log2("Exception: MedusaShowBackupJobs failed: %s\n" % e)
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'
@@ -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
+ try:
36
+ rtlist = CustomResources.medusa_show_restorejobs(dc, ns)
37
+ log2(lines_to_tabular(rtlist, 'NAME\tCREATED\tFINISHED', separator='\t'))
38
+ except Exception as e:
39
+ log2("Exception: MedusaShowRestoreJobs failed: %s\n" % e)
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'
adam/commands/nodetool.py CHANGED
@@ -2,12 +2,12 @@ import click
2
2
 
3
3
  from adam.commands.command import Command
4
4
  from adam.commands.command_helpers import ClusterOrPodCommandHelper
5
+ from adam.commands.cql.utils_cql import cassandra
5
6
  from adam.commands.nodetool_commands import NODETOOL_COMMANDS
6
7
  from adam.config import Config
7
- from adam.utils_k8s.cassandra_clusters import CassandraClusters
8
- from adam.utils_k8s.cassandra_nodes import CassandraNodes
9
8
  from adam.repl_state import ReplState, RequiredState
10
9
  from adam.utils import log
10
+ from adam.utils_k8s.statefulsets import StatefulSets
11
11
 
12
12
  class NodeTool(Command):
13
13
  COMMAND = 'nodetool'
@@ -31,28 +31,22 @@ class NodeTool(Command):
31
31
  if not(args := self.args(cmd)):
32
32
  return super().run(cmd, state)
33
33
 
34
- state, args = self.apply_state(args, state)
35
- if not self.validate_state(state):
36
- return state
37
-
38
- user, pw = state.user_pass()
39
- command = f"nodetool -u {user} -pw {pw} {' '.join(args)}"
34
+ with self.validate(args, state) as (args, state):
35
+ with cassandra(state) as pods:
36
+ pods.nodetool(' '.join(args))
40
37
 
41
- if state.pod:
42
- return CassandraNodes.exec(state.pod, state.namespace, command, show_out=True)
43
- elif state.sts:
44
- return CassandraClusters.exec(state.sts, state.namespace, command, action='nodetool', show_out=True)
45
-
46
- return state
38
+ return state
47
39
 
48
40
  def completion(self, state: ReplState):
49
- if state.pod or state.sts:
50
- return {NodeTool.COMMAND: {'help': None} | {c: None for c in NODETOOL_COMMANDS}}
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)}
51
45
 
52
46
  return {}
53
47
 
54
48
  def help(self, _: ReplState):
55
- return f'{NodeTool.COMMAND} <sub-command>\t run nodetool with arguments'
49
+ return f'{NodeTool.COMMAND} <sub-command> [&]\t run nodetool with arguments'
56
50
 
57
51
  class NodeToolCommandHelper(click.Command):
58
52
  def get_help(self, ctx: click.Context):
@@ -22,21 +22,20 @@ class GetParam(Command):
22
22
  if not(args := self.args(cmd)):
23
23
  return super().run(cmd, state)
24
24
 
25
- state, args = self.apply_state(args, state)
25
+ with self.validate(args, state) as (args, state):
26
+ if len(args) < 1:
27
+ lines = [f'{key}\t{Config().get(key, None)}' for key in Config().keys()]
28
+ log(lines_to_tabular(lines, separator='\t'))
26
29
 
27
- if len(args) < 1:
28
- lines = [f'{key}\t{Config().get(key, None)}' for key in Config().keys()]
29
- log(lines_to_tabular(lines, separator='\t'))
30
+ return state
30
31
 
31
- return state
32
+ key = args[0]
33
+ if v := Config().get(key, None):
34
+ log(v)
35
+ else:
36
+ log2(f'{key} is not set.')
32
37
 
33
- key = args[0]
34
- if v := Config().get(key, None):
35
- log(v)
36
- else:
37
- log2(f'{key} is not set.')
38
-
39
- return v if v else state
38
+ return v if v else state
40
39
 
41
40
  def completion(self, _: ReplState):
42
41
  return {GetParam.COMMAND: {key: None for key in Config().keys()}}
@@ -22,20 +22,19 @@ class SetParam(Command):
22
22
  if not(args := self.args(cmd)):
23
23
  return super().run(cmd, state)
24
24
 
25
- state, args = self.apply_state(args, state)
25
+ with self.validate(args, state) as (args, state):
26
+ if len(args) < 2:
27
+ log2('set <key> <value>')
26
28
 
27
- if len(args) < 2:
28
- log2('set <key> <value>')
29
+ return 'invalid args'
29
30
 
30
- return 'invalid args'
31
+ key = args[0]
32
+ value = args[1]
33
+ Config().set(key, value)
31
34
 
32
- key = args[0]
33
- value = args[1]
34
- Config().set(key, value)
35
+ log(Config().get(key, None))
35
36
 
36
- log(Config().get(key, None))
37
-
38
- return value
37
+ return value
39
38
 
40
39
  def completion(self, _: ReplState):
41
40
  return {SetParam.COMMAND: {key: ({'true': None, 'false': None} if Config().get(key, None) in [True, False] else None) for key in Config().keys()}}