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
adam/__init__.py ADDED
@@ -0,0 +1 @@
1
+ from .version import __version__, __release__
adam/app_session.py ADDED
@@ -0,0 +1,182 @@
1
+ import json
2
+ import threading
3
+ import time
4
+ import traceback
5
+ import requests
6
+ from urllib.parse import urlparse
7
+
8
+ from adam.log import Log
9
+ from adam.repl_state import ReplState
10
+ from adam.sso.idp import Idp
11
+ from adam.sso.idp_login import IdpLogin
12
+ from adam.config import Config
13
+ from adam.utils import debug, json_to_csv, lines_to_tabular, log, log2
14
+ from adam.apps import Apps
15
+
16
+ class AppLogin:
17
+ def __init__(self, session: requests.Session, app_access_token: str, idp_uri: str, idp_login: IdpLogin = None):
18
+ self.session = session
19
+ self.app_access_token = app_access_token
20
+ self.idp_uri = idp_uri
21
+ self.idp_login = idp_login
22
+
23
+ class NoAppIngressException(Exception):
24
+ pass
25
+
26
+ class AppSession:
27
+ sessions_by_host = {}
28
+
29
+ def __init__(self, host: str = None, env: str = None):
30
+ self.host = host
31
+ self.env = env
32
+ self.app_login: AppLogin = None
33
+
34
+ def create(env: str, app: str, namespace: str = None) -> 'AppSession':
35
+ if not(host := Apps.app_host(env, app, namespace)):
36
+ raise NoAppIngressException('Cannot locate ingress for app.')
37
+
38
+ key = f'{host}/{env}'
39
+ if key in AppSession.sessions_by_host:
40
+ return AppSession.sessions_by_host[key]
41
+
42
+ session = AppSession(host, env)
43
+
44
+ AppSession.sessions_by_host[key] = session
45
+
46
+ return session
47
+
48
+ def run(env: str, app: str, namespace: str, type: str, action: str, payload: any = None, forced = False):
49
+ app_session: AppSession = AppSession.create(env, app, namespace)
50
+
51
+ def run0(app_login: AppLogin, retried: bool):
52
+ if app_login:
53
+ with app_login.session as session:
54
+ uri = f'https://{app_session.host}/{env}/{app}/api/8/{type}/{action}'
55
+ r = session.post(uri, json=payload, headers={
56
+ 'X-Request-Envelope': 'true'
57
+ })
58
+
59
+ if Config().is_debug():
60
+ log2(f'{r.status_code} {uri}')
61
+ log2(payload)
62
+
63
+ if r.status_code >= 200 and r.status_code < 300 or r.status_code == 400:
64
+ try:
65
+ js = r.json()
66
+ try:
67
+ header, lines = json_to_csv(js, delimiter='\t')
68
+ log(lines_to_tabular(lines, header=header, separator='\t'))
69
+ except Exception as e:
70
+ # traceback.print_exc(e)
71
+ log(js)
72
+ except:
73
+ if urlparse(r.url).hostname != urlparse(uri).hostname and not retried:
74
+ app_login = app_session.login(idp_uri=app_login.idp_uri, forced=forced, use_token_from_env=False, use_cached_creds=False)
75
+ retried = True
76
+
77
+ return run0(app_login, True)
78
+
79
+ if r.text:
80
+ log2(f'{r.status_code} {r.url} Failed parsing the results.')
81
+ debug(r.text)
82
+ else:
83
+ log2(r.status_code)
84
+ log2(r.text)
85
+
86
+ app_login = app_session.login(forced=forced)
87
+ run0(app_login, False)
88
+
89
+ def login(self, idp_uri: str = None, forced = False, use_token_from_env=True, use_cached_creds=True) -> AppLogin:
90
+ if not forced and self.app_login:
91
+ return self.app_login
92
+
93
+ idp_login: IdpLogin = Idp.login(self.host, idp_uri=idp_uri, forced=forced, use_token_from_env=use_token_from_env, use_cached_creds=use_cached_creds, verify=False)
94
+ if not idp_login:
95
+ log2(f"Invalid username/password.")
96
+
97
+ return None
98
+
99
+ if idp_login.state == 'EMPTY':
100
+ idp_login.state = IdpLogin.create_from_idp_uri(self.idp_redirect_url()).state
101
+
102
+ headers = {
103
+ 'Content-Type': 'application/x-www-form-urlencoded',
104
+ }
105
+ form_data = {
106
+ 'state': idp_login.state,
107
+ 'id_token': idp_login.id_token
108
+ }
109
+
110
+ stop_event = threading.Event()
111
+
112
+ session = idp_login.session
113
+ if not session:
114
+ session = requests.Session()
115
+
116
+ def login0():
117
+ try:
118
+ # oidc/login may hang
119
+ timeout = Config().get('app.login.timeout', 5)
120
+ debug(f'-> {idp_login.app_login_url}')
121
+ session.post(idp_login.app_login_url, headers=headers, data=form_data, timeout=timeout)
122
+ except Exception:
123
+ pass
124
+ finally:
125
+ stop_event.set()
126
+
127
+ my_thread = threading.Thread(target=login0, daemon=True)
128
+ my_thread.start()
129
+
130
+ app_access_token = None
131
+ while not app_access_token and not stop_event.is_set():
132
+ time.sleep(1)
133
+
134
+ try:
135
+ check_uri = Config().get('app.login.session-check-url', 'https://{host}/{env}/{app}/api/8/C3/userSessionToken')
136
+ check_uri = check_uri.replace('{host}', self.host).replace('{env}', self.env).replace('{app}', 'c3')
137
+ r = session.get(check_uri)
138
+ debug(f'{r.status_code} {check_uri}')
139
+
140
+ res_text = r.text
141
+ js = json.loads(res_text)
142
+ if 'signedToken' not in js:
143
+ log2('Cannot get c3 access token, pleae re-login.')
144
+ break
145
+
146
+ app_access_token = js['signedToken']
147
+ debug(f'{r.text}')
148
+
149
+ self.app_login = AppLogin(session, app_access_token, idp_uri)
150
+ except Exception:
151
+ try:
152
+ need = urlparse(r.url).hostname
153
+ if idp_login.idp_uri:
154
+ idp_uri = r.url
155
+ has = urlparse(idp_login.idp_uri).hostname
156
+ msg = Config().get('app.login.another', "You're logged in to {has}. However, for this app, you need to log in to {need}.")
157
+ msg = msg.replace('{has}', has).replace('{need}', need)
158
+ log2(msg)
159
+ else:
160
+ log2(f"Invalid username/password.")
161
+ break
162
+ finally:
163
+ debug(traceback.format_exc())
164
+
165
+ if 'res_text' in locals():
166
+ Log.log_to_file(res_text)
167
+
168
+ return AppLogin(session, app_access_token, idp_uri, idp_login=idp_login)
169
+
170
+ def idp_redirect_url(self, show_endpoints = True) -> str:
171
+ # stgawsscpsr-c3-c3
172
+ uri = Config().get('app.login.url', 'https://{host}/{env}/{app}')
173
+ uri = uri.replace('{host}', self.host).replace('{env}', self.env).replace('{app}', 'c3')
174
+ r = requests.get(uri)
175
+
176
+ parsed_url = urlparse(r.url)
177
+ if show_endpoints:
178
+ log2(f'{r.status_code} {uri} <-> {parsed_url.hostname}...')
179
+ if r.status_code < 200 or r.status_code > 299:
180
+ return None
181
+
182
+ return r.url
{walker → adam}/apps.py RENAMED
@@ -1,18 +1,15 @@
1
1
  import copy
2
2
  import functools
3
- import importlib
4
- import os
5
- from pathlib import Path
6
3
  import re
7
4
  from typing import cast
8
5
  import yaml
9
6
 
10
- from walker.config import Config
11
- from walker.k8s_utils.ingresses import Ingresses
7
+ from adam.config import Config
8
+ from adam.utils_k8s.ingresses import Ingresses
12
9
 
13
10
  from . import __version__
14
- from walker.k8s_utils.services import Services
15
- from walker.utils import log2
11
+ from adam.utils_k8s.services import Services
12
+ from adam.utils import copy_config_file
16
13
 
17
14
  class AppAction:
18
15
  def __init__(self, name: str, payload: str = None, args: dict[str, str] = None, help: str = None):
@@ -135,24 +132,11 @@ class Apps:
135
132
  with open(path) as f:
136
133
  self.actions = cast(dict[str, any], yaml.safe_load(f))
137
134
  except:
138
- self.copy_apps_file()
135
+ with open(copy_config_file(f'apps.yaml.{__version__}', 'adam.embedded_apps')) as f:
136
+ self.actions = cast(dict[str, any], yaml.safe_load(f))
139
137
  elif not hasattr(self, 'actions'):
140
- self.copy_apps_file()
141
-
142
- def copy_apps_file(self):
143
- dir = f'{Path.home()}/.kaqing'
144
- path = f'{dir}/apps.yaml.{__version__}'
145
- if not os.path.exists(path):
146
- os.makedirs(dir, exist_ok=True)
147
- module = importlib.import_module('walker.embedded_apps')
148
- with open(path, 'w') as f:
149
- yaml.dump(module.apps(), f, default_flow_style=False)
150
- log2(f'Default apps.yaml has been written to {path}.')
151
-
152
- with open(path) as f:
153
- self.actions = cast(dict[str, any], yaml.safe_load(f))
154
-
155
- return path
138
+ with open(copy_config_file(f'apps.yaml.{__version__}', 'adam.embedded_apps')) as f:
139
+ self.actions = cast(dict[str, any], yaml.safe_load(f))
156
140
 
157
141
  def app_types(self) -> list[AppType]:
158
142
  return AppType.create(self.actions)
@@ -1,36 +1,42 @@
1
1
  import click
2
2
 
3
- from walker.commands.bash import Bash
4
- from walker.commands.check import Check, CheckCommandHelper
5
- from walker.commands.cp import ClipboardCopy, CopyCommandHelper
6
- from walker.commands.command import Command
7
- from walker.commands.command_helpers import ClusterCommandHelper, ClusterOrPodCommandHelper, PodCommandHelper
8
- from walker.commands.cqlsh import CqlCommandHelper, Cqlsh
9
- from walker.commands.frontend.setup import Setup, SetupCommandHelper
10
- from walker.commands.frontend.teardown import TearDown, TearDownCommandHelper
11
- from walker.commands.issues import Issues
12
- from walker.commands.login import Login
13
- from walker.commands.logs import Logs
14
- from walker.commands.ls import Ls
15
- from walker.commands.medusa.medusa import Medusa
16
- from walker.commands.nodetool import NodeTool, NodeToolCommandHelper
17
- from walker.commands.postgres.postgres import Postgres, PostgresCommandHelper
18
- from walker.commands.preview_table import PreviewTable
19
- from walker.commands.processes import Processes
20
- from walker.commands.reaper.reaper import Reaper, ReaperCommandHelper
21
- from walker.commands.repair.repair import Repair, RepairCommandHelper
22
- from walker.commands.report import Report
23
- from walker.commands.restart import Restart
24
- from walker.commands.rollout import RollOut
25
- from walker.commands.show.show import Show, ShowCommandHelper
26
- from walker.commands.status import Status as StatusCmd
27
- from walker.commands.storage import Storage
28
- from walker.commands.user_entry import UserEntry
29
- from walker.commands.watch import Watch
30
- from walker.k8s_utils.kube_context import KubeContext
31
- from walker.repl import enter_repl
32
- from walker.repl_state import ReplState
33
- from walker.cli_group import cli
3
+ from adam.commands.audit.audit import Audit, AuditCommandHelper
4
+ from adam.commands.bash.bash import Bash
5
+ from adam.commands.check import Check, CheckCommandHelper
6
+ from adam.commands.cp import ClipboardCopy, CopyCommandHelper
7
+ from adam.commands.command import Command
8
+ from adam.commands.command_helpers import ClusterCommandHelper, ClusterOrPodCommandHelper, PodCommandHelper
9
+ from adam.commands.cql.cqlsh import CqlCommandHelper, Cqlsh
10
+ from adam.commands.deploy.deploy import Deploy, DeployCommandHelper
11
+ from adam.commands.deploy.undeploy import Undeploy, UndeployCommandHelper
12
+ from adam.commands.issues import Issues
13
+ from adam.commands.login import Login
14
+ from adam.commands.logs import Logs
15
+ from adam.commands.ls import Ls
16
+ from adam.commands.medusa.medusa import Medusa
17
+ from adam.commands.nodetool import NodeTool, NodeToolCommandHelper
18
+ from adam.commands.postgres.postgres import Postgres, PostgresCommandHelper
19
+ from adam.commands.preview_table import PreviewTable
20
+ from adam.commands.reaper.reaper import Reaper, ReaperCommandHelper
21
+ from adam.commands.repair.repair import Repair, RepairCommandHelper
22
+ from adam.commands.report import Report
23
+ from adam.commands.restart import Restart
24
+ from adam.commands.rollout import RollOut
25
+ from adam.commands.show.show import Show, ShowCommandHelper
26
+ from adam.commands.watch import Watch
27
+ from adam.utils_k8s.kube_context import KubeContext
28
+ from adam.repl import enter_repl
29
+ from adam.repl_state import ReplState
30
+ from adam.cli_group import cli
31
+
32
+ @cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=AuditCommandHelper, help='Run audit functions.')
33
+ @click.option('--kubeconfig', '-k', required=False, metavar='path', help='path to kubeconfig file')
34
+ @click.option('--config', default='params.yaml', metavar='path', help='path to kaqing parameters file')
35
+ @click.option('--param', '-v', multiple=True, metavar='<key>=<value>', help='parameter override')
36
+ @click.argument('extra_args', nargs=-1, metavar='repair', type=click.UNPROCESSED)
37
+ def audit(kubeconfig: str, config: str, param: list[str], extra_args):
38
+ run_command(Audit(), kubeconfig, config, param, None, None, None, extra_args, device=ReplState.L)
39
+
34
40
 
35
41
  @cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=ClusterOrPodCommandHelper, help='Run a single bash command.')
36
42
  @click.option('--kubeconfig', '-k', required=False, metavar='path', help='path to kubeconfig file')
@@ -80,6 +86,16 @@ def cql(kubeconfig: str, config: str, param: list[str], cluster: str, namespace:
80
86
  run_command(Cqlsh(), kubeconfig, config, param, cluster, namespace, pod, extra_args)
81
87
 
82
88
 
89
+ @cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=DeployCommandHelper, help='Setup.')
90
+ @click.option('--kubeconfig', '-k', required=False, metavar='path', help='path to kubeconfig file')
91
+ @click.option('--config', default='params.yaml', metavar='path', help='path to kaqing parameters file')
92
+ @click.option('--param', '-v', multiple=True, metavar='<key>=<value>', help='parameter override')
93
+ @click.option('--namespace', '-n', required=False, metavar='namespace', help='Kubernetes namespace')
94
+ @click.argument('extra_args', nargs=-1, metavar='<pod>', type=click.UNPROCESSED)
95
+ def deploy(kubeconfig: str, config: str, param: list[str], namespace: str, extra_args):
96
+ run_command(Deploy(), kubeconfig, config, param, None, namespace, None, extra_args)
97
+
98
+
83
99
  @cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=ClusterOrPodCommandHelper, help="Print Qing's issues.")
84
100
  @click.option('--kubeconfig', '-k', required=False, metavar='path', help='path to kubeconfig file')
85
101
  @click.option('--config', default='params.yaml', metavar='path', help='path to kaqing parameters file')
@@ -93,7 +109,7 @@ def issues(kubeconfig: str, config: str, param: list[str], cluster: str, namespa
93
109
  run_command(Issues(), kubeconfig, config, param, cluster, namespace, pod, ('-s',) + extra_args if show else extra_args)
94
110
 
95
111
 
96
- @cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=PodCommandHelper, help='Get cassandra log.')
112
+ @cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=PodCommandHelper, help='SSO login.')
97
113
  @click.option('--kubeconfig', '-k', required=False, metavar='path', help='path to kubeconfig file')
98
114
  @click.option('--config', default='params.yaml', metavar='path', help='path to kaqing parameters file')
99
115
  @click.option('--param', '-v', multiple=True, metavar='<key>=<value>', help='parameter override')
@@ -173,19 +189,6 @@ def preview(kubeconfig: str, config: str, param: list[str], cluster: str, namesp
173
189
  run_command(PreviewTable(), kubeconfig, config, param, cluster, namespace, pod, extra_args)
174
190
 
175
191
 
176
- @cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=ClusterOrPodCommandHelper, help='Show process overview from Cassandra nodes.')
177
- @click.option('--kubeconfig', '-k', required=False, metavar='path', help='path to kubeconfig file')
178
- @click.option('--config', default='params.yaml', metavar='path', help='path to kaqing parameters file')
179
- @click.option('--param', '-v', multiple=True, metavar='<key>=<value>', help='parameter override')
180
- @click.option('--cluster', '-c', required=False, metavar='statefulset', help='Kubernetes statefulset name')
181
- @click.option('--namespace', '-n', required=False, metavar='namespace', help='Kubernetes namespace')
182
- @click.option('--pod', '-p', required=False, metavar='pod', help='Kubernetes pod name')
183
- @click.option('--show', '-s', is_flag=True, help='show output from Cassandra nodes')
184
- @click.argument('extra_args', nargs=-1, metavar='<cluster|pod>', type=click.UNPROCESSED)
185
- def processes(kubeconfig: str, config: str, param: list[str], cluster: str, namespace: str, pod: str, show: bool, extra_args):
186
- run_command(Processes(), kubeconfig, config, param, cluster, namespace, pod, ('-s',) + extra_args if show else extra_args)
187
-
188
-
189
192
  @cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=ReaperCommandHelper, help='Execute Cassandra Reaper operations.')
190
193
  @click.option('--kubeconfig', '-k', required=False, metavar='path', help='path to kubeconfig file')
191
194
  @click.option('--config', default='params.yaml', metavar='path', help='path to kaqing parameters file')
@@ -245,16 +248,6 @@ def rollout(kubeconfig: str, config: str, param: list[str], cluster: str, namesp
245
248
  run_command(RollOut(), kubeconfig, config, param, cluster, namespace, None, extra_args)
246
249
 
247
250
 
248
- @cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=SetupCommandHelper, help='Setup.')
249
- @click.option('--kubeconfig', '-k', required=False, metavar='path', help='path to kubeconfig file')
250
- @click.option('--config', default='params.yaml', metavar='path', help='path to kaqing parameters file')
251
- @click.option('--param', '-v', multiple=True, metavar='<key>=<value>', help='parameter override')
252
- @click.option('--namespace', '-n', required=False, metavar='namespace', help='Kubernetes namespace')
253
- @click.argument('extra_args', nargs=-1, metavar='<pod>', type=click.UNPROCESSED)
254
- def setup(kubeconfig: str, config: str, param: list[str], namespace: str, extra_args):
255
- run_command(Setup(), kubeconfig, config, param, None, namespace, None, extra_args)
256
-
257
-
258
251
  @cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=ShowCommandHelper, help='Show configuration or kubectl commands.')
259
252
  @click.option('--kubeconfig', '-k', required=False, metavar='path', help='path to kubeconfig file')
260
253
  @click.option('--config', default='params.yaml', metavar='path', help='path to kaqing parameters file')
@@ -267,50 +260,14 @@ def show(kubeconfig: str, config: str, param: list[str], cluster: str, namespace
267
260
  run_command(Show(), kubeconfig, config, param, cluster, namespace, pod, extra_args)
268
261
 
269
262
 
270
- @cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=ClusterOrPodCommandHelper, help='Show combined nodetool status from Cassandra nodes.')
271
- @click.option('--kubeconfig', '-k', required=False, metavar='path', help='path to kubeconfig file')
272
- @click.option('--config', default='params.yaml', metavar='path', help='path to kaqing parameters file')
273
- @click.option('--param', '-v', multiple=True, metavar='<key>=<value>', help='parameter override')
274
- @click.option('--cluster', '-c', required=False, metavar='statefulset', help='Kubernetes statefulset name')
275
- @click.option('--namespace', '-n', required=False, metavar='namespace', help='Kubernetes namespace')
276
- @click.option('--pod', '-p', required=False, metavar='pod', help='Kubernetes pod name')
277
- @click.option('--show', '-s', is_flag=True, help='show output from Cassandra nodes')
278
- @click.argument('extra_args', nargs=-1, metavar='<cluster|pod>', type=click.UNPROCESSED)
279
- def status(kubeconfig: str, config: str, param: list[str], cluster: str, namespace: str, pod: str, show: bool, extra_args):
280
- run_command(StatusCmd(), kubeconfig, config, param, cluster, namespace, pod, ('-s',) + extra_args if show else extra_args)
281
-
282
-
283
- @cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=ClusterOrPodCommandHelper, help='Show storage overview from Cassandra nodes.')
284
- @click.option('--kubeconfig', '-k', required=False, metavar='path', help='path to kubeconfig file')
285
- @click.option('--config', default='params.yaml', metavar='path', help='path to kaqing parameters file')
286
- @click.option('--param', '-v', multiple=True, metavar='<key>=<value>', help='parameter override')
287
- @click.option('--cluster', '-c', required=False, metavar='statefulset', help='Kubernetes statefulset name')
288
- @click.option('--namespace', '-n', required=False, metavar='namespace', help='Kubernetes namespace')
289
- @click.option('--pod', '-p', required=False, metavar='pod', help='Kubernetes pod name')
290
- @click.option('--show', '-s', is_flag=True, help='show output from Cassandra nodes')
291
- @click.argument('extra_args', nargs=-1, metavar='<cluster|pod>', type=click.UNPROCESSED)
292
- def storage(kubeconfig: str, config: str, param: list[str], cluster: str, namespace: str, pod: str, show: bool, extra_args):
293
- run_command(Storage(), kubeconfig, config, param, cluster, namespace, pod, ('-s',) + extra_args if show else extra_args)
294
-
295
-
296
- @cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=TearDownCommandHelper, help='Teardown.')
297
- @click.option('--kubeconfig', '-k', required=False, metavar='path', help='path to kubeconfig file')
298
- @click.option('--config', default='params.yaml', metavar='path', help='path to kaqing parameters file')
299
- @click.option('--param', '-v', multiple=True, metavar='<key>=<value>', help='parameter override')
300
- @click.option('--namespace', '-n', required=False, metavar='namespace', help='Kubernetes namespace')
301
- @click.argument('extra_args', nargs=-1, metavar='<pod>', type=click.UNPROCESSED)
302
- def teardown(kubeconfig: str, config: str, param: list[str], namespace: str, extra_args):
303
- run_command(TearDown(), kubeconfig, config, param, None, namespace, None, extra_args)
304
-
305
-
306
- @cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=PodCommandHelper, help='Get cassandra log.')
263
+ @cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=UndeployCommandHelper, help='Undeploy.')
307
264
  @click.option('--kubeconfig', '-k', required=False, metavar='path', help='path to kubeconfig file')
308
265
  @click.option('--config', default='params.yaml', metavar='path', help='path to kaqing parameters file')
309
266
  @click.option('--param', '-v', multiple=True, metavar='<key>=<value>', help='parameter override')
310
267
  @click.option('--namespace', '-n', required=False, metavar='namespace', help='Kubernetes namespace')
311
268
  @click.argument('extra_args', nargs=-1, metavar='<pod>', type=click.UNPROCESSED)
312
- def entry(kubeconfig: str, config: str, param: list[str], namespace: str, extra_args):
313
- run_command(UserEntry(), kubeconfig, config, param, None, namespace, None, extra_args)
269
+ def undeploy(kubeconfig: str, config: str, param: list[str], namespace: str, extra_args):
270
+ run_command(Undeploy(), kubeconfig, config, param, None, namespace, None, extra_args)
314
271
 
315
272
 
316
273
  @cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=ClusterOrPodCommandHelper, help='Watch pods in cluster.')
@@ -324,14 +281,14 @@ def watch(kubeconfig: str, config: str, param: list[str], cluster: str, namespac
324
281
  run_command(Watch(), kubeconfig, config, param, cluster, namespace, None, extra_args)
325
282
 
326
283
 
327
- def run_command(cmd: Command, kubeconfig: str, config: str, params: list[str], cluster:str, namespace: str, pod: str, extra_args):
328
- is_user_entry = cmd.command() == UserEntry().command()
284
+ def run_command(cmd: Command, kubeconfig: str, config: str, params: list[str], cluster:str, namespace: str, pod: str, extra_args, device=ReplState.C):
285
+ is_user_entry = False
329
286
 
330
287
  KubeContext.init_config(kubeconfig, is_user_entry=is_user_entry)
331
288
  if not KubeContext.init_params(config, params, is_user_entry=is_user_entry):
332
289
  return
333
290
 
334
- state = ReplState(ns_sts=cluster, pod=pod, namespace=namespace)
291
+ state = ReplState(device=device, ns_sts=cluster, pod=pod, namespace=namespace)
335
292
  if cmd.command() == 'pg' and not extra_args:
336
293
  state, _ = state.apply_args(extra_args)
337
294
  state.device = ReplState.P
@@ -1,8 +1,8 @@
1
1
  from abc import abstractmethod
2
2
 
3
- from walker.checks.check_context import CheckContext
4
- from walker.checks.check_result import CheckResult
5
- from walker.checks.issue import Issue
3
+ from adam.checks.check_context import CheckContext
4
+ from adam.checks.check_result import CheckResult
5
+ from adam.checks.issue import Issue
6
6
 
7
7
  class Check:
8
8
  """Abstract base class for checks"""
@@ -1,4 +1,4 @@
1
- from walker.checks.issue import Issue
1
+ from adam.checks.issue import Issue
2
2
 
3
3
  class CheckResult:
4
4
  def __init__(self, name: str, details: any = None, issues: list[Issue] = None):
@@ -0,0 +1,65 @@
1
+ from adam.checks.check import Check
2
+ from adam.checks.check_context import CheckContext
3
+ from adam.checks.check_result import CheckResult
4
+ from adam.checks.compactionstats import CompactionStats
5
+ from adam.checks.cpu import Cpu
6
+ from adam.checks.disk import Disk
7
+ from adam.checks.gossip import Gossip
8
+ from adam.checks.issue import Issue
9
+ from adam.checks.memory import Memory
10
+ from adam.checks.status import Status
11
+ from adam.config import Config
12
+ from adam.utils_k8s.cassandra_nodes import CassandraNodes
13
+ from adam.utils_k8s.secrets import Secrets
14
+ from adam.utils_k8s.statefulsets import StatefulSets
15
+ from adam.utils import parallelize, log2
16
+
17
+ def all_checks() -> list[Check]:
18
+ return [CompactionStats(), Cpu(), Gossip(), Memory(), Disk(), Status()]
19
+
20
+ def checks_from_csv(check_str: str):
21
+ checks: list[Check] = []
22
+
23
+ checks_by_name = {c.name(): c for c in all_checks()}
24
+
25
+ if check_str:
26
+ for check_name in check_str.strip(' ').split(','):
27
+ if check_name in checks_by_name:
28
+ checks.append(checks_by_name[check_name])
29
+ else:
30
+ log2(f'Invalid check name: {check_name}.')
31
+
32
+ return None
33
+
34
+ return checks
35
+
36
+ def run_checks(cluster: str = None, namespace: str = None, pod: str = None, checks: list[Check] = None, show_out=True):
37
+ if not checks:
38
+ checks = all_checks()
39
+
40
+ sts_ns: list[tuple[str, str]] = StatefulSets.list_sts_name_and_ns()
41
+
42
+ sts_ns_pods: list[tuple[str, str, str]] = []
43
+ for sts, ns in sts_ns:
44
+ if (not cluster or cluster == sts) and (not namespace or namespace == ns):
45
+ pods = StatefulSets.pods(sts, ns)
46
+ for pod_name in [pod.metadata.name for pod in pods]:
47
+ if not pod or pod == pod_name:
48
+ sts_ns_pods.append((sts, ns, pod_name))
49
+
50
+ with parallelize(sts_ns_pods, Config().action_workers('issues', 30), msg='d`Running|Ran checks on {size} pods') as exec:
51
+ return exec.map(lambda sts_ns_pod: run_checks_on_pod(checks, sts_ns_pod[0], sts_ns_pod[1], sts_ns_pod[2], show_out))
52
+
53
+ def run_checks_on_pod(checks: list[Check], cluster: str = None, namespace: str = None, pod: str = None, show_out=True):
54
+ host_id = CassandraNodes.get_host_id(pod, namespace)
55
+ user, pw = Secrets.get_user_pass(pod, namespace)
56
+ results = {}
57
+ issues: list[Issue] = []
58
+ for c in checks:
59
+ check_results = c.check(CheckContext(cluster, host_id, pod, namespace, user, pw, show_output=show_out))
60
+ if check_results.details:
61
+ results = results | {check_results.name: check_results.details}
62
+ if check_results.issues:
63
+ issues.extend(check_results.issues)
64
+
65
+ return CheckResult(None, results, issues)
@@ -1,11 +1,11 @@
1
1
  import re
2
2
 
3
- from walker.checks.check import Check
4
- from walker.checks.check_context import CheckContext
5
- from walker.checks.check_result import CheckResult
6
- from walker.checks.issue import Issue
7
- from walker.config import Config
8
- from walker.k8s_utils.cassandra_nodes import CassandraNodes
3
+ from adam.checks.check import Check
4
+ from adam.checks.check_context import CheckContext
5
+ from adam.checks.check_result import CheckResult
6
+ from adam.checks.issue import Issue
7
+ from adam.config import Config
8
+ from adam.utils_k8s.cassandra_nodes import CassandraNodes
9
9
 
10
10
  class CompactionStats(Check):
11
11
  def name(self):
@@ -1,12 +1,13 @@
1
1
  from kubernetes.utils import parse_quantity
2
2
 
3
- from walker.checks.check import Check
4
- from walker.checks.check_context import CheckContext
5
- from walker.checks.check_result import CheckResult
6
- from walker.checks.issue import Issue
7
- from walker.config import Config
8
- from walker.k8s_utils.cassandra_nodes import CassandraNodes
9
- from walker.k8s_utils.custom_resources import CustomResources
3
+ from adam.checks.check import Check
4
+ from adam.checks.check_context import CheckContext
5
+ from adam.checks.check_result import CheckResult
6
+ from adam.checks.issue import Issue
7
+ from adam.config import Config
8
+ from adam.utils_k8s.cassandra_nodes import CassandraNodes
9
+ from adam.utils_k8s.custom_resources import CustomResources
10
+ from adam.utils_k8s.pods import Pods
10
11
 
11
12
  class Cpu(Check):
12
13
  def name(self):
@@ -20,10 +21,15 @@ class Cpu(Check):
20
21
  'namespace': ctx.namespace,
21
22
  'statefulset': ctx.statefulset,
22
23
  'cpu': 'Unknown',
23
- 'idle': 'Unknown'
24
+ 'idle': 'Unknown',
25
+ 'limit': 'NA'
24
26
  }
25
27
 
26
28
  try:
29
+ container = Pods.get_container(ctx.namespace, ctx.pod, container_name='cassandra')
30
+ if container.resources.limits and "cpu" in container.resources.limits:
31
+ details['limit'] = container.resources.limits["cpu"]
32
+
27
33
  idle = 'Unknown'
28
34
  result = CassandraNodes.exec(ctx.pod, ctx.namespace, "mpstat 5 2 | grep Average | awk '{print $NF}'", show_out=ctx.show_output)
29
35
  lines = result.stdout.strip(' \r\n').split('\n')
@@ -0,0 +1,52 @@
1
+ from kubernetes.utils import parse_quantity
2
+
3
+ from adam.checks.check import Check
4
+ from adam.checks.check_context import CheckContext
5
+ from adam.checks.check_result import CheckResult
6
+ from adam.checks.issue import Issue
7
+ from adam.config import Config
8
+ from adam.utils_k8s.custom_resources import CustomResources
9
+ from adam.utils_k8s.pods import Pods
10
+
11
+ class CpuMetrics(Check):
12
+ def name(self):
13
+ return 'cpu-metrics'
14
+
15
+ def check(self, ctx: CheckContext) -> CheckResult:
16
+ issues: list[Issue] = []
17
+
18
+ details = {
19
+ 'name': ctx.pod,
20
+ 'namespace': ctx.namespace,
21
+ 'statefulset': ctx.statefulset,
22
+ 'cpu': 'Unknown',
23
+ 'limit': 'NA'
24
+ }
25
+
26
+ try:
27
+ container = Pods.get_container(ctx.namespace, ctx.pod, container_name='cassandra')
28
+ if container.resources.limits and "cpu" in container.resources.limits:
29
+ details['limit'] = container.resources.limits["cpu"]
30
+
31
+ metrics = CustomResources.get_metrics(ctx.namespace, ctx.pod, container_name='cassandra')
32
+ usage = 'Unknown'
33
+ if metrics:
34
+ usage = details['cpu'] = metrics["usage"]["cpu"]
35
+
36
+ cpu_threshold = Config().get('checks.cpu-threshold', 0.0)
37
+ if cpu_threshold != 0.0 and usage != "Unknown" and parse_quantity(usage) > cpu_threshold:
38
+ issues.append(Issue(
39
+ statefulset=ctx.statefulset,
40
+ namespace=ctx.namespace,
41
+ pod=ctx.pod,
42
+ category='cpu',
43
+ desc=f'CPU is too busy: {usage}',
44
+ suggestion=f"qing restart {ctx.pod}@{ctx.namespace}"
45
+ ))
46
+ except Exception as e:
47
+ issues.append(self.issue_from_err(sts_name=ctx.statefulset, ns=ctx.namespace, pod_name=ctx.pod, exception=e))
48
+
49
+ return CheckResult(self.name(), details, issues)
50
+
51
+ def help(self):
52
+ return f'{CpuMetrics().name()}: check cpu busy percentage with metrics'