kaqing 2.0.14__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/apps.py +2 -2
- adam/batch.py +13 -3
- 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/__init__.py +0 -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/__init__.py +0 -0
- 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/code_utils.py +2 -2
- adam/commands/deploy/deploy.py +8 -21
- adam/commands/deploy/deploy_frontend.py +1 -1
- adam/commands/deploy/deploy_pg_agent.py +3 -3
- adam/commands/deploy/deploy_pod.py +28 -27
- adam/commands/deploy/deploy_utils.py +16 -26
- adam/commands/deploy/undeploy.py +8 -21
- adam/commands/deploy/undeploy_frontend.py +1 -1
- adam/commands/deploy/undeploy_pg_agent.py +5 -3
- adam/commands/deploy/undeploy_pod.py +12 -10
- 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/export/clean_up_export_sessions.py +40 -0
- 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 +7 -4
- 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_session.py → postgres_context.py} +43 -42
- 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 +1 -1
- 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/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_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 +127 -117
- adam/repl_commands.py +51 -16
- 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/authn_ad.py +1 -1
- adam/sso/cred_cache.py +1 -1
- adam/sso/idp.py +1 -1
- adam/utils.py +83 -2
- 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/{k8s_utils → utils_k8s}/deployment.py +2 -2
- adam/{k8s_utils → utils_k8s}/kube_context.py +1 -1
- adam/{k8s_utils → utils_k8s}/pods.py +119 -26
- adam/{k8s_utils → utils_k8s}/secrets.py +4 -0
- adam/{k8s_utils → utils_k8s}/statefulsets.py +5 -4
- 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-2.0.14.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
- kaqing-2.0.14.dist-info/RECORD +0 -167
- /adam/{k8s_utils → commands/audit}/__init__.py +0 -0
- /adam/{k8s_utils → utils_k8s}/config_maps.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}/jobs.py +0 -0
- /adam/{k8s_utils → utils_k8s}/service_accounts.py +0 -0
- /adam/{k8s_utils → utils_k8s}/services.py +0 -0
- /adam/{k8s_utils → utils_k8s}/volumes.py +0 -0
- {kaqing-2.0.14.dist-info → kaqing-2.0.145.dist-info}/WHEEL +0 -0
- {kaqing-2.0.14.dist-info → kaqing-2.0.145.dist-info}/entry_points.txt +0 -0
- {kaqing-2.0.14.dist-info → kaqing-2.0.145.dist-info}/top_level.txt +0 -0
|
File without changes
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
from adam.commands.command import Command
|
|
3
|
+
from adam.repl_state import ReplState
|
|
4
|
+
|
|
5
|
+
class Device:
|
|
6
|
+
@abstractmethod
|
|
7
|
+
def ls(self, cmd: str, state: ReplState):
|
|
8
|
+
pass
|
|
9
|
+
|
|
10
|
+
def ls_completion(self, cmd: str, state: ReplState, default: dict = {}):
|
|
11
|
+
return default
|
|
12
|
+
|
|
13
|
+
def cd(self, dir: str, state: ReplState):
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
def cd_completion(self, cmd: str, state: ReplState, default: dict = {}):
|
|
17
|
+
return default
|
|
18
|
+
|
|
19
|
+
@abstractmethod
|
|
20
|
+
def pwd(self, state: ReplState):
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
def try_fallback_action(self, chain: Command, state: ReplState, cmd: str):
|
|
24
|
+
return False, None
|
|
25
|
+
|
|
26
|
+
def enter(state: ReplState):
|
|
27
|
+
pass
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
from adam.apps import Apps
|
|
2
|
+
from adam.commands.bash.bash import Bash
|
|
3
|
+
from adam.commands.command import Command
|
|
4
|
+
from adam.commands.devices.device import Device
|
|
5
|
+
from adam.config import Config
|
|
6
|
+
from adam.repl_state import ReplState
|
|
7
|
+
from adam.utils import lines_to_tabular, log
|
|
8
|
+
from adam.utils_k8s.app_pods import AppPods
|
|
9
|
+
from adam.utils_k8s.ingresses import Ingresses
|
|
10
|
+
|
|
11
|
+
class DeviceApp(Command, Device):
|
|
12
|
+
COMMAND = f'{ReplState.A}:'
|
|
13
|
+
|
|
14
|
+
# the singleton pattern
|
|
15
|
+
def __new__(cls, *args, **kwargs):
|
|
16
|
+
if not hasattr(cls, 'instance'): cls.instance = super(DeviceApp, 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 DeviceApp.COMMAND
|
|
25
|
+
|
|
26
|
+
def run(self, cmd: str, state: ReplState):
|
|
27
|
+
if not self.args(cmd):
|
|
28
|
+
return super().run(cmd, state)
|
|
29
|
+
|
|
30
|
+
state.device = ReplState.A
|
|
31
|
+
|
|
32
|
+
return state
|
|
33
|
+
|
|
34
|
+
def completion(self, state: ReplState):
|
|
35
|
+
return super().completion(state)
|
|
36
|
+
|
|
37
|
+
def help(self, _: ReplState):
|
|
38
|
+
return f'{DeviceApp.COMMAND}\t move to App Operations device'
|
|
39
|
+
|
|
40
|
+
def ls(self, cmd: str, state: ReplState):
|
|
41
|
+
if state.app_pod:
|
|
42
|
+
return Bash().run('bash ' + cmd, state)
|
|
43
|
+
elif state.app_app:
|
|
44
|
+
pods = AppPods.pod_names(state.namespace, state.app_env, state.app_app)
|
|
45
|
+
|
|
46
|
+
log(lines_to_tabular(pods, 'POD_NAME'))
|
|
47
|
+
elif state.app_env:
|
|
48
|
+
def line(n: str, ns: str):
|
|
49
|
+
host = Ingresses.get_host(Config().get('app.login.ingress', '{app_id}-k8singr-appleader-001').replace('{app_id}', f'{ns}-{n}'), ns)
|
|
50
|
+
if not host:
|
|
51
|
+
return None
|
|
52
|
+
|
|
53
|
+
endpoint = Config().get('app.login.url', 'https://{host}/{env}/{app}').replace('{host}', host).replace('{env}', state.app_env).replace('{app}', 'c3')
|
|
54
|
+
if not endpoint:
|
|
55
|
+
return None
|
|
56
|
+
|
|
57
|
+
return f"{n.split('-')[1]},{Ingresses.get_host(f'{ns}-{n}-k8singr-appleader-001', ns)},{endpoint}"
|
|
58
|
+
|
|
59
|
+
svcs = [l for l in [line(n, ns) for n, ns in Apps.apps(state.app_env)] if l]
|
|
60
|
+
|
|
61
|
+
log(lines_to_tabular(svcs, 'APP,HOST,ENDPOINT', separator=','))
|
|
62
|
+
else:
|
|
63
|
+
svcs = [n for n, ns in Apps.envs()]
|
|
64
|
+
|
|
65
|
+
log(lines_to_tabular(svcs, 'ENV', separator=','))
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def ls_completion(self, cmd, state, default: dict = {}):
|
|
69
|
+
if state.app_app:
|
|
70
|
+
def pod_names():
|
|
71
|
+
return [p for p in AppPods.pod_names(state.namespace, state.app_env, state.app_app)]
|
|
72
|
+
|
|
73
|
+
return super().completion(state) | {f'@{p}': {cmd: None} for p in pod_names()}
|
|
74
|
+
|
|
75
|
+
return default
|
|
76
|
+
|
|
77
|
+
def cd(self, dir: str, state: ReplState):
|
|
78
|
+
if dir == '':
|
|
79
|
+
state.app_env = None
|
|
80
|
+
state.app_app = None
|
|
81
|
+
state.app_pod = None
|
|
82
|
+
elif dir == '..':
|
|
83
|
+
if state.app_pod:
|
|
84
|
+
state.app_pod = None
|
|
85
|
+
elif state.app_app:
|
|
86
|
+
state.app_app = None
|
|
87
|
+
else:
|
|
88
|
+
state.app_env = None
|
|
89
|
+
else:
|
|
90
|
+
if state.app_app:
|
|
91
|
+
state.app_pod = dir
|
|
92
|
+
elif not state.app_env:
|
|
93
|
+
tks = dir.split('@')
|
|
94
|
+
if len(tks) > 1:
|
|
95
|
+
state.namespace = tks[1]
|
|
96
|
+
|
|
97
|
+
state.app_env = dir.split('@')[0]
|
|
98
|
+
else:
|
|
99
|
+
state.app_app = dir
|
|
100
|
+
|
|
101
|
+
def cd_completion(self, cmd: str, state: ReplState, default: dict = {}):
|
|
102
|
+
if state.app_app:
|
|
103
|
+
return {cmd: {'..': None} | {pod: None for pod in AppPods.pod_names(state.namespace, state.app_env, state.app_app)}}
|
|
104
|
+
elif state.app_env:
|
|
105
|
+
return {cmd: {'..': None} | {app[0].split('-')[1]: None for app in Apps.apps(state.app_env)}}
|
|
106
|
+
else:
|
|
107
|
+
return {cmd: {'..': None} | {env[0]: None for env in Apps.envs()}}
|
|
108
|
+
|
|
109
|
+
def pwd(self, state: ReplState):
|
|
110
|
+
words = []
|
|
111
|
+
|
|
112
|
+
if state.app_env:
|
|
113
|
+
words.append(f'env/{state.app_env}')
|
|
114
|
+
if state.app_app:
|
|
115
|
+
words.append(f'app/{state.app_app}')
|
|
116
|
+
|
|
117
|
+
return '\t'.join([f'{ReplState.X}:>'] + (words if words else ['/']))
|
|
118
|
+
|
|
119
|
+
def try_fallback_action(self, chain: Command, state: ReplState, cmd: str):
|
|
120
|
+
if state.app_app:
|
|
121
|
+
return True, chain.run(f'app {cmd}', state)
|
|
122
|
+
|
|
123
|
+
return False, None
|
|
124
|
+
|
|
125
|
+
def enter(self, state: ReplState):
|
|
126
|
+
if not state.app_env:
|
|
127
|
+
if auto_enter := Config().get('repl.a.auto-enter', 'c3/c3/*'):
|
|
128
|
+
if auto_enter != 'no':
|
|
129
|
+
ea = auto_enter.split('/')
|
|
130
|
+
state.app_env = ea[0]
|
|
131
|
+
if len(ea) > 2:
|
|
132
|
+
state.app_app = ea[1]
|
|
133
|
+
state.app_pod = ea[2]
|
|
134
|
+
if state.app_pod == '*':
|
|
135
|
+
if (pods := AppPods.pod_names(state.namespace, ea[0], ea[1])):
|
|
136
|
+
state.app_pod = pods[0]
|
|
137
|
+
Config().wait_log(f'Moving to {state.app_env}/{state.app_app}/{state.app_pod}...')
|
|
138
|
+
else:
|
|
139
|
+
Config().wait_log(f'No pods found, moving to {state.app_env}/{state.app_app}...')
|
|
140
|
+
else:
|
|
141
|
+
Config().wait_log(f'Moving to {state.app_env}/{state.app_app}/{state.app_pod}...')
|
|
142
|
+
elif len(ea) > 1:
|
|
143
|
+
state.app_app = ea[1]
|
|
144
|
+
Config().wait_log(f'Moving to {state.app_env}/{state.app_app}...')
|
|
145
|
+
else:
|
|
146
|
+
Config().wait_log(f'Moving to {state.app_env}...')
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from adam.commands.command import Command
|
|
2
|
+
from adam.commands.devices.device import Device
|
|
3
|
+
from adam.repl_state import ReplState
|
|
4
|
+
from adam.utils import lines_to_tabular, log
|
|
5
|
+
from adam.utils_athena import Athena
|
|
6
|
+
|
|
7
|
+
class DeviceAuditLog(Command, Device):
|
|
8
|
+
COMMAND = f'{ReplState.L}:'
|
|
9
|
+
|
|
10
|
+
# the singleton pattern
|
|
11
|
+
def __new__(cls, *args, **kwargs):
|
|
12
|
+
if not hasattr(cls, 'instance'): cls.instance = super(DeviceAuditLog, cls).__new__(cls)
|
|
13
|
+
|
|
14
|
+
return cls.instance
|
|
15
|
+
|
|
16
|
+
def __init__(self, successor: Command=None):
|
|
17
|
+
super().__init__(successor)
|
|
18
|
+
|
|
19
|
+
def command(self):
|
|
20
|
+
return DeviceAuditLog.COMMAND
|
|
21
|
+
|
|
22
|
+
def run(self, cmd: str, state: ReplState):
|
|
23
|
+
if not self.args(cmd):
|
|
24
|
+
return super().run(cmd, state)
|
|
25
|
+
|
|
26
|
+
state.device = ReplState.L
|
|
27
|
+
|
|
28
|
+
return state
|
|
29
|
+
|
|
30
|
+
def completion(self, state: ReplState):
|
|
31
|
+
return super().completion(state)
|
|
32
|
+
|
|
33
|
+
def help(self, _: ReplState):
|
|
34
|
+
return f'{DeviceAuditLog.COMMAND}\t move to Audit Log Operations device'
|
|
35
|
+
|
|
36
|
+
def ls(self, cmd: str, _: ReplState):
|
|
37
|
+
log(lines_to_tabular(Athena.table_names(), 'NAME', separator=','))
|
|
38
|
+
|
|
39
|
+
def pwd(self, state: ReplState):
|
|
40
|
+
return '\t'.join([f'{ReplState.L}:>', '/'])
|
|
41
|
+
|
|
42
|
+
def try_fallback_action(self, chain: Command, state: ReplState, cmd: str):
|
|
43
|
+
return True, chain.run(f'audit {cmd}', state)
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
from adam.commands.bash.bash import Bash
|
|
2
|
+
from adam.commands.command import Command
|
|
3
|
+
from adam.commands.commands_utils import show_pods, show_rollout
|
|
4
|
+
from adam.commands.devices.device import Device
|
|
5
|
+
from adam.config import Config
|
|
6
|
+
from adam.repl_state import ReplState
|
|
7
|
+
from adam.utils import lines_to_tabular, log, log2
|
|
8
|
+
from adam.utils_k8s.cassandra_clusters import CassandraClusters
|
|
9
|
+
from adam.utils_k8s.custom_resources import CustomResources
|
|
10
|
+
from adam.utils_k8s.kube_context import KubeContext
|
|
11
|
+
from adam.utils_k8s.statefulsets import StatefulSets
|
|
12
|
+
|
|
13
|
+
class DeviceCass(Command, Device):
|
|
14
|
+
COMMAND = f'{ReplState.C}:'
|
|
15
|
+
|
|
16
|
+
# the singleton pattern
|
|
17
|
+
def __new__(cls, *args, **kwargs):
|
|
18
|
+
if not hasattr(cls, 'instance'): cls.instance = super(DeviceCass, 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 DeviceCass.COMMAND
|
|
27
|
+
|
|
28
|
+
def run(self, cmd: str, state: ReplState):
|
|
29
|
+
if not self.args(cmd):
|
|
30
|
+
return super().run(cmd, state)
|
|
31
|
+
|
|
32
|
+
state.device = ReplState.C
|
|
33
|
+
|
|
34
|
+
return state
|
|
35
|
+
|
|
36
|
+
def completion(self, state: ReplState):
|
|
37
|
+
return super().completion(state)
|
|
38
|
+
|
|
39
|
+
def help(self, _: ReplState):
|
|
40
|
+
return f'{DeviceCass.COMMAND}\t move to Cassandra Operations device'
|
|
41
|
+
|
|
42
|
+
def ls(self, cmd: str, state: ReplState):
|
|
43
|
+
if state.pod:
|
|
44
|
+
return Bash().run('bash ' + cmd, state)
|
|
45
|
+
elif state.sts and state.namespace:
|
|
46
|
+
show_pods(StatefulSets.pods(state.sts, state.namespace), state.namespace, show_namespace=not KubeContext.in_cluster_namespace())
|
|
47
|
+
show_rollout(state.sts, state.namespace)
|
|
48
|
+
else:
|
|
49
|
+
self.show_statefulsets()
|
|
50
|
+
|
|
51
|
+
def ls_completion(self, cmd: str, state: ReplState, default: dict = {}):
|
|
52
|
+
def pod_names():
|
|
53
|
+
return [p for p in StatefulSets.pod_names(state.sts, state.namespace)]
|
|
54
|
+
|
|
55
|
+
if state.sts:
|
|
56
|
+
return super().completion(state) | {f'@{p}': {'ls': None} for p in pod_names()}
|
|
57
|
+
else:
|
|
58
|
+
return {cmd: {n: None for n in StatefulSets.list_sts_names()}}
|
|
59
|
+
|
|
60
|
+
def show_statefulsets(self):
|
|
61
|
+
ss = StatefulSets.list_sts_names()
|
|
62
|
+
if len(ss) == 0:
|
|
63
|
+
log2('No Cassandra clusters found.')
|
|
64
|
+
return
|
|
65
|
+
|
|
66
|
+
app_ids = CustomResources.get_app_ids()
|
|
67
|
+
list = []
|
|
68
|
+
for s in ss:
|
|
69
|
+
cr_name = CustomResources.get_cr_name(s)
|
|
70
|
+
app_id = 'Unknown'
|
|
71
|
+
if cr_name in app_ids:
|
|
72
|
+
app_id = app_ids[cr_name]
|
|
73
|
+
list.append(f"{s} {app_id}")
|
|
74
|
+
|
|
75
|
+
header = 'STATEFULSET_NAME@NAMESPACE APP_ID'
|
|
76
|
+
if KubeContext.in_cluster_namespace():
|
|
77
|
+
header = 'STATEFULSET_NAME APP_ID'
|
|
78
|
+
log(lines_to_tabular(list, header))
|
|
79
|
+
|
|
80
|
+
def cd(self, dir: str, state: ReplState):
|
|
81
|
+
if dir == '':
|
|
82
|
+
state.sts = None
|
|
83
|
+
state.pod = None
|
|
84
|
+
elif dir == '..':
|
|
85
|
+
if state.pod:
|
|
86
|
+
state.pod = None
|
|
87
|
+
else:
|
|
88
|
+
state.sts = None
|
|
89
|
+
else:
|
|
90
|
+
if not state.sts:
|
|
91
|
+
ss_and_ns = dir.split('@')
|
|
92
|
+
state.sts = ss_and_ns[0]
|
|
93
|
+
if len(ss_and_ns) > 1:
|
|
94
|
+
state.namespace = ss_and_ns[1]
|
|
95
|
+
elif not state.pod:
|
|
96
|
+
p, _ = KubeContext.is_pod_name(dir)
|
|
97
|
+
if p:
|
|
98
|
+
state.pod = p
|
|
99
|
+
else:
|
|
100
|
+
names = CassandraClusters.pod_names_by_host_id(state.sts, state.namespace);
|
|
101
|
+
if dir in names:
|
|
102
|
+
state.pod = names[dir]
|
|
103
|
+
else:
|
|
104
|
+
log2('Not a valid pod name or host id.')
|
|
105
|
+
|
|
106
|
+
def cd_completion(self, cmd: str, state: ReplState, default: dict = {}):
|
|
107
|
+
if state.pod:
|
|
108
|
+
return {cmd: {'..': None}}
|
|
109
|
+
elif state.sts:
|
|
110
|
+
return {cmd: {'..': None} | {p: None for p in StatefulSets.pod_names(state.sts, state.namespace)}}
|
|
111
|
+
else:
|
|
112
|
+
return {cmd: {p: None for p in StatefulSets.list_sts_names()}}
|
|
113
|
+
|
|
114
|
+
def pwd(self, state: ReplState):
|
|
115
|
+
words = []
|
|
116
|
+
|
|
117
|
+
if state.sts:
|
|
118
|
+
words.append(f'sts/{state.sts}')
|
|
119
|
+
if state.pod:
|
|
120
|
+
words.append(f'pod/{state.pod}')
|
|
121
|
+
|
|
122
|
+
return '\t'.join([f'{ReplState.C}:>'] + (words if words else ['/']))
|
|
123
|
+
|
|
124
|
+
def try_fallback_action(self, chain: Command, state: ReplState, cmd: str):
|
|
125
|
+
if state.sts:
|
|
126
|
+
return True, chain.run(f'cql {cmd}', state)
|
|
127
|
+
|
|
128
|
+
return False, None
|
|
129
|
+
|
|
130
|
+
def enter(self, state: ReplState):
|
|
131
|
+
auto_enter = Config().get('repl.c.auto-enter', 'cluster')
|
|
132
|
+
if auto_enter and auto_enter in ['cluster', 'first-pod']:
|
|
133
|
+
sts = StatefulSets.list_sts_name_and_ns()
|
|
134
|
+
if not sts:
|
|
135
|
+
log2("No Cassandra clusters found.")
|
|
136
|
+
elif not state.sts and len(sts) == 1:
|
|
137
|
+
cluster = sts[0]
|
|
138
|
+
state.sts = cluster[0]
|
|
139
|
+
state.namespace = cluster[1]
|
|
140
|
+
if auto_enter == 'first-pod':
|
|
141
|
+
state.pod = f'{state.sts}-0'
|
|
142
|
+
if KubeContext().in_cluster_namespace:
|
|
143
|
+
Config().wait_log(f'Moving to the only Cassandra cluster: {state.sts}...')
|
|
144
|
+
else:
|
|
145
|
+
Config().wait_log(f'Moving to the only Cassandra cluster: {state.sts}@{state.namespace}...')
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
from adam.commands.command import Command
|
|
2
|
+
from adam.commands.devices.device import Device
|
|
3
|
+
from adam.commands.export.export_databases import ExportDatabases
|
|
4
|
+
from adam.config import Config
|
|
5
|
+
from adam.repl_state import ReplState
|
|
6
|
+
from adam.utils import lines_to_tabular, log, log2
|
|
7
|
+
|
|
8
|
+
class DeviceExport(Command, Device):
|
|
9
|
+
COMMAND = f'{ReplState.X}:'
|
|
10
|
+
|
|
11
|
+
# the singleton pattern
|
|
12
|
+
def __new__(cls, *args, **kwargs):
|
|
13
|
+
if not hasattr(cls, 'instance'): cls.instance = super(DeviceExport, 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 DeviceExport.COMMAND
|
|
22
|
+
|
|
23
|
+
def run(self, cmd: str, state: ReplState):
|
|
24
|
+
if not self.args(cmd):
|
|
25
|
+
return super().run(cmd, state)
|
|
26
|
+
|
|
27
|
+
state.device = ReplState.X
|
|
28
|
+
|
|
29
|
+
return state
|
|
30
|
+
|
|
31
|
+
def completion(self, state: ReplState):
|
|
32
|
+
return super().completion(state)
|
|
33
|
+
|
|
34
|
+
def help(self, _: ReplState):
|
|
35
|
+
return f'{DeviceExport.COMMAND}\t move to Export Database Operations device'
|
|
36
|
+
|
|
37
|
+
def ls(self, cmd: str, state: ReplState):
|
|
38
|
+
if state.export_session:
|
|
39
|
+
self.show_export_tables(state.export_session)
|
|
40
|
+
else:
|
|
41
|
+
self.show_export_databases()
|
|
42
|
+
|
|
43
|
+
def show_export_databases(self, importer: str = None):
|
|
44
|
+
lines = [f'{k}\t{v}' for k, v in ExportDatabases.database_names_with_keyspace_cnt(importer).items()]
|
|
45
|
+
log(lines_to_tabular(lines, 'NAME\tKEYSPACES', separator='\t'))
|
|
46
|
+
|
|
47
|
+
def show_export_tables(self, export_session: str):
|
|
48
|
+
log(lines_to_tabular(ExportDatabases.table_names(export_session), 'NAME', separator=','))
|
|
49
|
+
|
|
50
|
+
def cd(self, dir: str, state: ReplState):
|
|
51
|
+
if dir in ['', '..']:
|
|
52
|
+
state.export_session = None
|
|
53
|
+
else:
|
|
54
|
+
state.export_session = dir
|
|
55
|
+
|
|
56
|
+
def cd_completion(self, cmd: str, state: ReplState, default: dict = {}):
|
|
57
|
+
if state.export_session:
|
|
58
|
+
return {cmd: {'..': None} | {n: None for n in ExportDatabases.database_names()}}
|
|
59
|
+
else:
|
|
60
|
+
return {cmd: {n: None for n in ExportDatabases.database_names()}}
|
|
61
|
+
|
|
62
|
+
def pwd(self, state: ReplState):
|
|
63
|
+
words = []
|
|
64
|
+
|
|
65
|
+
if state.export_session:
|
|
66
|
+
words.append(state.export_session)
|
|
67
|
+
|
|
68
|
+
return '\t'.join([f'{ReplState.X}:>'] + (words if words else ['/']))
|
|
69
|
+
|
|
70
|
+
def try_fallback_action(self, chain: Command, state: ReplState, cmd: str):
|
|
71
|
+
result = chain.run(f'.{cmd}', state)
|
|
72
|
+
if type(result) is ReplState:
|
|
73
|
+
if state.export_session and not result.export_session:
|
|
74
|
+
state.export_session = None
|
|
75
|
+
|
|
76
|
+
return True, result
|
|
77
|
+
|
|
78
|
+
def enter(self, state: ReplState):
|
|
79
|
+
if auto_enter := Config().get('repl.x.auto-enter', 'no'):
|
|
80
|
+
if auto_enter == 'latest':
|
|
81
|
+
Config().wait_log(f'Moving to the latest export database...')
|
|
82
|
+
if dbs := ExportDatabases.database_names():
|
|
83
|
+
state.export_session = sorted(dbs)[-1]
|
|
84
|
+
else:
|
|
85
|
+
log2('No export database found.')
|
|
86
|
+
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
from adam.commands.command import Command
|
|
2
|
+
from adam.commands.devices.device import Device
|
|
3
|
+
from adam.commands.postgres.postgres_context import PostgresContext
|
|
4
|
+
from adam.commands.postgres.postgres_utils import pg_database_names, pg_table_names
|
|
5
|
+
from adam.config import Config
|
|
6
|
+
from adam.repl_state import ReplState
|
|
7
|
+
from adam.utils import lines_to_tabular, log
|
|
8
|
+
|
|
9
|
+
class DevicePostgres(Command, Device):
|
|
10
|
+
COMMAND = f'{ReplState.P}:'
|
|
11
|
+
|
|
12
|
+
# the singleton pattern
|
|
13
|
+
def __new__(cls, *args, **kwargs):
|
|
14
|
+
if not hasattr(cls, 'instance'): cls.instance = super(DevicePostgres, cls).__new__(cls)
|
|
15
|
+
|
|
16
|
+
return cls.instance
|
|
17
|
+
|
|
18
|
+
def __init__(self, successor: Command=None):
|
|
19
|
+
super().__init__(successor)
|
|
20
|
+
|
|
21
|
+
def command(self):
|
|
22
|
+
return DevicePostgres.COMMAND
|
|
23
|
+
|
|
24
|
+
def run(self, cmd: str, state: ReplState):
|
|
25
|
+
if not self.args(cmd):
|
|
26
|
+
return super().run(cmd, state)
|
|
27
|
+
|
|
28
|
+
state.device = ReplState.P
|
|
29
|
+
|
|
30
|
+
return state
|
|
31
|
+
|
|
32
|
+
def completion(self, state: ReplState):
|
|
33
|
+
return super().completion(state)
|
|
34
|
+
|
|
35
|
+
def help(self, _: ReplState):
|
|
36
|
+
return f'{DevicePostgres.COMMAND}\t move to Postgres Operations device'
|
|
37
|
+
|
|
38
|
+
def ls(self, cmd: str, state: ReplState):
|
|
39
|
+
if state.pg_path:
|
|
40
|
+
pg: PostgresContext = PostgresContext.apply(state.namespace, state.pg_path)
|
|
41
|
+
if pg.db:
|
|
42
|
+
self.show_pg_tables(pg)
|
|
43
|
+
else:
|
|
44
|
+
self.show_pg_databases(pg)
|
|
45
|
+
else:
|
|
46
|
+
self.show_pg_hosts(state)
|
|
47
|
+
|
|
48
|
+
def show_pg_hosts(self, state: ReplState):
|
|
49
|
+
if state.namespace:
|
|
50
|
+
def line(pg: PostgresContext):
|
|
51
|
+
return f'{pg.path()},{pg.endpoint()}:{pg.port()},{pg.username()},{pg.password()}'
|
|
52
|
+
|
|
53
|
+
lines = [line(PostgresContext.apply(state.namespace, pg)) for pg in PostgresContext.hosts(state.namespace)]
|
|
54
|
+
|
|
55
|
+
log(lines_to_tabular(lines, 'NAME,ENDPOINT,USERNAME,PASSWORD', separator=','))
|
|
56
|
+
else:
|
|
57
|
+
def line(pg: PostgresContext):
|
|
58
|
+
return f'{pg.path()},{pg.namespace},{pg.endpoint()}:{pg.port()},{pg.username()},{pg.password()}'
|
|
59
|
+
|
|
60
|
+
lines = [line(PostgresContext.apply(state.namespace, pg)) for pg in PostgresContext.hosts(state.namespace)]
|
|
61
|
+
|
|
62
|
+
log(lines_to_tabular(lines, 'NAME,NAMESPACE,ENDPOINT,USERNAME,PASSWORD', separator=','))
|
|
63
|
+
|
|
64
|
+
def show_pg_databases(self, pg: PostgresContext):
|
|
65
|
+
log(lines_to_tabular(pg_database_names(pg.namespace, pg.path()), 'DATABASE', separator=','))
|
|
66
|
+
|
|
67
|
+
def show_pg_tables(self, pg: PostgresContext):
|
|
68
|
+
log(lines_to_tabular(pg_table_names(pg.namespace, pg.path()), 'NAME', separator=','))
|
|
69
|
+
|
|
70
|
+
def cd(self, dir: str, state: ReplState):
|
|
71
|
+
if dir == '':
|
|
72
|
+
state.pg_path = None
|
|
73
|
+
else:
|
|
74
|
+
context: PostgresContext = PostgresContext.apply(state.namespace, state.pg_path, arg=dir)
|
|
75
|
+
# patch up state.namespace from pg cd
|
|
76
|
+
if not state.namespace and context.namespace:
|
|
77
|
+
state.namespace = context.namespace
|
|
78
|
+
state.pg_path = context.path()
|
|
79
|
+
|
|
80
|
+
def cd_completion(self, cmd: str, state: ReplState, default: dict = {}):
|
|
81
|
+
pg: PostgresContext = PostgresContext.apply(state.namespace, state.pg_path) if state.pg_path else None
|
|
82
|
+
if pg and pg.db:
|
|
83
|
+
return {cmd: {'..': None}}
|
|
84
|
+
elif pg and pg.host:
|
|
85
|
+
return {cmd: {'..': None} | {p: None for p in pg_database_names(state.namespace, pg.path())}}
|
|
86
|
+
else:
|
|
87
|
+
return {cmd: {p: None for p in PostgresContext.hosts(state.namespace)}}
|
|
88
|
+
|
|
89
|
+
def pwd(self, state: ReplState):
|
|
90
|
+
words = []
|
|
91
|
+
|
|
92
|
+
pg: PostgresContext = PostgresContext.apply(state.namespace, state.pg_path)
|
|
93
|
+
|
|
94
|
+
if pg.host:
|
|
95
|
+
words.append(f'host/{pg.host}')
|
|
96
|
+
if pg.db:
|
|
97
|
+
words.append(f'database/{pg.db}')
|
|
98
|
+
|
|
99
|
+
return '\t'.join([f'{ReplState.P}:>'] + (words if words else ['/']))
|
|
100
|
+
|
|
101
|
+
def try_fallback_action(self, chain: Command, state: ReplState, cmd: str):
|
|
102
|
+
pg: PostgresContext = PostgresContext.apply(state.namespace, state.pg_path)
|
|
103
|
+
if pg.db:
|
|
104
|
+
return True, chain.run(f'pg {cmd}', state)
|
|
105
|
+
|
|
106
|
+
return False, None
|
|
107
|
+
|
|
108
|
+
def enter(self, state: ReplState):
|
|
109
|
+
Config().wait_log('Inspecting postgres database instances...')
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from adam.commands.devices.device import Device
|
|
2
|
+
from adam.commands.devices.device_app import DeviceApp
|
|
3
|
+
from adam.commands.devices.device_auit_log import DeviceAuditLog
|
|
4
|
+
from adam.commands.devices.device_cass import DeviceCass
|
|
5
|
+
from adam.commands.devices.device_export import DeviceExport
|
|
6
|
+
from adam.commands.devices.device_postgres import DevicePostgres
|
|
7
|
+
from adam.repl_state import ReplState
|
|
8
|
+
|
|
9
|
+
class Devices:
|
|
10
|
+
def device(state: ReplState) -> Device:
|
|
11
|
+
if state.device == ReplState.A:
|
|
12
|
+
return DeviceApp()
|
|
13
|
+
elif state.device == ReplState.C:
|
|
14
|
+
return DeviceCass()
|
|
15
|
+
elif state.device == ReplState.L:
|
|
16
|
+
return DeviceAuditLog()
|
|
17
|
+
elif state.device == ReplState.P:
|
|
18
|
+
return DevicePostgres()
|
|
19
|
+
elif state.device == ReplState.X:
|
|
20
|
+
return DeviceExport()
|
|
21
|
+
|
|
22
|
+
return DeviceCass()
|
|
23
|
+
|
|
24
|
+
def all():
|
|
25
|
+
return [DeviceApp(), DeviceCass(), DeviceAuditLog(), DevicePostgres(), DeviceExport()]
|
|
File without changes
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from adam.commands.command import Command
|
|
2
|
+
from adam.commands.export.exporter import Exporter
|
|
3
|
+
from adam.repl_state import ReplState, RequiredState
|
|
4
|
+
from adam.utils import log, log2
|
|
5
|
+
|
|
6
|
+
class CleanUpExportSession(Command):
|
|
7
|
+
COMMAND = 'clean up export session'
|
|
8
|
+
|
|
9
|
+
# the singleton pattern
|
|
10
|
+
def __new__(cls, *args, **kwargs):
|
|
11
|
+
if not hasattr(cls, 'instance'): cls.instance = super(CleanUpExportSession, 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 CleanUpExportSession.COMMAND
|
|
20
|
+
|
|
21
|
+
def required(self):
|
|
22
|
+
return RequiredState.CLUSTER_OR_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
|
+
state, args = self.apply_state(args, state)
|
|
29
|
+
if not self.validate_state(state):
|
|
30
|
+
return state
|
|
31
|
+
|
|
32
|
+
if not args:
|
|
33
|
+
if state.in_repl:
|
|
34
|
+
log2('Specify export session name.')
|
|
35
|
+
else:
|
|
36
|
+
log2('* Session name is missing.')
|
|
37
|
+
|
|
38
|
+
Command.display_help()
|
|
39
|
+
|
|
40
|
+
return 'command-missing'
|
|
41
|
+
|
|
42
|
+
csv_cnt, log_cnt = Exporter.clean_up_session(state.sts, state.pod, state.namespace, args[0])
|
|
43
|
+
log(f'Removed {csv_cnt} csv and {log_cnt} log files.')
|
|
44
|
+
|
|
45
|
+
Exporter.clear_export_session_cache()
|
|
46
|
+
|
|
47
|
+
return state
|
|
48
|
+
|
|
49
|
+
def completion(self, _: ReplState):
|
|
50
|
+
return {}
|
|
51
|
+
|
|
52
|
+
def help(self, _: ReplState):
|
|
53
|
+
return f'{CleanUpExportSession.COMMAND} <export-session-name>\t clean up export session'
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from adam.commands.command import Command
|
|
2
|
+
from adam.commands.export.exporter import Exporter
|
|
3
|
+
from adam.repl_state import ReplState, RequiredState
|
|
4
|
+
|
|
5
|
+
class CleanUpExportSessions(Command):
|
|
6
|
+
COMMAND = 'clean up all export sessions'
|
|
7
|
+
|
|
8
|
+
# the singleton pattern
|
|
9
|
+
def __new__(cls, *args, **kwargs):
|
|
10
|
+
if not hasattr(cls, 'instance'): cls.instance = super(CleanUpExportSessions, cls).__new__(cls)
|
|
11
|
+
|
|
12
|
+
return cls.instance
|
|
13
|
+
|
|
14
|
+
def __init__(self, successor: Command=None):
|
|
15
|
+
super().__init__(successor)
|
|
16
|
+
|
|
17
|
+
def command(self):
|
|
18
|
+
return CleanUpExportSessions.COMMAND
|
|
19
|
+
|
|
20
|
+
def required(self):
|
|
21
|
+
return RequiredState.CLUSTER_OR_POD
|
|
22
|
+
|
|
23
|
+
def run(self, cmd: str, state: ReplState):
|
|
24
|
+
if not(args := self.args(cmd)):
|
|
25
|
+
return super().run(cmd, state)
|
|
26
|
+
|
|
27
|
+
state, args = self.apply_state(args, state)
|
|
28
|
+
if not self.validate_state(state):
|
|
29
|
+
return state
|
|
30
|
+
|
|
31
|
+
if Exporter.clean_up_all_sessions(state.sts, state.pod, state.namespace):
|
|
32
|
+
Exporter.clear_export_session_cache()
|
|
33
|
+
|
|
34
|
+
return state
|
|
35
|
+
|
|
36
|
+
def completion(self, _: ReplState):
|
|
37
|
+
return {}
|
|
38
|
+
|
|
39
|
+
def help(self, _: ReplState):
|
|
40
|
+
return f'{CleanUpExportSessions.COMMAND}\t clean up all export sessions'
|