kaqing 2.0.98__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.
- adam/__init__.py +0 -2
- adam/app_session.py +9 -7
- adam/batch.py +4 -18
- adam/checks/check_utils.py +14 -46
- adam/checks/cpu.py +7 -1
- adam/checks/cpu_metrics.py +52 -0
- adam/columns/columns.py +3 -1
- adam/columns/cpu.py +3 -1
- adam/columns/cpu_metrics.py +22 -0
- adam/commands/__init__.py +15 -0
- adam/commands/alter_tables.py +50 -61
- adam/commands/app_cmd.py +38 -0
- adam/commands/app_ping.py +8 -14
- adam/commands/audit/audit.py +43 -30
- adam/commands/audit/audit_repair_tables.py +26 -46
- adam/commands/audit/audit_run.py +50 -0
- adam/commands/audit/show_last10.py +48 -0
- adam/commands/audit/show_slow10.py +47 -0
- adam/commands/audit/show_top10.py +45 -0
- adam/commands/audit/utils_show_top10.py +59 -0
- 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 +50 -0
- adam/commands/cd.py +15 -91
- adam/commands/check.py +23 -18
- adam/commands/cli_commands.py +2 -3
- adam/commands/code.py +57 -0
- adam/commands/command.py +96 -40
- adam/commands/commands_utils.py +9 -19
- adam/commands/cp.py +33 -39
- adam/commands/cql/cql_completions.py +30 -8
- adam/commands/cql/cqlsh.py +12 -27
- adam/commands/cql/utils_cql.py +343 -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 -21
- adam/commands/deploy/deploy_frontend.py +14 -17
- adam/commands/deploy/deploy_pg_agent.py +3 -6
- adam/commands/deploy/deploy_pod.py +67 -73
- adam/commands/deploy/deploy_utils.py +14 -24
- adam/commands/deploy/undeploy.py +4 -21
- 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/device.py +118 -0
- adam/commands/devices/device_app.py +173 -0
- adam/commands/devices/device_auit_log.py +49 -0
- adam/commands/devices/device_cass.py +185 -0
- adam/commands/devices/device_export.py +86 -0
- adam/commands/devices/device_postgres.py +144 -0
- adam/commands/devices/devices.py +25 -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 +51 -0
- adam/commands/export/drop_export_database.py +55 -0
- adam/commands/export/drop_export_databases.py +43 -0
- adam/commands/export/export.py +53 -0
- adam/commands/export/export_databases.py +170 -0
- adam/commands/export/export_handlers.py +71 -0
- adam/commands/export/export_select.py +81 -0
- adam/commands/export/export_select_x.py +54 -0
- adam/commands/export/export_use.py +52 -0
- adam/commands/export/exporter.py +352 -0
- adam/commands/export/import_session.py +40 -0
- adam/commands/export/importer.py +67 -0
- adam/commands/export/importer_athena.py +80 -0
- adam/commands/export/importer_sqlite.py +47 -0
- adam/commands/export/show_column_counts.py +54 -0
- adam/commands/export/show_export_databases.py +36 -0
- adam/commands/export/show_export_session.py +48 -0
- adam/commands/export/show_export_sessions.py +44 -0
- adam/commands/export/utils_export.py +314 -0
- adam/commands/help.py +10 -6
- adam/commands/intermediate_command.py +49 -0
- adam/commands/issues.py +14 -40
- adam/commands/kubectl.py +38 -0
- adam/commands/login.py +28 -24
- adam/commands/logs.py +4 -6
- adam/commands/ls.py +11 -116
- adam/commands/medusa/medusa.py +4 -22
- adam/commands/medusa/medusa_backup.py +20 -24
- adam/commands/medusa/medusa_restore.py +30 -32
- adam/commands/medusa/medusa_show_backupjobs.py +16 -17
- adam/commands/medusa/medusa_show_restorejobs.py +12 -17
- adam/commands/nodetool.py +11 -17
- adam/commands/param_get.py +11 -12
- adam/commands/param_set.py +9 -10
- adam/commands/postgres/postgres.py +43 -36
- adam/commands/postgres/{postgres_session.py → postgres_context.py} +80 -46
- adam/commands/postgres/postgres_ls.py +4 -8
- adam/commands/postgres/postgres_preview.py +5 -9
- adam/commands/postgres/psql_completions.py +2 -2
- adam/commands/postgres/utils_postgres.py +66 -0
- adam/commands/preview_table.py +8 -61
- adam/commands/pwd.py +14 -44
- adam/commands/reaper/reaper.py +4 -24
- adam/commands/reaper/reaper_forward.py +48 -55
- 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 +11 -30
- adam/commands/reaper/reaper_runs.py +42 -57
- adam/commands/reaper/reaper_runs_abort.py +29 -49
- adam/commands/reaper/reaper_schedule_activate.py +11 -30
- adam/commands/reaper/reaper_schedule_start.py +10 -29
- adam/commands/reaper/reaper_schedule_stop.py +10 -29
- adam/commands/reaper/reaper_schedules.py +4 -14
- adam/commands/reaper/reaper_status.py +8 -16
- adam/commands/reaper/utils_reaper.py +196 -0
- adam/commands/repair/repair.py +4 -22
- adam/commands/repair/repair_log.py +4 -7
- adam/commands/repair/repair_run.py +27 -29
- adam/commands/repair/repair_scan.py +31 -34
- adam/commands/repair/repair_stop.py +4 -7
- adam/commands/report.py +25 -21
- adam/commands/restart.py +25 -26
- adam/commands/rollout.py +19 -24
- adam/commands/shell.py +5 -4
- adam/commands/show/show.py +6 -19
- adam/commands/show/show_app_actions.py +26 -22
- adam/commands/show/show_app_id.py +8 -11
- adam/commands/show/show_app_queues.py +7 -10
- adam/commands/show/{show_repairs.py → show_cassandra_repairs.py} +8 -17
- adam/commands/show/show_cassandra_status.py +29 -33
- adam/commands/show/show_cassandra_version.py +4 -14
- adam/commands/show/show_commands.py +19 -21
- adam/commands/show/show_host.py +1 -1
- adam/commands/show/show_login.py +26 -24
- adam/commands/show/show_processes.py +16 -18
- 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/pod_exec_result.py +7 -1
- adam/repl.py +95 -131
- adam/repl_commands.py +48 -20
- adam/repl_state.py +270 -61
- adam/sql/sql_completer.py +105 -63
- adam/sql/sql_state_machine.py +618 -0
- adam/sql/term_completer.py +3 -0
- adam/sso/authn_ad.py +6 -5
- adam/sso/authn_okta.py +3 -3
- adam/sso/cred_cache.py +3 -2
- adam/sso/idp.py +3 -3
- adam/utils.py +439 -3
- adam/utils_app.py +98 -0
- adam/utils_athena.py +140 -87
- adam/utils_audits.py +106 -0
- adam/utils_issues.py +32 -0
- adam/utils_k8s/app_clusters.py +28 -0
- adam/utils_k8s/app_pods.py +33 -0
- adam/utils_k8s/cassandra_clusters.py +22 -20
- adam/utils_k8s/cassandra_nodes.py +4 -4
- adam/utils_k8s/custom_resources.py +5 -0
- adam/utils_k8s/ingresses.py +2 -2
- adam/utils_k8s/k8s.py +87 -0
- adam/utils_k8s/pods.py +77 -68
- 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_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 +109 -0
- adam/version.py +1 -1
- {kaqing-2.0.98.dist-info → kaqing-2.0.171.dist-info}/METADATA +1 -1
- kaqing-2.0.171.dist-info/RECORD +236 -0
- adam/commands/app.py +0 -67
- adam/commands/bash.py +0 -92
- adam/commands/cql/cql_table_completer.py +0 -8
- adam/commands/cql/cql_utils.py +0 -115
- adam/commands/describe/describe.py +0 -47
- adam/commands/describe/describe_keyspace.py +0 -60
- adam/commands/describe/describe_keyspaces.py +0 -49
- adam/commands/describe/describe_schema.py +0 -49
- adam/commands/describe/describe_table.py +0 -60
- adam/commands/describe/describe_tables.py +0 -49
- adam/commands/devices.py +0 -118
- adam/commands/postgres/postgres_utils.py +0 -31
- adam/commands/postgres/psql_table_completer.py +0 -11
- adam/commands/reaper/reaper_session.py +0 -159
- adam/sql/state_machine.py +0 -460
- kaqing-2.0.98.dist-info/RECORD +0 -191
- /adam/commands/{describe → devices}/__init__.py +0 -0
- {kaqing-2.0.98.dist-info → kaqing-2.0.171.dist-info}/WHEEL +0 -0
- {kaqing-2.0.98.dist-info → kaqing-2.0.171.dist-info}/entry_points.txt +0 -0
- {kaqing-2.0.98.dist-info → kaqing-2.0.171.dist-info}/top_level.txt +0 -0
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import click
|
|
2
2
|
|
|
3
|
+
from adam.commands import extract_trailing_options
|
|
3
4
|
from adam.commands.command import Command
|
|
5
|
+
from adam.commands.intermediate_command import IntermediateCommand
|
|
4
6
|
from adam.commands.postgres.psql_completions import psql_completions
|
|
5
|
-
from adam.commands.postgres.
|
|
7
|
+
from adam.commands.postgres.utils_postgres import pg_table_names, postgres
|
|
6
8
|
from .postgres_ls import PostgresLs
|
|
7
9
|
from .postgres_preview import PostgresPreview
|
|
8
|
-
from .
|
|
10
|
+
from .postgres_context import PostgresContext
|
|
9
11
|
from adam.repl_state import ReplState
|
|
10
12
|
from adam.utils import log, log2
|
|
11
13
|
|
|
12
|
-
class Postgres(
|
|
14
|
+
class Postgres(IntermediateCommand):
|
|
13
15
|
COMMAND = 'pg'
|
|
14
|
-
reaper_login = None
|
|
15
16
|
|
|
16
17
|
# the singleton pattern
|
|
17
18
|
def __new__(cls, *args, **kwargs):
|
|
@@ -29,40 +30,36 @@ class Postgres(Command):
|
|
|
29
30
|
if not(args := self.args(cmd)):
|
|
30
31
|
return super().run(cmd, state)
|
|
31
32
|
|
|
32
|
-
|
|
33
|
+
with self.validate(args, state) as (args, state):
|
|
34
|
+
with extract_trailing_options(args, '&') as (args, backgrounded):
|
|
35
|
+
if not args:
|
|
36
|
+
if state.in_repl:
|
|
37
|
+
log2('Please use SQL statement. e.g. pg \l')
|
|
38
|
+
else:
|
|
39
|
+
log2('* Command or SQL statements is missing.')
|
|
40
|
+
Command.display_help()
|
|
33
41
|
|
|
34
|
-
|
|
35
|
-
if state.in_repl:
|
|
36
|
-
log2('Please use SQL statement. e.g. pg \l')
|
|
37
|
-
else:
|
|
38
|
-
log2('* Command or SQL statements is missing.')
|
|
39
|
-
Command.display_help()
|
|
42
|
+
return 'command-missing'
|
|
40
43
|
|
|
41
|
-
|
|
44
|
+
if not state.pg_path:
|
|
45
|
+
if state.in_repl:
|
|
46
|
+
log2('Enter "use <pg-name>" first.')
|
|
47
|
+
else:
|
|
48
|
+
log2('* pg-name is missing.')
|
|
42
49
|
|
|
43
|
-
|
|
44
|
-
self.run_sql(state, args)
|
|
45
|
-
else:
|
|
46
|
-
# head with the Chain of Responsibility pattern
|
|
47
|
-
cmds = Command.chain(Postgres.cmd_list())
|
|
48
|
-
if not cmds.run(cmd, state) :
|
|
49
|
-
self.run_sql(state, args)
|
|
50
|
-
|
|
51
|
-
return state
|
|
52
|
-
|
|
53
|
-
def cmd_list():
|
|
54
|
-
return [PostgresLs(), PostgresPreview()]
|
|
50
|
+
return state
|
|
55
51
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
52
|
+
if state.in_repl:
|
|
53
|
+
with postgres(state) as pod:
|
|
54
|
+
pod.sql(args, background=backgrounded)
|
|
55
|
+
elif not self.run_subcommand(cmd, state):
|
|
56
|
+
with postgres(state) as pod:
|
|
57
|
+
pod.sql(args, background=backgrounded)
|
|
62
58
|
|
|
63
|
-
|
|
59
|
+
return state
|
|
64
60
|
|
|
65
|
-
|
|
61
|
+
def cmd_list(self):
|
|
62
|
+
return [PostgresLs(), PostgresPreview(), PostgresPg()]
|
|
66
63
|
|
|
67
64
|
def completion(self, state: ReplState):
|
|
68
65
|
if state.device != state.P:
|
|
@@ -70,7 +67,7 @@ class Postgres(Command):
|
|
|
70
67
|
return {}
|
|
71
68
|
|
|
72
69
|
leaf = {}
|
|
73
|
-
session =
|
|
70
|
+
session = PostgresContext.apply(state.namespace, state.pg_path)
|
|
74
71
|
if session.db:
|
|
75
72
|
if pg_table_names(state.namespace, state.pg_path):
|
|
76
73
|
leaf = psql_completions(state.namespace, state.pg_path)
|
|
@@ -86,12 +83,22 @@ class Postgres(Command):
|
|
|
86
83
|
return {}
|
|
87
84
|
|
|
88
85
|
def help(self, _: ReplState):
|
|
89
|
-
return f'
|
|
86
|
+
return f'<sql-statements> [&]\t run queries on Postgres databases'
|
|
90
87
|
|
|
91
88
|
class PostgresCommandHelper(click.Command):
|
|
92
89
|
def get_help(self, ctx: click.Context):
|
|
93
|
-
|
|
90
|
+
IntermediateCommand.intermediate_help(super().get_help(ctx), Postgres.COMMAND, Postgres().cmd_list(), show_cluster_help=True)
|
|
94
91
|
log('PG-Name: Kubernetes secret for Postgres credentials')
|
|
95
92
|
log(' e.g. stgawsscpsr-c3-c3-k8spg-cs-001')
|
|
96
93
|
log('Database: Postgres database name within a host')
|
|
97
|
-
log(' e.g. stgawsscpsr_c3_c3')
|
|
94
|
+
log(' e.g. stgawsscpsr_c3_c3')
|
|
95
|
+
|
|
96
|
+
# No action body, only for a help entry and auto-completion
|
|
97
|
+
class PostgresPg(Command):
|
|
98
|
+
COMMAND = 'pg'
|
|
99
|
+
|
|
100
|
+
def command(self):
|
|
101
|
+
return PostgresPg.COMMAND
|
|
102
|
+
|
|
103
|
+
def help(self, _: ReplState):
|
|
104
|
+
return f'pg <sql-statements>\t run queries on Postgres databases'
|
|
@@ -1,14 +1,37 @@
|
|
|
1
|
+
from datetime import datetime
|
|
1
2
|
import functools
|
|
2
3
|
import re
|
|
3
4
|
import subprocess
|
|
4
5
|
|
|
5
6
|
from adam.config import Config
|
|
7
|
+
from adam.repl_session import ReplSession
|
|
6
8
|
from adam.utils_k8s.kube_context import KubeContext
|
|
7
9
|
from adam.utils_k8s.pods import Pods
|
|
8
10
|
from adam.utils_k8s.secrets import Secrets
|
|
9
11
|
from adam.utils import log2
|
|
10
12
|
|
|
11
|
-
class
|
|
13
|
+
class PostgresContext:
|
|
14
|
+
def apply(namespace: str, path: str, arg: str = None) -> 'PostgresContext':
|
|
15
|
+
context = PostgresContext(namespace, path)
|
|
16
|
+
|
|
17
|
+
if arg:
|
|
18
|
+
if arg == '..':
|
|
19
|
+
if context.db:
|
|
20
|
+
context.db = None
|
|
21
|
+
else:
|
|
22
|
+
context.host = None
|
|
23
|
+
else:
|
|
24
|
+
tks = arg.split('@')
|
|
25
|
+
if not context.host:
|
|
26
|
+
context.host = tks[0]
|
|
27
|
+
else:
|
|
28
|
+
context.db = tks[0]
|
|
29
|
+
|
|
30
|
+
if not namespace and tks[1]:
|
|
31
|
+
context.namespace = tks[1]
|
|
32
|
+
|
|
33
|
+
return context
|
|
34
|
+
|
|
12
35
|
def __init__(self, ns: str, path: str):
|
|
13
36
|
self.namespace = ns
|
|
14
37
|
self.conn_details = None
|
|
@@ -25,29 +48,7 @@ class PostgresSession:
|
|
|
25
48
|
if len(tks) > 1:
|
|
26
49
|
self.db = tks[1]
|
|
27
50
|
|
|
28
|
-
def
|
|
29
|
-
if arg:
|
|
30
|
-
tks = arg.split('@')
|
|
31
|
-
if len(tks) > 1:
|
|
32
|
-
return tks[1]
|
|
33
|
-
|
|
34
|
-
return None
|
|
35
|
-
|
|
36
|
-
def directory(self, arg: str = None):
|
|
37
|
-
if arg:
|
|
38
|
-
if arg == '..':
|
|
39
|
-
if self.db:
|
|
40
|
-
self.db = None
|
|
41
|
-
else:
|
|
42
|
-
self.host = None
|
|
43
|
-
else:
|
|
44
|
-
tks = arg.split('@')
|
|
45
|
-
arg = tks[0]
|
|
46
|
-
if not self.host:
|
|
47
|
-
self.host = arg
|
|
48
|
-
else:
|
|
49
|
-
self.db = arg
|
|
50
|
-
|
|
51
|
+
def path(self):
|
|
51
52
|
if not self.host:
|
|
52
53
|
return None
|
|
53
54
|
|
|
@@ -58,7 +59,7 @@ class PostgresSession:
|
|
|
58
59
|
return f'{self.host}/{self.db}'
|
|
59
60
|
|
|
60
61
|
def hosts(ns: str):
|
|
61
|
-
return
|
|
62
|
+
return PostgresContext.hosts_for_namespace(ns)
|
|
62
63
|
|
|
63
64
|
@functools.lru_cache()
|
|
64
65
|
def hosts_for_namespace(ns: str):
|
|
@@ -132,44 +133,77 @@ class PostgresSession:
|
|
|
132
133
|
|
|
133
134
|
return dbs
|
|
134
135
|
|
|
135
|
-
def run_sql(self, sql: str, show_out = True):
|
|
136
|
-
db = self.db if self.db else
|
|
136
|
+
def run_sql(self, sql: str, show_out = True, background = False):
|
|
137
|
+
db = self.db if self.db else PostgresContext.default_db()
|
|
137
138
|
|
|
138
139
|
if KubeContext.in_cluster():
|
|
139
140
|
cmd1 = f'env PGPASSWORD={self.password()} psql -h {self.endpoint()} -p {self.port()} -U {self.username()} {db} --pset pager=off -c'
|
|
140
141
|
log2(f'{cmd1} "{sql}"')
|
|
141
142
|
# remove double quotes from the sql argument
|
|
142
143
|
cmd = cmd1.split(' ') + [sql]
|
|
143
|
-
|
|
144
|
+
|
|
145
|
+
r = subprocess.run(cmd, capture_output=not background, text=True)
|
|
144
146
|
if show_out:
|
|
145
147
|
log2(r.stdout)
|
|
146
148
|
log2(r.stderr)
|
|
147
149
|
|
|
148
150
|
return r
|
|
149
151
|
else:
|
|
150
|
-
|
|
151
|
-
|
|
152
|
+
pod_name, container_name = PostgresContext.pod_and_container(self.namespace)
|
|
153
|
+
if not pod_name:
|
|
154
|
+
return
|
|
155
|
+
|
|
156
|
+
# ns = self.namespace
|
|
157
|
+
# pod_name = Config().get('pg.agent.name', 'ops-pg-agent')
|
|
158
|
+
|
|
159
|
+
# if Config().get('pg.agent.just-in-time', False):
|
|
160
|
+
# if not PostgresContext.deploy_pg_agent(pod_name, ns):
|
|
161
|
+
# return
|
|
162
|
+
|
|
163
|
+
# real_pod_name = pod_name
|
|
164
|
+
# try:
|
|
165
|
+
# # try with dedicated pg agent pod name configured
|
|
166
|
+
# Pods.get(ns, pod_name)
|
|
167
|
+
# except:
|
|
168
|
+
# try:
|
|
169
|
+
# # try with the ops pod
|
|
170
|
+
# pod_name = Config().get('pod.name', 'ops')
|
|
171
|
+
# real_pod_name = Pods.get_with_selector(ns, label_selector = Config().get('pod.label-selector', 'run=ops')).metadata.name
|
|
172
|
+
# except:
|
|
173
|
+
# log2(f"Could not locate {pod_name} pod.")
|
|
174
|
+
# return None
|
|
175
|
+
|
|
176
|
+
cmd = f'psql -h {self.endpoint()} -p {self.port()} -U {self.username()} {db} --pset pager=off -c "{sql}"'
|
|
177
|
+
env_prefix = f'PGPASSWORD="{self.password()}"'
|
|
178
|
+
|
|
179
|
+
r = Pods.exec(pod_name, container_name, self.namespace, cmd, show_out=show_out, background=background, env_prefix=env_prefix)
|
|
180
|
+
if r and Config().get('repl.history.push-cat-remote-log-file', True):
|
|
181
|
+
if r.log_file and ReplSession().prompt_session:
|
|
182
|
+
ReplSession().prompt_session.history.append_string(f'@{r.pod} cat {r.log_file}')
|
|
183
|
+
|
|
184
|
+
return r
|
|
152
185
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
return
|
|
186
|
+
def pod_and_container(ns: str):
|
|
187
|
+
container_name = Config().get('pg.agent.name', 'ops-pg-agent')
|
|
156
188
|
|
|
157
|
-
|
|
189
|
+
if Config().get('pg.agent.just-in-time', False):
|
|
190
|
+
if not PostgresContext.deploy_pg_agent(container_name, ns):
|
|
191
|
+
return None
|
|
192
|
+
|
|
193
|
+
pod_name = container_name
|
|
194
|
+
try:
|
|
195
|
+
# try with dedicated pg agent pod name configured
|
|
196
|
+
Pods.get(ns, container_name)
|
|
197
|
+
except:
|
|
158
198
|
try:
|
|
159
|
-
# try with
|
|
160
|
-
|
|
199
|
+
# try with the ops pod
|
|
200
|
+
container_name = Config().get('pod.name', 'ops')
|
|
201
|
+
pod_name = Pods.get_with_selector(ns, label_selector = Config().get('pod.label-selector', 'run=ops')).metadata.name
|
|
161
202
|
except:
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
pod_name = Config().get('pod.name', 'ops')
|
|
165
|
-
real_pod_name = Pods.get_with_selector(ns, label_selector = Config().get('pod.label-selector', 'run=ops')).metadata.name
|
|
166
|
-
except:
|
|
167
|
-
log2(f"Could not locate {pod_name} pod.")
|
|
168
|
-
return None
|
|
169
|
-
|
|
170
|
-
cmd = f'PGPASSWORD="{self.password()}" psql -h {self.endpoint()} -p {self.port()} -U {self.username()} {db} --pset pager=off -c "{sql}"'
|
|
203
|
+
log2(f"Could not locate {container_name} pod.")
|
|
204
|
+
return None
|
|
171
205
|
|
|
172
|
-
|
|
206
|
+
return pod_name, container_name
|
|
173
207
|
|
|
174
208
|
def deploy_pg_agent(pod_name: str, ns: str) -> str:
|
|
175
209
|
image = Config().get('pg.agent.image', 'seanahnsf/kaqing')
|
|
@@ -4,7 +4,6 @@ from adam.repl_state import ReplState, RequiredState
|
|
|
4
4
|
|
|
5
5
|
class PostgresLs(Command):
|
|
6
6
|
COMMAND = 'pg ls'
|
|
7
|
-
reaper_login = None
|
|
8
7
|
|
|
9
8
|
# the singleton pattern
|
|
10
9
|
def __new__(cls, *args, **kwargs):
|
|
@@ -25,15 +24,12 @@ class PostgresLs(Command):
|
|
|
25
24
|
if not(args := self.args(cmd)):
|
|
26
25
|
return super().run(cmd, state)
|
|
27
26
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return state
|
|
31
|
-
|
|
32
|
-
state.device = ReplState.P
|
|
27
|
+
with self.validate(args, state) as (args, state):
|
|
28
|
+
state.device = ReplState.P
|
|
33
29
|
|
|
34
|
-
|
|
30
|
+
Ls().run('ls', state)
|
|
35
31
|
|
|
36
|
-
|
|
32
|
+
return state
|
|
37
33
|
|
|
38
34
|
def completion(self, state: ReplState):
|
|
39
35
|
if state.sts:
|
|
@@ -4,7 +4,6 @@ from adam.repl_state import ReplState, RequiredState
|
|
|
4
4
|
|
|
5
5
|
class PostgresPreview(Command):
|
|
6
6
|
COMMAND = 'pg preview'
|
|
7
|
-
reaper_login = None
|
|
8
7
|
|
|
9
8
|
# the singleton pattern
|
|
10
9
|
def __new__(cls, *args, **kwargs):
|
|
@@ -19,21 +18,18 @@ class PostgresPreview(Command):
|
|
|
19
18
|
return PostgresPreview.COMMAND
|
|
20
19
|
|
|
21
20
|
def required(self):
|
|
22
|
-
return RequiredState.
|
|
21
|
+
return RequiredState.PG_DATABASE
|
|
23
22
|
|
|
24
23
|
def run(self, cmd: str, state: ReplState):
|
|
25
24
|
if not(args := self.args(cmd)):
|
|
26
25
|
return super().run(cmd, state)
|
|
27
26
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return state
|
|
31
|
-
|
|
32
|
-
state.device = ReplState.P
|
|
27
|
+
with self.validate(args, state) as (args, state):
|
|
28
|
+
state.device = ReplState.P
|
|
33
29
|
|
|
34
|
-
|
|
30
|
+
PreviewTable().run(f'preview {" ".join(args)}', state)
|
|
35
31
|
|
|
36
|
-
|
|
32
|
+
return state
|
|
37
33
|
|
|
38
34
|
def completion(self, state: ReplState):
|
|
39
35
|
if state.sts:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from adam.commands.postgres.
|
|
1
|
+
from adam.commands.postgres.utils_postgres import pg_table_names
|
|
2
2
|
from adam.sql.sql_completer import SqlCompleter
|
|
3
3
|
|
|
4
4
|
def psql_completions(ns: str, pg_path: str):
|
|
@@ -7,4 +7,4 @@ def psql_completions(ns: str, pg_path: str):
|
|
|
7
7
|
'\d': None,
|
|
8
8
|
'\dt': None,
|
|
9
9
|
'\du': None
|
|
10
|
-
} | SqlCompleter
|
|
10
|
+
} | SqlCompleter(lambda: pg_table_names(ns, pg_path)).completions_for_nesting()
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
|
|
3
|
+
from adam.commands.postgres.postgres_context import PostgresContext
|
|
4
|
+
from adam.repl_state import ReplState
|
|
5
|
+
from adam.utils import log2, wait_log
|
|
6
|
+
from adam.utils_k8s.pods import Pods
|
|
7
|
+
|
|
8
|
+
TestPG = [False]
|
|
9
|
+
|
|
10
|
+
@functools.lru_cache()
|
|
11
|
+
def pg_database_names(ns: str, pg_path: str):
|
|
12
|
+
if TestPG[0]:
|
|
13
|
+
return ['azops88_c3ai_c3']
|
|
14
|
+
|
|
15
|
+
wait_log('Inspecting Postgres Databases...')
|
|
16
|
+
|
|
17
|
+
pg = PostgresContext.apply(ns, pg_path)
|
|
18
|
+
return [db['name'] for db in pg.databases() if db['owner'] == PostgresContext.default_owner()]
|
|
19
|
+
|
|
20
|
+
@functools.lru_cache()
|
|
21
|
+
def pg_table_names(ns: str, pg_path: str):
|
|
22
|
+
if TestPG[0]:
|
|
23
|
+
return ['C3_2_XYZ1']
|
|
24
|
+
|
|
25
|
+
wait_log('Inspecting Postgres Database...')
|
|
26
|
+
return [table['name'] for table in pg_tables(ns, pg_path) if table['schema'] == PostgresContext.default_schema()]
|
|
27
|
+
|
|
28
|
+
def pg_tables(ns: str, pg_path: str):
|
|
29
|
+
pg = PostgresContext.apply(ns, pg_path)
|
|
30
|
+
if pg.db:
|
|
31
|
+
return pg.tables()
|
|
32
|
+
|
|
33
|
+
return []
|
|
34
|
+
|
|
35
|
+
class PostgresPodService:
|
|
36
|
+
def __init__(self, handler: 'PostgresExecHandler'):
|
|
37
|
+
self.handler = handler
|
|
38
|
+
|
|
39
|
+
def exec(self, command: str, show_out=True):
|
|
40
|
+
state = self.handler.state
|
|
41
|
+
|
|
42
|
+
pod, container = PostgresContext.pod_and_container(state.namespace)
|
|
43
|
+
if not pod:
|
|
44
|
+
log2('Cannot locate postgres agent or ops pod.')
|
|
45
|
+
return state
|
|
46
|
+
|
|
47
|
+
return Pods.exec(pod, container, state.namespace, command, show_out=show_out)
|
|
48
|
+
|
|
49
|
+
def sql(self, args: list[str], background=False):
|
|
50
|
+
state = self.handler.state
|
|
51
|
+
|
|
52
|
+
PostgresContext.apply(state.namespace, state.pg_path).run_sql(' '.join(args), background=background)
|
|
53
|
+
|
|
54
|
+
class PostgresExecHandler:
|
|
55
|
+
def __init__(self, state: ReplState, background=False):
|
|
56
|
+
self.state = state
|
|
57
|
+
self.background = background
|
|
58
|
+
|
|
59
|
+
def __enter__(self):
|
|
60
|
+
return PostgresPodService(self)
|
|
61
|
+
|
|
62
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
63
|
+
return False
|
|
64
|
+
|
|
65
|
+
def postgres(state: ReplState, background=False):
|
|
66
|
+
return PostgresExecHandler(state, background=background)
|
adam/commands/preview_table.py
CHANGED
|
@@ -1,13 +1,6 @@
|
|
|
1
|
-
import functools
|
|
2
|
-
|
|
3
1
|
from adam.commands.command import Command
|
|
4
|
-
from adam.commands.
|
|
5
|
-
from adam.commands.cql.cql_utils import run_cql, table_names, tables
|
|
6
|
-
from adam.commands.postgres.postgres_session import PostgresSession
|
|
7
|
-
from adam.commands.postgres.psql_table_completer import PsqlTableNameCompleter
|
|
8
|
-
from adam.config import Config
|
|
2
|
+
from adam.commands.devices.devices import Devices
|
|
9
3
|
from adam.repl_state import ReplState, RequiredState
|
|
10
|
-
from adam.utils import lines_to_tabular, log, log2
|
|
11
4
|
|
|
12
5
|
class PreviewTable(Command):
|
|
13
6
|
COMMAND = 'preview'
|
|
@@ -25,66 +18,20 @@ class PreviewTable(Command):
|
|
|
25
18
|
return PreviewTable.COMMAND
|
|
26
19
|
|
|
27
20
|
def required(self):
|
|
28
|
-
return RequiredState.CLUSTER_OR_POD
|
|
21
|
+
return [RequiredState.CLUSTER_OR_POD, RequiredState.PG_DATABASE, ReplState.L]
|
|
29
22
|
|
|
30
23
|
def run(self, cmd: str, state: ReplState):
|
|
31
24
|
if not(args := self.args(cmd)):
|
|
32
25
|
return super().run(cmd, state)
|
|
33
26
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if not self.validate_state(state, RequiredState.PG_DATABASE):
|
|
37
|
-
return state
|
|
38
|
-
else:
|
|
39
|
-
if not self.validate_state(state):
|
|
40
|
-
return state
|
|
41
|
-
|
|
42
|
-
if not args:
|
|
43
|
-
def show_tables():
|
|
44
|
-
if state.device == ReplState.P:
|
|
45
|
-
pg = PostgresSession(state.namespace, state.pg_path)
|
|
46
|
-
lines = [db["name"] for db in pg.tables() if db["schema"] == PostgresSession.default_schema()]
|
|
47
|
-
log(lines_to_tabular(lines, separator=','))
|
|
48
|
-
else:
|
|
49
|
-
run_cql(state, f'describe tables', show_out=True)
|
|
50
|
-
|
|
51
|
-
if state.in_repl:
|
|
52
|
-
log2('Table is required.')
|
|
53
|
-
log2()
|
|
54
|
-
log2('Tables:')
|
|
55
|
-
show_tables()
|
|
56
|
-
else:
|
|
57
|
-
log2('* Table is missing.')
|
|
58
|
-
show_tables()
|
|
59
|
-
|
|
60
|
-
Command.display_help()
|
|
61
|
-
|
|
62
|
-
return 'command-missing'
|
|
27
|
+
with self.validate(args, state) as (args, state):
|
|
28
|
+
Devices.device(state).preview(args[0] if args else None, state)
|
|
63
29
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
rows = Config().get('preview.rows', 10)
|
|
67
|
-
if state.device == ReplState.P:
|
|
68
|
-
PostgresSession(state.namespace, state.pg_path).run_sql(f'select * from {table} limit {rows}')
|
|
69
|
-
else:
|
|
70
|
-
run_cql(state, f'select * from {table} limit {rows}', show_out=True, use_single_quotes=True)
|
|
71
|
-
|
|
72
|
-
return state
|
|
73
|
-
|
|
74
|
-
def completion(self, state: ReplState):
|
|
75
|
-
if state.device == ReplState.P:
|
|
76
|
-
return {PreviewTable.COMMAND: PsqlTableNameCompleter(state.namespace, state.pg_path)}
|
|
77
|
-
elif state.sts:
|
|
78
|
-
return {PreviewTable.COMMAND: CqlTableNameCompleter(table_names(state))}
|
|
30
|
+
return state
|
|
79
31
|
|
|
32
|
+
def completion(self, _: ReplState):
|
|
33
|
+
# taken care of by the sql completer
|
|
80
34
|
return {}
|
|
81
35
|
|
|
82
36
|
def help(self, _: ReplState):
|
|
83
|
-
return f'{PreviewTable.COMMAND} TABLE\t preview table'
|
|
84
|
-
|
|
85
|
-
@functools.lru_cache()
|
|
86
|
-
def cql_tables(state: ReplState):
|
|
87
|
-
if state.pod:
|
|
88
|
-
return tables(state)
|
|
89
|
-
|
|
90
|
-
return tables(state, on_any=True)
|
|
37
|
+
return f'{PreviewTable.COMMAND} TABLE\t preview table'
|
adam/commands/pwd.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from adam.app_session import AppSession
|
|
2
2
|
from adam.commands.command import Command
|
|
3
|
-
from adam.commands.
|
|
3
|
+
from adam.commands.devices.devices import Devices
|
|
4
4
|
from adam.repl_state import ReplState
|
|
5
5
|
from adam.utils import lines_to_tabular, log
|
|
6
6
|
|
|
@@ -23,52 +23,22 @@ class Pwd(Command):
|
|
|
23
23
|
if not(args := self.args(cmd)):
|
|
24
24
|
return super().run(cmd, state)
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
pg = PostgresSession(state.namespace, state.pg_path)
|
|
33
|
-
|
|
34
|
-
if pg.host:
|
|
35
|
-
words.append(f'host/{pg.host}')
|
|
36
|
-
if pg.db:
|
|
37
|
-
words.append(f'database/{pg.db}')
|
|
38
|
-
elif device == ReplState.A:
|
|
39
|
-
if state.app_env:
|
|
40
|
-
words.append(f'env/{state.app_env}')
|
|
41
|
-
if state.app_app:
|
|
42
|
-
words.append(f'app/{state.app_app}')
|
|
43
|
-
elif device == ReplState.L:
|
|
26
|
+
with self.validate(args, state) as (_, state):
|
|
27
|
+
host = "unknown"
|
|
28
|
+
try:
|
|
29
|
+
app_session: AppSession = AppSession.create('c3', 'c3')
|
|
30
|
+
host = app_session.host
|
|
31
|
+
except:
|
|
44
32
|
pass
|
|
45
|
-
else:
|
|
46
|
-
if state.sts:
|
|
47
|
-
words.append(f'sts/{state.sts}')
|
|
48
|
-
if state.pod:
|
|
49
|
-
words.append(f'pod/{state.pod}')
|
|
50
|
-
|
|
51
|
-
return '\t'.join([f'{device}:>'] + (words if words else ['/']))
|
|
52
|
-
|
|
53
|
-
host = "unknown"
|
|
54
|
-
try:
|
|
55
|
-
app_session: AppSession = AppSession.create('c3', 'c3')
|
|
56
|
-
host = app_session.host
|
|
57
|
-
except:
|
|
58
|
-
pass
|
|
59
33
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
f'HOST\t{host}',
|
|
67
|
-
f'NAMESPACE\t{state.namespace if state.namespace else "/"}',
|
|
68
|
-
], 'DEVICE\tLOCATION', separator='\t'))
|
|
69
|
-
log()
|
|
34
|
+
log(lines_to_tabular([device.pwd(state) for device in Devices.all()] + [
|
|
35
|
+
f'',
|
|
36
|
+
f'HOST\t{host}',
|
|
37
|
+
f'NAMESPACE\t{state.namespace if state.namespace else "/"}',
|
|
38
|
+
], 'DEVICE\tLOCATION', separator='\t'))
|
|
39
|
+
log()
|
|
70
40
|
|
|
71
|
-
|
|
41
|
+
return state
|
|
72
42
|
|
|
73
43
|
def completion(self, state: ReplState):
|
|
74
44
|
return super().completion(state)
|
adam/commands/reaper/reaper.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import click
|
|
2
2
|
|
|
3
|
-
from adam.commands.
|
|
3
|
+
from adam.commands.intermediate_command import IntermediateCommand
|
|
4
4
|
from .reaper_forward import ReaperForward
|
|
5
5
|
from .reaper_forward_stop import ReaperForwardStop
|
|
6
6
|
from .reaper_restart import ReaperRestart
|
|
@@ -12,11 +12,9 @@ from .reaper_schedule_start import ReaperScheduleStart
|
|
|
12
12
|
from .reaper_schedule_stop import ReaperScheduleStop
|
|
13
13
|
from .reaper_schedules import ReaperSchedules
|
|
14
14
|
from .reaper_status import ReaperStatus
|
|
15
|
-
from adam.repl_state import ReplState, RequiredState
|
|
16
15
|
|
|
17
|
-
class Reaper(
|
|
16
|
+
class Reaper(IntermediateCommand):
|
|
18
17
|
COMMAND = 'reaper'
|
|
19
|
-
reaper_login = None
|
|
20
18
|
|
|
21
19
|
# the singleton pattern
|
|
22
20
|
def __new__(cls, *args, **kwargs):
|
|
@@ -24,32 +22,14 @@ class Reaper(Command):
|
|
|
24
22
|
|
|
25
23
|
return cls.instance
|
|
26
24
|
|
|
27
|
-
def __init__(self, successor: Command=None):
|
|
28
|
-
super().__init__(successor)
|
|
29
|
-
|
|
30
25
|
def command(self):
|
|
31
26
|
return Reaper.COMMAND
|
|
32
27
|
|
|
33
|
-
def
|
|
34
|
-
return RequiredState.CLUSTER
|
|
35
|
-
|
|
36
|
-
def run(self, cmd: str, state: ReplState):
|
|
37
|
-
if not(args := self.args(cmd)):
|
|
38
|
-
return super().run(cmd, state)
|
|
39
|
-
|
|
40
|
-
return super().intermediate_run(cmd, state, args, Reaper.cmd_list())
|
|
41
|
-
|
|
42
|
-
def cmd_list():
|
|
28
|
+
def cmd_list(self):
|
|
43
29
|
return [ReaperSchedules(), ReaperScheduleStop(), ReaperScheduleActivate(), ReaperScheduleStart(),
|
|
44
30
|
ReaperForwardStop(), ReaperForward(), ReaperRunAbort(), ReaperRunsAbort(), ReaperRestart(),
|
|
45
31
|
ReaperRuns(), ReaperStatus()]
|
|
46
32
|
|
|
47
|
-
def completion(self, state: ReplState):
|
|
48
|
-
if state.sts:
|
|
49
|
-
return super().completion(state)
|
|
50
|
-
|
|
51
|
-
return {}
|
|
52
|
-
|
|
53
33
|
class ReaperCommandHelper(click.Command):
|
|
54
34
|
def get_help(self, ctx: click.Context):
|
|
55
|
-
|
|
35
|
+
IntermediateCommand.intermediate_help(super().get_help(ctx), Reaper.COMMAND, Reaper().cmd_list(), show_cluster_help=True)
|