kaqing 1.77.0__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 (308) hide show
  1. adam/__init__.py +1 -0
  2. adam/app_session.py +182 -0
  3. {walker → adam}/apps.py +8 -24
  4. {walker → adam}/batch.py +54 -97
  5. {walker → adam}/checks/check.py +3 -3
  6. {walker → adam}/checks/check_result.py +1 -1
  7. adam/checks/check_utils.py +65 -0
  8. {walker → adam}/checks/compactionstats.py +6 -6
  9. {walker → adam}/checks/cpu.py +14 -8
  10. adam/checks/cpu_metrics.py +52 -0
  11. {walker → adam}/checks/disk.py +6 -6
  12. {walker → adam}/checks/gossip.py +5 -5
  13. {walker → adam}/checks/memory.py +7 -7
  14. {walker → adam}/checks/status.py +5 -5
  15. {walker → adam}/cli.py +3 -3
  16. {walker → adam}/columns/column.py +1 -1
  17. adam/columns/columns.py +45 -0
  18. {walker → adam}/columns/compactions.py +5 -5
  19. {walker → adam}/columns/cpu.py +6 -4
  20. adam/columns/cpu_metrics.py +22 -0
  21. {walker → adam}/columns/dir_data.py +3 -3
  22. {walker → adam}/columns/dir_snapshots.py +3 -3
  23. {walker → adam}/columns/gossip.py +5 -5
  24. {walker → adam}/columns/host_id.py +3 -3
  25. {walker → adam}/columns/memory.py +3 -3
  26. {walker → adam}/columns/node_address.py +3 -3
  27. {walker → adam}/columns/node_load.py +3 -3
  28. {walker → adam}/columns/node_owns.py +3 -3
  29. {walker → adam}/columns/node_status.py +3 -3
  30. {walker → adam}/columns/node_tokens.py +3 -3
  31. {walker → adam}/columns/node_utils.py +2 -2
  32. {walker → adam}/columns/pod_name.py +2 -2
  33. {walker → adam}/columns/volume_cassandra.py +4 -4
  34. {walker → adam}/columns/volume_root.py +3 -3
  35. adam/commands/__init__.py +15 -0
  36. adam/commands/alter_tables.py +81 -0
  37. adam/commands/app_cmd.py +38 -0
  38. {walker → adam}/commands/app_ping.py +10 -16
  39. adam/commands/audit/audit.py +84 -0
  40. adam/commands/audit/audit_repair_tables.py +74 -0
  41. adam/commands/audit/audit_run.py +50 -0
  42. adam/commands/audit/show_last10.py +48 -0
  43. adam/commands/audit/show_slow10.py +47 -0
  44. adam/commands/audit/show_top10.py +45 -0
  45. adam/commands/audit/utils_show_top10.py +59 -0
  46. adam/commands/bash/__init__.py +5 -0
  47. adam/commands/bash/bash.py +36 -0
  48. adam/commands/bash/bash_completer.py +93 -0
  49. adam/commands/bash/utils_bash.py +16 -0
  50. adam/commands/cat.py +50 -0
  51. adam/commands/cd.py +43 -0
  52. adam/commands/check.py +73 -0
  53. {walker → adam}/commands/cli_commands.py +7 -8
  54. adam/commands/code.py +57 -0
  55. adam/commands/command.py +190 -0
  56. {walker → adam}/commands/command_helpers.py +1 -1
  57. {walker → adam}/commands/commands_utils.py +15 -25
  58. adam/commands/cp.py +89 -0
  59. adam/commands/cql/cql_completions.py +33 -0
  60. {walker/commands → adam/commands/cql}/cqlsh.py +20 -35
  61. adam/commands/cql/utils_cql.py +343 -0
  62. {walker/commands/frontend → adam/commands/deploy}/code_start.py +11 -14
  63. adam/commands/deploy/code_stop.py +40 -0
  64. {walker/commands/frontend → adam/commands/deploy}/code_utils.py +7 -9
  65. adam/commands/deploy/deploy.py +25 -0
  66. adam/commands/deploy/deploy_frontend.py +49 -0
  67. adam/commands/deploy/deploy_pg_agent.py +35 -0
  68. adam/commands/deploy/deploy_pod.py +108 -0
  69. adam/commands/deploy/deploy_utils.py +29 -0
  70. adam/commands/deploy/undeploy.py +25 -0
  71. adam/commands/deploy/undeploy_frontend.py +38 -0
  72. adam/commands/deploy/undeploy_pg_agent.py +39 -0
  73. adam/commands/deploy/undeploy_pod.py +48 -0
  74. adam/commands/devices/device.py +118 -0
  75. adam/commands/devices/device_app.py +173 -0
  76. adam/commands/devices/device_auit_log.py +49 -0
  77. adam/commands/devices/device_cass.py +185 -0
  78. adam/commands/devices/device_export.py +86 -0
  79. adam/commands/devices/device_postgres.py +144 -0
  80. adam/commands/devices/devices.py +25 -0
  81. {walker → adam}/commands/exit.py +3 -6
  82. adam/commands/export/clean_up_all_export_sessions.py +37 -0
  83. adam/commands/export/clean_up_export_sessions.py +51 -0
  84. adam/commands/export/drop_export_database.py +55 -0
  85. adam/commands/export/drop_export_databases.py +43 -0
  86. adam/commands/export/export.py +53 -0
  87. adam/commands/export/export_databases.py +170 -0
  88. adam/commands/export/export_handlers.py +71 -0
  89. adam/commands/export/export_select.py +81 -0
  90. adam/commands/export/export_select_x.py +54 -0
  91. adam/commands/export/export_use.py +52 -0
  92. adam/commands/export/exporter.py +352 -0
  93. adam/commands/export/import_session.py +40 -0
  94. adam/commands/export/importer.py +67 -0
  95. adam/commands/export/importer_athena.py +80 -0
  96. adam/commands/export/importer_sqlite.py +47 -0
  97. adam/commands/export/show_column_counts.py +54 -0
  98. adam/commands/export/show_export_databases.py +36 -0
  99. adam/commands/export/show_export_session.py +48 -0
  100. adam/commands/export/show_export_sessions.py +44 -0
  101. adam/commands/export/utils_export.py +314 -0
  102. {walker → adam}/commands/help.py +17 -12
  103. adam/commands/intermediate_command.py +49 -0
  104. adam/commands/issues.py +43 -0
  105. adam/commands/kubectl.py +38 -0
  106. adam/commands/login.py +70 -0
  107. {walker → adam}/commands/logs.py +8 -10
  108. adam/commands/ls.py +41 -0
  109. adam/commands/medusa/medusa.py +27 -0
  110. adam/commands/medusa/medusa_backup.py +57 -0
  111. adam/commands/medusa/medusa_restore.py +83 -0
  112. adam/commands/medusa/medusa_show_backupjobs.py +51 -0
  113. adam/commands/medusa/medusa_show_restorejobs.py +47 -0
  114. {walker → adam}/commands/nodetool.py +17 -21
  115. {walker → adam}/commands/param_get.py +15 -16
  116. adam/commands/param_set.py +43 -0
  117. adam/commands/postgres/postgres.py +104 -0
  118. adam/commands/postgres/postgres_context.py +274 -0
  119. {walker → adam}/commands/postgres/postgres_ls.py +7 -11
  120. {walker → adam}/commands/postgres/postgres_preview.py +8 -13
  121. adam/commands/postgres/psql_completions.py +10 -0
  122. adam/commands/postgres/utils_postgres.py +66 -0
  123. adam/commands/preview_table.py +37 -0
  124. adam/commands/pwd.py +47 -0
  125. adam/commands/reaper/reaper.py +35 -0
  126. adam/commands/reaper/reaper_forward.py +93 -0
  127. adam/commands/reaper/reaper_forward_session.py +6 -0
  128. {walker → adam}/commands/reaper/reaper_forward_stop.py +13 -19
  129. {walker → adam}/commands/reaper/reaper_restart.py +10 -17
  130. adam/commands/reaper/reaper_run_abort.py +46 -0
  131. adam/commands/reaper/reaper_runs.py +82 -0
  132. adam/commands/reaper/reaper_runs_abort.py +63 -0
  133. adam/commands/reaper/reaper_schedule_activate.py +45 -0
  134. adam/commands/reaper/reaper_schedule_start.py +45 -0
  135. adam/commands/reaper/reaper_schedule_stop.py +45 -0
  136. {walker → adam}/commands/reaper/reaper_schedules.py +6 -16
  137. {walker → adam}/commands/reaper/reaper_status.py +11 -19
  138. adam/commands/reaper/utils_reaper.py +196 -0
  139. adam/commands/repair/repair.py +26 -0
  140. {walker → adam}/commands/repair/repair_log.py +7 -10
  141. adam/commands/repair/repair_run.py +70 -0
  142. adam/commands/repair/repair_scan.py +71 -0
  143. {walker → adam}/commands/repair/repair_stop.py +8 -11
  144. adam/commands/report.py +61 -0
  145. adam/commands/restart.py +60 -0
  146. {walker → adam}/commands/rollout.py +25 -30
  147. adam/commands/shell.py +34 -0
  148. adam/commands/show/show.py +39 -0
  149. walker/commands/show/show_version.py → adam/commands/show/show_adam.py +14 -10
  150. adam/commands/show/show_app_actions.py +57 -0
  151. {walker → adam}/commands/show/show_app_id.py +12 -15
  152. {walker → adam}/commands/show/show_app_queues.py +9 -12
  153. adam/commands/show/show_cassandra_repairs.py +38 -0
  154. adam/commands/show/show_cassandra_status.py +124 -0
  155. {walker → adam}/commands/show/show_cassandra_version.py +6 -16
  156. adam/commands/show/show_commands.py +59 -0
  157. walker/commands/show/show_storage.py → adam/commands/show/show_host.py +11 -13
  158. adam/commands/show/show_login.py +62 -0
  159. {walker → adam}/commands/show/show_params.py +4 -4
  160. adam/commands/show/show_processes.py +51 -0
  161. adam/commands/show/show_storage.py +42 -0
  162. adam/commands/watch.py +82 -0
  163. {walker → adam}/config.py +10 -22
  164. {walker → adam}/embedded_apps.py +1 -1
  165. adam/embedded_params.py +2 -0
  166. adam/log.py +47 -0
  167. {walker → adam}/pod_exec_result.py +10 -2
  168. adam/repl.py +182 -0
  169. adam/repl_commands.py +124 -0
  170. adam/repl_state.py +458 -0
  171. adam/sql/__init__.py +0 -0
  172. adam/sql/sql_completer.py +120 -0
  173. adam/sql/sql_state_machine.py +618 -0
  174. adam/sql/term_completer.py +76 -0
  175. adam/sso/__init__.py +0 -0
  176. {walker → adam}/sso/authenticator.py +5 -1
  177. adam/sso/authn_ad.py +170 -0
  178. {walker → adam}/sso/authn_okta.py +39 -22
  179. adam/sso/cred_cache.py +60 -0
  180. adam/sso/id_token.py +23 -0
  181. adam/sso/idp.py +143 -0
  182. adam/sso/idp_login.py +50 -0
  183. adam/sso/idp_session.py +55 -0
  184. adam/sso/sso_config.py +63 -0
  185. adam/utils.py +679 -0
  186. adam/utils_app.py +98 -0
  187. adam/utils_athena.py +145 -0
  188. adam/utils_audits.py +106 -0
  189. adam/utils_issues.py +32 -0
  190. adam/utils_k8s/__init__.py +0 -0
  191. adam/utils_k8s/app_clusters.py +28 -0
  192. adam/utils_k8s/app_pods.py +33 -0
  193. adam/utils_k8s/cassandra_clusters.py +36 -0
  194. adam/utils_k8s/cassandra_nodes.py +33 -0
  195. adam/utils_k8s/config_maps.py +34 -0
  196. {walker/k8s_utils → adam/utils_k8s}/custom_resources.py +7 -2
  197. adam/utils_k8s/deployment.py +56 -0
  198. {walker/k8s_utils → adam/utils_k8s}/ingresses.py +3 -4
  199. {walker/k8s_utils → adam/utils_k8s}/jobs.py +3 -3
  200. adam/utils_k8s/k8s.py +87 -0
  201. {walker/k8s_utils → adam/utils_k8s}/kube_context.py +4 -4
  202. adam/utils_k8s/pods.py +290 -0
  203. {walker/k8s_utils → adam/utils_k8s}/secrets.py +8 -4
  204. adam/utils_k8s/service_accounts.py +170 -0
  205. {walker/k8s_utils → adam/utils_k8s}/services.py +3 -4
  206. {walker/k8s_utils → adam/utils_k8s}/statefulsets.py +6 -16
  207. {walker/k8s_utils → adam/utils_k8s}/volumes.py +10 -1
  208. adam/utils_net.py +24 -0
  209. adam/utils_repl/__init__.py +0 -0
  210. adam/utils_repl/automata_completer.py +48 -0
  211. adam/utils_repl/repl_completer.py +46 -0
  212. adam/utils_repl/state_machine.py +173 -0
  213. adam/utils_sqlite.py +109 -0
  214. adam/version.py +5 -0
  215. {kaqing-1.77.0.dist-info → kaqing-2.0.171.dist-info}/METADATA +1 -1
  216. kaqing-2.0.171.dist-info/RECORD +236 -0
  217. kaqing-2.0.171.dist-info/entry_points.txt +3 -0
  218. kaqing-2.0.171.dist-info/top_level.txt +1 -0
  219. kaqing-1.77.0.dist-info/RECORD +0 -159
  220. kaqing-1.77.0.dist-info/entry_points.txt +0 -3
  221. kaqing-1.77.0.dist-info/top_level.txt +0 -1
  222. walker/__init__.py +0 -3
  223. walker/app_session.py +0 -168
  224. walker/checks/check_utils.py +0 -97
  225. walker/columns/columns.py +0 -43
  226. walker/commands/add_user.py +0 -68
  227. walker/commands/app.py +0 -67
  228. walker/commands/bash.py +0 -87
  229. walker/commands/cd.py +0 -115
  230. walker/commands/check.py +0 -68
  231. walker/commands/command.py +0 -104
  232. walker/commands/cp.py +0 -95
  233. walker/commands/cql_utils.py +0 -53
  234. walker/commands/devices.py +0 -89
  235. walker/commands/frontend/code_stop.py +0 -57
  236. walker/commands/frontend/setup.py +0 -60
  237. walker/commands/frontend/setup_frontend.py +0 -58
  238. walker/commands/frontend/teardown.py +0 -61
  239. walker/commands/frontend/teardown_frontend.py +0 -42
  240. walker/commands/issues.py +0 -69
  241. walker/commands/login.py +0 -72
  242. walker/commands/ls.py +0 -145
  243. walker/commands/medusa/medusa.py +0 -69
  244. walker/commands/medusa/medusa_backup.py +0 -61
  245. walker/commands/medusa/medusa_restore.py +0 -86
  246. walker/commands/medusa/medusa_show_backupjobs.py +0 -52
  247. walker/commands/medusa/medusa_show_restorejobs.py +0 -52
  248. walker/commands/param_set.py +0 -44
  249. walker/commands/postgres/postgres.py +0 -113
  250. walker/commands/postgres/postgres_session.py +0 -225
  251. walker/commands/preview_table.py +0 -98
  252. walker/commands/processes.py +0 -53
  253. walker/commands/pwd.py +0 -64
  254. walker/commands/reaper/reaper.py +0 -78
  255. walker/commands/reaper/reaper_forward.py +0 -100
  256. walker/commands/reaper/reaper_run_abort.py +0 -65
  257. walker/commands/reaper/reaper_runs.py +0 -97
  258. walker/commands/reaper/reaper_runs_abort.py +0 -83
  259. walker/commands/reaper/reaper_schedule_activate.py +0 -64
  260. walker/commands/reaper/reaper_schedule_start.py +0 -64
  261. walker/commands/reaper/reaper_schedule_stop.py +0 -64
  262. walker/commands/reaper/reaper_session.py +0 -159
  263. walker/commands/repair/repair.py +0 -68
  264. walker/commands/repair/repair_run.py +0 -72
  265. walker/commands/repair/repair_scan.py +0 -79
  266. walker/commands/report.py +0 -57
  267. walker/commands/restart.py +0 -61
  268. walker/commands/show/show.py +0 -72
  269. walker/commands/show/show_app_actions.py +0 -53
  270. walker/commands/show/show_cassandra_status.py +0 -35
  271. walker/commands/show/show_commands.py +0 -58
  272. walker/commands/show/show_processes.py +0 -35
  273. walker/commands/show/show_repairs.py +0 -47
  274. walker/commands/status.py +0 -128
  275. walker/commands/storage.py +0 -52
  276. walker/commands/user_entry.py +0 -69
  277. walker/commands/watch.py +0 -85
  278. walker/embedded_params.py +0 -2
  279. walker/k8s_utils/cassandra_clusters.py +0 -48
  280. walker/k8s_utils/cassandra_nodes.py +0 -26
  281. walker/k8s_utils/pods.py +0 -211
  282. walker/repl.py +0 -165
  283. walker/repl_commands.py +0 -58
  284. walker/repl_state.py +0 -211
  285. walker/sso/authn_ad.py +0 -94
  286. walker/sso/idp.py +0 -150
  287. walker/sso/idp_login.py +0 -29
  288. walker/sso/sso_config.py +0 -45
  289. walker/utils.py +0 -194
  290. walker/version.py +0 -5
  291. {walker → adam}/checks/__init__.py +0 -0
  292. {walker → adam}/checks/check_context.py +0 -0
  293. {walker → adam}/checks/issue.py +0 -0
  294. {walker → adam}/cli_group.py +0 -0
  295. {walker → adam}/columns/__init__.py +0 -0
  296. {walker/commands → adam/commands/audit}/__init__.py +0 -0
  297. {walker/commands/frontend → adam/commands/cql}/__init__.py +0 -0
  298. {walker/commands/medusa → adam/commands/deploy}/__init__.py +0 -0
  299. {walker/commands/postgres → adam/commands/devices}/__init__.py +0 -0
  300. {walker/commands/reaper → adam/commands/export}/__init__.py +0 -0
  301. {walker/commands/repair → adam/commands/medusa}/__init__.py +0 -0
  302. {walker → adam}/commands/nodetool_commands.py +0 -0
  303. {walker/commands/show → adam/commands/postgres}/__init__.py +0 -0
  304. {walker/k8s_utils → adam/commands/reaper}/__init__.py +0 -0
  305. {walker/sso → adam/commands/repair}/__init__.py +0 -0
  306. /walker/medusa_show_restorejobs.py → /adam/commands/show/__init__.py +0 -0
  307. {walker → adam}/repl_session.py +0 -0
  308. {kaqing-1.77.0.dist-info → kaqing-2.0.171.dist-info}/WHEEL +0 -0
@@ -1,97 +0,0 @@
1
- import requests
2
-
3
- from walker.commands.command import Command
4
- from .reaper_session import ReaperSession
5
- from walker.config import Config
6
- from walker.repl_state import ReplState, RequiredState
7
- from walker.utils import convert_seconds, epoch, lines_to_tabular, log, log2
8
-
9
- class ReaperRuns(Command):
10
- COMMAND = 'reaper show runs'
11
- reaper_login = None
12
-
13
- # the singleton pattern
14
- def __new__(cls, *args, **kwargs):
15
- if not hasattr(cls, 'instance'): cls.instance = super(ReaperRuns, cls).__new__(cls)
16
-
17
- return cls.instance
18
-
19
- def __init__(self, successor: Command=None):
20
- super().__init__(successor)
21
-
22
- def command(self):
23
- return ReaperRuns.COMMAND
24
-
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
- state, args = self.apply_state(args, state)
33
- if not self.validate_state(state):
34
- return state
35
-
36
- if not(reaper := ReaperSession.create(state)):
37
- return state
38
-
39
- self.show_runs(state, reaper)
40
-
41
- return state
42
-
43
- def show_runs(self, state: ReplState, reaper: ReaperSession):
44
- def body(uri: str, headers: dict[str, str]):
45
- return requests.get(uri, headers=headers, params={
46
- 'cluster_name': 'all',
47
- 'limit': Config().get('reaper.show-runs-batch', 10)
48
- })
49
-
50
- def line(run):
51
- state = run['state']
52
- start_time = run['start_time']
53
- end_time = run['end_time']
54
- duration = '-'
55
- if state == 'DONE' and end_time:
56
- hours, minutes, seconds = convert_seconds(epoch(end_time) - epoch(start_time))
57
- if hours:
58
- duration = f"{hours:2d}h {minutes:2d}m {seconds:2d}s"
59
- elif minutes:
60
- duration = f"{minutes:2d}m {seconds:2d}s"
61
- else:
62
- duration = f"{seconds:2d}s"
63
-
64
- return f"{start_time},{duration},{state},{run['cluster_name']},{run['keyspace_name']},{len(run['column_families'])},{run['segments_repaired']}/{run['total_segments']}"
65
-
66
- # PAUSED, RUNNING, ABORTED
67
- response = reaper.port_forwarded(state, 'repair_run?state=RUNNING', body, method='GET')
68
- if not response:
69
- return
70
-
71
- header = 'Start,Duration,State,Cluster,Keyspace,Tables,Repaired'
72
-
73
- runs = response.json()
74
- if runs:
75
- log(lines_to_tabular(sorted([line(run) for run in runs], reverse=True), header, separator=","))
76
- else:
77
- log2('No running runs found.')
78
- log2()
79
-
80
- response = reaper.port_forwarded(state, 'repair_run?state=PAUSED,ABORTED,DONE', body, method='GET')
81
- if not response:
82
- return
83
-
84
- runs = response.json()
85
- if runs:
86
- log(lines_to_tabular(sorted([line(run) for run in runs], reverse=True), header, separator=","))
87
- else:
88
- log2('No runs found.')
89
-
90
- def completion(self, state: ReplState):
91
- if state.sts:
92
- return super().completion(state)
93
-
94
- return {}
95
-
96
- def help(self, _: ReplState):
97
- return f'{ReaperRuns.COMMAND}\t show reaper runs'
@@ -1,83 +0,0 @@
1
- import requests
2
-
3
- from walker.commands.command import Command
4
- from .reaper_session import ReaperSession
5
- from walker.config import Config
6
- from walker.repl_state import ReplState, RequiredState
7
- from walker.utils import log2
8
-
9
- class ReaperRunsAbort(Command):
10
- COMMAND = 'reaper abort runs'
11
- reaper_login = None
12
-
13
- # the singleton pattern
14
- def __new__(cls, *args, **kwargs):
15
- if not hasattr(cls, 'instance'): cls.instance = super(ReaperRunsAbort, cls).__new__(cls)
16
-
17
- return cls.instance
18
-
19
- def __init__(self, successor: Command=None):
20
- super().__init__(successor)
21
-
22
- def command(self):
23
- return ReaperRunsAbort.COMMAND
24
-
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
- state, args = self.apply_state(args, state)
33
- if not self.validate_state(state):
34
- return state
35
-
36
- if not(reaper := ReaperSession.create(state)):
37
- return state
38
-
39
- self.stop_runs(state, reaper)
40
-
41
- return state
42
-
43
- def stop_runs(self, state: ReplState, reaper: ReaperSession):
44
- def body_list(uri: str, headers: dict[str, str]):
45
- return requests.get(uri, headers=headers, params={
46
- 'cluster_name': 'all',
47
- 'limit': Config().get('reaper.abort-runs-batch', 10)
48
- })
49
-
50
- def body_abort(uri: str, headers: dict[str, str]):
51
- return requests.put(uri, headers=headers)
52
-
53
- # PAUSED, RUNNING, ABORTED
54
- aborted = 0
55
- while True == True:
56
- response = reaper.port_forwarded(state, 'repair_run?state=RUNNING', body_list, method='GET')
57
- if not response:
58
- break
59
-
60
- runs = response.json()
61
- if not runs:
62
- break
63
-
64
- for run in runs:
65
- run_id = run['id']
66
- # PUT /repair_run/{id}/state/{state}
67
- reaper.port_forwarded(state, f'repair_run/{run_id}/state/ABORTED', body_abort, method='PUT')
68
- log2(f'Aborted {len(runs)} runs.')
69
- aborted += 1
70
-
71
- if aborted:
72
- log2(f'Aborted {aborted} runs in total.')
73
- else:
74
- log2('No running repair runs found.')
75
-
76
- def completion(self, state: ReplState):
77
- if state.sts:
78
- return super().completion(state)
79
-
80
- return {}
81
-
82
- def help(self, _: ReplState):
83
- return f'{ReaperRunsAbort.COMMAND}\t abort all running reaper runs'
@@ -1,64 +0,0 @@
1
- import requests
2
-
3
- from walker.commands.command import Command
4
- from .reaper_session import ReaperSession
5
- from walker.repl_state import ReplState, RequiredState
6
- from walker.utils import log2
7
-
8
- class ReaperScheduleActivate(Command):
9
- COMMAND = 'reaper activate schedule'
10
- reaper_login = None
11
-
12
- # the singleton pattern
13
- def __new__(cls, *args, **kwargs):
14
- if not hasattr(cls, 'instance'): cls.instance = super(ReaperScheduleActivate, cls).__new__(cls)
15
-
16
- return cls.instance
17
-
18
- def __init__(self, successor: Command=None):
19
- super().__init__(successor)
20
-
21
- def command(self):
22
- return ReaperScheduleActivate.COMMAND
23
-
24
- def required(self):
25
- return RequiredState.CLUSTER
26
-
27
- def run(self, cmd: str, state: ReplState):
28
- if not(args := self.args(cmd)):
29
- return super().run(cmd, state)
30
-
31
- state, args = self.apply_state(args, state)
32
- if not self.validate_state(state):
33
- return state
34
-
35
- if not args:
36
- log2('Specify schedule to activate.')
37
-
38
- return state
39
-
40
- schedule_id = args[0]
41
- if not(reaper := ReaperSession.create(state)):
42
- return state
43
-
44
- self.activate_schedule(state, reaper, schedule_id)
45
-
46
- return schedule_id
47
-
48
- def activate_schedule(self, state: ReplState, reaper: ReaperSession, schedule_id: str):
49
- def body(uri: str, headers: dict[str, str]):
50
- return requests.put(uri, headers=headers)
51
-
52
- reaper.port_forwarded(state, f'repair_schedule/{schedule_id}?state=ACTIVE', body, method='PUT')
53
- reaper.show_schedule(state, schedule_id)
54
-
55
- def completion(self, state: ReplState):
56
- if state.sts:
57
- leaf = {id: None for id in ReaperSession.cached_schedule_ids(state)}
58
-
59
- return super().completion(state, leaf)
60
-
61
- return {}
62
-
63
- def help(self, _: ReplState):
64
- return f'{ReaperScheduleActivate.COMMAND} <schedule-id>\t resume reaper schedule'
@@ -1,64 +0,0 @@
1
- import requests
2
-
3
- from walker.commands.command import Command
4
- from .reaper_session import ReaperSession
5
- from walker.repl_state import ReplState, RequiredState
6
- from walker.utils import log2
7
-
8
- class ReaperScheduleStart(Command):
9
- COMMAND = 'reaper start schedule'
10
- reaper_login = None
11
-
12
- # the singleton pattern
13
- def __new__(cls, *args, **kwargs):
14
- if not hasattr(cls, 'instance'): cls.instance = super(ReaperScheduleStart, cls).__new__(cls)
15
-
16
- return cls.instance
17
-
18
- def __init__(self, successor: Command=None):
19
- super().__init__(successor)
20
-
21
- def command(self):
22
- return ReaperScheduleStart.COMMAND
23
-
24
- def required(self):
25
- return RequiredState.CLUSTER
26
-
27
- def run(self, cmd: str, state: ReplState):
28
- if not(args := self.args(cmd)):
29
- return super().run(cmd, state)
30
-
31
- state, args = self.apply_state(args, state)
32
- if not self.validate_state(state):
33
- return state
34
-
35
- if not args:
36
- log2('Specify schedule to activate.')
37
-
38
- return state
39
-
40
- schedule_id = args[0]
41
- if not(reaper := ReaperSession.create(state)):
42
- return schedule_id
43
-
44
- self.start_schedule(state, reaper, schedule_id)
45
-
46
- return schedule_id
47
-
48
- def start_schedule(self, state: ReplState, reaper: ReaperSession, schedule_id: str):
49
- def body(uri: str, headers: dict[str, str]):
50
- return requests.post(uri, headers=headers)
51
-
52
- reaper.port_forwarded(state, f'repair_schedule/start/{schedule_id}', body, method='POST')
53
- reaper.show_schedule(state, schedule_id)
54
-
55
- def completion(self, state: ReplState):
56
- if state.sts:
57
- leaf = {id: None for id in ReaperSession.cached_schedule_ids(state)}
58
-
59
- return super().completion(state, leaf)
60
-
61
- return {}
62
-
63
- def help(self, _: ReplState):
64
- return f'{ReaperScheduleStart.COMMAND} <schedule-id>\t start reaper runs for schedule'
@@ -1,64 +0,0 @@
1
- import requests
2
-
3
- from walker.commands.command import Command
4
- from .reaper_session import ReaperSession
5
- from walker.repl_state import ReplState, RequiredState
6
- from walker.utils import log2
7
-
8
- class ReaperScheduleStop(Command):
9
- COMMAND = 'reaper stop schedule'
10
- reaper_login = None
11
-
12
- # the singleton pattern
13
- def __new__(cls, *args, **kwargs):
14
- if not hasattr(cls, 'instance'): cls.instance = super(ReaperScheduleStop, cls).__new__(cls)
15
-
16
- return cls.instance
17
-
18
- def __init__(self, successor: Command=None):
19
- super().__init__(successor)
20
-
21
- def command(self):
22
- return ReaperScheduleStop.COMMAND
23
-
24
- def required(self):
25
- return RequiredState.CLUSTER
26
-
27
- def run(self, cmd: str, state: ReplState):
28
- if not(args := self.args(cmd)):
29
- return super().run(cmd, state)
30
-
31
- state, args = self.apply_state(args, state)
32
- if not self.validate_state(state):
33
- return state
34
-
35
- if not args:
36
- log2('Specify run schedule to stop.')
37
-
38
- return state
39
-
40
- schedule_id = args[0]
41
- if not(reaper := ReaperSession.create(state)):
42
- return schedule_id
43
-
44
- self.stop_schedule(state, reaper, schedule_id)
45
-
46
- return schedule_id
47
-
48
- def stop_schedule(self, state: ReplState, reaper: ReaperSession, schedule_id: str):
49
- def body(uri: str, headers: dict[str, str]):
50
- return requests.put(uri, headers=headers)
51
-
52
- reaper.port_forwarded(state, f'repair_schedule/{schedule_id}?state=PAUSED', body, method='PUT')
53
- reaper.show_schedule(state, schedule_id)
54
-
55
- def completion(self, state: ReplState):
56
- if state.sts:
57
- leaf = {id: None for id in ReaperSession.cached_schedule_ids(state)}
58
-
59
- return super().completion(state, leaf)
60
-
61
- return {}
62
-
63
- def help(self, _: ReplState):
64
- return f'{ReaperScheduleStop.COMMAND} <schedule-id>\t pause reaper schedule'
@@ -1,159 +0,0 @@
1
- from collections.abc import Callable
2
- import threading
3
- from kubernetes import client
4
- import portforward
5
- import re
6
- import requests
7
- from typing import List, cast
8
-
9
- from walker.config import Config
10
- from walker.k8s_utils.kube_context import KubeContext
11
- from walker.repl_state import ReplState
12
- from walker.utils import lines_to_tabular, log2
13
-
14
- class ReaperSession:
15
- is_forwarding = False
16
- stopping = threading.Event()
17
- schedules_ids_by_cluster: dict[str, list[str]] = {}
18
-
19
- def __init__(self, pod: str, headers: dict[str, str] = None):
20
- self.pod = pod
21
- self.headers = headers
22
-
23
- def login(self, state: ReplState, local_addr: str, remote_addr: str, show_output = True) -> str :
24
- user, pw = state.user_pass(secret_path='reaper.secret')
25
-
26
- response = requests.post(f'http://{local_addr}/login', headers={
27
- 'Accept': '*'
28
- },data={
29
- 'username':user,
30
- 'password':pw})
31
- if show_output:
32
- log2(f'POST {remote_addr}/login')
33
- log2(f' username={user}&password={pw}')
34
-
35
- if int(response.status_code / 100) != 2:
36
- if show_output:
37
- log2("login failed")
38
- return None
39
-
40
- return response.headers['Set-Cookie']
41
-
42
- def port_forwarded(self, state: ReplState, path: str, body: Callable[[str, dict[str, str]], requests.Response], method: str = None, show_output = True):
43
- local_port = Config().get('reaper.port-forward.local-port', 9001)
44
- target_port = 8080
45
-
46
- def f(local_addr: str, remote_addr: str):
47
- if not self.headers:
48
- self.headers = self.cookie_header(state, local_addr, remote_addr, show_output=show_output)
49
-
50
- if show_output and method:
51
- log2(f'{method} {remote_addr}/{path}')
52
- response = body(f'http://{local_addr}/{path}', self.headers)
53
-
54
- if response:
55
- if int(response.status_code / 100) != 2:
56
- if show_output:
57
- log2(response.status_code)
58
- return response
59
-
60
- if show_output:
61
- log2()
62
-
63
- return response if response else 'no-response'
64
-
65
- if KubeContext.in_cluster():
66
- # cs-a526330d23-cs-a526330d23-default-sts-0 ->
67
- # curl http://cs-a526330d23-cs-a526330d23-reaper-service.stgawsscpsr.svc.cluster.local:8080
68
- groups = re.match(r'^(.*?-.*?-.*?-.*?-).*', state.sts)
69
- if groups:
70
- svc_name = Config().get('reaper.service-name', 'reaper-service')
71
- svc = f'{groups[1]}{svc_name}.{state.namespace}.svc.cluster.local:{target_port}'
72
- return f(local_addr=svc, remote_addr=svc)
73
- else:
74
- return None
75
- else:
76
- with portforward.forward(state.namespace, self.pod, local_port, target_port):
77
- return f(local_addr=f'localhost:{local_port}', remote_addr=f'{self.pod}:{target_port}')
78
-
79
- def cookie_header(self, state: ReplState, local_addr, remote_addr, show_output = True):
80
- return {'Cookie': self.login(state, local_addr, remote_addr, show_output=show_output)}
81
-
82
- def create(state: ReplState) -> 'ReaperSession':
83
- pods = ReaperSession.list_reaper_pods(state.sts if state.sts else state.pod, state.namespace)
84
- if pods:
85
- return ReaperSession(pods[0].metadata.name)
86
- else:
87
- log2('No reaper found.')
88
-
89
- return None
90
-
91
- def list_reaper_pods(sts_name: str, namespace: str) -> List[client.V1Pod]:
92
- v1 = client.CoreV1Api()
93
-
94
- # k8ssandra.io/reaper: cs-d0767a536f-cs-d0767a536f-reaper
95
- groups = re.match(Config().get('reaper.pod.cluster-regex', r'(.*?-.*?-.*?-.*?)-.*'), sts_name)
96
- label_selector = Config().get('reaper.pod.label-selector', 'k8ssandra.io/reaper={cluster}-reaper').replace('{cluster}', groups[1])
97
-
98
- return cast(List[client.V1Pod], v1.list_namespaced_pod(namespace, label_selector=label_selector).items)
99
-
100
- def show_schedules(self, state: ReplState, filter: Callable[[list[dict]], dict] = None):
101
- schedules = self.list_schedules(state, filter=filter)
102
- # forced refresh of schedule list
103
- if not filter:
104
- self.schedules_ids_by_cluster[state.sts] = [schedule['id'] for schedule in schedules]
105
- self.show_schedules_tabular(schedules)
106
-
107
- def schedule_ids(self, state: ReplState, show_output = True, filter: Callable[[list[dict]], dict] = None):
108
- schedules = self.list_schedules(state, show_output=show_output, filter=filter)
109
- return [schedule['id'] for schedule in schedules]
110
-
111
- def list_schedules(self, state: ReplState, show_output = True, filter: Callable[[list[dict]], dict] = None) -> list[dict]:
112
- def body(uri: str, headers: dict[str, str]):
113
- return requests.get(uri, headers=headers)
114
-
115
- response = self.port_forwarded(state, 'repair_schedule', body, method='GET', show_output=show_output)
116
- if not response:
117
- return
118
-
119
- res = response.json()
120
- if filter:
121
- res = filter(res)
122
-
123
- return res
124
-
125
- def show_schedules_tabular(self, schedules: list[dict]):
126
- log2(lines_to_tabular([f"{schedule['id']} {schedule['state']} {schedule['cluster_name']} {schedule['keyspace_name']}" for schedule in schedules], 'ID STATE CLUSTER KEYSPACE'))
127
-
128
- def show_schedule(self, state: ReplState, schedule_id: str):
129
- def filter(schedules: list[dict]):
130
- return [schedule for schedule in schedules if schedule['id'] == schedule_id]
131
-
132
- self.show_schedules(state, filter)
133
-
134
- def reaper_spec(self, state: ReplState) -> dict[str, any]:
135
- user, pw = state.user_pass(secret_path='reaper.secret')
136
- local_port = Config().get('reaper.port-forward.local-port', 9001)
137
-
138
- return {
139
- 'pod': self.pod,
140
- 'exec': f'kubectl exec -it {self.pod} -n {state.namespace} -- bash',
141
- 'forward': f'kubectl port-forward pods/{self.pod} -n {state.namespace} {local_port}:8080',
142
- 'web-uri': f'http://localhost:{local_port}/webui',
143
- 'username': user,
144
- 'password': pw
145
- }
146
-
147
- def cached_schedule_ids(state: ReplState) -> list[str]:
148
- if state.sts in ReaperSession.schedules_ids_by_cluster:
149
- return ReaperSession.schedules_ids_by_cluster[state.sts]
150
-
151
- if reaper := ReaperSession.create(state):
152
- state.wait_log("Inspecting Cassandra Reaper...")
153
-
154
- schedules = reaper.schedule_ids(state, show_output = False)
155
- ReaperSession.schedules_ids_by_cluster[state.sts] = schedules
156
-
157
- return schedules
158
-
159
- return []
@@ -1,68 +0,0 @@
1
- import click
2
-
3
- from walker.commands.command import Command
4
- from walker.commands.command_helpers import ClusterCommandHelper
5
- from .repair_run import RepairRun
6
- from .repair_scan import RepairScan
7
- from .repair_stop import RepairStop
8
- from .repair_log import RepairLog
9
- from walker.repl_state import ReplState, RequiredState
10
- from walker.utils import lines_to_tabular, log, log2
11
-
12
- class Repair(Command):
13
- COMMAND = 'repair'
14
-
15
- # the singleton pattern
16
- def __new__(cls, *args, **kwargs):
17
- if not hasattr(cls, 'instance'): cls.instance = super(Repair, cls).__new__(cls)
18
-
19
- return cls.instance
20
-
21
- def __init__(self, successor: Command=None):
22
- super().__init__(successor)
23
-
24
- def command(self):
25
- return Repair.COMMAND
26
-
27
- def required(self):
28
- return RequiredState.CLUSTER
29
-
30
- def run(self, cmd: str, state: ReplState):
31
- if not(args := self.args(cmd)):
32
- return super().run(cmd, state)
33
-
34
- state, args = self.apply_state(args, state)
35
- if not self.validate_state(state):
36
- return state
37
-
38
- if state.in_repl:
39
- log(lines_to_tabular([c.help(ReplState()) for c in Repair.cmd_list()], separator=':'))
40
-
41
- return 'command-missing'
42
- else:
43
- # head with the Chain of Responsibility pattern
44
- cmds = Command.chain(Repair.cmd_list())
45
- if not cmds.run(cmd, state):
46
- log2('* Command is missing.')
47
- Command.display_help()
48
-
49
- def cmd_list():
50
- return [RepairRun(), RepairScan(), RepairStop(), RepairLog()]
51
-
52
- def completion(self, state: ReplState):
53
- if state.sts:
54
- return super().completion(state)
55
- return {}
56
-
57
- def help(self, _: ReplState):
58
- return None
59
-
60
- class RepairCommandHelper(click.Command):
61
- def get_help(self, ctx: click.Context):
62
- log(super().get_help(ctx))
63
- log()
64
- log('Sub-Commands:')
65
-
66
- log(lines_to_tabular([c.help(ReplState()).replace(f'{Repair.COMMAND} ', ' ', 1) for c in Repair.cmd_list()], separator=':'))
67
- log()
68
- ClusterCommandHelper.cluster_help()
@@ -1,72 +0,0 @@
1
- from walker.commands.command import Command
2
- from walker.k8s_utils.jobs import Jobs
3
- from walker.k8s_utils.volumes import Volumes
4
- from walker.repl_state import ReplState, RequiredState
5
- from walker.config import Config
6
- from walker.commands.reaper.reaper_session import ReaperSession
7
- from walker.commands.reaper.reaper_runs_abort import ReaperRunsAbort
8
- from walker.commands.reaper.reaper_schedule_stop import ReaperScheduleStop
9
- from walker.utils import log2
10
-
11
- class RepairRun(Command):
12
- COMMAND = 'repair run'
13
-
14
- # the singleton pattern
15
- def __new__(cls, *args, **kwargs):
16
- if not hasattr(cls, 'instance'): cls.instance = super(RepairRun, cls).__new__(cls)
17
-
18
- return cls.instance
19
-
20
- def __init__(self, successor: Command=None):
21
- super().__init__(successor)
22
-
23
- def command(self):
24
- return RepairRun.COMMAND
25
-
26
- def required(self):
27
- return RequiredState.CLUSTER
28
-
29
- def run(self, cmd: str, state: ReplState):
30
- if not(args := self.args(cmd)):
31
- return super().run(cmd, state)
32
-
33
- state, args = self.apply_state(args, state)
34
- if not self.validate_state(state):
35
- return state
36
-
37
- replace = False
38
- if len(args) == 1:
39
- replace = args[0] == 'replace'
40
-
41
- log2("Stopping all reaper schedules...")
42
- reaper = ReaperSession.create(state)
43
- schedules = reaper.schedule_ids(state)
44
- for schedule_id in schedules:
45
- ReaperScheduleStop().run(f'reaper stop schedule {schedule_id}', state)
46
- log2("Aborting all reaper runs...")
47
- state = ReaperRunsAbort().run('reaper abort runs', state)
48
-
49
- image = Config().get('repair.image', 'ci-registry.c3iot.io/cloudops/cassrepair:2.0.11')
50
- secret = Config().get('repair.secret', 'ciregistryc3iotio')
51
- log_path = Config().get('repair.log-path', '/home/cassrepair/logs/')
52
- user, _ = state.user_pass()
53
- ns = state.namespace
54
- env = Config().get('repair.env', {})
55
- env["cluster"] = ns
56
- env_from = {"username": user, "password": user}
57
- pvc_name ='cassrepair-log-' + state.sts
58
- Volumes.create_pvc(pvc_name, 30, ns)
59
- if replace:
60
- Jobs.delete('cassrepair-'+state.sts, ns)
61
- Jobs.create('cassrepair-'+state.sts, ns, image, secret, env, env_from, 'cassrepair', pvc_name, log_path)
62
-
63
- return state
64
-
65
- def completion(self, state: ReplState):
66
- if state.sts:
67
- return super().completion(state)
68
-
69
- return {}
70
-
71
- def help(self, _: ReplState):
72
- return f'{RepairRun.COMMAND} [replace]\t start a repair job, default not replacing'