kaqing 2.0.29__tar.gz → 2.0.31__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.
Files changed (179) hide show
  1. {kaqing-2.0.29 → kaqing-2.0.31}/PKG-INFO +1 -1
  2. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/alter_tables.py +8 -27
  3. kaqing-2.0.31/adam/commands/cql_utils.py +112 -0
  4. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/cqlsh.py +7 -5
  5. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/deploy/deploy_pod.py +7 -2
  6. kaqing-2.0.31/adam/commands/describe/describe_keyspace.py +60 -0
  7. kaqing-2.0.31/adam/commands/describe/describe_keyspaces.py +50 -0
  8. kaqing-2.0.31/adam/commands/describe/describe_table.py +60 -0
  9. kaqing-2.0.31/adam/commands/describe/describe_tables.py +50 -0
  10. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/param_set.py +1 -1
  11. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/preview_table.py +14 -7
  12. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/reaper/reaper_session.py +1 -1
  13. {kaqing-2.0.29 → kaqing-2.0.31}/adam/config.py +10 -1
  14. {kaqing-2.0.29 → kaqing-2.0.31}/adam/k8s_utils/cassandra_clusters.py +1 -0
  15. {kaqing-2.0.29 → kaqing-2.0.31}/adam/k8s_utils/pods.py +3 -2
  16. {kaqing-2.0.29 → kaqing-2.0.31}/adam/repl.py +7 -7
  17. {kaqing-2.0.29 → kaqing-2.0.31}/adam/repl_commands.py +8 -3
  18. {kaqing-2.0.29 → kaqing-2.0.31}/adam/repl_state.py +22 -10
  19. kaqing-2.0.31/adam/sso/__init__.py +0 -0
  20. {kaqing-2.0.29 → kaqing-2.0.31}/adam/utils.py +13 -0
  21. kaqing-2.0.31/adam/version.py +5 -0
  22. {kaqing-2.0.29 → kaqing-2.0.31}/kaqing.egg-info/PKG-INFO +1 -1
  23. {kaqing-2.0.29 → kaqing-2.0.31}/kaqing.egg-info/SOURCES.txt +5 -0
  24. {kaqing-2.0.29 → kaqing-2.0.31}/setup.py +1 -1
  25. kaqing-2.0.29/adam/commands/cql_utils.py +0 -53
  26. kaqing-2.0.29/adam/version.py +0 -5
  27. {kaqing-2.0.29 → kaqing-2.0.31}/README +0 -0
  28. {kaqing-2.0.29 → kaqing-2.0.31}/adam/__init__.py +0 -0
  29. {kaqing-2.0.29 → kaqing-2.0.31}/adam/app_session.py +0 -0
  30. {kaqing-2.0.29 → kaqing-2.0.31}/adam/apps.py +0 -0
  31. {kaqing-2.0.29 → kaqing-2.0.31}/adam/batch.py +0 -0
  32. {kaqing-2.0.29 → kaqing-2.0.31}/adam/checks/__init__.py +0 -0
  33. {kaqing-2.0.29 → kaqing-2.0.31}/adam/checks/check.py +0 -0
  34. {kaqing-2.0.29 → kaqing-2.0.31}/adam/checks/check_context.py +0 -0
  35. {kaqing-2.0.29 → kaqing-2.0.31}/adam/checks/check_result.py +0 -0
  36. {kaqing-2.0.29 → kaqing-2.0.31}/adam/checks/check_utils.py +0 -0
  37. {kaqing-2.0.29 → kaqing-2.0.31}/adam/checks/compactionstats.py +0 -0
  38. {kaqing-2.0.29 → kaqing-2.0.31}/adam/checks/cpu.py +0 -0
  39. {kaqing-2.0.29 → kaqing-2.0.31}/adam/checks/disk.py +0 -0
  40. {kaqing-2.0.29 → kaqing-2.0.31}/adam/checks/gossip.py +0 -0
  41. {kaqing-2.0.29 → kaqing-2.0.31}/adam/checks/issue.py +0 -0
  42. {kaqing-2.0.29 → kaqing-2.0.31}/adam/checks/memory.py +0 -0
  43. {kaqing-2.0.29 → kaqing-2.0.31}/adam/checks/status.py +0 -0
  44. {kaqing-2.0.29 → kaqing-2.0.31}/adam/cli.py +0 -0
  45. {kaqing-2.0.29 → kaqing-2.0.31}/adam/cli_group.py +0 -0
  46. {kaqing-2.0.29 → kaqing-2.0.31}/adam/columns/__init__.py +0 -0
  47. {kaqing-2.0.29 → kaqing-2.0.31}/adam/columns/column.py +0 -0
  48. {kaqing-2.0.29 → kaqing-2.0.31}/adam/columns/columns.py +0 -0
  49. {kaqing-2.0.29 → kaqing-2.0.31}/adam/columns/compactions.py +0 -0
  50. {kaqing-2.0.29 → kaqing-2.0.31}/adam/columns/cpu.py +0 -0
  51. {kaqing-2.0.29 → kaqing-2.0.31}/adam/columns/dir_data.py +0 -0
  52. {kaqing-2.0.29 → kaqing-2.0.31}/adam/columns/dir_snapshots.py +0 -0
  53. {kaqing-2.0.29 → kaqing-2.0.31}/adam/columns/gossip.py +0 -0
  54. {kaqing-2.0.29 → kaqing-2.0.31}/adam/columns/host_id.py +0 -0
  55. {kaqing-2.0.29 → kaqing-2.0.31}/adam/columns/memory.py +0 -0
  56. {kaqing-2.0.29 → kaqing-2.0.31}/adam/columns/node_address.py +0 -0
  57. {kaqing-2.0.29 → kaqing-2.0.31}/adam/columns/node_load.py +0 -0
  58. {kaqing-2.0.29 → kaqing-2.0.31}/adam/columns/node_owns.py +0 -0
  59. {kaqing-2.0.29 → kaqing-2.0.31}/adam/columns/node_status.py +0 -0
  60. {kaqing-2.0.29 → kaqing-2.0.31}/adam/columns/node_tokens.py +0 -0
  61. {kaqing-2.0.29 → kaqing-2.0.31}/adam/columns/node_utils.py +0 -0
  62. {kaqing-2.0.29 → kaqing-2.0.31}/adam/columns/pod_name.py +0 -0
  63. {kaqing-2.0.29 → kaqing-2.0.31}/adam/columns/volume_cassandra.py +0 -0
  64. {kaqing-2.0.29 → kaqing-2.0.31}/adam/columns/volume_root.py +0 -0
  65. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/__init__.py +0 -0
  66. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/app.py +0 -0
  67. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/app_ping.py +0 -0
  68. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/bash.py +0 -0
  69. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/cd.py +0 -0
  70. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/check.py +0 -0
  71. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/cli_commands.py +0 -0
  72. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/command.py +0 -0
  73. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/command_helpers.py +0 -0
  74. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/commands_utils.py +0 -0
  75. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/cp.py +0 -0
  76. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/deploy/__init__.py +0 -0
  77. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/deploy/code_start.py +0 -0
  78. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/deploy/code_stop.py +0 -0
  79. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/deploy/code_utils.py +0 -0
  80. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/deploy/deploy.py +0 -0
  81. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/deploy/deploy_frontend.py +0 -0
  82. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/deploy/deploy_pg_agent.py +0 -0
  83. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/deploy/deploy_utils.py +0 -0
  84. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/deploy/undeploy.py +0 -0
  85. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/deploy/undeploy_frontend.py +0 -0
  86. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/deploy/undeploy_pg_agent.py +0 -0
  87. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/deploy/undeploy_pod.py +0 -0
  88. {kaqing-2.0.29/adam/commands/medusa → kaqing-2.0.31/adam/commands/describe}/__init__.py +0 -0
  89. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/devices.py +0 -0
  90. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/exit.py +0 -0
  91. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/help.py +0 -0
  92. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/issues.py +0 -0
  93. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/login.py +0 -0
  94. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/logs.py +0 -0
  95. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/ls.py +0 -0
  96. {kaqing-2.0.29/adam/commands/postgres → kaqing-2.0.31/adam/commands/medusa}/__init__.py +0 -0
  97. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/medusa/medusa.py +0 -0
  98. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/medusa/medusa_backup.py +0 -0
  99. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/medusa/medusa_restore.py +0 -0
  100. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/medusa/medusa_show_backupjobs.py +0 -0
  101. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/medusa/medusa_show_restorejobs.py +0 -0
  102. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/nodetool.py +0 -0
  103. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/nodetool_commands.py +0 -0
  104. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/param_get.py +0 -0
  105. {kaqing-2.0.29/adam/commands/reaper → kaqing-2.0.31/adam/commands/postgres}/__init__.py +0 -0
  106. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/postgres/postgres.py +0 -0
  107. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/postgres/postgres_ls.py +0 -0
  108. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/postgres/postgres_preview.py +0 -0
  109. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/postgres/postgres_session.py +0 -0
  110. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/pwd.py +0 -0
  111. {kaqing-2.0.29/adam/commands/repair → kaqing-2.0.31/adam/commands/reaper}/__init__.py +0 -0
  112. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/reaper/reaper.py +0 -0
  113. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/reaper/reaper_forward.py +0 -0
  114. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/reaper/reaper_forward_stop.py +0 -0
  115. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/reaper/reaper_restart.py +0 -0
  116. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/reaper/reaper_run_abort.py +0 -0
  117. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/reaper/reaper_runs.py +0 -0
  118. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/reaper/reaper_runs_abort.py +0 -0
  119. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/reaper/reaper_schedule_activate.py +0 -0
  120. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/reaper/reaper_schedule_start.py +0 -0
  121. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/reaper/reaper_schedule_stop.py +0 -0
  122. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/reaper/reaper_schedules.py +0 -0
  123. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/reaper/reaper_status.py +0 -0
  124. {kaqing-2.0.29/adam/commands/show → kaqing-2.0.31/adam/commands/repair}/__init__.py +0 -0
  125. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/repair/repair.py +0 -0
  126. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/repair/repair_log.py +0 -0
  127. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/repair/repair_run.py +0 -0
  128. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/repair/repair_scan.py +0 -0
  129. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/repair/repair_stop.py +0 -0
  130. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/report.py +0 -0
  131. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/restart.py +0 -0
  132. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/rollout.py +0 -0
  133. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/shell.py +0 -0
  134. {kaqing-2.0.29/adam/k8s_utils → kaqing-2.0.31/adam/commands/show}/__init__.py +0 -0
  135. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/show/show.py +0 -0
  136. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/show/show_adam.py +0 -0
  137. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/show/show_app_actions.py +0 -0
  138. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/show/show_app_id.py +0 -0
  139. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/show/show_app_queues.py +0 -0
  140. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/show/show_cassandra_status.py +0 -0
  141. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/show/show_cassandra_version.py +0 -0
  142. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/show/show_commands.py +0 -0
  143. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/show/show_login.py +0 -0
  144. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/show/show_params.py +0 -0
  145. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/show/show_processes.py +0 -0
  146. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/show/show_repairs.py +0 -0
  147. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/show/show_storage.py +0 -0
  148. {kaqing-2.0.29 → kaqing-2.0.31}/adam/commands/watch.py +0 -0
  149. {kaqing-2.0.29 → kaqing-2.0.31}/adam/embedded_apps.py +0 -0
  150. {kaqing-2.0.29 → kaqing-2.0.31}/adam/embedded_params.py +0 -0
  151. {kaqing-2.0.29/adam/sso → kaqing-2.0.31/adam/k8s_utils}/__init__.py +0 -0
  152. {kaqing-2.0.29 → kaqing-2.0.31}/adam/k8s_utils/cassandra_nodes.py +0 -0
  153. {kaqing-2.0.29 → kaqing-2.0.31}/adam/k8s_utils/config_maps.py +0 -0
  154. {kaqing-2.0.29 → kaqing-2.0.31}/adam/k8s_utils/custom_resources.py +0 -0
  155. {kaqing-2.0.29 → kaqing-2.0.31}/adam/k8s_utils/deployment.py +0 -0
  156. {kaqing-2.0.29 → kaqing-2.0.31}/adam/k8s_utils/ingresses.py +0 -0
  157. {kaqing-2.0.29 → kaqing-2.0.31}/adam/k8s_utils/jobs.py +0 -0
  158. {kaqing-2.0.29 → kaqing-2.0.31}/adam/k8s_utils/kube_context.py +0 -0
  159. {kaqing-2.0.29 → kaqing-2.0.31}/adam/k8s_utils/secrets.py +0 -0
  160. {kaqing-2.0.29 → kaqing-2.0.31}/adam/k8s_utils/service_accounts.py +0 -0
  161. {kaqing-2.0.29 → kaqing-2.0.31}/adam/k8s_utils/services.py +0 -0
  162. {kaqing-2.0.29 → kaqing-2.0.31}/adam/k8s_utils/statefulsets.py +0 -0
  163. {kaqing-2.0.29 → kaqing-2.0.31}/adam/k8s_utils/volumes.py +0 -0
  164. {kaqing-2.0.29 → kaqing-2.0.31}/adam/log.py +0 -0
  165. {kaqing-2.0.29 → kaqing-2.0.31}/adam/pod_exec_result.py +0 -0
  166. {kaqing-2.0.29 → kaqing-2.0.31}/adam/repl_session.py +0 -0
  167. {kaqing-2.0.29 → kaqing-2.0.31}/adam/sso/authenticator.py +0 -0
  168. {kaqing-2.0.29 → kaqing-2.0.31}/adam/sso/authn_ad.py +0 -0
  169. {kaqing-2.0.29 → kaqing-2.0.31}/adam/sso/authn_okta.py +0 -0
  170. {kaqing-2.0.29 → kaqing-2.0.31}/adam/sso/cred_cache.py +0 -0
  171. {kaqing-2.0.29 → kaqing-2.0.31}/adam/sso/id_token.py +0 -0
  172. {kaqing-2.0.29 → kaqing-2.0.31}/adam/sso/idp.py +0 -0
  173. {kaqing-2.0.29 → kaqing-2.0.31}/adam/sso/idp_login.py +0 -0
  174. {kaqing-2.0.29 → kaqing-2.0.31}/adam/sso/idp_session.py +0 -0
  175. {kaqing-2.0.29 → kaqing-2.0.31}/adam/sso/sso_config.py +0 -0
  176. {kaqing-2.0.29 → kaqing-2.0.31}/kaqing.egg-info/dependency_links.txt +0 -0
  177. {kaqing-2.0.29 → kaqing-2.0.31}/kaqing.egg-info/entry_points.txt +0 -0
  178. {kaqing-2.0.29 → kaqing-2.0.31}/kaqing.egg-info/top_level.txt +0 -0
  179. {kaqing-2.0.29 → kaqing-2.0.31}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: kaqing
3
- Version: 2.0.29
3
+ Version: 2.0.31
4
4
  Summary: UNKNOWN
5
5
  Home-page: UNKNOWN
6
6
  License: UNKNOWN
@@ -1,12 +1,9 @@
1
- import click
2
-
3
1
  from adam.commands.command import Command
4
- from adam.commands.command_helpers import ClusterOrPodCommandHelper
5
- from adam.commands.cql_utils import parse_cql_desc_tables, run_cql
2
+ from adam.commands.cql_utils import tables as get_tables, run_cql
6
3
  from adam.config import Config
7
4
  from adam.pod_exec_result import PodExecResult
8
5
  from adam.repl_state import ReplState, RequiredState
9
- from adam.utils import log, log2
6
+ from adam.utils import log2
10
7
 
11
8
  class AlterTables(Command):
12
9
  COMMAND = 'alter tables with'
@@ -47,16 +44,16 @@ class AlterTables(Command):
47
44
  args, include_reaper = Command.extract_options(args, '--include-reaper')
48
45
  arg_str = ' '.join(args)
49
46
 
50
- r: list[PodExecResult] = run_cql(state, 'describe tables', show_out=False, on_any=True)
51
- if not r:
52
- log2('No pod is available')
53
- return 'no-pod'
47
+ # r: list[PodExecResult] = run_cql(state, 'describe tables', show_out=False, on_any=True)
48
+ # if not r:
49
+ # log2('No pod is available')
50
+ # return 'no-pod'
54
51
 
55
52
  excludes = [e.strip(' \r\n') for e in Config().get(
56
53
  'cql.alter-tables.excludes',
57
54
  'system_auth,system_traces,reaper_db,system_distributed,system_views,system,system_schema,system_virtual_schema').split(',')]
58
55
  batching = Config().get('cql.alter-tables.batching', True)
59
- tables = parse_cql_desc_tables(r[0].stdout)
56
+ tables = get_tables(state, on_any=True)
60
57
  for k, v in tables.items():
61
58
  if k not in excludes or k == 'reaper_db' and include_reaper:
62
59
  if batching:
@@ -92,20 +89,4 @@ class AlterTables(Command):
92
89
  return {}
93
90
 
94
91
  def help(self, _: ReplState) -> str:
95
- return f'[{AlterTables.COMMAND}] <param = value> [--include-reaper] \t alter on all tables'
96
-
97
- class CqlCommandHelper(click.Command):
98
- def get_help(self, ctx: click.Context):
99
- log(super().get_help(ctx))
100
- log()
101
- log(' e.g. qing cql <cluster or pod> select host_id from system.local')
102
- log()
103
- log('Advanced Usages:')
104
- log(' 1. Use -- to specify what arguments are passed to the cqlsh.')
105
- log(' 2. Use "" to avoid expansion on shell variables.')
106
- log(' 3. Use ; to use multiple CQL statements')
107
- log()
108
- log(' e.g. qing cql <cluster or pod> -- "consistency quorum; select * from system.local" --request-timeout=3600')
109
- log()
110
-
111
- ClusterOrPodCommandHelper.cluter_or_pod_help()
92
+ return f'{AlterTables.COMMAND} <param = value> [--include-reaper] \t alter on all tables'
@@ -0,0 +1,112 @@
1
+ import functools
2
+ import re
3
+
4
+ from adam.config import Config
5
+ from adam.k8s_utils.cassandra_clusters import CassandraClusters
6
+ from adam.k8s_utils.cassandra_nodes import CassandraNodes
7
+ from adam.k8s_utils.secrets import Secrets
8
+ from adam.pod_exec_result import PodExecResult
9
+ from adam.repl_state import ReplState
10
+ from adam.utils import log2
11
+
12
+ @functools.lru_cache()
13
+ def keyspaces(sts: str, namespace: str):
14
+ Config().wait_log("Inspecting Cassandra Keyspaces...")
15
+
16
+ user, pw = Secrets.get_user_pass(sts, namespace, secret_path='cql.secret')
17
+ command = f'cqlsh -u {user} -p {pw} -e "describe keyspaces"'
18
+
19
+ r: list[PodExecResult] = CassandraClusters.exec(sts, namespace, command, show_out=False, action='cql', on_any=True)
20
+ if not r:
21
+ log2('No pod is available')
22
+ return []
23
+
24
+ return parse_cql_desc_keyspaces(r[0].stdout)
25
+
26
+ def table_names(state: ReplState):
27
+ return [f'{k}.{t}' for k, ts in tables(state, on_any=True).items() for t in ts]
28
+
29
+ @functools.lru_cache()
30
+ def tables(state: ReplState, on_any=False):
31
+ r: list[PodExecResult] = run_cql(state, 'describe tables', show_out=False, on_any=on_any)
32
+ if not r:
33
+ log2('No pod is available')
34
+ return []
35
+
36
+ return parse_cql_desc_tables(r[0].stdout)
37
+
38
+ def run_cql(state: ReplState, cql: str, opts: list = [], show_out = False, use_single_quotes = False, on_any = False):
39
+ user, pw = Secrets.get_user_pass(state.sts if state.sts else state.pod, state.namespace, secret_path='cql.secret')
40
+ if use_single_quotes:
41
+ command = f"cqlsh -u {user} -p {pw} {' '.join(opts)} -e '{cql}'"
42
+ else:
43
+ command = f'cqlsh -u {user} -p {pw} {" ".join(opts)} -e "{cql}"'
44
+
45
+ if state.pod:
46
+ return CassandraNodes.exec(state.pod, state.namespace, command, show_out=show_out)
47
+ else:
48
+ return CassandraClusters.exec(state.sts, state.namespace, command, show_out=show_out, action='cql', on_any=on_any)
49
+
50
+ def parse_cql_desc_tables(out: str):
51
+ # Keyspace data_endpoint_auth
52
+ # ---------------------------
53
+ # "token"
54
+
55
+ # Keyspace reaper_db
56
+ # ------------------
57
+ # repair_run schema_migration
58
+ # repair_run_by_cluster schema_migration_leader
59
+
60
+ # Keyspace system
61
+ tables_by_keyspace: dict[str, list[str]] = {}
62
+ keyspace = None
63
+ state = 's0'
64
+ for line in out.split('\n'):
65
+ if state == 's0':
66
+ groups = re.match(r'^Keyspace (.*)$', line)
67
+ if groups:
68
+ keyspace = groups[1].strip(' \r')
69
+ state = 's1'
70
+ elif state == 's1':
71
+ if line.startswith('---'):
72
+ state = 's2'
73
+ elif state == 's2':
74
+ if not line.strip(' \r'):
75
+ state = 's0'
76
+ else:
77
+ for table in line.split(' '):
78
+ if t := table.strip(' \r'):
79
+ if not keyspace in tables_by_keyspace:
80
+ tables_by_keyspace[keyspace] = []
81
+ tables_by_keyspace[keyspace].append(t)
82
+
83
+ return tables_by_keyspace
84
+
85
+ def parse_cql_desc_keyspaces(out: str) -> list[str]:
86
+ #
87
+ # Warning: Cannot create directory at `/home/cassandra/.cassandra`. Command history will not be saved. Please check what was the environment property CQL_HISTORY set to.
88
+ #
89
+ #
90
+ # Warning: Using a password on the command line interface can be insecure.
91
+ # Recommendation: use the credentials file to securely provide the password.
92
+ #
93
+ #
94
+ # azops88_db system_auth system_traces
95
+ # reaper_db system_distributed system_views
96
+ # system system_schema system_virtual_schema
97
+ #
98
+ kses = []
99
+ for line in out.split('\n'):
100
+ line = line.strip(' \r')
101
+ if not line:
102
+ continue
103
+ if line.startswith('Warning:'):
104
+ continue
105
+ if line.startswith('Recommendation:'):
106
+ continue
107
+
108
+ for ks in line.split(' '):
109
+ if s := ks.strip(' \r\t'):
110
+ kses.append(s)
111
+
112
+ return kses
@@ -2,7 +2,7 @@ import click
2
2
 
3
3
  from adam.commands.command import Command
4
4
  from adam.commands.command_helpers import ClusterOrPodCommandHelper
5
- from adam.commands.cql_utils import run_cql
5
+ from adam.commands.cql_utils import run_cql, table_names, tables
6
6
  from adam.repl_state import ReplState, RequiredState
7
7
  from adam.utils import log, log2
8
8
 
@@ -54,11 +54,13 @@ class Cqlsh(Command):
54
54
 
55
55
  def completion(self, state: ReplState) -> dict[str, any]:
56
56
  if state.sts or state.pod:
57
+ ts = table_names(state)
57
58
  return {Cqlsh.COMMAND: None} | {
58
- 'delete': {'from': None},
59
- 'insert': {'into': None},
60
- 'select': None,
61
- 'update': None,
59
+ 'delete': {'from': {t: {'where': None} for t in ts}},
60
+ 'insert': {'into': {t: {'values': None} for t in ts}},
61
+ 'select': {'*': {'from': {t: {'limit': {'1': None}, 'where': None} for t in ts}}},
62
+ 'update': {t: {'set': None} for t in ts},
63
+ 'describe': {'keyspaces': None, 'table': {t: None for t in ts}, 'tables': None},
62
64
  }
63
65
 
64
66
  return {}
@@ -3,6 +3,7 @@ import yaml
3
3
 
4
4
  from adam.commands.command import Command
5
5
  from adam.commands.deploy.deploy_utils import creating, deploy_frontend, gen_labels
6
+ from adam.commands.deploy.undeploy_pod import UndeployPod
6
7
  from adam.config import Config
7
8
  from adam.k8s_utils.config_maps import ConfigMaps
8
9
  from adam.k8s_utils.deployment import Deployments
@@ -39,6 +40,10 @@ class DeployPod(Command):
39
40
  if not self.validate_state(state):
40
41
  return state
41
42
 
43
+ args, forced = Command.extract_options(args, '--force')
44
+ if forced:
45
+ UndeployPod().run(UndeployPod.COMMAND, state)
46
+
42
47
  if KubeContext.in_cluster():
43
48
  log2('This is doable only from outside of the Kubernetes cluster.')
44
49
  return state
@@ -103,7 +108,7 @@ class DeployPod(Command):
103
108
  return state
104
109
 
105
110
  def completion(self, state: ReplState):
106
- return super().completion(state)
111
+ return super().completion(state, {'--force': None})
107
112
 
108
113
  def help(self, _: ReplState):
109
- return f'{DeployPod.COMMAND}\t deploy Ops pod'
114
+ return f'{DeployPod.COMMAND} [--force]\t deploy Ops pod, --force to undeploy first'
@@ -0,0 +1,60 @@
1
+ from adam.commands.command import Command
2
+ from adam.commands.cql_utils import keyspaces, run_cql
3
+ from adam.pod_exec_result import PodExecResult
4
+ from adam.repl_state import ReplState, RequiredState
5
+ from adam.utils import log2
6
+
7
+ class DescribeKeyspace(Command):
8
+ COMMAND = 'describe keyspace'
9
+
10
+ # the singleton pattern
11
+ def __new__(cls, *args, **kwargs):
12
+ if not hasattr(cls, 'instance'): cls.instance = super(DescribeKeyspace, cls).__new__(cls)
13
+
14
+ return cls.instance
15
+
16
+ def __init__(self, successor: Command=None):
17
+ super().__init__(successor)
18
+
19
+ def required(self):
20
+ return RequiredState.CLUSTER
21
+
22
+ def command(self):
23
+ return DescribeKeyspace.COMMAND
24
+
25
+ def run(self, cmd: str, state: ReplState):
26
+ if not(args := self.args(cmd)):
27
+ return super().run(cmd, state)
28
+
29
+ state, args = self.apply_state(args, state)
30
+ if not self.validate_state(state):
31
+ return state
32
+
33
+ args, all_nodes = Command.extract_options(args, '--all-nodes')
34
+
35
+ if not args:
36
+ if state.in_repl:
37
+ log2('Please enter keyspace name')
38
+ else:
39
+ log2('* keyspace name is missing.')
40
+ log2()
41
+ Command.display_help()
42
+
43
+ return 'missing-keyspace'
44
+
45
+ r: list[PodExecResult] = run_cql(state, f'describe keyspace {args[0]}', show_out=True, on_any=not all_nodes)
46
+ if not r:
47
+ log2('No pod is available')
48
+ return 'no-pod'
49
+
50
+ # do not continue to cql route
51
+ return state
52
+
53
+ def completion(self, state: ReplState) -> dict[str, any]:
54
+ if state.sts:
55
+ return super().completion(state, {ks: {'--all-nodes': None} for ks in keyspaces(state.sts, state.namespace)})
56
+
57
+ return {}
58
+
59
+ def help(self, _: ReplState) -> str:
60
+ return f'{DescribeKeyspace.COMMAND} <keyspace-name> [--all-nodes]\t describe Cassandra keyspace'
@@ -0,0 +1,50 @@
1
+ from adam.commands.command import Command
2
+ from adam.commands.cql_utils import keyspaces, run_cql
3
+ from adam.pod_exec_result import PodExecResult
4
+ from adam.repl_state import ReplState, RequiredState
5
+ from adam.utils import log2
6
+
7
+ class DescribeKeyspaces(Command):
8
+ COMMAND = 'describe keyspaces'
9
+
10
+ # the singleton pattern
11
+ def __new__(cls, *args, **kwargs):
12
+ if not hasattr(cls, 'instance'): cls.instance = super(DescribeKeyspaces, cls).__new__(cls)
13
+
14
+ return cls.instance
15
+
16
+ def __init__(self, successor: Command=None):
17
+ super().__init__(successor)
18
+
19
+ def required(self):
20
+ return RequiredState.CLUSTER
21
+
22
+ def command(self):
23
+ return DescribeKeyspaces.COMMAND
24
+
25
+ def run(self, cmd: str, state: ReplState):
26
+ if not(args := self.args(cmd)):
27
+ return super().run(cmd, state)
28
+
29
+ state, args = self.apply_state(args, state)
30
+ if not self.validate_state(state):
31
+ return state
32
+
33
+ _, all_nodes = Command.extract_options(args, '--all-nodes')
34
+
35
+ r: list[PodExecResult] = run_cql(state, f'describe keyspaces', show_out=True, on_any=not all_nodes)
36
+ if not r:
37
+ log2('No pod is available')
38
+ return 'no-pod'
39
+
40
+ # do not continue to cql route
41
+ return state
42
+
43
+ def completion(self, state: ReplState) -> dict[str, any]:
44
+ if state.sts:
45
+ return super().completion(state, {'--all-nodes': None})
46
+
47
+ return {}
48
+
49
+ def help(self, _: ReplState) -> str:
50
+ return f'{DescribeKeyspaces.COMMAND} [--all-nodes]\t describe Cassandra keyspaces'
@@ -0,0 +1,60 @@
1
+ from adam.commands.command import Command
2
+ from adam.commands.cql_utils import keyspaces, run_cql, table_names, tables
3
+ from adam.pod_exec_result import PodExecResult
4
+ from adam.repl_state import ReplState, RequiredState
5
+ from adam.utils import log2
6
+
7
+ class DescribeTable(Command):
8
+ COMMAND = 'describe table'
9
+
10
+ # the singleton pattern
11
+ def __new__(cls, *args, **kwargs):
12
+ if not hasattr(cls, 'instance'): cls.instance = super(DescribeTable, cls).__new__(cls)
13
+
14
+ return cls.instance
15
+
16
+ def __init__(self, successor: Command=None):
17
+ super().__init__(successor)
18
+
19
+ def required(self):
20
+ return RequiredState.CLUSTER
21
+
22
+ def command(self):
23
+ return DescribeTable.COMMAND
24
+
25
+ def run(self, cmd: str, state: ReplState):
26
+ if not(args := self.args(cmd)):
27
+ return super().run(cmd, state)
28
+
29
+ state, args = self.apply_state(args, state)
30
+ if not self.validate_state(state):
31
+ return state
32
+
33
+ args, all_nodes = Command.extract_options(args, '--all-nodes')
34
+
35
+ if not args:
36
+ if state.in_repl:
37
+ log2('Please enter table name')
38
+ else:
39
+ log2('* table name is missing.')
40
+ log2()
41
+ Command.display_help()
42
+
43
+ return 'missing-table'
44
+
45
+ r: list[PodExecResult] = run_cql(state, f'describe table {args[0]}', show_out=True, on_any=not all_nodes)
46
+ if not r:
47
+ log2('No pod is available')
48
+ return 'no-pod'
49
+
50
+ # do not continue to cql route
51
+ return state
52
+
53
+ def completion(self, state: ReplState) -> dict[str, any]:
54
+ if state.sts:
55
+ return super().completion(state, {t: {'--all-nodes': None} for t in table_names(state)})
56
+
57
+ return {}
58
+
59
+ def help(self, _: ReplState) -> str:
60
+ return f'{DescribeTable.COMMAND} <table-name> [--all-nodes]\t describe Cassandra table'
@@ -0,0 +1,50 @@
1
+ from adam.commands.command import Command
2
+ from adam.commands.cql_utils import keyspaces, run_cql, table_names, tables
3
+ from adam.pod_exec_result import PodExecResult
4
+ from adam.repl_state import ReplState, RequiredState
5
+ from adam.utils import log2
6
+
7
+ class DescribeTables(Command):
8
+ COMMAND = 'describe tables'
9
+
10
+ # the singleton pattern
11
+ def __new__(cls, *args, **kwargs):
12
+ if not hasattr(cls, 'instance'): cls.instance = super(DescribeTables, cls).__new__(cls)
13
+
14
+ return cls.instance
15
+
16
+ def __init__(self, successor: Command=None):
17
+ super().__init__(successor)
18
+
19
+ def required(self):
20
+ return RequiredState.CLUSTER
21
+
22
+ def command(self):
23
+ return DescribeTables.COMMAND
24
+
25
+ def run(self, cmd: str, state: ReplState):
26
+ if not(args := self.args(cmd)):
27
+ return super().run(cmd, state)
28
+
29
+ state, args = self.apply_state(args, state)
30
+ if not self.validate_state(state):
31
+ return state
32
+
33
+ _, all_nodes = Command.extract_options(args, '--all-nodes')
34
+
35
+ r: list[PodExecResult] = run_cql(state, f'describe tables', show_out=True, on_any=not all_nodes)
36
+ if not r:
37
+ log2('No pod is available')
38
+ return 'no-pod'
39
+
40
+ # do not continue to cql route
41
+ return state
42
+
43
+ def completion(self, state: ReplState) -> dict[str, any]:
44
+ if state.sts:
45
+ return super().completion(state, {'--all-nodes': None})
46
+
47
+ return {}
48
+
49
+ def help(self, _: ReplState) -> str:
50
+ return f'{DescribeTables.COMMAND} [--all-nodes]\t describe Cassandra tables'
@@ -38,7 +38,7 @@ class SetParam(Command):
38
38
  return value
39
39
 
40
40
  def completion(self, _: ReplState):
41
- return {SetParam.COMMAND: {key: ({'true': None, 'false': None} if key.startswith('debug') else None) for key in Config().keys()}}
41
+ return {SetParam.COMMAND: {key: ({'true': None, 'false': None} if Config().get(key, None) in [True, False] else None) for key in Config().keys()}}
42
42
 
43
43
  def help(self, _: ReplState):
44
44
  return f"{SetParam.COMMAND} <key> <value>\t sets a Kaqing parameter to a different value"
@@ -1,7 +1,7 @@
1
1
  import functools
2
2
 
3
3
  from adam.commands.command import Command
4
- from adam.commands.cql_utils import parse_cql_desc_tables, run_cql
4
+ from adam.commands.cql_utils import run_cql, tables
5
5
  from adam.commands.postgres.postgres_session import PostgresSession
6
6
  from adam.config import Config
7
7
  from adam.pod_exec_result import PodExecResult
@@ -74,10 +74,9 @@ class PreviewTable(Command):
74
74
  if state.device == ReplState.P:
75
75
  if tables := PreviewTable.pg_tables(state.namespace, state.pg_path):
76
76
  return {PreviewTable.COMMAND: {db["name"]: None for db in tables if db["schema"] == PostgresSession.default_schema()}}
77
- else:
78
- if state.pod:
79
- tables = PreviewTable.cql_tables(state)
80
- return {PreviewTable.COMMAND: {f'{k}.{t}': None for k, ts in tables.items() for t in ts}}
77
+ elif state.sts:
78
+ tables = PreviewTable.cql_tables(state)
79
+ return {PreviewTable.COMMAND: {f'{k}.{t}': None for k, ts in tables.items() for t in ts}}
81
80
 
82
81
  return {}
83
82
 
@@ -86,8 +85,16 @@ class PreviewTable(Command):
86
85
 
87
86
  @functools.lru_cache()
88
87
  def cql_tables(state: ReplState):
89
- r: PodExecResult = run_cql(state, 'describe tables', show_out=False)
90
- return parse_cql_desc_tables(r.stdout)
88
+ if state.pod:
89
+ return tables(state)
90
+
91
+ return tables(state, on_any=True)
92
+
93
+ # r: list[PodExecResult] = run_cql(state, 'describe tables', show_out=False, on_any=True)
94
+ # if not r:
95
+ # return []
96
+
97
+ # return parse_cql_desc_tables(r[0].stdout)
91
98
 
92
99
  @functools.lru_cache()
93
100
  def pg_tables(ns: str, pg_path: str):
@@ -149,7 +149,7 @@ class ReaperSession:
149
149
  return ReaperSession.schedules_ids_by_cluster[state.sts]
150
150
 
151
151
  if reaper := ReaperSession.create(state):
152
- state.wait_log("Inspecting Cassandra Reaper...")
152
+ Config().wait_log("Inspecting Cassandra Reaper...")
153
153
 
154
154
  schedules = reaper.schedule_ids(state, show_output = False)
155
155
  ReaperSession.schedules_ids_by_cluster[state.sts] = schedules
@@ -17,6 +17,7 @@ class Config:
17
17
 
18
18
  def __init__(self, path: str = None, is_user_entry = False):
19
19
  if path:
20
+ self.wait_log_flag = False
20
21
  try:
21
22
  with open(path) as f:
22
23
  self.params = cast(dict[str, any], yaml.safe_load(f))
@@ -83,4 +84,12 @@ class Config:
83
84
  log2(f'incorrect path: {key}')
84
85
  return None
85
86
 
86
- return v if v else 'false'
87
+ return v if v else 'false'
88
+
89
+ def wait_log(self, msg: str):
90
+ if not self.wait_log_flag:
91
+ log2(msg)
92
+ self.wait_log_flag = True
93
+
94
+ def clear_wait_log_flag(self):
95
+ self.wait_log_flag = False
@@ -3,6 +3,7 @@ from concurrent.futures import ThreadPoolExecutor
3
3
  import sys
4
4
  from typing import TypeVar
5
5
 
6
+ from adam.config import Config
6
7
  from adam.k8s_utils.cassandra_nodes import CassandraNodes
7
8
  from adam.pod_exec_result import PodExecResult
8
9
  from adam.utils import log2
@@ -47,7 +47,7 @@ class Pods:
47
47
 
48
48
  if not max_workers:
49
49
  max_workers = Config().action_workers(action, 0)
50
- if not on_any and max_workers > 0:
50
+ if not on_any and max_workers > 0:
51
51
  # if parallel, node sampling is suppressed
52
52
  if KubeContext.show_parallelism():
53
53
  log2(f'Executing on all nodes from statefulset in parallel...')
@@ -79,7 +79,8 @@ class Pods:
79
79
  log2(f'Executing on {adj} nodes from statefulset...')
80
80
  for pod_name in pods:
81
81
  try:
82
- result = body(None, pod_name, namespace, show_out)
82
+ # disable stdout from the pod_exec, then show the output in a for loop
83
+ result = body(None, pod_name, namespace, False)
83
84
  if post:
84
85
  result = post(result, show_out=show_out)
85
86
  results.append(result)
@@ -18,7 +18,7 @@ from adam.log import Log
18
18
  from adam.repl_commands import ReplCommands
19
19
  from adam.repl_session import ReplSession
20
20
  from adam.repl_state import ReplState
21
- from adam.utils import deep_merge_dicts, lines_to_tabular, log2
21
+ from adam.utils import deep_merge_dicts, deep_sort_dict, lines_to_tabular, log2
22
22
  from adam.apps import Apps
23
23
  from . import __version__
24
24
 
@@ -70,7 +70,7 @@ def enter_repl(state: ReplState):
70
70
  cluster = ss[0]
71
71
  state.sts = cluster[0]
72
72
  state.namespace = cluster[1]
73
- state.wait_log(f'Moving to the only Cassandra cluster: {state.sts}@{state.namespace}...')
73
+ Config().wait_log(f'Moving to the only Cassandra cluster: {state.sts}@{state.namespace}...')
74
74
  elif state.device == ReplState.A:
75
75
  if app := Config().get('repl.auto-enter-app', 'c3/c3'):
76
76
  if app != 'no':
@@ -78,9 +78,9 @@ def enter_repl(state: ReplState):
78
78
  state.app_env = ea[0]
79
79
  if len(ea) > 1:
80
80
  state.app_app = ea[1]
81
- state.wait_log(f'Moving to {state.app_env}/{state.app_app}...')
81
+ Config().wait_log(f'Moving to {state.app_env}/{state.app_app}...')
82
82
  else:
83
- state.wait_log(f'Moving to {state.app_env}...')
83
+ Config().wait_log(f'Moving to {state.app_env}...')
84
84
 
85
85
  kb = KeyBindings()
86
86
 
@@ -102,7 +102,7 @@ def enter_repl(state: ReplState):
102
102
  for cmd in sorted_cmds:
103
103
  s1 = time.time()
104
104
  try:
105
- completions = deep_merge_dicts(completions, cmd.completion(state))
105
+ completions = deep_sort_dict(deep_merge_dicts(completions, cmd.completion(state)))
106
106
  finally:
107
107
  if Config().get('debugs.timings', False):
108
108
  Config().debug('Timing completion calc', cmd.command(), f'{time.time() - s1:.2f}')
@@ -151,7 +151,7 @@ def enter_repl(state: ReplState):
151
151
  log2(e)
152
152
  Config().debug(traceback.format_exc())
153
153
  finally:
154
- state.clear_wait_log_flag()
154
+ Config().clear_wait_log_flag()
155
155
  if Config().get('debugs.timings', False) and 'cmd' in locals() and 's0' in locals():
156
156
  print('Timing command', cmd, f'{time.time() - s0:.2f}')
157
157
 
@@ -168,5 +168,5 @@ def repl(kubeconfig: str, config: str, param: list[str], cluster:str, namespace:
168
168
  return
169
169
 
170
170
  state = ReplState(device=Config().get('repl.start-drive', 'a'), ns_sts=cluster, namespace=namespace, in_repl=True)
171
- state, _ = state.apply_args(extra_args)
171
+ state, _ = state.apply_device_arg(extra_args)
172
172
  enter_repl(state)
@@ -11,6 +11,10 @@ from adam.commands.deploy.undeploy import Undeploy
11
11
  from adam.commands.deploy.undeploy_frontend import UndeployFrontend
12
12
  from adam.commands.deploy.undeploy_pg_agent import UndeployPgAgent
13
13
  from adam.commands.deploy.undeploy_pod import UndeployPod
14
+ from adam.commands.describe.describe_keyspace import DescribeKeyspace
15
+ from adam.commands.describe.describe_keyspaces import DescribeKeyspaces
16
+ from adam.commands.describe.describe_table import DescribeTable
17
+ from adam.commands.describe.describe_tables import DescribeTables
14
18
  from adam.commands.shell import Shell
15
19
  from adam.commands.show.show_app_queues import ShowAppQueues
16
20
  from adam.commands.cp import ClipboardCopy
@@ -75,14 +79,15 @@ class ReplCommands:
75
79
  GetParam(), SetParam(), ShowParams(), ShowKubectlCommands(), ShowLogin(), ShowAdam()]
76
80
 
77
81
  def cassandra_check() -> list[Command]:
78
- return [ShowCassandraStatus(), ShowCassandraVersion(), ShowRepairs(), ShowStorage(), ShowProcesses(), Check(), Issues(), NodeTool(), Report()]
82
+ return [DescribeKeyspace(), DescribeKeyspaces(), DescribeTable(), DescribeTables(), ShowCassandraStatus(),
83
+ ShowCassandraVersion(), ShowRepairs(), ShowStorage(), ShowProcesses(), Check(), Issues(), NodeTool(), Report()]
79
84
 
80
85
  def cassandra_ops() -> list[Command]:
81
- # return Medusa.cmd_list() + [Restart(), RollOut(), Watch()] + Reaper.cmd_list() + Repair.cmd_list()
82
86
  return [AlterTables()] + Medusa.cmd_list() + [Restart(), RollOut(), Watch()] + Reaper.cmd_list() + Repair.cmd_list()
83
87
 
84
88
  def tools() -> list[Command]:
85
- return [Cqlsh(), Postgres(), Bash(), Shell(), CodeStart(), CodeStop(), DeployFrontend(), UndeployFrontend(), DeployPod(), UndeployPod(), DeployPgAgent(), UndeployPgAgent()]
89
+ return [Cqlsh(), Postgres(), Bash(), Shell(), CodeStart(), CodeStop(), DeployFrontend(), UndeployFrontend(),
90
+ DeployPod(), UndeployPod(), DeployPgAgent(), UndeployPgAgent()]
86
91
 
87
92
  def app() -> list[Command]:
88
93
  return [ShowAppActions(), ShowAppId(), ShowAppQueues(), AppPing(), App()]