kaqing 2.0.95__py3-none-any.whl → 2.0.115__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/batch.py +1 -15
- adam/commands/alter_tables.py +3 -14
- adam/commands/app.py +3 -3
- adam/commands/app_ping.py +2 -2
- adam/commands/audit/audit.py +26 -11
- adam/commands/audit/audit_repair_tables.py +20 -37
- adam/commands/audit/audit_run.py +58 -0
- adam/commands/audit/show_last10.py +51 -0
- adam/commands/audit/show_slow10.py +50 -0
- adam/commands/audit/show_top10.py +49 -0
- adam/commands/audit/utils_show_top10.py +59 -0
- adam/commands/bash/bash.py +124 -0
- adam/commands/bash/bash_completer.py +93 -0
- adam/commands/cat.py +55 -0
- adam/commands/cd.py +23 -11
- adam/commands/check.py +6 -0
- adam/commands/code.py +60 -0
- adam/commands/command.py +9 -4
- adam/commands/commands_utils.py +1 -2
- adam/commands/cql/cql_completions.py +7 -3
- adam/commands/cql/cql_utils.py +100 -8
- adam/commands/cql/cqlsh.py +10 -5
- adam/commands/deploy/deploy.py +7 -1
- adam/commands/deploy/deploy_pg_agent.py +2 -2
- adam/commands/deploy/undeploy.py +7 -1
- adam/commands/deploy/undeploy_pg_agent.py +2 -2
- adam/commands/devices.py +29 -0
- adam/commands/export/__init__.py +0 -0
- adam/commands/export/export.py +60 -0
- adam/commands/export/export_on_x.py +76 -0
- adam/commands/export/export_rmdbs.py +65 -0
- adam/commands/export/export_select.py +68 -0
- adam/commands/export/export_use.py +56 -0
- adam/commands/export/utils_export.py +253 -0
- adam/commands/help.py +9 -5
- adam/commands/issues.py +6 -0
- adam/commands/kubectl.py +41 -0
- adam/commands/login.py +6 -3
- adam/commands/logs.py +1 -0
- adam/commands/ls.py +39 -27
- adam/commands/medusa/medusa_show_backupjobs.py +1 -0
- adam/commands/nodetool.py +5 -2
- adam/commands/postgres/postgres.py +4 -4
- adam/commands/postgres/{postgres_session.py → postgres_context.py} +26 -27
- adam/commands/postgres/postgres_utils.py +5 -5
- adam/commands/postgres/psql_completions.py +1 -1
- adam/commands/preview_table.py +18 -32
- adam/commands/pwd.py +4 -3
- adam/commands/reaper/reaper.py +3 -0
- adam/commands/repair/repair.py +3 -3
- adam/commands/report.py +6 -0
- adam/commands/show/show.py +3 -1
- adam/commands/show/show_app_actions.py +3 -0
- adam/commands/show/show_app_queues.py +3 -2
- adam/commands/show/show_login.py +3 -0
- adam/config.py +1 -1
- adam/embedded_params.py +1 -1
- adam/pod_exec_result.py +7 -1
- adam/repl.py +121 -97
- adam/repl_commands.py +29 -17
- adam/repl_state.py +224 -44
- adam/sql/sql_completer.py +86 -62
- adam/sql/sql_state_machine.py +563 -0
- adam/sql/term_completer.py +3 -0
- adam/utils_athena.py +108 -74
- adam/utils_audits.py +104 -0
- adam/utils_export.py +42 -0
- adam/utils_k8s/app_clusters.py +33 -0
- adam/utils_k8s/app_pods.py +31 -0
- adam/utils_k8s/cassandra_clusters.py +4 -5
- adam/utils_k8s/cassandra_nodes.py +4 -4
- adam/utils_k8s/pods.py +42 -6
- adam/utils_k8s/statefulsets.py +2 -2
- adam/version.py +1 -1
- {kaqing-2.0.95.dist-info → kaqing-2.0.115.dist-info}/METADATA +1 -1
- {kaqing-2.0.95.dist-info → kaqing-2.0.115.dist-info}/RECORD +80 -67
- adam/commands/bash.py +0 -92
- adam/commands/cql/cql_table_completer.py +0 -8
- adam/commands/describe/describe.py +0 -46
- adam/commands/describe/describe_keyspace.py +0 -60
- adam/commands/describe/describe_keyspaces.py +0 -50
- adam/commands/describe/describe_table.py +0 -60
- adam/commands/describe/describe_tables.py +0 -50
- adam/commands/postgres/psql_table_completer.py +0 -11
- adam/sql/state_machine.py +0 -460
- /adam/commands/{describe → bash}/__init__.py +0 -0
- {kaqing-2.0.95.dist-info → kaqing-2.0.115.dist-info}/WHEEL +0 -0
- {kaqing-2.0.95.dist-info → kaqing-2.0.115.dist-info}/entry_points.txt +0 -0
- {kaqing-2.0.95.dist-info → kaqing-2.0.115.dist-info}/top_level.txt +0 -0
adam/batch.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import click
|
|
2
2
|
|
|
3
3
|
from adam.commands.audit.audit import Audit, AuditCommandHelper
|
|
4
|
-
from adam.commands.bash import Bash
|
|
4
|
+
from adam.commands.bash.bash import Bash
|
|
5
5
|
from adam.commands.check import Check, CheckCommandHelper
|
|
6
6
|
from adam.commands.cp import ClipboardCopy, CopyCommandHelper
|
|
7
7
|
from adam.commands.command import Command
|
|
@@ -9,7 +9,6 @@ from adam.commands.command_helpers import ClusterCommandHelper, ClusterOrPodComm
|
|
|
9
9
|
from adam.commands.cql.cqlsh import CqlCommandHelper, Cqlsh
|
|
10
10
|
from adam.commands.deploy.deploy import Deploy, DeployCommandHelper
|
|
11
11
|
from adam.commands.deploy.undeploy import Undeploy, UndeployCommandHelper
|
|
12
|
-
from adam.commands.describe.describe import Describe, DescribeCommandHelper
|
|
13
12
|
from adam.commands.issues import Issues
|
|
14
13
|
from adam.commands.login import Login
|
|
15
14
|
from adam.commands.logs import Logs
|
|
@@ -97,19 +96,6 @@ def deploy(kubeconfig: str, config: str, param: list[str], namespace: str, extra
|
|
|
97
96
|
run_command(Deploy(), kubeconfig, config, param, None, namespace, None, extra_args)
|
|
98
97
|
|
|
99
98
|
|
|
100
|
-
@cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=DescribeCommandHelper, help='Describe keyspace(s) or table(s).')
|
|
101
|
-
@click.option('--kubeconfig', '-k', required=False, metavar='path', help='path to kubeconfig file')
|
|
102
|
-
@click.option('--config', default='params.yaml', metavar='path', help='path to kaqing parameters file')
|
|
103
|
-
@click.option('--param', '-v', multiple=True, metavar='<key>=<value>', help='parameter override')
|
|
104
|
-
@click.option('--cluster', '-c', required=False, metavar='statefulset', help='Kubernetes statefulset name')
|
|
105
|
-
@click.option('--namespace', '-n', required=False, metavar='namespace', help='Kubernetes namespace')
|
|
106
|
-
@click.option('--pod', '-p', required=False, metavar='pod', help='Kubernetes pod name')
|
|
107
|
-
@click.option('--all-nodes', '-a', is_flag=True, help='execute on all Cassandra nodes')
|
|
108
|
-
@click.argument('extra_args', nargs=-1, metavar='<cluster|pod>', type=click.UNPROCESSED)
|
|
109
|
-
def describe(kubeconfig: str, config: str, param: list[str], cluster: str, namespace: str, pod: str, all_nodes: bool, extra_args):
|
|
110
|
-
run_command(Describe(), kubeconfig, config, param, cluster, namespace, pod, ('--all-nodes',) + extra_args if all_nodes else extra_args)
|
|
111
|
-
|
|
112
|
-
|
|
113
99
|
@cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=ClusterOrPodCommandHelper, help="Print Qing's issues.")
|
|
114
100
|
@click.option('--kubeconfig', '-k', required=False, metavar='path', help='path to kubeconfig file')
|
|
115
101
|
@click.option('--config', default='params.yaml', metavar='path', help='path to kaqing parameters file')
|
adam/commands/alter_tables.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from adam.commands.command import Command
|
|
2
2
|
from adam.commands.cql.cql_utils import tables as get_tables, run_cql
|
|
3
3
|
from adam.config import Config
|
|
4
|
-
from adam.pod_exec_result import PodExecResult
|
|
5
4
|
from adam.repl_state import ReplState, RequiredState
|
|
6
5
|
from adam.utils import log2
|
|
7
6
|
|
|
@@ -44,11 +43,6 @@ class AlterTables(Command):
|
|
|
44
43
|
args, include_reaper = Command.extract_options(args, '--include-reaper')
|
|
45
44
|
arg_str = ' '.join(args)
|
|
46
45
|
|
|
47
|
-
# r: list[PodExecResult] = run_cql(state, 'describe tables', show_out=False, on_any=True)
|
|
48
|
-
# if not r:
|
|
49
|
-
# log2('No pod is available')
|
|
50
|
-
# return 'no-pod'
|
|
51
|
-
|
|
52
46
|
excludes = [e.strip(' \r\n') for e in Config().get(
|
|
53
47
|
'cql.alter-tables.excludes',
|
|
54
48
|
'system_auth,system_traces,reaper_db,system_distributed,system_views,system,system_schema,system_virtual_schema').split(',')]
|
|
@@ -79,14 +73,9 @@ class AlterTables(Command):
|
|
|
79
73
|
# do not continue to cql route
|
|
80
74
|
return state
|
|
81
75
|
|
|
82
|
-
def completion(self,
|
|
83
|
-
|
|
84
|
-
ps = Config().get('cql.alter-tables.gc-grace-periods', '3600,86400,864000,7776000').split(',')
|
|
85
|
-
return super().completion(state, {
|
|
86
|
-
'GC_GRACE_SECONDS': {'=': {p.strip(' \r\n'): {'--include-reaper': None} for p in ps}},
|
|
87
|
-
})
|
|
88
|
-
|
|
76
|
+
def completion(self, _: ReplState) -> dict[str, any]:
|
|
77
|
+
# auto completion is taken care of by sql completer
|
|
89
78
|
return {}
|
|
90
79
|
|
|
91
80
|
def help(self, _: ReplState) -> str:
|
|
92
|
-
return f'{AlterTables.COMMAND} <param = value> [--include-reaper] \t alter on all tables'
|
|
81
|
+
return f'{AlterTables.COMMAND} <param = value> [--include-reaper] \t alter schema on all tables'
|
adam/commands/app.py
CHANGED
|
@@ -22,14 +22,14 @@ class App(Command):
|
|
|
22
22
|
return App.COMMAND
|
|
23
23
|
|
|
24
24
|
def required(self):
|
|
25
|
-
return RequiredState.
|
|
25
|
+
return RequiredState.APP_APP
|
|
26
26
|
|
|
27
27
|
def run(self, cmd: str, state: ReplState):
|
|
28
28
|
if not(args := self.args(cmd)):
|
|
29
29
|
return super().run(cmd, state)
|
|
30
30
|
|
|
31
31
|
state, args = self.apply_state(args, state)
|
|
32
|
-
if not self.validate_state(state
|
|
32
|
+
if not self.validate_state(state):
|
|
33
33
|
return state
|
|
34
34
|
|
|
35
35
|
args, forced = Command.extract_options(args, '--force')
|
|
@@ -64,4 +64,4 @@ class App(Command):
|
|
|
64
64
|
return {}
|
|
65
65
|
|
|
66
66
|
def help(self, _: ReplState):
|
|
67
|
-
return f"
|
|
67
|
+
return f"<AppType>.<AppAction> <args> [--force]\t post app action; check with 'show app actions' command"
|
adam/commands/app_ping.py
CHANGED
|
@@ -18,14 +18,14 @@ class AppPing(Command):
|
|
|
18
18
|
return AppPing.COMMAND
|
|
19
19
|
|
|
20
20
|
def required(self):
|
|
21
|
-
return RequiredState.
|
|
21
|
+
return RequiredState.APP_APP
|
|
22
22
|
|
|
23
23
|
def run(self, cmd: str, state: ReplState):
|
|
24
24
|
if not(args := self.args(cmd)):
|
|
25
25
|
return super().run(cmd, state)
|
|
26
26
|
|
|
27
27
|
state, args = self.apply_state(args, state)
|
|
28
|
-
if not self.validate_state(state
|
|
28
|
+
if not self.validate_state(state):
|
|
29
29
|
return state
|
|
30
30
|
|
|
31
31
|
_, forced = Command.extract_options(args, '--force')
|
adam/commands/audit/audit.py
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import click
|
|
2
2
|
|
|
3
3
|
from adam.commands.audit.audit_repair_tables import AuditRepairTables
|
|
4
|
+
from adam.commands.audit.audit_run import AuditRun
|
|
5
|
+
from adam.commands.audit.show_last10 import ShowLast10
|
|
6
|
+
from adam.commands.audit.show_slow10 import ShowSlow10
|
|
7
|
+
from adam.commands.audit.show_top10 import ShowTop10
|
|
8
|
+
from adam.commands.audit.utils_show_top10 import show_top10_completions_for_nesting
|
|
4
9
|
from adam.commands.command import Command
|
|
5
10
|
from adam.config import Config
|
|
6
11
|
from adam.repl_state import ReplState
|
|
7
12
|
from adam.sql.sql_completer import SqlCompleter
|
|
8
13
|
from adam.utils import log2
|
|
9
|
-
from adam.utils_athena import
|
|
14
|
+
from adam.utils_athena import Athena
|
|
15
|
+
from adam.utils_audits import Audits
|
|
10
16
|
|
|
11
17
|
class Audit(Command):
|
|
12
18
|
COMMAND = 'audit'
|
|
@@ -24,11 +30,16 @@ class Audit(Command):
|
|
|
24
30
|
def command(self):
|
|
25
31
|
return Audit.COMMAND
|
|
26
32
|
|
|
33
|
+
def required(self):
|
|
34
|
+
return ReplState.L
|
|
35
|
+
|
|
27
36
|
def run(self, cmd: str, state: ReplState):
|
|
28
37
|
if not(args := self.args(cmd)):
|
|
29
38
|
return super().run(cmd, state)
|
|
30
39
|
|
|
31
40
|
state, args = self.apply_state(args, state)
|
|
41
|
+
if not self.validate_state(state):
|
|
42
|
+
return state
|
|
32
43
|
|
|
33
44
|
r = None
|
|
34
45
|
if len(args) > 0:
|
|
@@ -41,7 +52,7 @@ class Audit(Command):
|
|
|
41
52
|
else:
|
|
42
53
|
log2(sql)
|
|
43
54
|
|
|
44
|
-
|
|
55
|
+
Athena.run_query(sql)
|
|
45
56
|
|
|
46
57
|
return state
|
|
47
58
|
|
|
@@ -50,21 +61,25 @@ class Audit(Command):
|
|
|
50
61
|
if not self.schema_read:
|
|
51
62
|
Config().wait_log(f'Inspecting audit database schema...')
|
|
52
63
|
self.schema_read = True
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return super().completion(state) |
|
|
59
|
-
|
|
64
|
+
# warm up the caches first time when l: drive is accessed
|
|
65
|
+
Athena.table_names()
|
|
66
|
+
Athena.column_names()
|
|
67
|
+
Athena.column_names(partition_cols_only=True)
|
|
68
|
+
|
|
69
|
+
return super().completion(state) | show_top10_completions_for_nesting() | SqlCompleter(
|
|
70
|
+
lambda: Athena.table_names(),
|
|
71
|
+
columns=lambda table: Athena.column_names(),
|
|
72
|
+
partition_columns=lambda table: Athena.column_names(partition_cols_only=True),
|
|
73
|
+
variant='athena'
|
|
74
|
+
).completions_for_nesting()
|
|
60
75
|
|
|
61
76
|
return {}
|
|
62
77
|
|
|
63
78
|
def cmd_list():
|
|
64
|
-
return [AuditRepairTables()]
|
|
79
|
+
return [AuditRepairTables(), AuditRun(), ShowLast10(), ShowSlow10(), ShowTop10()]
|
|
65
80
|
|
|
66
81
|
def help(self, _: ReplState):
|
|
67
|
-
return f'[{Audit.COMMAND}] <sql-statements
|
|
82
|
+
return f'[{Audit.COMMAND}] [<sql-statements>]\t run SQL queries on Authena audit database'
|
|
68
83
|
|
|
69
84
|
class AuditCommandHelper(click.Command):
|
|
70
85
|
def get_help(self, ctx: click.Context):
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import concurrent
|
|
2
2
|
import time
|
|
3
|
-
import requests
|
|
4
3
|
|
|
5
4
|
from adam.commands.command import Command
|
|
6
5
|
from adam.config import Config
|
|
7
6
|
from adam.repl_state import ReplState
|
|
8
7
|
from adam.utils import log, log2
|
|
9
|
-
from adam.utils_athena import
|
|
8
|
+
from adam.utils_athena import Athena
|
|
9
|
+
from adam.utils_audits import AuditMeta, Audits
|
|
10
10
|
|
|
11
11
|
class AuditRepairTables(Command):
|
|
12
12
|
COMMAND = 'audit repair'
|
|
@@ -24,17 +24,23 @@ class AuditRepairTables(Command):
|
|
|
24
24
|
def command(self):
|
|
25
25
|
return AuditRepairTables.COMMAND
|
|
26
26
|
|
|
27
|
+
def required(self):
|
|
28
|
+
return ReplState.L
|
|
29
|
+
|
|
27
30
|
def run(self, cmd: str, state: ReplState):
|
|
28
31
|
if not(args := self.args(cmd)):
|
|
29
32
|
return super().run(cmd, state)
|
|
30
33
|
|
|
31
34
|
state, args = self.apply_state(args, state)
|
|
35
|
+
if not self.validate_state(state):
|
|
36
|
+
return state
|
|
32
37
|
|
|
33
|
-
tables = Config().get('audit.tables', 'audit').split(',')
|
|
38
|
+
tables = Config().get('audit.athena.repair-partition-tables', 'audit').split(',')
|
|
34
39
|
if args:
|
|
35
40
|
tables = args
|
|
36
41
|
|
|
37
|
-
|
|
42
|
+
meta = Audits.get_meta()
|
|
43
|
+
self.repair(tables, meta)
|
|
38
44
|
|
|
39
45
|
return state
|
|
40
46
|
|
|
@@ -52,43 +58,20 @@ class AuditRepairTables(Command):
|
|
|
52
58
|
def auto_repair(self, hours: int):
|
|
53
59
|
self.auto_repaired = True
|
|
54
60
|
|
|
55
|
-
|
|
56
|
-
if
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
except:
|
|
63
|
-
pass
|
|
64
|
-
|
|
65
|
-
if do_repair:
|
|
66
|
-
tables = Config().get('audit.athena.tables', 'audit').split(',')
|
|
67
|
-
self.repair(tables, show_sql=True)
|
|
68
|
-
log2(f'Audit tables have been auto-repaired.')
|
|
69
|
-
|
|
70
|
-
def repair(self, tables: list[str], show_sql = False):
|
|
61
|
+
meta: AuditMeta = Audits.get_meta()
|
|
62
|
+
if meta.partitions_last_checked + hours * 60 * 60 < time.time():
|
|
63
|
+
tables = Config().get('audit.athena.repair-partition-tables', 'audit').split(',')
|
|
64
|
+
self.repair(tables, meta, show_sql=True)
|
|
65
|
+
log2(f'Audit tables have been auto-repaired.')
|
|
66
|
+
|
|
67
|
+
def repair(self, tables: list[str], meta: AuditMeta, show_sql = False):
|
|
71
68
|
with concurrent.futures.ThreadPoolExecutor(max_workers=Config().get('audit.workers', 3)) as executor:
|
|
72
69
|
for table in tables:
|
|
73
70
|
if show_sql:
|
|
74
71
|
log(f'MSCK REPAIR TABLE {table}')
|
|
75
72
|
|
|
76
|
-
executor.submit(
|
|
77
|
-
executor.submit(
|
|
73
|
+
executor.submit(Athena.run_query, f'MSCK REPAIR TABLE {table}', None,)
|
|
74
|
+
executor.submit(Audits.put_meta, Audits.PARTITIONS_ADDED, meta,)
|
|
78
75
|
|
|
79
76
|
def help(self, _: ReplState):
|
|
80
|
-
return f"{AuditRepairTables.COMMAND} \t run MSCK REPAIR command for new partition discovery"
|
|
81
|
-
|
|
82
|
-
def check_in(self):
|
|
83
|
-
payload = {
|
|
84
|
-
'action': 'check-in'
|
|
85
|
-
}
|
|
86
|
-
audit_endpoint = Config().get("audit.endpoint", "https://4psvtaxlcb.execute-api.us-west-2.amazonaws.com/prod/")
|
|
87
|
-
try:
|
|
88
|
-
response = requests.post(audit_endpoint, json=payload, timeout=Config().get("audit.timeout", 10))
|
|
89
|
-
if response.status_code in [200, 201]:
|
|
90
|
-
Config().debug(response.text)
|
|
91
|
-
else:
|
|
92
|
-
log2(f"Error: {response.status_code} {response.text}")
|
|
93
|
-
except requests.exceptions.Timeout as e:
|
|
94
|
-
log2(f"Timeout occurred: {e}")
|
|
77
|
+
return f"{AuditRepairTables.COMMAND} \t run MSCK REPAIR command for new partition discovery"
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import concurrent
|
|
2
|
+
|
|
3
|
+
from adam.commands.command import Command
|
|
4
|
+
from adam.config import Config
|
|
5
|
+
from adam.repl_state import ReplState
|
|
6
|
+
from adam.utils import log2
|
|
7
|
+
from adam.utils_athena import Athena
|
|
8
|
+
from adam.utils_audits import AuditMeta, Audits
|
|
9
|
+
|
|
10
|
+
class AuditRun(Command):
|
|
11
|
+
COMMAND = 'audit run'
|
|
12
|
+
|
|
13
|
+
# the singleton pattern
|
|
14
|
+
def __new__(cls, *args, **kwargs):
|
|
15
|
+
if not hasattr(cls, 'instance'): cls.instance = super(AuditRun, cls).__new__(cls)
|
|
16
|
+
|
|
17
|
+
return cls.instance
|
|
18
|
+
|
|
19
|
+
def __init__(self, successor: Command=None):
|
|
20
|
+
super().__init__(successor)
|
|
21
|
+
self.auto_repaired = False
|
|
22
|
+
|
|
23
|
+
def command(self):
|
|
24
|
+
return AuditRun.COMMAND
|
|
25
|
+
|
|
26
|
+
def required(self):
|
|
27
|
+
return ReplState.L
|
|
28
|
+
|
|
29
|
+
def run(self, cmd: str, state: ReplState):
|
|
30
|
+
if not(args := self.args(cmd)):
|
|
31
|
+
return super().run(cmd, state)
|
|
32
|
+
|
|
33
|
+
state, args = self.apply_state(args, state)
|
|
34
|
+
if not self.validate_state(state):
|
|
35
|
+
return state
|
|
36
|
+
|
|
37
|
+
meta: AuditMeta = Audits.get_meta()
|
|
38
|
+
clusters = Audits.find_new_clusters(meta.cluster_last_checked)
|
|
39
|
+
Audits.put_meta(Audits.ADD_CLUSTERS, meta, clusters=clusters)
|
|
40
|
+
if clusters:
|
|
41
|
+
log2(f'Added {len(clusters)} new clusters.')
|
|
42
|
+
tables = Config().get('audit.athena.repair-cluster-tables', 'cluster').split(',')
|
|
43
|
+
with concurrent.futures.ThreadPoolExecutor(max_workers=Config().get('audit.workers', 3)) as executor:
|
|
44
|
+
for table in tables:
|
|
45
|
+
executor.submit(Athena.run_query, f'MSCK REPAIR TABLE {table}', None,)
|
|
46
|
+
else:
|
|
47
|
+
log2(f'No new clusters were found.')
|
|
48
|
+
|
|
49
|
+
return state
|
|
50
|
+
|
|
51
|
+
def completion(self, state: ReplState):
|
|
52
|
+
if state.device == ReplState.L:
|
|
53
|
+
return super().completion(state)
|
|
54
|
+
|
|
55
|
+
return {}
|
|
56
|
+
|
|
57
|
+
def help(self, _: ReplState):
|
|
58
|
+
return f"{AuditRun.COMMAND} \t run"
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from adam.commands.audit.utils_show_top10 import extract_limit_and_duration
|
|
2
|
+
from adam.commands.command import Command
|
|
3
|
+
from adam.repl_state import ReplState
|
|
4
|
+
from adam.utils import log2
|
|
5
|
+
from adam.utils_athena import Athena
|
|
6
|
+
from adam.utils_audits import Audits
|
|
7
|
+
|
|
8
|
+
class ShowLast10(Command):
|
|
9
|
+
COMMAND = 'show last'
|
|
10
|
+
|
|
11
|
+
# the singleton pattern
|
|
12
|
+
def __new__(cls, *args, **kwargs):
|
|
13
|
+
if not hasattr(cls, 'instance'): cls.instance = super(ShowLast10, cls).__new__(cls)
|
|
14
|
+
|
|
15
|
+
return cls.instance
|
|
16
|
+
|
|
17
|
+
def __init__(self, successor: Command=None):
|
|
18
|
+
super().__init__(successor)
|
|
19
|
+
|
|
20
|
+
def command(self):
|
|
21
|
+
return ShowLast10.COMMAND
|
|
22
|
+
|
|
23
|
+
def required(self):
|
|
24
|
+
return ReplState.L
|
|
25
|
+
|
|
26
|
+
def run(self, cmd: str, state: ReplState):
|
|
27
|
+
if not(args := self.args(cmd)):
|
|
28
|
+
return super().run(cmd, state)
|
|
29
|
+
|
|
30
|
+
state, args = self.apply_state(args, state)
|
|
31
|
+
if not self.validate_state(state):
|
|
32
|
+
return state
|
|
33
|
+
|
|
34
|
+
limit, date_condition = extract_limit_and_duration(args)
|
|
35
|
+
|
|
36
|
+
query = '\n '.join([
|
|
37
|
+
"SELECT * FROM audit",
|
|
38
|
+
f"WHERE drive <> 'z' and ({date_condition})",
|
|
39
|
+
f"ORDER BY ts DESC LIMIT {limit};"])
|
|
40
|
+
log2(query)
|
|
41
|
+
log2()
|
|
42
|
+
Athena.run_query(query)
|
|
43
|
+
|
|
44
|
+
return state
|
|
45
|
+
|
|
46
|
+
def completion(self, _: ReplState):
|
|
47
|
+
|
|
48
|
+
return {}
|
|
49
|
+
|
|
50
|
+
def help(self, _: ReplState):
|
|
51
|
+
return f'{ShowLast10.COMMAND} [limit]\t show last <limit> audit lines'
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from adam.commands.audit.utils_show_top10 import extract_limit_and_duration
|
|
2
|
+
from adam.commands.command import Command
|
|
3
|
+
from adam.repl_state import ReplState
|
|
4
|
+
from adam.utils import log2
|
|
5
|
+
from adam.utils_athena import Athena
|
|
6
|
+
from adam.utils_audits import Audits
|
|
7
|
+
|
|
8
|
+
class ShowSlow10(Command):
|
|
9
|
+
COMMAND = 'show slow'
|
|
10
|
+
|
|
11
|
+
# the singleton pattern
|
|
12
|
+
def __new__(cls, *args, **kwargs):
|
|
13
|
+
if not hasattr(cls, 'instance'): cls.instance = super(ShowSlow10, cls).__new__(cls)
|
|
14
|
+
|
|
15
|
+
return cls.instance
|
|
16
|
+
|
|
17
|
+
def __init__(self, successor: Command=None):
|
|
18
|
+
super().__init__(successor)
|
|
19
|
+
|
|
20
|
+
def command(self):
|
|
21
|
+
return ShowSlow10.COMMAND
|
|
22
|
+
|
|
23
|
+
def required(self):
|
|
24
|
+
return ReplState.L
|
|
25
|
+
|
|
26
|
+
def run(self, cmd: str, state: ReplState):
|
|
27
|
+
if not(args := self.args(cmd)):
|
|
28
|
+
return super().run(cmd, state)
|
|
29
|
+
|
|
30
|
+
state, args = self.apply_state(args, state)
|
|
31
|
+
if not self.validate_state(state):
|
|
32
|
+
return state
|
|
33
|
+
|
|
34
|
+
limit, date_condition = extract_limit_and_duration(args)
|
|
35
|
+
|
|
36
|
+
query = '\n '.join([
|
|
37
|
+
"SELECT * FROM audit",
|
|
38
|
+
f"WHERE drive <> 'z' and ({date_condition})",
|
|
39
|
+
f"ORDER BY CAST(duration AS REAL) DESC LIMIT {limit};"])
|
|
40
|
+
log2(query)
|
|
41
|
+
log2()
|
|
42
|
+
Athena.run_query(query)
|
|
43
|
+
|
|
44
|
+
return state
|
|
45
|
+
|
|
46
|
+
def completion(self, _: ReplState):
|
|
47
|
+
return {}
|
|
48
|
+
|
|
49
|
+
def help(self, _: ReplState):
|
|
50
|
+
return f'{ShowSlow10.COMMAND} [limit]\t show slow <limit> audit lines'
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from adam.commands.audit.utils_show_top10 import extract_limit_and_duration
|
|
2
|
+
from adam.commands.command import Command
|
|
3
|
+
from adam.repl_state import ReplState
|
|
4
|
+
from adam.utils import log2
|
|
5
|
+
from adam.utils_athena import Athena
|
|
6
|
+
from adam.utils_audits import Audits
|
|
7
|
+
|
|
8
|
+
class ShowTop10(Command):
|
|
9
|
+
COMMAND = 'show top'
|
|
10
|
+
|
|
11
|
+
# the singleton pattern
|
|
12
|
+
def __new__(cls, *args, **kwargs):
|
|
13
|
+
if not hasattr(cls, 'instance'): cls.instance = super(ShowTop10, cls).__new__(cls)
|
|
14
|
+
|
|
15
|
+
return cls.instance
|
|
16
|
+
|
|
17
|
+
def __init__(self, successor: Command=None):
|
|
18
|
+
super().__init__(successor)
|
|
19
|
+
|
|
20
|
+
def command(self):
|
|
21
|
+
return ShowTop10.COMMAND
|
|
22
|
+
|
|
23
|
+
def required(self):
|
|
24
|
+
return ReplState.L
|
|
25
|
+
|
|
26
|
+
def run(self, cmd: str, state: ReplState):
|
|
27
|
+
if not(args := self.args(cmd)):
|
|
28
|
+
return super().run(cmd, state)
|
|
29
|
+
|
|
30
|
+
state, args = self.apply_state(args, state)
|
|
31
|
+
if not self.validate_state(state):
|
|
32
|
+
return state
|
|
33
|
+
|
|
34
|
+
limit, date_condition = extract_limit_and_duration(args)
|
|
35
|
+
query = '\n '.join([
|
|
36
|
+
"SELECT min(c) AS cluster, line, COUNT(*) AS cnt, avg(CAST(duration AS REAL)) AS duration",
|
|
37
|
+
f"FROM audit WHERE drive <> 'z' and ({date_condition})",
|
|
38
|
+
f"GROUP BY line ORDER BY cnt DESC LIMIT {limit};"])
|
|
39
|
+
log2(query)
|
|
40
|
+
log2()
|
|
41
|
+
Athena.run_query(query)
|
|
42
|
+
|
|
43
|
+
return state
|
|
44
|
+
|
|
45
|
+
def completion(self, _: ReplState):
|
|
46
|
+
return {}
|
|
47
|
+
|
|
48
|
+
def help(self, _: ReplState):
|
|
49
|
+
return f'{ShowTop10.COMMAND} [limit]\t show top <limit> audit lines'
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
from datetime import datetime, timedelta
|
|
2
|
+
|
|
3
|
+
from adam.utils_audits import Audits
|
|
4
|
+
from adam.utils_repl.automata_completer import AutomataCompleter
|
|
5
|
+
from adam.utils_repl.state_machine import StateMachine
|
|
6
|
+
|
|
7
|
+
def extract_limit_and_duration(args: list[str]) -> tuple[int, datetime]:
|
|
8
|
+
limit = 10
|
|
9
|
+
_from = datetime.now() - timedelta(days=30)
|
|
10
|
+
if args:
|
|
11
|
+
try:
|
|
12
|
+
limit = int(args[0])
|
|
13
|
+
except:
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
if len(args) > 2 and args[1] == 'over':
|
|
17
|
+
if args[2] == 'day':
|
|
18
|
+
_from = datetime.now() - timedelta(days=1)
|
|
19
|
+
|
|
20
|
+
return (limit, Audits.date_from(_from))
|
|
21
|
+
|
|
22
|
+
def limit_and_duration_completion():
|
|
23
|
+
return {'10': {'over': {
|
|
24
|
+
'day': None,
|
|
25
|
+
'month': None
|
|
26
|
+
}}}
|
|
27
|
+
|
|
28
|
+
SHOW_TOP10_SPEC = [
|
|
29
|
+
' > show > show',
|
|
30
|
+
'show > last|slow|top > show_top ^ last,slow,top',
|
|
31
|
+
'show_top > word > show_top_n ^ 10',
|
|
32
|
+
'show_top_n > over > show_top_n_over ^ over',
|
|
33
|
+
'show_top_n_over > day|month > show_top_n_over$ ^ day,month',
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
SHOW_TOP10_KEYWORDS = [
|
|
37
|
+
'show',
|
|
38
|
+
'top',
|
|
39
|
+
'last',
|
|
40
|
+
'slow',
|
|
41
|
+
'over',
|
|
42
|
+
'day',
|
|
43
|
+
'month'
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
class ShowTop10StateMachine(StateMachine[str]):
|
|
47
|
+
def spec(self) -> str:
|
|
48
|
+
return SHOW_TOP10_SPEC
|
|
49
|
+
|
|
50
|
+
def keywords(self) -> list[str]:
|
|
51
|
+
return SHOW_TOP10_KEYWORDS
|
|
52
|
+
|
|
53
|
+
def show_top10_completions_for_nesting():
|
|
54
|
+
return {
|
|
55
|
+
'show': {
|
|
56
|
+
'last': AutomataCompleter(ShowTop10StateMachine(), first_term='show last'),
|
|
57
|
+
'slow': AutomataCompleter(ShowTop10StateMachine(), first_term='show slow'),
|
|
58
|
+
'top': AutomataCompleter(ShowTop10StateMachine(), first_term='show top'),
|
|
59
|
+
}}
|