kaqing 2.0.145__py3-none-any.whl → 2.0.174__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 (174) hide show
  1. adam/__init__.py +0 -2
  2. adam/app_session.py +8 -11
  3. adam/batch.py +3 -3
  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/checks/disk.py +2 -3
  8. adam/columns/columns.py +3 -1
  9. adam/columns/cpu.py +3 -1
  10. adam/columns/cpu_metrics.py +22 -0
  11. adam/columns/memory.py +3 -4
  12. adam/commands/__init__.py +22 -0
  13. adam/commands/alter_tables.py +33 -48
  14. adam/commands/audit/audit.py +22 -23
  15. adam/commands/audit/audit_repair_tables.py +14 -17
  16. adam/commands/audit/audit_run.py +15 -23
  17. adam/commands/audit/show_last10.py +10 -13
  18. adam/commands/audit/show_slow10.py +10 -13
  19. adam/commands/audit/show_top10.py +10 -13
  20. adam/commands/audit/utils_show_top10.py +2 -3
  21. adam/commands/bash/__init__.py +5 -0
  22. adam/commands/bash/bash.py +7 -104
  23. adam/commands/bash/utils_bash.py +16 -0
  24. adam/commands/cat.py +7 -23
  25. adam/commands/cd.py +7 -11
  26. adam/commands/check.py +14 -23
  27. adam/commands/cli_commands.py +2 -3
  28. adam/commands/code.py +20 -23
  29. adam/commands/command.py +152 -37
  30. adam/commands/commands_utils.py +8 -17
  31. adam/commands/cp.py +18 -32
  32. adam/commands/cql/cql_completions.py +11 -7
  33. adam/commands/cql/cqlsh.py +10 -30
  34. adam/commands/cql/{cql_utils.py → utils_cql.py} +147 -15
  35. adam/commands/deploy/code_start.py +7 -10
  36. adam/commands/deploy/code_stop.py +4 -21
  37. adam/commands/deploy/code_utils.py +3 -3
  38. adam/commands/deploy/deploy.py +4 -27
  39. adam/commands/deploy/deploy_frontend.py +14 -17
  40. adam/commands/deploy/deploy_pg_agent.py +2 -5
  41. adam/commands/deploy/deploy_pod.py +64 -68
  42. adam/commands/deploy/undeploy.py +4 -27
  43. adam/commands/deploy/undeploy_frontend.py +4 -7
  44. adam/commands/deploy/undeploy_pg_agent.py +4 -7
  45. adam/commands/deploy/undeploy_pod.py +9 -12
  46. adam/commands/devices/device.py +93 -2
  47. adam/commands/devices/device_app.py +37 -10
  48. adam/commands/devices/device_auit_log.py +8 -2
  49. adam/commands/devices/device_cass.py +47 -7
  50. adam/commands/devices/device_export.py +9 -11
  51. adam/commands/devices/device_postgres.py +41 -6
  52. adam/commands/exit.py +1 -4
  53. adam/commands/export/clean_up_all_export_sessions.py +37 -0
  54. adam/commands/export/clean_up_export_sessions.py +12 -8
  55. adam/commands/export/drop_export_database.py +7 -26
  56. adam/commands/export/drop_export_databases.py +5 -14
  57. adam/commands/export/export.py +8 -38
  58. adam/commands/export/export_databases.py +86 -27
  59. adam/commands/export/export_select.py +25 -27
  60. adam/commands/export/export_select_x.py +3 -3
  61. adam/commands/export/export_sessions.py +124 -0
  62. adam/commands/export/export_use.py +8 -17
  63. adam/commands/export/exporter.py +88 -158
  64. adam/commands/export/import_session.py +7 -35
  65. adam/commands/export/importer.py +12 -5
  66. adam/commands/export/importer_athena.py +21 -20
  67. adam/commands/export/importer_sqlite.py +16 -21
  68. adam/commands/export/show_column_counts.py +7 -25
  69. adam/commands/export/show_export_databases.py +4 -6
  70. adam/commands/export/show_export_session.py +7 -18
  71. adam/commands/export/show_export_sessions.py +9 -12
  72. adam/commands/export/utils_export.py +26 -1
  73. adam/commands/intermediate_command.py +49 -0
  74. adam/commands/issues.py +11 -43
  75. adam/commands/kubectl.py +3 -6
  76. adam/commands/login.py +22 -24
  77. adam/commands/logs.py +3 -6
  78. adam/commands/ls.py +8 -9
  79. adam/commands/medusa/medusa.py +4 -22
  80. adam/commands/medusa/medusa_backup.py +20 -25
  81. adam/commands/medusa/medusa_restore.py +34 -36
  82. adam/commands/medusa/medusa_show_backupjobs.py +14 -18
  83. adam/commands/medusa/medusa_show_restorejobs.py +11 -18
  84. adam/commands/nodetool.py +6 -15
  85. adam/commands/param_get.py +11 -13
  86. adam/commands/param_set.py +8 -12
  87. adam/commands/postgres/postgres.py +22 -38
  88. adam/commands/postgres/postgres_context.py +47 -23
  89. adam/commands/postgres/postgres_ls.py +4 -8
  90. adam/commands/postgres/postgres_preview.py +5 -9
  91. adam/commands/postgres/psql_completions.py +1 -1
  92. adam/commands/postgres/utils_postgres.py +70 -0
  93. adam/commands/preview_table.py +6 -45
  94. adam/commands/pwd.py +13 -16
  95. adam/commands/reaper/reaper.py +4 -27
  96. adam/commands/reaper/reaper_forward.py +48 -55
  97. adam/commands/reaper/reaper_forward_session.py +6 -0
  98. adam/commands/reaper/reaper_forward_stop.py +10 -16
  99. adam/commands/reaper/reaper_restart.py +7 -14
  100. adam/commands/reaper/reaper_run_abort.py +8 -33
  101. adam/commands/reaper/reaper_runs.py +42 -57
  102. adam/commands/reaper/reaper_runs_abort.py +29 -49
  103. adam/commands/reaper/reaper_schedule_activate.py +9 -32
  104. adam/commands/reaper/reaper_schedule_start.py +9 -32
  105. adam/commands/reaper/reaper_schedule_stop.py +9 -32
  106. adam/commands/reaper/reaper_schedules.py +4 -14
  107. adam/commands/reaper/reaper_status.py +8 -16
  108. adam/commands/reaper/utils_reaper.py +196 -0
  109. adam/commands/repair/repair.py +4 -22
  110. adam/commands/repair/repair_log.py +5 -11
  111. adam/commands/repair/repair_run.py +27 -34
  112. adam/commands/repair/repair_scan.py +32 -38
  113. adam/commands/repair/repair_stop.py +5 -11
  114. adam/commands/report.py +27 -29
  115. adam/commands/restart.py +25 -26
  116. adam/commands/rollout.py +19 -24
  117. adam/commands/shell.py +10 -4
  118. adam/commands/show/show.py +10 -26
  119. adam/commands/show/show_cassandra_repairs.py +35 -0
  120. adam/commands/show/show_cassandra_status.py +32 -43
  121. adam/commands/show/show_cassandra_version.py +5 -18
  122. adam/commands/show/show_commands.py +19 -24
  123. adam/commands/show/show_host.py +1 -1
  124. adam/commands/show/show_login.py +20 -27
  125. adam/commands/show/show_processes.py +15 -19
  126. adam/commands/show/show_storage.py +10 -20
  127. adam/commands/watch.py +26 -29
  128. adam/config.py +4 -16
  129. adam/embedded_params.py +1 -1
  130. adam/log.py +4 -4
  131. adam/pod_exec_result.py +3 -3
  132. adam/repl.py +31 -32
  133. adam/repl_commands.py +11 -11
  134. adam/repl_state.py +52 -26
  135. adam/sql/sql_completer.py +4 -6
  136. adam/sql/sql_state_machine.py +21 -14
  137. adam/sso/authn_ad.py +6 -8
  138. adam/sso/authn_okta.py +4 -6
  139. adam/sso/cred_cache.py +3 -5
  140. adam/sso/idp.py +9 -12
  141. adam/utils.py +393 -33
  142. adam/utils_athena.py +14 -13
  143. adam/utils_audits.py +12 -12
  144. adam/utils_issues.py +32 -0
  145. adam/utils_k8s/app_clusters.py +13 -18
  146. adam/utils_k8s/app_pods.py +2 -0
  147. adam/utils_k8s/cassandra_clusters.py +21 -18
  148. adam/utils_k8s/custom_resources.py +16 -17
  149. adam/utils_k8s/ingresses.py +2 -2
  150. adam/utils_k8s/jobs.py +7 -11
  151. adam/utils_k8s/k8s.py +87 -0
  152. adam/utils_k8s/pods.py +14 -76
  153. adam/utils_k8s/secrets.py +4 -4
  154. adam/utils_k8s/service_accounts.py +5 -4
  155. adam/utils_k8s/services.py +2 -2
  156. adam/utils_k8s/statefulsets.py +1 -12
  157. adam/utils_repl/state_machine.py +3 -3
  158. adam/utils_sqlite.py +78 -42
  159. adam/version.py +1 -1
  160. {kaqing-2.0.145.dist-info → kaqing-2.0.174.dist-info}/METADATA +1 -1
  161. kaqing-2.0.174.dist-info/RECORD +230 -0
  162. adam/commands/app.py +0 -67
  163. adam/commands/app_ping.py +0 -44
  164. adam/commands/export/clean_up_export_session.py +0 -53
  165. adam/commands/postgres/postgres_utils.py +0 -31
  166. adam/commands/reaper/reaper_session.py +0 -159
  167. adam/commands/show/show_app_actions.py +0 -56
  168. adam/commands/show/show_app_id.py +0 -47
  169. adam/commands/show/show_app_queues.py +0 -45
  170. adam/commands/show/show_repairs.py +0 -47
  171. kaqing-2.0.145.dist-info/RECORD +0 -227
  172. {kaqing-2.0.145.dist-info → kaqing-2.0.174.dist-info}/WHEEL +0 -0
  173. {kaqing-2.0.145.dist-info → kaqing-2.0.174.dist-info}/entry_points.txt +0 -0
  174. {kaqing-2.0.145.dist-info → kaqing-2.0.174.dist-info}/top_level.txt +0 -0
@@ -4,7 +4,6 @@ from adam.repl_state import ReplState, RequiredState
4
4
 
5
5
  class PostgresPreview(Command):
6
6
  COMMAND = 'pg preview'
7
- reaper_login = None
8
7
 
9
8
  # the singleton pattern
10
9
  def __new__(cls, *args, **kwargs):
@@ -19,21 +18,18 @@ class PostgresPreview(Command):
19
18
  return PostgresPreview.COMMAND
20
19
 
21
20
  def required(self):
22
- return RequiredState.NAMESPACE
21
+ return RequiredState.PG_DATABASE
23
22
 
24
23
  def run(self, cmd: str, state: ReplState):
25
24
  if not(args := self.args(cmd)):
26
25
  return super().run(cmd, state)
27
26
 
28
- state, args = self.apply_state(args, state)
29
- if not self.validate_state(state, RequiredState.PG_DATABASE):
30
- return state
31
-
32
- state.device = ReplState.P
27
+ with self.validate(args, state) as (args, state):
28
+ state.device = ReplState.P
33
29
 
34
- PreviewTable().run(f'preview {" ".join(args)}', state)
30
+ PreviewTable().run(f'preview {" ".join(args)}', state)
35
31
 
36
- return state
32
+ return state
37
33
 
38
34
  def completion(self, state: ReplState):
39
35
  if state.sts:
@@ -1,4 +1,4 @@
1
- from adam.commands.postgres.postgres_utils import pg_table_names
1
+ from adam.commands.postgres.utils_postgres import pg_table_names
2
2
  from adam.sql.sql_completer import SqlCompleter
3
3
 
4
4
  def psql_completions(ns: str, pg_path: str):
@@ -0,0 +1,70 @@
1
+ import functools
2
+
3
+ from adam.commands.postgres.postgres_context import PostgresContext
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
+ @functools.lru_cache()
11
+ def pg_database_names(ns: str, pg_path: str):
12
+ if TestPG[0]:
13
+ return ['azops88_c3ai_c3']
14
+
15
+ wait_log('Inspecting Postgres Databases...')
16
+
17
+ pg = PostgresContext.apply(ns, pg_path)
18
+ return [db['name'] for db in pg.databases() if db['owner'] == PostgresContext.default_owner()]
19
+
20
+ @functools.lru_cache()
21
+ def pg_table_names(ns: str, pg_path: str):
22
+ if TestPG[0]:
23
+ return ['C3_2_XYZ1']
24
+
25
+ wait_log('Inspecting Postgres Database...')
26
+ return [table['name'] for table in pg_tables(ns, pg_path) if table['schema'] == PostgresContext.default_schema()]
27
+
28
+ def pg_tables(ns: str, pg_path: str):
29
+ pg = PostgresContext.apply(ns, pg_path)
30
+ if pg.db:
31
+ return pg.tables()
32
+
33
+ return []
34
+
35
+ class PostgresPodService:
36
+ def __init__(self, handler: 'PostgresExecHandler'):
37
+ self.handler = handler
38
+
39
+ def exec(self, command: str, show_out=True):
40
+ state = self.handler.state
41
+
42
+ pod, container = PostgresContext.pod_and_container(state.namespace)
43
+ if not pod:
44
+ log2('Cannot locate postgres agent or ops pod.')
45
+ return state
46
+
47
+ return Pods.exec(pod, container, state.namespace, command, show_out=show_out)
48
+
49
+ def sql(self, args: list[str], background=False):
50
+ state = self.handler.state
51
+
52
+ query = args
53
+ if isinstance(args, list):
54
+ query = ' '.join(args)
55
+
56
+ PostgresContext.apply(state.namespace, state.pg_path).run_sql(query, background=background)
57
+
58
+ class PostgresExecHandler:
59
+ def __init__(self, state: ReplState, background=False):
60
+ self.state = state
61
+ self.background = background
62
+
63
+ def __enter__(self):
64
+ return PostgresPodService(self)
65
+
66
+ def __exit__(self, exc_type, exc_val, exc_tb):
67
+ return False
68
+
69
+ def postgres(state: ReplState, background=False):
70
+ return PostgresExecHandler(state, background=background)
@@ -1,11 +1,6 @@
1
1
  from adam.commands.command import Command
2
- from adam.commands.cql.cql_utils import cassandra_table_names, run_cql
3
- from adam.commands.postgres.postgres_context import PostgresContext
4
- from adam.config import Config
2
+ from adam.commands.devices.devices import Devices
5
3
  from adam.repl_state import ReplState, RequiredState
6
- from adam.utils import lines_to_tabular, log, log2
7
- from adam.utils_athena import Athena
8
- from adam.utils_audits import Audits
9
4
 
10
5
  class PreviewTable(Command):
11
6
  COMMAND = 'preview'
@@ -23,53 +18,19 @@ class PreviewTable(Command):
23
18
  return PreviewTable.COMMAND
24
19
 
25
20
  def required(self):
26
- return [RequiredState.CLUSTER_OR_POD, RequiredState.PG_DATABASE, ReplState.L]
21
+ return [RequiredState.CLUSTER_OR_POD, RequiredState.PG_DATABASE, ReplState.L, RequiredState.EXPORT_DB]
27
22
 
28
23
  def run(self, cmd: str, state: ReplState):
29
24
  if not(args := self.args(cmd)):
30
25
  return super().run(cmd, state)
31
26
 
32
- state, args = self.apply_state(args, state)
33
- if not self.validate_state(state):
34
- return state
35
-
36
- if not args:
37
- def show_tables():
38
- if state.device == ReplState.P:
39
- pg = PostgresContext.apply(state.namespace, state.pg_path)
40
- lines = [db["name"] for db in pg.tables() if db["schema"] == PostgresContext.default_schema()]
41
- log(lines_to_tabular(lines, separator=','))
42
- elif state.device == ReplState.L:
43
- log(lines_to_tabular(Athena.table_names(), separator=','))
44
- else:
45
- log(lines_to_tabular(cassandra_table_names(state), separator=','))
46
-
47
- if state.in_repl:
48
- log2('Table is required.')
49
- log2()
50
- log2('Tables:')
51
- show_tables()
52
- else:
53
- log2('* Table is missing.')
54
- show_tables()
55
-
56
- Command.display_help()
27
+ with self.validate(args, state) as (args, state):
28
+ Devices.device(state).preview(args[0] if args else None, state)
57
29
 
58
- return 'command-missing'
59
-
60
- table = args[0]
61
-
62
- rows = Config().get('preview.rows', 10)
63
- if state.device == ReplState.P:
64
- PostgresContext.apply(state.namespace, state.pg_path).run_sql(f'select * from {table} limit {rows}')
65
- elif state.device == ReplState.L:
66
- Athena.run_query(f'select * from {table} limit {rows}')
67
- else:
68
- run_cql(state, f'select * from {table} limit {rows}', show_out=True, use_single_quotes=True, on_any=True)
69
-
70
- return state
30
+ return state
71
31
 
72
32
  def completion(self, _: ReplState):
33
+ # taken care of by the sql completer
73
34
  return {}
74
35
 
75
36
  def help(self, _: ReplState):
adam/commands/pwd.py CHANGED
@@ -2,7 +2,7 @@ from adam.app_session import AppSession
2
2
  from adam.commands.command import Command
3
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 lines_to_tabular, log, log_exc
6
6
 
7
7
  class Pwd(Command):
8
8
  COMMAND = 'pwd'
@@ -23,23 +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
- host = "unknown"
29
- try:
30
- app_session: AppSession = AppSession.create('c3', 'c3')
31
- host = app_session.host
32
- except:
33
- pass
32
+ log(lines_to_tabular([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
+ ], 'DEVICE\tLOCATION', separator='\t'))
37
+ log()
34
38
 
35
- log(lines_to_tabular([device.pwd(state) for device in Devices.all()] + [
36
- f'',
37
- f'HOST\t{host}',
38
- f'NAMESPACE\t{state.namespace if state.namespace else "/"}',
39
- ], 'DEVICE\tLOCATION', separator='\t'))
40
- log()
41
-
42
- return state
39
+ return state
43
40
 
44
41
  def completion(self, state: ReplState):
45
42
  return super().completion(state)
@@ -1,6 +1,6 @@
1
1
  import click
2
2
 
3
- from adam.commands.command import Command
3
+ from adam.commands.intermediate_command import IntermediateCommand
4
4
  from .reaper_forward import ReaperForward
5
5
  from .reaper_forward_stop import ReaperForwardStop
6
6
  from .reaper_restart import ReaperRestart
@@ -12,11 +12,9 @@ from .reaper_schedule_start import ReaperScheduleStart
12
12
  from .reaper_schedule_stop import ReaperScheduleStop
13
13
  from .reaper_schedules import ReaperSchedules
14
14
  from .reaper_status import ReaperStatus
15
- from adam.repl_state import ReplState, RequiredState
16
15
 
17
- class Reaper(Command):
16
+ class Reaper(IntermediateCommand):
18
17
  COMMAND = 'reaper'
19
- reaper_login = None
20
18
 
21
19
  # the singleton pattern
22
20
  def __new__(cls, *args, **kwargs):
@@ -24,35 +22,14 @@ class Reaper(Command):
24
22
 
25
23
  return cls.instance
26
24
 
27
- def __init__(self, successor: Command=None):
28
- super().__init__(successor)
29
-
30
25
  def command(self):
31
26
  return Reaper.COMMAND
32
27
 
33
- def required(self):
34
- return RequiredState.CLUSTER
35
-
36
- def run(self, cmd: str, state: ReplState):
37
- if not(args := self.args(cmd)):
38
- return super().run(cmd, state)
39
-
40
- if not self.validate_state(state):
41
- return state
42
-
43
- return super().intermediate_run(cmd, state, args, Reaper.cmd_list())
44
-
45
- def cmd_list():
28
+ def cmd_list(self):
46
29
  return [ReaperSchedules(), ReaperScheduleStop(), ReaperScheduleActivate(), ReaperScheduleStart(),
47
30
  ReaperForwardStop(), ReaperForward(), ReaperRunAbort(), ReaperRunsAbort(), ReaperRestart(),
48
31
  ReaperRuns(), ReaperStatus()]
49
32
 
50
- def completion(self, state: ReplState):
51
- if state.sts:
52
- return super().completion(state)
53
-
54
- return {}
55
-
56
33
  class ReaperCommandHelper(click.Command):
57
34
  def get_help(self, ctx: click.Context):
58
- Command.intermediate_help(super().get_help(ctx), Reaper.COMMAND, Reaper.cmd_list(), show_cluster_help=True)
35
+ IntermediateCommand.intermediate_help(super().get_help(ctx), Reaper.COMMAND, Reaper().cmd_list(), show_cluster_help=True)
@@ -1,8 +1,10 @@
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
@@ -10,7 +12,6 @@ from adam.utils import lines_to_tabular, 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
+ log2(lines_to_tabular([f'{k},{v}' for k, v in d.items()], 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.commands.reaper.utils_reaper import Reapers
2
3
  from adam.utils_k8s.pods import Pods
3
- from .reaper_session import ReaperSession
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'