kaqing 2.0.14__py3-none-any.whl → 2.0.189__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of kaqing might be problematic. Click here for more details.
- adam/__init__.py +0 -2
- adam/app_session.py +9 -12
- adam/apps.py +20 -6
- adam/batch.py +16 -6
- adam/checks/check_utils.py +19 -49
- adam/checks/compactionstats.py +1 -1
- adam/checks/cpu.py +9 -3
- adam/checks/cpu_metrics.py +52 -0
- adam/checks/disk.py +3 -4
- adam/checks/gossip.py +1 -1
- adam/checks/memory.py +3 -3
- adam/checks/status.py +1 -1
- adam/columns/columns.py +3 -1
- adam/columns/cpu.py +3 -1
- adam/columns/cpu_metrics.py +22 -0
- adam/columns/memory.py +3 -4
- adam/commands/__init__.py +24 -0
- adam/commands/alter_tables.py +66 -0
- adam/commands/app/app.py +38 -0
- adam/commands/{app_ping.py → app/app_ping.py} +8 -14
- adam/commands/app/show_app_actions.py +49 -0
- adam/commands/{show → app}/show_app_id.py +9 -12
- adam/commands/{show → app}/show_app_queues.py +8 -14
- adam/commands/app/utils_app.py +106 -0
- adam/commands/audit/__init__.py +0 -0
- adam/commands/audit/audit.py +67 -0
- adam/commands/audit/audit_repair_tables.py +72 -0
- adam/commands/audit/audit_run.py +50 -0
- adam/commands/audit/completions_l.py +15 -0
- adam/commands/audit/show_last10.py +36 -0
- adam/commands/audit/show_slow10.py +36 -0
- adam/commands/audit/show_top10.py +36 -0
- adam/commands/audit/utils_show_top10.py +71 -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 +36 -0
- adam/commands/cd.py +14 -88
- adam/commands/check.py +18 -21
- adam/commands/cli_commands.py +11 -7
- adam/commands/clipboard_copy.py +87 -0
- adam/commands/code.py +57 -0
- adam/commands/command.py +220 -19
- adam/commands/commands_utils.py +28 -31
- adam/commands/cql/__init__.py +0 -0
- adam/commands/cql/completions_c.py +28 -0
- adam/commands/{cqlsh.py → cql/cqlsh.py} +13 -32
- adam/commands/cql/utils_cql.py +305 -0
- adam/commands/deploy/code_start.py +7 -10
- adam/commands/deploy/code_stop.py +4 -21
- adam/commands/deploy/code_utils.py +5 -5
- adam/commands/deploy/deploy.py +4 -40
- adam/commands/deploy/deploy_frontend.py +15 -18
- adam/commands/deploy/deploy_pg_agent.py +4 -7
- adam/commands/deploy/deploy_pod.py +74 -77
- adam/commands/deploy/deploy_utils.py +16 -26
- adam/commands/deploy/undeploy.py +4 -40
- adam/commands/deploy/undeploy_frontend.py +5 -8
- adam/commands/deploy/undeploy_pg_agent.py +7 -8
- adam/commands/deploy/undeploy_pod.py +16 -17
- adam/commands/devices/__init__.py +0 -0
- adam/commands/devices/device.py +149 -0
- adam/commands/devices/device_app.py +163 -0
- adam/commands/devices/device_auit_log.py +49 -0
- adam/commands/devices/device_cass.py +179 -0
- adam/commands/devices/device_export.py +87 -0
- adam/commands/devices/device_postgres.py +160 -0
- adam/commands/devices/devices.py +25 -0
- adam/commands/download_file.py +47 -0
- adam/commands/exit.py +1 -4
- adam/commands/export/__init__.py +0 -0
- adam/commands/export/clean_up_all_export_sessions.py +37 -0
- adam/commands/export/clean_up_export_sessions.py +39 -0
- adam/commands/export/completions_x.py +11 -0
- adam/commands/export/download_export_session.py +40 -0
- adam/commands/export/drop_export_database.py +39 -0
- adam/commands/export/drop_export_databases.py +37 -0
- adam/commands/export/export.py +37 -0
- adam/commands/export/export_databases.py +246 -0
- adam/commands/export/export_select.py +34 -0
- adam/commands/export/export_sessions.py +209 -0
- adam/commands/export/export_use.py +49 -0
- adam/commands/export/export_x_select.py +48 -0
- adam/commands/export/exporter.py +332 -0
- adam/commands/export/import_files.py +44 -0
- adam/commands/export/import_session.py +44 -0
- adam/commands/export/importer.py +81 -0
- adam/commands/export/importer_athena.py +148 -0
- adam/commands/export/importer_sqlite.py +67 -0
- adam/commands/export/show_column_counts.py +45 -0
- adam/commands/export/show_export_databases.py +39 -0
- adam/commands/export/show_export_session.py +39 -0
- adam/commands/export/show_export_sessions.py +37 -0
- adam/commands/export/utils_export.py +344 -0
- adam/commands/find_files.py +51 -0
- adam/commands/find_processes.py +76 -0
- adam/commands/head.py +36 -0
- adam/commands/help.py +14 -9
- adam/commands/intermediate_command.py +52 -0
- adam/commands/issues.py +14 -40
- adam/commands/kubectl.py +38 -0
- adam/commands/login.py +26 -25
- adam/commands/logs.py +5 -7
- adam/commands/ls.py +11 -115
- adam/commands/medusa/medusa.py +4 -46
- adam/commands/medusa/medusa_backup.py +22 -29
- adam/commands/medusa/medusa_restore.py +51 -49
- adam/commands/medusa/medusa_show_backupjobs.py +20 -21
- adam/commands/medusa/medusa_show_restorejobs.py +16 -21
- adam/commands/medusa/utils_medusa.py +15 -0
- adam/commands/nodetool.py +8 -17
- adam/commands/param_get.py +11 -14
- adam/commands/param_set.py +9 -13
- adam/commands/postgres/completions_p.py +22 -0
- adam/commands/postgres/postgres.py +49 -73
- adam/commands/postgres/postgres_databases.py +270 -0
- adam/commands/postgres/postgres_ls.py +4 -8
- adam/commands/postgres/postgres_preview.py +5 -9
- adam/commands/postgres/utils_postgres.py +79 -0
- adam/commands/preview_table.py +10 -69
- adam/commands/pwd.py +14 -43
- adam/commands/reaper/reaper.py +6 -49
- adam/commands/reaper/reaper_forward.py +49 -56
- adam/commands/reaper/reaper_forward_session.py +6 -0
- adam/commands/reaper/reaper_forward_stop.py +10 -16
- adam/commands/reaper/reaper_restart.py +8 -15
- adam/commands/reaper/reaper_run_abort.py +8 -33
- adam/commands/reaper/reaper_runs.py +43 -58
- adam/commands/reaper/reaper_runs_abort.py +29 -49
- adam/commands/reaper/reaper_schedule_activate.py +14 -33
- adam/commands/reaper/reaper_schedule_start.py +9 -33
- adam/commands/reaper/reaper_schedule_stop.py +9 -33
- adam/commands/reaper/reaper_schedules.py +4 -14
- adam/commands/reaper/reaper_status.py +8 -16
- adam/commands/reaper/utils_reaper.py +203 -0
- adam/commands/repair/repair.py +4 -46
- adam/commands/repair/repair_log.py +6 -12
- adam/commands/repair/repair_run.py +29 -36
- adam/commands/repair/repair_scan.py +33 -41
- adam/commands/repair/repair_stop.py +6 -13
- adam/commands/report.py +25 -21
- adam/commands/restart.py +27 -28
- adam/commands/rollout.py +20 -25
- adam/commands/shell.py +12 -4
- adam/commands/show/show.py +15 -46
- adam/commands/show/show_adam.py +3 -3
- adam/commands/show/show_cassandra_repairs.py +37 -0
- adam/commands/show/show_cassandra_status.py +48 -52
- adam/commands/show/show_cassandra_version.py +5 -18
- adam/commands/show/show_cli_commands.py +56 -0
- adam/commands/show/show_host.py +33 -0
- adam/commands/show/show_login.py +23 -27
- adam/commands/show/show_params.py +2 -5
- adam/commands/show/show_processes.py +18 -21
- adam/commands/show/show_storage.py +11 -20
- adam/commands/watch.py +27 -30
- adam/config.py +8 -6
- adam/embedded_params.py +1 -1
- adam/log.py +4 -4
- adam/pod_exec_result.py +13 -5
- adam/repl.py +136 -120
- adam/repl_commands.py +66 -24
- adam/repl_session.py +8 -1
- adam/repl_state.py +343 -73
- adam/sql/__init__.py +0 -0
- adam/sql/lark_completer.py +284 -0
- adam/sql/lark_parser.py +604 -0
- adam/sql/sql_completer.py +118 -0
- adam/sql/sql_state_machine.py +630 -0
- adam/sql/term_completer.py +76 -0
- adam/sso/authn_ad.py +7 -9
- adam/sso/authn_okta.py +4 -6
- adam/sso/cred_cache.py +4 -6
- adam/sso/idp.py +10 -13
- adam/utils.py +539 -11
- adam/utils_athena.py +145 -0
- adam/utils_audits.py +102 -0
- adam/utils_issues.py +32 -0
- adam/utils_k8s/__init__.py +0 -0
- adam/utils_k8s/app_clusters.py +28 -0
- adam/utils_k8s/app_pods.py +36 -0
- adam/utils_k8s/cassandra_clusters.py +44 -0
- adam/{k8s_utils → utils_k8s}/cassandra_nodes.py +12 -5
- adam/{k8s_utils → utils_k8s}/custom_resources.py +16 -17
- adam/{k8s_utils → utils_k8s}/deployment.py +2 -2
- adam/{k8s_utils → utils_k8s}/ingresses.py +2 -2
- adam/{k8s_utils → utils_k8s}/jobs.py +7 -11
- adam/utils_k8s/k8s.py +96 -0
- adam/{k8s_utils → utils_k8s}/kube_context.py +3 -3
- adam/{k8s_utils → utils_k8s}/pods.py +132 -83
- adam/{k8s_utils → utils_k8s}/secrets.py +7 -3
- adam/{k8s_utils → utils_k8s}/service_accounts.py +5 -4
- adam/{k8s_utils → utils_k8s}/services.py +2 -2
- adam/{k8s_utils → utils_k8s}/statefulsets.py +9 -16
- adam/utils_local.py +4 -0
- adam/utils_net.py +24 -0
- adam/utils_repl/__init__.py +0 -0
- adam/utils_repl/appendable_completer.py +6 -0
- adam/utils_repl/automata_completer.py +48 -0
- adam/utils_repl/repl_completer.py +172 -0
- adam/utils_repl/state_machine.py +173 -0
- adam/utils_sqlite.py +137 -0
- adam/version.py +1 -1
- {kaqing-2.0.14.dist-info → kaqing-2.0.189.dist-info}/METADATA +1 -1
- kaqing-2.0.189.dist-info/RECORD +253 -0
- kaqing-2.0.189.dist-info/top_level.txt +2 -0
- teddy/__init__.py +0 -0
- teddy/lark_parser.py +436 -0
- teddy/lark_parser2.py +618 -0
- adam/commands/app.py +0 -67
- adam/commands/bash.py +0 -87
- adam/commands/cp.py +0 -95
- adam/commands/cql_utils.py +0 -53
- adam/commands/devices.py +0 -89
- adam/commands/postgres/postgres_session.py +0 -247
- adam/commands/reaper/reaper_session.py +0 -159
- adam/commands/show/show_app_actions.py +0 -53
- adam/commands/show/show_commands.py +0 -61
- adam/commands/show/show_repairs.py +0 -47
- adam/k8s_utils/cassandra_clusters.py +0 -48
- kaqing-2.0.14.dist-info/RECORD +0 -167
- kaqing-2.0.14.dist-info/top_level.txt +0 -1
- /adam/{k8s_utils → commands/app}/__init__.py +0 -0
- /adam/{k8s_utils → utils_k8s}/config_maps.py +0 -0
- /adam/{k8s_utils → utils_k8s}/volumes.py +0 -0
- {kaqing-2.0.14.dist-info → kaqing-2.0.189.dist-info}/WHEEL +0 -0
- {kaqing-2.0.14.dist-info → kaqing-2.0.189.dist-info}/entry_points.txt +0 -0
adam/commands/kubectl.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
|
|
3
|
+
from adam.commands.command import Command
|
|
4
|
+
from adam.repl_state import ReplState, RequiredState
|
|
5
|
+
|
|
6
|
+
class Kubectl(Command):
|
|
7
|
+
COMMAND = 'k'
|
|
8
|
+
|
|
9
|
+
# the singleton pattern
|
|
10
|
+
def __new__(cls, *args, **kwargs):
|
|
11
|
+
if not hasattr(cls, 'instance'): cls.instance = super(Kubectl, 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 Kubectl.COMMAND
|
|
20
|
+
|
|
21
|
+
def required(self):
|
|
22
|
+
return RequiredState.NAMESPACE
|
|
23
|
+
|
|
24
|
+
def run(self, cmd: str, state: ReplState):
|
|
25
|
+
if not(args := self.args(cmd)):
|
|
26
|
+
return super().run(cmd, state)
|
|
27
|
+
|
|
28
|
+
with self.validate(args, state) as (args, state):
|
|
29
|
+
subprocess.run(["kubectl"] + args)
|
|
30
|
+
|
|
31
|
+
return state
|
|
32
|
+
|
|
33
|
+
def completion(self, state: ReplState):
|
|
34
|
+
return super().completion(state)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def help(self, _: ReplState):
|
|
38
|
+
return f'{Kubectl.COMMAND} \t run a kubectl command'
|
adam/commands/login.py
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import signal
|
|
3
|
-
import traceback
|
|
4
3
|
|
|
5
4
|
from adam.app_session import AppSession
|
|
6
5
|
from adam.apps import Apps
|
|
6
|
+
from adam.commands import extract_options
|
|
7
7
|
from adam.config import Config
|
|
8
8
|
from adam.sso.idp import Idp
|
|
9
9
|
from adam.sso.idp_login import IdpLogin
|
|
10
10
|
from adam.commands.command import Command
|
|
11
11
|
from adam.repl_state import ReplState
|
|
12
|
-
from adam.utils import log, log2
|
|
12
|
+
from adam.utils import log, log2, log_exc
|
|
13
13
|
|
|
14
14
|
class Login(Command):
|
|
15
15
|
COMMAND = 'login'
|
|
@@ -26,41 +26,42 @@ class Login(Command):
|
|
|
26
26
|
def command(self):
|
|
27
27
|
return Login.COMMAND
|
|
28
28
|
|
|
29
|
+
def required(self):
|
|
30
|
+
return ReplState.NON_L
|
|
31
|
+
|
|
29
32
|
def run(self, cmd: str, state: ReplState):
|
|
33
|
+
if not(args := self.args(cmd)):
|
|
34
|
+
return super().run(cmd, state)
|
|
35
|
+
|
|
30
36
|
def custom_handler(signum, frame):
|
|
31
37
|
AppSession.ctrl_c_entered = True
|
|
32
38
|
|
|
33
39
|
signal.signal(signal.SIGINT, custom_handler)
|
|
34
40
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
args, debug = Command.extract_options(args, ['d'])
|
|
40
|
-
if debug:
|
|
41
|
-
Config().set('debug.show-out', True)
|
|
41
|
+
with self.validate(args, state) as (args, state):
|
|
42
|
+
with extract_options(args, 'd') as (args, debug):
|
|
43
|
+
if debug:
|
|
44
|
+
Config().set('debug', True)
|
|
42
45
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
+
username: str = os.getenv('USERNAME')
|
|
47
|
+
if len(args) > 0:
|
|
48
|
+
username = args[0]
|
|
46
49
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
login: IdpLogin = None
|
|
51
|
+
with log_exc(True):
|
|
52
|
+
if not(host := Apps.app_host('c3', 'c3', state.namespace)):
|
|
53
|
+
log2('Cannot locate ingress for app.')
|
|
54
|
+
return state
|
|
52
55
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
except:
|
|
56
|
-
log2(traceback.format_exc())
|
|
56
|
+
if not (login := Idp.login(host, username=username, use_token_from_env=False)):
|
|
57
|
+
log2('Invalid username/password. Please try again.')
|
|
57
58
|
|
|
58
|
-
|
|
59
|
+
log(f'IDP_TOKEN={login.ser() if login else ""}')
|
|
59
60
|
|
|
60
|
-
|
|
61
|
+
return state
|
|
61
62
|
|
|
62
|
-
def completion(self,
|
|
63
|
-
return
|
|
63
|
+
def completion(self, state: ReplState):
|
|
64
|
+
return super().completion(state)
|
|
64
65
|
|
|
65
66
|
def help(self, _: ReplState):
|
|
66
67
|
return f'{Login.COMMAND}\t SSO login'
|
adam/commands/logs.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from adam.commands.command import Command
|
|
2
2
|
from adam.config import Config
|
|
3
|
-
from adam.
|
|
3
|
+
from adam.utils_k8s.cassandra_nodes import CassandraNodes
|
|
4
4
|
from adam.repl_state import ReplState, RequiredState
|
|
5
5
|
|
|
6
6
|
class Logs(Command):
|
|
@@ -25,14 +25,12 @@ class Logs(Command):
|
|
|
25
25
|
if not(args := self.args(cmd)):
|
|
26
26
|
return super().run(cmd, state)
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return state
|
|
31
|
-
|
|
32
|
-
path = Config().get('logs.path', '/c3/cassandra/logs/system.log')
|
|
33
|
-
return CassandraNodes.exec(state.pod, state.namespace, f'cat {path}')
|
|
28
|
+
with self.validate(args, state) as (args, state):
|
|
29
|
+
path = Config().get('logs.path', '/c3/cassandra/logs/system.log')
|
|
30
|
+
return CassandraNodes.exec(state.pod, state.namespace, f'cat {path}')
|
|
34
31
|
|
|
35
32
|
def completion(self, _: ReplState):
|
|
33
|
+
# available only on cli
|
|
36
34
|
return {}
|
|
37
35
|
|
|
38
36
|
def help(self, _: ReplState):
|
adam/commands/ls.py
CHANGED
|
@@ -1,20 +1,8 @@
|
|
|
1
1
|
import copy
|
|
2
|
-
import re
|
|
3
2
|
|
|
4
3
|
from adam.commands.command import Command
|
|
5
|
-
from adam.commands.
|
|
6
|
-
from adam.commands.cqlsh import Cqlsh
|
|
7
|
-
from adam.commands.postgres.postgres_session import PostgresSession
|
|
8
|
-
from adam.config import Config
|
|
9
|
-
from adam.k8s_utils.custom_resources import CustomResources
|
|
10
|
-
from adam.k8s_utils.ingresses import Ingresses
|
|
11
|
-
from adam.k8s_utils.kube_context import KubeContext
|
|
12
|
-
from adam.k8s_utils.services import Services
|
|
13
|
-
from adam.k8s_utils.statefulsets import StatefulSets
|
|
14
|
-
from adam.pod_exec_result import PodExecResult
|
|
4
|
+
from adam.commands.devices.devices import Devices
|
|
15
5
|
from adam.repl_state import ReplState
|
|
16
|
-
from adam.utils import lines_to_tabular, log, log2
|
|
17
|
-
from adam.apps import Apps
|
|
18
6
|
|
|
19
7
|
class Ls(Command):
|
|
20
8
|
COMMAND = 'ls'
|
|
@@ -35,111 +23,19 @@ class Ls(Command):
|
|
|
35
23
|
if not(args := self.args(cmd)):
|
|
36
24
|
return super().run(cmd, state)
|
|
37
25
|
|
|
38
|
-
|
|
26
|
+
with self.validate(args, state) as (args, state):
|
|
27
|
+
if len(args) > 0:
|
|
28
|
+
arg = args[0]
|
|
29
|
+
if arg in ['p:', 'c:'] and arg != f'{state.device}:':
|
|
30
|
+
state = copy.copy(state)
|
|
31
|
+
state.device = arg.replace(':', '')
|
|
39
32
|
|
|
40
|
-
|
|
41
|
-
arg = args[0]
|
|
42
|
-
if arg in ['p:', 'c:'] and arg != f'{state.device}:':
|
|
43
|
-
state = copy.copy(state)
|
|
44
|
-
state.device = arg.replace(':', '')
|
|
33
|
+
Devices.device(state).ls(cmd, state)
|
|
45
34
|
|
|
46
|
-
|
|
47
|
-
if state.pg_path:
|
|
48
|
-
pg = PostgresSession(state.namespace, state.pg_path)
|
|
49
|
-
if pg.db:
|
|
50
|
-
self.show_pg_tables(pg)
|
|
51
|
-
else:
|
|
52
|
-
self.show_pg_databases(pg)
|
|
53
|
-
else:
|
|
54
|
-
self.show_pg_hosts(state)
|
|
55
|
-
elif state.device == ReplState.A:
|
|
56
|
-
if state.app_env:
|
|
57
|
-
def line(n: str, ns: str):
|
|
58
|
-
host = Ingresses.get_host(Config().get('app.login.ingress', '{app_id}-k8singr-appleader-001').replace('{app_id}', f'{ns}-{n}'), ns)
|
|
59
|
-
if not host:
|
|
60
|
-
return None
|
|
61
|
-
|
|
62
|
-
endpoint = Config().get('app.login.url', 'https://{host}/{env}/{app}').replace('{host}', host).replace('{env}', state.app_env).replace('{app}', 'c3')
|
|
63
|
-
if not endpoint:
|
|
64
|
-
return None
|
|
65
|
-
|
|
66
|
-
return f"{n.split('-')[1]},{Ingresses.get_host(f'{ns}-{n}-k8singr-appleader-001', ns)},{endpoint}"
|
|
67
|
-
|
|
68
|
-
svcs = [l for l in [line(n, ns) for n, ns in Apps.apps(state.app_env)] if l]
|
|
69
|
-
|
|
70
|
-
log(lines_to_tabular(svcs, 'APP,HOST,ENDPOINT', separator=','))
|
|
71
|
-
else:
|
|
72
|
-
svcs = [n for n, ns in Apps.envs()]
|
|
73
|
-
|
|
74
|
-
log(lines_to_tabular(svcs, 'ENV', separator=','))
|
|
75
|
-
else:
|
|
76
|
-
if state.pod:
|
|
77
|
-
r: PodExecResult = Cqlsh().run(f'cql describe tables', state)
|
|
78
|
-
if r.stderr:
|
|
79
|
-
log(r.stderr)
|
|
80
|
-
log(r.stdout)
|
|
81
|
-
elif state.sts and state.namespace:
|
|
82
|
-
show_pods(StatefulSets.pods(state.sts, state.namespace), state.namespace, show_namespace=not KubeContext.in_cluster_namespace())
|
|
83
|
-
show_rollout(state.sts, state.namespace)
|
|
84
|
-
else:
|
|
85
|
-
self.show_statefulsets()
|
|
86
|
-
|
|
87
|
-
return state
|
|
88
|
-
|
|
89
|
-
def show_statefulsets(self):
|
|
90
|
-
ss = StatefulSets.list_sts_names(show_namespace=not KubeContext.in_cluster_namespace())
|
|
91
|
-
if len(ss) == 0:
|
|
92
|
-
log2('No cassandra statefulsets found.')
|
|
93
|
-
return
|
|
94
|
-
|
|
95
|
-
app_ids = CustomResources.get_app_ids()
|
|
96
|
-
list = []
|
|
97
|
-
for s in ss:
|
|
98
|
-
cr_name = CustomResources.get_cr_name(s)
|
|
99
|
-
app_id = 'Unknown'
|
|
100
|
-
if cr_name in app_ids:
|
|
101
|
-
app_id = app_ids[cr_name]
|
|
102
|
-
list.append(f"{s} {app_id}")
|
|
103
|
-
|
|
104
|
-
header = 'STATEFULSET_NAME@NAMESPACE APP_ID'
|
|
105
|
-
if KubeContext.in_cluster_namespace():
|
|
106
|
-
header = 'STATEFULSET_NAME APP_ID'
|
|
107
|
-
log(lines_to_tabular(list, header))
|
|
108
|
-
|
|
109
|
-
def show_pg_hosts(self, state: ReplState):
|
|
110
|
-
if state.namespace:
|
|
111
|
-
def line(pg: PostgresSession):
|
|
112
|
-
return f'{pg.directory()},{pg.endpoint()}:{pg.port()},{pg.username()},{pg.password()}'
|
|
113
|
-
|
|
114
|
-
lines = [line(PostgresSession(state.namespace, pg)) for pg in PostgresSession.hosts(state.namespace)]
|
|
115
|
-
|
|
116
|
-
log(lines_to_tabular(lines, 'NAME,ENDPOINT,USERNAME,PASSWORD', separator=','))
|
|
117
|
-
else:
|
|
118
|
-
def line(pg: PostgresSession):
|
|
119
|
-
return f'{pg.directory()},{pg.namespace},{pg.endpoint()}:{pg.port()},{pg.username()},{pg.password()}'
|
|
120
|
-
|
|
121
|
-
lines = [line(PostgresSession(state.namespace, pg)) for pg in PostgresSession.hosts(state.namespace)]
|
|
122
|
-
|
|
123
|
-
log(lines_to_tabular(lines, 'NAME,NAMESPACE,ENDPOINT,USERNAME,PASSWORD', separator=','))
|
|
124
|
-
|
|
125
|
-
def show_pg_databases(self, pg: PostgresSession):
|
|
126
|
-
lines = [db["name"] for db in pg.databases() if db["owner"] == PostgresSession.default_owner()]
|
|
127
|
-
|
|
128
|
-
log(lines_to_tabular(lines, 'DATABASE', separator=','))
|
|
129
|
-
|
|
130
|
-
def show_pg_tables(self, pg: PostgresSession):
|
|
131
|
-
lines = [db["name"] for db in pg.tables() if db["schema"] == PostgresSession.default_schema()]
|
|
132
|
-
|
|
133
|
-
log(lines_to_tabular(lines, 'NAME', separator=','))
|
|
35
|
+
return state
|
|
134
36
|
|
|
135
37
|
def completion(self, state: ReplState):
|
|
136
|
-
|
|
137
|
-
return {}
|
|
138
|
-
|
|
139
|
-
if not state.sts:
|
|
140
|
-
return {Ls.COMMAND: {n: None for n in StatefulSets.list_sts_names()}}
|
|
141
|
-
|
|
142
|
-
return {Ls.COMMAND: None}
|
|
38
|
+
return super().completion(state, {'&': None}, pods=Devices.device(state).pods(state, '-'))
|
|
143
39
|
|
|
144
40
|
def help(self, _: ReplState):
|
|
145
|
-
return f'{Ls.COMMAND} [device:]\t list apps, envs, clusters, nodes, pg hosts or
|
|
41
|
+
return f'{Ls.COMMAND} [device:]\t list apps, envs, clusters, nodes, pg hosts/databases or export databases'
|
adam/commands/medusa/medusa.py
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import click
|
|
2
2
|
|
|
3
3
|
from adam.commands.command import Command
|
|
4
|
-
from adam.commands.
|
|
4
|
+
from adam.commands.intermediate_command import IntermediateCommand
|
|
5
5
|
from .medusa_backup import MedusaBackup
|
|
6
6
|
from .medusa_restore import MedusaRestore
|
|
7
7
|
from .medusa_show_backupjobs import MedusaShowBackupJobs
|
|
8
8
|
from .medusa_show_restorejobs import MedusaShowRestoreJobs
|
|
9
|
-
from adam.repl_state import ReplState, RequiredState
|
|
10
|
-
from adam.utils import lines_to_tabular, log, log2
|
|
11
9
|
|
|
12
|
-
class Medusa(
|
|
10
|
+
class Medusa(IntermediateCommand):
|
|
13
11
|
COMMAND = 'medusa'
|
|
14
12
|
|
|
15
13
|
# the singleton pattern
|
|
@@ -18,52 +16,12 @@ class Medusa(Command):
|
|
|
18
16
|
|
|
19
17
|
return cls.instance
|
|
20
18
|
|
|
21
|
-
def __init__(self, successor: Command=None):
|
|
22
|
-
super().__init__(successor)
|
|
23
|
-
|
|
24
19
|
def command(self):
|
|
25
20
|
return Medusa.COMMAND
|
|
26
21
|
|
|
27
|
-
def
|
|
28
|
-
return RequiredState.CLUSTER
|
|
29
|
-
|
|
30
|
-
def run(self, cmd: str, state: ReplState):
|
|
31
|
-
if not(args := self.args(cmd)):
|
|
32
|
-
return super().run(cmd, state)
|
|
33
|
-
|
|
34
|
-
state, args = self.apply_state(args, state)
|
|
35
|
-
if not self.validate_state(state):
|
|
36
|
-
return state
|
|
37
|
-
|
|
38
|
-
if state.in_repl:
|
|
39
|
-
log(lines_to_tabular([c.help(ReplState()) for c in Medusa.cmd_list()], separator=':'))
|
|
40
|
-
|
|
41
|
-
return 'command-missing'
|
|
42
|
-
else:
|
|
43
|
-
# head with the Chain of Responsibility pattern
|
|
44
|
-
cmds = Command.chain(Medusa.cmd_list())
|
|
45
|
-
if not cmds.run(cmd, state):
|
|
46
|
-
log2('* Command is missing.')
|
|
47
|
-
Command.display_help()
|
|
48
|
-
|
|
49
|
-
def cmd_list():
|
|
22
|
+
def cmd_list(self):
|
|
50
23
|
return [MedusaBackup(), MedusaRestore(), MedusaShowBackupJobs(), MedusaShowRestoreJobs()]
|
|
51
24
|
|
|
52
|
-
def completion(self, state: ReplState):
|
|
53
|
-
if state.sts:
|
|
54
|
-
return super().completion(state)
|
|
55
|
-
|
|
56
|
-
return {}
|
|
57
|
-
|
|
58
|
-
def help(self, _: ReplState):
|
|
59
|
-
return None
|
|
60
|
-
|
|
61
25
|
class MedusaCommandHelper(click.Command):
|
|
62
26
|
def get_help(self, ctx: click.Context):
|
|
63
|
-
|
|
64
|
-
log()
|
|
65
|
-
log('Sub-Commands:')
|
|
66
|
-
|
|
67
|
-
log(lines_to_tabular([c.help(ReplState()).replace(f'{Medusa.COMMAND} ', ' ', 1) for c in Medusa.cmd_list()], separator=':'))
|
|
68
|
-
log()
|
|
69
|
-
ClusterCommandHelper.cluster_help()
|
|
27
|
+
IntermediateCommand.intermediate_help(super().get_help(ctx), Medusa.COMMAND, Medusa().cmd_list(), show_cluster_help=True)
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
|
-
import re
|
|
3
2
|
|
|
3
|
+
from adam.commands import validate_args
|
|
4
4
|
from adam.commands.command import Command
|
|
5
|
-
from adam.
|
|
5
|
+
from adam.utils_k8s.statefulsets import StatefulSets
|
|
6
6
|
from adam.repl_state import ReplState, RequiredState
|
|
7
|
-
from adam.
|
|
7
|
+
from adam.utils_k8s.custom_resources import CustomResources
|
|
8
8
|
from adam.utils import log2
|
|
9
9
|
|
|
10
|
-
|
|
11
10
|
class MedusaBackup(Command):
|
|
12
11
|
COMMAND = 'backup'
|
|
13
12
|
|
|
@@ -29,33 +28,27 @@ class MedusaBackup(Command):
|
|
|
29
28
|
def run(self, cmd: str, state: ReplState):
|
|
30
29
|
if not(args := self.args(cmd)):
|
|
31
30
|
return super().run(cmd, state)
|
|
32
|
-
state, args = self.apply_state(args, state)
|
|
33
|
-
if not self.validate_state(state):
|
|
34
|
-
return state
|
|
35
|
-
|
|
36
|
-
ns = state.namespace
|
|
37
|
-
sts = state.sts
|
|
38
|
-
now_dtformat = datetime.now().strftime("%Y-%m-%d.%H.%M.%S")
|
|
39
|
-
bkname = 'medusa-' + now_dtformat + 'full-backup-' + sts
|
|
40
|
-
if len(args) == 1:
|
|
41
|
-
bkname = str(args[0])
|
|
42
|
-
groups = re.match(r'^(.*?-.*?-).*', sts)
|
|
43
|
-
dc = StatefulSets.get_datacenter(state.sts, ns)
|
|
44
|
-
if not dc:
|
|
45
|
-
return state
|
|
46
|
-
|
|
47
|
-
try:
|
|
48
|
-
CustomResources.create_medusa_backupjob(bkname, dc, ns)
|
|
49
|
-
except Exception as e:
|
|
50
|
-
log2("Exception: MedusaBackup failed: %s\n" % e)
|
|
51
|
-
|
|
52
|
-
return state
|
|
53
31
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
32
|
+
with self.validate(args, state) as (args, state):
|
|
33
|
+
ns = state.namespace
|
|
34
|
+
sts = state.sts
|
|
35
|
+
now_dtformat = datetime.now().strftime("%Y-%m-%d.%H.%M.%S")
|
|
36
|
+
with validate_args(args, state, default='medusa-' + now_dtformat + 'full-backup-' + sts) as bkname:
|
|
37
|
+
dc = StatefulSets.get_datacenter(state.sts, ns)
|
|
38
|
+
if not dc:
|
|
39
|
+
return state
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
CustomResources.create_medusa_backupjob(bkname, dc, ns)
|
|
43
|
+
except Exception as e:
|
|
44
|
+
log2("Exception: MedusaBackup failed: %s\n" % e)
|
|
45
|
+
finally:
|
|
46
|
+
CustomResources.clear_caches()
|
|
57
47
|
|
|
58
|
-
|
|
48
|
+
return state
|
|
49
|
+
|
|
50
|
+
def completion(self, state: ReplState):
|
|
51
|
+
return super().completion(state)
|
|
59
52
|
|
|
60
53
|
def help(self, _: ReplState):
|
|
61
54
|
return f'{MedusaBackup.COMMAND}\t start a backup job'
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
1
2
|
from datetime import datetime
|
|
3
|
+
from functools import partial
|
|
2
4
|
|
|
3
|
-
from adam.commands
|
|
4
|
-
from adam.
|
|
5
|
+
from adam.commands import validate_args
|
|
6
|
+
from adam.commands.command import Command, InvalidArgumentsException
|
|
7
|
+
from adam.commands.medusa.utils_medusa import medusa_backup_names
|
|
8
|
+
from adam.utils_k8s.statefulsets import StatefulSets
|
|
5
9
|
from adam.repl_state import ReplState, RequiredState
|
|
6
|
-
from adam.
|
|
10
|
+
from adam.utils_k8s.custom_resources import CustomResources
|
|
7
11
|
from adam.config import Config
|
|
8
|
-
from adam.utils import
|
|
12
|
+
from adam.utils import tabulize, log2, log_exc
|
|
9
13
|
|
|
10
14
|
class MedusaRestore(Command):
|
|
11
15
|
COMMAND = 'restore'
|
|
@@ -28,57 +32,55 @@ class MedusaRestore(Command):
|
|
|
28
32
|
def run(self, cmd: str, state: ReplState):
|
|
29
33
|
if not(args := self.args(cmd)):
|
|
30
34
|
return super().run(cmd, state)
|
|
31
|
-
state, args = self.apply_state(args, state)
|
|
32
|
-
if not self.validate_state(state):
|
|
33
|
-
return state
|
|
34
|
-
|
|
35
|
-
ns = state.namespace
|
|
36
|
-
dc = StatefulSets.get_datacenter(state.sts, ns)
|
|
37
|
-
if not dc:
|
|
38
|
-
return state
|
|
39
|
-
|
|
40
|
-
if len(args) == 1:
|
|
41
|
-
bkname = args[0]
|
|
42
|
-
job = CustomResources.medusa_get_backupjob(dc, ns, bkname)
|
|
43
|
-
if not job:
|
|
44
|
-
log2('\n* Backup job name is not valid.')
|
|
45
|
-
bklist = [f"{x['metadata']['name']}\t{x['metadata']['creationTimestamp']}\t{x['status'].get('finishTime', '')}" for x in CustomResources.medusa_show_backupjobs(dc, ns)]
|
|
46
|
-
log2(lines_to_tabular(bklist, 'NAME\tCREATED\tFINISHED', separator='\t'))
|
|
47
35
|
|
|
36
|
+
with self.validate(args, state) as (args, state):
|
|
37
|
+
ns = state.namespace
|
|
38
|
+
dc: str = StatefulSets.get_datacenter(state.sts, ns)
|
|
39
|
+
if not dc:
|
|
48
40
|
return state
|
|
49
41
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
log2(lines_to_tabular(bklist, 'NAME\tCREATED\tFINISHED', separator='\t'))
|
|
57
|
-
return state
|
|
58
|
-
|
|
59
|
-
now_dtformat = datetime.now().strftime("%Y-%m-%d.%H.%M.%S")
|
|
60
|
-
rtname = 'medusa-' + now_dtformat + '-restore-from-' + bkname
|
|
61
|
-
try:
|
|
62
|
-
print('SEAN doing')
|
|
63
|
-
# CustomResources.create_medusa_restorejob(rtname, bkname, dc, ns)
|
|
64
|
-
except Exception as e:
|
|
65
|
-
log2("Exception: MedusaRestore failed: %s\n" % e)
|
|
66
|
-
|
|
67
|
-
return state
|
|
42
|
+
def msg(missing: bool):
|
|
43
|
+
if missing:
|
|
44
|
+
log2('\n* Missing Backup Name')
|
|
45
|
+
log2('Usage: qing restore <backup> <sts@name_space>\n')
|
|
46
|
+
else:
|
|
47
|
+
log2('\n* Backup job name is not valid.')
|
|
68
48
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
return {}
|
|
49
|
+
tabulize(CustomResources.medusa_show_backupjobs(dc, ns),
|
|
50
|
+
lambda x: f"{x['metadata']['name']}\t{x['metadata']['creationTimestamp']}\t{x['status'].get('finishTime', '')}",
|
|
51
|
+
header='NAME\tCREATED\tFINISHED',
|
|
52
|
+
separator='\t',
|
|
53
|
+
to=2)
|
|
75
54
|
|
|
76
|
-
|
|
77
|
-
|
|
55
|
+
with validate_args(args, state, msg=partial(msg, True)) as bkname:
|
|
56
|
+
if not (job := CustomResources.medusa_get_backupjob(dc, ns, bkname)):
|
|
57
|
+
msg(False)
|
|
58
|
+
raise InvalidArgumentsException()
|
|
78
59
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
60
|
+
if not input(f"Restoring from {bkname} created at {job['metadata']['creationTimestamp']}. Please enter Yes to continue: ").lower() in ['y', 'yes']:
|
|
61
|
+
return state
|
|
62
|
+
|
|
63
|
+
with log_exc(lambda e: "Exception: MedusaRestore failed: %s\n" % e):
|
|
64
|
+
now_dtformat = datetime.now().strftime("%Y-%m-%d.%H.%M.%S")
|
|
65
|
+
rtname = 'medusa-' + now_dtformat + '-restore-from-' + bkname
|
|
66
|
+
CustomResources.create_medusa_restorejob(rtname, bkname, dc, ns)
|
|
67
|
+
|
|
68
|
+
return state
|
|
69
|
+
|
|
70
|
+
def completion(self, state: ReplState):
|
|
71
|
+
return super().completion(state, lambda: {id: None for id in medusa_backup_names(state)}, auto_key='medusa.backups')
|
|
72
|
+
# if sc := super().completion(state):
|
|
73
|
+
# ns = state.namespace
|
|
74
|
+
# dc: str = StatefulSets.get_datacenter(state.sts, ns)
|
|
75
|
+
# if not dc:
|
|
76
|
+
# return {}
|
|
77
|
+
|
|
78
|
+
# if Config().get('medusa.restore-auto-complete', False):
|
|
79
|
+
# leaf = {id: None for id in [f"{x['metadata']['name']}" for x in CustomResources.medusa_show_backupjobs(dc, ns)]}
|
|
80
|
+
|
|
81
|
+
# return super().completion(state, leaf)
|
|
82
|
+
# else:
|
|
83
|
+
# return sc
|
|
82
84
|
|
|
83
85
|
return {}
|
|
84
86
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
from adam.commands.command import Command
|
|
2
|
-
from adam.
|
|
2
|
+
from adam.utils_k8s.statefulsets import StatefulSets
|
|
3
3
|
from adam.repl_state import ReplState, RequiredState
|
|
4
|
-
from adam.
|
|
5
|
-
from adam.utils import
|
|
4
|
+
from adam.utils_k8s.custom_resources import CustomResources
|
|
5
|
+
from adam.utils import tabulize, log_exc
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class MedusaShowBackupJobs(Command):
|
|
@@ -26,27 +26,26 @@ class MedusaShowBackupJobs(Command):
|
|
|
26
26
|
def run(self, cmd: str, state: ReplState):
|
|
27
27
|
if not(args := self.args(cmd)):
|
|
28
28
|
return super().run(cmd, state)
|
|
29
|
-
state, args = self.apply_state(args, state)
|
|
30
|
-
if not self.validate_state(state):
|
|
31
|
-
return state
|
|
32
|
-
ns = state.namespace
|
|
33
|
-
dc = StatefulSets.get_datacenter(state.sts, ns)
|
|
34
|
-
if not dc:
|
|
35
|
-
return state
|
|
36
29
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
30
|
+
with self.validate(args, state) as (args, state):
|
|
31
|
+
ns = state.namespace
|
|
32
|
+
dc = StatefulSets.get_datacenter(state.sts, ns)
|
|
33
|
+
if not dc:
|
|
34
|
+
return state
|
|
42
35
|
|
|
43
|
-
|
|
36
|
+
with log_exc(lambda e: "Exception: MedusaShowBackupJobs failed: %s\n" % e):
|
|
37
|
+
CustomResources.clear_caches()
|
|
44
38
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
39
|
+
tabulize(CustomResources.medusa_show_backupjobs(dc, ns),
|
|
40
|
+
lambda x: f"{x['metadata']['name']}\t{x['metadata']['creationTimestamp']}\t{x['status'].get('finishTime', '') if 'status' in x else 'unknown'}",
|
|
41
|
+
header='NAME\tCREATED\tFINISHED',
|
|
42
|
+
separator='\t',
|
|
43
|
+
to=2)
|
|
48
44
|
|
|
49
|
-
|
|
45
|
+
return state
|
|
46
|
+
|
|
47
|
+
def completion(self, state: ReplState):
|
|
48
|
+
return super().completion(state)
|
|
50
49
|
|
|
51
50
|
def help(self, _: ReplState):
|
|
52
|
-
return f'{MedusaShowBackupJobs.COMMAND}\t show backups'
|
|
51
|
+
return f'{MedusaShowBackupJobs.COMMAND}\t show Medusa backups'
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
from adam.commands.command import Command
|
|
2
|
-
from adam.
|
|
2
|
+
from adam.utils_k8s.statefulsets import StatefulSets
|
|
3
3
|
from adam.repl_state import ReplState, RequiredState
|
|
4
|
-
from adam.
|
|
5
|
-
from adam.utils import
|
|
4
|
+
from adam.utils_k8s.custom_resources import CustomResources
|
|
5
|
+
from adam.utils import tabulize, log_exc
|
|
6
6
|
|
|
7
7
|
class MedusaShowRestoreJobs(Command):
|
|
8
8
|
COMMAND = 'show restores'
|
|
@@ -25,28 +25,23 @@ class MedusaShowRestoreJobs(Command):
|
|
|
25
25
|
def run(self, cmd: str, state: ReplState):
|
|
26
26
|
if not(args := self.args(cmd)):
|
|
27
27
|
return super().run(cmd, state)
|
|
28
|
-
state, args = self.apply_state(args, state)
|
|
29
|
-
if not self.validate_state(state):
|
|
30
|
-
return state
|
|
31
28
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
29
|
+
with self.validate(args, state) as (args, state):
|
|
30
|
+
ns = state.namespace
|
|
31
|
+
dc = StatefulSets.get_datacenter(state.sts, ns)
|
|
32
|
+
if not dc:
|
|
33
|
+
return state
|
|
36
34
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
35
|
+
with log_exc(lambda e: "Exception: MedusaShowRestoreJobs failed: %s\n" % e):
|
|
36
|
+
tabulize(CustomResources.medusa_show_restorejobs(dc, ns),
|
|
37
|
+
header='NAME\tCREATED\tFINISHED',
|
|
38
|
+
separator='\t',
|
|
39
|
+
to=2)
|
|
42
40
|
|
|
43
|
-
|
|
41
|
+
return state
|
|
44
42
|
|
|
45
43
|
def completion(self, state: ReplState):
|
|
46
|
-
|
|
47
|
-
return super().completion(state)
|
|
48
|
-
|
|
49
|
-
return {}
|
|
44
|
+
return super().completion(state)
|
|
50
45
|
|
|
51
46
|
def help(self, _: ReplState):
|
|
52
|
-
return f'{MedusaShowRestoreJobs.COMMAND}\t show restores'
|
|
47
|
+
return f'{MedusaShowRestoreJobs.COMMAND}\t show Medusa restores'
|