kaqing 2.0.110__py3-none-any.whl → 2.0.184__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of kaqing might be problematic. Click here for more details.
- adam/__init__.py +0 -2
- adam/app_session.py +9 -12
- adam/apps.py +18 -4
- adam/batch.py +5 -5
- adam/checks/check_utils.py +16 -46
- adam/checks/cpu.py +7 -1
- adam/checks/cpu_metrics.py +52 -0
- adam/checks/disk.py +2 -3
- adam/columns/columns.py +3 -1
- adam/columns/cpu.py +3 -1
- adam/columns/cpu_metrics.py +22 -0
- adam/columns/memory.py +3 -4
- adam/commands/__init__.py +24 -0
- adam/commands/alter_tables.py +33 -48
- adam/commands/app/__init__.py +0 -0
- adam/commands/app/app.py +38 -0
- adam/commands/{app_ping.py → app/app_ping.py} +7 -13
- adam/commands/app/show_app_actions.py +49 -0
- adam/commands/{show → app}/show_app_id.py +8 -11
- adam/commands/{show → app}/show_app_queues.py +7 -14
- adam/commands/app/utils_app.py +98 -0
- adam/commands/audit/audit.py +27 -31
- adam/commands/audit/audit_repair_tables.py +14 -18
- adam/commands/audit/audit_run.py +16 -23
- adam/commands/audit/show_last10.py +4 -17
- adam/commands/audit/show_slow10.py +4 -17
- adam/commands/audit/show_top10.py +4 -16
- adam/commands/audit/utils_show_top10.py +15 -3
- adam/commands/bash/__init__.py +5 -0
- adam/commands/bash/bash.py +36 -0
- adam/commands/bash/bash_completer.py +93 -0
- adam/commands/bash/utils_bash.py +16 -0
- adam/commands/cat.py +36 -0
- adam/commands/cd.py +11 -95
- adam/commands/check.py +15 -24
- adam/commands/cli_commands.py +2 -3
- adam/commands/clipboard_copy.py +86 -0
- adam/commands/code.py +57 -0
- adam/commands/command.py +198 -40
- adam/commands/commands_utils.py +12 -27
- adam/commands/cql/cql_completions.py +27 -10
- adam/commands/cql/cqlsh.py +12 -30
- adam/commands/cql/utils_cql.py +297 -0
- adam/commands/deploy/code_start.py +7 -10
- adam/commands/deploy/code_stop.py +4 -21
- adam/commands/deploy/code_utils.py +3 -3
- adam/commands/deploy/deploy.py +4 -27
- adam/commands/deploy/deploy_frontend.py +14 -17
- adam/commands/deploy/deploy_pg_agent.py +3 -6
- adam/commands/deploy/deploy_pod.py +65 -73
- adam/commands/deploy/deploy_utils.py +14 -24
- adam/commands/deploy/undeploy.py +4 -27
- adam/commands/deploy/undeploy_frontend.py +4 -7
- adam/commands/deploy/undeploy_pg_agent.py +6 -8
- adam/commands/deploy/undeploy_pod.py +11 -12
- adam/commands/devices/__init__.py +0 -0
- adam/commands/devices/device.py +123 -0
- adam/commands/devices/device_app.py +163 -0
- adam/commands/devices/device_auit_log.py +49 -0
- adam/commands/devices/device_cass.py +179 -0
- adam/commands/devices/device_export.py +84 -0
- adam/commands/devices/device_postgres.py +150 -0
- adam/commands/devices/devices.py +25 -0
- adam/commands/download_file.py +47 -0
- adam/commands/exit.py +1 -4
- adam/commands/export/__init__.py +0 -0
- adam/commands/export/clean_up_all_export_sessions.py +37 -0
- adam/commands/export/clean_up_export_sessions.py +39 -0
- adam/commands/export/download_export_session.py +39 -0
- adam/commands/export/drop_export_database.py +39 -0
- adam/commands/export/drop_export_databases.py +37 -0
- adam/commands/export/export.py +53 -0
- adam/commands/export/export_databases.py +245 -0
- adam/commands/export/export_select.py +59 -0
- adam/commands/export/export_select_x.py +54 -0
- adam/commands/export/export_sessions.py +209 -0
- adam/commands/export/export_use.py +49 -0
- adam/commands/export/exporter.py +332 -0
- adam/commands/export/import_files.py +44 -0
- adam/commands/export/import_session.py +44 -0
- adam/commands/export/importer.py +81 -0
- adam/commands/export/importer_athena.py +177 -0
- adam/commands/export/importer_sqlite.py +67 -0
- adam/commands/export/show_column_counts.py +45 -0
- adam/commands/export/show_export_databases.py +38 -0
- adam/commands/export/show_export_session.py +39 -0
- adam/commands/export/show_export_sessions.py +37 -0
- adam/commands/export/utils_export.py +343 -0
- adam/commands/find_files.py +51 -0
- adam/commands/find_processes.py +76 -0
- adam/commands/head.py +36 -0
- adam/commands/help.py +5 -3
- adam/commands/intermediate_command.py +49 -0
- adam/commands/issues.py +11 -43
- adam/commands/kubectl.py +38 -0
- adam/commands/login.py +22 -24
- adam/commands/logs.py +3 -6
- adam/commands/ls.py +11 -116
- adam/commands/medusa/medusa.py +4 -22
- adam/commands/medusa/medusa_backup.py +20 -27
- adam/commands/medusa/medusa_restore.py +38 -37
- adam/commands/medusa/medusa_show_backupjobs.py +16 -18
- adam/commands/medusa/medusa_show_restorejobs.py +13 -18
- adam/commands/nodetool.py +11 -17
- adam/commands/param_get.py +11 -14
- adam/commands/param_set.py +8 -12
- adam/commands/postgres/postgres.py +45 -46
- adam/commands/postgres/postgres_databases.py +269 -0
- adam/commands/postgres/postgres_ls.py +4 -8
- adam/commands/postgres/postgres_preview.py +5 -9
- adam/commands/postgres/psql_completions.py +4 -3
- adam/commands/postgres/utils_postgres.py +70 -0
- adam/commands/preview_table.py +8 -44
- adam/commands/pwd.py +14 -46
- adam/commands/reaper/reaper.py +4 -27
- adam/commands/reaper/reaper_forward.py +49 -56
- adam/commands/reaper/reaper_forward_session.py +6 -0
- adam/commands/reaper/reaper_forward_stop.py +10 -16
- adam/commands/reaper/reaper_restart.py +7 -14
- adam/commands/reaper/reaper_run_abort.py +8 -33
- adam/commands/reaper/reaper_runs.py +43 -58
- adam/commands/reaper/reaper_runs_abort.py +29 -49
- adam/commands/reaper/reaper_schedule_activate.py +9 -32
- adam/commands/reaper/reaper_schedule_start.py +9 -32
- adam/commands/reaper/reaper_schedule_stop.py +9 -32
- adam/commands/reaper/reaper_schedules.py +4 -14
- adam/commands/reaper/reaper_status.py +8 -16
- adam/commands/reaper/utils_reaper.py +194 -0
- adam/commands/repair/repair.py +4 -22
- adam/commands/repair/repair_log.py +5 -11
- adam/commands/repair/repair_run.py +27 -34
- adam/commands/repair/repair_scan.py +32 -38
- adam/commands/repair/repair_stop.py +5 -11
- adam/commands/report.py +27 -29
- adam/commands/restart.py +25 -26
- adam/commands/rollout.py +19 -24
- adam/commands/shell.py +12 -4
- adam/commands/show/show.py +10 -25
- adam/commands/show/show_adam.py +3 -3
- adam/commands/show/show_cassandra_repairs.py +35 -0
- adam/commands/show/show_cassandra_status.py +33 -51
- adam/commands/show/show_cassandra_version.py +5 -18
- adam/commands/show/show_commands.py +20 -25
- adam/commands/show/show_host.py +1 -1
- adam/commands/show/show_login.py +20 -27
- adam/commands/show/show_params.py +2 -5
- adam/commands/show/show_processes.py +15 -19
- adam/commands/show/show_storage.py +10 -20
- adam/commands/watch.py +26 -29
- adam/config.py +5 -14
- adam/embedded_params.py +1 -1
- adam/log.py +4 -4
- adam/pod_exec_result.py +6 -3
- adam/repl.py +69 -115
- adam/repl_commands.py +52 -19
- adam/repl_state.py +161 -40
- adam/sql/sql_completer.py +52 -27
- adam/sql/sql_state_machine.py +131 -19
- adam/sso/authn_ad.py +6 -8
- adam/sso/authn_okta.py +4 -6
- adam/sso/cred_cache.py +3 -5
- adam/sso/idp.py +9 -12
- adam/utils.py +511 -9
- adam/utils_athena.py +145 -0
- adam/utils_audits.py +12 -103
- adam/utils_issues.py +32 -0
- adam/utils_k8s/app_clusters.py +28 -0
- adam/utils_k8s/app_pods.py +36 -0
- adam/utils_k8s/cassandra_clusters.py +30 -19
- adam/utils_k8s/cassandra_nodes.py +3 -3
- adam/utils_k8s/custom_resources.py +16 -17
- adam/utils_k8s/ingresses.py +2 -2
- adam/utils_k8s/jobs.py +7 -11
- adam/utils_k8s/k8s.py +87 -0
- adam/utils_k8s/kube_context.py +2 -2
- adam/utils_k8s/pods.py +89 -78
- adam/utils_k8s/secrets.py +4 -4
- adam/utils_k8s/service_accounts.py +5 -4
- adam/utils_k8s/services.py +2 -2
- adam/utils_k8s/statefulsets.py +1 -12
- adam/utils_local.py +4 -0
- adam/utils_net.py +4 -4
- adam/utils_repl/__init__.py +0 -0
- adam/utils_repl/automata_completer.py +48 -0
- adam/utils_repl/repl_completer.py +46 -0
- adam/utils_repl/state_machine.py +173 -0
- adam/utils_sqlite.py +137 -0
- adam/version.py +1 -1
- {kaqing-2.0.110.dist-info → kaqing-2.0.184.dist-info}/METADATA +1 -1
- kaqing-2.0.184.dist-info/RECORD +244 -0
- adam/commands/app.py +0 -67
- adam/commands/bash.py +0 -150
- adam/commands/cp.py +0 -95
- adam/commands/cql/cql_utils.py +0 -112
- adam/commands/devices.py +0 -118
- adam/commands/postgres/postgres_context.py +0 -239
- adam/commands/postgres/postgres_utils.py +0 -31
- adam/commands/reaper/reaper_session.py +0 -159
- adam/commands/show/show_app_actions.py +0 -56
- adam/commands/show/show_repairs.py +0 -47
- kaqing-2.0.110.dist-info/RECORD +0 -187
- {kaqing-2.0.110.dist-info → kaqing-2.0.184.dist-info}/WHEEL +0 -0
- {kaqing-2.0.110.dist-info → kaqing-2.0.184.dist-info}/entry_points.txt +0 -0
- {kaqing-2.0.110.dist-info → kaqing-2.0.184.dist-info}/top_level.txt +0 -0
adam/repl_state.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import copy
|
|
1
|
+
from copy import copy
|
|
2
2
|
from enum import Enum
|
|
3
3
|
import re
|
|
4
|
-
import traceback
|
|
5
4
|
from typing import Callable
|
|
6
5
|
|
|
7
|
-
from adam.
|
|
6
|
+
from adam.utils_k8s.app_clusters import AppClusters
|
|
7
|
+
from adam.utils_k8s.app_pods import AppPods
|
|
8
8
|
from adam.utils_k8s.cassandra_clusters import CassandraClusters
|
|
9
9
|
from adam.utils_k8s.cassandra_nodes import CassandraNodes
|
|
10
10
|
from adam.utils_k8s.kube_context import KubeContext
|
|
@@ -19,25 +19,8 @@ class BashSession:
|
|
|
19
19
|
def pwd(self, state: 'ReplState'):
|
|
20
20
|
command = f'cat /tmp/.qing-{self.session_id}'
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
elif state.sts:
|
|
25
|
-
rs = CassandraClusters.exec(state.sts, state.namespace, command, action='bash', show_out=False)
|
|
26
|
-
|
|
27
|
-
dir = None
|
|
28
|
-
for r in rs:
|
|
29
|
-
if r.exit_code(): # if fails to read the session file, ignore
|
|
30
|
-
continue
|
|
31
|
-
|
|
32
|
-
dir0 = r.stdout.strip(' \r\n')
|
|
33
|
-
if dir:
|
|
34
|
-
if dir != dir0:
|
|
35
|
-
log2('Inconsitent working dir found across multiple pods.')
|
|
36
|
-
return None
|
|
37
|
-
else:
|
|
38
|
-
dir = dir0
|
|
39
|
-
|
|
40
|
-
return dir
|
|
22
|
+
with device(state) as pods:
|
|
23
|
+
return pods.exec(command, action='bash', show_out=False)
|
|
41
24
|
|
|
42
25
|
class RequiredState(Enum):
|
|
43
26
|
CLUSTER = 'cluster'
|
|
@@ -46,20 +29,22 @@ class RequiredState(Enum):
|
|
|
46
29
|
NAMESPACE = 'namespace'
|
|
47
30
|
PG_DATABASE = 'pg_database'
|
|
48
31
|
APP_APP = 'app_app'
|
|
32
|
+
EXPORT_DB = 'export_db'
|
|
49
33
|
|
|
50
34
|
class ReplState:
|
|
51
35
|
A = 'a'
|
|
52
36
|
C = 'c'
|
|
53
37
|
L = 'l'
|
|
54
38
|
P = 'p'
|
|
39
|
+
X = 'x'
|
|
55
40
|
|
|
56
|
-
ANY = [A, C, L, P]
|
|
57
|
-
NON_L = [A, C, P]
|
|
41
|
+
ANY = [A, C, L, P, X]
|
|
42
|
+
NON_L = [A, C, P, X]
|
|
58
43
|
|
|
59
44
|
def __init__(self, device: str = None,
|
|
60
45
|
sts: str = None, pod: str = None, namespace: str = None, ns_sts: str = None,
|
|
61
46
|
pg_path: str = None,
|
|
62
|
-
app_env: str = None, app_app: str = None,
|
|
47
|
+
app_env: str = None, app_app: str = None, app_pod: str = None,
|
|
63
48
|
in_repl = False, bash_session: BashSession = None, remote_dir = None):
|
|
64
49
|
self.namespace = KubeContext.in_cluster_namespace()
|
|
65
50
|
|
|
@@ -69,12 +54,15 @@ class ReplState:
|
|
|
69
54
|
self.pg_path = pg_path
|
|
70
55
|
self.app_env = app_env
|
|
71
56
|
self.app_app = app_app
|
|
57
|
+
self.app_pod = app_pod
|
|
72
58
|
if namespace:
|
|
73
59
|
self.namespace = namespace
|
|
74
60
|
self.in_repl = in_repl
|
|
75
61
|
self.bash_session = bash_session
|
|
76
62
|
self.remote_dir = remote_dir
|
|
77
|
-
|
|
63
|
+
self.original_state: ReplState = None
|
|
64
|
+
|
|
65
|
+
self.export_session: str = None
|
|
78
66
|
|
|
79
67
|
if ns_sts:
|
|
80
68
|
nn = ns_sts.split('@')
|
|
@@ -89,13 +77,51 @@ class ReplState:
|
|
|
89
77
|
def __hash__(self):
|
|
90
78
|
return hash((self.sts, self.pod))
|
|
91
79
|
|
|
80
|
+
def __str__(self):
|
|
81
|
+
msg = ''
|
|
82
|
+
if self.device == ReplState.P:
|
|
83
|
+
msg = f'{ReplState.P}:'
|
|
84
|
+
host, database = self.pg_host_n_database()
|
|
85
|
+
if database:
|
|
86
|
+
msg += database
|
|
87
|
+
elif host:
|
|
88
|
+
msg += host
|
|
89
|
+
elif self.device == ReplState.A:
|
|
90
|
+
msg = f'{ReplState.A}:'
|
|
91
|
+
if self.app_env:
|
|
92
|
+
msg += self.app_env
|
|
93
|
+
if self.app_app:
|
|
94
|
+
msg += f'/{self.app_app}'
|
|
95
|
+
if self.app_pod:
|
|
96
|
+
# azops88-c3-c3-k8sdeploy-appleader-001-79957cf5b6-9k4bw
|
|
97
|
+
group = re.match(r".*?-.*?-.*?-.*?-(.*?-.*?)-.*", self.app_pod)
|
|
98
|
+
msg += '/' + group[1]
|
|
99
|
+
elif self.device == ReplState.L:
|
|
100
|
+
msg = f'{ReplState.L}:'
|
|
101
|
+
elif self.device == ReplState.X:
|
|
102
|
+
msg = f'{ReplState.X}:'
|
|
103
|
+
if self.export_session:
|
|
104
|
+
msg += self.export_session
|
|
105
|
+
else:
|
|
106
|
+
msg = f'{ReplState.C}:'
|
|
107
|
+
if self.pod:
|
|
108
|
+
# cs-d0767a536f-cs-d0767a536f-default-sts-0
|
|
109
|
+
group = re.match(r".*?-.*?-(.*)", self.pod)
|
|
110
|
+
msg += group[1]
|
|
111
|
+
elif self.sts:
|
|
112
|
+
# cs-d0767a536f-cs-d0767a536f-default-sts
|
|
113
|
+
group = re.match(r".*?-.*?-(.*)", self.sts)
|
|
114
|
+
msg += group[1]
|
|
115
|
+
|
|
116
|
+
return msg
|
|
117
|
+
|
|
92
118
|
def apply_args(self, args: list[str], cmd: list[str] = None, resolve_pg = True, args_to_check = 6) -> tuple['ReplState', list[str]]:
|
|
93
119
|
state = self
|
|
94
120
|
|
|
95
121
|
new_args = []
|
|
96
122
|
for index, arg in enumerate(args):
|
|
97
123
|
if index < args_to_check:
|
|
98
|
-
state = copy
|
|
124
|
+
state = copy(state)
|
|
99
125
|
|
|
100
126
|
s, n = KubeContext.is_sts_name(arg)
|
|
101
127
|
if s:
|
|
@@ -133,9 +159,9 @@ class ReplState:
|
|
|
133
159
|
new_args = []
|
|
134
160
|
for index, arg in enumerate(args):
|
|
135
161
|
if index < 6:
|
|
136
|
-
state = copy
|
|
162
|
+
state = copy(state)
|
|
137
163
|
|
|
138
|
-
groups = re.match(r'^([a|c|l|p]):(.*)$', arg)
|
|
164
|
+
groups = re.match(r'^([a|c|l|p|x]):(.*)$', arg)
|
|
139
165
|
if groups:
|
|
140
166
|
if groups[1] == 'p':
|
|
141
167
|
state.device = 'p'
|
|
@@ -154,6 +180,8 @@ class ReplState:
|
|
|
154
180
|
state.namespace = ns
|
|
155
181
|
elif groups[1] == 'l':
|
|
156
182
|
state.device = 'l'
|
|
183
|
+
elif groups[1] == 'x':
|
|
184
|
+
state.device = 'x'
|
|
157
185
|
else:
|
|
158
186
|
state.device = 'a'
|
|
159
187
|
if path := groups[2]:
|
|
@@ -196,8 +224,8 @@ class ReplState:
|
|
|
196
224
|
|
|
197
225
|
return False
|
|
198
226
|
|
|
199
|
-
devices = [r for r in required if r in [ReplState.L, ReplState.A, ReplState.C, ReplState.P]]
|
|
200
|
-
non_devices = [r for r in required if r not in [ReplState.L, ReplState.A, ReplState.C, ReplState.P]]
|
|
227
|
+
devices = [r for r in required if r in [ReplState.L, ReplState.A, ReplState.C, ReplState.P, ReplState.X]]
|
|
228
|
+
non_devices = [r for r in required if r not in [ReplState.L, ReplState.A, ReplState.C, ReplState.P, ReplState.X]]
|
|
201
229
|
|
|
202
230
|
first_error: Callable = None
|
|
203
231
|
for r in non_devices:
|
|
@@ -285,8 +313,8 @@ class ReplState:
|
|
|
285
313
|
if self.device != ReplState.P:
|
|
286
314
|
return (False, None)
|
|
287
315
|
|
|
288
|
-
|
|
289
|
-
if not
|
|
316
|
+
_, database = self.pg_host_n_database()
|
|
317
|
+
if not database:
|
|
290
318
|
def error():
|
|
291
319
|
if self.in_repl:
|
|
292
320
|
log2('cd to a database first.')
|
|
@@ -310,7 +338,24 @@ class ReplState:
|
|
|
310
338
|
display_help()
|
|
311
339
|
return (False, error)
|
|
312
340
|
|
|
313
|
-
elif required
|
|
341
|
+
elif required == RequiredState.EXPORT_DB:
|
|
342
|
+
if self.device not in [ReplState.C, ReplState.X]:
|
|
343
|
+
return (False, None)
|
|
344
|
+
|
|
345
|
+
if not self.export_session:
|
|
346
|
+
def error():
|
|
347
|
+
if self.in_repl:
|
|
348
|
+
if self.device == ReplState.C:
|
|
349
|
+
log2("Select an export database first with 'use' command.")
|
|
350
|
+
else:
|
|
351
|
+
log2('cd to an export database first.')
|
|
352
|
+
else:
|
|
353
|
+
log2('* export database is missing.')
|
|
354
|
+
log2()
|
|
355
|
+
display_help()
|
|
356
|
+
return (False, error)
|
|
357
|
+
|
|
358
|
+
elif required in [ReplState.L, ReplState.A, ReplState.C, ReplState.P, ReplState.X] and self.device != required:
|
|
314
359
|
def error():
|
|
315
360
|
if self.in_repl:
|
|
316
361
|
log2(f'Switch to {required}: first.')
|
|
@@ -339,13 +384,89 @@ class ReplState:
|
|
|
339
384
|
return Secrets.get_user_pass(self.pod if self.pod else self.sts, self.namespace, secret_path=secret_path)
|
|
340
385
|
|
|
341
386
|
def enter_bash(self, bash_session: BashSession):
|
|
387
|
+
self.push()
|
|
388
|
+
|
|
342
389
|
self.bash_session = bash_session
|
|
343
|
-
if self.device != ReplState.C:
|
|
344
|
-
self.device = ReplState.C
|
|
345
|
-
log2(f'Moved to {ReplState.C}: automatically. Will move back to {ReplState.P}: when you exit the bash session.')
|
|
346
390
|
|
|
347
391
|
def exit_bash(self):
|
|
348
|
-
|
|
349
|
-
|
|
392
|
+
self.pop()
|
|
393
|
+
self.bash_session = None
|
|
394
|
+
|
|
395
|
+
def push(self):
|
|
396
|
+
if not self.original_state:
|
|
397
|
+
self.original_state = copy(self)
|
|
398
|
+
|
|
399
|
+
def pop(self):
|
|
400
|
+
if o := self.original_state:
|
|
401
|
+
self.device = o.device
|
|
402
|
+
self.sts = o.sts
|
|
403
|
+
self.pod = o.pod
|
|
404
|
+
self.pg_path = o.pg_path
|
|
405
|
+
self.app_env = o.app_env
|
|
406
|
+
self.app_app = o.app_app
|
|
407
|
+
self.app_pod = o.app_pod
|
|
408
|
+
# self.export_session = o.export_session
|
|
409
|
+
self.namespace = o.namespace
|
|
410
|
+
|
|
411
|
+
self.original_state = None
|
|
412
|
+
|
|
413
|
+
def pg_host_n_database(self):
|
|
414
|
+
host = None
|
|
415
|
+
database = None
|
|
416
|
+
|
|
417
|
+
if self.pg_path:
|
|
418
|
+
host_n_db = self.pg_path.split('/')
|
|
419
|
+
host = host_n_db[0]
|
|
420
|
+
if len(host_n_db) > 1:
|
|
421
|
+
database = host_n_db[1]
|
|
422
|
+
|
|
423
|
+
return host, database
|
|
424
|
+
|
|
425
|
+
class DevicePodService:
|
|
426
|
+
def __init__(self, handler: 'DeviceExecHandler'):
|
|
427
|
+
self.handler = handler
|
|
428
|
+
|
|
429
|
+
def exec(self, command: str, action='bash', show_out = True):
|
|
430
|
+
state = self.handler.state
|
|
431
|
+
|
|
432
|
+
rs = None
|
|
433
|
+
if state.device == ReplState.A and state.app_app:
|
|
434
|
+
if state.app_pod:
|
|
435
|
+
rs = [AppPods.exec(state.app_pod, state.namespace, command, show_out=show_out)]
|
|
436
|
+
else:
|
|
437
|
+
pods = AppPods.pod_names(state.namespace, state.app_env, state.app_app)
|
|
438
|
+
rs = AppClusters.exec(pods, state.namespace, command, show_out=show_out)
|
|
439
|
+
elif state.pod:
|
|
440
|
+
rs = [CassandraNodes.exec(state.pod, state.namespace, command, show_out=show_out)]
|
|
441
|
+
elif state.sts:
|
|
442
|
+
rs = CassandraClusters.exec(state.sts, state.namespace, command, action=action, show_out=show_out)
|
|
443
|
+
# assume that pg-agent or ops pod is single pod
|
|
444
|
+
|
|
445
|
+
dir = None
|
|
446
|
+
if rs:
|
|
447
|
+
for r in rs:
|
|
448
|
+
if r.exit_code(): # if fails to read the session file, ignore
|
|
449
|
+
continue
|
|
450
|
+
|
|
451
|
+
dir0 = r.stdout.strip(' \r\n')
|
|
452
|
+
if dir:
|
|
453
|
+
if dir != dir0:
|
|
454
|
+
log2('Inconsitent working dir found across multiple pods.')
|
|
455
|
+
return None
|
|
456
|
+
else:
|
|
457
|
+
dir = dir0
|
|
458
|
+
|
|
459
|
+
return dir
|
|
460
|
+
|
|
461
|
+
class DeviceExecHandler:
|
|
462
|
+
def __init__(self, state: ReplState):
|
|
463
|
+
self.state = state
|
|
464
|
+
|
|
465
|
+
def __enter__(self):
|
|
466
|
+
return DevicePodService(self)
|
|
467
|
+
|
|
468
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
469
|
+
return False
|
|
350
470
|
|
|
351
|
-
|
|
471
|
+
def device(state: ReplState):
|
|
472
|
+
return DeviceExecHandler(state)
|
adam/sql/sql_completer.py
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
from enum import Enum
|
|
1
2
|
from typing import Callable
|
|
2
3
|
|
|
3
4
|
import sqlparse
|
|
4
|
-
from sqlparse.sql import
|
|
5
|
+
from sqlparse.sql import Token
|
|
5
6
|
|
|
6
7
|
from adam.sql.term_completer import TermCompleter
|
|
7
8
|
from adam.utils_repl.automata_completer import AutomataCompleter
|
|
@@ -12,41 +13,42 @@ __all__ = [
|
|
|
12
13
|
"SqlCompleter",
|
|
13
14
|
]
|
|
14
15
|
|
|
15
|
-
def default_columns(
|
|
16
|
+
def default_columns(x: list[str]):
|
|
16
17
|
return 'id,x.,y.,z.'.split(',')
|
|
17
18
|
|
|
19
|
+
class SqlVariant(Enum):
|
|
20
|
+
SQL = 'sql'
|
|
21
|
+
CQL = 'cql'
|
|
22
|
+
ATHENA = 'athena'
|
|
23
|
+
|
|
18
24
|
class SqlCompleter(AutomataCompleter[Token]):
|
|
19
25
|
def tokens(self, text: str) -> list[Token]:
|
|
20
26
|
tokens = []
|
|
21
27
|
|
|
22
28
|
stmts = sqlparse.parse(text)
|
|
23
|
-
if
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
statement: Statement = stmts[0]
|
|
27
|
-
tokens = statement.tokens
|
|
29
|
+
if stmts:
|
|
30
|
+
for stmt in stmts:
|
|
31
|
+
tokens.extend(stmt.tokens)
|
|
28
32
|
|
|
29
33
|
return tokens
|
|
30
34
|
|
|
31
35
|
def __init__(self,
|
|
32
36
|
tables: Callable[[], list[str]],
|
|
33
37
|
dml: str = None,
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
table_props: Callable[[], dict[str,list[str]]] = lambda: [],
|
|
37
|
-
variant = 'sql',
|
|
38
|
+
expandables: dict = {},
|
|
39
|
+
variant: SqlVariant = SqlVariant.SQL,
|
|
38
40
|
debug = False):
|
|
39
41
|
machine = SqlStateMachine(debug=debug)
|
|
40
|
-
if variant ==
|
|
42
|
+
if variant == SqlVariant.CQL:
|
|
41
43
|
machine = CqlStateMachine(debug=debug)
|
|
42
|
-
elif variant ==
|
|
44
|
+
elif variant == SqlVariant.ATHENA:
|
|
43
45
|
machine = AthenaStateMachine(debug=debug)
|
|
44
46
|
super().__init__(machine, dml, debug)
|
|
45
47
|
|
|
46
48
|
self.tables = tables
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
self.
|
|
49
|
+
if 'columns' not in expandables:
|
|
50
|
+
expandables['columns'] = default_columns
|
|
51
|
+
self.expandables = expandables
|
|
50
52
|
self.variant = variant
|
|
51
53
|
self.debug = debug
|
|
52
54
|
|
|
@@ -63,31 +65,54 @@ class SqlCompleter(AutomataCompleter[Token]):
|
|
|
63
65
|
def _terms(self, state: State, word: str) -> list[str]:
|
|
64
66
|
terms = []
|
|
65
67
|
|
|
66
|
-
if word
|
|
68
|
+
if word.startswith('`') and word.endswith('`'):
|
|
69
|
+
terms.append(word.strip('`'))
|
|
70
|
+
elif word == 'tables':
|
|
67
71
|
terms.extend(self.tables())
|
|
68
|
-
elif word == '`tables`':
|
|
69
|
-
terms.append('tables')
|
|
70
72
|
elif word == 'columns':
|
|
71
|
-
|
|
73
|
+
if 'last_name' in state.context and (n := state.context['last_name']):
|
|
74
|
+
if 'last_namespace' in state.context and (ns := state.context['last_namespace']):
|
|
75
|
+
n = f'{ns}.{n}'
|
|
76
|
+
terms.extend(self._call_expandable(word, [n]))
|
|
77
|
+
else:
|
|
78
|
+
terms.extend(self._call_expandable(word, []))
|
|
72
79
|
elif word == 'partition-columns':
|
|
73
|
-
terms.extend(self.
|
|
80
|
+
terms.extend(self._call_expandable(word, []))
|
|
74
81
|
elif word == 'table-props':
|
|
75
|
-
terms.extend(self.
|
|
82
|
+
terms.extend(self._call_expandable(word).keys())
|
|
76
83
|
elif word == 'table-prop-values':
|
|
77
84
|
if 'last_name' in state.context and state.context['last_name']:
|
|
78
|
-
|
|
85
|
+
table_props = self._call_expandable('table-props')
|
|
86
|
+
terms.extend(table_props[state.context['last_name']])
|
|
79
87
|
elif word == 'single':
|
|
80
88
|
terms.append("'")
|
|
81
89
|
elif word == 'comma':
|
|
82
90
|
terms.append(",")
|
|
91
|
+
elif word in self.machine.expandable_names():
|
|
92
|
+
terms.extend(self._call_expandable(word))
|
|
83
93
|
else:
|
|
84
94
|
terms.append(word)
|
|
85
95
|
|
|
86
96
|
return terms
|
|
87
97
|
|
|
88
|
-
def
|
|
98
|
+
def _call_expandable(self, name: str, *args):
|
|
99
|
+
if name in self.expandables:
|
|
100
|
+
c = self.expandables[name]
|
|
101
|
+
if args:
|
|
102
|
+
return c(args)
|
|
103
|
+
else:
|
|
104
|
+
return c()
|
|
105
|
+
|
|
106
|
+
return []
|
|
107
|
+
|
|
108
|
+
def completions_for_nesting(self, dml: str = None):
|
|
109
|
+
if dml:
|
|
110
|
+
return {dml: SqlCompleter(self.tables, dml, expandables=self.expandables, variant=self.variant)}
|
|
111
|
+
|
|
89
112
|
return {
|
|
90
|
-
word
|
|
91
|
-
table_props=self.table_props, variant=self.variant)
|
|
113
|
+
word: SqlCompleter(self.tables, word, expandables=self.expandables, variant=self.variant)
|
|
92
114
|
for word in self.machine.suggestions[''].strip(' ').split(',')
|
|
93
|
-
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
def __str__(self):
|
|
118
|
+
return f'{self.variant}, {self.first_term}'
|