kaqing 2.0.100__tar.gz → 2.0.102__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 (197) hide show
  1. {kaqing-2.0.100 → kaqing-2.0.102}/PKG-INFO +1 -1
  2. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/audit/audit.py +3 -2
  3. kaqing-2.0.102/adam/commands/audit/audit_table_completer.py +9 -0
  4. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/cql/cql_utils.py +5 -8
  5. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/cql/cqlsh.py +5 -2
  6. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/describe/describe.py +18 -4
  7. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/describe/describe_keyspace.py +2 -4
  8. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/describe/describe_keyspaces.py +1 -4
  9. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/describe/describe_schema.py +1 -4
  10. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/describe/describe_table.py +3 -6
  11. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/describe/describe_tables.py +1 -4
  12. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/ls.py +1 -1
  13. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/preview_table.py +11 -3
  14. {kaqing-2.0.100 → kaqing-2.0.102}/adam/embedded_params.py +1 -1
  15. {kaqing-2.0.100 → kaqing-2.0.102}/adam/repl.py +71 -40
  16. {kaqing-2.0.100 → kaqing-2.0.102}/adam/repl_commands.py +4 -2
  17. {kaqing-2.0.100 → kaqing-2.0.102}/adam/sql/sql_completer.py +2 -1
  18. {kaqing-2.0.100 → kaqing-2.0.102}/adam/sql/state_machine.py +28 -1
  19. {kaqing-2.0.100 → kaqing-2.0.102}/adam/utils_k8s/cassandra_clusters.py +4 -4
  20. {kaqing-2.0.100 → kaqing-2.0.102}/adam/utils_k8s/cassandra_nodes.py +2 -2
  21. {kaqing-2.0.100 → kaqing-2.0.102}/adam/utils_k8s/pods.py +10 -4
  22. {kaqing-2.0.100 → kaqing-2.0.102}/adam/utils_k8s/statefulsets.py +2 -2
  23. kaqing-2.0.102/adam/version.py +5 -0
  24. {kaqing-2.0.100 → kaqing-2.0.102}/kaqing.egg-info/PKG-INFO +1 -1
  25. {kaqing-2.0.100 → kaqing-2.0.102}/kaqing.egg-info/SOURCES.txt +1 -0
  26. {kaqing-2.0.100 → kaqing-2.0.102}/setup.py +1 -1
  27. kaqing-2.0.100/adam/version.py +0 -5
  28. {kaqing-2.0.100 → kaqing-2.0.102}/README +0 -0
  29. {kaqing-2.0.100 → kaqing-2.0.102}/adam/__init__.py +0 -0
  30. {kaqing-2.0.100 → kaqing-2.0.102}/adam/app_session.py +0 -0
  31. {kaqing-2.0.100 → kaqing-2.0.102}/adam/apps.py +0 -0
  32. {kaqing-2.0.100 → kaqing-2.0.102}/adam/batch.py +0 -0
  33. {kaqing-2.0.100 → kaqing-2.0.102}/adam/checks/__init__.py +0 -0
  34. {kaqing-2.0.100 → kaqing-2.0.102}/adam/checks/check.py +0 -0
  35. {kaqing-2.0.100 → kaqing-2.0.102}/adam/checks/check_context.py +0 -0
  36. {kaqing-2.0.100 → kaqing-2.0.102}/adam/checks/check_result.py +0 -0
  37. {kaqing-2.0.100 → kaqing-2.0.102}/adam/checks/check_utils.py +0 -0
  38. {kaqing-2.0.100 → kaqing-2.0.102}/adam/checks/compactionstats.py +0 -0
  39. {kaqing-2.0.100 → kaqing-2.0.102}/adam/checks/cpu.py +0 -0
  40. {kaqing-2.0.100 → kaqing-2.0.102}/adam/checks/disk.py +0 -0
  41. {kaqing-2.0.100 → kaqing-2.0.102}/adam/checks/gossip.py +0 -0
  42. {kaqing-2.0.100 → kaqing-2.0.102}/adam/checks/issue.py +0 -0
  43. {kaqing-2.0.100 → kaqing-2.0.102}/adam/checks/memory.py +0 -0
  44. {kaqing-2.0.100 → kaqing-2.0.102}/adam/checks/status.py +0 -0
  45. {kaqing-2.0.100 → kaqing-2.0.102}/adam/cli.py +0 -0
  46. {kaqing-2.0.100 → kaqing-2.0.102}/adam/cli_group.py +0 -0
  47. {kaqing-2.0.100 → kaqing-2.0.102}/adam/columns/__init__.py +0 -0
  48. {kaqing-2.0.100 → kaqing-2.0.102}/adam/columns/column.py +0 -0
  49. {kaqing-2.0.100 → kaqing-2.0.102}/adam/columns/columns.py +0 -0
  50. {kaqing-2.0.100 → kaqing-2.0.102}/adam/columns/compactions.py +0 -0
  51. {kaqing-2.0.100 → kaqing-2.0.102}/adam/columns/cpu.py +0 -0
  52. {kaqing-2.0.100 → kaqing-2.0.102}/adam/columns/dir_data.py +0 -0
  53. {kaqing-2.0.100 → kaqing-2.0.102}/adam/columns/dir_snapshots.py +0 -0
  54. {kaqing-2.0.100 → kaqing-2.0.102}/adam/columns/gossip.py +0 -0
  55. {kaqing-2.0.100 → kaqing-2.0.102}/adam/columns/host_id.py +0 -0
  56. {kaqing-2.0.100 → kaqing-2.0.102}/adam/columns/memory.py +0 -0
  57. {kaqing-2.0.100 → kaqing-2.0.102}/adam/columns/node_address.py +0 -0
  58. {kaqing-2.0.100 → kaqing-2.0.102}/adam/columns/node_load.py +0 -0
  59. {kaqing-2.0.100 → kaqing-2.0.102}/adam/columns/node_owns.py +0 -0
  60. {kaqing-2.0.100 → kaqing-2.0.102}/adam/columns/node_status.py +0 -0
  61. {kaqing-2.0.100 → kaqing-2.0.102}/adam/columns/node_tokens.py +0 -0
  62. {kaqing-2.0.100 → kaqing-2.0.102}/adam/columns/node_utils.py +0 -0
  63. {kaqing-2.0.100 → kaqing-2.0.102}/adam/columns/pod_name.py +0 -0
  64. {kaqing-2.0.100 → kaqing-2.0.102}/adam/columns/volume_cassandra.py +0 -0
  65. {kaqing-2.0.100 → kaqing-2.0.102}/adam/columns/volume_root.py +0 -0
  66. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/__init__.py +0 -0
  67. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/alter_tables.py +0 -0
  68. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/app.py +0 -0
  69. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/app_ping.py +0 -0
  70. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/audit/__init__.py +0 -0
  71. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/audit/audit_repair_tables.py +0 -0
  72. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/bash.py +0 -0
  73. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/cd.py +0 -0
  74. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/check.py +0 -0
  75. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/cli_commands.py +0 -0
  76. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/command.py +0 -0
  77. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/command_helpers.py +0 -0
  78. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/commands_utils.py +0 -0
  79. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/cp.py +0 -0
  80. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/cql/__init__.py +0 -0
  81. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/cql/cql_completions.py +0 -0
  82. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/cql/cql_table_completer.py +0 -0
  83. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/deploy/__init__.py +0 -0
  84. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/deploy/code_start.py +0 -0
  85. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/deploy/code_stop.py +0 -0
  86. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/deploy/code_utils.py +0 -0
  87. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/deploy/deploy.py +0 -0
  88. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/deploy/deploy_frontend.py +0 -0
  89. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/deploy/deploy_pg_agent.py +0 -0
  90. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/deploy/deploy_pod.py +0 -0
  91. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/deploy/deploy_utils.py +0 -0
  92. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/deploy/undeploy.py +0 -0
  93. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/deploy/undeploy_frontend.py +0 -0
  94. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/deploy/undeploy_pg_agent.py +0 -0
  95. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/deploy/undeploy_pod.py +0 -0
  96. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/describe/__init__.py +0 -0
  97. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/devices.py +0 -0
  98. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/exit.py +0 -0
  99. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/help.py +0 -0
  100. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/issues.py +0 -0
  101. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/login.py +0 -0
  102. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/logs.py +0 -0
  103. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/medusa/__init__.py +0 -0
  104. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/medusa/medusa.py +0 -0
  105. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/medusa/medusa_backup.py +0 -0
  106. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/medusa/medusa_restore.py +0 -0
  107. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/medusa/medusa_show_backupjobs.py +0 -0
  108. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/medusa/medusa_show_restorejobs.py +0 -0
  109. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/nodetool.py +0 -0
  110. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/nodetool_commands.py +0 -0
  111. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/param_get.py +0 -0
  112. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/param_set.py +0 -0
  113. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/postgres/__init__.py +0 -0
  114. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/postgres/postgres.py +0 -0
  115. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/postgres/postgres_ls.py +0 -0
  116. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/postgres/postgres_preview.py +0 -0
  117. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/postgres/postgres_session.py +0 -0
  118. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/postgres/postgres_utils.py +0 -0
  119. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/postgres/psql_completions.py +0 -0
  120. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/postgres/psql_table_completer.py +0 -0
  121. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/pwd.py +0 -0
  122. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/reaper/__init__.py +0 -0
  123. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/reaper/reaper.py +0 -0
  124. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/reaper/reaper_forward.py +0 -0
  125. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/reaper/reaper_forward_stop.py +0 -0
  126. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/reaper/reaper_restart.py +0 -0
  127. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/reaper/reaper_run_abort.py +0 -0
  128. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/reaper/reaper_runs.py +0 -0
  129. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/reaper/reaper_runs_abort.py +0 -0
  130. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/reaper/reaper_schedule_activate.py +0 -0
  131. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/reaper/reaper_schedule_start.py +0 -0
  132. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/reaper/reaper_schedule_stop.py +0 -0
  133. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/reaper/reaper_schedules.py +0 -0
  134. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/reaper/reaper_session.py +0 -0
  135. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/reaper/reaper_status.py +0 -0
  136. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/repair/__init__.py +0 -0
  137. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/repair/repair.py +0 -0
  138. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/repair/repair_log.py +0 -0
  139. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/repair/repair_run.py +0 -0
  140. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/repair/repair_scan.py +0 -0
  141. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/repair/repair_stop.py +0 -0
  142. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/report.py +0 -0
  143. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/restart.py +0 -0
  144. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/rollout.py +0 -0
  145. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/shell.py +0 -0
  146. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/show/__init__.py +0 -0
  147. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/show/show.py +0 -0
  148. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/show/show_adam.py +0 -0
  149. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/show/show_app_actions.py +0 -0
  150. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/show/show_app_id.py +0 -0
  151. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/show/show_app_queues.py +0 -0
  152. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/show/show_cassandra_status.py +0 -0
  153. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/show/show_cassandra_version.py +0 -0
  154. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/show/show_commands.py +0 -0
  155. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/show/show_host.py +0 -0
  156. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/show/show_login.py +0 -0
  157. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/show/show_params.py +0 -0
  158. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/show/show_processes.py +0 -0
  159. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/show/show_repairs.py +0 -0
  160. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/show/show_storage.py +0 -0
  161. {kaqing-2.0.100 → kaqing-2.0.102}/adam/commands/watch.py +0 -0
  162. {kaqing-2.0.100 → kaqing-2.0.102}/adam/config.py +0 -0
  163. {kaqing-2.0.100 → kaqing-2.0.102}/adam/embedded_apps.py +0 -0
  164. {kaqing-2.0.100 → kaqing-2.0.102}/adam/log.py +0 -0
  165. {kaqing-2.0.100 → kaqing-2.0.102}/adam/pod_exec_result.py +0 -0
  166. {kaqing-2.0.100 → kaqing-2.0.102}/adam/repl_session.py +0 -0
  167. {kaqing-2.0.100 → kaqing-2.0.102}/adam/repl_state.py +0 -0
  168. {kaqing-2.0.100 → kaqing-2.0.102}/adam/sql/__init__.py +0 -0
  169. {kaqing-2.0.100 → kaqing-2.0.102}/adam/sql/term_completer.py +0 -0
  170. {kaqing-2.0.100 → kaqing-2.0.102}/adam/sso/__init__.py +0 -0
  171. {kaqing-2.0.100 → kaqing-2.0.102}/adam/sso/authenticator.py +0 -0
  172. {kaqing-2.0.100 → kaqing-2.0.102}/adam/sso/authn_ad.py +0 -0
  173. {kaqing-2.0.100 → kaqing-2.0.102}/adam/sso/authn_okta.py +0 -0
  174. {kaqing-2.0.100 → kaqing-2.0.102}/adam/sso/cred_cache.py +0 -0
  175. {kaqing-2.0.100 → kaqing-2.0.102}/adam/sso/id_token.py +0 -0
  176. {kaqing-2.0.100 → kaqing-2.0.102}/adam/sso/idp.py +0 -0
  177. {kaqing-2.0.100 → kaqing-2.0.102}/adam/sso/idp_login.py +0 -0
  178. {kaqing-2.0.100 → kaqing-2.0.102}/adam/sso/idp_session.py +0 -0
  179. {kaqing-2.0.100 → kaqing-2.0.102}/adam/sso/sso_config.py +0 -0
  180. {kaqing-2.0.100 → kaqing-2.0.102}/adam/utils.py +0 -0
  181. {kaqing-2.0.100 → kaqing-2.0.102}/adam/utils_athena.py +0 -0
  182. {kaqing-2.0.100 → kaqing-2.0.102}/adam/utils_k8s/__init__.py +0 -0
  183. {kaqing-2.0.100 → kaqing-2.0.102}/adam/utils_k8s/config_maps.py +0 -0
  184. {kaqing-2.0.100 → kaqing-2.0.102}/adam/utils_k8s/custom_resources.py +0 -0
  185. {kaqing-2.0.100 → kaqing-2.0.102}/adam/utils_k8s/deployment.py +0 -0
  186. {kaqing-2.0.100 → kaqing-2.0.102}/adam/utils_k8s/ingresses.py +0 -0
  187. {kaqing-2.0.100 → kaqing-2.0.102}/adam/utils_k8s/jobs.py +0 -0
  188. {kaqing-2.0.100 → kaqing-2.0.102}/adam/utils_k8s/kube_context.py +0 -0
  189. {kaqing-2.0.100 → kaqing-2.0.102}/adam/utils_k8s/secrets.py +0 -0
  190. {kaqing-2.0.100 → kaqing-2.0.102}/adam/utils_k8s/service_accounts.py +0 -0
  191. {kaqing-2.0.100 → kaqing-2.0.102}/adam/utils_k8s/services.py +0 -0
  192. {kaqing-2.0.100 → kaqing-2.0.102}/adam/utils_k8s/volumes.py +0 -0
  193. {kaqing-2.0.100 → kaqing-2.0.102}/adam/utils_net.py +0 -0
  194. {kaqing-2.0.100 → kaqing-2.0.102}/kaqing.egg-info/dependency_links.txt +0 -0
  195. {kaqing-2.0.100 → kaqing-2.0.102}/kaqing.egg-info/entry_points.txt +0 -0
  196. {kaqing-2.0.100 → kaqing-2.0.102}/kaqing.egg-info/top_level.txt +0 -0
  197. {kaqing-2.0.100 → kaqing-2.0.102}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: kaqing
3
- Version: 2.0.100
3
+ Version: 2.0.102
4
4
  Summary: UNKNOWN
5
5
  Home-page: UNKNOWN
6
6
  License: UNKNOWN
@@ -62,8 +62,9 @@ class Audit(Command):
62
62
  columns=lambda table: audit_column_names(),
63
63
  partition_columns=lambda table: audit_column_names(partition_cols_only=True),
64
64
  variant='athena'
65
- ) | {
66
- 'desc': {table: None for table in audit_table_names()}}
65
+ )
66
+ # | {
67
+ # 'desc': {table: None for table in audit_table_names()}}
67
68
 
68
69
  return {}
69
70
 
@@ -0,0 +1,9 @@
1
+ from adam.sql.term_completer import TermCompleter
2
+ from adam.utils_athena import audit_table_names
3
+
4
+ class AuditTableNameCompleter(TermCompleter):
5
+ def __init__(self, ignore_case: bool = True):
6
+ super().__init__(audit_table_names(), ignore_case=ignore_case)
7
+
8
+ def __repr__(self) -> str:
9
+ return "AuditTableCompleter()"
@@ -27,28 +27,25 @@ def table_names(state: ReplState):
27
27
  return [f'{k}.{t}' for k, ts in tables(state, on_any=True).items() for t in ts]
28
28
 
29
29
  @functools.lru_cache()
30
- def tables(state: ReplState, on_any=False):
30
+ def tables(state: ReplState, on_any=False) -> dict[str, list[str]]:
31
31
  r: list[PodExecResult] = run_cql(state, 'describe tables', show_out=False, on_any=on_any)
32
32
  if not r:
33
33
  log2('No pod is available')
34
- return []
34
+ return {}
35
35
 
36
36
  return parse_cql_desc_tables(r.stdout if state.pod else r[0].stdout)
37
37
 
38
- def run_cql(state: ReplState, cql: str, opts: list = [], show_out = False, use_single_quotes = False, on_any = False):
38
+ def run_cql(state: ReplState, cql: str, opts: list = [], show_out = False, use_single_quotes = False, on_any = False, background=False):
39
39
  user, pw = Secrets.get_user_pass(state.sts if state.sts else state.pod, state.namespace, secret_path='cql.secret')
40
40
  if use_single_quotes:
41
41
  command = f"cqlsh -u {user} -p {pw} {' '.join(opts)} -e '{cql}'"
42
42
  else:
43
43
  command = f'cqlsh -u {user} -p {pw} {" ".join(opts)} -e "{cql}"'
44
44
 
45
- if not on_any:
46
- command = f'{command} &'
47
-
48
45
  if state.pod:
49
- return CassandraNodes.exec(state.pod, state.namespace, command, show_out=show_out)
46
+ return CassandraNodes.exec(state.pod, state.namespace, command, show_out=show_out, background=background)
50
47
  else:
51
- return CassandraClusters.exec(state.sts, state.namespace, command, show_out=show_out, action='cql', on_any=on_any)
48
+ return CassandraClusters.exec(state.sts, state.namespace, command, show_out=show_out, action='cql', on_any=on_any, background=background)
52
49
 
53
50
  def parse_cql_desc_tables(out: str):
54
51
  # Keyspace data_endpoint_auth
@@ -33,11 +33,14 @@ class Cqlsh(Command):
33
33
  if not self.validate_state(state):
34
34
  return state
35
35
 
36
+ background = False
36
37
  opts = []
37
38
  cqls = []
38
- for arg in args:
39
+ for index, arg in enumerate(args):
39
40
  if arg.startswith('--'):
40
41
  opts.append(arg)
42
+ elif index == len(args) -1 and arg == '&':
43
+ background = True
41
44
  elif arg != '-e':
42
45
  cqls.append(arg)
43
46
  if not cqls:
@@ -51,7 +54,7 @@ class Cqlsh(Command):
51
54
  return 'no-cql'
52
55
 
53
56
  cql = ' '.join(cqls)
54
- return run_cql(state, cql, opts, show_out=True)
57
+ return run_cql(state, cql, opts, show_out=True, background=background)
55
58
 
56
59
  def completion(self, state: ReplState) -> dict[str, any]:
57
60
  if state.device != state.C:
@@ -7,6 +7,8 @@ from adam.commands.describe.describe_schema import DescribeSchema
7
7
  from adam.commands.describe.describe_table import DescribeTable
8
8
  from adam.commands.describe.describe_tables import DescribeTables
9
9
  from adam.repl_state import ReplState, RequiredState
10
+ from adam.utils import log2
11
+ from adam.utils_athena import run_audit_query
10
12
 
11
13
  class Describe(Command):
12
14
  COMMAND = 'describe'
@@ -31,15 +33,27 @@ class Describe(Command):
31
33
  if not(args := self.args(cmd)):
32
34
  return super().run(cmd, state)
33
35
 
36
+ if state.device == ReplState.L:
37
+ state, args = self.apply_state(args, state)
38
+ if not args:
39
+ if state.in_repl:
40
+ log2('Please enter table name')
41
+ else:
42
+ log2('* table name is missing.')
43
+ log2()
44
+ Command.display_help()
45
+ return state
46
+
47
+ run_audit_query(f'describe {args[0]}')
48
+
49
+ return state
50
+
34
51
  return super().intermediate_run(cmd, state, args, Describe.cmd_list())
35
52
 
36
53
  def cmd_list():
37
54
  return [DescribeKeyspace(), DescribeKeyspaces(), DescribeSchema(), DescribeTable(), DescribeTables()]
38
55
 
39
- def completion(self, state: ReplState):
40
- if state.sts:
41
- return super().completion(state)
42
-
56
+ def completion(self, _: ReplState):
43
57
  return {}
44
58
 
45
59
  class DescribeCommandHelper(click.Command):
@@ -1,5 +1,5 @@
1
1
  from adam.commands.command import Command
2
- from adam.commands.cql.cql_utils import keyspaces, run_cql
2
+ from adam.commands.cql.cql_utils import run_cql
3
3
  from adam.pod_exec_result import PodExecResult
4
4
  from adam.repl_state import ReplState, RequiredState
5
5
  from adam.utils import log2
@@ -50,9 +50,7 @@ class DescribeKeyspace(Command):
50
50
  # do not continue to cql route
51
51
  return state
52
52
 
53
- def completion(self, state: ReplState) -> dict[str, any]:
54
- if state.sts:
55
- return super().completion(state, {ks: {'&': None} for ks in keyspaces(state, on_any=True)})
53
+ def completion(self, _: ReplState) -> dict[str, any]:
56
54
 
57
55
  return {}
58
56
 
@@ -39,10 +39,7 @@ class DescribeKeyspaces(Command):
39
39
  # do not continue to cql route
40
40
  return state
41
41
 
42
- def completion(self, state: ReplState) -> dict[str, any]:
43
- if state.sts:
44
- return super().completion(state, {'&': None})
45
-
42
+ def completion(self, _: ReplState) -> dict[str, any]:
46
43
  return {}
47
44
 
48
45
  def help(self, _: ReplState) -> str:
@@ -39,10 +39,7 @@ class DescribeSchema(Command):
39
39
  # do not continue to cql route
40
40
  return state
41
41
 
42
- def completion(self, state: ReplState) -> dict[str, any]:
43
- if state.sts:
44
- return super().completion(state, {'&': None})
45
-
42
+ def completion(self, _: ReplState) -> dict[str, any]:
46
43
  return {}
47
44
 
48
45
  def help(self, _: ReplState) -> str:
@@ -1,5 +1,5 @@
1
1
  from adam.commands.command import Command
2
- from adam.commands.cql.cql_utils import run_cql, table_names
2
+ from adam.commands.cql.cql_utils import run_cql
3
3
  from adam.pod_exec_result import PodExecResult
4
4
  from adam.repl_state import ReplState, RequiredState
5
5
  from adam.utils import log2
@@ -50,11 +50,8 @@ class DescribeTable(Command):
50
50
  # do not continue to cql route
51
51
  return state
52
52
 
53
- def completion(self, state: ReplState) -> dict[str, any]:
54
- if state.sts:
55
- return super().completion(state, {t: {'&': None} for t in table_names(state)})
56
-
53
+ def completion(self, _: ReplState) -> dict[str, any]:
57
54
  return {}
58
55
 
59
56
  def help(self, _: ReplState) -> str:
60
- return f'{DescribeTable.COMMAND} <table-name> [&]\t describe Cassandra table'
57
+ return f'{DescribeTable.COMMAND} <table-name> [&]\t describe Cassandra or Athena table'
@@ -39,10 +39,7 @@ class DescribeTables(Command):
39
39
  # do not continue to cql route
40
40
  return state
41
41
 
42
- def completion(self, state: ReplState) -> dict[str, any]:
43
- if state.sts:
44
- return super().completion(state, {'&': None})
45
-
42
+ def completion(self, _: ReplState) -> dict[str, any]:
46
43
  return {}
47
44
 
48
45
  def help(self, _: ReplState) -> str:
@@ -91,7 +91,7 @@ class Ls(Command):
91
91
  def show_statefulsets(self):
92
92
  ss = StatefulSets.list_sts_names()
93
93
  if len(ss) == 0:
94
- log2('No cassandra statefulsets found.')
94
+ log2('No Cassandra clusters found.')
95
95
  return
96
96
 
97
97
  app_ids = CustomResources.get_app_ids()
@@ -1,5 +1,6 @@
1
1
  import functools
2
2
 
3
+ from adam.commands.audit.audit_table_completer import AuditTableNameCompleter
3
4
  from adam.commands.command import Command
4
5
  from adam.commands.cql.cql_table_completer import CqlTableNameCompleter
5
6
  from adam.commands.cql.cql_utils import run_cql, table_names, tables
@@ -8,6 +9,7 @@ from adam.commands.postgres.psql_table_completer import PsqlTableNameCompleter
8
9
  from adam.config import Config
9
10
  from adam.repl_state import ReplState, RequiredState
10
11
  from adam.utils import lines_to_tabular, log, log2
12
+ from adam.utils_athena import audit_table_names, run_audit_query
11
13
 
12
14
  class PreviewTable(Command):
13
15
  COMMAND = 'preview'
@@ -35,7 +37,7 @@ class PreviewTable(Command):
35
37
  if state.device == ReplState.P:
36
38
  if not self.validate_state(state, RequiredState.PG_DATABASE):
37
39
  return state
38
- else:
40
+ elif state.device != ReplState.L:
39
41
  if not self.validate_state(state):
40
42
  return state
41
43
 
@@ -45,8 +47,10 @@ class PreviewTable(Command):
45
47
  pg = PostgresSession(state.namespace, state.pg_path)
46
48
  lines = [db["name"] for db in pg.tables() if db["schema"] == PostgresSession.default_schema()]
47
49
  log(lines_to_tabular(lines, separator=','))
50
+ elif state.device == ReplState.L:
51
+ log(lines_to_tabular(audit_table_names(), separator=','))
48
52
  else:
49
- run_cql(state, f'describe tables', show_out=True)
53
+ run_cql(state, f'describe tables', show_out=True, on_any=True)
50
54
 
51
55
  if state.in_repl:
52
56
  log2('Table is required.')
@@ -66,14 +70,18 @@ class PreviewTable(Command):
66
70
  rows = Config().get('preview.rows', 10)
67
71
  if state.device == ReplState.P:
68
72
  PostgresSession(state.namespace, state.pg_path).run_sql(f'select * from {table} limit {rows}')
73
+ elif state.device == ReplState.L:
74
+ run_audit_query(f'select * from {table} limit {rows}')
69
75
  else:
70
- run_cql(state, f'select * from {table} limit {rows}', show_out=True, use_single_quotes=True)
76
+ run_cql(state, f'select * from {table} limit {rows}', show_out=True, use_single_quotes=True, on_any=True)
71
77
 
72
78
  return state
73
79
 
74
80
  def completion(self, state: ReplState):
75
81
  if state.device == ReplState.P:
76
82
  return {PreviewTable.COMMAND: PsqlTableNameCompleter(state.namespace, state.pg_path)}
83
+ elif state.device == ReplState.L:
84
+ return {PreviewTable.COMMAND: AuditTableNameCompleter()}
77
85
  elif state.sts:
78
86
  return {PreviewTable.COMMAND: CqlTableNameCompleter(table_names(state))}
79
87
 
@@ -1,2 +1,2 @@
1
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', 'tables': 'audit', 'output': 's3://s3.ops--audit/ddl/results'}}, '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-app': 'c3/c3'}, 'c': {'auto-enter-only-cluster': '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}}
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', 'tables': 'audit', 'output': 's3://s3.ops--audit/ddl/results'}}, '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}}
@@ -69,20 +69,21 @@ def enter_repl(state: ReplState):
69
69
  Log.log2(f'kaqing {__version__}')
70
70
 
71
71
  if state.device == ReplState.C:
72
- auto_enter = Config().get('repl.c.auto-enter-only-cluster', 'cluster')
73
- ss = StatefulSets.list_sts_name_and_ns()
74
- if not ss:
75
- raise Exception("no Cassandra clusters found")
76
- elif not state.sts and len(ss) == 1 and auto_enter in ['cluster', 'first-pod']:
77
- cluster = ss[0]
78
- state.sts = cluster[0]
79
- state.namespace = cluster[1]
80
- if auto_enter == 'first-pod':
81
- state.pod = f'{state.sts}-0'
82
- if KubeContext().in_cluster_namespace:
83
- Config().wait_log(f'Moving to the only Cassandra cluster: {state.sts}...')
84
- else:
85
- Config().wait_log(f'Moving to the only Cassandra cluster: {state.sts}@{state.namespace}...')
72
+ auto_enter = Config().get('repl.c.auto-enter', 'cluster')
73
+ if auto_enter and auto_enter in ['cluster', 'first-pod']:
74
+ ss = StatefulSets.list_sts_name_and_ns()
75
+ if not ss:
76
+ log2("No Cassandra clusters found.")
77
+ elif not state.sts and len(ss) == 1:
78
+ cluster = ss[0]
79
+ state.sts = cluster[0]
80
+ state.namespace = cluster[1]
81
+ if auto_enter == 'first-pod':
82
+ state.pod = f'{state.sts}-0'
83
+ if KubeContext().in_cluster_namespace:
84
+ Config().wait_log(f'Moving to the only Cassandra cluster: {state.sts}...')
85
+ else:
86
+ Config().wait_log(f'Moving to the only Cassandra cluster: {state.sts}@{state.namespace}...')
86
87
  elif state.device == ReplState.A:
87
88
  if not state.app_env:
88
89
  if app := Config().get('repl.a.auto-enter-app', 'c3/c3'):
@@ -140,32 +141,34 @@ def enter_repl(state: ReplState):
140
141
  cmd = f'bash {cmd}'
141
142
 
142
143
  if cmd and cmd.strip(' ') and not cmds.run(cmd, state):
143
- c_sql_tried = False
144
- if state.device == ReplState.P:
145
- pg = PostgresSession(state.namespace, state.pg_path)
146
- if pg.db:
147
- c_sql_tried = True
148
- cmd = f'pg {cmd}'
149
- cmds.run(cmd, state)
150
- elif state.device == ReplState.A:
151
- if state.app_app:
152
- c_sql_tried = True
153
- cmd = f'app {cmd}'
154
- cmds.run(cmd, state)
155
- elif state.device == ReplState.L:
156
- c_sql_tried = True
157
- cmd = f'audit {cmd}'
158
- cmds.run(cmd, state)
159
- elif state.sts:
160
- c_sql_tried = True
161
- cmd = f'cql {cmd}'
162
- cmds.run(cmd, state)
163
-
164
- if not c_sql_tried:
165
- log2(f'* Invalid command: {cmd}')
166
- log2()
167
- lines = [c.help(state) for c in cmd_list if c.help(state)]
168
- log2(lines_to_tabular(lines, separator='\t'))
144
+ try_device_default_action(state, cmds, cmd_list, cmd)
145
+ # not served by any command in the chain; try SQL query or C3 action
146
+ # c_sql_tried = False
147
+ # if state.device == ReplState.P:
148
+ # pg = PostgresSession(state.namespace, state.pg_path)
149
+ # if pg.db:
150
+ # c_sql_tried = True
151
+ # cmd = f'pg {cmd}'
152
+ # cmds.run(cmd, state)
153
+ # elif state.device == ReplState.A:
154
+ # if state.app_app:
155
+ # c_sql_tried = True
156
+ # cmd = f'app {cmd}'
157
+ # cmds.run(cmd, state)
158
+ # elif state.device == ReplState.L:
159
+ # c_sql_tried = True
160
+ # cmd = f'audit {cmd}'
161
+ # cmds.run(cmd, state)
162
+ # elif state.sts:
163
+ # c_sql_tried = True
164
+ # cmd = f'cql {cmd}'
165
+ # cmds.run(cmd, state)
166
+
167
+ # if not c_sql_tried:
168
+ # log2(f'* Invalid command: {cmd}')
169
+ # log2()
170
+ # lines = [c.help(state) for c in cmd_list if c.help(state)]
171
+ # log2(lines_to_tabular(lines, separator='\t'))
169
172
  except EOFError: # Handle Ctrl+D (EOF) for graceful exit
170
173
  break
171
174
  except Exception as e:
@@ -183,6 +186,34 @@ def enter_repl(state: ReplState):
183
186
  if cmd and (state.device != ReplState.L or Config().get('audit.log-audit-queries', False)):
184
187
  executor.submit(audit_log, cmd, state)
185
188
 
189
+ def try_device_default_action(state: ReplState, cmds: Command, cmd_list: list[Command], cmd: str):
190
+ c_sql_tried = False
191
+ if state.device == ReplState.P:
192
+ pg = PostgresSession(state.namespace, state.pg_path)
193
+ if pg.db:
194
+ c_sql_tried = True
195
+ cmd = f'pg {cmd}'
196
+ cmds.run(cmd, state)
197
+ elif state.device == ReplState.A:
198
+ if state.app_app:
199
+ c_sql_tried = True
200
+ cmd = f'app {cmd}'
201
+ cmds.run(cmd, state)
202
+ elif state.device == ReplState.L:
203
+ c_sql_tried = True
204
+ cmd = f'audit {cmd}'
205
+ cmds.run(cmd, state)
206
+ elif state.sts:
207
+ c_sql_tried = True
208
+ cmd = f'cql {cmd}'
209
+ cmds.run(cmd, state)
210
+
211
+ if not c_sql_tried:
212
+ log2(f'* Invalid command: {cmd}')
213
+ log2()
214
+ lines = [c.help(state) for c in cmd_list if c.help(state)]
215
+ log2(lines_to_tabular(lines, separator='\t'))
216
+
186
217
  def audit_log(cmd: str, state: ReplState):
187
218
  payload = {
188
219
  'cluster': state.namespace if state.namespace else 'NA',
@@ -58,7 +58,8 @@ class ReplCommands:
58
58
  cmds: list[Command] = ReplCommands.navigation() + ReplCommands.cassandra_check() + ReplCommands.cassandra_ops() + \
59
59
  ReplCommands.tools() + ReplCommands.app() + ReplCommands.exit()
60
60
 
61
- intermediate_cmds: list[Command] = [App(), Reaper(), Repair(), Deploy(), Describe(), Show(), Undeploy()]
61
+ intermediate_cmds: list[Command] = [App(), Reaper(), Repair(), Deploy(), Show(), Undeploy()]
62
+ # intermediate_cmds: list[Command] = [App(), Reaper(), Repair(), Deploy(), Describe(), Show(), Undeploy()]
62
63
  ic = [c.command() for c in intermediate_cmds]
63
64
  # 1. dedup commands
64
65
  deduped = []
@@ -79,7 +80,8 @@ class ReplCommands:
79
80
  GetParam(), SetParam(), ShowParams(), ShowKubectlCommands(), ShowLogin(), ShowAdam(), ShowHost()]
80
81
 
81
82
  def cassandra_check() -> list[Command]:
82
- return Describe.cmd_list() + [ShowCassandraStatus(),
83
+ # return Describe.cmd_list() + [ShowCassandraStatus(),
84
+ return [ShowCassandraStatus(),
83
85
  ShowCassandraVersion(), ShowRepairs(), ShowStorage(), ShowProcesses(), Check(), Issues(), NodeTool(), Report()]
84
86
 
85
87
  def cassandra_ops() -> list[Command]:
@@ -11,7 +11,7 @@ __all__ = [
11
11
  "SqlCompleter",
12
12
  ]
13
13
 
14
- DML_COMPLETER = TermCompleter(['select', 'insert', 'delete', 'update', 'alter'])
14
+ DML_COMPLETER = TermCompleter(['select', 'insert', 'delete', 'update', 'alter', 'describe'])
15
15
 
16
16
  def default_columns(tables: list[str]):
17
17
  return 'id,x.,y.,z.'.split(',')
@@ -98,4 +98,5 @@ class SqlCompleter(Completer):
98
98
  'select': SqlCompleter(table_names, 'select', columns=columns, partition_columns=partition_columns, table_props=table_props, variant=variant),
99
99
  'update': SqlCompleter(table_names, 'update', columns=columns, partition_columns=partition_columns, table_props=table_props, variant=variant),
100
100
  'alter': SqlCompleter(table_names, 'alter', columns=columns, partition_columns=partition_columns, table_props=table_props, variant=variant),
101
+ 'describe': SqlCompleter(table_names, 'describe', columns=columns, partition_columns=partition_columns, table_props=table_props, variant=variant),
101
102
  }
@@ -321,7 +321,8 @@ class SqlSpec:
321
321
  'update', 'where', 'set',
322
322
  'delete',
323
323
  'audit',
324
- 'alter', 'table', 'tables', 'add', 'drop', 'with'
324
+ 'alter', 'table', 'tables', 'add', 'drop', 'with',
325
+ 'describe'
325
326
  ]
326
327
 
327
328
  def spec(self):
@@ -346,11 +347,32 @@ class CqlSpec(SqlSpec):
346
347
  'alter_table_with_ > name > alter_table_with_p ^ table-props',
347
348
  'alter_table_with_p > comparison > alter_table_with_p_op ^ =',
348
349
  'alter_table_with_p_op > name|single|num > alter_table_with_p_op ^ table-prop-values',
350
+
351
+ ' > describe > describe',
352
+ 'describe_ > table > desc_table ^ table,`tables`,keyspace,keyspaces,schema',
353
+ '- > tables > desc_tables',
354
+ '- > keyspace > desc_keyspace',
355
+ '- > keyspaces > desc_keyspaces',
356
+ '- > schema > desc_schema',
357
+ 'desc_table_ > name > desc_table_t ^ tables',
358
+ 'desc_table_t > name > desc_table_t ^ tables',
359
+ 'desc_table_t_ > & > desc_table_t_bg ^ &',
360
+ 'desc_tables_ > & > desc_tables_bg ^ &',
361
+ 'desc_keyspace_ > name > desc_keyspace_k',
362
+ 'desc_keyspace_k_ > & > desc_keyspace_k_bg ^ &',
363
+ 'desc_schema_ > & > desc_schema_bg ^ &',
364
+ ]
365
+
366
+ KEYWORDS = SqlSpec.KEYWORDS + [
367
+ 'schema', 'keyspace', 'keyspaces', 'tables'
349
368
  ]
350
369
 
351
370
  def spec(self):
352
371
  return CqlSpec.SPEC
353
372
 
373
+ def keywords(self):
374
+ return CqlSpec.KEYWORDS
375
+
354
376
  class AthenaSpec(SqlSpec):
355
377
  SPEC = SqlSpec.SPEC + [
356
378
  'alter_table_t_ > add > alter_table_add ^ add partition,drop partition',
@@ -362,6 +384,11 @@ class AthenaSpec(SqlSpec):
362
384
  'alter_partition_lp_a_op > single > alter_partition_lp_a_op_v ^ single',
363
385
  'alter_partition_lp_a_op_v > , > alter_partition_lp_sc ^ single',
364
386
  'alter_partition_lp_sc > name|) > alter_partition_lp_a ^ partition-columns',
387
+
388
+ ' > describe > describe',
389
+ 'describe_ > name > desc_t ^ tables',
390
+ 'desc_t > name > desc_t ^ tables',
391
+ 'desc_t_ > name > desc_t_',
365
392
  ]
366
393
 
367
394
  KEYWORDS = SqlSpec.KEYWORDS + [
@@ -14,12 +14,12 @@ T = TypeVar('T')
14
14
  # utility collection on cassandra clusters; methods are all static
15
15
  class CassandraClusters:
16
16
  def exec(statefulset: str, namespace: str, command: str, action: str = 'action',
17
- max_workers=0, show_out=True, on_any = False, shell = '/bin/sh') -> list[PodExecResult]:
17
+ max_workers=0, show_out=True, on_any = False, shell = '/bin/sh', background = False) -> list[PodExecResult]:
18
18
  def body(executor: ThreadPoolExecutor, pod: str, namespace: str, show_out: bool):
19
19
  if executor:
20
- return executor.submit(CassandraNodes.exec, pod, namespace, command, False, False, shell)
20
+ return executor.submit(CassandraNodes.exec, pod, namespace, command, False, False, shell, background)
21
21
 
22
- return CassandraNodes.exec(pod, namespace, command, show_out=show_out)
22
+ return CassandraNodes.exec(pod, namespace, command, show_out=show_out, background=background)
23
23
 
24
24
  def post(result, show_out: bool):
25
25
  if KubeContext.show_out(show_out):
@@ -31,4 +31,4 @@ class CassandraClusters:
31
31
 
32
32
  return result
33
33
 
34
- return StatefulSets.on_cluster(statefulset, namespace, body, post=post, action=action, max_workers=max_workers, show_out=show_out, on_any=on_any)
34
+ return StatefulSets.on_cluster(statefulset, namespace, body, post=post, action=action, max_workers=max_workers, show_out=show_out, on_any=on_any, background=background)
@@ -6,8 +6,8 @@ from adam.repl_session import ReplSession
6
6
 
7
7
  # utility collection on cassandra nodes; methods are all static
8
8
  class CassandraNodes:
9
- def exec(pod_name: str, namespace: str, command: str, show_out = True, throw_err = False, shell = '/bin/sh') -> PodExecResult:
10
- r = Pods.exec(pod_name, "cassandra", namespace, command, show_out = show_out, throw_err = throw_err, shell = shell)
9
+ def exec(pod_name: str, namespace: str, command: str, show_out = True, throw_err = False, shell = '/bin/sh', background = False) -> PodExecResult:
10
+ r = Pods.exec(pod_name, "cassandra", namespace, command, show_out = show_out, throw_err = throw_err, shell = shell, background = background)
11
11
 
12
12
  if r and Config().get('repl.history.push-cat-remote-log-file', True):
13
13
  if r.log_file:
@@ -43,7 +43,11 @@ class Pods:
43
43
  namespace: str,
44
44
  body: Callable[[ThreadPoolExecutor, str, str, bool], T],
45
45
  post: Callable[[T], T] = None,
46
- action: str = 'action', max_workers=0, show_out=True, on_any = False) -> list[T]:
46
+ action: str = 'action',
47
+ max_workers=0,
48
+ show_out=True,
49
+ on_any = False,
50
+ background = False) -> list[T]:
47
51
  show_out = KubeContext.show_out(show_out)
48
52
 
49
53
  if not max_workers:
@@ -94,7 +98,9 @@ class Pods:
94
98
 
95
99
  return results
96
100
 
97
- def exec(pod_name: str, container: str, namespace: str, command: str, show_out = True, throw_err = False, shell = '/bin/sh',
101
+ def exec(pod_name: str, container: str, namespace: str, command: str,
102
+ show_out = True, throw_err = False, shell = '/bin/sh',
103
+ background = False,
98
104
  interaction: Callable[[any, list[str]], any] = None):
99
105
  if _TEST_POD_EXEC_OUTS:
100
106
  return _TEST_POD_EXEC_OUTS
@@ -106,8 +112,8 @@ class Pods:
106
112
  log_file = None
107
113
  tty = True
108
114
  exec_command = [shell, '-c', command]
109
- if command.endswith(' &'):
110
- # should be false for starting a backgroud process
115
+ if background or command.endswith(' &'):
116
+ # should be false for starting a background process
111
117
  tty = False
112
118
 
113
119
  if Config().get('repl.background-process.auto-nohup', True):
@@ -62,10 +62,10 @@ class StatefulSets:
62
62
  namespace: str,
63
63
  body: Callable[[ThreadPoolExecutor, str, str, bool], T],
64
64
  post: Callable[[T], T] = None,
65
- action: str = 'action', max_workers=0, show_out=True, on_any = False) -> list[T]:
65
+ action: str = 'action', max_workers=0, show_out=True, on_any = False, background = False) -> list[T]:
66
66
  pods = StatefulSets.pod_names(statefulset, namespace)
67
67
 
68
- return Pods.on_pods(pods, namespace, body, post=post, action=action, max_workers=max_workers, show_out=show_out, on_any=on_any)
68
+ return Pods.on_pods(pods, namespace, body, post=post, action=action, max_workers=max_workers, show_out=show_out, on_any=on_any, background=background)
69
69
 
70
70
  @functools.lru_cache()
71
71
  def pod_names(ss: str, ns: str):
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ __version__ = "2.0.102" #: the working version
5
+ __release__ = "1.0.0" #: the release version