kaqing 2.0.171__py3-none-any.whl → 2.0.203__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/app_session.py +5 -10
- adam/apps.py +18 -4
- adam/batch.py +7 -7
- adam/checks/check_utils.py +3 -1
- adam/checks/disk.py +2 -3
- adam/columns/memory.py +3 -4
- adam/commands/__init__.py +15 -6
- adam/commands/alter_tables.py +26 -41
- adam/commands/app/__init__.py +0 -0
- adam/commands/{app_cmd.py → app/app.py} +2 -2
- adam/commands/{show → app}/show_app_actions.py +7 -15
- adam/commands/{show → app}/show_app_queues.py +1 -4
- adam/{utils_app.py → commands/app/utils_app.py} +9 -1
- adam/commands/audit/audit.py +9 -26
- adam/commands/audit/audit_repair_tables.py +5 -7
- adam/commands/audit/audit_run.py +1 -1
- adam/commands/audit/completions_l.py +15 -0
- adam/commands/audit/show_last10.py +2 -14
- adam/commands/audit/show_slow10.py +2 -13
- adam/commands/audit/show_top10.py +2 -11
- adam/commands/audit/utils_show_top10.py +15 -3
- adam/commands/bash/bash.py +1 -1
- adam/commands/bash/utils_bash.py +1 -1
- adam/commands/cassandra/__init__.py +0 -0
- adam/commands/cassandra/download_cassandra_log.py +45 -0
- adam/commands/cassandra/nodetool.py +64 -0
- adam/commands/cassandra/nodetool_commands.py +120 -0
- adam/commands/cassandra/restart_cluster.py +47 -0
- adam/commands/cassandra/restart_node.py +51 -0
- adam/commands/cassandra/restart_nodes.py +47 -0
- adam/commands/cassandra/rollout.py +88 -0
- adam/commands/cat.py +5 -19
- adam/commands/cd.py +7 -9
- adam/commands/check.py +10 -18
- adam/commands/cli_commands.py +6 -1
- adam/commands/{cp.py → clipboard_copy.py} +34 -36
- adam/commands/code.py +2 -2
- adam/commands/command.py +139 -22
- adam/commands/commands_utils.py +14 -12
- adam/commands/cql/alter_tables.py +66 -0
- adam/commands/cql/completions_c.py +29 -0
- adam/commands/cql/cqlsh.py +3 -7
- adam/commands/cql/utils_cql.py +23 -61
- 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/deploy/deploy_pg_agent.py +2 -2
- adam/commands/deploy/deploy_pod.py +2 -4
- adam/commands/deploy/undeploy_pg_agent.py +2 -2
- adam/commands/devices/device.py +40 -9
- adam/commands/devices/device_app.py +19 -29
- adam/commands/devices/device_auit_log.py +3 -3
- adam/commands/devices/device_cass.py +17 -23
- adam/commands/devices/device_export.py +12 -11
- adam/commands/devices/device_postgres.py +79 -63
- adam/commands/devices/devices.py +1 -1
- adam/commands/download_cassandra_log.py +45 -0
- adam/commands/download_file.py +47 -0
- adam/commands/export/clean_up_all_export_sessions.py +3 -3
- adam/commands/export/clean_up_export_sessions.py +7 -19
- adam/commands/export/completions_x.py +11 -0
- adam/commands/export/download_export_session.py +40 -0
- adam/commands/export/drop_export_database.py +6 -22
- adam/commands/export/drop_export_databases.py +3 -9
- adam/commands/export/export.py +1 -17
- adam/commands/export/export_databases.py +109 -32
- adam/commands/export/export_select.py +8 -55
- adam/commands/export/export_sessions.py +211 -0
- adam/commands/export/export_use.py +13 -16
- adam/commands/export/export_x_select.py +48 -0
- adam/commands/export/exporter.py +176 -167
- adam/commands/export/import_files.py +44 -0
- adam/commands/export/import_session.py +10 -6
- adam/commands/export/importer.py +24 -9
- adam/commands/export/importer_athena.py +114 -44
- adam/commands/export/importer_sqlite.py +45 -23
- adam/commands/export/show_column_counts.py +11 -20
- adam/commands/export/show_export_databases.py +5 -2
- adam/commands/export/show_export_session.py +6 -15
- adam/commands/export/show_export_sessions.py +4 -11
- adam/commands/export/utils_export.py +79 -27
- adam/commands/find_files.py +51 -0
- adam/commands/find_processes.py +76 -0
- adam/commands/generate_report.py +52 -0
- adam/commands/head.py +36 -0
- adam/commands/help.py +2 -2
- adam/commands/intermediate_command.py +6 -3
- adam/commands/login.py +3 -6
- adam/commands/ls.py +2 -2
- adam/commands/medusa/medusa_backup.py +13 -16
- adam/commands/medusa/medusa_restore.py +26 -37
- adam/commands/medusa/medusa_show_backupjobs.py +7 -7
- adam/commands/medusa/medusa_show_restorejobs.py +6 -6
- adam/commands/medusa/utils_medusa.py +15 -0
- adam/commands/nodetool.py +3 -8
- adam/commands/os/__init__.py +0 -0
- adam/commands/os/cat.py +36 -0
- adam/commands/os/download_file.py +47 -0
- adam/commands/os/find_files.py +51 -0
- adam/commands/os/find_processes.py +76 -0
- adam/commands/os/head.py +36 -0
- adam/commands/os/shell.py +41 -0
- adam/commands/param_get.py +10 -12
- adam/commands/param_set.py +7 -10
- adam/commands/postgres/completions_p.py +22 -0
- adam/commands/postgres/postgres.py +25 -40
- adam/commands/postgres/postgres_databases.py +269 -0
- adam/commands/postgres/utils_postgres.py +33 -20
- adam/commands/preview_table.py +4 -2
- adam/commands/pwd.py +4 -6
- adam/commands/reaper/reaper_forward.py +2 -2
- adam/commands/reaper/reaper_run_abort.py +4 -10
- adam/commands/reaper/reaper_runs.py +3 -3
- adam/commands/reaper/reaper_schedule_activate.py +12 -12
- adam/commands/reaper/reaper_schedule_start.py +7 -12
- adam/commands/reaper/reaper_schedule_stop.py +7 -12
- adam/commands/reaper/utils_reaper.py +13 -6
- adam/commands/repair/repair_log.py +1 -4
- adam/commands/repair/repair_run.py +3 -8
- adam/commands/repair/repair_scan.py +1 -6
- adam/commands/repair/repair_stop.py +1 -5
- adam/commands/restart_cluster.py +47 -0
- adam/commands/restart_node.py +51 -0
- adam/commands/restart_nodes.py +47 -0
- adam/commands/shell.py +9 -2
- adam/commands/show/show.py +4 -4
- adam/commands/show/show_adam.py +3 -3
- adam/commands/show/show_cassandra_repairs.py +5 -6
- adam/commands/show/show_cassandra_status.py +29 -29
- adam/commands/show/show_cassandra_version.py +1 -4
- adam/commands/show/{show_commands.py → show_cli_commands.py} +3 -6
- adam/commands/show/show_login.py +3 -9
- adam/commands/show/show_params.py +2 -5
- adam/commands/show/show_processes.py +15 -16
- adam/commands/show/show_storage.py +9 -8
- adam/config.py +4 -5
- adam/embedded_params.py +1 -1
- adam/log.py +4 -4
- adam/repl.py +26 -18
- adam/repl_commands.py +32 -20
- adam/repl_session.py +9 -1
- adam/repl_state.py +39 -10
- adam/sql/async_executor.py +44 -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 +4 -6
- adam/sql/sql_state_machine.py +25 -13
- adam/sso/authn_ad.py +2 -5
- adam/sso/authn_okta.py +2 -4
- adam/sso/cred_cache.py +2 -5
- adam/sso/idp.py +8 -11
- adam/utils.py +299 -105
- adam/utils_athena.py +18 -18
- adam/utils_audits.py +3 -7
- adam/utils_issues.py +2 -2
- adam/utils_k8s/app_clusters.py +4 -4
- adam/utils_k8s/app_pods.py +8 -6
- adam/utils_k8s/cassandra_clusters.py +16 -5
- adam/utils_k8s/cassandra_nodes.py +9 -6
- adam/utils_k8s/custom_resources.py +11 -17
- adam/utils_k8s/jobs.py +7 -11
- adam/utils_k8s/k8s.py +14 -5
- adam/utils_k8s/kube_context.py +3 -6
- adam/{pod_exec_result.py → utils_k8s/pod_exec_result.py} +4 -4
- adam/utils_k8s/pods.py +85 -23
- adam/utils_k8s/statefulsets.py +5 -2
- adam/utils_local.py +42 -0
- adam/utils_repl/appendable_completer.py +6 -0
- adam/utils_repl/repl_completer.py +45 -2
- adam/utils_repl/state_machine.py +3 -3
- adam/utils_sqlite.py +58 -30
- adam/version.py +1 -1
- {kaqing-2.0.171.dist-info → kaqing-2.0.203.dist-info}/METADATA +1 -1
- kaqing-2.0.203.dist-info/RECORD +277 -0
- kaqing-2.0.203.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/cql/cql_completions.py +0 -33
- adam/commands/export/export_handlers.py +0 -71
- adam/commands/export/export_select_x.py +0 -54
- adam/commands/logs.py +0 -37
- adam/commands/postgres/postgres_context.py +0 -274
- adam/commands/postgres/psql_completions.py +0 -10
- adam/commands/report.py +0 -61
- adam/commands/restart.py +0 -60
- kaqing-2.0.171.dist-info/RECORD +0 -236
- kaqing-2.0.171.dist-info/top_level.txt +0 -1
- /adam/commands/{app_ping.py → app/app_ping.py} +0 -0
- /adam/commands/{show → app}/show_app_id.py +0 -0
- {kaqing-2.0.171.dist-info → kaqing-2.0.203.dist-info}/WHEEL +0 -0
- {kaqing-2.0.171.dist-info → kaqing-2.0.203.dist-info}/entry_points.txt +0 -0
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
from adam.commands.command import Command
|
|
2
|
-
from adam.commands.export.export_databases import ExportDatabases
|
|
3
|
-
from adam.commands.export.exporter import Exporter
|
|
4
|
-
from adam.commands.export.utils_export import ExportSpec, state_with_pod
|
|
5
|
-
from adam.repl_state import ReplState
|
|
6
|
-
from adam.utils import log, log2
|
|
7
|
-
|
|
8
|
-
class ExportService:
|
|
9
|
-
def __init__(self, handler: 'ExporterHandler'):
|
|
10
|
-
self.handler = handler
|
|
11
|
-
|
|
12
|
-
def export(self, args: list[str], export_only=False):
|
|
13
|
-
state = self.handler.state
|
|
14
|
-
export_session = state.export_session
|
|
15
|
-
spec: ExportSpec = None
|
|
16
|
-
try:
|
|
17
|
-
with state_with_pod(state) as state:
|
|
18
|
-
# --export-only for testing only
|
|
19
|
-
statuses, spec = Exporter.export_tables(args, state, export_only=export_only)
|
|
20
|
-
if not statuses:
|
|
21
|
-
return state
|
|
22
|
-
|
|
23
|
-
Exporter.clear_export_session_cache()
|
|
24
|
-
|
|
25
|
-
if spec.importer == 'csv' or export_only:
|
|
26
|
-
ExportDatabases.disply_export_session(state.sts, state.pod, state.namespace, spec.session)
|
|
27
|
-
else:
|
|
28
|
-
log()
|
|
29
|
-
ExportDatabases.display_export_db(state.export_session)
|
|
30
|
-
finally:
|
|
31
|
-
# if exporting to csv, do not bind the new session id to repl state
|
|
32
|
-
if spec and spec.importer == 'csv':
|
|
33
|
-
state.export_session = export_session
|
|
34
|
-
|
|
35
|
-
return state
|
|
36
|
-
|
|
37
|
-
def import_sesion(self, args: list[str]):
|
|
38
|
-
state = self.handler.state
|
|
39
|
-
|
|
40
|
-
if not args:
|
|
41
|
-
if state.in_repl:
|
|
42
|
-
log2('Specify export session name.')
|
|
43
|
-
else:
|
|
44
|
-
log2('* Export session name is missing.')
|
|
45
|
-
|
|
46
|
-
Command.display_help()
|
|
47
|
-
|
|
48
|
-
return 'command-missing'
|
|
49
|
-
|
|
50
|
-
with state_with_pod(state) as state:
|
|
51
|
-
tables, _ = Exporter.import_session(args, state)
|
|
52
|
-
if tables:
|
|
53
|
-
Exporter.clear_export_session_cache()
|
|
54
|
-
|
|
55
|
-
log()
|
|
56
|
-
ExportDatabases.display_export_db(state.export_session)
|
|
57
|
-
|
|
58
|
-
return state
|
|
59
|
-
|
|
60
|
-
class ExporterHandler:
|
|
61
|
-
def __init__(self, state: ReplState):
|
|
62
|
-
self.state = state
|
|
63
|
-
|
|
64
|
-
def __enter__(self):
|
|
65
|
-
return ExportService(self)
|
|
66
|
-
|
|
67
|
-
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
68
|
-
return False
|
|
69
|
-
|
|
70
|
-
def export(state: ReplState):
|
|
71
|
-
return ExporterHandler(state)
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
from adam.commands.command import Command
|
|
2
|
-
from adam.commands.export.export_databases import ExportDatabases
|
|
3
|
-
from adam.repl_state import ReplState, RequiredState
|
|
4
|
-
from adam.sql.sql_completer import SqlCompleter, SqlVariant
|
|
5
|
-
from adam.utils_athena import Athena
|
|
6
|
-
|
|
7
|
-
# No action body, only for a help entry and auto-completion
|
|
8
|
-
class ExportSelectX(Command):
|
|
9
|
-
COMMAND = 'select_on_x'
|
|
10
|
-
|
|
11
|
-
# the singleton pattern
|
|
12
|
-
def __new__(cls, *args, **kwargs):
|
|
13
|
-
if not hasattr(cls, 'instance'): cls.instance = super(ExportSelectX, cls).__new__(cls)
|
|
14
|
-
|
|
15
|
-
return cls.instance
|
|
16
|
-
|
|
17
|
-
def __init__(self, successor: Command=None):
|
|
18
|
-
super().__init__(successor)
|
|
19
|
-
|
|
20
|
-
def command(self):
|
|
21
|
-
return ExportSelectX.COMMAND
|
|
22
|
-
|
|
23
|
-
def required(self):
|
|
24
|
-
return RequiredState.EXPORT_DB
|
|
25
|
-
|
|
26
|
-
def completion(self, state: ReplState):
|
|
27
|
-
completions = {}
|
|
28
|
-
|
|
29
|
-
if state.device == ReplState.X:
|
|
30
|
-
completions = {'drop': SqlCompleter(
|
|
31
|
-
lambda: ExportDatabases.table_names(state.export_session),
|
|
32
|
-
dml='drop',
|
|
33
|
-
expandables={
|
|
34
|
-
'export-dbs': lambda: ExportDatabases.database_names(),
|
|
35
|
-
'columns':lambda _: Athena.column_names(database=state.export_session, function='export'),
|
|
36
|
-
},
|
|
37
|
-
variant=SqlVariant.ATHENA
|
|
38
|
-
)}
|
|
39
|
-
|
|
40
|
-
if state.export_session:
|
|
41
|
-
completions |= {'select': SqlCompleter(
|
|
42
|
-
lambda: ExportDatabases.table_names(state.export_session),
|
|
43
|
-
dml='select',
|
|
44
|
-
expandables={
|
|
45
|
-
'export-dbs': lambda: ExportDatabases.database_names(),
|
|
46
|
-
'columns':lambda _: Athena.column_names(database=state.export_session, function='export'),
|
|
47
|
-
},
|
|
48
|
-
variant=SqlVariant.ATHENA
|
|
49
|
-
)}
|
|
50
|
-
|
|
51
|
-
return completions
|
|
52
|
-
|
|
53
|
-
def help(self, _: ReplState):
|
|
54
|
-
return f'<sql-select-statements>\t run queries on export database'
|
adam/commands/logs.py
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
from adam.commands.command import Command
|
|
2
|
-
from adam.config import Config
|
|
3
|
-
from adam.utils_k8s.cassandra_nodes import CassandraNodes
|
|
4
|
-
from adam.repl_state import ReplState, RequiredState
|
|
5
|
-
|
|
6
|
-
class Logs(Command):
|
|
7
|
-
COMMAND = 'logs'
|
|
8
|
-
|
|
9
|
-
# the singleton pattern
|
|
10
|
-
def __new__(cls, *args, **kwargs):
|
|
11
|
-
if not hasattr(cls, 'instance'): cls.instance = super(Logs, cls).__new__(cls)
|
|
12
|
-
|
|
13
|
-
return cls.instance
|
|
14
|
-
|
|
15
|
-
def __init__(self, successor: Command=None):
|
|
16
|
-
super().__init__(successor)
|
|
17
|
-
|
|
18
|
-
def command(self):
|
|
19
|
-
return Logs.COMMAND
|
|
20
|
-
|
|
21
|
-
def required(self):
|
|
22
|
-
return RequiredState.POD
|
|
23
|
-
|
|
24
|
-
def run(self, cmd: str, state: ReplState):
|
|
25
|
-
if not(args := self.args(cmd)):
|
|
26
|
-
return super().run(cmd, state)
|
|
27
|
-
|
|
28
|
-
with self.validate(args, state) as (args, state):
|
|
29
|
-
path = Config().get('logs.path', '/c3/cassandra/logs/system.log')
|
|
30
|
-
return CassandraNodes.exec(state.pod, state.namespace, f'cat {path}')
|
|
31
|
-
|
|
32
|
-
def completion(self, _: ReplState):
|
|
33
|
-
# available only on cli
|
|
34
|
-
return {}
|
|
35
|
-
|
|
36
|
-
def help(self, _: ReplState):
|
|
37
|
-
return f'{Logs.COMMAND}\t show cassandra system log'
|
|
@@ -1,274 +0,0 @@
|
|
|
1
|
-
from datetime import datetime
|
|
2
|
-
import functools
|
|
3
|
-
import re
|
|
4
|
-
import subprocess
|
|
5
|
-
|
|
6
|
-
from adam.config import Config
|
|
7
|
-
from adam.repl_session import ReplSession
|
|
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
|
|
12
|
-
|
|
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
|
-
|
|
35
|
-
def __init__(self, ns: str, path: str):
|
|
36
|
-
self.namespace = ns
|
|
37
|
-
self.conn_details = None
|
|
38
|
-
self.host = None
|
|
39
|
-
self.db = None
|
|
40
|
-
|
|
41
|
-
if path:
|
|
42
|
-
tks = path.split('/')
|
|
43
|
-
hn = tks[0].split('@')
|
|
44
|
-
self.host = hn[0]
|
|
45
|
-
if len(hn) > 1 and not ns:
|
|
46
|
-
self.namespace = hn[1]
|
|
47
|
-
|
|
48
|
-
if len(tks) > 1:
|
|
49
|
-
self.db = tks[1]
|
|
50
|
-
|
|
51
|
-
def path(self):
|
|
52
|
-
if not self.host:
|
|
53
|
-
return None
|
|
54
|
-
|
|
55
|
-
d = self.host
|
|
56
|
-
if not self.db:
|
|
57
|
-
return d
|
|
58
|
-
|
|
59
|
-
return f'{self.host}/{self.db}'
|
|
60
|
-
|
|
61
|
-
def hosts(ns: str):
|
|
62
|
-
return PostgresContext.hosts_for_namespace(ns)
|
|
63
|
-
|
|
64
|
-
@functools.lru_cache()
|
|
65
|
-
def hosts_for_namespace(ns: str):
|
|
66
|
-
ss = Secrets.list_secrets(ns, name_pattern=Config().get('pg.name-pattern', '^{namespace}.*k8spg.*'))
|
|
67
|
-
|
|
68
|
-
def excludes(name: str):
|
|
69
|
-
exs = Config().get('pg.excludes', '.helm., -admin-secret')
|
|
70
|
-
if exs:
|
|
71
|
-
for ex in exs.split(','):
|
|
72
|
-
if ex.strip(' ') in name:
|
|
73
|
-
return True
|
|
74
|
-
|
|
75
|
-
return False
|
|
76
|
-
|
|
77
|
-
return [s for s in ss if not excludes(s)]
|
|
78
|
-
|
|
79
|
-
def databases(self):
|
|
80
|
-
dbs = []
|
|
81
|
-
# List of databases
|
|
82
|
-
# Name | Owner | Encoding | Collate | Ctype | ICU Locale | Locale Provider | Access privileges
|
|
83
|
-
# ---------------------------------------+----------+----------+-------------+-------------+------------+-----------------+-----------------------
|
|
84
|
-
# postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc |
|
|
85
|
-
# stgawsscpsr_c3_c3 | postgres | UTF8 | C | C | | libc |
|
|
86
|
-
# template1 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc | =c/postgres +
|
|
87
|
-
# | | | | | | | postgres=CTc/postgres
|
|
88
|
-
# (48 rows)
|
|
89
|
-
if r := self.run_sql('\l', show_out=False):
|
|
90
|
-
s = 0
|
|
91
|
-
for line in r.stdout.split('\n'):
|
|
92
|
-
line: str = line.strip(' \r')
|
|
93
|
-
if s == 0:
|
|
94
|
-
if 'List of databases' in line:
|
|
95
|
-
s = 1
|
|
96
|
-
elif s == 1:
|
|
97
|
-
if 'Name' in line and 'Owner' in line and 'Encoding' in line:
|
|
98
|
-
s = 2
|
|
99
|
-
elif s == 2:
|
|
100
|
-
if line.startswith('---------'):
|
|
101
|
-
s = 3
|
|
102
|
-
elif s == 3:
|
|
103
|
-
groups = re.match(r'^\s*(\S*)\s*\|\s*(\S*)\s*\|.*', line)
|
|
104
|
-
if groups and groups[1] != '|':
|
|
105
|
-
dbs.append({'name': groups[1], 'owner': groups[2]})
|
|
106
|
-
|
|
107
|
-
return dbs
|
|
108
|
-
|
|
109
|
-
def tables(self):
|
|
110
|
-
dbs = []
|
|
111
|
-
# List of relations
|
|
112
|
-
# Schema | Name | Type | Owner
|
|
113
|
-
# ----------+------------------------------------------------------------+-------+---------------
|
|
114
|
-
# postgres | c3_2_admin_aclpriv | table | postgres
|
|
115
|
-
# postgres | c3_2_admin_aclpriv_a | table | postgres
|
|
116
|
-
if r := self.run_sql('\dt', show_out=False):
|
|
117
|
-
s = 0
|
|
118
|
-
for line in r.stdout.split('\n'):
|
|
119
|
-
line: str = line.strip(' \r')
|
|
120
|
-
if s == 0:
|
|
121
|
-
if 'List of relations' in line:
|
|
122
|
-
s = 1
|
|
123
|
-
elif s == 1:
|
|
124
|
-
if 'Schema' in line and 'Name' in line and 'Type' in line:
|
|
125
|
-
s = 2
|
|
126
|
-
elif s == 2:
|
|
127
|
-
if line.startswith('---------'):
|
|
128
|
-
s = 3
|
|
129
|
-
elif s == 3:
|
|
130
|
-
groups = re.match(r'^\s*(\S*)\s*\|\s*(\S*)\s*\|.*', line)
|
|
131
|
-
if groups and groups[1] != '|':
|
|
132
|
-
dbs.append({'schema': groups[1], 'name': groups[2]})
|
|
133
|
-
|
|
134
|
-
return dbs
|
|
135
|
-
|
|
136
|
-
def run_sql(self, sql: str, show_out = True, background = False):
|
|
137
|
-
db = self.db if self.db else PostgresContext.default_db()
|
|
138
|
-
|
|
139
|
-
if KubeContext.in_cluster():
|
|
140
|
-
cmd1 = f'env PGPASSWORD={self.password()} psql -h {self.endpoint()} -p {self.port()} -U {self.username()} {db} --pset pager=off -c'
|
|
141
|
-
log2(f'{cmd1} "{sql}"')
|
|
142
|
-
# remove double quotes from the sql argument
|
|
143
|
-
cmd = cmd1.split(' ') + [sql]
|
|
144
|
-
|
|
145
|
-
r = subprocess.run(cmd, capture_output=not background, text=True)
|
|
146
|
-
if show_out:
|
|
147
|
-
log2(r.stdout)
|
|
148
|
-
log2(r.stderr)
|
|
149
|
-
|
|
150
|
-
return r
|
|
151
|
-
else:
|
|
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
|
|
185
|
-
|
|
186
|
-
def pod_and_container(ns: str):
|
|
187
|
-
container_name = Config().get('pg.agent.name', 'ops-pg-agent')
|
|
188
|
-
|
|
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:
|
|
198
|
-
try:
|
|
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
|
|
202
|
-
except:
|
|
203
|
-
log2(f"Could not locate {container_name} pod.")
|
|
204
|
-
return None
|
|
205
|
-
|
|
206
|
-
return pod_name, container_name
|
|
207
|
-
|
|
208
|
-
def deploy_pg_agent(pod_name: str, ns: str) -> str:
|
|
209
|
-
image = Config().get('pg.agent.image', 'seanahnsf/kaqing')
|
|
210
|
-
timeout = Config().get('pg.agent.timeout', 3600)
|
|
211
|
-
try:
|
|
212
|
-
Pods.create(ns, pod_name, image, ['sleep', f'{timeout}'], env={'NAMESPACE': ns}, sa_name='c3')
|
|
213
|
-
except Exception as e:
|
|
214
|
-
if e.status == 409:
|
|
215
|
-
if Pods.completed(ns, pod_name):
|
|
216
|
-
try:
|
|
217
|
-
Pods.delete(pod_name, ns)
|
|
218
|
-
Pods.create(ns, pod_name, image, ['sleep', f'{timeout}'], env={'NAMESPACE': ns}, sa_name='c3')
|
|
219
|
-
except Exception as e2:
|
|
220
|
-
log2("Exception when calling BatchV1Api->create_pod: %s\n" % e2)
|
|
221
|
-
|
|
222
|
-
return
|
|
223
|
-
else:
|
|
224
|
-
log2("Exception when calling BatchV1Api->create_pod: %s\n" % e)
|
|
225
|
-
|
|
226
|
-
return
|
|
227
|
-
|
|
228
|
-
Pods.wait_for_running(ns, pod_name)
|
|
229
|
-
|
|
230
|
-
return pod_name
|
|
231
|
-
|
|
232
|
-
def undeploy_pg_agent(pod_name: str, ns: str):
|
|
233
|
-
Pods.delete(pod_name, ns, grace_period_seconds=0)
|
|
234
|
-
|
|
235
|
-
def endpoint(self):
|
|
236
|
-
if not self.conn_details:
|
|
237
|
-
self.conn_details = Secrets.get_data(self.namespace, self.host)
|
|
238
|
-
|
|
239
|
-
endpoint_key = Config().get('pg.secret.endpoint-key', 'postgres-db-endpoint')
|
|
240
|
-
|
|
241
|
-
return self.conn_details[endpoint_key] if endpoint_key in self.conn_details else ''
|
|
242
|
-
|
|
243
|
-
def port(self):
|
|
244
|
-
if not self.conn_details:
|
|
245
|
-
self.conn_details = Secrets.get_data(self.namespace, self.host)
|
|
246
|
-
|
|
247
|
-
port_key = Config().get('pg.secret.port-key', 'postgres-db-port')
|
|
248
|
-
|
|
249
|
-
return self.conn_details[port_key] if port_key in self.conn_details else ''
|
|
250
|
-
|
|
251
|
-
def username(self):
|
|
252
|
-
if not self.conn_details:
|
|
253
|
-
self.conn_details = Secrets.get_data(self.namespace, self.host)
|
|
254
|
-
|
|
255
|
-
username_key = Config().get('pg.secret.username-key', 'postgres-admin-username')
|
|
256
|
-
|
|
257
|
-
return self.conn_details[username_key] if username_key in self.conn_details else ''
|
|
258
|
-
|
|
259
|
-
def password(self):
|
|
260
|
-
if not self.conn_details:
|
|
261
|
-
self.conn_details = Secrets.get_data(self.namespace, self.host)
|
|
262
|
-
|
|
263
|
-
password_key = Config().get('pg.secret.password-key', 'postgres-admin-password')
|
|
264
|
-
|
|
265
|
-
return self.conn_details[password_key] if password_key in self.conn_details else ''
|
|
266
|
-
|
|
267
|
-
def default_db():
|
|
268
|
-
return Config().get('pg.default-db', 'postgres')
|
|
269
|
-
|
|
270
|
-
def default_owner():
|
|
271
|
-
return Config().get('pg.default-owner', 'postgres')
|
|
272
|
-
|
|
273
|
-
def default_schema():
|
|
274
|
-
return Config().get('pg.default-schema', 'postgres')
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
from adam.commands.postgres.utils_postgres import pg_table_names
|
|
2
|
-
from adam.sql.sql_completer import SqlCompleter
|
|
3
|
-
|
|
4
|
-
def psql_completions(ns: str, pg_path: str):
|
|
5
|
-
return {
|
|
6
|
-
'\h': None,
|
|
7
|
-
'\d': None,
|
|
8
|
-
'\dt': None,
|
|
9
|
-
'\du': None
|
|
10
|
-
} | SqlCompleter(lambda: pg_table_names(ns, pg_path)).completions_for_nesting()
|
adam/commands/report.py
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import click
|
|
2
|
-
import json
|
|
3
|
-
|
|
4
|
-
from adam.checks.check_result import CheckResult
|
|
5
|
-
from adam.checks.check_utils import run_checks
|
|
6
|
-
from adam.commands.command import Command
|
|
7
|
-
from adam.repl_state import ReplState
|
|
8
|
-
from adam.utils import log2
|
|
9
|
-
|
|
10
|
-
class Report(Command):
|
|
11
|
-
COMMAND = 'report'
|
|
12
|
-
|
|
13
|
-
# the singleton pattern
|
|
14
|
-
def __new__(cls, *args, **kwargs):
|
|
15
|
-
if not hasattr(cls, 'instance'): cls.instance = super(Report, cls).__new__(cls)
|
|
16
|
-
|
|
17
|
-
return cls.instance
|
|
18
|
-
|
|
19
|
-
def __init__(self, successor: Command=None):
|
|
20
|
-
super().__init__(successor)
|
|
21
|
-
|
|
22
|
-
def command(self):
|
|
23
|
-
return Report.COMMAND
|
|
24
|
-
|
|
25
|
-
def required(self):
|
|
26
|
-
return ReplState.NON_L
|
|
27
|
-
|
|
28
|
-
def run(self, cmd: str, state: ReplState):
|
|
29
|
-
if not(args := self.args(cmd)):
|
|
30
|
-
return super().run(cmd, state)
|
|
31
|
-
|
|
32
|
-
with self.validate(args, state) as (args, state):
|
|
33
|
-
output: dict[str, any] = {}
|
|
34
|
-
|
|
35
|
-
if state.in_repl:
|
|
36
|
-
args, show = Command.extract_options(args, ['-s', '--show'])
|
|
37
|
-
|
|
38
|
-
args, redirect = Command.extract_options(args, ['>'])
|
|
39
|
-
if not redirect or not args:
|
|
40
|
-
log2('Please specify file name: e.g. report > /tmp/report.log')
|
|
41
|
-
return 'no-report-destination'
|
|
42
|
-
|
|
43
|
-
results = run_checks(state.sts, state.namespace, state.pod, show_out=show)
|
|
44
|
-
output = CheckResult.report(results)
|
|
45
|
-
with open(args[0], "w") as json_file:
|
|
46
|
-
json.dump(output, json_file, indent=2)
|
|
47
|
-
log2(f'Report stored in {args[0]}.')
|
|
48
|
-
else:
|
|
49
|
-
args, show = Command.extract_options(args, ['-s', '--show'])
|
|
50
|
-
|
|
51
|
-
results = run_checks(state.sts, state.namespace, state.pod, show_out=show)
|
|
52
|
-
output = CheckResult.report(results)
|
|
53
|
-
click.echo(json.dumps(output, indent=2))
|
|
54
|
-
|
|
55
|
-
return output
|
|
56
|
-
|
|
57
|
-
def completion(self, state: ReplState):
|
|
58
|
-
return super().completion(state, {">": None})
|
|
59
|
-
|
|
60
|
-
def help(self, _: ReplState):
|
|
61
|
-
return f"{Report.COMMAND} > <file-name>\t generate report"
|
adam/commands/restart.py
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
from adam.commands import extract_options
|
|
2
|
-
from adam.commands.command import Command
|
|
3
|
-
from adam.utils_k8s.pods import Pods
|
|
4
|
-
from adam.utils_k8s.statefulsets import StatefulSets
|
|
5
|
-
from adam.repl_state import ReplState, RequiredState
|
|
6
|
-
from adam.utils import log2
|
|
7
|
-
|
|
8
|
-
class Restart(Command):
|
|
9
|
-
COMMAND = 'restart'
|
|
10
|
-
|
|
11
|
-
# the singleton pattern
|
|
12
|
-
def __new__(cls, *args, **kwargs):
|
|
13
|
-
if not hasattr(cls, 'instance'): cls.instance = super(Restart, cls).__new__(cls)
|
|
14
|
-
|
|
15
|
-
return cls.instance
|
|
16
|
-
|
|
17
|
-
def __init__(self, successor: Command=None):
|
|
18
|
-
super().__init__(successor)
|
|
19
|
-
|
|
20
|
-
def command(self):
|
|
21
|
-
return Restart.COMMAND
|
|
22
|
-
|
|
23
|
-
def required(self):
|
|
24
|
-
return RequiredState.CLUSTER_OR_POD
|
|
25
|
-
|
|
26
|
-
def run(self, cmd: str, state: ReplState):
|
|
27
|
-
if not(args := self.args(cmd)):
|
|
28
|
-
return super().run(cmd, state)
|
|
29
|
-
|
|
30
|
-
with self.validate(args, state) as (args, state):
|
|
31
|
-
with extract_options(args, '--force') as (args, forced):
|
|
32
|
-
if not args:
|
|
33
|
-
if state.pod:
|
|
34
|
-
log2(f'Restarting {state.pod}...')
|
|
35
|
-
Pods.delete(state.pod, state.namespace)
|
|
36
|
-
else:
|
|
37
|
-
if not forced:
|
|
38
|
-
log2('Please add --force for restarting all nodes in a cluster.')
|
|
39
|
-
return 'force-needed'
|
|
40
|
-
|
|
41
|
-
log2(f'Restarting all pods from {state.sts}...')
|
|
42
|
-
for pod_name in StatefulSets.pod_names(state.sts, state.namespace):
|
|
43
|
-
Pods.delete(pod_name, state.namespace)
|
|
44
|
-
else:
|
|
45
|
-
for arg in args:
|
|
46
|
-
Pods.delete(arg, state.namespace)
|
|
47
|
-
|
|
48
|
-
return state
|
|
49
|
-
|
|
50
|
-
def completion(self, state: ReplState):
|
|
51
|
-
if super().completion(state):
|
|
52
|
-
if state.pod:
|
|
53
|
-
return {Restart.COMMAND: None}
|
|
54
|
-
elif state.sts:
|
|
55
|
-
return {Restart.COMMAND: {p: None for p in StatefulSets.pod_names(state.sts, state.namespace)}}
|
|
56
|
-
|
|
57
|
-
return {}
|
|
58
|
-
|
|
59
|
-
def help(self, _: ReplState):
|
|
60
|
-
return f"{Restart.COMMAND} [<host-id>] [--force]\t restart the node you're in or all the nodes in the cluster"
|