kaqing 2.0.103__tar.gz → 2.0.104__tar.gz
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.
- {kaqing-2.0.103 → kaqing-2.0.104}/PKG-INFO +1 -1
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/audit/audit.py +2 -1
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/audit/audit_repair_tables.py +13 -35
- kaqing-2.0.104/adam/commands/audit/audit_run.py +49 -0
- kaqing-2.0.104/adam/commands/bash.py +150 -0
- kaqing-2.0.104/adam/embedded_params.py +2 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/repl_commands.py +2 -1
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/sql/sql_completer.py +31 -4
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/sql/sql_state_machine.py +92 -8
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_athena.py +68 -1
- kaqing-2.0.104/adam/version.py +5 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/kaqing.egg-info/PKG-INFO +1 -1
- {kaqing-2.0.103 → kaqing-2.0.104}/kaqing.egg-info/SOURCES.txt +1 -2
- {kaqing-2.0.103 → kaqing-2.0.104}/setup.py +1 -1
- kaqing-2.0.103/adam/commands/bash.py +0 -92
- kaqing-2.0.103/adam/embedded_params.py +0 -2
- kaqing-2.0.103/adam/sql/automata_completer.py +0 -63
- kaqing-2.0.103/adam/sql/state_machine.py +0 -207
- kaqing-2.0.103/adam/version.py +0 -5
- {kaqing-2.0.103 → kaqing-2.0.104}/README +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/__init__.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/app_session.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/apps.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/batch.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/checks/__init__.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/checks/check.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/checks/check_context.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/checks/check_result.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/checks/check_utils.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/checks/compactionstats.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/checks/cpu.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/checks/disk.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/checks/gossip.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/checks/issue.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/checks/memory.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/checks/status.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/cli.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/cli_group.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/__init__.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/column.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/columns.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/compactions.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/cpu.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/dir_data.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/dir_snapshots.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/gossip.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/host_id.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/memory.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/node_address.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/node_load.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/node_owns.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/node_status.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/node_tokens.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/node_utils.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/pod_name.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/volume_cassandra.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/volume_root.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/__init__.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/alter_tables.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/app.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/app_ping.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/audit/__init__.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/cd.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/check.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/cli_commands.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/command.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/command_helpers.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/commands_utils.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/cp.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/cql/__init__.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/cql/cql_completions.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/cql/cql_utils.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/cql/cqlsh.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/deploy/__init__.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/deploy/code_start.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/deploy/code_stop.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/deploy/code_utils.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/deploy/deploy.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/deploy/deploy_frontend.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/deploy/deploy_pg_agent.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/deploy/deploy_pod.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/deploy/deploy_utils.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/deploy/undeploy.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/deploy/undeploy_frontend.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/deploy/undeploy_pg_agent.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/deploy/undeploy_pod.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/devices.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/exit.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/help.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/issues.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/login.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/logs.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/ls.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/medusa/__init__.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/medusa/medusa.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/medusa/medusa_backup.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/medusa/medusa_restore.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/medusa/medusa_show_backupjobs.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/medusa/medusa_show_restorejobs.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/nodetool.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/nodetool_commands.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/param_get.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/param_set.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/postgres/__init__.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/postgres/postgres.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/postgres/postgres_context.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/postgres/postgres_ls.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/postgres/postgres_preview.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/postgres/postgres_utils.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/postgres/psql_completions.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/preview_table.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/pwd.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/reaper/__init__.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/reaper/reaper.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/reaper/reaper_forward.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/reaper/reaper_forward_stop.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/reaper/reaper_restart.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/reaper/reaper_run_abort.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/reaper/reaper_runs.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/reaper/reaper_runs_abort.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/reaper/reaper_schedule_activate.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/reaper/reaper_schedule_start.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/reaper/reaper_schedule_stop.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/reaper/reaper_schedules.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/reaper/reaper_session.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/reaper/reaper_status.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/repair/__init__.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/repair/repair.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/repair/repair_log.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/repair/repair_run.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/repair/repair_scan.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/repair/repair_stop.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/report.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/restart.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/rollout.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/shell.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/show/__init__.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/show/show.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/show/show_adam.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/show/show_app_actions.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/show/show_app_id.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/show/show_app_queues.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/show/show_cassandra_status.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/show/show_cassandra_version.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/show/show_commands.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/show/show_host.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/show/show_login.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/show/show_params.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/show/show_processes.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/show/show_repairs.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/show/show_storage.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/watch.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/config.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/embedded_apps.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/log.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/pod_exec_result.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/repl.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/repl_session.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/repl_state.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/sql/__init__.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/sql/term_completer.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/sso/__init__.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/sso/authenticator.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/sso/authn_ad.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/sso/authn_okta.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/sso/cred_cache.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/sso/id_token.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/sso/idp.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/sso/idp_login.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/sso/idp_session.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/sso/sso_config.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_k8s/__init__.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_k8s/cassandra_clusters.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_k8s/cassandra_nodes.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_k8s/config_maps.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_k8s/custom_resources.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_k8s/deployment.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_k8s/ingresses.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_k8s/jobs.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_k8s/kube_context.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_k8s/pods.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_k8s/secrets.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_k8s/service_accounts.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_k8s/services.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_k8s/statefulsets.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_k8s/volumes.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_net.py +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/kaqing.egg-info/dependency_links.txt +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/kaqing.egg-info/entry_points.txt +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/kaqing.egg-info/top_level.txt +0 -0
- {kaqing-2.0.103 → kaqing-2.0.104}/setup.cfg +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
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
|
|
4
5
|
from adam.commands.command import Command
|
|
5
6
|
from adam.config import Config
|
|
6
7
|
from adam.repl_state import ReplState
|
|
@@ -64,7 +65,7 @@ class Audit(Command):
|
|
|
64
65
|
return {}
|
|
65
66
|
|
|
66
67
|
def cmd_list():
|
|
67
|
-
return [AuditRepairTables()]
|
|
68
|
+
return [AuditRepairTables(), AuditRun()]
|
|
68
69
|
|
|
69
70
|
def help(self, _: ReplState):
|
|
70
71
|
return f'[{Audit.COMMAND}] <sql-statements>\t run SQL queries on Authena audit database'
|
|
@@ -6,7 +6,7 @@ from adam.commands.command import Command
|
|
|
6
6
|
from adam.config import Config
|
|
7
7
|
from adam.repl_state import ReplState
|
|
8
8
|
from adam.utils import log, log2
|
|
9
|
-
from adam.utils_athena import audit_query, run_audit_query
|
|
9
|
+
from adam.utils_athena import AuditMeta, audit_query, get_meta, put_meta, run_audit_query
|
|
10
10
|
|
|
11
11
|
class AuditRepairTables(Command):
|
|
12
12
|
COMMAND = 'audit repair'
|
|
@@ -30,11 +30,12 @@ class AuditRepairTables(Command):
|
|
|
30
30
|
|
|
31
31
|
state, args = self.apply_state(args, state)
|
|
32
32
|
|
|
33
|
-
tables = Config().get('audit.tables', 'audit').split(',')
|
|
33
|
+
tables = Config().get('audit.athena.repair-partition-tables', 'audit').split(',')
|
|
34
34
|
if args:
|
|
35
35
|
tables = args
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
meta = get_meta()
|
|
38
|
+
self.repair(tables, meta)
|
|
38
39
|
|
|
39
40
|
return state
|
|
40
41
|
|
|
@@ -52,43 +53,20 @@ class AuditRepairTables(Command):
|
|
|
52
53
|
def auto_repair(self, hours: int):
|
|
53
54
|
self.auto_repaired = True
|
|
54
55
|
|
|
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):
|
|
56
|
+
meta = get_meta()
|
|
57
|
+
if meta.checked_in + hours * 60 * 60 < time.time():
|
|
58
|
+
tables = Config().get('audit.athena.repair-partition-tables', 'audit').split(',')
|
|
59
|
+
self.repair(tables, meta, show_sql=True)
|
|
60
|
+
log2(f'Audit tables have been auto-repaired.')
|
|
61
|
+
|
|
62
|
+
def repair(self, tables: list[str], meta: AuditMeta, show_sql = False):
|
|
71
63
|
with concurrent.futures.ThreadPoolExecutor(max_workers=Config().get('audit.workers', 3)) as executor:
|
|
72
64
|
for table in tables:
|
|
73
65
|
if show_sql:
|
|
74
66
|
log(f'MSCK REPAIR TABLE {table}')
|
|
75
67
|
|
|
76
68
|
executor.submit(run_audit_query, f'MSCK REPAIR TABLE {table}', None,)
|
|
77
|
-
executor.submit(
|
|
69
|
+
executor.submit(put_meta, 'check-in', meta,)
|
|
78
70
|
|
|
79
71
|
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}")
|
|
72
|
+
return f"{AuditRepairTables.COMMAND} \t run MSCK REPAIR command for new partition discovery"
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from adam.commands.command import Command
|
|
2
|
+
from adam.config import Config
|
|
3
|
+
from adam.repl_state import ReplState
|
|
4
|
+
from adam.utils import log2
|
|
5
|
+
from adam.utils_athena import AuditMeta, find_new_clusters, get_meta, put_meta, run_audit_query
|
|
6
|
+
|
|
7
|
+
class AuditRun(Command):
|
|
8
|
+
COMMAND = 'audit run'
|
|
9
|
+
|
|
10
|
+
# the singleton pattern
|
|
11
|
+
def __new__(cls, *args, **kwargs):
|
|
12
|
+
if not hasattr(cls, 'instance'): cls.instance = super(AuditRun, cls).__new__(cls)
|
|
13
|
+
|
|
14
|
+
return cls.instance
|
|
15
|
+
|
|
16
|
+
def __init__(self, successor: Command=None):
|
|
17
|
+
super().__init__(successor)
|
|
18
|
+
self.auto_repaired = False
|
|
19
|
+
|
|
20
|
+
def command(self):
|
|
21
|
+
return AuditRun.COMMAND
|
|
22
|
+
|
|
23
|
+
def run(self, cmd: str, state: ReplState):
|
|
24
|
+
if not(args := self.args(cmd)):
|
|
25
|
+
return super().run(cmd, state)
|
|
26
|
+
|
|
27
|
+
state, args = self.apply_state(args, state)
|
|
28
|
+
|
|
29
|
+
meta: AuditMeta = get_meta()
|
|
30
|
+
clusters = find_new_clusters(meta.cluster_last_checked)
|
|
31
|
+
if clusters:
|
|
32
|
+
put_meta('add-clusters', meta, clusters=clusters)
|
|
33
|
+
log2(f'Added {len(clusters)} new clusters.')
|
|
34
|
+
tables = Config().get('audit.athena.repair-cluster-tables', 'cluster').split(',')
|
|
35
|
+
for table in tables:
|
|
36
|
+
run_audit_query(f'MSCK REPAIR TABLE {table}')
|
|
37
|
+
else:
|
|
38
|
+
log2(f'No new clusters were found.')
|
|
39
|
+
|
|
40
|
+
return state
|
|
41
|
+
|
|
42
|
+
def completion(self, state: ReplState):
|
|
43
|
+
if state.device == ReplState.L:
|
|
44
|
+
return super().completion(state)
|
|
45
|
+
|
|
46
|
+
return {}
|
|
47
|
+
|
|
48
|
+
def help(self, _: ReplState):
|
|
49
|
+
return f"{AuditRun.COMMAND} \t run"
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
from adam.commands.command import Command
|
|
2
|
+
from adam.utils_k8s.cassandra_clusters import CassandraClusters
|
|
3
|
+
from adam.utils_k8s.cassandra_nodes import CassandraNodes
|
|
4
|
+
from adam.pod_exec_result import PodExecResult
|
|
5
|
+
from adam.repl_state import BashSession, ReplState, RequiredState
|
|
6
|
+
from adam.utils_repl.automata_completer import AutomataCompleter
|
|
7
|
+
from adam.utils_repl.state_machine import StateMachine
|
|
8
|
+
|
|
9
|
+
class Bash(Command):
|
|
10
|
+
COMMAND = 'bash'
|
|
11
|
+
|
|
12
|
+
# the singleton pattern
|
|
13
|
+
def __new__(cls, *args, **kwargs):
|
|
14
|
+
if not hasattr(cls, 'instance'): cls.instance = super(Bash, cls).__new__(cls)
|
|
15
|
+
|
|
16
|
+
return cls.instance
|
|
17
|
+
|
|
18
|
+
def __init__(self, successor: Command=None):
|
|
19
|
+
super().__init__(successor)
|
|
20
|
+
|
|
21
|
+
def command(self):
|
|
22
|
+
return Bash.COMMAND
|
|
23
|
+
|
|
24
|
+
def required(self):
|
|
25
|
+
return RequiredState.CLUSTER_OR_POD
|
|
26
|
+
|
|
27
|
+
def run(self, cmd: str, s0: ReplState):
|
|
28
|
+
if not(args := self.args(cmd)):
|
|
29
|
+
return super().run(cmd, s0)
|
|
30
|
+
|
|
31
|
+
state, args = self.apply_state(args, s0, args_to_check=2)
|
|
32
|
+
if not self.validate_state(state):
|
|
33
|
+
return state
|
|
34
|
+
|
|
35
|
+
if state.in_repl:
|
|
36
|
+
if s0.sts != state.sts or s0.pod != state.pod:
|
|
37
|
+
r = self.exec_with_dir(state, args)
|
|
38
|
+
else:
|
|
39
|
+
r = self.exec_with_dir(s0, args)
|
|
40
|
+
|
|
41
|
+
if not r:
|
|
42
|
+
state.exit_bash()
|
|
43
|
+
|
|
44
|
+
return 'inconsistent pwd'
|
|
45
|
+
|
|
46
|
+
return r
|
|
47
|
+
else:
|
|
48
|
+
command = ' '.join(args)
|
|
49
|
+
|
|
50
|
+
if state.pod:
|
|
51
|
+
CassandraNodes.exec(state.pod, state.namespace, command, show_out=True)
|
|
52
|
+
elif state.sts:
|
|
53
|
+
CassandraClusters.exec(state.sts, state.namespace, command, action='bash', show_out=True)
|
|
54
|
+
|
|
55
|
+
return state
|
|
56
|
+
|
|
57
|
+
def exec_with_dir(self, state: ReplState, args: list[str]) -> list[PodExecResult]:
|
|
58
|
+
session_just_created = False
|
|
59
|
+
if not args:
|
|
60
|
+
session_just_created = True
|
|
61
|
+
session = BashSession(state.device)
|
|
62
|
+
state.enter_bash(session)
|
|
63
|
+
|
|
64
|
+
if state.bash_session:
|
|
65
|
+
if args != ['pwd']:
|
|
66
|
+
if args:
|
|
67
|
+
args.append('&&')
|
|
68
|
+
args.extend(['pwd', '>', f'/tmp/.qing-{state.bash_session.session_id}'])
|
|
69
|
+
|
|
70
|
+
if not session_just_created:
|
|
71
|
+
if pwd := state.bash_session.pwd(state):
|
|
72
|
+
args = ['cd', pwd, '&&'] + args
|
|
73
|
+
|
|
74
|
+
command = ' '.join(args)
|
|
75
|
+
|
|
76
|
+
rs = []
|
|
77
|
+
|
|
78
|
+
if state.pod:
|
|
79
|
+
rs = [CassandraNodes.exec(state.pod, state.namespace, command,
|
|
80
|
+
show_out=not session_just_created, shell='bash')]
|
|
81
|
+
elif state.sts:
|
|
82
|
+
rs = CassandraClusters.exec(state.sts, state.namespace, command, action='bash',
|
|
83
|
+
show_out=not session_just_created, shell='bash')
|
|
84
|
+
|
|
85
|
+
return rs
|
|
86
|
+
|
|
87
|
+
def completion(self, state: ReplState):
|
|
88
|
+
if state.pod or state.sts:
|
|
89
|
+
return {Bash.COMMAND: AutomataCompleter(BashStateMachine())}
|
|
90
|
+
|
|
91
|
+
return {}
|
|
92
|
+
|
|
93
|
+
def help(self, _: ReplState):
|
|
94
|
+
return f'{Bash.COMMAND} [bash-commands]\t run bash on the Cassandra nodes'
|
|
95
|
+
|
|
96
|
+
BASH_SPEC = [
|
|
97
|
+
# <command> ::= <simple_command> | <pipeline> | <conditional_command>
|
|
98
|
+
# <simple_command> ::= <word> <argument>* <redirection>*
|
|
99
|
+
# <pipeline> ::= <command> '|' <command>
|
|
100
|
+
# <conditional_command> ::= <command> '&&' <command> | <command> '||' <command>
|
|
101
|
+
# <word> ::= <letter> <letter_or_digit>*
|
|
102
|
+
# <argument> ::= <word>
|
|
103
|
+
# <redirection> ::= '>' <filename> | '<' <filename>
|
|
104
|
+
# <filename> ::= <word>
|
|
105
|
+
# <letter> ::= 'a' | 'b' | ... | 'z' | 'A' | 'B' | ... | 'Z'
|
|
106
|
+
# <digit> ::= '0' | '1' | ... | '9'
|
|
107
|
+
# <letter_or_digit> ::= <letter> | <digit>
|
|
108
|
+
|
|
109
|
+
' > word > word',
|
|
110
|
+
'word > word > word ^ |,>,2>,<,&,&&,||',
|
|
111
|
+
'- > pipe > word_pipe',
|
|
112
|
+
'- > _rdr0_ > word_rdr0',
|
|
113
|
+
'- > _rdr1_ > word_rdr1',
|
|
114
|
+
'- > _rdr2_ > word_rdr2',
|
|
115
|
+
'- > & > word_bg ^ |,>,2>,<,&,&&,||',
|
|
116
|
+
'- > &&|_or_ > word',
|
|
117
|
+
'word_a > word > word',
|
|
118
|
+
'word_pipe > word > word',
|
|
119
|
+
'word_rdr0 > word > word_rdr0_f',
|
|
120
|
+
'word_rdr1 > word > word_rdr1_f',
|
|
121
|
+
'word_rdr2 > word > word_rdr2_f',
|
|
122
|
+
'word_rdr1_f > pipe > word_pipe ^ |,2>,<,&,&&,||',
|
|
123
|
+
'- > _rdr2_ > word_rdr2',
|
|
124
|
+
'- > _rdr0_ > word_rdr0',
|
|
125
|
+
'word_rdr2_f > pipe > word_pipe ^ |,<,&,&&,||',
|
|
126
|
+
'- > _rdr0_ > word_rdr0',
|
|
127
|
+
'- > & > word_bg ^ |,>,2>,<,&,&&,||',
|
|
128
|
+
'- > &&|_or_ > word',
|
|
129
|
+
'word_rdr0_f > pipe > word_pipe ^ |,&,&&,||',
|
|
130
|
+
'- > & > word_bg ^ |,>,2>,<,&,&&,||',
|
|
131
|
+
'- > &&|_or_ > word',
|
|
132
|
+
'word_bg > &&|_or_ > ^ &&,||',
|
|
133
|
+
]
|
|
134
|
+
|
|
135
|
+
BASH_KEYWORDS = [
|
|
136
|
+
'&',
|
|
137
|
+
'&&',
|
|
138
|
+
'|',
|
|
139
|
+
'||',
|
|
140
|
+
'>',
|
|
141
|
+
'2>',
|
|
142
|
+
'>>',
|
|
143
|
+
'<'
|
|
144
|
+
]
|
|
145
|
+
class BashStateMachine(StateMachine[str]):
|
|
146
|
+
def spec(self) -> str:
|
|
147
|
+
return BASH_SPEC
|
|
148
|
+
|
|
149
|
+
def keywords(self) -> list[str]:
|
|
150
|
+
return BASH_KEYWORDS
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
def config():
|
|
2
|
+
return {'app': {'console-endpoint': 'https://{host}/{env}/{app}/static/console/index.html', 'cr': {'cluster-regex': '(.*?-.*?)-.*', 'group': 'ops.c3.ai', 'v': 'v2', 'plural': 'c3cassandras'}, 'label': 'c3__app_id-0', 'login': {'admin-group': '{host}/C3.ClusterAdmin', 'ingress': '{app_id}-k8singr-appleader-001', 'timeout': 5, 'session-check-url': 'https://{host}/{env}/{app}/api/8/C3/userSessionToken', 'cache-creds': True, 'cache-username': True, 'url': 'https://{host}/{env}/{app}', 'another': "You're logged in to {has}. However, for this app, you need to log in to {need}.", 'token-server-url': 'http://localhost:{port}', 'password-max-length': 128}, 'strip': '0'}, 'audit': {'endpoint': 'https://4psvtaxlcb.execute-api.us-west-2.amazonaws.com/prod/', 'workers': 3, 'timeout': 10, 'log-audit-queries': False, 'athena': {'auto-repair': {'elapsed_hours': 12}, 'region': 'us-west-2', 'catalog': 'AwsDataCatalog', 'database': 'audit', 'repair-partition-tables': 'audit', 'output': 's3://s3.ops--audit/ddl/results', 'repair-cluster-tables': 'audit'}}, 'bash': {'workers': 32}, 'cassandra': {'service-name': 'all-pods-service'}, 'cql': {'workers': 32, 'samples': 3, 'secret': {'cluster-regex': '(.*?-.*?)-.*', 'name': '{cluster}-superuser', 'password-item': 'password'}, 'alter-tables': {'excludes': 'system_auth,system_traces,reaper_db,system_distributed,system_views,system,system_schema,system_virtual_schema', 'gc-grace-periods': '3600,86400,864000,7776000', 'batching': True}}, 'checks': {'compactions-threshold': 250, 'cpu-busy-threshold': 98.0, 'cpu-threshold': 0.0, 'cassandra-data-path': '/c3/cassandra', 'root-disk-threshold': 50, 'cassandra-disk-threshold': 50, 'snapshot-size-cmd': "ls /c3/cassandra/data/data/*/*/snapshots | grep snapshots | sed 's/:$//g' | xargs -I {} du -sk {} | awk '{print $1}' | awk '{s+=$1} END {print s}'", 'snapshot-size-threshold': '40G', 'table-sizes-cmd': "ls -Al /c3/cassandra/data/data/ | awk '{print $9}' | sed 's/\\^r//g' | xargs -I {} du -sk /c3/cassandra/data/data/{}"}, 'get-host-id': {'workers': 32}, 'idps': {'ad': {'email-pattern': '.*@c3.ai', 'uri': 'https://login.microsoftonline.com/53ad779a-93e7-485c-ba20-ac8290d7252b/oauth2/v2.0/authorize?response_type=id_token&response_mode=form_post&client_id=00ff94a8-6b0a-4715-98e0-95490012d818&scope=openid+email+profile&redirect_uri=https%3A%2F%2Fplat.c3ci.cloud%2Fc3%2Fc3%2Foidc%2Flogin&nonce={nonce}&state=EMPTY', 'jwks-uri': 'https://login.microsoftonline.com/common/discovery/keys', 'contact': 'Please contact ted.tran@c3.ai.', 'whitelist-file': '/kaqing/members'}, 'okta': {'default': True, 'email-pattern': '.*@c3iot.com', 'uri': 'https://c3energy.okta.com/oauth2/v1/authorize?response_type=id_token&response_mode=form_post&client_id={client_id}&scope=openid+email+profile+groups&redirect_uri=https%3A%2F%2F{host}%2Fc3%2Fc3%2Foidc%2Flogin&nonce={nonce}&state=EMPTY', 'jwks-uri': 'https://c3energy.okta.com/oauth2/v1/keys'}}, 'issues': {'workers': 32}, 'logs': {'path': '/c3/cassandra/logs/system.log'}, 'medusa': {'restore-auto-complete': False}, 'nodetool': {'workers': 32, 'samples': 3, 'commands_in_line': 40}, 'pg': {'name-pattern': '^{namespace}.*-k8spg-.*', 'excludes': '.helm., -admin-secret', 'agent': {'name': 'ops-pg-agent', 'just-in-time': False, 'timeout': 86400, 'image': 'seanahnsf/kaqing'}, 'default-db': 'postgres', 'default-schema': 'postgres', 'secret': {'endpoint-key': 'postgres-db-endpoint', 'port-key': 'postgres-db-port', 'username-key': 'postgres-admin-username', 'password-key': 'postgres-admin-password'}}, 'pod': {'name': 'ops', 'image': 'seanahnsf/kaqing-cloud', 'sa': {'name': 'ops', 'proto': 'c3', 'additional-cluster-roles': 'c3aiops-k8ssandra-operator'}, 'label-selector': 'run=ops'}, 'preview': {'rows': 10}, 'processes': {'columns': 'pod,cpu,mem', 'header': 'POD_NAME,CPU,MEM/LIMIT'}, 'reaper': {'service-name': 'reaper-service', 'port-forward': {'timeout': 86400, 'local-port': 9001}, 'abort-runs-batch': 10, 'show-runs-batch': 100, 'pod': {'cluster-regex': '(.*?-.*?-.*?-.*?)-.*', 'label-selector': 'k8ssandra.io/reaper={cluster}-reaper'}, 'secret': {'cluster-regex': '(.*?-.*?)-.*', 'name': '{cluster}-reaper-ui', 'password-item': 'password'}}, 'repair': {'log-path': '/home/cassrepair/logs/', 'image': 'ci-registry.c3iot.io/cloudops/cassrepair:2.0.14', 'secret': 'ciregistryc3iotio', 'env': {'interval': 24, 'timeout': 60, 'pr': False, 'runs': 1}}, 'repl': {'start-drive': 'a', 'a': {'auto-enter': 'c3/c3'}, 'c': {'auto-enter': 'cluster'}, 'history': {'push-cat-remote-log-file': True}, 'background-process': {'auto-nohup': True}}, 'status': {'columns': 'status,address,load,tokens,owns,host_id,gossip,compactions', 'header': '--,Address,Load,Tokens,Owns,Host ID,GOSSIP,COMPACTIONS'}, 'storage': {'columns': 'pod,volume_root,volume_cassandra,snapshots,data,compactions', 'header': 'POD_NAME,VOLUME /,VOLUME CASS,SNAPSHOTS,DATA,COMPACTIONS'}, 'watch': {'auto': 'rollout', 'timeout': 3600, 'interval': 10}, 'debug': False, 'debugs': {'timings': False, 'exit-on-error': False, 'show-parallelism': False}}
|
|
@@ -3,6 +3,7 @@ from adam.commands.app import App
|
|
|
3
3
|
from adam.commands.app_ping import AppPing
|
|
4
4
|
from adam.commands.audit.audit import Audit
|
|
5
5
|
from adam.commands.audit.audit_repair_tables import AuditRepairTables
|
|
6
|
+
from adam.commands.audit.audit_run import AuditRun
|
|
6
7
|
from adam.commands.deploy.code_start import CodeStart
|
|
7
8
|
from adam.commands.deploy.code_stop import CodeStop
|
|
8
9
|
from adam.commands.deploy.deploy import Deploy
|
|
@@ -85,7 +86,7 @@ class ReplCommands:
|
|
|
85
86
|
|
|
86
87
|
def tools() -> list[Command]:
|
|
87
88
|
return [Cqlsh(), Postgres(), Bash(), Shell(), CodeStart(), CodeStop(), DeployFrontend(), UndeployFrontend(),
|
|
88
|
-
DeployPod(), UndeployPod(), DeployPgAgent(), UndeployPgAgent(), AuditRepairTables(), Audit()]
|
|
89
|
+
DeployPod(), UndeployPod(), DeployPgAgent(), UndeployPgAgent(), AuditRepairTables(), AuditRun(), Audit()]
|
|
89
90
|
|
|
90
91
|
def app() -> list[Command]:
|
|
91
92
|
return [ShowAppActions(), ShowAppId(), ShowAppQueues(), AppPing(), App()]
|
|
@@ -1,16 +1,33 @@
|
|
|
1
1
|
from typing import Callable
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import sqlparse
|
|
4
|
+
from sqlparse.sql import Statement, Token
|
|
5
|
+
|
|
6
|
+
from adam.sql.term_completer import TermCompleter
|
|
7
|
+
from adam.utils_repl.automata_completer import AutomataCompleter
|
|
4
8
|
from adam.sql.sql_state_machine import AthenaStateMachine, CqlStateMachine, SqlStateMachine
|
|
9
|
+
from adam.utils_repl.state_machine import State
|
|
5
10
|
|
|
6
11
|
__all__ = [
|
|
7
12
|
"SqlCompleter",
|
|
8
13
|
]
|
|
9
14
|
|
|
10
|
-
def default_columns(
|
|
15
|
+
def default_columns(_: list[str]):
|
|
11
16
|
return 'id,x.,y.,z.'.split(',')
|
|
12
17
|
|
|
13
|
-
class SqlCompleter(AutomataCompleter):
|
|
18
|
+
class SqlCompleter(AutomataCompleter[Token]):
|
|
19
|
+
def tokens(self, text: str) -> list[Token]:
|
|
20
|
+
tokens = []
|
|
21
|
+
|
|
22
|
+
stmts = sqlparse.parse(text)
|
|
23
|
+
if not stmts:
|
|
24
|
+
tokens = []
|
|
25
|
+
else:
|
|
26
|
+
statement: Statement = stmts[0]
|
|
27
|
+
tokens = statement.tokens
|
|
28
|
+
|
|
29
|
+
return tokens
|
|
30
|
+
|
|
14
31
|
def __init__(self,
|
|
15
32
|
tables: Callable[[], list[str]],
|
|
16
33
|
dml: str = None,
|
|
@@ -33,7 +50,17 @@ class SqlCompleter(AutomataCompleter):
|
|
|
33
50
|
self.variant = variant
|
|
34
51
|
self.debug = debug
|
|
35
52
|
|
|
36
|
-
def
|
|
53
|
+
def suggestions_completer(self, state: State, suggestions: str) -> list[str]:
|
|
54
|
+
if not suggestions:
|
|
55
|
+
return None
|
|
56
|
+
|
|
57
|
+
terms = []
|
|
58
|
+
for suggestion in suggestions.split(','):
|
|
59
|
+
terms.extend(self._terms(state, suggestion))
|
|
60
|
+
|
|
61
|
+
return TermCompleter(terms)
|
|
62
|
+
|
|
63
|
+
def _terms(self, state: State, word: str) -> list[str]:
|
|
37
64
|
terms = []
|
|
38
65
|
|
|
39
66
|
if word == 'tables':
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
from
|
|
1
|
+
from typing import Callable
|
|
2
|
+
from sqlparse.sql import Token
|
|
3
|
+
from sqlparse import tokens as TOKEN
|
|
4
|
+
|
|
5
|
+
from adam.utils_repl.state_machine import StateMachine, State
|
|
2
6
|
|
|
3
7
|
__all__ = [
|
|
4
8
|
'SqlStateMachine', 'CqlStateMachine', 'AthenaStateMachine'
|
|
@@ -70,7 +74,7 @@ SQL_SPEC = [
|
|
|
70
74
|
'select_from_lp_ > select > select',
|
|
71
75
|
'select_from_x > , > select_from_x_comma_ ^ (select,tables',
|
|
72
76
|
'select_from_sq_ > as > select_from_x_as ^ as',
|
|
73
|
-
'select_from_x_comma_ > name
|
|
77
|
+
'select_from_x_comma_ > name|audit > select_from_x ^ tables',
|
|
74
78
|
'select_from_x_ ^ as,where,inner join,left outer join,right outer join,full outer join,group by,order by,limit',
|
|
75
79
|
'select_from_x_as_x_ > , > select_from_x_comma_ ^ where,inner join,left outer join,right outer join,full outer join,group by,order by,limit',
|
|
76
80
|
'- > as > select_from_x_as',
|
|
@@ -92,7 +96,7 @@ SQL_SPEC = [
|
|
|
92
96
|
'- > full outer join > select_join',
|
|
93
97
|
'select_from_x_as_ > name > select_from_x_as_x ^ x,y,z',
|
|
94
98
|
'select_from_x_as_x > , > select_from_x_as_x_comma_',
|
|
95
|
-
'select_from_x_as_x_comma_ > name
|
|
99
|
+
'select_from_x_as_x_comma_ > name|audit > select_from_x ^ tables',
|
|
96
100
|
'select_where_ > name > select_where_a ^ columns',
|
|
97
101
|
'select_where_a > name > select_where_a ^ columns,=,<,<=,>,>=,<>',
|
|
98
102
|
'- > comparison > select_where_a_op',
|
|
@@ -134,7 +138,7 @@ SQL_SPEC = [
|
|
|
134
138
|
'select_where_sc_limit_ > num > select_where_sc_limit_num ^ 1',
|
|
135
139
|
'select_where_sc_limit_num_rp__ > as > select_from_x_as ^ as',
|
|
136
140
|
'select_where_x_inner_ > join > select_join',
|
|
137
|
-
'select_join_ > name
|
|
141
|
+
'select_join_ > name|audit > select_x_join_y ^ tables',
|
|
138
142
|
'select_from_x_left_ > join > select_join ^ outer join',
|
|
139
143
|
'- > outer > select_from_x_left_outer',
|
|
140
144
|
'select_from_x_left_outer_ > join > select_join ^ join',
|
|
@@ -171,7 +175,7 @@ SQL_SPEC = [
|
|
|
171
175
|
# <query_expression> ::= SELECT <select_list> FROM <table_reference_list> [ WHERE <search_condition> ] [ GROUP BY <grouping_column_list> ] [ HAVING <search_condition> ] [ ORDER BY <sort_specification_list> ]
|
|
172
176
|
' > insert > insert',
|
|
173
177
|
'insert_ > into > insert_into ^ into',
|
|
174
|
-
'insert_into_ > name
|
|
178
|
+
'insert_into_ > name|audit > insert_into_x ^ tables',
|
|
175
179
|
'insert_into_x > ( > insert_into_x_lp_',
|
|
176
180
|
'insert_into_x_ > ( > insert_into_x_lp_ ^ (,values(',
|
|
177
181
|
'- > values > insert_values',
|
|
@@ -198,7 +202,7 @@ SQL_SPEC = [
|
|
|
198
202
|
|
|
199
203
|
# <search_condition> ::= <boolean_expression>
|
|
200
204
|
' > update > update',
|
|
201
|
-
'update_ > name
|
|
205
|
+
'update_ > name|audit > update_x ^ tables',
|
|
202
206
|
'update_x_ > set > update_set ^ set',
|
|
203
207
|
'update_set_ > name > update_set_a ^ id',
|
|
204
208
|
'update_set_a > comparison > update_set_a_op',
|
|
@@ -267,7 +271,7 @@ SQL_SPEC = [
|
|
|
267
271
|
# <expression_list> ::= <expression> { , <expression> }...
|
|
268
272
|
' > delete > delete',
|
|
269
273
|
'delete_ > from > delete_from ^ from',
|
|
270
|
-
'delete_from_ > name
|
|
274
|
+
'delete_from_ > name|audit > delete_from_x ^ tables',
|
|
271
275
|
'delete_from_x_ > where > update_where ^ where',
|
|
272
276
|
|
|
273
277
|
# <alter table action> ::=
|
|
@@ -381,10 +385,90 @@ ATHENA_KEYWORDS = SQL_KEYWORDS + [
|
|
|
381
385
|
'partition'
|
|
382
386
|
]
|
|
383
387
|
|
|
384
|
-
class SqlStateMachine(StateMachine):
|
|
388
|
+
class SqlStateMachine(StateMachine[Token]):
|
|
385
389
|
def __init__(self, indent=0, push_level = 0, debug = False):
|
|
386
390
|
super().__init__(indent, push_level, debug)
|
|
387
391
|
|
|
392
|
+
def traverse_tokens(self, tokens: list[Token], state: State = State('')):
|
|
393
|
+
def handle_push():
|
|
394
|
+
if f'{state.state} > {it}' in self.states:
|
|
395
|
+
state_test = self.states[f'{state.state} > {it}']
|
|
396
|
+
if state_test.comeback_token:
|
|
397
|
+
self.comebacks[self.push_level] = state_test.comeback_state
|
|
398
|
+
|
|
399
|
+
def handle_pop():
|
|
400
|
+
if self.push_level in self.comebacks:
|
|
401
|
+
try:
|
|
402
|
+
return State(self.comebacks[self.push_level])
|
|
403
|
+
finally:
|
|
404
|
+
del self.comebacks[self.push_level]
|
|
405
|
+
|
|
406
|
+
return None
|
|
407
|
+
|
|
408
|
+
for token in tokens:
|
|
409
|
+
if self.debug:
|
|
410
|
+
if token.ttype == TOKEN.Whitespace:
|
|
411
|
+
print('_ ', end='')
|
|
412
|
+
elif token.ttype in [TOKEN.DML, TOKEN.Wildcard, TOKEN.Punctuation, TOKEN.CTE]:
|
|
413
|
+
print(f'{token.value} ', end='')
|
|
414
|
+
elif token.ttype:
|
|
415
|
+
tks = str(token.ttype).split('.')
|
|
416
|
+
typ = tks[len(tks) - 1]
|
|
417
|
+
if ' ' in token.value:
|
|
418
|
+
print(f'"{token.value}:{typ}" ', end='')
|
|
419
|
+
else:
|
|
420
|
+
print(f'{token.value}:{typ} ', end='')
|
|
421
|
+
# print(" " * self.indent + f"Token: {token.value}, Type: {token.ttype}@{token.ttype.__class__}")
|
|
422
|
+
|
|
423
|
+
last_name = None
|
|
424
|
+
if token.is_group:
|
|
425
|
+
state = self.traverse_tokens(token.tokens, state)
|
|
426
|
+
else:
|
|
427
|
+
comeback_state = None
|
|
428
|
+
|
|
429
|
+
it = ''
|
|
430
|
+
if (t := token.value.lower()) in self.keywords():
|
|
431
|
+
it = t
|
|
432
|
+
elif token.ttype == TOKEN.Text.Whitespace:
|
|
433
|
+
it = '_'
|
|
434
|
+
elif token.ttype == TOKEN.Name:
|
|
435
|
+
it = 'name'
|
|
436
|
+
last_name = token.value
|
|
437
|
+
elif token.ttype == TOKEN.Literal.String.Single:
|
|
438
|
+
it = 'single'
|
|
439
|
+
elif token.ttype in [TOKEN.Literal.Number.Integer, TOKEN.Literal.Number.Float]:
|
|
440
|
+
it = 'num'
|
|
441
|
+
elif token.ttype == TOKEN.Wildcard:
|
|
442
|
+
it = '*'
|
|
443
|
+
elif token.ttype == TOKEN.Punctuation:
|
|
444
|
+
it = token.value
|
|
445
|
+
|
|
446
|
+
if it == '(':
|
|
447
|
+
handle_push()
|
|
448
|
+
self.push_level += 1
|
|
449
|
+
elif it == ')':
|
|
450
|
+
self.push_level -= 1
|
|
451
|
+
comeback_state = handle_pop()
|
|
452
|
+
|
|
453
|
+
elif token.ttype == TOKEN.Operator.Comparison:
|
|
454
|
+
it = 'comparison'
|
|
455
|
+
|
|
456
|
+
try:
|
|
457
|
+
# print(f'\n{state.to_s} > {it} > ', end='')
|
|
458
|
+
if comeback_state:
|
|
459
|
+
state = comeback_state
|
|
460
|
+
else:
|
|
461
|
+
context = state.context
|
|
462
|
+
state = self.states[f'{state.state} > {it}']
|
|
463
|
+
state.context = context
|
|
464
|
+
|
|
465
|
+
if last_name:
|
|
466
|
+
state.context['last_name'] = last_name
|
|
467
|
+
except:
|
|
468
|
+
pass
|
|
469
|
+
|
|
470
|
+
return state
|
|
471
|
+
|
|
388
472
|
def spec(self):
|
|
389
473
|
return SQL_SPEC
|
|
390
474
|
|
|
@@ -1,10 +1,77 @@
|
|
|
1
|
+
from datetime import datetime
|
|
1
2
|
import functools
|
|
2
3
|
import time
|
|
3
4
|
import boto3
|
|
5
|
+
import requests
|
|
4
6
|
|
|
5
7
|
from adam.config import Config
|
|
6
8
|
from adam.utils import lines_to_tabular, log, log2
|
|
7
9
|
|
|
10
|
+
class AuditMeta:
|
|
11
|
+
def __init__(self, checked_in: float, cluster_last_checked: float):
|
|
12
|
+
self.checked_in = checked_in
|
|
13
|
+
self.cluster_last_checked = cluster_last_checked
|
|
14
|
+
|
|
15
|
+
def get_meta() -> AuditMeta:
|
|
16
|
+
checked_in = 0.0
|
|
17
|
+
cluster_last_checked = 0.0
|
|
18
|
+
|
|
19
|
+
state, _, rs = audit_query(f'select partitions_last_checked, clusters_last_checked from meta')
|
|
20
|
+
if state == 'SUCCEEDED':
|
|
21
|
+
if len(rs) > 1:
|
|
22
|
+
try:
|
|
23
|
+
row = rs[1]['Data']
|
|
24
|
+
checked_in = float(row[0]['VarCharValue'])
|
|
25
|
+
cluster_last_checked = float(row[1]['VarCharValue'])
|
|
26
|
+
except:
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
return AuditMeta(checked_in, cluster_last_checked)
|
|
30
|
+
|
|
31
|
+
def find_new_clusters(cluster_last_checked: float) -> list[str]:
|
|
32
|
+
dt_object = datetime.fromtimestamp(cluster_last_checked)
|
|
33
|
+
|
|
34
|
+
y = dt_object.strftime("%Y")
|
|
35
|
+
m = dt_object.strftime("%m")
|
|
36
|
+
d = dt_object.strftime("%d")
|
|
37
|
+
# select distinct c2.name from cluster as c1 right outer join
|
|
38
|
+
# (select distinct c as name from audit where y = '1969' and m = '12' and d >= '31' or y = '1969' and m > '12' or y > '1969') as c2
|
|
39
|
+
# on c1.name = c2.name where c1.name is null
|
|
40
|
+
where = f"y = '{y}' and m = '{m}' and d >= '{d}' or y = '{y}' and m > '{m}' or y > '{y}'"
|
|
41
|
+
query = '\n '.join([
|
|
42
|
+
'select distinct c2.name from cluster as c1 right outer join',
|
|
43
|
+
f'(select distinct c as name from audit where {where}) as c2',
|
|
44
|
+
'on c1.name = c2.name where c1.name is null'])
|
|
45
|
+
log2(query)
|
|
46
|
+
state, _, rs = audit_query(query)
|
|
47
|
+
if state == 'SUCCEEDED':
|
|
48
|
+
if len(rs) > 1:
|
|
49
|
+
try:
|
|
50
|
+
return [r['Data'][0]['VarCharValue'] for r in rs[1:]]
|
|
51
|
+
except:
|
|
52
|
+
pass
|
|
53
|
+
|
|
54
|
+
return []
|
|
55
|
+
|
|
56
|
+
def put_meta(action: str, meta: AuditMeta, clusters: list[str] = None):
|
|
57
|
+
payload = {
|
|
58
|
+
'action': action,
|
|
59
|
+
'partitions-last-checked': meta.checked_in,
|
|
60
|
+
'clusters-last-checked': meta.cluster_last_checked
|
|
61
|
+
}
|
|
62
|
+
if clusters:
|
|
63
|
+
payload['clusters'] = clusters
|
|
64
|
+
|
|
65
|
+
audit_endpoint = Config().get("audit.endpoint", "https://4psvtaxlcb.execute-api.us-west-2.amazonaws.com/prod/")
|
|
66
|
+
try:
|
|
67
|
+
response = requests.post(audit_endpoint, json=payload, timeout=Config().get("audit.timeout", 10))
|
|
68
|
+
if response.status_code in [200, 201]:
|
|
69
|
+
Config().debug(response.text)
|
|
70
|
+
else:
|
|
71
|
+
log2(f"Error: {response.status_code} {response.text}")
|
|
72
|
+
except requests.exceptions.Timeout as e:
|
|
73
|
+
log2(f"Timeout occurred: {e}")
|
|
74
|
+
|
|
8
75
|
@functools.lru_cache()
|
|
9
76
|
def audit_table_names():
|
|
10
77
|
region_name = Config().get('audit.athena.region', 'us-west-2')
|
|
@@ -50,7 +117,7 @@ def run_audit_query(sql: str, database: str = None):
|
|
|
50
117
|
columns = [col.get('VarCharValue') for col in column_info]
|
|
51
118
|
lines = []
|
|
52
119
|
for row in rs[1:]:
|
|
53
|
-
row_data = [col.get('VarCharValue') for col in row['Data']]
|
|
120
|
+
row_data = [col.get('VarCharValue') if col else '' for col in row['Data']]
|
|
54
121
|
lines.append('\t'.join(row_data))
|
|
55
122
|
|
|
56
123
|
log(lines_to_tabular(lines, header='\t'.join(columns), separator='\t'))
|