kaqing 2.0.98__py3-none-any.whl → 2.0.171__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- adam/__init__.py +0 -2
- adam/app_session.py +9 -7
- adam/batch.py +4 -18
- adam/checks/check_utils.py +14 -46
- adam/checks/cpu.py +7 -1
- adam/checks/cpu_metrics.py +52 -0
- adam/columns/columns.py +3 -1
- adam/columns/cpu.py +3 -1
- adam/columns/cpu_metrics.py +22 -0
- adam/commands/__init__.py +15 -0
- adam/commands/alter_tables.py +50 -61
- adam/commands/app_cmd.py +38 -0
- adam/commands/app_ping.py +8 -14
- adam/commands/audit/audit.py +43 -30
- adam/commands/audit/audit_repair_tables.py +26 -46
- adam/commands/audit/audit_run.py +50 -0
- adam/commands/audit/show_last10.py +48 -0
- adam/commands/audit/show_slow10.py +47 -0
- adam/commands/audit/show_top10.py +45 -0
- adam/commands/audit/utils_show_top10.py +59 -0
- adam/commands/bash/__init__.py +5 -0
- adam/commands/bash/bash.py +36 -0
- adam/commands/bash/bash_completer.py +93 -0
- adam/commands/bash/utils_bash.py +16 -0
- adam/commands/cat.py +50 -0
- adam/commands/cd.py +15 -91
- adam/commands/check.py +23 -18
- adam/commands/cli_commands.py +2 -3
- adam/commands/code.py +57 -0
- adam/commands/command.py +96 -40
- adam/commands/commands_utils.py +9 -19
- adam/commands/cp.py +33 -39
- adam/commands/cql/cql_completions.py +30 -8
- adam/commands/cql/cqlsh.py +12 -27
- adam/commands/cql/utils_cql.py +343 -0
- adam/commands/deploy/code_start.py +7 -10
- adam/commands/deploy/code_stop.py +4 -21
- adam/commands/deploy/code_utils.py +3 -3
- adam/commands/deploy/deploy.py +4 -21
- adam/commands/deploy/deploy_frontend.py +14 -17
- adam/commands/deploy/deploy_pg_agent.py +3 -6
- adam/commands/deploy/deploy_pod.py +67 -73
- adam/commands/deploy/deploy_utils.py +14 -24
- adam/commands/deploy/undeploy.py +4 -21
- adam/commands/deploy/undeploy_frontend.py +4 -7
- adam/commands/deploy/undeploy_pg_agent.py +6 -8
- adam/commands/deploy/undeploy_pod.py +11 -12
- adam/commands/devices/device.py +118 -0
- adam/commands/devices/device_app.py +173 -0
- adam/commands/devices/device_auit_log.py +49 -0
- adam/commands/devices/device_cass.py +185 -0
- adam/commands/devices/device_export.py +86 -0
- adam/commands/devices/device_postgres.py +144 -0
- adam/commands/devices/devices.py +25 -0
- adam/commands/exit.py +1 -4
- adam/commands/export/__init__.py +0 -0
- adam/commands/export/clean_up_all_export_sessions.py +37 -0
- adam/commands/export/clean_up_export_sessions.py +51 -0
- adam/commands/export/drop_export_database.py +55 -0
- adam/commands/export/drop_export_databases.py +43 -0
- adam/commands/export/export.py +53 -0
- adam/commands/export/export_databases.py +170 -0
- adam/commands/export/export_handlers.py +71 -0
- adam/commands/export/export_select.py +81 -0
- adam/commands/export/export_select_x.py +54 -0
- adam/commands/export/export_use.py +52 -0
- adam/commands/export/exporter.py +352 -0
- adam/commands/export/import_session.py +40 -0
- adam/commands/export/importer.py +67 -0
- adam/commands/export/importer_athena.py +80 -0
- adam/commands/export/importer_sqlite.py +47 -0
- adam/commands/export/show_column_counts.py +54 -0
- adam/commands/export/show_export_databases.py +36 -0
- adam/commands/export/show_export_session.py +48 -0
- adam/commands/export/show_export_sessions.py +44 -0
- adam/commands/export/utils_export.py +314 -0
- adam/commands/help.py +10 -6
- adam/commands/intermediate_command.py +49 -0
- adam/commands/issues.py +14 -40
- adam/commands/kubectl.py +38 -0
- adam/commands/login.py +28 -24
- adam/commands/logs.py +4 -6
- adam/commands/ls.py +11 -116
- adam/commands/medusa/medusa.py +4 -22
- adam/commands/medusa/medusa_backup.py +20 -24
- adam/commands/medusa/medusa_restore.py +30 -32
- adam/commands/medusa/medusa_show_backupjobs.py +16 -17
- adam/commands/medusa/medusa_show_restorejobs.py +12 -17
- adam/commands/nodetool.py +11 -17
- adam/commands/param_get.py +11 -12
- adam/commands/param_set.py +9 -10
- adam/commands/postgres/postgres.py +43 -36
- adam/commands/postgres/{postgres_session.py → postgres_context.py} +80 -46
- adam/commands/postgres/postgres_ls.py +4 -8
- adam/commands/postgres/postgres_preview.py +5 -9
- adam/commands/postgres/psql_completions.py +2 -2
- adam/commands/postgres/utils_postgres.py +66 -0
- adam/commands/preview_table.py +8 -61
- adam/commands/pwd.py +14 -44
- adam/commands/reaper/reaper.py +4 -24
- adam/commands/reaper/reaper_forward.py +48 -55
- adam/commands/reaper/reaper_forward_session.py +6 -0
- adam/commands/reaper/reaper_forward_stop.py +10 -16
- adam/commands/reaper/reaper_restart.py +7 -14
- adam/commands/reaper/reaper_run_abort.py +11 -30
- adam/commands/reaper/reaper_runs.py +42 -57
- adam/commands/reaper/reaper_runs_abort.py +29 -49
- adam/commands/reaper/reaper_schedule_activate.py +11 -30
- adam/commands/reaper/reaper_schedule_start.py +10 -29
- adam/commands/reaper/reaper_schedule_stop.py +10 -29
- adam/commands/reaper/reaper_schedules.py +4 -14
- adam/commands/reaper/reaper_status.py +8 -16
- adam/commands/reaper/utils_reaper.py +196 -0
- adam/commands/repair/repair.py +4 -22
- adam/commands/repair/repair_log.py +4 -7
- adam/commands/repair/repair_run.py +27 -29
- adam/commands/repair/repair_scan.py +31 -34
- adam/commands/repair/repair_stop.py +4 -7
- adam/commands/report.py +25 -21
- adam/commands/restart.py +25 -26
- adam/commands/rollout.py +19 -24
- adam/commands/shell.py +5 -4
- adam/commands/show/show.py +6 -19
- adam/commands/show/show_app_actions.py +26 -22
- adam/commands/show/show_app_id.py +8 -11
- adam/commands/show/show_app_queues.py +7 -10
- adam/commands/show/{show_repairs.py → show_cassandra_repairs.py} +8 -17
- adam/commands/show/show_cassandra_status.py +29 -33
- adam/commands/show/show_cassandra_version.py +4 -14
- adam/commands/show/show_commands.py +19 -21
- adam/commands/show/show_host.py +1 -1
- adam/commands/show/show_login.py +26 -24
- adam/commands/show/show_processes.py +16 -18
- adam/commands/show/show_storage.py +10 -20
- adam/commands/watch.py +26 -29
- adam/config.py +5 -14
- adam/embedded_params.py +1 -1
- adam/pod_exec_result.py +7 -1
- adam/repl.py +95 -131
- adam/repl_commands.py +48 -20
- adam/repl_state.py +270 -61
- adam/sql/sql_completer.py +105 -63
- adam/sql/sql_state_machine.py +618 -0
- adam/sql/term_completer.py +3 -0
- adam/sso/authn_ad.py +6 -5
- adam/sso/authn_okta.py +3 -3
- adam/sso/cred_cache.py +3 -2
- adam/sso/idp.py +3 -3
- adam/utils.py +439 -3
- adam/utils_app.py +98 -0
- adam/utils_athena.py +140 -87
- adam/utils_audits.py +106 -0
- adam/utils_issues.py +32 -0
- adam/utils_k8s/app_clusters.py +28 -0
- adam/utils_k8s/app_pods.py +33 -0
- adam/utils_k8s/cassandra_clusters.py +22 -20
- adam/utils_k8s/cassandra_nodes.py +4 -4
- adam/utils_k8s/custom_resources.py +5 -0
- adam/utils_k8s/ingresses.py +2 -2
- adam/utils_k8s/k8s.py +87 -0
- adam/utils_k8s/pods.py +77 -68
- adam/utils_k8s/secrets.py +4 -4
- adam/utils_k8s/service_accounts.py +5 -4
- adam/utils_k8s/services.py +2 -2
- adam/utils_k8s/statefulsets.py +1 -12
- adam/utils_net.py +4 -4
- adam/utils_repl/__init__.py +0 -0
- adam/utils_repl/automata_completer.py +48 -0
- adam/utils_repl/repl_completer.py +46 -0
- adam/utils_repl/state_machine.py +173 -0
- adam/utils_sqlite.py +109 -0
- adam/version.py +1 -1
- {kaqing-2.0.98.dist-info → kaqing-2.0.171.dist-info}/METADATA +1 -1
- kaqing-2.0.171.dist-info/RECORD +236 -0
- adam/commands/app.py +0 -67
- adam/commands/bash.py +0 -92
- adam/commands/cql/cql_table_completer.py +0 -8
- adam/commands/cql/cql_utils.py +0 -115
- adam/commands/describe/describe.py +0 -47
- adam/commands/describe/describe_keyspace.py +0 -60
- adam/commands/describe/describe_keyspaces.py +0 -49
- adam/commands/describe/describe_schema.py +0 -49
- adam/commands/describe/describe_table.py +0 -60
- adam/commands/describe/describe_tables.py +0 -49
- adam/commands/devices.py +0 -118
- adam/commands/postgres/postgres_utils.py +0 -31
- adam/commands/postgres/psql_table_completer.py +0 -11
- adam/commands/reaper/reaper_session.py +0 -159
- adam/sql/state_machine.py +0 -460
- kaqing-2.0.98.dist-info/RECORD +0 -191
- /adam/commands/{describe → devices}/__init__.py +0 -0
- {kaqing-2.0.98.dist-info → kaqing-2.0.171.dist-info}/WHEEL +0 -0
- {kaqing-2.0.98.dist-info → kaqing-2.0.171.dist-info}/entry_points.txt +0 -0
- {kaqing-2.0.98.dist-info → kaqing-2.0.171.dist-info}/top_level.txt +0 -0
adam/repl_commands.py
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
from adam.commands.alter_tables import AlterTables
|
|
2
|
-
from adam.commands.
|
|
2
|
+
from adam.commands.app_cmd import App
|
|
3
3
|
from adam.commands.app_ping import AppPing
|
|
4
4
|
from adam.commands.audit.audit import Audit
|
|
5
|
-
from adam.commands.
|
|
5
|
+
from adam.commands.cat import Cat
|
|
6
|
+
from adam.commands.code import Code
|
|
6
7
|
from adam.commands.deploy.code_start import CodeStart
|
|
7
8
|
from adam.commands.deploy.code_stop import CodeStop
|
|
8
9
|
from adam.commands.deploy.deploy import Deploy
|
|
@@ -13,23 +14,40 @@ from adam.commands.deploy.undeploy import Undeploy
|
|
|
13
14
|
from adam.commands.deploy.undeploy_frontend import UndeployFrontend
|
|
14
15
|
from adam.commands.deploy.undeploy_pg_agent import UndeployPgAgent
|
|
15
16
|
from adam.commands.deploy.undeploy_pod import UndeployPod
|
|
16
|
-
from adam.commands.
|
|
17
|
+
from adam.commands.devices.device_app import DeviceApp
|
|
18
|
+
from adam.commands.devices.device_auit_log import DeviceAuditLog
|
|
19
|
+
from adam.commands.devices.device_cass import DeviceCass
|
|
20
|
+
from adam.commands.devices.device_export import DeviceExport
|
|
21
|
+
from adam.commands.devices.device_postgres import DevicePostgres
|
|
22
|
+
from adam.commands.export.drop_export_database import DropExportDatabase
|
|
23
|
+
from adam.commands.export.export import ExportTables
|
|
24
|
+
from adam.commands.export.import_session import ImportSession
|
|
25
|
+
from adam.commands.export.clean_up_export_sessions import CleanUpExportSessions
|
|
26
|
+
from adam.commands.export.clean_up_all_export_sessions import CleanUpAllExportSessions
|
|
27
|
+
from adam.commands.export.drop_export_databases import DropExportDatabases
|
|
28
|
+
from adam.commands.export.export_select import ExportSelect
|
|
29
|
+
from adam.commands.export.export_use import ExportUse
|
|
30
|
+
from adam.commands.export.export_select_x import ExportSelectX
|
|
31
|
+
from adam.commands.export.show_column_counts import ShowColumnCounts
|
|
32
|
+
from adam.commands.export.show_export_databases import ShowExportDatabases
|
|
33
|
+
from adam.commands.export.show_export_session import ShowExportSession
|
|
34
|
+
from adam.commands.export.show_export_sessions import ShowExportSessions
|
|
35
|
+
from adam.commands.kubectl import Kubectl
|
|
17
36
|
from adam.commands.shell import Shell
|
|
18
37
|
from adam.commands.show.show_app_queues import ShowAppQueues
|
|
19
38
|
from adam.commands.cp import ClipboardCopy
|
|
20
|
-
from adam.commands.bash import Bash
|
|
39
|
+
from adam.commands.bash.bash import Bash
|
|
21
40
|
from adam.commands.cd import Cd
|
|
22
41
|
from adam.commands.check import Check
|
|
23
42
|
from adam.commands.command import Command
|
|
24
43
|
from adam.commands.cql.cqlsh import Cqlsh
|
|
25
|
-
from adam.commands.devices import DeviceApp, DeviceAuditLog, DeviceCass, DevicePostgres
|
|
26
44
|
from adam.commands.exit import Exit
|
|
27
45
|
from adam.commands.medusa.medusa import Medusa
|
|
28
46
|
from adam.commands.param_get import GetParam
|
|
29
47
|
from adam.commands.issues import Issues
|
|
30
48
|
from adam.commands.ls import Ls
|
|
31
49
|
from adam.commands.nodetool import NodeTool
|
|
32
|
-
from adam.commands.postgres.postgres import Postgres
|
|
50
|
+
from adam.commands.postgres.postgres import Postgres, PostgresPg
|
|
33
51
|
from adam.commands.preview_table import PreviewTable
|
|
34
52
|
from adam.commands.pwd import Pwd
|
|
35
53
|
from adam.commands.reaper.reaper import Reaper
|
|
@@ -48,17 +66,17 @@ from adam.commands.show.show_host import ShowHost
|
|
|
48
66
|
from adam.commands.show.show_login import ShowLogin
|
|
49
67
|
from adam.commands.show.show_params import ShowParams
|
|
50
68
|
from adam.commands.show.show_processes import ShowProcesses
|
|
51
|
-
from adam.commands.show.
|
|
69
|
+
from adam.commands.show.show_cassandra_repairs import ShowCassandraRepairs
|
|
52
70
|
from adam.commands.show.show_storage import ShowStorage
|
|
53
71
|
from adam.commands.show.show_adam import ShowAdam
|
|
54
72
|
from adam.commands.watch import Watch
|
|
55
73
|
|
|
56
74
|
class ReplCommands:
|
|
57
75
|
def repl_cmd_list() -> list[Command]:
|
|
58
|
-
cmds: list[Command] = ReplCommands.navigation() + ReplCommands.
|
|
59
|
-
ReplCommands.
|
|
76
|
+
cmds: list[Command] = ReplCommands.navigation() + ReplCommands.cassandra_ops() + ReplCommands.postgres_ops() + \
|
|
77
|
+
ReplCommands.app_ops() + ReplCommands.audit_ops() + ReplCommands.export_ops() + ReplCommands.tools() + ReplCommands.exit()
|
|
60
78
|
|
|
61
|
-
intermediate_cmds: list[Command] = [App(),
|
|
79
|
+
intermediate_cmds: list[Command] = [App(), Audit(), Reaper(), Repair(), Deploy(), Show(), Undeploy()]
|
|
62
80
|
ic = [c.command() for c in intermediate_cmds]
|
|
63
81
|
# 1. dedup commands
|
|
64
82
|
deduped = []
|
|
@@ -75,22 +93,32 @@ class ReplCommands:
|
|
|
75
93
|
return deduped
|
|
76
94
|
|
|
77
95
|
def navigation() -> list[Command]:
|
|
78
|
-
return [Ls(), PreviewTable(), DeviceApp(), DevicePostgres(), DeviceCass(), DeviceAuditLog(), Cd(), Pwd(), ClipboardCopy(),
|
|
96
|
+
return [Ls(), PreviewTable(), DeviceApp(), DevicePostgres(), DeviceCass(), DeviceAuditLog(), DeviceExport(), Cd(), Cat(), Pwd(), ClipboardCopy(),
|
|
79
97
|
GetParam(), SetParam(), ShowParams(), ShowKubectlCommands(), ShowLogin(), ShowAdam(), ShowHost()]
|
|
80
98
|
|
|
81
|
-
def cassandra_check() -> list[Command]:
|
|
82
|
-
return Describe.cmd_list() + [ShowCassandraStatus(),
|
|
83
|
-
ShowCassandraVersion(), ShowRepairs(), ShowStorage(), ShowProcesses(), Check(), Issues(), NodeTool(), Report()]
|
|
84
|
-
|
|
85
99
|
def cassandra_ops() -> list[Command]:
|
|
86
|
-
return [
|
|
100
|
+
return [Cqlsh(), ShowCassandraStatus(), ShowCassandraVersion(), ShowCassandraRepairs(), ShowStorage(), ShowProcesses(),
|
|
101
|
+
Check(), Issues(), NodeTool(), Report(), AlterTables(), Bash(),
|
|
102
|
+
ExportTables(), ExportSelect(), ExportUse(), ShowExportDatabases(), ShowColumnCounts(),
|
|
103
|
+
DropExportDatabase(), DropExportDatabases(),
|
|
104
|
+
ShowExportSessions(), ShowExportSession(),
|
|
105
|
+
CleanUpExportSessions(), CleanUpAllExportSessions(), ImportSession()] + \
|
|
106
|
+
Medusa().cmd_list() + [Restart(), RollOut(), Watch()] + Reaper().cmd_list() + Repair().cmd_list()
|
|
87
107
|
|
|
88
|
-
def
|
|
89
|
-
return [
|
|
90
|
-
DeployPod(), UndeployPod(), DeployPgAgent(), UndeployPgAgent(), AuditRepairTables(), Audit()]
|
|
108
|
+
def postgres_ops() -> list[Command]:
|
|
109
|
+
return [Postgres(), DeployPgAgent(), UndeployPgAgent(), PostgresPg()]
|
|
91
110
|
|
|
92
|
-
def
|
|
111
|
+
def app_ops() -> list[Command]:
|
|
93
112
|
return [ShowAppActions(), ShowAppId(), ShowAppQueues(), AppPing(), App()]
|
|
94
113
|
|
|
114
|
+
def audit_ops() -> list[Command]:
|
|
115
|
+
return [Audit()] + Audit().cmd_list()
|
|
116
|
+
|
|
117
|
+
def export_ops() -> list[Command]:
|
|
118
|
+
return [ExportSelectX(), DropExportDatabase(), DropExportDatabases(), ShowColumnCounts()]
|
|
119
|
+
|
|
120
|
+
def tools() -> list[Command]:
|
|
121
|
+
return [Shell(), CodeStart(), CodeStop(), DeployFrontend(), UndeployFrontend(), DeployPod(), UndeployPod(), Kubectl(), Code()]
|
|
122
|
+
|
|
95
123
|
def exit() -> list[Command]:
|
|
96
124
|
return [Exit()]
|
adam/repl_state.py
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import copy
|
|
1
|
+
from copy import copy
|
|
2
2
|
from enum import Enum
|
|
3
3
|
import re
|
|
4
|
+
from typing import Callable
|
|
4
5
|
|
|
5
|
-
from adam.commands.postgres.
|
|
6
|
+
from adam.commands.postgres.postgres_context import PostgresContext
|
|
7
|
+
from adam.utils_k8s.app_clusters import AppClusters
|
|
8
|
+
from adam.utils_k8s.app_pods import AppPods
|
|
6
9
|
from adam.utils_k8s.cassandra_clusters import CassandraClusters
|
|
7
10
|
from adam.utils_k8s.cassandra_nodes import CassandraNodes
|
|
8
11
|
from adam.utils_k8s.kube_context import KubeContext
|
|
@@ -17,25 +20,8 @@ class BashSession:
|
|
|
17
20
|
def pwd(self, state: 'ReplState'):
|
|
18
21
|
command = f'cat /tmp/.qing-{self.session_id}'
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
elif state.sts:
|
|
23
|
-
rs = CassandraClusters.exec(state.sts, state.namespace, command, action='bash', show_out=False)
|
|
24
|
-
|
|
25
|
-
dir = None
|
|
26
|
-
for r in rs:
|
|
27
|
-
if r.exit_code(): # if fails to read the session file, ignore
|
|
28
|
-
continue
|
|
29
|
-
|
|
30
|
-
dir0 = r.stdout.strip(' \r\n')
|
|
31
|
-
if dir:
|
|
32
|
-
if dir != dir0:
|
|
33
|
-
log2('Inconsitent working dir found across multiple pods.')
|
|
34
|
-
return None
|
|
35
|
-
else:
|
|
36
|
-
dir = dir0
|
|
37
|
-
|
|
38
|
-
return dir
|
|
23
|
+
with device(state) as pods:
|
|
24
|
+
return pods.exec(command, action='bash', show_out=False)
|
|
39
25
|
|
|
40
26
|
class RequiredState(Enum):
|
|
41
27
|
CLUSTER = 'cluster'
|
|
@@ -44,17 +30,22 @@ class RequiredState(Enum):
|
|
|
44
30
|
NAMESPACE = 'namespace'
|
|
45
31
|
PG_DATABASE = 'pg_database'
|
|
46
32
|
APP_APP = 'app_app'
|
|
33
|
+
EXPORT_DB = 'export_db'
|
|
47
34
|
|
|
48
35
|
class ReplState:
|
|
49
36
|
A = 'a'
|
|
50
37
|
C = 'c'
|
|
51
38
|
L = 'l'
|
|
52
39
|
P = 'p'
|
|
40
|
+
X = 'x'
|
|
41
|
+
|
|
42
|
+
ANY = [A, C, L, P, X]
|
|
43
|
+
NON_L = [A, C, P, X]
|
|
53
44
|
|
|
54
45
|
def __init__(self, device: str = None,
|
|
55
46
|
sts: str = None, pod: str = None, namespace: str = None, ns_sts: str = None,
|
|
56
47
|
pg_path: str = None,
|
|
57
|
-
app_env: str = None, app_app: str = None,
|
|
48
|
+
app_env: str = None, app_app: str = None, app_pod: str = None,
|
|
58
49
|
in_repl = False, bash_session: BashSession = None, remote_dir = None):
|
|
59
50
|
self.namespace = KubeContext.in_cluster_namespace()
|
|
60
51
|
|
|
@@ -64,12 +55,15 @@ class ReplState:
|
|
|
64
55
|
self.pg_path = pg_path
|
|
65
56
|
self.app_env = app_env
|
|
66
57
|
self.app_app = app_app
|
|
58
|
+
self.app_pod = app_pod
|
|
67
59
|
if namespace:
|
|
68
60
|
self.namespace = namespace
|
|
69
61
|
self.in_repl = in_repl
|
|
70
62
|
self.bash_session = bash_session
|
|
71
63
|
self.remote_dir = remote_dir
|
|
72
|
-
|
|
64
|
+
self.original_state: ReplState = None
|
|
65
|
+
|
|
66
|
+
self.export_session: str = None
|
|
73
67
|
|
|
74
68
|
if ns_sts:
|
|
75
69
|
nn = ns_sts.split('@')
|
|
@@ -84,13 +78,51 @@ class ReplState:
|
|
|
84
78
|
def __hash__(self):
|
|
85
79
|
return hash((self.sts, self.pod))
|
|
86
80
|
|
|
81
|
+
def __str__(self):
|
|
82
|
+
msg = ''
|
|
83
|
+
if self.device == ReplState.P:
|
|
84
|
+
msg = f'{ReplState.P}:'
|
|
85
|
+
pg: PostgresContext = PostgresContext.apply(self.namespace, self.pg_path) if self.pg_path else None
|
|
86
|
+
if pg and pg.db:
|
|
87
|
+
msg += pg.db
|
|
88
|
+
elif pg and pg.host:
|
|
89
|
+
msg += pg.host
|
|
90
|
+
elif self.device == ReplState.A:
|
|
91
|
+
msg = f'{ReplState.A}:'
|
|
92
|
+
if self.app_env:
|
|
93
|
+
msg += self.app_env
|
|
94
|
+
if self.app_app:
|
|
95
|
+
msg += f'/{self.app_app}'
|
|
96
|
+
if self.app_pod:
|
|
97
|
+
# azops88-c3-c3-k8sdeploy-appleader-001-79957cf5b6-9k4bw
|
|
98
|
+
group = re.match(r".*?-.*?-.*?-.*?-(.*?-.*?)-.*", self.app_pod)
|
|
99
|
+
msg += '/' + group[1]
|
|
100
|
+
elif self.device == ReplState.L:
|
|
101
|
+
msg = f'{ReplState.L}:'
|
|
102
|
+
elif self.device == ReplState.X:
|
|
103
|
+
msg = f'{ReplState.X}:'
|
|
104
|
+
if self.export_session:
|
|
105
|
+
msg += self.export_session
|
|
106
|
+
else:
|
|
107
|
+
msg = f'{ReplState.C}:'
|
|
108
|
+
if self.pod:
|
|
109
|
+
# cs-d0767a536f-cs-d0767a536f-default-sts-0
|
|
110
|
+
group = re.match(r".*?-.*?-(.*)", self.pod)
|
|
111
|
+
msg += group[1]
|
|
112
|
+
elif self.sts:
|
|
113
|
+
# cs-d0767a536f-cs-d0767a536f-default-sts
|
|
114
|
+
group = re.match(r".*?-.*?-(.*)", self.sts)
|
|
115
|
+
msg += group[1]
|
|
116
|
+
|
|
117
|
+
return msg
|
|
118
|
+
|
|
87
119
|
def apply_args(self, args: list[str], cmd: list[str] = None, resolve_pg = True, args_to_check = 6) -> tuple['ReplState', list[str]]:
|
|
88
120
|
state = self
|
|
89
121
|
|
|
90
122
|
new_args = []
|
|
91
123
|
for index, arg in enumerate(args):
|
|
92
124
|
if index < args_to_check:
|
|
93
|
-
state = copy
|
|
125
|
+
state = copy(state)
|
|
94
126
|
|
|
95
127
|
s, n = KubeContext.is_sts_name(arg)
|
|
96
128
|
if s:
|
|
@@ -128,9 +160,9 @@ class ReplState:
|
|
|
128
160
|
new_args = []
|
|
129
161
|
for index, arg in enumerate(args):
|
|
130
162
|
if index < 6:
|
|
131
|
-
state = copy
|
|
163
|
+
state = copy(state)
|
|
132
164
|
|
|
133
|
-
groups = re.match(r'^([a|c|l|p]):(.*)$', arg)
|
|
165
|
+
groups = re.match(r'^([a|c|l|p|x]):(.*)$', arg)
|
|
134
166
|
if groups:
|
|
135
167
|
if groups[1] == 'p':
|
|
136
168
|
state.device = 'p'
|
|
@@ -149,6 +181,8 @@ class ReplState:
|
|
|
149
181
|
state.namespace = ns
|
|
150
182
|
elif groups[1] == 'l':
|
|
151
183
|
state.device = 'l'
|
|
184
|
+
elif groups[1] == 'x':
|
|
185
|
+
state.device = 'x'
|
|
152
186
|
else:
|
|
153
187
|
state.device = 'a'
|
|
154
188
|
if path := groups[2]:
|
|
@@ -166,84 +200,259 @@ class ReplState:
|
|
|
166
200
|
|
|
167
201
|
return (state, new_args)
|
|
168
202
|
|
|
169
|
-
def validate(self, required: RequiredState =
|
|
170
|
-
if not
|
|
171
|
-
|
|
172
|
-
|
|
203
|
+
def validate(self, required: list[RequiredState] = [], show_err = True):
|
|
204
|
+
if not required:
|
|
205
|
+
return True
|
|
206
|
+
|
|
207
|
+
def default_err():
|
|
208
|
+
if self.in_repl:
|
|
209
|
+
log2(f'Not a valid command on {self.device}: drive.')
|
|
210
|
+
else:
|
|
211
|
+
log2('* on a wrong device.')
|
|
212
|
+
log2()
|
|
213
|
+
display_help()
|
|
214
|
+
|
|
215
|
+
if type(required) is not list:
|
|
216
|
+
valid, err = self._validate(required)
|
|
217
|
+
if valid:
|
|
218
|
+
return True
|
|
219
|
+
|
|
220
|
+
if show_err:
|
|
221
|
+
if err:
|
|
222
|
+
err()
|
|
223
|
+
else:
|
|
224
|
+
default_err()
|
|
225
|
+
|
|
226
|
+
return False
|
|
227
|
+
|
|
228
|
+
devices = [r for r in required if r in [ReplState.L, ReplState.A, ReplState.C, ReplState.P, ReplState.X]]
|
|
229
|
+
non_devices = [r for r in required if r not in [ReplState.L, ReplState.A, ReplState.C, ReplState.P, ReplState.X]]
|
|
230
|
+
|
|
231
|
+
first_error: Callable = None
|
|
232
|
+
for r in non_devices:
|
|
233
|
+
valid, err = self._validate(r)
|
|
234
|
+
if valid:
|
|
235
|
+
return True
|
|
236
|
+
|
|
237
|
+
if not first_error:
|
|
238
|
+
first_error = err
|
|
239
|
+
|
|
240
|
+
if devices:
|
|
241
|
+
valid, err = self._validate_device(devices)
|
|
242
|
+
if valid:
|
|
243
|
+
return True
|
|
244
|
+
|
|
245
|
+
if not first_error:
|
|
246
|
+
first_error = err
|
|
247
|
+
|
|
248
|
+
if show_err and first_error:
|
|
249
|
+
if first_error:
|
|
250
|
+
first_error()
|
|
251
|
+
else:
|
|
252
|
+
default_err()
|
|
253
|
+
|
|
254
|
+
return False
|
|
255
|
+
|
|
256
|
+
def _validate(self, required: RequiredState):
|
|
257
|
+
if required == RequiredState.CLUSTER:
|
|
258
|
+
if self.device != ReplState.C:
|
|
259
|
+
return (False, None)
|
|
260
|
+
|
|
261
|
+
if not self.namespace or not self.sts:
|
|
262
|
+
def error():
|
|
173
263
|
if self.in_repl:
|
|
174
264
|
log2('cd to a Cassandra cluster first.')
|
|
175
265
|
else:
|
|
176
266
|
log2('* Cassandra cluster is missing.')
|
|
177
267
|
log2()
|
|
178
268
|
display_help()
|
|
269
|
+
return (False, error)
|
|
179
270
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
271
|
+
elif required == RequiredState.POD:
|
|
272
|
+
if self.device != ReplState.C:
|
|
273
|
+
return (False, None)
|
|
274
|
+
|
|
275
|
+
if not self.namespace or not self.pod:
|
|
276
|
+
def error():
|
|
183
277
|
if self.in_repl:
|
|
184
278
|
log2('cd to a pod first.')
|
|
185
279
|
else:
|
|
186
280
|
log2('* Pod is missing.')
|
|
187
281
|
log2()
|
|
188
282
|
display_help()
|
|
283
|
+
return (False, error)
|
|
284
|
+
|
|
285
|
+
elif required == RequiredState.CLUSTER_OR_POD:
|
|
286
|
+
if self.device != ReplState.C:
|
|
287
|
+
return (False, None)
|
|
189
288
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
if not self.namespace or not self.sts and not self.pod:
|
|
289
|
+
if not self.namespace or not self.sts and not self.pod:
|
|
290
|
+
def error():
|
|
193
291
|
if self.in_repl:
|
|
194
292
|
log2('cd to a Cassandra cluster first.')
|
|
195
293
|
else:
|
|
196
294
|
log2('* Cassandra cluster or pod is missing.')
|
|
197
295
|
log2()
|
|
198
296
|
display_help()
|
|
297
|
+
return (False, error)
|
|
199
298
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
299
|
+
elif required == RequiredState.NAMESPACE:
|
|
300
|
+
if self.device != ReplState.C:
|
|
301
|
+
return (False, None)
|
|
302
|
+
|
|
303
|
+
if not self.namespace:
|
|
304
|
+
def error():
|
|
203
305
|
if self.in_repl:
|
|
204
306
|
log2('Namespace is required.')
|
|
205
307
|
else:
|
|
206
308
|
log2('* namespace is missing.')
|
|
207
309
|
log2()
|
|
208
310
|
display_help()
|
|
311
|
+
return (False, error)
|
|
209
312
|
|
|
210
|
-
|
|
313
|
+
elif required == RequiredState.PG_DATABASE:
|
|
314
|
+
if self.device != ReplState.P:
|
|
315
|
+
return (False, None)
|
|
211
316
|
|
|
212
|
-
|
|
213
|
-
pg = PostgresSession(self.namespace, self.pg_path)
|
|
317
|
+
pg: PostgresContext = PostgresContext.apply(self.namespace, self.pg_path)
|
|
214
318
|
if not pg.db:
|
|
319
|
+
def error():
|
|
320
|
+
if self.in_repl:
|
|
321
|
+
log2('cd to a database first.')
|
|
322
|
+
else:
|
|
323
|
+
log2('* database is missing.')
|
|
324
|
+
log2()
|
|
325
|
+
display_help()
|
|
326
|
+
return (False, error)
|
|
327
|
+
|
|
328
|
+
elif required == RequiredState.APP_APP:
|
|
329
|
+
if self.device != ReplState.A:
|
|
330
|
+
return (False, None)
|
|
331
|
+
|
|
332
|
+
if not self.app_app:
|
|
333
|
+
def error():
|
|
334
|
+
if self.in_repl:
|
|
335
|
+
log2('cd to an app first.')
|
|
336
|
+
else:
|
|
337
|
+
log2('* app is missing.')
|
|
338
|
+
log2()
|
|
339
|
+
display_help()
|
|
340
|
+
return (False, error)
|
|
341
|
+
|
|
342
|
+
elif required == RequiredState.EXPORT_DB:
|
|
343
|
+
if self.device not in [ReplState.C, ReplState.X]:
|
|
344
|
+
return (False, None)
|
|
345
|
+
|
|
346
|
+
if not self.export_session:
|
|
347
|
+
def error():
|
|
348
|
+
if self.in_repl:
|
|
349
|
+
log2("Select an export database first with 'use' command.")
|
|
350
|
+
else:
|
|
351
|
+
log2('* export database is missing.')
|
|
352
|
+
log2()
|
|
353
|
+
display_help()
|
|
354
|
+
return (False, error)
|
|
355
|
+
|
|
356
|
+
elif required in [ReplState.L, ReplState.A, ReplState.C, ReplState.P, ReplState.X] and self.device != required:
|
|
357
|
+
def error():
|
|
215
358
|
if self.in_repl:
|
|
216
|
-
log2('
|
|
359
|
+
log2(f'Switch to {required}: first.')
|
|
217
360
|
else:
|
|
218
|
-
log2('*
|
|
361
|
+
log2('* on a wrong device.')
|
|
219
362
|
log2()
|
|
220
363
|
display_help()
|
|
364
|
+
return (False, error)
|
|
221
365
|
|
|
222
|
-
|
|
366
|
+
return (True, None)
|
|
223
367
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
368
|
+
def _validate_device(self, devices: list[RequiredState]):
|
|
369
|
+
if self.device not in devices:
|
|
370
|
+
def error():
|
|
371
|
+
if self.in_repl:
|
|
372
|
+
log2(f'Not a valid command on {self.device}: drive.')
|
|
373
|
+
else:
|
|
374
|
+
log2('* on a wrong device.')
|
|
375
|
+
log2()
|
|
376
|
+
display_help()
|
|
377
|
+
return (False, error)
|
|
233
378
|
|
|
234
|
-
return True
|
|
379
|
+
return (True, None)
|
|
235
380
|
|
|
236
381
|
def user_pass(self, secret_path = 'cql.secret'):
|
|
237
382
|
return Secrets.get_user_pass(self.pod if self.pod else self.sts, self.namespace, secret_path=secret_path)
|
|
238
383
|
|
|
239
384
|
def enter_bash(self, bash_session: BashSession):
|
|
385
|
+
self.push()
|
|
386
|
+
|
|
240
387
|
self.bash_session = bash_session
|
|
241
|
-
if self.device != ReplState.C:
|
|
242
|
-
self.device = ReplState.C
|
|
243
|
-
log2(f'Moved to {ReplState.C}: automatically. Will move back to {ReplState.P}: when you exit the bash session.')
|
|
244
388
|
|
|
245
389
|
def exit_bash(self):
|
|
246
|
-
|
|
247
|
-
|
|
390
|
+
self.pop()
|
|
391
|
+
self.bash_session = None
|
|
392
|
+
|
|
393
|
+
def push(self):
|
|
394
|
+
if not self.original_state:
|
|
395
|
+
self.original_state = copy(self)
|
|
396
|
+
|
|
397
|
+
def pop(self):
|
|
398
|
+
if o := self.original_state:
|
|
399
|
+
self.device = o.device
|
|
400
|
+
self.sts = o.sts
|
|
401
|
+
self.pod = o.pod
|
|
402
|
+
self.pg_path = o.pg_path
|
|
403
|
+
self.app_env = o.app_env
|
|
404
|
+
self.app_app = o.app_app
|
|
405
|
+
self.app_pod = o.app_pod
|
|
406
|
+
# self.export_session = o.export_session
|
|
407
|
+
self.namespace = o.namespace
|
|
408
|
+
|
|
409
|
+
self.original_state = None
|
|
410
|
+
|
|
411
|
+
class DevicePodService:
|
|
412
|
+
def __init__(self, handler: 'DeviceExecHandler'):
|
|
413
|
+
self.handler = handler
|
|
414
|
+
|
|
415
|
+
def exec(self, command: str, action='bash', show_out = True):
|
|
416
|
+
state = self.handler.state
|
|
417
|
+
|
|
418
|
+
rs = None
|
|
419
|
+
if state.device == ReplState.A and state.app_app:
|
|
420
|
+
if state.app_pod:
|
|
421
|
+
rs = [AppPods.exec(state.app_pod, state.namespace, command, show_out=show_out)]
|
|
422
|
+
else:
|
|
423
|
+
pods = AppPods.pod_names(state.namespace, state.app_env, state.app_app)
|
|
424
|
+
rs = AppClusters.exec(pods, state.namespace, command, show_out=show_out)
|
|
425
|
+
elif state.pod:
|
|
426
|
+
rs = [CassandraNodes.exec(state.pod, state.namespace, command, show_out=show_out)]
|
|
427
|
+
elif state.sts:
|
|
428
|
+
rs = CassandraClusters.exec(state.sts, state.namespace, command, action=action, show_out=show_out)
|
|
429
|
+
# assume that pg-agent or ops pod is single pod
|
|
430
|
+
|
|
431
|
+
dir = None
|
|
432
|
+
if rs:
|
|
433
|
+
for r in rs:
|
|
434
|
+
if r.exit_code(): # if fails to read the session file, ignore
|
|
435
|
+
continue
|
|
436
|
+
|
|
437
|
+
dir0 = r.stdout.strip(' \r\n')
|
|
438
|
+
if dir:
|
|
439
|
+
if dir != dir0:
|
|
440
|
+
log2('Inconsitent working dir found across multiple pods.')
|
|
441
|
+
return None
|
|
442
|
+
else:
|
|
443
|
+
dir = dir0
|
|
444
|
+
|
|
445
|
+
return dir
|
|
446
|
+
|
|
447
|
+
class DeviceExecHandler:
|
|
448
|
+
def __init__(self, state: ReplState):
|
|
449
|
+
self.state = state
|
|
450
|
+
|
|
451
|
+
def __enter__(self):
|
|
452
|
+
return DevicePodService(self)
|
|
453
|
+
|
|
454
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
455
|
+
return False
|
|
248
456
|
|
|
249
|
-
|
|
457
|
+
def device(state: ReplState):
|
|
458
|
+
return DeviceExecHandler(state)
|