kaqing 2.0.184__py3-none-any.whl → 2.0.214__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of kaqing might be problematic. Click here for more details.
- adam/app_session.py +1 -1
- adam/batch.py +15 -15
- adam/commands/app/app.py +2 -2
- adam/commands/app/show_app_actions.py +1 -1
- adam/commands/{show → app}/show_login.py +1 -1
- adam/commands/app/utils_app.py +9 -1
- adam/commands/audit/audit.py +6 -20
- adam/commands/audit/audit_repair_tables.py +1 -1
- adam/commands/audit/audit_run.py +1 -1
- adam/commands/audit/completions_l.py +15 -0
- adam/commands/audit/show_last10.py +0 -1
- adam/commands/bash/bash.py +1 -1
- adam/commands/bash/utils_bash.py +1 -1
- adam/commands/cassandra/download_cassandra_log.py +45 -0
- adam/commands/cassandra/restart_cluster.py +47 -0
- adam/commands/cassandra/restart_node.py +51 -0
- adam/commands/cassandra/restart_nodes.py +47 -0
- adam/commands/{rollout.py → cassandra/rollout.py} +1 -1
- adam/commands/{show → cassandra}/show_cassandra_repairs.py +5 -3
- adam/commands/{show → cassandra}/show_cassandra_status.py +22 -15
- adam/commands/cassandra/show_processes.py +50 -0
- adam/commands/{show → cassandra}/show_storage.py +10 -8
- adam/commands/cli/__init__.py +0 -0
- adam/commands/{cli_commands.py → cli/cli_commands.py} +6 -1
- adam/commands/{clipboard_copy.py → cli/clipboard_copy.py} +2 -2
- adam/commands/{show/show_commands.py → cli/show_cli_commands.py} +2 -2
- adam/commands/command.py +22 -9
- adam/commands/commands_utils.py +14 -6
- adam/commands/config/__init__.py +0 -0
- adam/commands/{show → config}/show_params.py +1 -1
- adam/commands/{alter_tables.py → cql/alter_tables.py} +1 -1
- adam/commands/cql/completions_c.py +29 -0
- adam/commands/cql/cqlsh.py +2 -6
- adam/commands/cql/utils_cql.py +26 -17
- adam/commands/debug/__init__.py +0 -0
- adam/commands/debug/debug.py +22 -0
- adam/commands/debug/debug_completes.py +35 -0
- adam/commands/debug/debug_timings.py +35 -0
- adam/commands/debug/show_offloaded_completes.py +45 -0
- adam/commands/devices/device.py +30 -4
- adam/commands/devices/device_app.py +1 -1
- adam/commands/devices/device_export.py +5 -2
- adam/commands/devices/device_postgres.py +13 -3
- adam/commands/devices/devices.py +1 -1
- adam/commands/diag/__init__.py +0 -0
- adam/commands/{check.py → diag/check.py} +1 -1
- adam/commands/diag/generate_report.py +52 -0
- adam/commands/export/completions_x.py +11 -0
- adam/commands/export/download_export_session.py +2 -1
- adam/commands/export/export.py +0 -16
- adam/commands/export/export_databases.py +16 -10
- adam/commands/export/export_select.py +8 -33
- adam/commands/export/export_sessions.py +12 -11
- adam/commands/export/export_use.py +3 -3
- adam/commands/export/export_x_select.py +48 -0
- adam/commands/export/exporter.py +140 -53
- adam/commands/export/import_files.py +2 -2
- adam/commands/export/import_session.py +0 -4
- adam/commands/export/importer.py +11 -11
- adam/commands/export/importer_athena.py +15 -35
- adam/commands/export/importer_sqlite.py +19 -8
- adam/commands/export/show_column_counts.py +10 -10
- adam/commands/export/show_export_databases.py +2 -1
- adam/commands/export/show_export_session.py +1 -1
- adam/commands/export/show_export_sessions.py +1 -1
- adam/commands/export/utils_export.py +38 -15
- adam/commands/fs/__init__.py +0 -0
- adam/commands/{cat.py → fs/cat.py} +2 -2
- adam/commands/fs/cat_local.py +42 -0
- adam/commands/{cd.py → fs/cd.py} +2 -2
- adam/commands/{download_file.py → fs/download_file.py} +5 -5
- adam/commands/{find_files.py → fs/find_files.py} +4 -4
- adam/commands/{find_processes.py → fs/find_processes.py} +3 -3
- adam/commands/{head.py → fs/head.py} +2 -2
- adam/commands/{ls.py → fs/ls.py} +2 -2
- adam/commands/fs/ls_local.py +40 -0
- adam/commands/fs/rm.py +18 -0
- adam/commands/fs/rm_downloads.py +39 -0
- adam/commands/fs/rm_logs.py +38 -0
- adam/commands/{show → fs}/show_adam.py +1 -1
- adam/commands/intermediate_command.py +3 -0
- adam/commands/medusa/medusa_restore.py +2 -16
- adam/commands/medusa/utils_medusa.py +15 -0
- adam/commands/nodetool/__init__.py +0 -0
- adam/commands/{nodetool.py → nodetool/nodetool.py} +3 -8
- adam/commands/postgres/completions_p.py +22 -0
- adam/commands/postgres/postgres.py +7 -14
- adam/commands/postgres/postgres_databases.py +3 -3
- adam/commands/postgres/postgres_ls.py +1 -1
- adam/commands/postgres/utils_postgres.py +12 -2
- adam/commands/preview_table.py +1 -1
- adam/commands/reaper/reaper_schedule_activate.py +6 -2
- adam/commands/reaper/reaper_schedule_start.py +1 -2
- adam/commands/reaper/reaper_schedule_stop.py +1 -2
- adam/commands/reaper/utils_reaper.py +10 -1
- adam/commands/repair/repair_scan.py +0 -2
- adam/commands/repair/repair_stop.py +0 -1
- adam/commands/{show/show.py → show.py} +12 -11
- adam/config.py +4 -5
- adam/embedded_params.py +1 -1
- adam/repl.py +22 -9
- adam/repl_commands.py +50 -42
- adam/repl_session.py +9 -1
- adam/repl_state.py +16 -1
- adam/sql/async_executor.py +62 -0
- adam/sql/lark_completer.py +286 -0
- adam/sql/lark_parser.py +604 -0
- adam/sql/qingl.lark +1076 -0
- adam/sso/cred_cache.py +2 -5
- adam/utils.py +216 -79
- adam/utils_k8s/app_clusters.py +11 -4
- adam/utils_k8s/app_pods.py +10 -5
- adam/utils_k8s/cassandra_clusters.py +8 -4
- adam/utils_k8s/cassandra_nodes.py +14 -5
- adam/utils_k8s/k8s.py +9 -0
- adam/utils_k8s/kube_context.py +1 -4
- adam/{pod_exec_result.py → utils_k8s/pod_exec_result.py} +8 -2
- adam/utils_k8s/pods.py +83 -24
- adam/utils_k8s/statefulsets.py +5 -2
- adam/utils_local.py +78 -2
- adam/utils_repl/appendable_completer.py +6 -0
- adam/utils_repl/repl_completer.py +51 -4
- adam/utils_sqlite.py +3 -8
- adam/version.py +1 -1
- {kaqing-2.0.184.dist-info → kaqing-2.0.214.dist-info}/METADATA +1 -1
- kaqing-2.0.214.dist-info/RECORD +272 -0
- kaqing-2.0.214.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/cql/cql_completions.py +0 -32
- adam/commands/export/export_select_x.py +0 -54
- adam/commands/logs.py +0 -37
- adam/commands/postgres/psql_completions.py +0 -11
- adam/commands/report.py +0 -61
- adam/commands/restart.py +0 -60
- adam/commands/show/show_processes.py +0 -49
- kaqing-2.0.184.dist-info/RECORD +0 -244
- kaqing-2.0.184.dist-info/top_level.txt +0 -1
- /adam/commands/{login.py → app/login.py} +0 -0
- /adam/commands/{show → cassandra}/__init__.py +0 -0
- /adam/commands/{show → cassandra}/show_cassandra_version.py +0 -0
- /adam/commands/{watch.py → cassandra/watch.py} +0 -0
- /adam/commands/{param_get.py → config/param_get.py} +0 -0
- /adam/commands/{param_set.py → config/param_set.py} +0 -0
- /adam/commands/{issues.py → diag/issues.py} +0 -0
- /adam/commands/{pwd.py → fs/pwd.py} +0 -0
- /adam/commands/{shell.py → fs/shell.py} +0 -0
- /adam/commands/{show → fs}/show_host.py +0 -0
- /adam/commands/{nodetool_commands.py → nodetool/nodetool_commands.py} +0 -0
- {kaqing-2.0.184.dist-info → kaqing-2.0.214.dist-info}/WHEEL +0 -0
- {kaqing-2.0.184.dist-info → kaqing-2.0.214.dist-info}/entry_points.txt +0 -0
|
@@ -3,14 +3,19 @@ import re
|
|
|
3
3
|
|
|
4
4
|
from adam.commands.reaper.utils_reaper import Reapers
|
|
5
5
|
from adam.config import Config
|
|
6
|
+
from adam.utils import log_timing
|
|
6
7
|
from adam.utils_k8s.kube_context import KubeContext
|
|
7
8
|
from adam.utils_k8s.secrets import Secrets
|
|
8
9
|
from adam.utils_k8s.statefulsets import StatefulSets
|
|
9
10
|
from adam.repl_state import ReplState
|
|
10
11
|
|
|
11
12
|
class CliCommands:
|
|
12
|
-
@functools.lru_cache()
|
|
13
13
|
def values(state: ReplState, collapse = False):
|
|
14
|
+
with log_timing('CliCommands.values'):
|
|
15
|
+
return CliCommands._values(state, collapse)
|
|
16
|
+
|
|
17
|
+
@functools.lru_cache()
|
|
18
|
+
def _values(state: ReplState, collapse = False):
|
|
14
19
|
# node-exec-?, nodetool-?, cql-?, reaper-exec, reaper-forward, reaper-ui, reaper-usernae, reaper-password
|
|
15
20
|
d = {}
|
|
16
21
|
|
|
@@ -3,9 +3,9 @@ import click
|
|
|
3
3
|
import pyperclip
|
|
4
4
|
|
|
5
5
|
from adam.commands import validate_args
|
|
6
|
+
from adam.commands.cli.cli_commands import CliCommands
|
|
6
7
|
from adam.commands.command import Command, InvalidArgumentsException
|
|
7
8
|
from adam.commands.command_helpers import ClusterOrPodCommandHelper
|
|
8
|
-
from adam.commands.cli_commands import CliCommands
|
|
9
9
|
from adam.repl_state import ReplState, RequiredState
|
|
10
10
|
from adam.utils import tabulize, log, log2
|
|
11
11
|
|
|
@@ -62,7 +62,7 @@ class ClipboardCopy(Command):
|
|
|
62
62
|
return state
|
|
63
63
|
|
|
64
64
|
def completion(self, state: ReplState):
|
|
65
|
-
return super().completion(state, lambda: {key: None for key in CliCommands.values(state).keys()})
|
|
65
|
+
return super().completion(state, lambda: {key: None for key in CliCommands.values(state).keys()}, auto_key='cli.cp-auto-complete')
|
|
66
66
|
|
|
67
67
|
def help(self, _: ReplState):
|
|
68
68
|
return f"{ClipboardCopy.COMMAND} <key>\t copy a value to clipboard for conveninence"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
from adam.commands.cli.cli_commands import CliCommands
|
|
1
2
|
from adam.commands.command import Command
|
|
2
|
-
from adam.commands.cli_commands import CliCommands
|
|
3
3
|
from adam.repl_state import ReplState, RequiredState
|
|
4
4
|
from adam.utils import tabulize, log
|
|
5
5
|
|
|
@@ -22,7 +22,7 @@ class ShowKubectlCommands(Command):
|
|
|
22
22
|
return RequiredState.CLUSTER_OR_POD
|
|
23
23
|
|
|
24
24
|
def run(self, cmd: str, state: ReplState):
|
|
25
|
-
if not self.args(cmd):
|
|
25
|
+
if not (args := self.args(cmd)):
|
|
26
26
|
return super().run(cmd, state)
|
|
27
27
|
|
|
28
28
|
with self.validate(args, state) as (args, state):
|
adam/commands/command.py
CHANGED
|
@@ -5,8 +5,10 @@ import subprocess
|
|
|
5
5
|
import sys
|
|
6
6
|
from typing import Union
|
|
7
7
|
|
|
8
|
+
from adam.config import Config
|
|
8
9
|
from adam.repl_state import ReplState, RequiredState
|
|
9
|
-
from adam.
|
|
10
|
+
from adam.sql.lark_completer import LarkCompleter
|
|
11
|
+
from adam.utils import log2
|
|
10
12
|
|
|
11
13
|
repl_cmds: list['Command'] = []
|
|
12
14
|
|
|
@@ -29,10 +31,10 @@ class Command:
|
|
|
29
31
|
|
|
30
32
|
return None
|
|
31
33
|
|
|
32
|
-
def completion(self, state: ReplState, leaf: dict[str, any] = None, pods: tuple[list[str], str] = None) -> dict[str, any]:
|
|
34
|
+
def completion(self, state: ReplState, leaf: dict[str, any] = None, pods: tuple[list[str], str] = None, auto: str = 'on', auto_key: str = None) -> dict[str, any]:
|
|
33
35
|
# pods is a tuple of list of pod names and the current pod repl is on
|
|
34
36
|
if not pods:
|
|
35
|
-
return self._completion(state, leaf)
|
|
37
|
+
return self._completion(state, leaf, auto=auto, auto_key=auto_key)
|
|
36
38
|
|
|
37
39
|
c = {}
|
|
38
40
|
|
|
@@ -40,18 +42,27 @@ class Command:
|
|
|
40
42
|
pod = pods[1]
|
|
41
43
|
|
|
42
44
|
if pod:
|
|
43
|
-
c |= self._completion(state, leaf)
|
|
45
|
+
c |= self._completion(state, leaf, auto=auto, auto_key=auto_key)
|
|
44
46
|
|
|
45
|
-
c |= {f'@{p}': self._completion(state, leaf, to_validate=False) for p in pod_names if p != pod}
|
|
47
|
+
c |= {f'@{p}': self._completion(state.with_pod(p), leaf, to_validate=False, auto=auto, auto_key=auto_key) for p in pod_names if p != pod}
|
|
46
48
|
|
|
47
49
|
return c
|
|
48
50
|
|
|
49
|
-
def _completion(self, state: ReplState, leaf: dict[str, any] = None, to_validate = True) -> dict[str, any]:
|
|
51
|
+
def _completion(self, state: ReplState, leaf: dict[str, any] = None, to_validate = True, auto: str = 'on', auto_key: str = None) -> dict[str, any]:
|
|
50
52
|
if to_validate and not self.validate_state(state, show_err=False):
|
|
51
53
|
return {}
|
|
52
54
|
|
|
53
|
-
if
|
|
54
|
-
|
|
55
|
+
if callable(leaf):
|
|
56
|
+
if auto_key:
|
|
57
|
+
auto_key = f'auto-complete.{auto_key}'
|
|
58
|
+
auto = Config().get(auto_key, 'off')
|
|
59
|
+
|
|
60
|
+
if auto == 'on':
|
|
61
|
+
leaf = leaf()
|
|
62
|
+
elif auto in ['lazy', 'jit']:
|
|
63
|
+
leaf = LarkCompleter.from_lambda(auto_key, leaf, auto=auto)
|
|
64
|
+
else:
|
|
65
|
+
leaf = None
|
|
55
66
|
|
|
56
67
|
d = leaf
|
|
57
68
|
for t in reversed(self.command().split(' ')):
|
|
@@ -130,7 +141,7 @@ class Command:
|
|
|
130
141
|
options = [options]
|
|
131
142
|
|
|
132
143
|
if args and trailing:
|
|
133
|
-
while args[-1] in trailing:
|
|
144
|
+
while args and args[-1] in trailing:
|
|
134
145
|
found_trailing = True
|
|
135
146
|
args = args[:-1]
|
|
136
147
|
|
|
@@ -148,6 +159,8 @@ class Command:
|
|
|
148
159
|
return new_args, found_trailing, found_sequence, found_options
|
|
149
160
|
|
|
150
161
|
def extract_option_sequence(args, sequence):
|
|
162
|
+
new_args = args
|
|
163
|
+
|
|
151
164
|
len_sub = len(sequence)
|
|
152
165
|
len_main = len(args)
|
|
153
166
|
for i in range(len_main - len_sub + 1):
|
adam/commands/commands_utils.py
CHANGED
|
@@ -8,7 +8,7 @@ from adam.utils_k8s.cassandra_nodes import CassandraNodes
|
|
|
8
8
|
from adam.utils_k8s.pods import Pods
|
|
9
9
|
from adam.utils_k8s.statefulsets import StatefulSets
|
|
10
10
|
from adam.repl_state import ReplState
|
|
11
|
-
from adam.utils import SORT, duration,
|
|
11
|
+
from adam.utils import SORT, duration, kaqing_log_file, tabulize, log2
|
|
12
12
|
|
|
13
13
|
def show_pods(pods: List[client.V1Pod], ns: str, show_namespace = True, show_host_id = True):
|
|
14
14
|
if len(pods) == 0:
|
|
@@ -59,14 +59,22 @@ def show_rollout(sts: str, ns: str):
|
|
|
59
59
|
else:
|
|
60
60
|
log2(f'Cluster has completed rollout {d} ago.')
|
|
61
61
|
|
|
62
|
-
def show_table(state: ReplState, pods: list[str], cols: str, header: str, show_out=False):
|
|
62
|
+
def show_table(state: ReplState, pods: list[str], cols: str, header: str, show_out=False, backgrounded = False):
|
|
63
63
|
columns = Columns.create_columns(cols)
|
|
64
64
|
|
|
65
65
|
results = run_checks(cluster=state.sts, pod=state.pod, namespace=state.namespace, checks=collect_checks(columns), show_out=show_out)
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
r = tabulize(pods, lambda p: ','.join([c.pod_value(results, p) for c in columns]), header=header, separator=',', sorted=SORT, to = 0 if backgrounded else 1)
|
|
68
|
+
|
|
69
|
+
if backgrounded:
|
|
70
|
+
r = write_to_kaqing_log_file(r)
|
|
71
|
+
|
|
72
|
+
IssuesUtils.show(results, state.in_repl)
|
|
73
|
+
|
|
74
|
+
return r
|
|
69
75
|
|
|
70
|
-
|
|
76
|
+
def write_to_kaqing_log_file(r: str):
|
|
77
|
+
with kaqing_log_file() as f:
|
|
78
|
+
f.write(r)
|
|
71
79
|
|
|
72
|
-
|
|
80
|
+
return f.name
|
|
File without changes
|
|
@@ -59,7 +59,7 @@ class AlterTables(Command):
|
|
|
59
59
|
return state
|
|
60
60
|
|
|
61
61
|
def completion(self, _: ReplState) -> dict[str, any]:
|
|
62
|
-
# auto completion is taken care of by
|
|
62
|
+
# auto completion is taken care of by lark completer
|
|
63
63
|
return {}
|
|
64
64
|
|
|
65
65
|
def help(self, _: ReplState) -> str:
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from adam.commands.cql.utils_cql import cassandra_keyspaces, cassandra_table_names
|
|
2
|
+
from adam.commands.export.export_sessions import ExportSessions
|
|
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.sql.lark_completer import LarkCompleter
|
|
7
|
+
from adam.utils import log_timing
|
|
8
|
+
from adam.utils_k8s.statefulsets import StatefulSets
|
|
9
|
+
|
|
10
|
+
def completions_c(state: ReplState) -> dict[str, any]:
|
|
11
|
+
ps = Config().get('cql.alter-tables.gc-grace-periods', '3600,86400,864000,7776000').split(',')
|
|
12
|
+
|
|
13
|
+
with log_timing('lark.completions'):
|
|
14
|
+
return LarkCompleter(
|
|
15
|
+
expandables = {
|
|
16
|
+
'tables': lambda x: cassandra_table_names(state),
|
|
17
|
+
'keyspaces': lambda x: cassandra_keyspaces(state.with_no_pod()),
|
|
18
|
+
'table-props': {
|
|
19
|
+
'GC_GRACE_SECONDS': ps
|
|
20
|
+
},
|
|
21
|
+
'table-props-value': lambda x: {None: None, 'GC_GRACE_SECONDS': ps}[x],
|
|
22
|
+
'export-database-types': ['athena', 'sqlite', 'csv'],
|
|
23
|
+
'export-databases': lambda x: ExportDatabases.database_names(),
|
|
24
|
+
'export-sessions': lambda x: ExportSessions.export_session_names(state.sts, state.pod, state.namespace),
|
|
25
|
+
'export-sessions-incomplete': lambda x: ExportSessions.export_session_names(state.sts, state.pod, state.namespace, export_state='pending_import'),
|
|
26
|
+
'hosts': lambda x: [f'@{p}' for p in StatefulSets.pod_names(state.sts, state.namespace)],
|
|
27
|
+
},
|
|
28
|
+
variant=ReplState.C
|
|
29
|
+
).completions_for_nesting()
|
adam/commands/cql/cqlsh.py
CHANGED
|
@@ -3,9 +3,8 @@ import click
|
|
|
3
3
|
from adam.commands import extract_trailing_options
|
|
4
4
|
from adam.commands.command import Command
|
|
5
5
|
from adam.commands.command_helpers import ClusterOrPodCommandHelper
|
|
6
|
-
from adam.commands.cql.
|
|
6
|
+
from adam.commands.cql.completions_c import completions_c
|
|
7
7
|
from adam.commands.cql.utils_cql import cassandra
|
|
8
|
-
from adam.utils_k8s.statefulsets import StatefulSets
|
|
9
8
|
from adam.repl_state import ReplState, RequiredState
|
|
10
9
|
from adam.utils import log
|
|
11
10
|
|
|
@@ -38,13 +37,10 @@ class Cqlsh(Command):
|
|
|
38
37
|
|
|
39
38
|
def completion(self, state: ReplState) -> dict[str, any]:
|
|
40
39
|
if state.device != state.C:
|
|
41
|
-
# conflicts with psql completions
|
|
42
40
|
return {}
|
|
43
41
|
|
|
44
42
|
if state.sts or state.pod:
|
|
45
|
-
|
|
46
|
-
return c | \
|
|
47
|
-
{f'@{p}': c for p in StatefulSets.pod_names(state.sts, state.namespace)}
|
|
43
|
+
return completions_c(state)
|
|
48
44
|
|
|
49
45
|
return {}
|
|
50
46
|
|
adam/commands/cql/utils_cql.py
CHANGED
|
@@ -7,11 +7,19 @@ from adam.commands.commands_utils import show_table
|
|
|
7
7
|
from adam.utils_k8s.cassandra_clusters import CassandraClusters
|
|
8
8
|
from adam.utils_k8s.cassandra_nodes import CassandraNodes
|
|
9
9
|
from adam.utils_k8s.secrets import Secrets
|
|
10
|
-
from adam.pod_exec_result import PodExecResult
|
|
10
|
+
from adam.utils_k8s.pod_exec_result import PodExecResult
|
|
11
11
|
from adam.repl_state import ReplState
|
|
12
|
-
from adam.utils import log2, log_timing, wait_log
|
|
12
|
+
from adam.utils import ing, log2, log_timing, wait_log
|
|
13
13
|
from adam.utils_k8s.statefulsets import StatefulSets
|
|
14
14
|
|
|
15
|
+
def cd_dirs(state: ReplState) -> list[str]:
|
|
16
|
+
if state.pod:
|
|
17
|
+
return [".."]
|
|
18
|
+
elif state.sts:
|
|
19
|
+
return [".."] + StatefulSets.pod_names(state.sts, state.namespace)
|
|
20
|
+
else:
|
|
21
|
+
return StatefulSets.list_sts_names()
|
|
22
|
+
|
|
15
23
|
@functools.lru_cache()
|
|
16
24
|
def cassandra_keyspaces(state: ReplState, on_any=True):
|
|
17
25
|
if state.pod:
|
|
@@ -47,7 +55,7 @@ def table_spec(state: ReplState, table: str, on_any=False) -> 'TableSpec':
|
|
|
47
55
|
|
|
48
56
|
return parse_cql_desc_table(r.stdout if state.pod else r[0].stdout)
|
|
49
57
|
|
|
50
|
-
def run_cql(state: ReplState, cql: str, opts: list = [], show_out = False, show_query = False, use_single_quotes = False, on_any = False, backgrounded=False, log_file=None) -> list[PodExecResult]:
|
|
58
|
+
def run_cql(state: ReplState, cql: str, opts: list = [], show_out = False, show_query = False, use_single_quotes = False, on_any = False, backgrounded=False, log_file=None, history=True) -> list[PodExecResult]:
|
|
51
59
|
if show_query:
|
|
52
60
|
log2(cql)
|
|
53
61
|
|
|
@@ -61,7 +69,7 @@ def run_cql(state: ReplState, cql: str, opts: list = [], show_out = False, show_
|
|
|
61
69
|
|
|
62
70
|
with log_timing(cql):
|
|
63
71
|
with cassandra(state) as pods:
|
|
64
|
-
return pods.exec(command, action='cql', show_out=show_out, on_any=on_any, backgrounded=backgrounded, log_file=log_file)
|
|
72
|
+
return pods.exec(command, action='cql', show_out=show_out, on_any=on_any, backgrounded=backgrounded, log_file=log_file, history=history)
|
|
65
73
|
|
|
66
74
|
def parse_cql_desc_tables(out: str):
|
|
67
75
|
# Keyspace data_endpoint_auth
|
|
@@ -219,16 +227,16 @@ class CassandraPodService:
|
|
|
219
227
|
def __init__(self, handler: 'CassandraExecHandler'):
|
|
220
228
|
self.handler = handler
|
|
221
229
|
|
|
222
|
-
def exec(self, command: str, action='bash', show_out = True, on_any = False, throw_err = False, shell = '/bin/sh', backgrounded = False, log_file = None) -> Union[PodExecResult, list[PodExecResult]]:
|
|
230
|
+
def exec(self, command: str, action='bash', show_out = True, on_any = False, throw_err = False, shell = '/bin/sh', backgrounded = False, log_file = None, history=True) -> Union[PodExecResult, list[PodExecResult]]:
|
|
223
231
|
state = self.handler.state
|
|
224
232
|
pod = self.handler.pod
|
|
225
233
|
|
|
226
234
|
if pod:
|
|
227
235
|
return CassandraNodes.exec(pod, state.namespace, command,
|
|
228
|
-
show_out=show_out, throw_err=throw_err, shell=shell, backgrounded=backgrounded, log_file=log_file)
|
|
236
|
+
show_out=show_out, throw_err=throw_err, shell=shell, backgrounded=backgrounded, log_file=log_file, history=history)
|
|
229
237
|
elif state.sts:
|
|
230
238
|
return CassandraClusters.exec(state.sts, state.namespace, command, action=action,
|
|
231
|
-
show_out=show_out, on_any=on_any, shell=shell, backgrounded=backgrounded, log_file=log_file)
|
|
239
|
+
show_out=show_out, on_any=on_any, shell=shell, backgrounded=backgrounded, log_file=log_file, history=history)
|
|
232
240
|
|
|
233
241
|
return []
|
|
234
242
|
|
|
@@ -259,16 +267,17 @@ class CassandraPodService:
|
|
|
259
267
|
|
|
260
268
|
return run_cql(state, query, opts=opts, show_out=show_out, show_query=show_query, use_single_quotes=use_single_quotes, on_any=on_any, backgrounded=backgrounded, log_file=log_file)
|
|
261
269
|
|
|
262
|
-
def display_table(self, cols: str, header: str, show_out = True):
|
|
270
|
+
def display_table(self, cols: str, header: str, show_out = True, backgrounded = False, msg: str = None):
|
|
263
271
|
state = self.handler.state
|
|
264
272
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
273
|
+
with ing(msg=msg, condition=backgrounded and msg):
|
|
274
|
+
if state.pod:
|
|
275
|
+
return show_table(state, [state.pod], cols, header, show_out=show_out, backgrounded = backgrounded)
|
|
276
|
+
elif state.sts:
|
|
277
|
+
pod_names = [pod.metadata.name for pod in StatefulSets.pods(state.sts, state.namespace)]
|
|
278
|
+
return show_table(state, pod_names, cols, header, show_out=show_out, backgrounded = backgrounded)
|
|
270
279
|
|
|
271
|
-
def nodetool(self, args: str, status = False, show_out = True) -> Union[PodExecResult, list[PodExecResult]]:
|
|
280
|
+
def nodetool(self, args: str, status = False, show_out = True, backgrounded = False) -> Union[PodExecResult, list[PodExecResult]]:
|
|
272
281
|
state = self.handler.state
|
|
273
282
|
pod = self.handler.pod
|
|
274
283
|
|
|
@@ -276,9 +285,9 @@ class CassandraPodService:
|
|
|
276
285
|
command = f"nodetool -u {user} -pw {pw} {args}"
|
|
277
286
|
|
|
278
287
|
if pod:
|
|
279
|
-
return CassandraNodes.exec(pod, state.namespace, command, show_out=show_out)
|
|
288
|
+
return CassandraNodes.exec(pod, state.namespace, command, show_out=show_out, backgrounded=backgrounded)
|
|
280
289
|
else:
|
|
281
|
-
return CassandraClusters.exec(state.sts, state.namespace, command, action='nodetool.status' if status else 'nodetool', show_out=show_out)
|
|
290
|
+
return CassandraClusters.exec(state.sts, state.namespace, command, action='nodetool.status' if status else 'nodetool', show_out=show_out, backgrounded=backgrounded)
|
|
282
291
|
|
|
283
292
|
class CassandraExecHandler:
|
|
284
293
|
def __init__(self, state: ReplState, pod: str = None):
|
|
@@ -294,4 +303,4 @@ class CassandraExecHandler:
|
|
|
294
303
|
return False
|
|
295
304
|
|
|
296
305
|
def cassandra(state: ReplState, pod: str=None):
|
|
297
|
-
return CassandraExecHandler(state, pod=pod)
|
|
306
|
+
return CassandraExecHandler(state, pod=pod)
|
|
File without changes
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from adam.commands.command import Command
|
|
2
|
+
from adam.commands.debug.debug_completes import DebugCompletes
|
|
3
|
+
from adam.commands.debug.debug_timings import DebugTimings
|
|
4
|
+
from adam.commands.intermediate_command import IntermediateCommand
|
|
5
|
+
|
|
6
|
+
class Debug(IntermediateCommand):
|
|
7
|
+
COMMAND = 'debug'
|
|
8
|
+
|
|
9
|
+
# the singleton pattern
|
|
10
|
+
def __new__(cls, *args, **kwargs):
|
|
11
|
+
if not hasattr(cls, 'instance'): cls.instance = super(Debug, 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 Debug.COMMAND
|
|
20
|
+
|
|
21
|
+
def cmd_list(self):
|
|
22
|
+
return [DebugTimings(), DebugCompletes()]
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from adam.commands import validate_args
|
|
2
|
+
from adam.commands.command import Command
|
|
3
|
+
from adam.config import Config
|
|
4
|
+
from adam.repl_state import ReplState
|
|
5
|
+
|
|
6
|
+
class DebugCompletes(Command):
|
|
7
|
+
COMMAND = 'debug completes'
|
|
8
|
+
|
|
9
|
+
# the singleton pattern
|
|
10
|
+
def __new__(cls, *args, **kwargs):
|
|
11
|
+
if not hasattr(cls, 'instance'): cls.instance = super(DebugCompletes, 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 DebugCompletes.COMMAND
|
|
20
|
+
|
|
21
|
+
def run(self, cmd: str, state: ReplState):
|
|
22
|
+
if not(args := self.args(cmd)):
|
|
23
|
+
return super().run(cmd, state)
|
|
24
|
+
|
|
25
|
+
with self.validate(args, state) as (args, state):
|
|
26
|
+
with validate_args(args, state, name='on, off or file') as args:
|
|
27
|
+
Config().set('debugs.complete', args)
|
|
28
|
+
|
|
29
|
+
return state
|
|
30
|
+
|
|
31
|
+
def completion(self, state: ReplState):
|
|
32
|
+
return super().completion(state, {f: None for f in ['on', 'off', 'file']})
|
|
33
|
+
|
|
34
|
+
def help(self, _: ReplState):
|
|
35
|
+
return f'{DebugCompletes.COMMAND} on|off|file\t turn auto complete debug on or off'
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from adam.commands import validate_args
|
|
2
|
+
from adam.commands.command import Command
|
|
3
|
+
from adam.config import Config
|
|
4
|
+
from adam.repl_state import ReplState
|
|
5
|
+
|
|
6
|
+
class DebugTimings(Command):
|
|
7
|
+
COMMAND = 'debug timings'
|
|
8
|
+
|
|
9
|
+
# the singleton pattern
|
|
10
|
+
def __new__(cls, *args, **kwargs):
|
|
11
|
+
if not hasattr(cls, 'instance'): cls.instance = super(DebugTimings, 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 DebugTimings.COMMAND
|
|
20
|
+
|
|
21
|
+
def run(self, cmd: str, state: ReplState):
|
|
22
|
+
if not(args := self.args(cmd)):
|
|
23
|
+
return super().run(cmd, state)
|
|
24
|
+
|
|
25
|
+
with self.validate(args, state) as (args, state):
|
|
26
|
+
with validate_args(args, state, name='on, off or file') as args:
|
|
27
|
+
Config().set('debugs.timings', args)
|
|
28
|
+
|
|
29
|
+
return state
|
|
30
|
+
|
|
31
|
+
def completion(self, state: ReplState):
|
|
32
|
+
return super().completion(state, {f: None for f in ['on', 'off', 'file']})
|
|
33
|
+
|
|
34
|
+
def help(self, _: ReplState):
|
|
35
|
+
return f'{DebugTimings.COMMAND} on|off|file\t turn timing debug on or off'
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from adam.commands.command import Command
|
|
2
|
+
from adam.repl_state import ReplState
|
|
3
|
+
from adam.sql.async_executor import AsyncExecutor
|
|
4
|
+
from adam.utils import tabulize
|
|
5
|
+
|
|
6
|
+
class ShowOffloadedCompletes(Command):
|
|
7
|
+
COMMAND = 'show offloaded completes'
|
|
8
|
+
|
|
9
|
+
# the singleton pattern
|
|
10
|
+
def __new__(cls, *args, **kwargs):
|
|
11
|
+
if not hasattr(cls, 'instance'): cls.instance = super(ShowOffloadedCompletes, 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 ShowOffloadedCompletes.COMMAND
|
|
20
|
+
|
|
21
|
+
def run(self, cmd: str, state: ReplState):
|
|
22
|
+
if not(args := self.args(cmd)):
|
|
23
|
+
return super().run(cmd, state)
|
|
24
|
+
|
|
25
|
+
with self.validate(args, state) as (args, state):
|
|
26
|
+
pending, processed, first, last = AsyncExecutor.entries_in_queue()
|
|
27
|
+
lines = []
|
|
28
|
+
for k, v in processed.items():
|
|
29
|
+
lines.append(f'{k}\t{v:2.2f}')
|
|
30
|
+
for k in pending:
|
|
31
|
+
lines.append(f'{k}\tpending')
|
|
32
|
+
lines += [
|
|
33
|
+
f'---------------------------',
|
|
34
|
+
f'duration\t{last-first:2.2f}'
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
tabulize(lines, header='key\tduration(in sec)', separator='\t')
|
|
38
|
+
|
|
39
|
+
return state
|
|
40
|
+
|
|
41
|
+
def completion(self, state: ReplState):
|
|
42
|
+
return super().completion(state)
|
|
43
|
+
|
|
44
|
+
def help(self, _: ReplState):
|
|
45
|
+
return f'{ShowOffloadedCompletes.COMMAND}\t show offloaded completes'
|
adam/commands/devices/device.py
CHANGED
|
@@ -2,13 +2,23 @@ from abc import abstractmethod
|
|
|
2
2
|
|
|
3
3
|
from adam.commands.command import Command
|
|
4
4
|
from adam.config import Config
|
|
5
|
-
from adam.pod_exec_result import PodExecResult
|
|
5
|
+
from adam.utils_k8s.pod_exec_result import PodExecResult
|
|
6
6
|
from adam.repl_state import BashSession, ReplState
|
|
7
7
|
from adam.utils import log2
|
|
8
|
+
from adam.utils_k8s.pods import Pods
|
|
8
9
|
|
|
9
10
|
class Device:
|
|
10
|
-
def pods(self, state: ReplState) -> tuple[list[str], str]:
|
|
11
|
-
return self.pod_names(state), self.pod(state)
|
|
11
|
+
def pods(self, state: ReplState, me: str = None) -> tuple[list[str], str]:
|
|
12
|
+
return self.pod_names(state), me if me else self.pod(state)
|
|
13
|
+
|
|
14
|
+
def default_pod(self, state: ReplState) -> tuple[list[str], str]:
|
|
15
|
+
if me := self.pod(state):
|
|
16
|
+
return me
|
|
17
|
+
|
|
18
|
+
if pods := self.pod_names(state):
|
|
19
|
+
return pods[0]
|
|
20
|
+
|
|
21
|
+
return None
|
|
12
22
|
|
|
13
23
|
def pod(self, state: ReplState) -> str:
|
|
14
24
|
return None
|
|
@@ -32,6 +42,9 @@ class Device:
|
|
|
32
42
|
def cd_completion(self, cmd: str, state: ReplState, default: dict = {}):
|
|
33
43
|
return default
|
|
34
44
|
|
|
45
|
+
def direct_dirs(self, cmd: str, state: ReplState, default: dict = {}) -> list[str]:
|
|
46
|
+
return []
|
|
47
|
+
|
|
35
48
|
@abstractmethod
|
|
36
49
|
def pwd(self, state: ReplState):
|
|
37
50
|
pass
|
|
@@ -120,4 +133,17 @@ class Device:
|
|
|
120
133
|
pass
|
|
121
134
|
|
|
122
135
|
def bash_completion(self, cmd: str, state: ReplState, default: dict = {}):
|
|
123
|
-
return default
|
|
136
|
+
return default
|
|
137
|
+
|
|
138
|
+
def files(self, state: ReplState):
|
|
139
|
+
r: PodExecResult = Pods.exec(self.default_pod(state), self.default_container(state), state.namespace, f'find -maxdepth 1 -type f', show_out=Config().is_debug(), shell='bash')
|
|
140
|
+
|
|
141
|
+
log_files = []
|
|
142
|
+
for line in r.stdout.split('\n'):
|
|
143
|
+
line = line.strip(' \r')
|
|
144
|
+
if line:
|
|
145
|
+
if line.startswith('./'):
|
|
146
|
+
line = line[2:]
|
|
147
|
+
log_files.append(line)
|
|
148
|
+
|
|
149
|
+
return log_files
|
|
@@ -116,7 +116,7 @@ class DeviceApp(Command, Device):
|
|
|
116
116
|
if state.app_app:
|
|
117
117
|
words.append(f'app/{state.app_app}')
|
|
118
118
|
|
|
119
|
-
return '\t'.join([f'{ReplState.
|
|
119
|
+
return '\t'.join([f'{ReplState.A}:>'] + (words if words else ['/']))
|
|
120
120
|
|
|
121
121
|
def try_fallback_action(self, chain: Command, state: ReplState, cmd: str):
|
|
122
122
|
if state.app_app:
|
|
@@ -3,7 +3,7 @@ from adam.commands.devices.device import Device
|
|
|
3
3
|
from adam.commands.export.export_databases import ExportDatabases, export_db
|
|
4
4
|
from adam.config import Config
|
|
5
5
|
from adam.repl_state import ReplState
|
|
6
|
-
from adam.utils import tabulize,
|
|
6
|
+
from adam.utils import tabulize, log2, wait_log
|
|
7
7
|
|
|
8
8
|
class DeviceExport(Command, Device):
|
|
9
9
|
COMMAND = f'{ReplState.X}:'
|
|
@@ -66,7 +66,10 @@ class DeviceExport(Command, Device):
|
|
|
66
66
|
return '\t'.join([f'{ReplState.X}:>'] + (words if words else ['/']))
|
|
67
67
|
|
|
68
68
|
def try_fallback_action(self, chain: Command, state: ReplState, cmd: str):
|
|
69
|
-
|
|
69
|
+
if cmd.startswith('select '):
|
|
70
|
+
cmd = f'xelect {cmd[7:]}'
|
|
71
|
+
|
|
72
|
+
result = chain.run(cmd, state)
|
|
70
73
|
if type(result) is ReplState:
|
|
71
74
|
if state.export_session and not result.export_session:
|
|
72
75
|
state.export_session = None
|
|
@@ -47,6 +47,10 @@ class DevicePostgres(Command, Device):
|
|
|
47
47
|
return container
|
|
48
48
|
|
|
49
49
|
def ls(self, cmd: str, state: ReplState):
|
|
50
|
+
if state.pod_targetted:
|
|
51
|
+
self.bash(state, state, ['ls'])
|
|
52
|
+
return
|
|
53
|
+
|
|
50
54
|
with pg_path(state) as (host, database):
|
|
51
55
|
if database:
|
|
52
56
|
tabulize(pg_table_names(state), header='NAME', separator=',')
|
|
@@ -94,13 +98,16 @@ class DevicePostgres(Command, Device):
|
|
|
94
98
|
state.pg_path = host
|
|
95
99
|
|
|
96
100
|
def cd_completion(self, cmd: str, state: ReplState, default: dict = {}):
|
|
101
|
+
return {cmd: {d: None for d in self.direct_dirs(cmd, state, default=default)}}
|
|
102
|
+
|
|
103
|
+
def direct_dirs(self, cmd: str, state: ReplState, default: dict = {}) -> list[str]:
|
|
97
104
|
with pg_path(state) as (host, database):
|
|
98
105
|
if database:
|
|
99
|
-
return
|
|
106
|
+
return ['..']
|
|
100
107
|
elif host:
|
|
101
|
-
return
|
|
108
|
+
return ['..'] + [p for p in pg_database_names(state)]
|
|
102
109
|
else:
|
|
103
|
-
return
|
|
110
|
+
return [p for p in PostgresDatabases.host_names(state.namespace)]
|
|
104
111
|
|
|
105
112
|
def pwd(self, state: ReplState):
|
|
106
113
|
words = []
|
|
@@ -115,6 +122,9 @@ class DevicePostgres(Command, Device):
|
|
|
115
122
|
|
|
116
123
|
def try_fallback_action(self, chain: Command, state: ReplState, cmd: str):
|
|
117
124
|
with pg_path(state) as (_, database):
|
|
125
|
+
if not database:
|
|
126
|
+
database = PostgresDatabases.default_db()
|
|
127
|
+
|
|
118
128
|
if database:
|
|
119
129
|
return True, chain.run(f'pg {cmd}', state)
|
|
120
130
|
|
adam/commands/devices/devices.py
CHANGED
|
@@ -7,7 +7,7 @@ from adam.commands.devices.device_postgres import DevicePostgres
|
|
|
7
7
|
from adam.repl_state import ReplState
|
|
8
8
|
|
|
9
9
|
class Devices:
|
|
10
|
-
def
|
|
10
|
+
def of(state: ReplState) -> Device:
|
|
11
11
|
if state.device == ReplState.A:
|
|
12
12
|
return DeviceApp()
|
|
13
13
|
elif state.device == ReplState.C:
|
|
File without changes
|
|
@@ -5,7 +5,7 @@ from adam.checks.check_utils import all_checks, checks_from_csv, run_checks
|
|
|
5
5
|
from adam.commands import extract_options, validate_args
|
|
6
6
|
from adam.commands.command import Command
|
|
7
7
|
from adam.commands.command_helpers import ClusterOrPodCommandHelper
|
|
8
|
-
from adam.commands.issues import Issues
|
|
8
|
+
from adam.commands.diag.issues import Issues
|
|
9
9
|
from adam.repl_state import ReplState
|
|
10
10
|
from adam.utils import tabulize, log
|
|
11
11
|
from adam.utils_issues import IssuesUtils
|