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.

Files changed (192) hide show
  1. {kaqing-2.0.103 → kaqing-2.0.104}/PKG-INFO +1 -1
  2. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/audit/audit.py +2 -1
  3. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/audit/audit_repair_tables.py +13 -35
  4. kaqing-2.0.104/adam/commands/audit/audit_run.py +49 -0
  5. kaqing-2.0.104/adam/commands/bash.py +150 -0
  6. kaqing-2.0.104/adam/embedded_params.py +2 -0
  7. {kaqing-2.0.103 → kaqing-2.0.104}/adam/repl_commands.py +2 -1
  8. {kaqing-2.0.103 → kaqing-2.0.104}/adam/sql/sql_completer.py +31 -4
  9. {kaqing-2.0.103 → kaqing-2.0.104}/adam/sql/sql_state_machine.py +92 -8
  10. {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_athena.py +68 -1
  11. kaqing-2.0.104/adam/version.py +5 -0
  12. {kaqing-2.0.103 → kaqing-2.0.104}/kaqing.egg-info/PKG-INFO +1 -1
  13. {kaqing-2.0.103 → kaqing-2.0.104}/kaqing.egg-info/SOURCES.txt +1 -2
  14. {kaqing-2.0.103 → kaqing-2.0.104}/setup.py +1 -1
  15. kaqing-2.0.103/adam/commands/bash.py +0 -92
  16. kaqing-2.0.103/adam/embedded_params.py +0 -2
  17. kaqing-2.0.103/adam/sql/automata_completer.py +0 -63
  18. kaqing-2.0.103/adam/sql/state_machine.py +0 -207
  19. kaqing-2.0.103/adam/version.py +0 -5
  20. {kaqing-2.0.103 → kaqing-2.0.104}/README +0 -0
  21. {kaqing-2.0.103 → kaqing-2.0.104}/adam/__init__.py +0 -0
  22. {kaqing-2.0.103 → kaqing-2.0.104}/adam/app_session.py +0 -0
  23. {kaqing-2.0.103 → kaqing-2.0.104}/adam/apps.py +0 -0
  24. {kaqing-2.0.103 → kaqing-2.0.104}/adam/batch.py +0 -0
  25. {kaqing-2.0.103 → kaqing-2.0.104}/adam/checks/__init__.py +0 -0
  26. {kaqing-2.0.103 → kaqing-2.0.104}/adam/checks/check.py +0 -0
  27. {kaqing-2.0.103 → kaqing-2.0.104}/adam/checks/check_context.py +0 -0
  28. {kaqing-2.0.103 → kaqing-2.0.104}/adam/checks/check_result.py +0 -0
  29. {kaqing-2.0.103 → kaqing-2.0.104}/adam/checks/check_utils.py +0 -0
  30. {kaqing-2.0.103 → kaqing-2.0.104}/adam/checks/compactionstats.py +0 -0
  31. {kaqing-2.0.103 → kaqing-2.0.104}/adam/checks/cpu.py +0 -0
  32. {kaqing-2.0.103 → kaqing-2.0.104}/adam/checks/disk.py +0 -0
  33. {kaqing-2.0.103 → kaqing-2.0.104}/adam/checks/gossip.py +0 -0
  34. {kaqing-2.0.103 → kaqing-2.0.104}/adam/checks/issue.py +0 -0
  35. {kaqing-2.0.103 → kaqing-2.0.104}/adam/checks/memory.py +0 -0
  36. {kaqing-2.0.103 → kaqing-2.0.104}/adam/checks/status.py +0 -0
  37. {kaqing-2.0.103 → kaqing-2.0.104}/adam/cli.py +0 -0
  38. {kaqing-2.0.103 → kaqing-2.0.104}/adam/cli_group.py +0 -0
  39. {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/__init__.py +0 -0
  40. {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/column.py +0 -0
  41. {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/columns.py +0 -0
  42. {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/compactions.py +0 -0
  43. {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/cpu.py +0 -0
  44. {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/dir_data.py +0 -0
  45. {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/dir_snapshots.py +0 -0
  46. {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/gossip.py +0 -0
  47. {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/host_id.py +0 -0
  48. {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/memory.py +0 -0
  49. {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/node_address.py +0 -0
  50. {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/node_load.py +0 -0
  51. {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/node_owns.py +0 -0
  52. {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/node_status.py +0 -0
  53. {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/node_tokens.py +0 -0
  54. {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/node_utils.py +0 -0
  55. {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/pod_name.py +0 -0
  56. {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/volume_cassandra.py +0 -0
  57. {kaqing-2.0.103 → kaqing-2.0.104}/adam/columns/volume_root.py +0 -0
  58. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/__init__.py +0 -0
  59. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/alter_tables.py +0 -0
  60. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/app.py +0 -0
  61. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/app_ping.py +0 -0
  62. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/audit/__init__.py +0 -0
  63. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/cd.py +0 -0
  64. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/check.py +0 -0
  65. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/cli_commands.py +0 -0
  66. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/command.py +0 -0
  67. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/command_helpers.py +0 -0
  68. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/commands_utils.py +0 -0
  69. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/cp.py +0 -0
  70. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/cql/__init__.py +0 -0
  71. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/cql/cql_completions.py +0 -0
  72. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/cql/cql_utils.py +0 -0
  73. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/cql/cqlsh.py +0 -0
  74. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/deploy/__init__.py +0 -0
  75. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/deploy/code_start.py +0 -0
  76. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/deploy/code_stop.py +0 -0
  77. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/deploy/code_utils.py +0 -0
  78. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/deploy/deploy.py +0 -0
  79. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/deploy/deploy_frontend.py +0 -0
  80. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/deploy/deploy_pg_agent.py +0 -0
  81. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/deploy/deploy_pod.py +0 -0
  82. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/deploy/deploy_utils.py +0 -0
  83. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/deploy/undeploy.py +0 -0
  84. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/deploy/undeploy_frontend.py +0 -0
  85. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/deploy/undeploy_pg_agent.py +0 -0
  86. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/deploy/undeploy_pod.py +0 -0
  87. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/devices.py +0 -0
  88. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/exit.py +0 -0
  89. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/help.py +0 -0
  90. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/issues.py +0 -0
  91. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/login.py +0 -0
  92. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/logs.py +0 -0
  93. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/ls.py +0 -0
  94. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/medusa/__init__.py +0 -0
  95. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/medusa/medusa.py +0 -0
  96. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/medusa/medusa_backup.py +0 -0
  97. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/medusa/medusa_restore.py +0 -0
  98. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/medusa/medusa_show_backupjobs.py +0 -0
  99. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/medusa/medusa_show_restorejobs.py +0 -0
  100. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/nodetool.py +0 -0
  101. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/nodetool_commands.py +0 -0
  102. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/param_get.py +0 -0
  103. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/param_set.py +0 -0
  104. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/postgres/__init__.py +0 -0
  105. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/postgres/postgres.py +0 -0
  106. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/postgres/postgres_context.py +0 -0
  107. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/postgres/postgres_ls.py +0 -0
  108. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/postgres/postgres_preview.py +0 -0
  109. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/postgres/postgres_utils.py +0 -0
  110. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/postgres/psql_completions.py +0 -0
  111. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/preview_table.py +0 -0
  112. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/pwd.py +0 -0
  113. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/reaper/__init__.py +0 -0
  114. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/reaper/reaper.py +0 -0
  115. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/reaper/reaper_forward.py +0 -0
  116. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/reaper/reaper_forward_stop.py +0 -0
  117. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/reaper/reaper_restart.py +0 -0
  118. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/reaper/reaper_run_abort.py +0 -0
  119. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/reaper/reaper_runs.py +0 -0
  120. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/reaper/reaper_runs_abort.py +0 -0
  121. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/reaper/reaper_schedule_activate.py +0 -0
  122. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/reaper/reaper_schedule_start.py +0 -0
  123. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/reaper/reaper_schedule_stop.py +0 -0
  124. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/reaper/reaper_schedules.py +0 -0
  125. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/reaper/reaper_session.py +0 -0
  126. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/reaper/reaper_status.py +0 -0
  127. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/repair/__init__.py +0 -0
  128. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/repair/repair.py +0 -0
  129. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/repair/repair_log.py +0 -0
  130. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/repair/repair_run.py +0 -0
  131. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/repair/repair_scan.py +0 -0
  132. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/repair/repair_stop.py +0 -0
  133. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/report.py +0 -0
  134. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/restart.py +0 -0
  135. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/rollout.py +0 -0
  136. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/shell.py +0 -0
  137. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/show/__init__.py +0 -0
  138. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/show/show.py +0 -0
  139. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/show/show_adam.py +0 -0
  140. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/show/show_app_actions.py +0 -0
  141. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/show/show_app_id.py +0 -0
  142. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/show/show_app_queues.py +0 -0
  143. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/show/show_cassandra_status.py +0 -0
  144. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/show/show_cassandra_version.py +0 -0
  145. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/show/show_commands.py +0 -0
  146. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/show/show_host.py +0 -0
  147. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/show/show_login.py +0 -0
  148. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/show/show_params.py +0 -0
  149. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/show/show_processes.py +0 -0
  150. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/show/show_repairs.py +0 -0
  151. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/show/show_storage.py +0 -0
  152. {kaqing-2.0.103 → kaqing-2.0.104}/adam/commands/watch.py +0 -0
  153. {kaqing-2.0.103 → kaqing-2.0.104}/adam/config.py +0 -0
  154. {kaqing-2.0.103 → kaqing-2.0.104}/adam/embedded_apps.py +0 -0
  155. {kaqing-2.0.103 → kaqing-2.0.104}/adam/log.py +0 -0
  156. {kaqing-2.0.103 → kaqing-2.0.104}/adam/pod_exec_result.py +0 -0
  157. {kaqing-2.0.103 → kaqing-2.0.104}/adam/repl.py +0 -0
  158. {kaqing-2.0.103 → kaqing-2.0.104}/adam/repl_session.py +0 -0
  159. {kaqing-2.0.103 → kaqing-2.0.104}/adam/repl_state.py +0 -0
  160. {kaqing-2.0.103 → kaqing-2.0.104}/adam/sql/__init__.py +0 -0
  161. {kaqing-2.0.103 → kaqing-2.0.104}/adam/sql/term_completer.py +0 -0
  162. {kaqing-2.0.103 → kaqing-2.0.104}/adam/sso/__init__.py +0 -0
  163. {kaqing-2.0.103 → kaqing-2.0.104}/adam/sso/authenticator.py +0 -0
  164. {kaqing-2.0.103 → kaqing-2.0.104}/adam/sso/authn_ad.py +0 -0
  165. {kaqing-2.0.103 → kaqing-2.0.104}/adam/sso/authn_okta.py +0 -0
  166. {kaqing-2.0.103 → kaqing-2.0.104}/adam/sso/cred_cache.py +0 -0
  167. {kaqing-2.0.103 → kaqing-2.0.104}/adam/sso/id_token.py +0 -0
  168. {kaqing-2.0.103 → kaqing-2.0.104}/adam/sso/idp.py +0 -0
  169. {kaqing-2.0.103 → kaqing-2.0.104}/adam/sso/idp_login.py +0 -0
  170. {kaqing-2.0.103 → kaqing-2.0.104}/adam/sso/idp_session.py +0 -0
  171. {kaqing-2.0.103 → kaqing-2.0.104}/adam/sso/sso_config.py +0 -0
  172. {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils.py +0 -0
  173. {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_k8s/__init__.py +0 -0
  174. {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_k8s/cassandra_clusters.py +0 -0
  175. {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_k8s/cassandra_nodes.py +0 -0
  176. {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_k8s/config_maps.py +0 -0
  177. {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_k8s/custom_resources.py +0 -0
  178. {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_k8s/deployment.py +0 -0
  179. {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_k8s/ingresses.py +0 -0
  180. {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_k8s/jobs.py +0 -0
  181. {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_k8s/kube_context.py +0 -0
  182. {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_k8s/pods.py +0 -0
  183. {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_k8s/secrets.py +0 -0
  184. {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_k8s/service_accounts.py +0 -0
  185. {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_k8s/services.py +0 -0
  186. {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_k8s/statefulsets.py +0 -0
  187. {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_k8s/volumes.py +0 -0
  188. {kaqing-2.0.103 → kaqing-2.0.104}/adam/utils_net.py +0 -0
  189. {kaqing-2.0.103 → kaqing-2.0.104}/kaqing.egg-info/dependency_links.txt +0 -0
  190. {kaqing-2.0.103 → kaqing-2.0.104}/kaqing.egg-info/entry_points.txt +0 -0
  191. {kaqing-2.0.103 → kaqing-2.0.104}/kaqing.egg-info/top_level.txt +0 -0
  192. {kaqing-2.0.103 → kaqing-2.0.104}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: kaqing
3
- Version: 2.0.103
3
+ Version: 2.0.104
4
4
  Summary: UNKNOWN
5
5
  Home-page: UNKNOWN
6
6
  License: UNKNOWN
@@ -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
- self.repair(tables)
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
- state, _, rs = audit_query(f'select * from meta')
56
- if state == 'SUCCEEDED':
57
- do_repair = True
58
- if len(rs) > 1:
59
- try:
60
- checked_in = float(rs[1]['Data'][0]['VarCharValue'])
61
- do_repair = checked_in + hours * 60 * 60 < time.time()
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(self.check_in,)
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
- from adam.sql.automata_completer import AutomataCompleter
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(tables: list[str]):
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 terms(self, state: str, word: str) -> list[str]:
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 adam.sql.state_machine import StateMachine
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 > select_from_x ^ tables',
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 > select_from_x ^ tables',
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 > select_x_join_y ^ tables',
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 > insert_into_x ^ tables',
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 > update_x ^ tables',
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 > delete_from_x ^ tables',
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'))
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ __version__ = "2.0.104" #: the working version
5
+ __release__ = "1.0.0" #: the release version
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: kaqing
3
- Version: 2.0.103
3
+ Version: 2.0.104
4
4
  Summary: UNKNOWN
5
5
  Home-page: UNKNOWN
6
6
  License: UNKNOWN