kaqing 1.98.15__py3-none-any.whl → 2.0.145__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/app_session.py +1 -1
- adam/apps.py +2 -2
- adam/batch.py +30 -31
- adam/checks/check_utils.py +4 -4
- adam/checks/compactionstats.py +1 -1
- adam/checks/cpu.py +2 -2
- adam/checks/disk.py +1 -1
- adam/checks/gossip.py +1 -1
- adam/checks/memory.py +3 -3
- adam/checks/status.py +1 -1
- adam/commands/alter_tables.py +81 -0
- adam/commands/app.py +3 -3
- adam/commands/app_ping.py +2 -2
- adam/commands/audit/audit.py +86 -0
- adam/commands/audit/audit_repair_tables.py +77 -0
- adam/commands/audit/audit_run.py +58 -0
- adam/commands/audit/show_last10.py +51 -0
- adam/commands/audit/show_slow10.py +50 -0
- adam/commands/audit/show_top10.py +48 -0
- adam/commands/audit/utils_show_top10.py +59 -0
- adam/commands/bash/bash.py +133 -0
- adam/commands/bash/bash_completer.py +93 -0
- adam/commands/cat.py +56 -0
- adam/commands/cd.py +12 -82
- adam/commands/check.py +6 -0
- adam/commands/cli_commands.py +3 -3
- adam/commands/code.py +60 -0
- adam/commands/command.py +48 -12
- adam/commands/commands_utils.py +4 -5
- adam/commands/cql/cql_completions.py +28 -0
- adam/commands/cql/cql_utils.py +209 -0
- adam/commands/{cqlsh.py → cql/cqlsh.py} +15 -10
- adam/commands/deploy/__init__.py +0 -0
- adam/commands/{frontend → deploy}/code_start.py +1 -1
- adam/commands/{frontend → deploy}/code_stop.py +1 -1
- adam/commands/{frontend → deploy}/code_utils.py +2 -2
- adam/commands/deploy/deploy.py +48 -0
- adam/commands/deploy/deploy_frontend.py +52 -0
- adam/commands/deploy/deploy_pg_agent.py +38 -0
- adam/commands/deploy/deploy_pod.py +110 -0
- adam/commands/deploy/deploy_utils.py +29 -0
- adam/commands/deploy/undeploy.py +48 -0
- adam/commands/deploy/undeploy_frontend.py +41 -0
- adam/commands/deploy/undeploy_pg_agent.py +42 -0
- adam/commands/deploy/undeploy_pod.py +51 -0
- adam/commands/devices/__init__.py +0 -0
- adam/commands/devices/device.py +27 -0
- adam/commands/devices/device_app.py +146 -0
- adam/commands/devices/device_auit_log.py +43 -0
- adam/commands/devices/device_cass.py +145 -0
- adam/commands/devices/device_export.py +86 -0
- adam/commands/devices/device_postgres.py +109 -0
- adam/commands/devices/devices.py +25 -0
- adam/commands/export/__init__.py +0 -0
- adam/commands/export/clean_up_export_session.py +53 -0
- adam/commands/{frontend/teardown_frontend.py → export/clean_up_export_sessions.py} +9 -11
- adam/commands/export/drop_export_database.py +58 -0
- adam/commands/export/drop_export_databases.py +46 -0
- adam/commands/export/export.py +83 -0
- adam/commands/export/export_databases.py +170 -0
- adam/commands/export/export_select.py +85 -0
- adam/commands/export/export_select_x.py +54 -0
- adam/commands/export/export_use.py +55 -0
- adam/commands/export/exporter.py +364 -0
- adam/commands/export/import_session.py +68 -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 +63 -0
- adam/commands/export/show_export_databases.py +39 -0
- adam/commands/export/show_export_session.py +51 -0
- adam/commands/export/show_export_sessions.py +47 -0
- adam/commands/export/utils_export.py +291 -0
- adam/commands/help.py +12 -7
- adam/commands/issues.py +6 -0
- adam/commands/kubectl.py +41 -0
- adam/commands/login.py +9 -5
- adam/commands/logs.py +2 -1
- adam/commands/ls.py +4 -107
- adam/commands/medusa/medusa.py +2 -26
- adam/commands/medusa/medusa_backup.py +2 -2
- adam/commands/medusa/medusa_restore.py +3 -4
- adam/commands/medusa/medusa_show_backupjobs.py +4 -3
- adam/commands/medusa/medusa_show_restorejobs.py +3 -3
- adam/commands/nodetool.py +9 -4
- adam/commands/param_set.py +1 -1
- adam/commands/postgres/postgres.py +42 -43
- adam/commands/postgres/postgres_context.py +248 -0
- adam/commands/postgres/postgres_preview.py +0 -1
- adam/commands/postgres/postgres_utils.py +31 -0
- adam/commands/postgres/psql_completions.py +10 -0
- adam/commands/preview_table.py +18 -40
- adam/commands/pwd.py +2 -28
- adam/commands/reaper/reaper.py +4 -24
- adam/commands/reaper/reaper_restart.py +1 -1
- adam/commands/reaper/reaper_session.py +2 -2
- adam/commands/repair/repair.py +3 -27
- adam/commands/repair/repair_log.py +1 -1
- adam/commands/repair/repair_run.py +2 -2
- adam/commands/repair/repair_scan.py +2 -7
- adam/commands/repair/repair_stop.py +1 -1
- adam/commands/report.py +6 -0
- adam/commands/restart.py +2 -2
- adam/commands/rollout.py +1 -1
- adam/commands/shell.py +33 -0
- adam/commands/show/show.py +11 -26
- adam/commands/show/show_app_actions.py +3 -0
- adam/commands/show/show_app_id.py +1 -1
- adam/commands/show/show_app_queues.py +3 -2
- adam/commands/show/show_cassandra_status.py +3 -3
- adam/commands/show/show_cassandra_version.py +3 -3
- adam/commands/show/show_commands.py +4 -1
- adam/commands/show/show_host.py +33 -0
- adam/commands/show/show_login.py +3 -0
- adam/commands/show/show_processes.py +1 -1
- adam/commands/show/show_repairs.py +2 -2
- adam/commands/show/show_storage.py +1 -1
- adam/commands/watch.py +1 -1
- adam/config.py +16 -3
- adam/embedded_params.py +1 -1
- adam/pod_exec_result.py +10 -2
- adam/repl.py +132 -117
- adam/repl_commands.py +62 -18
- adam/repl_state.py +276 -55
- adam/sql/__init__.py +0 -0
- adam/sql/sql_completer.py +120 -0
- adam/sql/sql_state_machine.py +617 -0
- adam/sql/term_completer.py +76 -0
- adam/sso/authenticator.py +1 -1
- adam/sso/authn_ad.py +36 -56
- adam/sso/authn_okta.py +6 -32
- adam/sso/cred_cache.py +1 -1
- adam/sso/idp.py +74 -9
- adam/sso/idp_login.py +2 -2
- adam/sso/idp_session.py +10 -7
- adam/utils.py +85 -4
- adam/utils_athena.py +145 -0
- adam/utils_audits.py +102 -0
- adam/utils_k8s/__init__.py +0 -0
- adam/utils_k8s/app_clusters.py +33 -0
- adam/utils_k8s/app_pods.py +31 -0
- adam/{k8s_utils → utils_k8s}/cassandra_clusters.py +6 -21
- adam/{k8s_utils → utils_k8s}/cassandra_nodes.py +12 -5
- adam/utils_k8s/config_maps.py +34 -0
- adam/utils_k8s/deployment.py +56 -0
- adam/{k8s_utils → utils_k8s}/jobs.py +1 -1
- adam/{k8s_utils → utils_k8s}/kube_context.py +1 -1
- adam/utils_k8s/pods.py +342 -0
- adam/{k8s_utils → utils_k8s}/secrets.py +4 -0
- adam/utils_k8s/service_accounts.py +169 -0
- adam/{k8s_utils → utils_k8s}/statefulsets.py +5 -4
- adam/{k8s_utils → utils_k8s}/volumes.py +9 -0
- adam/utils_net.py +24 -0
- 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 +101 -0
- adam/version.py +1 -1
- {kaqing-1.98.15.dist-info → kaqing-2.0.145.dist-info}/METADATA +1 -1
- kaqing-2.0.145.dist-info/RECORD +227 -0
- adam/commands/bash.py +0 -87
- adam/commands/cql_utils.py +0 -53
- adam/commands/devices.py +0 -89
- adam/commands/frontend/setup.py +0 -60
- adam/commands/frontend/setup_frontend.py +0 -58
- adam/commands/frontend/teardown.py +0 -61
- adam/commands/postgres/postgres_session.py +0 -225
- adam/commands/user_entry.py +0 -77
- adam/k8s_utils/pods.py +0 -211
- kaqing-1.98.15.dist-info/RECORD +0 -160
- /adam/commands/{frontend → audit}/__init__.py +0 -0
- /adam/{k8s_utils → commands/bash}/__init__.py +0 -0
- /adam/{medusa_show_restorejobs.py → commands/cql/__init__.py} +0 -0
- /adam/{k8s_utils → utils_k8s}/custom_resources.py +0 -0
- /adam/{k8s_utils → utils_k8s}/ingresses.py +0 -0
- /adam/{k8s_utils → utils_k8s}/services.py +0 -0
- {kaqing-1.98.15.dist-info → kaqing-2.0.145.dist-info}/WHEEL +0 -0
- {kaqing-1.98.15.dist-info → kaqing-2.0.145.dist-info}/entry_points.txt +0 -0
- {kaqing-1.98.15.dist-info → kaqing-2.0.145.dist-info}/top_level.txt +0 -0
adam/commands/devices.py
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
from adam.commands.command import Command
|
|
2
|
-
from adam.repl_state import ReplState
|
|
3
|
-
|
|
4
|
-
class DeviceCass(Command):
|
|
5
|
-
COMMAND = f'{ReplState.C}:'
|
|
6
|
-
|
|
7
|
-
# the singleton pattern
|
|
8
|
-
def __new__(cls, *args, **kwargs):
|
|
9
|
-
if not hasattr(cls, 'instance'): cls.instance = super(DeviceCass, cls).__new__(cls)
|
|
10
|
-
|
|
11
|
-
return cls.instance
|
|
12
|
-
|
|
13
|
-
def __init__(self, successor: Command=None):
|
|
14
|
-
super().__init__(successor)
|
|
15
|
-
|
|
16
|
-
def command(self):
|
|
17
|
-
return DeviceCass.COMMAND
|
|
18
|
-
|
|
19
|
-
def run(self, cmd: str, state: ReplState):
|
|
20
|
-
if not self.args(cmd):
|
|
21
|
-
return super().run(cmd, state)
|
|
22
|
-
|
|
23
|
-
state.device = ReplState.C
|
|
24
|
-
|
|
25
|
-
return state
|
|
26
|
-
|
|
27
|
-
def completion(self, state: ReplState):
|
|
28
|
-
return super().completion(state)
|
|
29
|
-
|
|
30
|
-
def help(self, _: ReplState):
|
|
31
|
-
return f'{DeviceCass.COMMAND}\t move to Cassandra Operations device'
|
|
32
|
-
|
|
33
|
-
class DevicePostgres(Command):
|
|
34
|
-
COMMAND = f'{ReplState.P}:'
|
|
35
|
-
|
|
36
|
-
# the singleton pattern
|
|
37
|
-
def __new__(cls, *args, **kwargs):
|
|
38
|
-
if not hasattr(cls, 'instance'): cls.instance = super(DevicePostgres, cls).__new__(cls)
|
|
39
|
-
|
|
40
|
-
return cls.instance
|
|
41
|
-
|
|
42
|
-
def __init__(self, successor: Command=None):
|
|
43
|
-
super().__init__(successor)
|
|
44
|
-
|
|
45
|
-
def command(self):
|
|
46
|
-
return DevicePostgres.COMMAND
|
|
47
|
-
|
|
48
|
-
def run(self, cmd: str, state: ReplState):
|
|
49
|
-
if not self.args(cmd):
|
|
50
|
-
return super().run(cmd, state)
|
|
51
|
-
|
|
52
|
-
state.device = ReplState.P
|
|
53
|
-
|
|
54
|
-
return state
|
|
55
|
-
|
|
56
|
-
def completion(self, state: ReplState):
|
|
57
|
-
return super().completion(state)
|
|
58
|
-
|
|
59
|
-
def help(self, _: ReplState):
|
|
60
|
-
return f'{DevicePostgres.COMMAND}\t move to Postgres Operations device'
|
|
61
|
-
|
|
62
|
-
class DeviceApp(Command):
|
|
63
|
-
COMMAND = f'{ReplState.A}:'
|
|
64
|
-
|
|
65
|
-
# the singleton pattern
|
|
66
|
-
def __new__(cls, *args, **kwargs):
|
|
67
|
-
if not hasattr(cls, 'instance'): cls.instance = super(DeviceApp, cls).__new__(cls)
|
|
68
|
-
|
|
69
|
-
return cls.instance
|
|
70
|
-
|
|
71
|
-
def __init__(self, successor: Command=None):
|
|
72
|
-
super().__init__(successor)
|
|
73
|
-
|
|
74
|
-
def command(self):
|
|
75
|
-
return DeviceApp.COMMAND
|
|
76
|
-
|
|
77
|
-
def run(self, cmd: str, state: ReplState):
|
|
78
|
-
if not self.args(cmd):
|
|
79
|
-
return super().run(cmd, state)
|
|
80
|
-
|
|
81
|
-
state.device = ReplState.A
|
|
82
|
-
|
|
83
|
-
return state
|
|
84
|
-
|
|
85
|
-
def completion(self, state: ReplState):
|
|
86
|
-
return super().completion(state)
|
|
87
|
-
|
|
88
|
-
def help(self, _: ReplState):
|
|
89
|
-
return f'{DeviceApp.COMMAND}\t move to App Operations device'
|
adam/commands/frontend/setup.py
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import click
|
|
2
|
-
|
|
3
|
-
from adam.commands.command import Command
|
|
4
|
-
from adam.commands.command_helpers import ClusterCommandHelper
|
|
5
|
-
from .setup_frontend import SetupFrontend
|
|
6
|
-
from adam.repl_state import ReplState
|
|
7
|
-
from adam.utils import lines_to_tabular, log, log2
|
|
8
|
-
|
|
9
|
-
class Setup(Command):
|
|
10
|
-
COMMAND = 'setup'
|
|
11
|
-
reaper_login = None
|
|
12
|
-
|
|
13
|
-
# the singleton pattern
|
|
14
|
-
def __new__(cls, *args, **kwargs):
|
|
15
|
-
if not hasattr(cls, 'instance'): cls.instance = super(Setup, 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 Setup.COMMAND
|
|
24
|
-
|
|
25
|
-
def run(self, cmd: str, state: ReplState):
|
|
26
|
-
if not(args := self.args(cmd)):
|
|
27
|
-
return super().run(cmd, state)
|
|
28
|
-
|
|
29
|
-
state, args = self.apply_state(args, state)
|
|
30
|
-
|
|
31
|
-
if state.in_repl:
|
|
32
|
-
log(lines_to_tabular([c.help(ReplState()) for c in Setup.cmd_list()], separator=':'))
|
|
33
|
-
|
|
34
|
-
return 'command-missing'
|
|
35
|
-
else:
|
|
36
|
-
# head with the Chain of Responsibility pattern
|
|
37
|
-
cmds = Command.chain(Setup.cmd_list())
|
|
38
|
-
if not cmds.run(cmd, state):
|
|
39
|
-
log2('* Command is missing.')
|
|
40
|
-
Command.display_help()
|
|
41
|
-
|
|
42
|
-
def cmd_list():
|
|
43
|
-
return [SetupFrontend()]
|
|
44
|
-
|
|
45
|
-
def completion(self, state: ReplState):
|
|
46
|
-
if state.sts:
|
|
47
|
-
return super().completion(state)
|
|
48
|
-
|
|
49
|
-
return {}
|
|
50
|
-
|
|
51
|
-
def help(self, _: ReplState):
|
|
52
|
-
return None
|
|
53
|
-
|
|
54
|
-
class SetupCommandHelper(click.Command):
|
|
55
|
-
def get_help(self, ctx: click.Context):
|
|
56
|
-
log(super().get_help(ctx))
|
|
57
|
-
log()
|
|
58
|
-
log('Sub-Commands:')
|
|
59
|
-
|
|
60
|
-
log(lines_to_tabular([c.help(ReplState()).replace(f'{Setup.COMMAND} ', ' ', 1) for c in Setup.cmd_list()], separator=':'))
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
from adam.app_session import AppSession
|
|
2
|
-
from adam.commands.command import Command
|
|
3
|
-
from adam.k8s_utils.ingresses import Ingresses
|
|
4
|
-
from adam.k8s_utils.services import Services
|
|
5
|
-
from adam.repl_state import ReplState, RequiredState
|
|
6
|
-
from adam.utils import log2
|
|
7
|
-
|
|
8
|
-
class SetupFrontend(Command):
|
|
9
|
-
COMMAND = 'setup frontend'
|
|
10
|
-
|
|
11
|
-
# the singleton pattern
|
|
12
|
-
def __new__(cls, *args, **kwargs):
|
|
13
|
-
if not hasattr(cls, 'instance'): cls.instance = super(SetupFrontend, 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 SetupFrontend.COMMAND
|
|
22
|
-
|
|
23
|
-
def required(self):
|
|
24
|
-
return RequiredState.NAMESPACE
|
|
25
|
-
|
|
26
|
-
def run(self, cmd: str, state: ReplState):
|
|
27
|
-
if not(args := self.args(cmd)):
|
|
28
|
-
return super().run(cmd, state)
|
|
29
|
-
|
|
30
|
-
state, args = self.apply_state(args, state)
|
|
31
|
-
if not self.validate_state(state):
|
|
32
|
-
return state
|
|
33
|
-
|
|
34
|
-
log2('This will support c3/c3 only for demo.')
|
|
35
|
-
|
|
36
|
-
app_session: AppSession = AppSession.create('c3', 'c3', state.namespace)
|
|
37
|
-
try:
|
|
38
|
-
name = 'ops'
|
|
39
|
-
port = 7678
|
|
40
|
-
Services.create_service(name, state.namespace, port, {"run": "ops"})
|
|
41
|
-
Ingresses.create_ingress(name, state.namespace, app_session.host, '/c3/c3/ops($|/)', port, annotations={
|
|
42
|
-
'kubernetes.io/ingress.class': 'nginx',
|
|
43
|
-
'nginx.ingress.kubernetes.io/use-regex': 'true',
|
|
44
|
-
'nginx.ingress.kubernetes.io/rewrite-target': '/'
|
|
45
|
-
})
|
|
46
|
-
except Exception as e:
|
|
47
|
-
if e.status == 409:
|
|
48
|
-
log2(f"Error: '{name}' already exists in namespace '{state.namespace}'.")
|
|
49
|
-
else:
|
|
50
|
-
log2(f"Error creating ingress or service: {e}")
|
|
51
|
-
|
|
52
|
-
return state
|
|
53
|
-
|
|
54
|
-
def completion(self, _: ReplState):
|
|
55
|
-
return {}
|
|
56
|
-
|
|
57
|
-
def help(self, _: ReplState):
|
|
58
|
-
return f'{SetupFrontend.COMMAND}\t sets up frontend'
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import click
|
|
2
|
-
|
|
3
|
-
from adam.commands.command import Command
|
|
4
|
-
from adam.commands.command_helpers import ClusterCommandHelper
|
|
5
|
-
from adam.commands.frontend.teardown_frontend import TearDownFrontend
|
|
6
|
-
from .setup_frontend import SetupFrontend
|
|
7
|
-
from adam.repl_state import ReplState
|
|
8
|
-
from adam.utils import lines_to_tabular, log, log2
|
|
9
|
-
|
|
10
|
-
class TearDown(Command):
|
|
11
|
-
COMMAND = 'teardown'
|
|
12
|
-
reaper_login = None
|
|
13
|
-
|
|
14
|
-
# the singleton pattern
|
|
15
|
-
def __new__(cls, *args, **kwargs):
|
|
16
|
-
if not hasattr(cls, 'instance'): cls.instance = super(TearDown, cls).__new__(cls)
|
|
17
|
-
|
|
18
|
-
return cls.instance
|
|
19
|
-
|
|
20
|
-
def __init__(self, successor: Command=None):
|
|
21
|
-
super().__init__(successor)
|
|
22
|
-
|
|
23
|
-
def command(self):
|
|
24
|
-
return TearDown.COMMAND
|
|
25
|
-
|
|
26
|
-
def run(self, cmd: str, state: ReplState):
|
|
27
|
-
if not(args := self.args(cmd)):
|
|
28
|
-
return super().run(cmd, state)
|
|
29
|
-
|
|
30
|
-
state, args = self.apply_state(args, state)
|
|
31
|
-
|
|
32
|
-
if state.in_repl:
|
|
33
|
-
log(lines_to_tabular([c.help(ReplState()) for c in TearDown.cmd_list()], separator=':'))
|
|
34
|
-
|
|
35
|
-
return 'command-missing'
|
|
36
|
-
else:
|
|
37
|
-
# head with the Chain of Responsibility pattern
|
|
38
|
-
cmds = Command.chain(TearDown.cmd_list())
|
|
39
|
-
if not cmds.run(cmd, state):
|
|
40
|
-
log2('* Command is missing.')
|
|
41
|
-
Command.display_help()
|
|
42
|
-
|
|
43
|
-
def cmd_list():
|
|
44
|
-
return [TearDownFrontend()]
|
|
45
|
-
|
|
46
|
-
def completion(self, state: ReplState):
|
|
47
|
-
if state.sts:
|
|
48
|
-
return super().completion(state)
|
|
49
|
-
|
|
50
|
-
return {}
|
|
51
|
-
|
|
52
|
-
def help(self, _: ReplState):
|
|
53
|
-
return None
|
|
54
|
-
|
|
55
|
-
class TearDownCommandHelper(click.Command):
|
|
56
|
-
def get_help(self, ctx: click.Context):
|
|
57
|
-
log(super().get_help(ctx))
|
|
58
|
-
log()
|
|
59
|
-
log('Sub-Commands:')
|
|
60
|
-
|
|
61
|
-
log(lines_to_tabular([c.help(ReplState()).replace(f'{TearDown.COMMAND} ', ' ', 1) for c in TearDown.cmd_list()], separator=':'))
|
|
@@ -1,225 +0,0 @@
|
|
|
1
|
-
import functools
|
|
2
|
-
import re
|
|
3
|
-
import subprocess
|
|
4
|
-
|
|
5
|
-
from adam.config import Config
|
|
6
|
-
from adam.k8s_utils.kube_context import KubeContext
|
|
7
|
-
from adam.k8s_utils.pods import Pods
|
|
8
|
-
from adam.k8s_utils.secrets import Secrets
|
|
9
|
-
from adam.utils import log2
|
|
10
|
-
|
|
11
|
-
class PostgresSession:
|
|
12
|
-
def __init__(self, ns: str, path: str):
|
|
13
|
-
self.namespace = ns
|
|
14
|
-
self.conn_details = None
|
|
15
|
-
self.host = None
|
|
16
|
-
self.db = None
|
|
17
|
-
|
|
18
|
-
if path:
|
|
19
|
-
tks = path.split('/')
|
|
20
|
-
hn = tks[0].split('@')
|
|
21
|
-
self.host = hn[0]
|
|
22
|
-
if len(hn) > 1 and not ns:
|
|
23
|
-
self.namespace = hn[1]
|
|
24
|
-
|
|
25
|
-
if len(tks) > 1:
|
|
26
|
-
self.db = tks[1]
|
|
27
|
-
|
|
28
|
-
# work for databases()
|
|
29
|
-
def __eq__(self, other: 'PostgresSession'):
|
|
30
|
-
return self.host == other.host
|
|
31
|
-
|
|
32
|
-
def __hash__(self):
|
|
33
|
-
return hash(self.host)
|
|
34
|
-
|
|
35
|
-
def find_namespace(self, arg: str):
|
|
36
|
-
if arg:
|
|
37
|
-
tks = arg.split('@')
|
|
38
|
-
if len(tks) > 1:
|
|
39
|
-
return tks[1]
|
|
40
|
-
|
|
41
|
-
return None
|
|
42
|
-
|
|
43
|
-
def directory(self, arg: str = None):
|
|
44
|
-
if arg:
|
|
45
|
-
if arg == '..':
|
|
46
|
-
if self.db:
|
|
47
|
-
self.db = None
|
|
48
|
-
else:
|
|
49
|
-
self.host = None
|
|
50
|
-
else:
|
|
51
|
-
tks = arg.split('@')
|
|
52
|
-
arg = tks[0]
|
|
53
|
-
if not self.host:
|
|
54
|
-
self.host = arg
|
|
55
|
-
else:
|
|
56
|
-
self.db = arg
|
|
57
|
-
|
|
58
|
-
if not self.host:
|
|
59
|
-
return None
|
|
60
|
-
|
|
61
|
-
d = self.host
|
|
62
|
-
if not self.db:
|
|
63
|
-
return d
|
|
64
|
-
|
|
65
|
-
return f'{self.host}/{self.db}'
|
|
66
|
-
|
|
67
|
-
def hosts(ns: str):
|
|
68
|
-
return PostgresSession.hosts_for_namespace(ns)
|
|
69
|
-
|
|
70
|
-
@functools.lru_cache()
|
|
71
|
-
def hosts_for_namespace(ns: str):
|
|
72
|
-
ss = Secrets.list_secrets(ns, name_pattern=Config().get('pg.name-pattern', '^{namespace}.*k8spg.*'))
|
|
73
|
-
|
|
74
|
-
def excludes(name: str):
|
|
75
|
-
exs = Config().get('pg.excludes', '.helm., -admin-secret')
|
|
76
|
-
if exs:
|
|
77
|
-
for ex in exs.split(','):
|
|
78
|
-
if ex.strip(' ') in name:
|
|
79
|
-
return True
|
|
80
|
-
|
|
81
|
-
return False
|
|
82
|
-
|
|
83
|
-
return [s for s in ss if not excludes(s)]
|
|
84
|
-
|
|
85
|
-
@functools.lru_cache()
|
|
86
|
-
def databases(self):
|
|
87
|
-
dbs = []
|
|
88
|
-
# List of databases
|
|
89
|
-
# Name | Owner | Encoding | Collate | Ctype | ICU Locale | Locale Provider | Access privileges
|
|
90
|
-
# ---------------------------------------+----------+----------+-------------+-------------+------------+-----------------+-----------------------
|
|
91
|
-
# postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc |
|
|
92
|
-
# stgawsscpsr_c3_c3 | postgres | UTF8 | C | C | | libc |
|
|
93
|
-
# template1 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc | =c/postgres +
|
|
94
|
-
# | | | | | | | postgres=CTc/postgres
|
|
95
|
-
# (48 rows)
|
|
96
|
-
r = self.run_sql('\l', show_out=False)
|
|
97
|
-
s = 0
|
|
98
|
-
for line in r.stdout.split('\n'):
|
|
99
|
-
line: str = line.strip(' \r')
|
|
100
|
-
if s == 0:
|
|
101
|
-
if 'List of databases' in line:
|
|
102
|
-
s = 1
|
|
103
|
-
elif s == 1:
|
|
104
|
-
if 'Name' in line and 'Owner' in line and 'Encoding' in line:
|
|
105
|
-
s = 2
|
|
106
|
-
elif s == 2:
|
|
107
|
-
if line.startswith('---------'):
|
|
108
|
-
s = 3
|
|
109
|
-
elif s == 3:
|
|
110
|
-
groups = re.match(r'^\s*(\S*)\s*\|\s*(\S*)\s*\|.*', line)
|
|
111
|
-
if groups and groups[1] != '|':
|
|
112
|
-
dbs.append({'name': groups[1], 'owner': groups[2]})
|
|
113
|
-
|
|
114
|
-
return dbs
|
|
115
|
-
|
|
116
|
-
def tables(self):
|
|
117
|
-
dbs = []
|
|
118
|
-
# List of relations
|
|
119
|
-
# Schema | Name | Type | Owner
|
|
120
|
-
# ----------+------------------------------------------------------------+-------+---------------
|
|
121
|
-
# postgres | c3_2_admin_aclpriv | table | postgres
|
|
122
|
-
# postgres | c3_2_admin_aclpriv_a | table | postgres
|
|
123
|
-
r = self.run_sql('\dt', show_out=False)
|
|
124
|
-
s = 0
|
|
125
|
-
for line in r.stdout.split('\n'):
|
|
126
|
-
line: str = line.strip(' \r')
|
|
127
|
-
if s == 0:
|
|
128
|
-
if 'List of relations' in line:
|
|
129
|
-
s = 1
|
|
130
|
-
elif s == 1:
|
|
131
|
-
if 'Schema' in line and 'Name' in line and 'Type' in line:
|
|
132
|
-
s = 2
|
|
133
|
-
elif s == 2:
|
|
134
|
-
if line.startswith('---------'):
|
|
135
|
-
s = 3
|
|
136
|
-
elif s == 3:
|
|
137
|
-
groups = re.match(r'^\s*(\S*)\s*\|\s*(\S*)\s*\|.*', line)
|
|
138
|
-
if groups and groups[1] != '|':
|
|
139
|
-
dbs.append({'schema': groups[1], 'name': groups[2]})
|
|
140
|
-
|
|
141
|
-
return dbs
|
|
142
|
-
|
|
143
|
-
def run_sql(self, sql: str, show_out = True):
|
|
144
|
-
db = self.db if self.db else PostgresSession.default_db()
|
|
145
|
-
|
|
146
|
-
if KubeContext.in_cluster():
|
|
147
|
-
cmd1 = f'env PGPASSWORD={self.password()} psql -h {self.endpoint()} -p {self.port()} -U {self.username()} {db} --pset pager=off -c'
|
|
148
|
-
log2(f'{cmd1} "{sql}"')
|
|
149
|
-
# remove double quotes from the sql argument
|
|
150
|
-
cmd = cmd1.split(' ') + [sql]
|
|
151
|
-
r = subprocess.run(cmd, capture_output=True, text=True)
|
|
152
|
-
if show_out:
|
|
153
|
-
log2(r.stdout)
|
|
154
|
-
log2(r.stderr)
|
|
155
|
-
|
|
156
|
-
return r
|
|
157
|
-
else:
|
|
158
|
-
ns = self.namespace
|
|
159
|
-
image = Config().get('pg.agent.image', 'seanahnsf/kaqing')
|
|
160
|
-
pod_name = Config().get('pg.agent.name', 'kaqing-agent')
|
|
161
|
-
timeout = Config().get('pg.agent.timeout', 3600)
|
|
162
|
-
|
|
163
|
-
try:
|
|
164
|
-
Pods.create(ns, pod_name, image, ['sleep', f'{timeout}'], env={'NAMESPACE': ns}, sa_name='c3')
|
|
165
|
-
except Exception as e:
|
|
166
|
-
if e.status == 409:
|
|
167
|
-
if Pods.completed(ns, pod_name):
|
|
168
|
-
try:
|
|
169
|
-
Pods.delete(pod_name, ns)
|
|
170
|
-
Pods.create(ns, pod_name, image, ['sleep', f'{timeout}'], env={'NAMESPACE': ns}, sa_name='c3')
|
|
171
|
-
except Exception as e2:
|
|
172
|
-
log2("Exception when calling BatchV1Api->create_pod: %s\n" % e2)
|
|
173
|
-
|
|
174
|
-
return
|
|
175
|
-
else:
|
|
176
|
-
log2("Exception when calling BatchV1Api->create_pod: %s\n" % e)
|
|
177
|
-
|
|
178
|
-
return
|
|
179
|
-
|
|
180
|
-
Pods.wait_for_running(ns, pod_name)
|
|
181
|
-
|
|
182
|
-
cmd = f'PGPASSWORD="{self.password()}" psql -h {self.endpoint()} -p {self.port()} -U {self.username()} {db} --pset pager=off -c "{sql}"'
|
|
183
|
-
|
|
184
|
-
return Pods.exec(pod_name, pod_name, ns, cmd, show_out=show_out)
|
|
185
|
-
|
|
186
|
-
def endpoint(self):
|
|
187
|
-
if not self.conn_details:
|
|
188
|
-
self.conn_details = Secrets.get_data(self.namespace, self.host)
|
|
189
|
-
|
|
190
|
-
endpoint_key = Config().get('pg.secret.endpoint-key', 'postgres-db-endpoint')
|
|
191
|
-
|
|
192
|
-
return self.conn_details[endpoint_key] if endpoint_key in self.conn_details else ''
|
|
193
|
-
|
|
194
|
-
def port(self):
|
|
195
|
-
if not self.conn_details:
|
|
196
|
-
self.conn_details = Secrets.get_data(self.namespace, self.host)
|
|
197
|
-
|
|
198
|
-
port_key = Config().get('pg.secret.port-key', 'postgres-db-port')
|
|
199
|
-
|
|
200
|
-
return self.conn_details[port_key] if port_key in self.conn_details else ''
|
|
201
|
-
|
|
202
|
-
def username(self):
|
|
203
|
-
if not self.conn_details:
|
|
204
|
-
self.conn_details = Secrets.get_data(self.namespace, self.host)
|
|
205
|
-
|
|
206
|
-
username_key = Config().get('pg.secret.username-key', 'postgres-admin-username')
|
|
207
|
-
|
|
208
|
-
return self.conn_details[username_key] if username_key in self.conn_details else ''
|
|
209
|
-
|
|
210
|
-
def password(self):
|
|
211
|
-
if not self.conn_details:
|
|
212
|
-
self.conn_details = Secrets.get_data(self.namespace, self.host)
|
|
213
|
-
|
|
214
|
-
password_key = Config().get('pg.secret.password-key', 'postgres-admin-password')
|
|
215
|
-
|
|
216
|
-
return self.conn_details[password_key] if password_key in self.conn_details else ''
|
|
217
|
-
|
|
218
|
-
def default_db():
|
|
219
|
-
return Config().get('pg.default-db', 'postgres')
|
|
220
|
-
|
|
221
|
-
def default_owner():
|
|
222
|
-
return Config().get('pg.default-owner', 'postgres')
|
|
223
|
-
|
|
224
|
-
def default_schema():
|
|
225
|
-
return Config().get('pg.default-schema', 'postgres')
|
adam/commands/user_entry.py
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import signal
|
|
3
|
-
import traceback
|
|
4
|
-
|
|
5
|
-
from adam.config import Config
|
|
6
|
-
from adam.sso.idp import Idp
|
|
7
|
-
from adam.app_session import AppSession, IdpLogin
|
|
8
|
-
from adam.apps import Apps
|
|
9
|
-
from adam.commands.command import Command
|
|
10
|
-
from adam.repl_state import ReplState
|
|
11
|
-
from adam.utils import log2
|
|
12
|
-
|
|
13
|
-
class UserEntry(Command):
|
|
14
|
-
COMMAND = 'entry'
|
|
15
|
-
|
|
16
|
-
# the singleton pattern
|
|
17
|
-
def __new__(cls, *args, **kwargs):
|
|
18
|
-
if not hasattr(cls, 'instance'): cls.instance = super(UserEntry, cls).__new__(cls)
|
|
19
|
-
|
|
20
|
-
return cls.instance
|
|
21
|
-
|
|
22
|
-
def __init__(self, successor: Command=None):
|
|
23
|
-
super().__init__(successor)
|
|
24
|
-
|
|
25
|
-
def command(self):
|
|
26
|
-
return UserEntry.COMMAND
|
|
27
|
-
|
|
28
|
-
def run(self, cmd: str, state: ReplState):
|
|
29
|
-
def custom_handler(signum, frame):
|
|
30
|
-
AppSession.ctrl_c_entered = True
|
|
31
|
-
|
|
32
|
-
signal.signal(signal.SIGINT, custom_handler)
|
|
33
|
-
|
|
34
|
-
if not(args := self.args(cmd)):
|
|
35
|
-
return super().run(cmd, state)
|
|
36
|
-
|
|
37
|
-
state, args = self.apply_state(args, state)
|
|
38
|
-
args, debug = Command.extract_options(args, 'd')
|
|
39
|
-
if debug:
|
|
40
|
-
Config().set('debug.show-out', True)
|
|
41
|
-
|
|
42
|
-
username: str = None
|
|
43
|
-
if len(args) > 0:
|
|
44
|
-
username = args[0]
|
|
45
|
-
|
|
46
|
-
login: IdpLogin = None
|
|
47
|
-
while not login:
|
|
48
|
-
try:
|
|
49
|
-
if not(host := Apps.app_host('c3', 'c3', state.namespace)):
|
|
50
|
-
log2('Cannot locate ingress for app.')
|
|
51
|
-
username = None
|
|
52
|
-
continue
|
|
53
|
-
|
|
54
|
-
if not (login := Idp.login(host, username=username, use_token_from_env=False)):
|
|
55
|
-
log2('Invalid username/password. Please try again.')
|
|
56
|
-
username = None
|
|
57
|
-
except Exception as e:
|
|
58
|
-
log2(e)
|
|
59
|
-
|
|
60
|
-
Config().debug(traceback.format_exc())
|
|
61
|
-
|
|
62
|
-
sh = f'{os.getcwd()}/login.sh'
|
|
63
|
-
if not os.path.exists(sh):
|
|
64
|
-
sh = f'{os.getcwd()}/docker/login.sh'
|
|
65
|
-
|
|
66
|
-
if os.getenv('PASS_DOWN_IDP_TOKEN', "true").lower() == "true":
|
|
67
|
-
os.system(f'{sh} {login.shell_user()} {login.ser()}')
|
|
68
|
-
else:
|
|
69
|
-
os.system(f'{sh} {login.shell_user()}')
|
|
70
|
-
|
|
71
|
-
return state
|
|
72
|
-
|
|
73
|
-
def completion(self, _: ReplState):
|
|
74
|
-
return {}
|
|
75
|
-
|
|
76
|
-
def help(self, _: ReplState):
|
|
77
|
-
return f'{UserEntry.COMMAND}\t ttyd user entry'
|