kaqing 2.0.145__py3-none-any.whl → 2.0.174__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 +8 -11
- adam/batch.py +3 -3
- adam/checks/check_utils.py +14 -46
- adam/checks/cpu.py +7 -1
- adam/checks/cpu_metrics.py +52 -0
- adam/checks/disk.py +2 -3
- 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 +22 -0
- adam/commands/alter_tables.py +33 -48
- adam/commands/audit/audit.py +22 -23
- adam/commands/audit/audit_repair_tables.py +14 -17
- adam/commands/audit/audit_run.py +15 -23
- adam/commands/audit/show_last10.py +10 -13
- adam/commands/audit/show_slow10.py +10 -13
- adam/commands/audit/show_top10.py +10 -13
- adam/commands/audit/utils_show_top10.py +2 -3
- adam/commands/bash/__init__.py +5 -0
- adam/commands/bash/bash.py +7 -104
- adam/commands/bash/utils_bash.py +16 -0
- adam/commands/cat.py +7 -23
- adam/commands/cd.py +7 -11
- adam/commands/check.py +14 -23
- adam/commands/cli_commands.py +2 -3
- adam/commands/code.py +20 -23
- adam/commands/command.py +152 -37
- adam/commands/commands_utils.py +8 -17
- adam/commands/cp.py +18 -32
- adam/commands/cql/cql_completions.py +11 -7
- adam/commands/cql/cqlsh.py +10 -30
- adam/commands/cql/{cql_utils.py → utils_cql.py} +147 -15
- 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 -27
- adam/commands/deploy/deploy_frontend.py +14 -17
- adam/commands/deploy/deploy_pg_agent.py +2 -5
- adam/commands/deploy/deploy_pod.py +64 -68
- adam/commands/deploy/undeploy.py +4 -27
- adam/commands/deploy/undeploy_frontend.py +4 -7
- adam/commands/deploy/undeploy_pg_agent.py +4 -7
- adam/commands/deploy/undeploy_pod.py +9 -12
- adam/commands/devices/device.py +93 -2
- adam/commands/devices/device_app.py +37 -10
- adam/commands/devices/device_auit_log.py +8 -2
- adam/commands/devices/device_cass.py +47 -7
- adam/commands/devices/device_export.py +9 -11
- adam/commands/devices/device_postgres.py +41 -6
- adam/commands/exit.py +1 -4
- adam/commands/export/clean_up_all_export_sessions.py +37 -0
- adam/commands/export/clean_up_export_sessions.py +12 -8
- adam/commands/export/drop_export_database.py +7 -26
- adam/commands/export/drop_export_databases.py +5 -14
- adam/commands/export/export.py +8 -38
- adam/commands/export/export_databases.py +86 -27
- adam/commands/export/export_select.py +25 -27
- adam/commands/export/export_select_x.py +3 -3
- adam/commands/export/export_sessions.py +124 -0
- adam/commands/export/export_use.py +8 -17
- adam/commands/export/exporter.py +88 -158
- adam/commands/export/import_session.py +7 -35
- adam/commands/export/importer.py +12 -5
- adam/commands/export/importer_athena.py +21 -20
- adam/commands/export/importer_sqlite.py +16 -21
- adam/commands/export/show_column_counts.py +7 -25
- adam/commands/export/show_export_databases.py +4 -6
- adam/commands/export/show_export_session.py +7 -18
- adam/commands/export/show_export_sessions.py +9 -12
- adam/commands/export/utils_export.py +26 -1
- adam/commands/intermediate_command.py +49 -0
- adam/commands/issues.py +11 -43
- adam/commands/kubectl.py +3 -6
- adam/commands/login.py +22 -24
- adam/commands/logs.py +3 -6
- adam/commands/ls.py +8 -9
- adam/commands/medusa/medusa.py +4 -22
- adam/commands/medusa/medusa_backup.py +20 -25
- adam/commands/medusa/medusa_restore.py +34 -36
- adam/commands/medusa/medusa_show_backupjobs.py +14 -18
- adam/commands/medusa/medusa_show_restorejobs.py +11 -18
- adam/commands/nodetool.py +6 -15
- adam/commands/param_get.py +11 -13
- adam/commands/param_set.py +8 -12
- adam/commands/postgres/postgres.py +22 -38
- adam/commands/postgres/postgres_context.py +47 -23
- adam/commands/postgres/postgres_ls.py +4 -8
- adam/commands/postgres/postgres_preview.py +5 -9
- adam/commands/postgres/psql_completions.py +1 -1
- adam/commands/postgres/utils_postgres.py +70 -0
- adam/commands/preview_table.py +6 -45
- adam/commands/pwd.py +13 -16
- adam/commands/reaper/reaper.py +4 -27
- 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 +8 -33
- adam/commands/reaper/reaper_runs.py +42 -57
- adam/commands/reaper/reaper_runs_abort.py +29 -49
- adam/commands/reaper/reaper_schedule_activate.py +9 -32
- adam/commands/reaper/reaper_schedule_start.py +9 -32
- adam/commands/reaper/reaper_schedule_stop.py +9 -32
- 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 +5 -11
- adam/commands/repair/repair_run.py +27 -34
- adam/commands/repair/repair_scan.py +32 -38
- adam/commands/repair/repair_stop.py +5 -11
- adam/commands/report.py +27 -29
- adam/commands/restart.py +25 -26
- adam/commands/rollout.py +19 -24
- adam/commands/shell.py +10 -4
- adam/commands/show/show.py +10 -26
- adam/commands/show/show_cassandra_repairs.py +35 -0
- adam/commands/show/show_cassandra_status.py +32 -43
- adam/commands/show/show_cassandra_version.py +5 -18
- adam/commands/show/show_commands.py +19 -24
- adam/commands/show/show_host.py +1 -1
- adam/commands/show/show_login.py +20 -27
- adam/commands/show/show_processes.py +15 -19
- adam/commands/show/show_storage.py +10 -20
- adam/commands/watch.py +26 -29
- adam/config.py +4 -16
- adam/embedded_params.py +1 -1
- adam/log.py +4 -4
- adam/pod_exec_result.py +3 -3
- adam/repl.py +31 -32
- adam/repl_commands.py +11 -11
- adam/repl_state.py +52 -26
- adam/sql/sql_completer.py +4 -6
- adam/sql/sql_state_machine.py +21 -14
- adam/sso/authn_ad.py +6 -8
- adam/sso/authn_okta.py +4 -6
- adam/sso/cred_cache.py +3 -5
- adam/sso/idp.py +9 -12
- adam/utils.py +393 -33
- adam/utils_athena.py +14 -13
- adam/utils_audits.py +12 -12
- adam/utils_issues.py +32 -0
- adam/utils_k8s/app_clusters.py +13 -18
- adam/utils_k8s/app_pods.py +2 -0
- adam/utils_k8s/cassandra_clusters.py +21 -18
- adam/utils_k8s/custom_resources.py +16 -17
- adam/utils_k8s/ingresses.py +2 -2
- adam/utils_k8s/jobs.py +7 -11
- adam/utils_k8s/k8s.py +87 -0
- adam/utils_k8s/pods.py +14 -76
- 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_repl/state_machine.py +3 -3
- adam/utils_sqlite.py +78 -42
- adam/version.py +1 -1
- {kaqing-2.0.145.dist-info → kaqing-2.0.174.dist-info}/METADATA +1 -1
- kaqing-2.0.174.dist-info/RECORD +230 -0
- adam/commands/app.py +0 -67
- adam/commands/app_ping.py +0 -44
- adam/commands/export/clean_up_export_session.py +0 -53
- adam/commands/postgres/postgres_utils.py +0 -31
- adam/commands/reaper/reaper_session.py +0 -159
- adam/commands/show/show_app_actions.py +0 -56
- adam/commands/show/show_app_id.py +0 -47
- adam/commands/show/show_app_queues.py +0 -45
- adam/commands/show/show_repairs.py +0 -47
- kaqing-2.0.145.dist-info/RECORD +0 -227
- {kaqing-2.0.145.dist-info → kaqing-2.0.174.dist-info}/WHEEL +0 -0
- {kaqing-2.0.145.dist-info → kaqing-2.0.174.dist-info}/entry_points.txt +0 -0
- {kaqing-2.0.145.dist-info → kaqing-2.0.174.dist-info}/top_level.txt +0 -0
adam/commands/medusa/medusa.py
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import click
|
|
2
2
|
|
|
3
3
|
from adam.commands.command import Command
|
|
4
|
+
from adam.commands.intermediate_command import IntermediateCommand
|
|
4
5
|
from .medusa_backup import MedusaBackup
|
|
5
6
|
from .medusa_restore import MedusaRestore
|
|
6
7
|
from .medusa_show_backupjobs import MedusaShowBackupJobs
|
|
7
8
|
from .medusa_show_restorejobs import MedusaShowRestoreJobs
|
|
8
|
-
from adam.repl_state import ReplState, RequiredState
|
|
9
9
|
|
|
10
|
-
class Medusa(
|
|
10
|
+
class Medusa(IntermediateCommand):
|
|
11
11
|
COMMAND = 'medusa'
|
|
12
12
|
|
|
13
13
|
# the singleton pattern
|
|
@@ -16,30 +16,12 @@ class Medusa(Command):
|
|
|
16
16
|
|
|
17
17
|
return cls.instance
|
|
18
18
|
|
|
19
|
-
def __init__(self, successor: Command=None):
|
|
20
|
-
super().__init__(successor)
|
|
21
|
-
|
|
22
19
|
def command(self):
|
|
23
20
|
return Medusa.COMMAND
|
|
24
21
|
|
|
25
|
-
def
|
|
26
|
-
return RequiredState.CLUSTER
|
|
27
|
-
|
|
28
|
-
def run(self, cmd: str, state: ReplState):
|
|
29
|
-
if not(args := self.args(cmd)):
|
|
30
|
-
return super().run(cmd, state)
|
|
31
|
-
|
|
32
|
-
return super().intermediate_run(cmd, state, args, Medusa.cmd_list())
|
|
33
|
-
|
|
34
|
-
def cmd_list():
|
|
22
|
+
def cmd_list(self):
|
|
35
23
|
return [MedusaBackup(), MedusaRestore(), MedusaShowBackupJobs(), MedusaShowRestoreJobs()]
|
|
36
24
|
|
|
37
|
-
def completion(self, state: ReplState):
|
|
38
|
-
if state.sts:
|
|
39
|
-
return super().completion(state)
|
|
40
|
-
|
|
41
|
-
return {}
|
|
42
|
-
|
|
43
25
|
class MedusaCommandHelper(click.Command):
|
|
44
26
|
def get_help(self, ctx: click.Context):
|
|
45
|
-
|
|
27
|
+
IntermediateCommand.intermediate_help(super().get_help(ctx), Medusa.COMMAND, Medusa().cmd_list(), show_cluster_help=True)
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
|
-
import re
|
|
3
2
|
|
|
4
3
|
from adam.commands.command import Command
|
|
5
4
|
from adam.utils_k8s.statefulsets import StatefulSets
|
|
@@ -7,7 +6,6 @@ from adam.repl_state import ReplState, RequiredState
|
|
|
7
6
|
from adam.utils_k8s.custom_resources import CustomResources
|
|
8
7
|
from adam.utils import log2
|
|
9
8
|
|
|
10
|
-
|
|
11
9
|
class MedusaBackup(Command):
|
|
12
10
|
COMMAND = 'backup'
|
|
13
11
|
|
|
@@ -29,33 +27,30 @@ class MedusaBackup(Command):
|
|
|
29
27
|
def run(self, cmd: str, state: ReplState):
|
|
30
28
|
if not(args := self.args(cmd)):
|
|
31
29
|
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
30
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
31
|
+
with self.validate(args, state) as (args, state):
|
|
32
|
+
ns = state.namespace
|
|
33
|
+
sts = state.sts
|
|
34
|
+
now_dtformat = datetime.now().strftime("%Y-%m-%d.%H.%M.%S")
|
|
35
|
+
bkname = 'medusa-' + now_dtformat + 'full-backup-' + sts
|
|
36
|
+
if len(args) == 1:
|
|
37
|
+
bkname = str(args[0])
|
|
38
|
+
|
|
39
|
+
dc = StatefulSets.get_datacenter(state.sts, ns)
|
|
40
|
+
if not dc:
|
|
41
|
+
return state
|
|
42
|
+
|
|
43
|
+
try:
|
|
44
|
+
CustomResources.create_medusa_backupjob(bkname, dc, ns)
|
|
45
|
+
except Exception as e:
|
|
46
|
+
log2("Exception: MedusaBackup failed: %s\n" % e)
|
|
47
|
+
finally:
|
|
48
|
+
CustomResources.clear_caches()
|
|
51
49
|
|
|
52
|
-
|
|
50
|
+
return state
|
|
53
51
|
|
|
54
52
|
def completion(self, state: ReplState):
|
|
55
|
-
|
|
56
|
-
return super().completion(state)
|
|
57
|
-
|
|
58
|
-
return {}
|
|
53
|
+
return super().completion(state)
|
|
59
54
|
|
|
60
55
|
def help(self, _: ReplState):
|
|
61
56
|
return f'{MedusaBackup.COMMAND}\t start a backup job'
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
1
2
|
from datetime import datetime
|
|
3
|
+
from functools import partial
|
|
2
4
|
|
|
3
|
-
from adam.commands
|
|
5
|
+
from adam.commands import validate_args
|
|
6
|
+
from adam.commands.command import Command, InvalidArgumentsException
|
|
4
7
|
from adam.utils_k8s.statefulsets import StatefulSets
|
|
5
8
|
from adam.repl_state import ReplState, RequiredState
|
|
6
9
|
from adam.utils_k8s.custom_resources import CustomResources
|
|
7
10
|
from adam.config import Config
|
|
8
|
-
from adam.utils import lines_to_tabular, log2
|
|
11
|
+
from adam.utils import lines_to_tabular, log2, log_exc
|
|
9
12
|
|
|
10
13
|
class MedusaRestore(Command):
|
|
11
14
|
COMMAND = 'restore'
|
|
@@ -28,47 +31,42 @@ class MedusaRestore(Command):
|
|
|
28
31
|
def run(self, cmd: str, state: ReplState):
|
|
29
32
|
if not(args := self.args(cmd)):
|
|
30
33
|
return super().run(cmd, state)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
34
|
+
|
|
35
|
+
with self.validate(args, state) as (args, state):
|
|
36
|
+
ns = state.namespace
|
|
37
|
+
dc: str = StatefulSets.get_datacenter(state.sts, ns)
|
|
38
|
+
if not dc:
|
|
39
|
+
return state
|
|
40
|
+
|
|
41
|
+
def msg(missing: bool):
|
|
42
|
+
if missing:
|
|
43
|
+
log2('\n* Missing Backup Name')
|
|
44
|
+
log2('Usage: qing restore <backup> <sts@name_space>\n')
|
|
45
|
+
else:
|
|
46
|
+
log2('\n* Backup job name is not valid.')
|
|
47
|
+
|
|
45
48
|
bklist = [f"{x['metadata']['name']}\t{x['metadata']['creationTimestamp']}\t{x['status'].get('finishTime', '')}" for x in CustomResources.medusa_show_backupjobs(dc, ns)]
|
|
46
49
|
log2(lines_to_tabular(bklist, 'NAME\tCREATED\tFINISHED', separator='\t'))
|
|
47
50
|
|
|
48
|
-
|
|
51
|
+
with validate_args(args, state, msg=partial(msg, True)) as bkname:
|
|
52
|
+
if not (job := CustomResources.medusa_get_backupjob(dc, ns, bkname)):
|
|
53
|
+
msg(False)
|
|
54
|
+
raise InvalidArgumentsException()
|
|
55
|
+
|
|
56
|
+
if not input(f"Restoring from {bkname} created at {job['metadata']['creationTimestamp']}. Please enter Yes to continue: ").lower() in ['y', 'yes']:
|
|
57
|
+
return state
|
|
58
|
+
|
|
59
|
+
with log_exc(lambda e: "Exception: MedusaRestore failed: %s\n" % e):
|
|
60
|
+
now_dtformat = datetime.now().strftime("%Y-%m-%d.%H.%M.%S")
|
|
61
|
+
rtname = 'medusa-' + now_dtformat + '-restore-from-' + bkname
|
|
62
|
+
CustomResources.create_medusa_restorejob(rtname, bkname, dc, ns)
|
|
49
63
|
|
|
50
|
-
if not input(f"Restoring from {bkname} created at {job['metadata']['creationTimestamp']}. Please enter Yes to continue: ").lower() in ['y', 'yes']:
|
|
51
64
|
return state
|
|
52
|
-
else:
|
|
53
|
-
bklist = [f"{x['metadata']['name']}\t{x['metadata']['creationTimestamp']}\t{x['status'].get('finishTime', '')}" for x in CustomResources.medusa_show_backupjobs(dc, ns)]
|
|
54
|
-
log2('\n* Missing Backup Name')
|
|
55
|
-
log2('Usage: qing medusa restore <backup> <sts@name_space>\n')
|
|
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
|
-
CustomResources.create_medusa_restorejob(rtname, bkname, dc, ns)
|
|
63
|
-
except Exception as e:
|
|
64
|
-
log2("Exception: MedusaRestore failed: %s\n" % e)
|
|
65
|
-
|
|
66
|
-
return state
|
|
67
65
|
|
|
68
66
|
def completion(self, state: ReplState):
|
|
69
|
-
if state
|
|
67
|
+
if sc := super().completion(state):
|
|
70
68
|
ns = state.namespace
|
|
71
|
-
dc = StatefulSets.get_datacenter(state.sts, ns)
|
|
69
|
+
dc: str = StatefulSets.get_datacenter(state.sts, ns)
|
|
72
70
|
if not dc:
|
|
73
71
|
return {}
|
|
74
72
|
|
|
@@ -77,7 +75,7 @@ class MedusaRestore(Command):
|
|
|
77
75
|
|
|
78
76
|
return super().completion(state, leaf)
|
|
79
77
|
else:
|
|
80
|
-
return
|
|
78
|
+
return sc
|
|
81
79
|
|
|
82
80
|
return {}
|
|
83
81
|
|
|
@@ -2,7 +2,7 @@ from adam.commands.command import Command
|
|
|
2
2
|
from adam.utils_k8s.statefulsets import StatefulSets
|
|
3
3
|
from adam.repl_state import ReplState, RequiredState
|
|
4
4
|
from adam.utils_k8s.custom_resources import CustomResources
|
|
5
|
-
from adam.utils import lines_to_tabular, log2
|
|
5
|
+
from adam.utils import lines_to_tabular, log2, log_exc
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class MedusaShowBackupJobs(Command):
|
|
@@ -26,28 +26,24 @@ 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
29
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
|
37
35
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
except Exception as e:
|
|
42
|
-
log2("Exception: MedusaShowBackupJobs failed: %s\n" % e)
|
|
36
|
+
# try:
|
|
37
|
+
with log_exc(lambda e: "Exception: MedusaShowBackupJobs failed: %s\n" % e):
|
|
38
|
+
CustomResources.clear_caches()
|
|
43
39
|
|
|
44
|
-
|
|
40
|
+
bklist = [f"{x['metadata']['name']}\t{x['metadata']['creationTimestamp']}\t{x['status'].get('finishTime', '') if 'status' in x else 'unknown'}" for x in CustomResources.medusa_show_backupjobs(dc, ns)]
|
|
41
|
+
log2(lines_to_tabular(bklist, 'NAME\tCREATED\tFINISHED', separator='\t'))
|
|
45
42
|
|
|
46
|
-
|
|
47
|
-
if state.sts:
|
|
48
|
-
return super().completion(state)
|
|
43
|
+
return state
|
|
49
44
|
|
|
50
|
-
|
|
45
|
+
def completion(self, state: ReplState):
|
|
46
|
+
return super().completion(state)
|
|
51
47
|
|
|
52
48
|
def help(self, _: ReplState):
|
|
53
49
|
return f'{MedusaShowBackupJobs.COMMAND}\t show Medusa backups'
|
|
@@ -2,7 +2,7 @@ from adam.commands.command import Command
|
|
|
2
2
|
from adam.utils_k8s.statefulsets import StatefulSets
|
|
3
3
|
from adam.repl_state import ReplState, RequiredState
|
|
4
4
|
from adam.utils_k8s.custom_resources import CustomResources
|
|
5
|
-
from adam.utils import lines_to_tabular, log2
|
|
5
|
+
from adam.utils import lines_to_tabular, log2, log_exc
|
|
6
6
|
|
|
7
7
|
class MedusaShowRestoreJobs(Command):
|
|
8
8
|
COMMAND = 'show restores'
|
|
@@ -25,28 +25,21 @@ 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
|
-
except Exception as e:
|
|
41
|
-
log2("Exception: MedusaShowRestoreJobs failed: %s\n" % e)
|
|
35
|
+
with log_exc(lambda e: "Exception: MedusaShowRestoreJobs failed: %s\n" % e):
|
|
36
|
+
rtlist = CustomResources.medusa_show_restorejobs(dc, ns)
|
|
37
|
+
log2(lines_to_tabular(rtlist, 'NAME\tCREATED\tFINISHED', separator='\t'))
|
|
42
38
|
|
|
43
|
-
|
|
39
|
+
return state
|
|
44
40
|
|
|
45
41
|
def completion(self, state: ReplState):
|
|
46
|
-
|
|
47
|
-
return super().completion(state)
|
|
48
|
-
|
|
49
|
-
return {}
|
|
42
|
+
return super().completion(state)
|
|
50
43
|
|
|
51
44
|
def help(self, _: ReplState):
|
|
52
45
|
return f'{MedusaShowRestoreJobs.COMMAND}\t show Medusa restores'
|
adam/commands/nodetool.py
CHANGED
|
@@ -2,10 +2,9 @@ import click
|
|
|
2
2
|
|
|
3
3
|
from adam.commands.command import Command
|
|
4
4
|
from adam.commands.command_helpers import ClusterOrPodCommandHelper
|
|
5
|
+
from adam.commands.cql.utils_cql import cassandra
|
|
5
6
|
from adam.commands.nodetool_commands import NODETOOL_COMMANDS
|
|
6
7
|
from adam.config import Config
|
|
7
|
-
from adam.utils_k8s.cassandra_clusters import CassandraClusters
|
|
8
|
-
from adam.utils_k8s.cassandra_nodes import CassandraNodes
|
|
9
8
|
from adam.repl_state import ReplState, RequiredState
|
|
10
9
|
from adam.utils import log
|
|
11
10
|
from adam.utils_k8s.statefulsets import StatefulSets
|
|
@@ -32,22 +31,14 @@ class NodeTool(Command):
|
|
|
32
31
|
if not(args := self.args(cmd)):
|
|
33
32
|
return super().run(cmd, state)
|
|
34
33
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
user, pw = state.user_pass()
|
|
40
|
-
command = f"nodetool -u {user} -pw {pw} {' '.join(args)}"
|
|
34
|
+
with self.validate(args, state) as (args, state):
|
|
35
|
+
with cassandra(state) as pods:
|
|
36
|
+
pods.nodetool(' '.join(args))
|
|
41
37
|
|
|
42
|
-
|
|
43
|
-
return CassandraNodes.exec(state.pod, state.namespace, command, show_out=True)
|
|
44
|
-
elif state.sts:
|
|
45
|
-
return CassandraClusters.exec(state.sts, state.namespace, command, action='nodetool', show_out=True)
|
|
46
|
-
|
|
47
|
-
return state
|
|
38
|
+
return state
|
|
48
39
|
|
|
49
40
|
def completion(self, state: ReplState):
|
|
50
|
-
if
|
|
41
|
+
if super().completion(state):
|
|
51
42
|
d = {c: {'&': None} for c in NODETOOL_COMMANDS}
|
|
52
43
|
return {NodeTool.COMMAND: {'help': None} | d} | \
|
|
53
44
|
{f'@{p}': {NodeTool.COMMAND: d} for p in StatefulSets.pod_names(state.sts, state.namespace)}
|
adam/commands/param_get.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from adam.commands import validate_args
|
|
1
2
|
from adam.commands.command import Command
|
|
2
3
|
from adam.config import Config
|
|
3
4
|
from adam.repl_state import ReplState
|
|
@@ -22,21 +23,18 @@ class GetParam(Command):
|
|
|
22
23
|
if not(args := self.args(cmd)):
|
|
23
24
|
return super().run(cmd, state)
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
with self.validate(args, state) as (args, state):
|
|
27
|
+
def msg():
|
|
28
|
+
lines = [f'{key}\t{Config().get(key, None)}' for key in Config().keys()]
|
|
29
|
+
log(lines_to_tabular(lines, separator='\t'))
|
|
26
30
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
31
|
+
with validate_args(args, state, msg=msg) as key:
|
|
32
|
+
if v := Config().get(key, None):
|
|
33
|
+
log(v)
|
|
34
|
+
else:
|
|
35
|
+
log2(f'{key} is not set.')
|
|
30
36
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
key = args[0]
|
|
34
|
-
if v := Config().get(key, None):
|
|
35
|
-
log(v)
|
|
36
|
-
else:
|
|
37
|
-
log2(f'{key} is not set.')
|
|
38
|
-
|
|
39
|
-
return v if v else state
|
|
37
|
+
return v if v else state
|
|
40
38
|
|
|
41
39
|
def completion(self, _: ReplState):
|
|
42
40
|
return {GetParam.COMMAND: {key: None for key in Config().keys()}}
|
adam/commands/param_set.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from adam.commands import validate_args
|
|
1
2
|
from adam.commands.command import Command
|
|
2
3
|
from adam.config import Config
|
|
3
4
|
from adam.repl_state import ReplState
|
|
@@ -22,20 +23,15 @@ class SetParam(Command):
|
|
|
22
23
|
if not(args := self.args(cmd)):
|
|
23
24
|
return super().run(cmd, state)
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
with self.validate(args, state) as (args, state):
|
|
27
|
+
with validate_args(args, state, count_at_least=2, msg=lambda: log2('set <key> <value>')):
|
|
28
|
+
key = args[0]
|
|
29
|
+
value = args[1]
|
|
30
|
+
Config().set(key, value)
|
|
26
31
|
|
|
27
|
-
|
|
28
|
-
log2('set <key> <value>')
|
|
32
|
+
log(Config().get(key, None))
|
|
29
33
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
key = args[0]
|
|
33
|
-
value = args[1]
|
|
34
|
-
Config().set(key, value)
|
|
35
|
-
|
|
36
|
-
log(Config().get(key, None))
|
|
37
|
-
|
|
38
|
-
return value
|
|
34
|
+
return value
|
|
39
35
|
|
|
40
36
|
def completion(self, _: ReplState):
|
|
41
37
|
return {SetParam.COMMAND: {key: ({'true': None, 'false': None} if Config().get(key, None) in [True, False] else None) for key in Config().keys()}}
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import click
|
|
2
2
|
|
|
3
|
+
from adam.commands import extract_trailing_options, validate_args
|
|
3
4
|
from adam.commands.command import Command
|
|
5
|
+
from adam.commands.intermediate_command import IntermediateCommand
|
|
4
6
|
from adam.commands.postgres.psql_completions import psql_completions
|
|
5
|
-
from adam.commands.postgres.
|
|
7
|
+
from adam.commands.postgres.utils_postgres import pg_table_names, postgres
|
|
6
8
|
from .postgres_ls import PostgresLs
|
|
7
9
|
from .postgres_preview import PostgresPreview
|
|
8
10
|
from .postgres_context import PostgresContext
|
|
9
11
|
from adam.repl_state import ReplState
|
|
10
12
|
from adam.utils import log, log2
|
|
11
13
|
|
|
12
|
-
class Postgres(
|
|
14
|
+
class Postgres(IntermediateCommand):
|
|
13
15
|
COMMAND = 'pg'
|
|
14
|
-
reaper_login = None
|
|
15
16
|
|
|
16
17
|
# the singleton pattern
|
|
17
18
|
def __new__(cls, *args, **kwargs):
|
|
@@ -29,46 +30,29 @@ class Postgres(Command):
|
|
|
29
30
|
if not(args := self.args(cmd)):
|
|
30
31
|
return super().run(cmd, state)
|
|
31
32
|
|
|
32
|
-
|
|
33
|
+
with self.validate(args, state) as (args, state):
|
|
34
|
+
with extract_trailing_options(args, '&') as (args, backgrounded):
|
|
35
|
+
with validate_args(args, state, name='SQL statement') as sql:
|
|
36
|
+
if not state.pg_path:
|
|
37
|
+
if state.in_repl:
|
|
38
|
+
log2('Enter "use <pg-name>" first.')
|
|
39
|
+
else:
|
|
40
|
+
log2('* pg-name is missing.')
|
|
33
41
|
|
|
34
|
-
|
|
35
|
-
if state.in_repl:
|
|
36
|
-
log2('Please use SQL statement. e.g. pg \l')
|
|
37
|
-
else:
|
|
38
|
-
log2('* Command or SQL statements is missing.')
|
|
39
|
-
Command.display_help()
|
|
42
|
+
return state
|
|
40
43
|
|
|
41
|
-
|
|
44
|
+
if state.in_repl:
|
|
45
|
+
with postgres(state) as pod:
|
|
46
|
+
pod.sql(args, background=backgrounded)
|
|
47
|
+
elif not self.run_subcommand(cmd, state):
|
|
48
|
+
with postgres(state) as pod:
|
|
49
|
+
pod.sql(args, background=backgrounded)
|
|
42
50
|
|
|
43
|
-
|
|
44
|
-
self.run_sql(state, args)
|
|
45
|
-
else:
|
|
46
|
-
# head with the Chain of Responsibility pattern
|
|
47
|
-
cmds = Command.chain(Postgres.cmd_list())
|
|
48
|
-
if not cmds.run(cmd, state) :
|
|
49
|
-
self.run_sql(state, args)
|
|
50
|
-
|
|
51
|
-
return state
|
|
51
|
+
return state
|
|
52
52
|
|
|
53
|
-
def cmd_list():
|
|
53
|
+
def cmd_list(self):
|
|
54
54
|
return [PostgresLs(), PostgresPreview(), PostgresPg()]
|
|
55
55
|
|
|
56
|
-
def run_sql(self, state: ReplState, args: list[str]):
|
|
57
|
-
if not state.pg_path:
|
|
58
|
-
if state.in_repl:
|
|
59
|
-
log2('Enter "use <pg-name>" first.')
|
|
60
|
-
else:
|
|
61
|
-
log2('* pg-name is missing.')
|
|
62
|
-
|
|
63
|
-
return state
|
|
64
|
-
|
|
65
|
-
background = False
|
|
66
|
-
if args and args[-1] == '&':
|
|
67
|
-
args = args[:-1]
|
|
68
|
-
background = True
|
|
69
|
-
|
|
70
|
-
PostgresContext.apply(state.namespace, state.pg_path).run_sql(' '.join(args), background=background)
|
|
71
|
-
|
|
72
56
|
def completion(self, state: ReplState):
|
|
73
57
|
if state.device != state.P:
|
|
74
58
|
# conflicts with cql completions
|
|
@@ -95,7 +79,7 @@ class Postgres(Command):
|
|
|
95
79
|
|
|
96
80
|
class PostgresCommandHelper(click.Command):
|
|
97
81
|
def get_help(self, ctx: click.Context):
|
|
98
|
-
|
|
82
|
+
IntermediateCommand.intermediate_help(super().get_help(ctx), Postgres.COMMAND, Postgres().cmd_list(), show_cluster_help=True)
|
|
99
83
|
log('PG-Name: Kubernetes secret for Postgres credentials')
|
|
100
84
|
log(' e.g. stgawsscpsr-c3-c3-k8spg-cs-001')
|
|
101
85
|
log('Database: Postgres database name within a host')
|
|
@@ -8,7 +8,7 @@ from adam.repl_session import ReplSession
|
|
|
8
8
|
from adam.utils_k8s.kube_context import KubeContext
|
|
9
9
|
from adam.utils_k8s.pods import Pods
|
|
10
10
|
from adam.utils_k8s.secrets import Secrets
|
|
11
|
-
from adam.utils import log2
|
|
11
|
+
from adam.utils import log2, log_exc
|
|
12
12
|
|
|
13
13
|
class PostgresContext:
|
|
14
14
|
def apply(namespace: str, path: str, arg: str = None) -> 'PostgresContext':
|
|
@@ -149,36 +149,62 @@ class PostgresContext:
|
|
|
149
149
|
|
|
150
150
|
return r
|
|
151
151
|
else:
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
if Config().get('pg.agent.just-in-time', False):
|
|
156
|
-
if not PostgresContext.deploy_pg_agent(pod_name, ns):
|
|
157
|
-
return
|
|
152
|
+
pod_name, container_name = PostgresContext.pod_and_container(self.namespace)
|
|
153
|
+
if not pod_name:
|
|
154
|
+
return
|
|
158
155
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
156
|
+
# ns = self.namespace
|
|
157
|
+
# pod_name = Config().get('pg.agent.name', 'ops-pg-agent')
|
|
158
|
+
|
|
159
|
+
# if Config().get('pg.agent.just-in-time', False):
|
|
160
|
+
# if not PostgresContext.deploy_pg_agent(pod_name, ns):
|
|
161
|
+
# return
|
|
162
|
+
|
|
163
|
+
# real_pod_name = pod_name
|
|
164
|
+
# try:
|
|
165
|
+
# # try with dedicated pg agent pod name configured
|
|
166
|
+
# Pods.get(ns, pod_name)
|
|
167
|
+
# except:
|
|
168
|
+
# try:
|
|
169
|
+
# # try with the ops pod
|
|
170
|
+
# pod_name = Config().get('pod.name', 'ops')
|
|
171
|
+
# real_pod_name = Pods.get_with_selector(ns, label_selector = Config().get('pod.label-selector', 'run=ops')).metadata.name
|
|
172
|
+
# except:
|
|
173
|
+
# log2(f"Could not locate {pod_name} pod.")
|
|
174
|
+
# return None
|
|
171
175
|
|
|
172
176
|
cmd = f'psql -h {self.endpoint()} -p {self.port()} -U {self.username()} {db} --pset pager=off -c "{sql}"'
|
|
173
177
|
env_prefix = f'PGPASSWORD="{self.password()}"'
|
|
174
178
|
|
|
175
|
-
r = Pods.exec(
|
|
179
|
+
r = Pods.exec(pod_name, container_name, self.namespace, cmd, show_out=show_out, background=background, env_prefix=env_prefix)
|
|
176
180
|
if r and Config().get('repl.history.push-cat-remote-log-file', True):
|
|
177
181
|
if r.log_file and ReplSession().prompt_session:
|
|
178
182
|
ReplSession().prompt_session.history.append_string(f'@{r.pod} cat {r.log_file}')
|
|
179
183
|
|
|
180
184
|
return r
|
|
181
185
|
|
|
186
|
+
def pod_and_container(ns: str):
|
|
187
|
+
container_name = Config().get('pg.agent.name', 'ops-pg-agent')
|
|
188
|
+
|
|
189
|
+
if Config().get('pg.agent.just-in-time', False):
|
|
190
|
+
if not PostgresContext.deploy_pg_agent(container_name, ns):
|
|
191
|
+
return None
|
|
192
|
+
|
|
193
|
+
pod_name = container_name
|
|
194
|
+
try:
|
|
195
|
+
# try with dedicated pg agent pod name configured
|
|
196
|
+
Pods.get(ns, container_name)
|
|
197
|
+
except:
|
|
198
|
+
try:
|
|
199
|
+
# try with the ops pod
|
|
200
|
+
container_name = Config().get('pod.name', 'ops')
|
|
201
|
+
pod_name = Pods.get_with_selector(ns, label_selector = Config().get('pod.label-selector', 'run=ops')).metadata.name
|
|
202
|
+
except:
|
|
203
|
+
log2(f"Could not locate {container_name} pod.")
|
|
204
|
+
return None
|
|
205
|
+
|
|
206
|
+
return pod_name, container_name
|
|
207
|
+
|
|
182
208
|
def deploy_pg_agent(pod_name: str, ns: str) -> str:
|
|
183
209
|
image = Config().get('pg.agent.image', 'seanahnsf/kaqing')
|
|
184
210
|
timeout = Config().get('pg.agent.timeout', 3600)
|
|
@@ -187,11 +213,9 @@ class PostgresContext:
|
|
|
187
213
|
except Exception as e:
|
|
188
214
|
if e.status == 409:
|
|
189
215
|
if Pods.completed(ns, pod_name):
|
|
190
|
-
|
|
216
|
+
with log_exc(lambda e2: "Exception when calling BatchV1Api->create_pod: %s\n" % e2):
|
|
191
217
|
Pods.delete(pod_name, ns)
|
|
192
218
|
Pods.create(ns, pod_name, image, ['sleep', f'{timeout}'], env={'NAMESPACE': ns}, sa_name='c3')
|
|
193
|
-
except Exception as e2:
|
|
194
|
-
log2("Exception when calling BatchV1Api->create_pod: %s\n" % e2)
|
|
195
219
|
|
|
196
220
|
return
|
|
197
221
|
else:
|
|
@@ -4,7 +4,6 @@ from adam.repl_state import ReplState, RequiredState
|
|
|
4
4
|
|
|
5
5
|
class PostgresLs(Command):
|
|
6
6
|
COMMAND = 'pg ls'
|
|
7
|
-
reaper_login = None
|
|
8
7
|
|
|
9
8
|
# the singleton pattern
|
|
10
9
|
def __new__(cls, *args, **kwargs):
|
|
@@ -25,15 +24,12 @@ class PostgresLs(Command):
|
|
|
25
24
|
if not(args := self.args(cmd)):
|
|
26
25
|
return super().run(cmd, state)
|
|
27
26
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return state
|
|
31
|
-
|
|
32
|
-
state.device = ReplState.P
|
|
27
|
+
with self.validate(args, state) as (args, state):
|
|
28
|
+
state.device = ReplState.P
|
|
33
29
|
|
|
34
|
-
|
|
30
|
+
Ls().run('ls', state)
|
|
35
31
|
|
|
36
|
-
|
|
32
|
+
return state
|
|
37
33
|
|
|
38
34
|
def completion(self, state: ReplState):
|
|
39
35
|
if state.sts:
|