kaqing 2.0.110__py3-none-any.whl → 2.0.214__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 +19 -19
- 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/app/app.py +38 -0
- adam/commands/{app_ping.py → app/app_ping.py} +7 -13
- adam/commands/{login.py → app/login.py} +22 -24
- 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/show_login.py +56 -0
- adam/commands/app/utils_app.py +106 -0
- adam/commands/audit/audit.py +22 -40
- adam/commands/audit/audit_repair_tables.py +15 -19
- adam/commands/audit/audit_run.py +15 -22
- adam/commands/audit/completions_l.py +15 -0
- adam/commands/audit/show_last10.py +4 -18
- 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/cassandra/__init__.py +0 -0
- adam/commands/cassandra/download_cassandra_log.py +45 -0
- adam/commands/{restart.py → cassandra/restart_cluster.py} +12 -26
- adam/commands/cassandra/restart_node.py +51 -0
- adam/commands/cassandra/restart_nodes.py +47 -0
- adam/commands/{rollout.py → cassandra/rollout.py} +20 -25
- adam/commands/cassandra/show_cassandra_repairs.py +37 -0
- adam/commands/cassandra/show_cassandra_status.py +117 -0
- adam/commands/{show → cassandra}/show_cassandra_version.py +5 -18
- adam/commands/cassandra/show_processes.py +50 -0
- adam/commands/cassandra/show_storage.py +44 -0
- adam/commands/{watch.py → cassandra/watch.py} +26 -29
- adam/commands/cli/__init__.py +0 -0
- adam/commands/{cli_commands.py → cli/cli_commands.py} +8 -4
- adam/commands/cli/clipboard_copy.py +86 -0
- adam/commands/cli/show_cli_commands.py +56 -0
- adam/commands/code.py +57 -0
- adam/commands/command.py +211 -40
- adam/commands/commands_utils.py +20 -27
- adam/commands/config/__init__.py +0 -0
- adam/commands/{param_get.py → config/param_get.py} +11 -14
- adam/commands/{param_set.py → config/param_set.py} +8 -12
- adam/commands/{show → config}/show_params.py +2 -5
- adam/commands/cql/alter_tables.py +66 -0
- adam/commands/cql/completions_c.py +29 -0
- adam/commands/cql/cqlsh.py +10 -32
- adam/commands/cql/utils_cql.py +306 -0
- adam/commands/debug/__init__.py +0 -0
- adam/commands/debug/debug.py +22 -0
- adam/commands/debug/debug_completes.py +35 -0
- adam/commands/debug/debug_timings.py +35 -0
- adam/commands/debug/show_offloaded_completes.py +45 -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 +149 -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 +87 -0
- adam/commands/devices/device_postgres.py +160 -0
- adam/commands/devices/devices.py +25 -0
- adam/commands/diag/__init__.py +0 -0
- adam/commands/{check.py → diag/check.py} +16 -25
- adam/commands/diag/generate_report.py +52 -0
- adam/commands/diag/issues.py +43 -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/completions_x.py +11 -0
- adam/commands/export/download_export_session.py +40 -0
- adam/commands/export/drop_export_database.py +39 -0
- adam/commands/export/drop_export_databases.py +37 -0
- adam/commands/export/export.py +37 -0
- adam/commands/export/export_databases.py +251 -0
- adam/commands/export/export_select.py +34 -0
- adam/commands/export/export_sessions.py +210 -0
- adam/commands/export/export_use.py +49 -0
- adam/commands/export/export_x_select.py +48 -0
- adam/commands/export/exporter.py +419 -0
- adam/commands/export/import_files.py +44 -0
- adam/commands/export/import_session.py +40 -0
- adam/commands/export/importer.py +81 -0
- adam/commands/export/importer_athena.py +157 -0
- adam/commands/export/importer_sqlite.py +78 -0
- adam/commands/export/show_column_counts.py +45 -0
- adam/commands/export/show_export_databases.py +39 -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 +366 -0
- adam/commands/fs/__init__.py +0 -0
- adam/commands/fs/cat.py +36 -0
- adam/commands/fs/cat_local.py +42 -0
- adam/commands/fs/cd.py +41 -0
- adam/commands/fs/download_file.py +47 -0
- adam/commands/fs/find_files.py +51 -0
- adam/commands/fs/find_processes.py +76 -0
- adam/commands/fs/head.py +36 -0
- adam/commands/fs/ls.py +41 -0
- adam/commands/fs/ls_local.py +40 -0
- adam/commands/fs/pwd.py +45 -0
- adam/commands/fs/rm.py +18 -0
- adam/commands/fs/rm_downloads.py +39 -0
- adam/commands/fs/rm_logs.py +38 -0
- adam/commands/{shell.py → fs/shell.py} +12 -4
- adam/commands/{show → fs}/show_adam.py +3 -3
- adam/commands/{show → fs}/show_host.py +1 -1
- adam/commands/help.py +5 -3
- adam/commands/intermediate_command.py +52 -0
- adam/commands/kubectl.py +38 -0
- adam/commands/medusa/medusa.py +4 -22
- adam/commands/medusa/medusa_backup.py +20 -27
- adam/commands/medusa/medusa_restore.py +35 -48
- adam/commands/medusa/medusa_show_backupjobs.py +16 -18
- adam/commands/medusa/medusa_show_restorejobs.py +13 -18
- adam/commands/medusa/utils_medusa.py +15 -0
- adam/commands/nodetool/__init__.py +0 -0
- adam/commands/{nodetool.py → nodetool/nodetool.py} +9 -20
- adam/commands/postgres/completions_p.py +22 -0
- adam/commands/postgres/postgres.py +47 -55
- adam/commands/postgres/postgres_databases.py +269 -0
- adam/commands/postgres/postgres_ls.py +5 -9
- adam/commands/postgres/postgres_preview.py +5 -9
- adam/commands/postgres/utils_postgres.py +80 -0
- adam/commands/preview_table.py +8 -44
- 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 +14 -33
- adam/commands/reaper/reaper_schedule_start.py +9 -33
- adam/commands/reaper/reaper_schedule_stop.py +9 -33
- adam/commands/reaper/reaper_schedules.py +4 -14
- adam/commands/reaper/reaper_status.py +8 -16
- adam/commands/reaper/utils_reaper.py +203 -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 -40
- adam/commands/repair/repair_stop.py +5 -12
- adam/commands/show.py +40 -0
- adam/config.py +5 -15
- adam/embedded_params.py +1 -1
- adam/log.py +4 -4
- adam/repl.py +83 -116
- adam/repl_commands.py +86 -45
- adam/repl_session.py +9 -1
- adam/repl_state.py +176 -40
- adam/sql/async_executor.py +62 -0
- adam/sql/lark_completer.py +286 -0
- adam/sql/lark_parser.py +604 -0
- adam/sql/qingl.lark +1076 -0
- 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 +4 -9
- adam/sso/idp.py +9 -12
- adam/utils.py +670 -31
- adam/utils_athena.py +145 -0
- adam/utils_audits.py +12 -103
- adam/utils_issues.py +32 -0
- adam/utils_k8s/app_clusters.py +35 -0
- adam/utils_k8s/app_pods.py +41 -0
- adam/utils_k8s/cassandra_clusters.py +35 -20
- adam/utils_k8s/cassandra_nodes.py +15 -6
- 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 +96 -0
- adam/utils_k8s/kube_context.py +3 -6
- adam/{pod_exec_result.py → utils_k8s/pod_exec_result.py} +13 -4
- adam/utils_k8s/pods.py +159 -89
- 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 +6 -14
- adam/utils_local.py +80 -0
- adam/utils_net.py +4 -4
- adam/utils_repl/__init__.py +0 -0
- adam/utils_repl/appendable_completer.py +6 -0
- adam/utils_repl/automata_completer.py +48 -0
- adam/utils_repl/repl_completer.py +93 -0
- adam/utils_repl/state_machine.py +173 -0
- adam/utils_sqlite.py +132 -0
- adam/version.py +1 -1
- {kaqing-2.0.110.dist-info → kaqing-2.0.214.dist-info}/METADATA +1 -1
- kaqing-2.0.214.dist-info/RECORD +272 -0
- kaqing-2.0.214.dist-info/top_level.txt +2 -0
- teddy/__init__.py +0 -0
- teddy/lark_parser.py +436 -0
- teddy/lark_parser2.py +618 -0
- adam/commands/alter_tables.py +0 -81
- adam/commands/app.py +0 -67
- adam/commands/bash.py +0 -150
- adam/commands/cd.py +0 -125
- adam/commands/cp.py +0 -95
- adam/commands/cql/cql_completions.py +0 -15
- adam/commands/cql/cql_utils.py +0 -112
- adam/commands/devices.py +0 -118
- adam/commands/issues.py +0 -75
- adam/commands/logs.py +0 -40
- adam/commands/ls.py +0 -146
- adam/commands/postgres/postgres_context.py +0 -239
- adam/commands/postgres/postgres_utils.py +0 -31
- adam/commands/postgres/psql_completions.py +0 -10
- adam/commands/pwd.py +0 -77
- adam/commands/reaper/reaper_session.py +0 -159
- adam/commands/report.py +0 -63
- adam/commands/show/show.py +0 -54
- adam/commands/show/show_app_actions.py +0 -56
- adam/commands/show/show_cassandra_status.py +0 -128
- adam/commands/show/show_commands.py +0 -61
- adam/commands/show/show_login.py +0 -63
- adam/commands/show/show_processes.py +0 -53
- adam/commands/show/show_repairs.py +0 -47
- adam/commands/show/show_storage.py +0 -52
- kaqing-2.0.110.dist-info/RECORD +0 -187
- kaqing-2.0.110.dist-info/top_level.txt +0 -1
- /adam/commands/{show → app}/__init__.py +0 -0
- /adam/commands/{nodetool_commands.py → nodetool/nodetool_commands.py} +0 -0
- {kaqing-2.0.110.dist-info → kaqing-2.0.214.dist-info}/WHEEL +0 -0
- {kaqing-2.0.110.dist-info → kaqing-2.0.214.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
import re
|
|
3
|
+
import subprocess
|
|
4
|
+
|
|
5
|
+
from adam.config import Config
|
|
6
|
+
from adam.repl_session import ReplSession
|
|
7
|
+
from adam.repl_state import ReplState
|
|
8
|
+
from adam.utils_k8s.kube_context import KubeContext
|
|
9
|
+
from adam.utils_k8s.pods import Pods
|
|
10
|
+
from adam.utils_k8s.secrets import Secrets
|
|
11
|
+
from adam.utils import log2, log_exc
|
|
12
|
+
|
|
13
|
+
class ConnectionDetails:
|
|
14
|
+
def __init__(self, state: ReplState, namespace: str, host: str):
|
|
15
|
+
self.state = state
|
|
16
|
+
self.namespace = namespace
|
|
17
|
+
self.host = host
|
|
18
|
+
|
|
19
|
+
def endpoint(self):
|
|
20
|
+
return PostgresDatabases._connection_property(self.state, 'pg.secret.endpoint-key', 'postgres-db-endpoint', host=self.host)
|
|
21
|
+
|
|
22
|
+
def port(self):
|
|
23
|
+
return PostgresDatabases._connection_property(self.state, 'pg.secret.port-key', 'postgres-db-port', host=self.host)
|
|
24
|
+
|
|
25
|
+
def username(self):
|
|
26
|
+
return PostgresDatabases._connection_property(self.state, 'pg.secret.username-key', 'postgres-admin-username', host=self.host)
|
|
27
|
+
|
|
28
|
+
def password(self):
|
|
29
|
+
return PostgresDatabases._connection_property(self.state, 'pg.secret.password-key', 'postgres-admin-password', host=self.host)
|
|
30
|
+
|
|
31
|
+
class PostgresDatabases:
|
|
32
|
+
def hosts(state: ReplState, namespace: str = None):
|
|
33
|
+
if not namespace:
|
|
34
|
+
namespace = state.namespace
|
|
35
|
+
|
|
36
|
+
return [ConnectionDetails(state, namespace, host) for host in PostgresDatabases.host_names(namespace)]
|
|
37
|
+
|
|
38
|
+
@functools.lru_cache()
|
|
39
|
+
def host_names(namespace: str):
|
|
40
|
+
ss = Secrets.list_secrets(namespace, name_pattern=Config().get('pg.name-pattern', '^{namespace}.*k8spg.*'))
|
|
41
|
+
|
|
42
|
+
def excludes(name: str):
|
|
43
|
+
exs = Config().get('pg.excludes', '.helm., -admin-secret')
|
|
44
|
+
if exs:
|
|
45
|
+
for ex in exs.split(','):
|
|
46
|
+
if ex.strip(' ') in name:
|
|
47
|
+
return True
|
|
48
|
+
|
|
49
|
+
return False
|
|
50
|
+
|
|
51
|
+
return [s for s in ss if not excludes(s)]
|
|
52
|
+
|
|
53
|
+
def databases(state: ReplState, default_owner = False):
|
|
54
|
+
dbs = []
|
|
55
|
+
# List of databases
|
|
56
|
+
# Name | Owner | Encoding | Collate | Ctype | ICU Locale | Locale Provider | Access privileges
|
|
57
|
+
# ---------------------------------------+----------+----------+-------------+-------------+------------+-----------------+-----------------------
|
|
58
|
+
# postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc |
|
|
59
|
+
# stgawsscpsr_c3_c3 | postgres | UTF8 | C | C | | libc |
|
|
60
|
+
# template1 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc | =c/postgres +
|
|
61
|
+
# | | | | | | | postgres=CTc/postgres
|
|
62
|
+
# (48 rows)
|
|
63
|
+
if r := PostgresDatabases.run_sql(state, '\l', show_out=False):
|
|
64
|
+
s = 0
|
|
65
|
+
for line in r.stdout.split('\n'):
|
|
66
|
+
line: str = line.strip(' \r')
|
|
67
|
+
if s == 0:
|
|
68
|
+
if 'List of databases' in line:
|
|
69
|
+
s = 1
|
|
70
|
+
elif s == 1:
|
|
71
|
+
if 'Name' in line and 'Owner' in line and 'Encoding' in line:
|
|
72
|
+
s = 2
|
|
73
|
+
elif s == 2:
|
|
74
|
+
if line.startswith('---------'):
|
|
75
|
+
s = 3
|
|
76
|
+
elif s == 3:
|
|
77
|
+
groups = re.match(r'^\s*(\S*)\s*\|\s*(\S*)\s*\|.*', line)
|
|
78
|
+
if groups and groups[1] != '|':
|
|
79
|
+
dbs.append({'name': groups[1], 'owner': groups[2]})
|
|
80
|
+
|
|
81
|
+
if default_owner:
|
|
82
|
+
dbs = [db for db in dbs if db['owner'] == PostgresDatabases.default_owner()]
|
|
83
|
+
|
|
84
|
+
return dbs
|
|
85
|
+
|
|
86
|
+
def tables(state: ReplState, default_schema = False):
|
|
87
|
+
dbs = []
|
|
88
|
+
# List of relations
|
|
89
|
+
# Schema | Name | Type | Owner
|
|
90
|
+
# ----------+------------------------------------------------------------+-------+---------------
|
|
91
|
+
# postgres | c3_2_admin_aclpriv | table | postgres
|
|
92
|
+
# postgres | c3_2_admin_aclpriv_a | table | postgres
|
|
93
|
+
if r := PostgresDatabases.run_sql(state, '\dt', show_out=False):
|
|
94
|
+
s = 0
|
|
95
|
+
for line in r.stdout.split('\n'):
|
|
96
|
+
line: str = line.strip(' \r')
|
|
97
|
+
if s == 0:
|
|
98
|
+
if 'List of relations' in line:
|
|
99
|
+
s = 1
|
|
100
|
+
elif s == 1:
|
|
101
|
+
if 'Schema' in line and 'Name' in line and 'Type' in line:
|
|
102
|
+
s = 2
|
|
103
|
+
elif s == 2:
|
|
104
|
+
if line.startswith('---------'):
|
|
105
|
+
s = 3
|
|
106
|
+
elif s == 3:
|
|
107
|
+
groups = re.match(r'^\s*(\S*)\s*\|\s*(\S*)\s*\|.*', line)
|
|
108
|
+
if groups and groups[1] != '|':
|
|
109
|
+
dbs.append({'schema': groups[1], 'name': groups[2]})
|
|
110
|
+
|
|
111
|
+
if default_schema:
|
|
112
|
+
dbs = [db for db in dbs if db["schema"] == PostgresDatabases.default_schema()]
|
|
113
|
+
|
|
114
|
+
return dbs
|
|
115
|
+
|
|
116
|
+
def run_sql(state: ReplState, sql: str, database: str = None, show_out = True, backgrounded = False):
|
|
117
|
+
if not database:
|
|
118
|
+
database = PostgresDatabases.database(state)
|
|
119
|
+
if not database:
|
|
120
|
+
database = PostgresDatabases.default_db()
|
|
121
|
+
|
|
122
|
+
username = PostgresDatabases.username(state)
|
|
123
|
+
password = PostgresDatabases.password(state)
|
|
124
|
+
endpoint = PostgresDatabases.endpoint(state)
|
|
125
|
+
|
|
126
|
+
if KubeContext.in_cluster():
|
|
127
|
+
cmd1 = f'env PGPASSWORD={password} psql -h {endpoint} -p {PostgresDatabases.port()} -U {username} {database} --pset pager=off -c'
|
|
128
|
+
log2(f'{cmd1} "{sql}"')
|
|
129
|
+
# remove double quotes from the sql argument
|
|
130
|
+
cmd = cmd1.split(' ') + [sql]
|
|
131
|
+
|
|
132
|
+
r = subprocess.run(cmd, capture_output=not backgrounded, text=True)
|
|
133
|
+
if show_out:
|
|
134
|
+
log2(r.stdout)
|
|
135
|
+
log2(r.stderr)
|
|
136
|
+
|
|
137
|
+
return r
|
|
138
|
+
else:
|
|
139
|
+
pod_name, container_name = PostgresDatabases.pod_and_container(state.namespace)
|
|
140
|
+
if not pod_name:
|
|
141
|
+
return
|
|
142
|
+
|
|
143
|
+
cmd = f'psql -h {endpoint} -p {PostgresDatabases.port(state)} -U {username} {database} --pset pager=off -c "{sql}"'
|
|
144
|
+
env_prefix = f'PGPASSWORD="{password}"'
|
|
145
|
+
|
|
146
|
+
r = Pods.exec(pod_name, container_name, state.namespace, cmd, show_out=show_out, backgrounded=backgrounded, env_prefix=env_prefix)
|
|
147
|
+
if r and r.log_file:
|
|
148
|
+
ReplSession().append_history(f':cat {r.log_file}')
|
|
149
|
+
|
|
150
|
+
return r
|
|
151
|
+
|
|
152
|
+
@functools.lru_cache()
|
|
153
|
+
def pod_and_container(namespace: str):
|
|
154
|
+
container_name = Config().get('pg.agent.name', 'ops-pg-agent')
|
|
155
|
+
|
|
156
|
+
if Config().get('pg.agent.just-in-time', False):
|
|
157
|
+
if not PostgresDatabases.deploy_pg_agent(container_name, namespace):
|
|
158
|
+
return None
|
|
159
|
+
|
|
160
|
+
pod_name = container_name
|
|
161
|
+
try:
|
|
162
|
+
# try with dedicated pg agent pod name configured
|
|
163
|
+
Pods.get(namespace, container_name)
|
|
164
|
+
except:
|
|
165
|
+
try:
|
|
166
|
+
# try with the ops pod
|
|
167
|
+
container_name = Config().get('pod.name', 'ops')
|
|
168
|
+
pod_name = Pods.get_with_selector(namespace, label_selector = Config().get('pod.label-selector', 'run=ops')).metadata.name
|
|
169
|
+
except:
|
|
170
|
+
log2(f"Could not locate {container_name} pod.")
|
|
171
|
+
return None
|
|
172
|
+
|
|
173
|
+
return pod_name, container_name
|
|
174
|
+
|
|
175
|
+
def deploy_pg_agent(pod_name: str, namespace: str) -> str:
|
|
176
|
+
image = Config().get('pg.agent.image', 'seanahnsf/kaqing')
|
|
177
|
+
timeout = Config().get('pg.agent.timeout', 3600)
|
|
178
|
+
try:
|
|
179
|
+
Pods.create(namespace, pod_name, image, ['sleep', f'{timeout}'], env={'NAMESPACE': namespace}, sa_name='c3')
|
|
180
|
+
except Exception as e:
|
|
181
|
+
if e.status == 409:
|
|
182
|
+
if Pods.completed(namespace, pod_name):
|
|
183
|
+
with log_exc(lambda e2: "Exception when calling BatchV1Api->create_pod: %s\n" % e2):
|
|
184
|
+
Pods.delete(pod_name, namespace)
|
|
185
|
+
Pods.create(namespace, pod_name, image, ['sleep', f'{timeout}'], env={'NAMESPACE': namespace}, sa_name='c3')
|
|
186
|
+
|
|
187
|
+
return
|
|
188
|
+
else:
|
|
189
|
+
log2("Exception when calling BatchV1Api->create_pod: %s\n" % e)
|
|
190
|
+
|
|
191
|
+
return
|
|
192
|
+
|
|
193
|
+
Pods.wait_for_running(namespace, pod_name)
|
|
194
|
+
|
|
195
|
+
return pod_name
|
|
196
|
+
|
|
197
|
+
def undeploy_pg_agent(pod_name: str, namespace: str):
|
|
198
|
+
Pods.delete(pod_name, namespace, grace_period_seconds=0)
|
|
199
|
+
|
|
200
|
+
def endpoint(state: ReplState):
|
|
201
|
+
return PostgresDatabases._connection_property(state, 'pg.secret.endpoint-key', 'postgres-db-endpoint')
|
|
202
|
+
|
|
203
|
+
def port(state: ReplState):
|
|
204
|
+
return PostgresDatabases._connection_property(state, 'pg.secret.port-key', 'postgres-db-port')
|
|
205
|
+
|
|
206
|
+
def username(state: ReplState):
|
|
207
|
+
return PostgresDatabases._connection_property(state, 'pg.secret.username-key', 'postgres-admin-username')
|
|
208
|
+
|
|
209
|
+
def password(state: ReplState):
|
|
210
|
+
return PostgresDatabases._connection_property(state, 'pg.secret.password-key', 'postgres-admin-password')
|
|
211
|
+
|
|
212
|
+
def _connection_property(state: ReplState, config_key: str, default: str, host: str = None, database: str = None):
|
|
213
|
+
with pg_path(state, host=host, database=database) as (host, _):
|
|
214
|
+
if not (conn := PostgresDatabases.conn_details(state.namespace, host)):
|
|
215
|
+
return ''
|
|
216
|
+
|
|
217
|
+
key = Config().get(config_key, default)
|
|
218
|
+
return conn[key] if key in conn else ''
|
|
219
|
+
|
|
220
|
+
def default_db():
|
|
221
|
+
return Config().get('pg.default-db', 'postgres')
|
|
222
|
+
|
|
223
|
+
def default_owner():
|
|
224
|
+
return Config().get('pg.default-owner', 'postgres')
|
|
225
|
+
|
|
226
|
+
def default_schema():
|
|
227
|
+
return Config().get('pg.default-schema', 'postgres')
|
|
228
|
+
|
|
229
|
+
def host(state: ReplState):
|
|
230
|
+
if not state.pg_path:
|
|
231
|
+
return None
|
|
232
|
+
|
|
233
|
+
return state.pg_path.split('/')[0]
|
|
234
|
+
|
|
235
|
+
def database(state: ReplState):
|
|
236
|
+
if not state.pg_path:
|
|
237
|
+
return None
|
|
238
|
+
|
|
239
|
+
tokens = state.pg_path.split('/')
|
|
240
|
+
if len(tokens) > 1:
|
|
241
|
+
return tokens[1]
|
|
242
|
+
|
|
243
|
+
return None
|
|
244
|
+
|
|
245
|
+
@functools.lru_cache()
|
|
246
|
+
def conn_details(namespace: str, host: str):
|
|
247
|
+
return Secrets.get_data(namespace, host)
|
|
248
|
+
|
|
249
|
+
class PostgresPathHandler:
|
|
250
|
+
def __init__(self, state: ReplState, host: str = None, database: str = None):
|
|
251
|
+
self.state = state
|
|
252
|
+
self.host = host
|
|
253
|
+
self.database = database
|
|
254
|
+
|
|
255
|
+
def __enter__(self) -> tuple[str, str]:
|
|
256
|
+
if self.state and self.state.pg_path:
|
|
257
|
+
host_n_db = self.state.pg_path.split('/')
|
|
258
|
+
if not self.host:
|
|
259
|
+
self.host = host_n_db[0]
|
|
260
|
+
if not self.database and len(host_n_db) > 1:
|
|
261
|
+
self.database = host_n_db[1]
|
|
262
|
+
|
|
263
|
+
return self.host, self.database
|
|
264
|
+
|
|
265
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
266
|
+
return False
|
|
267
|
+
|
|
268
|
+
def pg_path(state: ReplState, host: str = None, database: str = None):
|
|
269
|
+
return PostgresPathHandler(state, host=host, database=database)
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
from adam.commands.command import Command
|
|
2
|
-
from adam.commands.ls import Ls
|
|
2
|
+
from adam.commands.fs.ls import Ls
|
|
3
3
|
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:
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
|
|
3
|
+
from adam.commands.postgres.postgres_databases import PostgresDatabases, pg_path
|
|
4
|
+
from adam.config import Config
|
|
5
|
+
from adam.repl_state import ReplState
|
|
6
|
+
from adam.utils import log2, wait_log
|
|
7
|
+
from adam.utils_k8s.pods import Pods
|
|
8
|
+
|
|
9
|
+
TestPG = [False]
|
|
10
|
+
|
|
11
|
+
def direct_dirs(state: ReplState) -> list[str]:
|
|
12
|
+
with pg_path(state) as (host, database):
|
|
13
|
+
if database:
|
|
14
|
+
return ['..']
|
|
15
|
+
elif host:
|
|
16
|
+
return ['..'] + pg_database_names(state)
|
|
17
|
+
else:
|
|
18
|
+
return PostgresDatabases.host_names(state.namespace)
|
|
19
|
+
|
|
20
|
+
def pg_database_names(state: ReplState):
|
|
21
|
+
# cache on pg_path
|
|
22
|
+
return _pg_database_names(state, state.pg_path)
|
|
23
|
+
|
|
24
|
+
@functools.lru_cache()
|
|
25
|
+
def _pg_database_names(state: ReplState, pg_path: str):
|
|
26
|
+
if TestPG[0]:
|
|
27
|
+
return ['azops88_c3ai_c3']
|
|
28
|
+
|
|
29
|
+
wait_log('Inspecting Postgres Databases...')
|
|
30
|
+
|
|
31
|
+
return [db['name'] for db in PostgresDatabases.databases(state, default_owner=True)]
|
|
32
|
+
|
|
33
|
+
def pg_table_names(state: ReplState):
|
|
34
|
+
# cache on pg_path
|
|
35
|
+
return _pg_table_names(state, state.pg_path)
|
|
36
|
+
|
|
37
|
+
@functools.lru_cache()
|
|
38
|
+
def _pg_table_names(state: ReplState, pg_path: str):
|
|
39
|
+
if TestPG[0]:
|
|
40
|
+
return ['C3_2_XYZ1']
|
|
41
|
+
|
|
42
|
+
wait_log('Inspecting Postgres Database...')
|
|
43
|
+
return [table['name'] for table in PostgresDatabases.tables(state, default_schema=True)]
|
|
44
|
+
|
|
45
|
+
class PostgresPodService:
|
|
46
|
+
def __init__(self, handler: 'PostgresExecHandler'):
|
|
47
|
+
self.handler = handler
|
|
48
|
+
|
|
49
|
+
def exec(self, command: str, show_out=True):
|
|
50
|
+
state = self.handler.state
|
|
51
|
+
|
|
52
|
+
pod, container = PostgresDatabases.pod_and_container(state.namespace)
|
|
53
|
+
if not pod:
|
|
54
|
+
log2('Cannot locate postgres agent or ops pod.')
|
|
55
|
+
return state
|
|
56
|
+
|
|
57
|
+
return Pods.exec(pod, container, state.namespace, command, show_out=show_out)
|
|
58
|
+
|
|
59
|
+
def sql(self, args: list[str], backgrounded=False):
|
|
60
|
+
state = self.handler.state
|
|
61
|
+
|
|
62
|
+
query = args
|
|
63
|
+
if isinstance(args, list):
|
|
64
|
+
query = ' '.join(args)
|
|
65
|
+
|
|
66
|
+
PostgresDatabases.run_sql(state, query, show_out=Config().is_debug(), backgrounded=backgrounded)
|
|
67
|
+
|
|
68
|
+
class PostgresExecHandler:
|
|
69
|
+
def __init__(self, state: ReplState, backgrounded=False):
|
|
70
|
+
self.state = state
|
|
71
|
+
self.backgrounded = backgrounded
|
|
72
|
+
|
|
73
|
+
def __enter__(self):
|
|
74
|
+
return PostgresPodService(self)
|
|
75
|
+
|
|
76
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
77
|
+
return False
|
|
78
|
+
|
|
79
|
+
def postgres(state: ReplState, backgrounded=False):
|
|
80
|
+
return PostgresExecHandler(state, backgrounded=backgrounded)
|
adam/commands/preview_table.py
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
|
+
from adam.commands import validate_args
|
|
1
2
|
from adam.commands.command import Command
|
|
2
|
-
from adam.commands.
|
|
3
|
-
from adam.commands.postgres.postgres_context import PostgresContext
|
|
4
|
-
from adam.config import Config
|
|
3
|
+
from adam.commands.devices.devices import Devices
|
|
5
4
|
from adam.repl_state import ReplState, RequiredState
|
|
6
|
-
from adam.utils import lines_to_tabular, log, log2
|
|
7
|
-
from adam.utils_audits import Audits
|
|
8
5
|
|
|
9
6
|
class PreviewTable(Command):
|
|
10
7
|
COMMAND = 'preview'
|
|
@@ -22,53 +19,20 @@ class PreviewTable(Command):
|
|
|
22
19
|
return PreviewTable.COMMAND
|
|
23
20
|
|
|
24
21
|
def required(self):
|
|
25
|
-
return [RequiredState.CLUSTER_OR_POD, RequiredState.PG_DATABASE, ReplState.L]
|
|
22
|
+
return [RequiredState.CLUSTER_OR_POD, RequiredState.PG_DATABASE, ReplState.L, RequiredState.EXPORT_DB]
|
|
26
23
|
|
|
27
24
|
def run(self, cmd: str, state: ReplState):
|
|
28
25
|
if not(args := self.args(cmd)):
|
|
29
26
|
return super().run(cmd, state)
|
|
30
27
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if not args:
|
|
36
|
-
def show_tables():
|
|
37
|
-
if state.device == ReplState.P:
|
|
38
|
-
pg = PostgresContext.apply(state.namespace, state.pg_path)
|
|
39
|
-
lines = [db["name"] for db in pg.tables() if db["schema"] == PostgresContext.default_schema()]
|
|
40
|
-
log(lines_to_tabular(lines, separator=','))
|
|
41
|
-
elif state.device == ReplState.L:
|
|
42
|
-
log(lines_to_tabular(Audits.audit_table_names(), separator=','))
|
|
43
|
-
else:
|
|
44
|
-
log(lines_to_tabular(cassandra_table_names(state), separator=','))
|
|
45
|
-
|
|
46
|
-
if state.in_repl:
|
|
47
|
-
log2('Table is required.')
|
|
48
|
-
log2()
|
|
49
|
-
log2('Tables:')
|
|
50
|
-
show_tables()
|
|
51
|
-
else:
|
|
52
|
-
log2('* Table is missing.')
|
|
53
|
-
show_tables()
|
|
54
|
-
|
|
55
|
-
Command.display_help()
|
|
28
|
+
with self.validate(args, state) as (args, state):
|
|
29
|
+
with validate_args(args, state, at_least=1) as table:
|
|
30
|
+
Devices.of(state).preview(table, state)
|
|
56
31
|
|
|
57
|
-
return
|
|
58
|
-
|
|
59
|
-
table = args[0]
|
|
60
|
-
|
|
61
|
-
rows = Config().get('preview.rows', 10)
|
|
62
|
-
if state.device == ReplState.P:
|
|
63
|
-
PostgresContext.apply(state.namespace, state.pg_path).run_sql(f'select * from {table} limit {rows}')
|
|
64
|
-
elif state.device == ReplState.L:
|
|
65
|
-
Audits.run_audit_query(f'select * from {table} limit {rows}')
|
|
66
|
-
else:
|
|
67
|
-
run_cql(state, f'select * from {table} limit {rows}', show_out=True, use_single_quotes=True, on_any=True)
|
|
68
|
-
|
|
69
|
-
return state
|
|
32
|
+
return state
|
|
70
33
|
|
|
71
34
|
def completion(self, _: ReplState):
|
|
35
|
+
# taken care of by the sql completer
|
|
72
36
|
return {}
|
|
73
37
|
|
|
74
38
|
def help(self, _: ReplState):
|
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,35 +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
|
-
if not self.validate_state(state):
|
|
41
|
-
return state
|
|
42
|
-
|
|
43
|
-
return super().intermediate_run(cmd, state, args, Reaper.cmd_list())
|
|
44
|
-
|
|
45
|
-
def cmd_list():
|
|
28
|
+
def cmd_list(self):
|
|
46
29
|
return [ReaperSchedules(), ReaperScheduleStop(), ReaperScheduleActivate(), ReaperScheduleStart(),
|
|
47
30
|
ReaperForwardStop(), ReaperForward(), ReaperRunAbort(), ReaperRunsAbort(), ReaperRestart(),
|
|
48
31
|
ReaperRuns(), ReaperStatus()]
|
|
49
32
|
|
|
50
|
-
def completion(self, state: ReplState):
|
|
51
|
-
if state.sts:
|
|
52
|
-
return super().completion(state)
|
|
53
|
-
|
|
54
|
-
return {}
|
|
55
|
-
|
|
56
33
|
class ReaperCommandHelper(click.Command):
|
|
57
34
|
def get_help(self, ctx: click.Context):
|
|
58
|
-
|
|
35
|
+
IntermediateCommand.intermediate_help(super().get_help(ctx), Reaper.COMMAND, Reaper().cmd_list(), show_cluster_help=True)
|