kaqing 2.0.14__py3-none-any.whl → 2.0.189__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of kaqing might be problematic. Click here for more details.

Files changed (228) hide show
  1. adam/__init__.py +0 -2
  2. adam/app_session.py +9 -12
  3. adam/apps.py +20 -6
  4. adam/batch.py +16 -6
  5. adam/checks/check_utils.py +19 -49
  6. adam/checks/compactionstats.py +1 -1
  7. adam/checks/cpu.py +9 -3
  8. adam/checks/cpu_metrics.py +52 -0
  9. adam/checks/disk.py +3 -4
  10. adam/checks/gossip.py +1 -1
  11. adam/checks/memory.py +3 -3
  12. adam/checks/status.py +1 -1
  13. adam/columns/columns.py +3 -1
  14. adam/columns/cpu.py +3 -1
  15. adam/columns/cpu_metrics.py +22 -0
  16. adam/columns/memory.py +3 -4
  17. adam/commands/__init__.py +24 -0
  18. adam/commands/alter_tables.py +66 -0
  19. adam/commands/app/app.py +38 -0
  20. adam/commands/{app_ping.py → app/app_ping.py} +8 -14
  21. adam/commands/app/show_app_actions.py +49 -0
  22. adam/commands/{show → app}/show_app_id.py +9 -12
  23. adam/commands/{show → app}/show_app_queues.py +8 -14
  24. adam/commands/app/utils_app.py +106 -0
  25. adam/commands/audit/__init__.py +0 -0
  26. adam/commands/audit/audit.py +67 -0
  27. adam/commands/audit/audit_repair_tables.py +72 -0
  28. adam/commands/audit/audit_run.py +50 -0
  29. adam/commands/audit/completions_l.py +15 -0
  30. adam/commands/audit/show_last10.py +36 -0
  31. adam/commands/audit/show_slow10.py +36 -0
  32. adam/commands/audit/show_top10.py +36 -0
  33. adam/commands/audit/utils_show_top10.py +71 -0
  34. adam/commands/bash/__init__.py +5 -0
  35. adam/commands/bash/bash.py +36 -0
  36. adam/commands/bash/bash_completer.py +93 -0
  37. adam/commands/bash/utils_bash.py +16 -0
  38. adam/commands/cat.py +36 -0
  39. adam/commands/cd.py +14 -88
  40. adam/commands/check.py +18 -21
  41. adam/commands/cli_commands.py +11 -7
  42. adam/commands/clipboard_copy.py +87 -0
  43. adam/commands/code.py +57 -0
  44. adam/commands/command.py +220 -19
  45. adam/commands/commands_utils.py +28 -31
  46. adam/commands/cql/__init__.py +0 -0
  47. adam/commands/cql/completions_c.py +28 -0
  48. adam/commands/{cqlsh.py → cql/cqlsh.py} +13 -32
  49. adam/commands/cql/utils_cql.py +305 -0
  50. adam/commands/deploy/code_start.py +7 -10
  51. adam/commands/deploy/code_stop.py +4 -21
  52. adam/commands/deploy/code_utils.py +5 -5
  53. adam/commands/deploy/deploy.py +4 -40
  54. adam/commands/deploy/deploy_frontend.py +15 -18
  55. adam/commands/deploy/deploy_pg_agent.py +4 -7
  56. adam/commands/deploy/deploy_pod.py +74 -77
  57. adam/commands/deploy/deploy_utils.py +16 -26
  58. adam/commands/deploy/undeploy.py +4 -40
  59. adam/commands/deploy/undeploy_frontend.py +5 -8
  60. adam/commands/deploy/undeploy_pg_agent.py +7 -8
  61. adam/commands/deploy/undeploy_pod.py +16 -17
  62. adam/commands/devices/__init__.py +0 -0
  63. adam/commands/devices/device.py +149 -0
  64. adam/commands/devices/device_app.py +163 -0
  65. adam/commands/devices/device_auit_log.py +49 -0
  66. adam/commands/devices/device_cass.py +179 -0
  67. adam/commands/devices/device_export.py +87 -0
  68. adam/commands/devices/device_postgres.py +160 -0
  69. adam/commands/devices/devices.py +25 -0
  70. adam/commands/download_file.py +47 -0
  71. adam/commands/exit.py +1 -4
  72. adam/commands/export/__init__.py +0 -0
  73. adam/commands/export/clean_up_all_export_sessions.py +37 -0
  74. adam/commands/export/clean_up_export_sessions.py +39 -0
  75. adam/commands/export/completions_x.py +11 -0
  76. adam/commands/export/download_export_session.py +40 -0
  77. adam/commands/export/drop_export_database.py +39 -0
  78. adam/commands/export/drop_export_databases.py +37 -0
  79. adam/commands/export/export.py +37 -0
  80. adam/commands/export/export_databases.py +246 -0
  81. adam/commands/export/export_select.py +34 -0
  82. adam/commands/export/export_sessions.py +209 -0
  83. adam/commands/export/export_use.py +49 -0
  84. adam/commands/export/export_x_select.py +48 -0
  85. adam/commands/export/exporter.py +332 -0
  86. adam/commands/export/import_files.py +44 -0
  87. adam/commands/export/import_session.py +44 -0
  88. adam/commands/export/importer.py +81 -0
  89. adam/commands/export/importer_athena.py +148 -0
  90. adam/commands/export/importer_sqlite.py +67 -0
  91. adam/commands/export/show_column_counts.py +45 -0
  92. adam/commands/export/show_export_databases.py +39 -0
  93. adam/commands/export/show_export_session.py +39 -0
  94. adam/commands/export/show_export_sessions.py +37 -0
  95. adam/commands/export/utils_export.py +344 -0
  96. adam/commands/find_files.py +51 -0
  97. adam/commands/find_processes.py +76 -0
  98. adam/commands/head.py +36 -0
  99. adam/commands/help.py +14 -9
  100. adam/commands/intermediate_command.py +52 -0
  101. adam/commands/issues.py +14 -40
  102. adam/commands/kubectl.py +38 -0
  103. adam/commands/login.py +26 -25
  104. adam/commands/logs.py +5 -7
  105. adam/commands/ls.py +11 -115
  106. adam/commands/medusa/medusa.py +4 -46
  107. adam/commands/medusa/medusa_backup.py +22 -29
  108. adam/commands/medusa/medusa_restore.py +51 -49
  109. adam/commands/medusa/medusa_show_backupjobs.py +20 -21
  110. adam/commands/medusa/medusa_show_restorejobs.py +16 -21
  111. adam/commands/medusa/utils_medusa.py +15 -0
  112. adam/commands/nodetool.py +8 -17
  113. adam/commands/param_get.py +11 -14
  114. adam/commands/param_set.py +9 -13
  115. adam/commands/postgres/completions_p.py +22 -0
  116. adam/commands/postgres/postgres.py +49 -73
  117. adam/commands/postgres/postgres_databases.py +270 -0
  118. adam/commands/postgres/postgres_ls.py +4 -8
  119. adam/commands/postgres/postgres_preview.py +5 -9
  120. adam/commands/postgres/utils_postgres.py +79 -0
  121. adam/commands/preview_table.py +10 -69
  122. adam/commands/pwd.py +14 -43
  123. adam/commands/reaper/reaper.py +6 -49
  124. adam/commands/reaper/reaper_forward.py +49 -56
  125. adam/commands/reaper/reaper_forward_session.py +6 -0
  126. adam/commands/reaper/reaper_forward_stop.py +10 -16
  127. adam/commands/reaper/reaper_restart.py +8 -15
  128. adam/commands/reaper/reaper_run_abort.py +8 -33
  129. adam/commands/reaper/reaper_runs.py +43 -58
  130. adam/commands/reaper/reaper_runs_abort.py +29 -49
  131. adam/commands/reaper/reaper_schedule_activate.py +14 -33
  132. adam/commands/reaper/reaper_schedule_start.py +9 -33
  133. adam/commands/reaper/reaper_schedule_stop.py +9 -33
  134. adam/commands/reaper/reaper_schedules.py +4 -14
  135. adam/commands/reaper/reaper_status.py +8 -16
  136. adam/commands/reaper/utils_reaper.py +203 -0
  137. adam/commands/repair/repair.py +4 -46
  138. adam/commands/repair/repair_log.py +6 -12
  139. adam/commands/repair/repair_run.py +29 -36
  140. adam/commands/repair/repair_scan.py +33 -41
  141. adam/commands/repair/repair_stop.py +6 -13
  142. adam/commands/report.py +25 -21
  143. adam/commands/restart.py +27 -28
  144. adam/commands/rollout.py +20 -25
  145. adam/commands/shell.py +12 -4
  146. adam/commands/show/show.py +15 -46
  147. adam/commands/show/show_adam.py +3 -3
  148. adam/commands/show/show_cassandra_repairs.py +37 -0
  149. adam/commands/show/show_cassandra_status.py +48 -52
  150. adam/commands/show/show_cassandra_version.py +5 -18
  151. adam/commands/show/show_cli_commands.py +56 -0
  152. adam/commands/show/show_host.py +33 -0
  153. adam/commands/show/show_login.py +23 -27
  154. adam/commands/show/show_params.py +2 -5
  155. adam/commands/show/show_processes.py +18 -21
  156. adam/commands/show/show_storage.py +11 -20
  157. adam/commands/watch.py +27 -30
  158. adam/config.py +8 -6
  159. adam/embedded_params.py +1 -1
  160. adam/log.py +4 -4
  161. adam/pod_exec_result.py +13 -5
  162. adam/repl.py +136 -120
  163. adam/repl_commands.py +66 -24
  164. adam/repl_session.py +8 -1
  165. adam/repl_state.py +343 -73
  166. adam/sql/__init__.py +0 -0
  167. adam/sql/lark_completer.py +284 -0
  168. adam/sql/lark_parser.py +604 -0
  169. adam/sql/sql_completer.py +118 -0
  170. adam/sql/sql_state_machine.py +630 -0
  171. adam/sql/term_completer.py +76 -0
  172. adam/sso/authn_ad.py +7 -9
  173. adam/sso/authn_okta.py +4 -6
  174. adam/sso/cred_cache.py +4 -6
  175. adam/sso/idp.py +10 -13
  176. adam/utils.py +539 -11
  177. adam/utils_athena.py +145 -0
  178. adam/utils_audits.py +102 -0
  179. adam/utils_issues.py +32 -0
  180. adam/utils_k8s/__init__.py +0 -0
  181. adam/utils_k8s/app_clusters.py +28 -0
  182. adam/utils_k8s/app_pods.py +36 -0
  183. adam/utils_k8s/cassandra_clusters.py +44 -0
  184. adam/{k8s_utils → utils_k8s}/cassandra_nodes.py +12 -5
  185. adam/{k8s_utils → utils_k8s}/custom_resources.py +16 -17
  186. adam/{k8s_utils → utils_k8s}/deployment.py +2 -2
  187. adam/{k8s_utils → utils_k8s}/ingresses.py +2 -2
  188. adam/{k8s_utils → utils_k8s}/jobs.py +7 -11
  189. adam/utils_k8s/k8s.py +96 -0
  190. adam/{k8s_utils → utils_k8s}/kube_context.py +3 -3
  191. adam/{k8s_utils → utils_k8s}/pods.py +132 -83
  192. adam/{k8s_utils → utils_k8s}/secrets.py +7 -3
  193. adam/{k8s_utils → utils_k8s}/service_accounts.py +5 -4
  194. adam/{k8s_utils → utils_k8s}/services.py +2 -2
  195. adam/{k8s_utils → utils_k8s}/statefulsets.py +9 -16
  196. adam/utils_local.py +4 -0
  197. adam/utils_net.py +24 -0
  198. adam/utils_repl/__init__.py +0 -0
  199. adam/utils_repl/appendable_completer.py +6 -0
  200. adam/utils_repl/automata_completer.py +48 -0
  201. adam/utils_repl/repl_completer.py +172 -0
  202. adam/utils_repl/state_machine.py +173 -0
  203. adam/utils_sqlite.py +137 -0
  204. adam/version.py +1 -1
  205. {kaqing-2.0.14.dist-info → kaqing-2.0.189.dist-info}/METADATA +1 -1
  206. kaqing-2.0.189.dist-info/RECORD +253 -0
  207. kaqing-2.0.189.dist-info/top_level.txt +2 -0
  208. teddy/__init__.py +0 -0
  209. teddy/lark_parser.py +436 -0
  210. teddy/lark_parser2.py +618 -0
  211. adam/commands/app.py +0 -67
  212. adam/commands/bash.py +0 -87
  213. adam/commands/cp.py +0 -95
  214. adam/commands/cql_utils.py +0 -53
  215. adam/commands/devices.py +0 -89
  216. adam/commands/postgres/postgres_session.py +0 -247
  217. adam/commands/reaper/reaper_session.py +0 -159
  218. adam/commands/show/show_app_actions.py +0 -53
  219. adam/commands/show/show_commands.py +0 -61
  220. adam/commands/show/show_repairs.py +0 -47
  221. adam/k8s_utils/cassandra_clusters.py +0 -48
  222. kaqing-2.0.14.dist-info/RECORD +0 -167
  223. kaqing-2.0.14.dist-info/top_level.txt +0 -1
  224. /adam/{k8s_utils → commands/app}/__init__.py +0 -0
  225. /adam/{k8s_utils → utils_k8s}/config_maps.py +0 -0
  226. /adam/{k8s_utils → utils_k8s}/volumes.py +0 -0
  227. {kaqing-2.0.14.dist-info → kaqing-2.0.189.dist-info}/WHEEL +0 -0
  228. {kaqing-2.0.14.dist-info → kaqing-2.0.189.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,79 @@
1
+ import functools
2
+
3
+ from adam.commands.postgres.postgres_databases import PostgresDatabases, pg_path
4
+ from adam.repl_state import ReplState
5
+ from adam.utils import log2, wait_log
6
+ from adam.utils_k8s.pods import Pods
7
+
8
+ TestPG = [False]
9
+
10
+ def direct_dirs(state: ReplState) -> list[str]:
11
+ with pg_path(state) as (host, database):
12
+ if database:
13
+ return ['..']
14
+ elif host:
15
+ return ['..'] + pg_database_names(state)
16
+ else:
17
+ return PostgresDatabases.host_names(state.namespace)
18
+
19
+ def pg_database_names(state: ReplState):
20
+ # cache on pg_path
21
+ return _pg_database_names(state, state.pg_path)
22
+
23
+ @functools.lru_cache()
24
+ def _pg_database_names(state: ReplState, pg_path: str):
25
+ if TestPG[0]:
26
+ return ['azops88_c3ai_c3']
27
+
28
+ wait_log('Inspecting Postgres Databases...')
29
+
30
+ return [db['name'] for db in PostgresDatabases.databases(state, default_owner=True)]
31
+
32
+ def pg_table_names(state: ReplState):
33
+ # cache on pg_path
34
+ return _pg_table_names(state, state.pg_path)
35
+
36
+ @functools.lru_cache()
37
+ def _pg_table_names(state: ReplState, pg_path: str):
38
+ if TestPG[0]:
39
+ return ['C3_2_XYZ1']
40
+
41
+ wait_log('Inspecting Postgres Database...')
42
+ return [table['name'] for table in PostgresDatabases.tables(state, default_schema=True)]
43
+
44
+ class PostgresPodService:
45
+ def __init__(self, handler: 'PostgresExecHandler'):
46
+ self.handler = handler
47
+
48
+ def exec(self, command: str, show_out=True):
49
+ state = self.handler.state
50
+
51
+ pod, container = PostgresDatabases.pod_and_container(state.namespace)
52
+ if not pod:
53
+ log2('Cannot locate postgres agent or ops pod.')
54
+ return state
55
+
56
+ return Pods.exec(pod, container, state.namespace, command, show_out=show_out)
57
+
58
+ def sql(self, args: list[str], backgrounded=False):
59
+ state = self.handler.state
60
+
61
+ query = args
62
+ if isinstance(args, list):
63
+ query = ' '.join(args)
64
+
65
+ PostgresDatabases.run_sql(state, query, backgrounded=backgrounded)
66
+
67
+ class PostgresExecHandler:
68
+ def __init__(self, state: ReplState, backgrounded=False):
69
+ self.state = state
70
+ self.backgrounded = backgrounded
71
+
72
+ def __enter__(self):
73
+ return PostgresPodService(self)
74
+
75
+ def __exit__(self, exc_type, exc_val, exc_tb):
76
+ return False
77
+
78
+ def postgres(state: ReplState, backgrounded=False):
79
+ return PostgresExecHandler(state, backgrounded=backgrounded)
@@ -1,12 +1,7 @@
1
- import functools
2
-
1
+ from adam.commands import validate_args
3
2
  from adam.commands.command import Command
4
- from adam.commands.cql_utils import parse_cql_desc_tables, run_cql
5
- from adam.commands.postgres.postgres_session import PostgresSession
6
- from adam.config import Config
7
- from adam.pod_exec_result import PodExecResult
3
+ from adam.commands.devices.devices import Devices
8
4
  from adam.repl_state import ReplState, RequiredState
9
- from adam.utils import lines_to_tabular, log, log2
10
5
 
11
6
  class PreviewTable(Command):
12
7
  COMMAND = 'preview'
@@ -24,75 +19,21 @@ class PreviewTable(Command):
24
19
  return PreviewTable.COMMAND
25
20
 
26
21
  def required(self):
27
- return RequiredState.CLUSTER_OR_POD
22
+ return [RequiredState.CLUSTER_OR_POD, RequiredState.PG_DATABASE, ReplState.L, RequiredState.EXPORT_DB]
28
23
 
29
24
  def run(self, cmd: str, state: ReplState):
30
25
  if not(args := self.args(cmd)):
31
26
  return super().run(cmd, state)
32
27
 
33
- state, args = self.apply_state(args, state)
34
- if state.device == ReplState.P:
35
- if not self.validate_state(state, RequiredState.PG_DATABASE):
36
- return state
37
- else:
38
- if not self.validate_state(state):
39
- return state
40
-
41
- if not args:
42
- def show_tables():
43
- if state.device == ReplState.P:
44
- pg = PostgresSession(state.namespace, state.pg_path)
45
- lines = [db["name"] for db in pg.tables() if db["schema"] == PostgresSession.default_schema()]
46
- log(lines_to_tabular(lines, separator=','))
47
- else:
48
- run_cql(state, f'describe tables', show_out=True)
49
-
50
- if state.in_repl:
51
- log2('Table is required.')
52
- log2()
53
- log2('Tables:')
54
- show_tables()
55
- else:
56
- log2('* Table is missing.')
57
- show_tables()
58
-
59
- Command.display_help()
60
-
61
- return 'command-missing'
62
-
63
- table = args[0]
28
+ with self.validate(args, state) as (args, state):
29
+ with validate_args(args, state, at_least=1) as table:
30
+ Devices.device(state).preview(table, state)
64
31
 
65
- rows = Config().get('preview.rows', 10)
66
- if state.device == ReplState.P:
67
- PostgresSession(state.namespace, state.pg_path).run_sql(f'select * from {table} limit {rows}')
68
- else:
69
- run_cql(state, f'select * from {table} limit {rows}', show_out=True, use_single_quotes=True)
70
-
71
- return state
72
-
73
- def completion(self, state: ReplState):
74
- if state.device == ReplState.P:
75
- if tables := PreviewTable.pg_tables(state.namespace, state.pg_path):
76
- return {PreviewTable.COMMAND: {db["name"]: None for db in tables if db["schema"] == PostgresSession.default_schema()}}
77
- else:
78
- if state.pod:
79
- tables = PreviewTable.cql_tables(state)
80
- return {PreviewTable.COMMAND: {f'{k}.{t}': None for k, ts in tables.items() for t in ts}}
32
+ return state
81
33
 
34
+ def completion(self, _: ReplState):
35
+ # taken care of by the sql completer
82
36
  return {}
83
37
 
84
38
  def help(self, _: ReplState):
85
- return f'{PreviewTable.COMMAND} TABLE\t preview table'
86
-
87
- @functools.lru_cache()
88
- def cql_tables(state: ReplState):
89
- r: PodExecResult = run_cql(state, 'describe tables', show_out=False)
90
- return parse_cql_desc_tables(r.stdout)
91
-
92
- @functools.lru_cache()
93
- def pg_tables(ns: str, pg_path: str):
94
- pg = PostgresSession(ns, pg_path)
95
- if pg.db:
96
- return pg.tables()
97
-
98
- return None
39
+ return f'{PreviewTable.COMMAND} TABLE\t preview table'
adam/commands/pwd.py CHANGED
@@ -1,8 +1,8 @@
1
1
  from adam.app_session import AppSession
2
2
  from adam.commands.command import Command
3
- from adam.commands.postgres.postgres_session import PostgresSession
3
+ from adam.commands.devices.devices import Devices
4
4
  from adam.repl_state import ReplState
5
- from adam.utils import lines_to_tabular, log
5
+ from adam.utils import tabulize, log, log_exc
6
6
 
7
7
  class Pwd(Command):
8
8
  COMMAND = 'pwd'
@@ -23,49 +23,20 @@ class Pwd(Command):
23
23
  if not(args := self.args(cmd)):
24
24
  return super().run(cmd, state)
25
25
 
26
- state, _ = self.apply_state(args, state)
26
+ with self.validate(args, state) as (_, state):
27
+ host = "unknown"
28
+ with log_exc():
29
+ app_session: AppSession = AppSession.create('c3', 'c3')
30
+ host = app_session.host
27
31
 
28
- def device_line(state: ReplState, device: str):
29
- words = []
32
+ tabulize([device.pwd(state) for device in Devices.all()] + [
33
+ f'',
34
+ f'HOST\t{host}',
35
+ f'NAMESPACE\t{state.namespace if state.namespace else "/"}',
36
+ ], header='DEVICE\tLOCATION', separator='\t')
37
+ log()
30
38
 
31
- if device == ReplState.P:
32
- pg = PostgresSession(state.namespace, state.pg_path)
33
-
34
- if pg.host:
35
- words.append(f'host/{pg.host}')
36
- if pg.db:
37
- words.append(f'database/{pg.db}')
38
- elif device == ReplState.A:
39
- if state.app_env:
40
- words.append(f'env/{state.app_env}')
41
- if state.app_app:
42
- words.append(f'app/{state.app_app}')
43
- else:
44
- if state.sts:
45
- words.append(f'sts/{state.sts}')
46
- if state.pod:
47
- words.append(f'pod/{state.pod}')
48
-
49
- return '\t'.join([f'{device}:>'] + (words if words else ['/']))
50
-
51
- host = "unknown"
52
- try:
53
- app_session: AppSession = AppSession.create('c3', 'c3')
54
- host = app_session.host
55
- except:
56
- pass
57
-
58
- log(lines_to_tabular([
59
- device_line(state, ReplState.A),
60
- device_line(state, ReplState.C),
61
- device_line(state, ReplState.P),
62
- f'',
63
- f'HOST\t{host}',
64
- f'NAMESPACE\t{state.namespace if state.namespace else "/"}',
65
- ], 'DEVICE\tLOCATION', separator='\t'))
66
- log()
67
-
68
- return state
39
+ return state
69
40
 
70
41
  def completion(self, state: ReplState):
71
42
  return super().completion(state)
@@ -1,7 +1,6 @@
1
1
  import click
2
2
 
3
- from adam.commands.command import Command
4
- from adam.commands.command_helpers import ClusterCommandHelper
3
+ from adam.commands.intermediate_command import IntermediateCommand
5
4
  from .reaper_forward import ReaperForward
6
5
  from .reaper_forward_stop import ReaperForwardStop
7
6
  from .reaper_restart import ReaperRestart
@@ -13,12 +12,9 @@ from .reaper_schedule_start import ReaperScheduleStart
13
12
  from .reaper_schedule_stop import ReaperScheduleStop
14
13
  from .reaper_schedules import ReaperSchedules
15
14
  from .reaper_status import ReaperStatus
16
- from adam.repl_state import ReplState, RequiredState
17
- from adam.utils import lines_to_tabular, log, log2
18
15
 
19
- class Reaper(Command):
16
+ class Reaper(IntermediateCommand):
20
17
  COMMAND = 'reaper'
21
- reaper_login = None
22
18
 
23
19
  # the singleton pattern
24
20
  def __new__(cls, *args, **kwargs):
@@ -26,53 +22,14 @@ class Reaper(Command):
26
22
 
27
23
  return cls.instance
28
24
 
29
- def __init__(self, successor: Command=None):
30
- super().__init__(successor)
31
-
32
25
  def command(self):
33
26
  return Reaper.COMMAND
34
27
 
35
- def required(self):
36
- return RequiredState.CLUSTER
37
-
38
- def run(self, cmd: str, state: ReplState):
39
- if not(args := self.args(cmd)):
40
- return super().run(cmd, state)
41
-
42
- state, args = self.apply_state(args, state)
43
- if not self.validate_state(state):
44
- return state
45
-
46
- if state.in_repl:
47
- log(lines_to_tabular([c.help(ReplState()) for c in Reaper.cmd_list()], separator='\t'))
48
-
49
- return 'command-missing'
50
- else:
51
- # head with the Chain of Responsibility pattern
52
- cmds = Command.chain(Reaper.cmd_list())
53
- if not cmds.run(cmd, state):
54
- log2('* Command is missing.')
55
- Command.display_help()
56
-
57
- def cmd_list():
28
+ def cmd_list(self):
58
29
  return [ReaperSchedules(), ReaperScheduleStop(), ReaperScheduleActivate(), ReaperScheduleStart(),
59
- ReaperForwardStop(), ReaperForward(), ReaperRunAbort(), ReaperRunsAbort(), ReaperRestart(), ReaperRuns(), ReaperStatus()]
60
-
61
- def completion(self, state: ReplState):
62
- if state.sts:
63
- return super().completion(state)
64
-
65
- return {}
66
-
67
- def help(self, _: ReplState):
68
- return None
30
+ ReaperForwardStop(), ReaperForward(), ReaperRunAbort(), ReaperRunsAbort(), ReaperRestart(),
31
+ ReaperRuns(), ReaperStatus()]
69
32
 
70
33
  class ReaperCommandHelper(click.Command):
71
34
  def get_help(self, ctx: click.Context):
72
- log(super().get_help(ctx))
73
- log()
74
- log('Sub-Commands:')
75
-
76
- log(lines_to_tabular([c.help(ReplState()).replace(f'{Reaper.COMMAND} ', ' ', 1) for c in Reaper.cmd_list()], separator='\t'))
77
- log()
78
- ClusterCommandHelper.cluster_help()
35
+ IntermediateCommand.intermediate_help(super().get_help(ctx), Reaper.COMMAND, Reaper().cmd_list(), show_cluster_help=True)
@@ -1,16 +1,17 @@
1
+ from functools import partial
1
2
  import threading
2
3
  import time
3
4
 
4
5
  from adam.commands.command import Command
5
- from .reaper_session import ReaperSession
6
+ from adam.commands.reaper.reaper_forward_session import ReaperForwardSession
7
+ from adam.commands.reaper.utils_reaper import Reapers, port_forwarding
6
8
  from adam.config import Config
7
9
  from adam.repl_session import ReplSession
8
10
  from adam.repl_state import ReplState, RequiredState
9
- from adam.utils import lines_to_tabular, log2
11
+ from adam.utils import tabulize, log2
10
12
 
11
13
  class ReaperForward(Command):
12
14
  COMMAND = 'reaper forward'
13
- reaper_login = None
14
15
 
15
16
  # the singleton pattern
16
17
  def __new__(cls, *args, **kwargs):
@@ -31,70 +32,62 @@ class ReaperForward(Command):
31
32
  if not(args := self.args(cmd)):
32
33
  return super().run(cmd, state)
33
34
 
34
- state, args = self.apply_state(args, state)
35
- if not self.validate_state(state):
36
- return state
35
+ with self.validate(args, state) as (args, state):
36
+ if not Reapers.pod_name(state):
37
+ return state
37
38
 
38
- if not(reaper := ReaperSession.create(state)):
39
- return state
39
+ spec = Reapers.reaper_spec(state)
40
+ if state.in_repl:
41
+ if ReaperForwardSession.is_forwarding:
42
+ log2("Another port-forward is already running.")
40
43
 
41
- spec = reaper.reaper_spec(state)
42
- if state.in_repl:
43
- if ReaperSession.is_forwarding:
44
- log2("Another port-forward is already running.")
45
-
46
- return "already-running"
47
-
48
- # make it a daemon to exit with a Ctrl-D
49
- thread = threading.Thread(target=self.loop, args=(state, reaper), daemon=True)
50
- thread.start()
51
-
52
- while not ReaperSession.is_forwarding:
53
- time.sleep(1)
54
-
55
- d = {
56
- 'reaper-ui': spec["web-uri"],
57
- 'reaper-username': spec["username"],
58
- 'reaper-password': spec["password"]
59
- }
60
- log2()
61
- log2(lines_to_tabular([f'{k},{v}' for k, v in d.items()], separator=','))
62
-
63
- for k, v in d.items():
64
- ReplSession().prompt_session.history.append_string(f'cp {k}')
65
- log2()
66
- log2(f'Use <Up> arrow key to copy the values to clipboard.')
67
- else:
68
- try:
69
- log2(f'Click: {spec["web-uri"]}')
70
- log2(f'username: {spec["username"]}')
71
- log2(f'password: {spec["password"]}')
44
+ return "already-running"
45
+
46
+ # make it a daemon to exit with a Ctrl-D
47
+ thread = threading.Thread(target=self.loop, args=(state,), daemon=True)
48
+ thread.start()
49
+
50
+ while not ReaperForwardSession.is_forwarding:
51
+ time.sleep(1)
52
+
53
+ d = {
54
+ 'reaper-ui': spec["web-uri"],
55
+ 'reaper-username': spec["username"],
56
+ 'reaper-password': spec["password"]
57
+ }
72
58
  log2()
73
- log2(f"Press Ctrl+C to break.")
59
+ tabulize(d.items(), lambda a: f'{a[0]},{a[1]}', separator=',')
74
60
 
75
- time.sleep(Config().get('reaper.port-forward.timeout', 3600 * 24))
76
- except KeyboardInterrupt:
77
- pass
61
+ for k, v in d.items():
62
+ ReplSession().prompt_session.history.append_string(f'cp {k}')
63
+ log2()
64
+ log2(f'Use <Up> arrow key to copy the values to clipboard.')
65
+ else:
66
+ try:
67
+ log2(f'Click: {spec["web-uri"]}')
68
+ log2(f'username: {spec["username"]}')
69
+ log2(f'password: {spec["password"]}')
70
+ log2()
71
+ log2(f"Press Ctrl+C to break.")
72
+
73
+ time.sleep(Config().get('reaper.port-forward.timeout', 3600 * 24))
74
+ except KeyboardInterrupt:
75
+ pass
78
76
 
79
- return state
77
+ return state
80
78
 
81
- def loop(self, state: ReplState, reaper: ReaperSession):
82
- def body(uri: str, _: dict[str, str]):
83
- ReaperSession.is_forwarding = True
79
+ def loop(self, state: ReplState):
80
+ with port_forwarding(state, Reapers.local_port(), partial(Reapers.svc_or_pod, state), Reapers.target_port()):
81
+ ReaperForwardSession.is_forwarding = True
84
82
  try:
85
- while not ReaperSession.stopping.is_set():
83
+ while not ReaperForwardSession.stopping.is_set():
86
84
  time.sleep(1)
87
85
  finally:
88
- ReaperSession.stopping.clear()
89
- ReaperSession.is_forwarding = False
90
-
91
- return reaper.port_forwarded(state, 'webui', body)
86
+ ReaperForwardSession.stopping.clear()
87
+ ReaperForwardSession.is_forwarding = False
92
88
 
93
89
  def completion(self, state: ReplState):
94
- if state.sts:
95
- return super().completion(state)
96
-
97
- return {}
90
+ return super().completion(state)
98
91
 
99
92
  def help(self, _: ReplState):
100
93
  return f'{ReaperForward.COMMAND}\t port-forward to reaper'
@@ -0,0 +1,6 @@
1
+ import threading
2
+
3
+ class ReaperForwardSession:
4
+ is_forwarding = False
5
+ stopping = threading.Event()
6
+ schedules_ids_by_cluster: dict[str, list[str]] = {}
@@ -1,11 +1,11 @@
1
1
  from adam.commands.command import Command
2
- from .reaper_session import ReaperSession
2
+ from adam.commands.reaper.reaper_forward_session import ReaperForwardSession
3
+ from adam.commands.reaper.utils_reaper import Reapers
3
4
  from adam.repl_state import ReplState, RequiredState
4
5
  from adam.utils import log2
5
6
 
6
7
  class ReaperForwardStop(Command):
7
8
  COMMAND = 'reaper forward stop'
8
- reaper_login = None
9
9
 
10
10
  # the singleton pattern
11
11
  def __new__(cls, *args, **kwargs):
@@ -26,24 +26,18 @@ class ReaperForwardStop(Command):
26
26
  if not(args := self.args(cmd)):
27
27
  return super().run(cmd, state)
28
28
 
29
- state, args = self.apply_state(args, state)
30
- if not self.validate_state(state):
31
- return state
32
-
33
- if not ReaperSession.create(state):
34
- return state
29
+ with self.validate(args, state) as (args, state):
30
+ if not Reapers.pod_name(state):
31
+ return state
35
32
 
36
- ReaperSession.is_forwarding = False
37
- ReaperSession.stopping.set()
38
- log2("Stopped reaper forward session.")
33
+ ReaperForwardSession.is_forwarding = False
34
+ ReaperForwardSession.stopping.set()
35
+ log2("Stopped reaper forward session.")
39
36
 
40
- return state
37
+ return state
41
38
 
42
39
  def completion(self, state: ReplState):
43
- if state.sts:
44
- return super().completion(state)
45
-
46
- return {}
40
+ return super().completion(state)
47
41
 
48
42
  def help(self, _: ReplState):
49
43
  return f'{ReaperForwardStop.COMMAND}\t stop port-forward to reaper'
@@ -1,11 +1,10 @@
1
1
  from adam.commands.command import Command
2
- from adam.k8s_utils.pods import Pods
3
- from .reaper_session import ReaperSession
2
+ from adam.commands.reaper.utils_reaper import Reapers
3
+ from adam.utils_k8s.pods import Pods
4
4
  from adam.repl_state import ReplState, RequiredState
5
5
 
6
6
  class ReaperRestart(Command):
7
7
  COMMAND = 'reaper restart'
8
- reaper_login = None
9
8
 
10
9
  # the singleton pattern
11
10
  def __new__(cls, *args, **kwargs):
@@ -26,22 +25,16 @@ class ReaperRestart(Command):
26
25
  if not(args := self.args(cmd)):
27
26
  return super().run(cmd, state)
28
27
 
29
- state, args = self.apply_state(args, state)
30
- if not self.validate_state(state):
31
- return state
32
-
33
- if not(reaper := ReaperSession.create(state)):
34
- return state
28
+ with self.validate(args, state) as (args, state):
29
+ if not (pod := Reapers.pod_name(state)):
30
+ return state
35
31
 
36
- Pods.delete(reaper.pod, state.namespace)
32
+ Pods.delete(pod, state.namespace)
37
33
 
38
- return state
34
+ return state
39
35
 
40
36
  def completion(self, state: ReplState):
41
- if state.sts:
42
- return super().completion(state)
43
-
44
- return {}
37
+ return super().completion(state)
45
38
 
46
39
  def help(self, _: ReplState):
47
40
  return f'{ReaperRestart.COMMAND}\t restart reaper'
@@ -1,13 +1,11 @@
1
- import requests
2
-
1
+ from adam.commands import validate_args
3
2
  from adam.commands.command import Command
4
- from .reaper_session import ReaperSession
3
+ from adam.commands.reaper.utils_reaper import reaper
5
4
  from adam.repl_state import ReplState, RequiredState
6
5
  from adam.utils import log2
7
6
 
8
7
  class ReaperRunAbort(Command):
9
8
  COMMAND = 'reaper abort run'
10
- reaper_login = None
11
9
 
12
10
  # the singleton pattern
13
11
  def __new__(cls, *args, **kwargs):
@@ -28,38 +26,15 @@ class ReaperRunAbort(Command):
28
26
  if not(args := self.args(cmd)):
29
27
  return super().run(cmd, state)
30
28
 
31
- state, args = self.apply_state(args, state)
32
- if not self.validate_state(state):
33
- return state
34
-
35
- if not args:
36
- if state.in_repl:
37
- log2('Specify run id to abort.')
38
- else:
39
- Command.display_help()
40
-
41
- return state
42
-
43
- if not(reaper := ReaperSession.create(state)):
44
- return state
29
+ with self.validate(args, state) as (args, state):
30
+ with validate_args(args, state, name='run id') as run_id:
31
+ with reaper(state) as http:
32
+ http.put(f'repair_run/{run_id}/state/ABORTED')
45
33
 
46
- self.stop_run(state, reaper, args[0])
47
-
48
- return state
49
-
50
- def stop_run(self, state: ReplState, reaper: ReaperSession, run_id: str):
51
- def body(uri: str, headers: dict[str, str]):
52
- return requests.put(uri, headers=headers)
53
-
54
- # PAUSED, RUNNING, ABORTED
55
- # PUT /repair_run/{id}/state/{state}
56
- reaper.port_forwarded(state, f'repair_run/{run_id}/state/ABORTED', body, method='PUT')
34
+ return state
57
35
 
58
36
  def completion(self, state: ReplState):
59
- if state.sts:
60
- return super().completion(state)
61
-
62
- return {}
37
+ return super().completion(state)
63
38
 
64
39
  def help(self, _: ReplState):
65
40
  return f'{ReaperRunAbort.COMMAND} <run-id>\t abort reaper run'