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
walker/repl_state.py DELETED
@@ -1,211 +0,0 @@
1
- import copy
2
- from enum import Enum
3
-
4
- from walker.commands.postgres.postgres_session import PostgresSession
5
- from walker.k8s_utils.cassandra_clusters import CassandraClusters
6
- from walker.k8s_utils.cassandra_nodes import CassandraNodes
7
- from walker.k8s_utils.kube_context import KubeContext
8
- from walker.k8s_utils.secrets import Secrets
9
- from walker.utils import display_help, log2, random_alphanumeric
10
-
11
- class BashSession:
12
- def __init__(self, device: str = None):
13
- self.session_id = random_alphanumeric(6)
14
- self.device = device
15
-
16
- def pwd(self, state: 'ReplState'):
17
- command = f'cat /tmp/.qing-{self.session_id}'
18
-
19
- if state.pod:
20
- rs = [CassandraNodes.exec(state.pod, state.namespace, command, show_out=False)]
21
- elif state.sts:
22
- rs = CassandraClusters.exec(state.sts, state.namespace, command, action='bash', show_out=False)
23
-
24
- dir = None
25
- for r in rs:
26
- if r.exit_code(): # if fails to read the session file, ignore
27
- continue
28
-
29
- dir0 = r.stdout.strip(' \r\n')
30
- if dir:
31
- if dir != dir0:
32
- log2('Inconsitent working dir found across multiple pods.')
33
- return None
34
- else:
35
- dir = dir0
36
-
37
- return dir
38
-
39
- class RequiredState(Enum):
40
- CLUSTER = 'cluster'
41
- POD = 'pod'
42
- CLUSTER_OR_POD = 'cluster_or_pod'
43
- NAMESPACE = 'namespace'
44
- PG_DATABASE = 'pg_database'
45
- APP_APP = 'app_app'
46
-
47
- class ReplState:
48
- A = 'a'
49
- C = 'c'
50
- P = 'p'
51
-
52
- def __init__(self, device: str = None,
53
- sts: str = None, pod: str = None, namespace: str = None, ns_sts: str = None,
54
- pg_path: str = None,
55
- app_env: str = None, app_app: str = None,
56
- in_repl = False, bash_session: BashSession = None, remote_dir = None):
57
- self.namespace = KubeContext.in_cluster_namespace()
58
-
59
- self.device = device
60
- self.sts = sts
61
- self.pod = pod
62
- self.pg_path = pg_path
63
- self.app_env = app_env
64
- self.app_app = app_app
65
- if namespace:
66
- self.namespace = namespace
67
- self.in_repl = in_repl
68
- self.bash_session = bash_session
69
- self.remote_dir = remote_dir
70
- self.wait_log_flag = False
71
-
72
- if ns_sts:
73
- nn = ns_sts.split('@')
74
- self.sts = nn[0]
75
- if len(nn) > 1:
76
- self.namespace = nn[1]
77
-
78
- # work for CliCommand.Values()
79
- def __eq__(self, other: 'ReplState'):
80
- return self.sts == other.sts and self.pod == other.pod
81
-
82
- def __hash__(self):
83
- return hash((self.sts, self.pod))
84
-
85
- def apply_args(self, args: list[str], cmd: list[str] = None, resolve_pg = True) -> tuple['ReplState', list[str]]:
86
- state = self
87
-
88
- new_args = []
89
- for index, arg in enumerate(args):
90
- if index < 6:
91
- state = copy.copy(state)
92
-
93
- s, n = KubeContext.is_sts_name(arg)
94
- if s:
95
- if not state.sts:
96
- state.sts = s
97
- if n and not state.namespace:
98
- state.namespace = n
99
-
100
- p, n = KubeContext.is_pod_name(arg)
101
- if p:
102
- if not state.pod:
103
- state.pod = p
104
- if n and not state.namespace:
105
- state.namespace = n
106
-
107
- pg = None
108
- if resolve_pg:
109
- pg = KubeContext.is_pg_name(arg)
110
- if pg and not state.pg_path:
111
- state.pg_path = pg
112
-
113
- if not s and not p and not pg:
114
- new_args.append(arg)
115
- else:
116
- new_args.append(arg)
117
-
118
- if cmd:
119
- new_args = new_args[len(cmd):]
120
-
121
- return (state, new_args)
122
-
123
- def validate(self, required: RequiredState = None, pg_required: RequiredState = None, app_required: RequiredState = None):
124
- if not pg_required and not app_required:
125
- if required == RequiredState.CLUSTER:
126
- if not self.namespace or not self.sts:
127
- if self.in_repl:
128
- log2('cd to a cluster first.')
129
- else:
130
- log2('* cluster is missing.')
131
- log2()
132
- display_help()
133
-
134
- return False
135
- elif required == RequiredState.POD:
136
- if not self.namespace or not self.pod:
137
- if self.in_repl:
138
- log2('cd to a pod first.')
139
- else:
140
- log2('* Pod is missing.')
141
- log2()
142
- display_help()
143
-
144
- return False
145
- elif required == RequiredState.CLUSTER_OR_POD:
146
- if not self.namespace or not self.sts and not self.pod:
147
- if self.in_repl:
148
- log2('cd to a cluster first.')
149
- else:
150
- log2('* cluster or pod is missing.')
151
- log2()
152
- display_help()
153
-
154
- return False
155
- elif required == RequiredState.NAMESPACE:
156
- if not self.namespace:
157
- if self.in_repl:
158
- log2('Namespace is required.')
159
- else:
160
- log2('* namespace is missing.')
161
- log2()
162
- display_help()
163
-
164
- return False
165
-
166
- if pg_required == RequiredState.PG_DATABASE:
167
- pg = PostgresSession(self.namespace, self.pg_path)
168
- if not pg.db:
169
- if self.in_repl:
170
- log2('cd to a database first.')
171
- else:
172
- log2('* database is missing.')
173
- log2()
174
- display_help()
175
-
176
- return False
177
-
178
- if app_required == RequiredState.APP_APP and not self.app_app:
179
- if self.in_repl:
180
- log2('cd to an app first.')
181
- else:
182
- log2('* app is missing.')
183
- log2()
184
- display_help()
185
-
186
- return False
187
-
188
- return True
189
-
190
- def user_pass(self, secret_path = 'cql.secret'):
191
- return Secrets.get_user_pass(self.pod if self.pod else self.sts, self.namespace, secret_path=secret_path)
192
-
193
- def enter_bash(self, bash_session: BashSession):
194
- self.bash_session = bash_session
195
- if self.device != ReplState.C:
196
- self.device = ReplState.C
197
- log2(f'Moved to {ReplState.C}: automatically. Will move back to {ReplState.P}: when you exit the bash session.')
198
-
199
- def exit_bash(self):
200
- if self.bash_session and self.bash_session.device:
201
- self.device = self.bash_session.device
202
-
203
- self.bash_session = None
204
-
205
- def wait_log(self, msg: str):
206
- if not self.wait_log_flag:
207
- log2(msg)
208
- self.wait_log_flag = True
209
-
210
- def clear_wait_log_flag(self):
211
- self.wait_log_flag = False
walker/sso/authn_ad.py DELETED
@@ -1,94 +0,0 @@
1
- import json
2
- import re
3
- import requests
4
- from urllib.parse import urlparse, parse_qs, unquote
5
-
6
- from walker.sso.authenticator import Authenticator
7
-
8
- from .idp_login import IdpLogin
9
- from walker.config import Config
10
- from walker.utils import log2
11
-
12
- class AdAuthenticator(Authenticator):
13
- # the singleton pattern
14
- def __new__(cls, *args, **kwargs):
15
- if not hasattr(cls, 'instance'): cls.instance = super(AdAuthenticator, cls).__new__(cls)
16
-
17
- return cls.instance
18
-
19
- def authenticate(self, idp_uri: str, app_host: str, username: str, password: str) -> IdpLogin:
20
- # https%3A%2F%2Fplat.c3ci.cloud%2Fc3%2Fc3%2Foidc%2Flogin
21
- parsed_url = urlparse(idp_uri)
22
- query_string = parsed_url.query
23
- params = parse_qs(query_string)
24
- state_token = params.get('state', [''])[0]
25
- redirect_url = params.get('redirect_uri', [''])[0]
26
-
27
- session = requests.Session()
28
- r = session.get(idp_uri)
29
- if Config().is_debug():
30
- log2(f'{r.status_code} {idp_uri}')
31
- # print(r.text)
32
-
33
- # extract_config_object('$Config={"fShowPersistentCookiesWarning":false}\n//]]></script>')
34
- config = self.extract_config_object(r.text)
35
-
36
- login = f'https://login.microsoftonline.com/53ad779a-93e7-485c-ba20-ac8290d7252b/login';
37
- body = {
38
- 'login': username,
39
- 'LoginOptions': '3',
40
- 'passwd': password,
41
- 'ctx': config['sCtx'],
42
- 'hpgrequestid': config['sessionId'],
43
- 'flowToken': config['sFT']
44
- }
45
- # print(body)
46
- r = session.post(login, data=body, headers={
47
- 'Content-Type': 'application/x-www-form-urlencoded'
48
- })
49
- if Config().is_debug():
50
- log2(f'{r.status_code} {login}')
51
- # print(r.text)
52
-
53
- config = self.extract_config_object(r.text)
54
-
55
- kmsi = 'https://login.microsoftonline.com/kmsi'
56
- body = {
57
- 'LoginOptions': '1',
58
- 'ctx': config['sCtx'],
59
- 'hpgrequestid': config['sessionId'],
60
- 'flowToken': config['sFT'],
61
- }
62
- r = session.post(kmsi, data=body, headers={
63
- 'Content-Type': 'application/x-www-form-urlencoded'
64
- })
65
- if Config().is_debug():
66
- log2(f'{r.status_code} {kmsi}')
67
-
68
- id_token = None
69
- if (config := self.extract_config_object(r.text)):
70
- if 'strServiceExceptionMessage' in config:
71
- log2(config['strServiceExceptionMessage'])
72
- else:
73
- log2('Unknown err.')
74
-
75
- return None
76
-
77
- id_token = self.extract(r.text, r'.*name=\"id_token\" value=\"(.*?)\".*')
78
-
79
- return IdpLogin(redirect_url, id_token, state_token, username, session=session)
80
-
81
- def extract_config_object(self, text: str):
82
- for line in text.split('\n'):
83
- groups = re.match(r'.*\$Config=\s*(\{.*)', line)
84
- if groups:
85
- js = groups[1].replace(';', '')
86
- config = json.loads(js)
87
-
88
- # print("* sessionId =", config['sessionId'])
89
- # print("* ctx =", config['sCtx'])
90
- # print("* flowToken =", config['sFT'])
91
-
92
- return config
93
-
94
- return None
walker/sso/idp.py DELETED
@@ -1,150 +0,0 @@
1
- import getpass
2
- import os
3
- from pathlib import Path
4
- from dotenv import load_dotenv
5
- from urllib.parse import urlparse, parse_qs
6
-
7
- from walker.sso import authn_okta
8
- from walker.sso.authenticator import Authenticator
9
- from walker.sso.authn_ad import AdAuthenticator
10
- from walker.sso.sso_config import SsoConfig
11
-
12
- from .idp_login import IdpLogin
13
- from walker.config import Config
14
- from walker.k8s_utils.kube_context import KubeContext
15
- from walker.utils import log, log2
16
-
17
- class Idp:
18
- ctrl_c_entered = False
19
-
20
- def __init__(self):
21
- pass
22
-
23
- def parse_idp_uri(idp_uri: str):
24
- parsed_url = urlparse(idp_uri)
25
- query_string = parsed_url.query
26
- params = parse_qs(query_string)
27
- state_token = params.get('state', [''])[0]
28
- redirect_url = params.get('redirect_uri', [''])[0]
29
-
30
- return IdpLogin(app_login_url=redirect_url, id=None, state=state_token)
31
-
32
- def login(app_host: str, username: str = None, forced = False, use_cached = True) -> IdpLogin:
33
- idp_uri = SsoConfig().find_idp_uri(username, app_host, app_host)
34
-
35
- if use_cached:
36
- if idp_token := os.getenv('IDP_TOKEN'):
37
- l0: IdpLogin = IdpLogin.deser(idp_token)
38
- l1: IdpLogin = Idp.parse_idp_uri(idp_uri)
39
- if l0.app_login_url == l1.app_login_url:
40
- if l0.state != 'EMPTY':
41
- return l0
42
-
43
- l0.state = l1.state
44
-
45
- return l0
46
-
47
- return Idp.with_creds(app_host, idp_uri, forced, username=username)
48
-
49
- def with_creds(app_host: str, idp_uri: str, forced: bool, username: str = None) -> IdpLogin:
50
- idp = urlparse(idp_uri).hostname
51
-
52
- def resolve_authn():
53
- if 'okta' in idp.lower():
54
- return authn_okta.OktaAuthenticator()
55
- elif 'microsoftonline' in idp.lower():
56
- return AdAuthenticator()
57
- else:
58
- log2(f'{idp} is not supported; only okta and ad are supported.')
59
-
60
- return None
61
-
62
- authn: Authenticator = resolve_authn()
63
- if not authn:
64
- return None
65
-
66
- okta = idp.upper().split('.')[0]
67
- dir = f'{Path.home()}/.kaqing'
68
- env_f = f'{dir}/.credentials'
69
- load_dotenv(dotenv_path=env_f)
70
-
71
- # c3energy.okta.com login:
72
- # Password:
73
- # username = None
74
- if username:
75
- log(f'{idp} login: {username}')
76
-
77
- while not username or Idp.ctrl_c_entered:
78
- if Idp.ctrl_c_entered:
79
- Idp.ctrl_c_entered = False
80
-
81
- default_user = os.getenv(f'{okta}_USERNAME')
82
- if default_user:
83
- if forced:
84
- username = default_user
85
- else:
86
- username = input(f'{idp} login(default {default_user}): ') or default_user
87
- else:
88
- username = input(f'{idp} login: ')
89
-
90
- idp2_uri = SsoConfig().find_idp_uri(username, app_host, app_host)
91
- if idp != (idp2 := urlparse(idp2_uri).hostname):
92
- log(f'Switched to {idp2}.')
93
- idp = idp2
94
- log(f'{idp} login: {username}')
95
- authn = resolve_authn()
96
- idp_uri = idp2_uri
97
-
98
- password = None
99
- while not password or Idp.ctrl_c_entered:
100
- if Idp.ctrl_c_entered:
101
- Idp.ctrl_c_entered = False
102
-
103
- default_pass = os.getenv(f'{okta}_PASSWORD')
104
- if default_pass:
105
- if forced:
106
- password = default_pass
107
- else:
108
- password = getpass.getpass(f'Password(default ********): ') or default_pass
109
- else:
110
- password = getpass.getpass(f'Password: ')
111
-
112
- if username and password:
113
- r: IdpLogin = None
114
- try:
115
- r = authn.authenticate(idp_uri, app_host, username, password)
116
-
117
- return r
118
- finally:
119
- if r and Config().get('app.login.cache-creds', True):
120
- updated = []
121
- if os.path.exists(env_f):
122
- with open(env_f, 'r') as file:
123
- try:
124
- file_content = file.read()
125
- for l in file_content.split('\n'):
126
- tks = l.split('=')
127
- key = tks[0]
128
- value = tks[1] if len(tks) > 1 else ''
129
- if key == f'{okta}_USERNAME':
130
- value = username
131
- elif key == f'{okta}_PASSWORD' and not KubeContext.in_cluster():
132
- # do not store password to the .credentials file when in Kubernetes pod
133
- value = password
134
- updated.append(f'{key}={value}')
135
- except:
136
- updated = None
137
- log2('Update failed')
138
- else:
139
- updated.append(f'{okta}_USERNAME={username}')
140
- if not KubeContext.in_cluster():
141
- # do not store password to the .credentials file when in Kubernetes pod
142
- updated.append(f'{okta}_PASSWORD={password}')
143
-
144
- if updated:
145
- if not os.path.exists(env_f):
146
- os.makedirs(dir, exist_ok=True)
147
- with open(env_f, "w") as file:
148
- file.write('\n'.join(updated))
149
-
150
- return None
walker/sso/idp_login.py DELETED
@@ -1,29 +0,0 @@
1
- import base64
2
- import json
3
- import requests
4
-
5
- class IdpLogin:
6
- def __init__(self, app_login_url: str, id: str, state: str, user: str = None, session: requests.Session = None):
7
- self.app_login_url = app_login_url
8
- self.id = id
9
- self.state = state
10
- self.user = user
11
- self.session = session
12
-
13
- def deser(idp_token: str):
14
- j = json.loads(base64.b64decode(idp_token.encode('utf-8')))
15
-
16
- return IdpLogin(j['r'], j['id'], j['state'])
17
-
18
- def ser(self):
19
- return base64.b64encode(json.dumps({
20
- 'r': self.app_login_url,
21
- 'id': self.id,
22
- 'state': self.state
23
- }).encode('utf-8')).decode('utf-8')
24
-
25
- def shell_user(self):
26
- if not self.user:
27
- return None
28
-
29
- return self.user.split('@')[0].replace('.', '')
walker/sso/sso_config.py DELETED
@@ -1,45 +0,0 @@
1
- import base64
2
- import json
3
- import os
4
- import re
5
- import requests
6
-
7
- from walker.config import Config
8
-
9
- class SsoConfig:
10
- # the singleton pattern
11
- def __new__(cls, *args, **kwargs):
12
- if not hasattr(cls, 'instance'): cls.instance = super(SsoConfig, cls).__new__(cls)
13
-
14
- return cls.instance
15
-
16
- def __init__(self):
17
- if not hasattr(self, 'config'):
18
- self.config = Config().get('idps', {
19
-
20
- })
21
- # print(self.config)
22
-
23
- def find_idp_uri(self, user_email: str, client_id: str, app_host: str):
24
- default = 'https://c3energy.okta.com/oauth2/v1/authorize?response_type=id_token&response_mode=form_post&client_id={client_id}&scope=openid+email+profile+groups&redirect_uri=https%3A%2F%2F{host}%2Fc3%2Fc3%2Foidc%2Flogin&nonce={nonce}&state=EMPTY'
25
-
26
- def rpl(uri: str):
27
- return uri.replace('{client_id}', client_id).replace('{host}', app_host).replace('{nonce}', SsoConfig.generate_oauth_nonce())
28
-
29
- if not user_email:
30
- return rpl(default)
31
-
32
- for idp_name, conf in self.config.items():
33
- if 'email-pattern' in conf:
34
- groups = re.match(conf['email-pattern'], user_email)
35
- if groups:
36
- return rpl(conf['uri'])
37
-
38
- return rpl(default)
39
-
40
- def generate_oauth_nonce():
41
- random_bytes = os.urandom(32)
42
- nonce = base64.urlsafe_b64encode(random_bytes).decode('utf-8')
43
- nonce = nonce.rstrip('=')
44
-
45
- return nonce