kaqing 2.0.110__py3-none-any.whl → 2.0.214__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of kaqing might be problematic. Click here for more details.

Files changed (251) hide show
  1. adam/__init__.py +0 -2
  2. adam/app_session.py +9 -12
  3. adam/apps.py +18 -4
  4. adam/batch.py +19 -19
  5. adam/checks/check_utils.py +16 -46
  6. adam/checks/cpu.py +7 -1
  7. adam/checks/cpu_metrics.py +52 -0
  8. adam/checks/disk.py +2 -3
  9. adam/columns/columns.py +3 -1
  10. adam/columns/cpu.py +3 -1
  11. adam/columns/cpu_metrics.py +22 -0
  12. adam/columns/memory.py +3 -4
  13. adam/commands/__init__.py +24 -0
  14. adam/commands/app/app.py +38 -0
  15. adam/commands/{app_ping.py → app/app_ping.py} +7 -13
  16. adam/commands/{login.py → app/login.py} +22 -24
  17. adam/commands/app/show_app_actions.py +49 -0
  18. adam/commands/{show → app}/show_app_id.py +8 -11
  19. adam/commands/{show → app}/show_app_queues.py +7 -14
  20. adam/commands/app/show_login.py +56 -0
  21. adam/commands/app/utils_app.py +106 -0
  22. adam/commands/audit/audit.py +22 -40
  23. adam/commands/audit/audit_repair_tables.py +15 -19
  24. adam/commands/audit/audit_run.py +15 -22
  25. adam/commands/audit/completions_l.py +15 -0
  26. adam/commands/audit/show_last10.py +4 -18
  27. adam/commands/audit/show_slow10.py +4 -17
  28. adam/commands/audit/show_top10.py +4 -16
  29. adam/commands/audit/utils_show_top10.py +15 -3
  30. adam/commands/bash/__init__.py +5 -0
  31. adam/commands/bash/bash.py +36 -0
  32. adam/commands/bash/bash_completer.py +93 -0
  33. adam/commands/bash/utils_bash.py +16 -0
  34. adam/commands/cassandra/__init__.py +0 -0
  35. adam/commands/cassandra/download_cassandra_log.py +45 -0
  36. adam/commands/{restart.py → cassandra/restart_cluster.py} +12 -26
  37. adam/commands/cassandra/restart_node.py +51 -0
  38. adam/commands/cassandra/restart_nodes.py +47 -0
  39. adam/commands/{rollout.py → cassandra/rollout.py} +20 -25
  40. adam/commands/cassandra/show_cassandra_repairs.py +37 -0
  41. adam/commands/cassandra/show_cassandra_status.py +117 -0
  42. adam/commands/{show → cassandra}/show_cassandra_version.py +5 -18
  43. adam/commands/cassandra/show_processes.py +50 -0
  44. adam/commands/cassandra/show_storage.py +44 -0
  45. adam/commands/{watch.py → cassandra/watch.py} +26 -29
  46. adam/commands/cli/__init__.py +0 -0
  47. adam/commands/{cli_commands.py → cli/cli_commands.py} +8 -4
  48. adam/commands/cli/clipboard_copy.py +86 -0
  49. adam/commands/cli/show_cli_commands.py +56 -0
  50. adam/commands/code.py +57 -0
  51. adam/commands/command.py +211 -40
  52. adam/commands/commands_utils.py +20 -27
  53. adam/commands/config/__init__.py +0 -0
  54. adam/commands/{param_get.py → config/param_get.py} +11 -14
  55. adam/commands/{param_set.py → config/param_set.py} +8 -12
  56. adam/commands/{show → config}/show_params.py +2 -5
  57. adam/commands/cql/alter_tables.py +66 -0
  58. adam/commands/cql/completions_c.py +29 -0
  59. adam/commands/cql/cqlsh.py +10 -32
  60. adam/commands/cql/utils_cql.py +306 -0
  61. adam/commands/debug/__init__.py +0 -0
  62. adam/commands/debug/debug.py +22 -0
  63. adam/commands/debug/debug_completes.py +35 -0
  64. adam/commands/debug/debug_timings.py +35 -0
  65. adam/commands/debug/show_offloaded_completes.py +45 -0
  66. adam/commands/deploy/code_start.py +7 -10
  67. adam/commands/deploy/code_stop.py +4 -21
  68. adam/commands/deploy/code_utils.py +3 -3
  69. adam/commands/deploy/deploy.py +4 -27
  70. adam/commands/deploy/deploy_frontend.py +14 -17
  71. adam/commands/deploy/deploy_pg_agent.py +3 -6
  72. adam/commands/deploy/deploy_pod.py +65 -73
  73. adam/commands/deploy/deploy_utils.py +14 -24
  74. adam/commands/deploy/undeploy.py +4 -27
  75. adam/commands/deploy/undeploy_frontend.py +4 -7
  76. adam/commands/deploy/undeploy_pg_agent.py +6 -8
  77. adam/commands/deploy/undeploy_pod.py +11 -12
  78. adam/commands/devices/__init__.py +0 -0
  79. adam/commands/devices/device.py +149 -0
  80. adam/commands/devices/device_app.py +163 -0
  81. adam/commands/devices/device_auit_log.py +49 -0
  82. adam/commands/devices/device_cass.py +179 -0
  83. adam/commands/devices/device_export.py +87 -0
  84. adam/commands/devices/device_postgres.py +160 -0
  85. adam/commands/devices/devices.py +25 -0
  86. adam/commands/diag/__init__.py +0 -0
  87. adam/commands/{check.py → diag/check.py} +16 -25
  88. adam/commands/diag/generate_report.py +52 -0
  89. adam/commands/diag/issues.py +43 -0
  90. adam/commands/exit.py +1 -4
  91. adam/commands/export/__init__.py +0 -0
  92. adam/commands/export/clean_up_all_export_sessions.py +37 -0
  93. adam/commands/export/clean_up_export_sessions.py +39 -0
  94. adam/commands/export/completions_x.py +11 -0
  95. adam/commands/export/download_export_session.py +40 -0
  96. adam/commands/export/drop_export_database.py +39 -0
  97. adam/commands/export/drop_export_databases.py +37 -0
  98. adam/commands/export/export.py +37 -0
  99. adam/commands/export/export_databases.py +251 -0
  100. adam/commands/export/export_select.py +34 -0
  101. adam/commands/export/export_sessions.py +210 -0
  102. adam/commands/export/export_use.py +49 -0
  103. adam/commands/export/export_x_select.py +48 -0
  104. adam/commands/export/exporter.py +419 -0
  105. adam/commands/export/import_files.py +44 -0
  106. adam/commands/export/import_session.py +40 -0
  107. adam/commands/export/importer.py +81 -0
  108. adam/commands/export/importer_athena.py +157 -0
  109. adam/commands/export/importer_sqlite.py +78 -0
  110. adam/commands/export/show_column_counts.py +45 -0
  111. adam/commands/export/show_export_databases.py +39 -0
  112. adam/commands/export/show_export_session.py +39 -0
  113. adam/commands/export/show_export_sessions.py +37 -0
  114. adam/commands/export/utils_export.py +366 -0
  115. adam/commands/fs/__init__.py +0 -0
  116. adam/commands/fs/cat.py +36 -0
  117. adam/commands/fs/cat_local.py +42 -0
  118. adam/commands/fs/cd.py +41 -0
  119. adam/commands/fs/download_file.py +47 -0
  120. adam/commands/fs/find_files.py +51 -0
  121. adam/commands/fs/find_processes.py +76 -0
  122. adam/commands/fs/head.py +36 -0
  123. adam/commands/fs/ls.py +41 -0
  124. adam/commands/fs/ls_local.py +40 -0
  125. adam/commands/fs/pwd.py +45 -0
  126. adam/commands/fs/rm.py +18 -0
  127. adam/commands/fs/rm_downloads.py +39 -0
  128. adam/commands/fs/rm_logs.py +38 -0
  129. adam/commands/{shell.py → fs/shell.py} +12 -4
  130. adam/commands/{show → fs}/show_adam.py +3 -3
  131. adam/commands/{show → fs}/show_host.py +1 -1
  132. adam/commands/help.py +5 -3
  133. adam/commands/intermediate_command.py +52 -0
  134. adam/commands/kubectl.py +38 -0
  135. adam/commands/medusa/medusa.py +4 -22
  136. adam/commands/medusa/medusa_backup.py +20 -27
  137. adam/commands/medusa/medusa_restore.py +35 -48
  138. adam/commands/medusa/medusa_show_backupjobs.py +16 -18
  139. adam/commands/medusa/medusa_show_restorejobs.py +13 -18
  140. adam/commands/medusa/utils_medusa.py +15 -0
  141. adam/commands/nodetool/__init__.py +0 -0
  142. adam/commands/{nodetool.py → nodetool/nodetool.py} +9 -20
  143. adam/commands/postgres/completions_p.py +22 -0
  144. adam/commands/postgres/postgres.py +47 -55
  145. adam/commands/postgres/postgres_databases.py +269 -0
  146. adam/commands/postgres/postgres_ls.py +5 -9
  147. adam/commands/postgres/postgres_preview.py +5 -9
  148. adam/commands/postgres/utils_postgres.py +80 -0
  149. adam/commands/preview_table.py +8 -44
  150. adam/commands/reaper/reaper.py +4 -27
  151. adam/commands/reaper/reaper_forward.py +49 -56
  152. adam/commands/reaper/reaper_forward_session.py +6 -0
  153. adam/commands/reaper/reaper_forward_stop.py +10 -16
  154. adam/commands/reaper/reaper_restart.py +7 -14
  155. adam/commands/reaper/reaper_run_abort.py +8 -33
  156. adam/commands/reaper/reaper_runs.py +43 -58
  157. adam/commands/reaper/reaper_runs_abort.py +29 -49
  158. adam/commands/reaper/reaper_schedule_activate.py +14 -33
  159. adam/commands/reaper/reaper_schedule_start.py +9 -33
  160. adam/commands/reaper/reaper_schedule_stop.py +9 -33
  161. adam/commands/reaper/reaper_schedules.py +4 -14
  162. adam/commands/reaper/reaper_status.py +8 -16
  163. adam/commands/reaper/utils_reaper.py +203 -0
  164. adam/commands/repair/repair.py +4 -22
  165. adam/commands/repair/repair_log.py +5 -11
  166. adam/commands/repair/repair_run.py +27 -34
  167. adam/commands/repair/repair_scan.py +32 -40
  168. adam/commands/repair/repair_stop.py +5 -12
  169. adam/commands/show.py +40 -0
  170. adam/config.py +5 -15
  171. adam/embedded_params.py +1 -1
  172. adam/log.py +4 -4
  173. adam/repl.py +83 -116
  174. adam/repl_commands.py +86 -45
  175. adam/repl_session.py +9 -1
  176. adam/repl_state.py +176 -40
  177. adam/sql/async_executor.py +62 -0
  178. adam/sql/lark_completer.py +286 -0
  179. adam/sql/lark_parser.py +604 -0
  180. adam/sql/qingl.lark +1076 -0
  181. adam/sql/sql_completer.py +52 -27
  182. adam/sql/sql_state_machine.py +131 -19
  183. adam/sso/authn_ad.py +6 -8
  184. adam/sso/authn_okta.py +4 -6
  185. adam/sso/cred_cache.py +4 -9
  186. adam/sso/idp.py +9 -12
  187. adam/utils.py +670 -31
  188. adam/utils_athena.py +145 -0
  189. adam/utils_audits.py +12 -103
  190. adam/utils_issues.py +32 -0
  191. adam/utils_k8s/app_clusters.py +35 -0
  192. adam/utils_k8s/app_pods.py +41 -0
  193. adam/utils_k8s/cassandra_clusters.py +35 -20
  194. adam/utils_k8s/cassandra_nodes.py +15 -6
  195. adam/utils_k8s/custom_resources.py +16 -17
  196. adam/utils_k8s/ingresses.py +2 -2
  197. adam/utils_k8s/jobs.py +7 -11
  198. adam/utils_k8s/k8s.py +96 -0
  199. adam/utils_k8s/kube_context.py +3 -6
  200. adam/{pod_exec_result.py → utils_k8s/pod_exec_result.py} +13 -4
  201. adam/utils_k8s/pods.py +159 -89
  202. adam/utils_k8s/secrets.py +4 -4
  203. adam/utils_k8s/service_accounts.py +5 -4
  204. adam/utils_k8s/services.py +2 -2
  205. adam/utils_k8s/statefulsets.py +6 -14
  206. adam/utils_local.py +80 -0
  207. adam/utils_net.py +4 -4
  208. adam/utils_repl/__init__.py +0 -0
  209. adam/utils_repl/appendable_completer.py +6 -0
  210. adam/utils_repl/automata_completer.py +48 -0
  211. adam/utils_repl/repl_completer.py +93 -0
  212. adam/utils_repl/state_machine.py +173 -0
  213. adam/utils_sqlite.py +132 -0
  214. adam/version.py +1 -1
  215. {kaqing-2.0.110.dist-info → kaqing-2.0.214.dist-info}/METADATA +1 -1
  216. kaqing-2.0.214.dist-info/RECORD +272 -0
  217. kaqing-2.0.214.dist-info/top_level.txt +2 -0
  218. teddy/__init__.py +0 -0
  219. teddy/lark_parser.py +436 -0
  220. teddy/lark_parser2.py +618 -0
  221. adam/commands/alter_tables.py +0 -81
  222. adam/commands/app.py +0 -67
  223. adam/commands/bash.py +0 -150
  224. adam/commands/cd.py +0 -125
  225. adam/commands/cp.py +0 -95
  226. adam/commands/cql/cql_completions.py +0 -15
  227. adam/commands/cql/cql_utils.py +0 -112
  228. adam/commands/devices.py +0 -118
  229. adam/commands/issues.py +0 -75
  230. adam/commands/logs.py +0 -40
  231. adam/commands/ls.py +0 -146
  232. adam/commands/postgres/postgres_context.py +0 -239
  233. adam/commands/postgres/postgres_utils.py +0 -31
  234. adam/commands/postgres/psql_completions.py +0 -10
  235. adam/commands/pwd.py +0 -77
  236. adam/commands/reaper/reaper_session.py +0 -159
  237. adam/commands/report.py +0 -63
  238. adam/commands/show/show.py +0 -54
  239. adam/commands/show/show_app_actions.py +0 -56
  240. adam/commands/show/show_cassandra_status.py +0 -128
  241. adam/commands/show/show_commands.py +0 -61
  242. adam/commands/show/show_login.py +0 -63
  243. adam/commands/show/show_processes.py +0 -53
  244. adam/commands/show/show_repairs.py +0 -47
  245. adam/commands/show/show_storage.py +0 -52
  246. kaqing-2.0.110.dist-info/RECORD +0 -187
  247. kaqing-2.0.110.dist-info/top_level.txt +0 -1
  248. /adam/commands/{show → app}/__init__.py +0 -0
  249. /adam/commands/{nodetool_commands.py → nodetool/nodetool_commands.py} +0 -0
  250. {kaqing-2.0.110.dist-info → kaqing-2.0.214.dist-info}/WHEEL +0 -0
  251. {kaqing-2.0.110.dist-info → kaqing-2.0.214.dist-info}/entry_points.txt +0 -0
adam/commands/show.py ADDED
@@ -0,0 +1,40 @@
1
+ import click
2
+
3
+ from adam.commands.app.show_app_actions import ShowAppActions
4
+ from adam.commands.app.show_app_id import ShowAppId
5
+ from adam.commands.app.show_app_queues import ShowAppQueues
6
+ from adam.commands.cassandra.show_cassandra_repairs import ShowCassandraRepairs
7
+ from adam.commands.cassandra.show_cassandra_status import ShowCassandraStatus
8
+ from adam.commands.cassandra.show_cassandra_version import ShowCassandraVersion
9
+ from adam.commands.cassandra.show_processes import ShowProcesses
10
+ from adam.commands.cassandra.show_storage import ShowStorage
11
+ from adam.commands.cli.show_cli_commands import ShowKubectlCommands
12
+ from adam.commands.config.show_params import ShowParams
13
+ from adam.commands.debug.show_offloaded_completes import ShowOffloadedCompletes
14
+ from adam.commands.fs.show_adam import ShowAdam
15
+ from adam.commands.intermediate_command import IntermediateCommand
16
+ from adam.commands.medusa.medusa_show_backupjobs import MedusaShowBackupJobs
17
+ from adam.commands.medusa.medusa_show_restorejobs import MedusaShowRestoreJobs
18
+ from adam.commands.fs.show_host import ShowHost
19
+ from adam.commands.app.show_login import ShowLogin
20
+
21
+ class Show(IntermediateCommand):
22
+ COMMAND = 'show'
23
+
24
+ # the singleton pattern
25
+ def __new__(cls, *args, **kwargs):
26
+ if not hasattr(cls, 'instance'): cls.instance = super(Show, cls).__new__(cls)
27
+
28
+ return cls.instance
29
+
30
+ def command(self):
31
+ return Show.COMMAND
32
+
33
+ def cmd_list(self):
34
+ return [ShowAppActions(), ShowAppId(), ShowAppQueues(), ShowOffloadedCompletes(), ShowHost(), ShowLogin(), ShowKubectlCommands(),
35
+ ShowParams(), ShowProcesses(), ShowCassandraRepairs(), ShowStorage(), ShowAdam(),
36
+ ShowCassandraStatus(), ShowCassandraVersion(), MedusaShowRestoreJobs(), MedusaShowBackupJobs()]
37
+
38
+ class ShowCommandHelper(click.Command):
39
+ def get_help(self, ctx: click.Context):
40
+ IntermediateCommand.intermediate_help(super().get_help(ctx), Show.COMMAND, Show().cmd_list(), show_cluster_help=True)
adam/config.py CHANGED
@@ -3,11 +3,11 @@ from typing import TypeVar, cast
3
3
  import yaml
4
4
 
5
5
  from . import __version__
6
- from adam.utils import copy_config_file, get_deep_keys, log2
6
+ from adam.utils import ConfigHolder, ConfigReadable, copy_config_file, get_deep_keys, log2
7
7
 
8
8
  T = TypeVar('T')
9
9
 
10
- class Config:
10
+ class Config(ConfigReadable):
11
11
  EMBEDDED_PARAMS = {}
12
12
 
13
13
  # the singleton pattern
@@ -25,6 +25,8 @@ class Config:
25
25
  except:
26
26
  with open(copy_config_file(f'params.yaml.{__version__}', 'adam.embedded_params', show_out=not is_user_entry)) as f:
27
27
  self.params = cast(dict[str, any], yaml.safe_load(f))
28
+
29
+ ConfigHolder().config = self
28
30
  elif not hasattr(self, 'params'):
29
31
  with open(copy_config_file(f'params.yaml.{__version__}', 'adam.embedded_params', show_out=not is_user_entry)) as f:
30
32
  self.params = cast(dict[str, any], yaml.safe_load(f))
@@ -41,10 +43,6 @@ class Config:
41
43
  def is_debug(self):
42
44
  return os.getenv('QING_DEV', 'false').lower() == 'true' or Config().get('debug', False)
43
45
 
44
- def debug(self, s: None):
45
- if self.is_debug():
46
- log2(f'DEBUG {s}')
47
-
48
46
  def get(self, key: str, default: T) -> T:
49
47
  # params['nodetool']['status']['max-nodes']
50
48
  d = self.params
@@ -85,12 +83,4 @@ class Config:
85
83
  log2(f'incorrect path: {key}')
86
84
  return None
87
85
 
88
- return v if v else 'false'
89
-
90
- def wait_log(self, msg: str):
91
- if hasattr(self, 'wait_log_flag') and not self.wait_log_flag:
92
- log2(msg)
93
- self.wait_log_flag = True
94
-
95
- def clear_wait_log_flag(self):
96
- self.wait_log_flag = False
86
+ return v if v else 'false'
adam/embedded_params.py CHANGED
@@ -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', 'repair-partition-tables': 'audit', 'output': 's3://s3.ops--audit/ddl/results', 'repair-cluster-tables': 'cluster'}}, '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}}
2
+ return {'app': {'console-endpoint': 'https://{host}/{env}/{app}/static/console/index.html', 'container-name': 'c3-server', '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': 'cluster'}, 'queries': {'last10': "SELECT * FROM audit\nWHERE drive <> 'z' and ({date_condition})\nORDER BY ts DESC LIMIT {limit}", 'slow10': "SELECT * FROM audit\nWHERE drive <> 'z' and ({date_condition})\nORDER BY CAST(duration AS REAL) DESC LIMIT {limit}", 'top10': "SELECT min(c) AS cluster, line, COUNT(*) AS cnt, avg(CAST(duration AS REAL)) AS duration\nFROM audit WHERE drive <> 'z' and ({date_condition})\nGROUP BY line ORDER BY cnt DESC LIMIT {limit}"}}, '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/{}"}, 'download': {'workers': 8}, 'export': {'workers': 8, 'csv_dir': '/c3/cassandra/tmp', 'column_counts_query': 'select id, count(id) as columns from {table} group by id order by columns desc limit 10', 'default-importer': 'sqlite', 'sqlite': {'workers': 8, 'columns': '<row-key>', 'local-db-dir': '/tmp/qing-db/q/export/db'}, 'athena': {'workers': 8, 'columns': '<keys>', 'bucket': 'c3.ops--qing'}, 'csv': {'workers': 8, 'columns': '<row-key>'}, 'log-dir': '/tmp/qing-db/q/export/logs'}, '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}, 'local-qing-dir': '/tmp/qing-db/q', 'local-downloads-dir': '/tmp/qing-db/q/downloads', 'logs': {'path': '/c3/cassandra/logs/system.log'}, 'log-dir': '/tmp/qing-db/q/logs', 'nodetool': {'workers': 96, 'commands_in_line': 40, 'status': {'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-metrics,mem', 'header': 'POD_NAME,M_CPU(USAGE/LIMIT),MEM/LIMIT'}, 'processes-qing': {'columns': 'pod,cpu,mem', 'header': 'POD_NAME,Q_CPU/TOTAL,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': 'c', 'a': {'auto-enter': 'c3/c3'}, 'c': {'auto-enter': 'cluster'}, 'x': {'auto-enter': 'latest'}, 'history': {'push-cat-log-file': True, '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}, 'auto-complete': {'c': {'tables': 'lazy', 'table-props-value': 'jit'}, 'x': {'tables': 'lazy'}, 'cli': {'cp': 'jit'}, 'export': {'databases': 'jit'}, 'medusa': {'backups': 'jit'}, 'reaper': {'schedules': 'jit'}}, 'debug': False, 'debugs': {'complete': False, 'timings': False, 'exit-on-error': False}}
adam/log.py CHANGED
@@ -4,6 +4,8 @@ import os
4
4
  import sys
5
5
  import click
6
6
 
7
+ from adam.utils import log_exc
8
+
7
9
  class Log:
8
10
  DEBUG = False
9
11
 
@@ -28,7 +30,7 @@ class Log:
28
30
  print(file=sys.stderr)
29
31
 
30
32
  def log_to_file(config: dict[any, any]):
31
- try:
33
+ with log_exc():
32
34
  base = f"/tmp/logs"
33
35
  os.makedirs(base, exist_ok=True)
34
36
 
@@ -42,6 +44,4 @@ class Log:
42
44
  except:
43
45
  f.write(config)
44
46
  else:
45
- f.write(config)
46
- except:
47
- pass
47
+ f.write(config)
adam/repl.py CHANGED
@@ -1,29 +1,32 @@
1
1
  import os
2
- import re
3
2
  import time
4
- import traceback
3
+ from typing import cast
5
4
  import click
6
- import concurrent
7
- from prompt_toolkit.completion import NestedCompleter
8
5
  from prompt_toolkit.key_binding import KeyBindings
9
6
 
10
7
  from adam.cli_group import cli
11
- from adam.commands.command import Command
8
+ from adam.commands.command import Command, InvalidArgumentsException, InvalidStateException
12
9
  from adam.commands.command_helpers import ClusterCommandHelper
10
+ from adam.commands.devices.devices import Devices
13
11
  from adam.commands.help import Help
14
- from adam.commands.postgres.postgres_context import PostgresContext
15
12
  from adam.config import Config
13
+ from adam.sql.async_executor import AsyncExecutor
16
14
  from adam.utils_audits import Audits
17
15
  from adam.utils_k8s.kube_context import KubeContext
18
- from adam.utils_k8s.statefulsets import StatefulSets
19
16
  from adam.log import Log
20
17
  from adam.repl_commands import ReplCommands
21
18
  from adam.repl_session import ReplSession
22
19
  from adam.repl_state import ReplState
23
- from adam.utils import deep_merge_dicts, deep_sort_dict, lines_to_tabular, log2
20
+ from adam.utils import CommandLog, clear_wait_log_flag, debug_trace, deep_sort_dict, tabulize, log2, log_exc, log_timing
24
21
  from adam.apps import Apps
22
+ from adam.utils_repl.repl_completer import ReplCompleter, merge_completions
25
23
  from . import __version__
26
24
 
25
+ import nest_asyncio
26
+ nest_asyncio.apply()
27
+
28
+ import asyncio
29
+
27
30
  def enter_repl(state: ReplState):
28
31
  if os.getenv('QING_DROPPED', 'false') == 'true':
29
32
  log2('You have dropped to bash from another qing instance. Please enter "exit" to go back to qing.')
@@ -35,66 +38,13 @@ def enter_repl(state: ReplState):
35
38
  session = ReplSession().prompt_session
36
39
 
37
40
  def prompt_msg():
38
- msg = ''
39
- if state.device == ReplState.P:
40
- msg = f'{ReplState.P}:'
41
- pg: PostgresContext = PostgresContext.apply(state.namespace, state.pg_path) if state.pg_path else None
42
- if pg and pg.db:
43
- msg += pg.db
44
- elif pg and pg.host:
45
- msg += pg.host
46
- elif state.device == ReplState.A:
47
- msg = f'{ReplState.A}:'
48
- if state.app_env:
49
- msg += state.app_env
50
- if state.app_app:
51
- msg += f'/{state.app_app}'
52
- elif state.device == ReplState.L:
53
- msg = f'{ReplState.L}:'
54
- else:
55
- msg = f'{ReplState.C}:'
56
- if state.pod:
57
- # cs-d0767a536f-cs-d0767a536f-default-sts-0
58
- group = re.match(r".*?-.*?-(.*)", state.pod)
59
- msg += group[1]
60
- elif state.sts:
61
- # cs-d0767a536f-cs-d0767a536f-default-sts
62
- group = re.match(r".*?-.*?-(.*)", state.sts)
63
- msg += group[1]
41
+ msg = state.__str__()
64
42
 
65
43
  return f"{msg}$ " if state.bash_session else f"{msg}> "
66
44
 
67
45
  Log.log2(f'kaqing {__version__}')
68
46
 
69
- if state.device == ReplState.C:
70
- auto_enter = Config().get('repl.c.auto-enter', 'cluster')
71
- if auto_enter and auto_enter in ['cluster', 'first-pod']:
72
- ss = StatefulSets.list_sts_name_and_ns()
73
- if not ss:
74
- log2("No Cassandra clusters found.")
75
- elif not state.sts and len(ss) == 1:
76
- cluster = ss[0]
77
- state.sts = cluster[0]
78
- state.namespace = cluster[1]
79
- if auto_enter == 'first-pod':
80
- state.pod = f'{state.sts}-0'
81
- if KubeContext().in_cluster_namespace:
82
- Config().wait_log(f'Moving to the only Cassandra cluster: {state.sts}...')
83
- else:
84
- Config().wait_log(f'Moving to the only Cassandra cluster: {state.sts}@{state.namespace}...')
85
- elif state.device == ReplState.A:
86
- if not state.app_env:
87
- if app := Config().get('repl.a.auto-enter-app', 'c3/c3'):
88
- if app != 'no':
89
- ea = app.split('/')
90
- state.app_env = ea[0]
91
- if len(ea) > 1:
92
- state.app_app = ea[1]
93
- Config().wait_log(f'Moving to {state.app_env}/{state.app_app}...')
94
- else:
95
- Config().wait_log(f'Moving to {state.app_env}...')
96
- elif state.device == ReplState.P:
97
- Config().wait_log('Inspecting postgres database instances...')
47
+ Devices.of(state).enter(state)
98
48
 
99
49
  kb = KeyBindings()
100
50
 
@@ -102,34 +52,34 @@ def enter_repl(state: ReplState):
102
52
  def _(event):
103
53
  event.app.current_buffer.text = ''
104
54
 
105
- with concurrent.futures.ThreadPoolExecutor(max_workers=Config().get('audit.workers', 3)) as executor:
55
+ with Audits.offload() as exec:
106
56
  # warm up AWS lambda - this log line may timeout and get lost, which is fine
107
- executor.submit(Audits.log, 'entering kaqing repl', state.namespace, 'z', 0.0)
57
+ exec.submit(Audits.log, 'entering kaqing repl', state.namespace, 'z', 0.0)
108
58
 
109
59
  s0 = time.time()
110
60
 
111
61
  # use sorted command list only for auto-completion
112
62
  sorted_cmds = sorted(cmd_list, key=lambda cmd: cmd.command())
113
63
  while True:
64
+ AsyncExecutor.reset()
65
+
66
+ cmd: str = None
114
67
  result = None
115
68
  try:
116
- completer = NestedCompleter.from_nested_dict({})
69
+ completer = ReplCompleter.from_nested_dict({})
117
70
  if not state.bash_session:
118
- completions = {}
119
- # app commands are available only on a: drive
120
- if state.device == ReplState.A and state.app_app:
121
- completions = Apps(path='apps.yaml').commands()
122
-
123
- for cmd in sorted_cmds:
124
- s1 = time.time()
125
- try:
126
- completions = deep_sort_dict(deep_merge_dicts(completions, cmd.completion(state)))
127
- finally:
128
- if Config().get('debugs.timings', False):
129
- log2(f'Timing auto-completion-calc {cmd.command()}: {time.time() - s1:.2f}')
130
-
131
- # print(json.dumps(completions, indent=4))
132
- completer = NestedCompleter.from_nested_dict(completions)
71
+ with log_timing('completion-calcs'):
72
+ completions = {}
73
+ # app commands are available only on a: drive
74
+ if state.device == ReplState.A and state.app_app:
75
+ completions = log_timing('actions', lambda: Apps(path='apps.yaml').commands())
76
+
77
+ for c in sorted_cmds:
78
+ with log_exc(f'* {c.command()} command returned None completions.'):
79
+ completions = log_timing(c.command(), lambda: deep_sort_dict(merge_completions(completions, c.completion(state))))
80
+
81
+ # print(json.dumps(completions, indent=4))
82
+ completer = ReplCompleter.from_nested_dict(completions)
133
83
 
134
84
  cmd = session.prompt(prompt_msg(), completer=completer, key_bindings=kb)
135
85
  s0 = time.time()
@@ -141,9 +91,40 @@ def enter_repl(state: ReplState):
141
91
 
142
92
  cmd = f'bash {cmd}'
143
93
 
144
- if cmd and cmd.strip(' ') and not (result := cmds.run(cmd, state)):
145
- # not served by any command in the chain; try SQL query or C3 action
146
- result = try_device_default_action(state, cmds, cmd_list, cmd)
94
+ def targetted(state: ReplState, cmd: str):
95
+ if not (cmd.startswith('@') and len(arry := cmd.split(' ')) > 1):
96
+ return state, cmd
97
+
98
+ if state.device == ReplState.A and state.app_app or state.device == ReplState.P:
99
+ state.push(pod_targetted=True)
100
+
101
+ state.app_pod = arry[0].strip('@')
102
+ cmd = ' '.join(arry[1:])
103
+ elif state.device == ReplState.P:
104
+ state.push(pod_targetted=True)
105
+
106
+ state.app_pod = arry[0].strip('@')
107
+ cmd = ' '.join(arry[1:])
108
+ elif state.sts:
109
+ state.push(pod_targetted=True)
110
+
111
+ state.pod = arry[0].strip('@')
112
+ cmd = ' '.join(arry[1:])
113
+
114
+ return (state, cmd)
115
+
116
+ target, cmd = targetted(state, cmd)
117
+ try:
118
+ if cmd and cmd.strip(' ') and not (result := cmds.run(cmd, target)):
119
+ result = try_device_default_action(target, cmds, cmd_list, cmd)
120
+ except InvalidStateException:
121
+ pass
122
+ except InvalidArgumentsException:
123
+ pass
124
+
125
+ if result and type(result) is ReplState and (s := cast(ReplState, result).export_session) != state.export_session:
126
+ state.export_session = s
127
+
147
128
  except EOFError: # Handle Ctrl+D (EOF) for graceful exit
148
129
  break
149
130
  except Exception as e:
@@ -151,45 +132,28 @@ def enter_repl(state: ReplState):
151
132
  raise e
152
133
  else:
153
134
  log2(e)
154
- Config().debug(traceback.format_exc())
135
+ debug_trace()
155
136
  finally:
156
- Config().clear_wait_log_flag()
157
- if Config().get('debugs.timings', False) and 'cmd' in locals() and 's0' in locals():
158
- log2(f'Timing command {cmd}: {time.time() - s0:.2f}')
137
+ if not state.bash_session:
138
+ state.pop()
139
+
140
+ clear_wait_log_flag()
141
+ if cmd:
142
+ log_timing(f'command {cmd}', s0=s0)
159
143
 
160
144
  # offload audit logging
161
145
  if cmd and (state.device != ReplState.L or Config().get('audit.log-audit-queries', False)):
162
- executor.submit(Audits.log, cmd, state.namespace, state.device, time.time() - s0, get_audit_extra(result))
146
+ exec.submit(Audits.log, cmd, state.namespace, state.device, time.time() - s0, get_audit_extra(result))
147
+
148
+ CommandLog.close_log_file()
163
149
 
164
150
  def try_device_default_action(state: ReplState, cmds: Command, cmd_list: list[Command], cmd: str):
165
- result = None
166
-
167
- c_sql_tried = False
168
- if state.device == ReplState.P:
169
- pg: PostgresContext = PostgresContext.apply(state.namespace, state.pg_path)
170
- if pg.db:
171
- c_sql_tried = True
172
- cmd = f'pg {cmd}'
173
- result = cmds.run(cmd, state)
174
- elif state.device == ReplState.A:
175
- if state.app_app:
176
- c_sql_tried = True
177
- cmd = f'app {cmd}'
178
- result = cmds.run(cmd, state)
179
- elif state.device == ReplState.L:
180
- c_sql_tried = True
181
- cmd = f'audit {cmd}'
182
- result = cmds.run(cmd, state)
183
- elif state.sts:
184
- c_sql_tried = True
185
- cmd = f'cql {cmd}'
186
- result = cmds.run(cmd, state)
187
-
188
- if not c_sql_tried:
151
+ action_taken, result = Devices.of(state).try_fallback_action(cmds, state, cmd)
152
+
153
+ if not action_taken:
189
154
  log2(f'* Invalid command: {cmd}')
190
155
  log2()
191
- lines = [c.help(state) for c in cmd_list if c.help(state)]
192
- log2(lines_to_tabular(lines, separator='\t'))
156
+ tabulize([c.help(state) for c in cmd_list if c.help(state)], separator='\t', to=2)
193
157
 
194
158
  return result
195
159
 
@@ -221,6 +185,9 @@ def repl(kubeconfig: str, config: str, param: list[str], cluster:str, namespace:
221
185
  if not KubeContext.init_params(config, param):
222
186
  return
223
187
 
224
- state = ReplState(device=Config().get('repl.start-drive', 'a'), ns_sts=cluster, namespace=namespace, in_repl=True)
188
+ state = ReplState(ns_sts=cluster, namespace=namespace, in_repl=True)
225
189
  state, _ = state.apply_device_arg(extra_args)
190
+ if not state.device:
191
+ state.device=Config().get('repl.start-drive', 'a')
192
+
226
193
  enter_repl(state)
adam/repl_commands.py CHANGED
@@ -1,9 +1,33 @@
1
- from adam.commands.alter_tables import AlterTables
2
- from adam.commands.app import App
3
- from adam.commands.app_ping import AppPing
1
+ from adam.commands.app.app import App
2
+ from adam.commands.app.app_ping import AppPing
3
+ from adam.commands.app.show_app_actions import ShowAppActions
4
+ from adam.commands.app.show_app_id import ShowAppId
5
+ from adam.commands.app.show_app_queues import ShowAppQueues
4
6
  from adam.commands.audit.audit import Audit
5
- from adam.commands.audit.audit_repair_tables import AuditRepairTables
6
- from adam.commands.audit.audit_run import AuditRun
7
+ from adam.commands.cassandra.restart_cluster import RestartCluster
8
+ from adam.commands.cassandra.restart_node import RestartNode
9
+ from adam.commands.cassandra.restart_nodes import RestartNodes
10
+ from adam.commands.cassandra.rollout import RollOut
11
+ from adam.commands.cassandra.show_cassandra_repairs import ShowCassandraRepairs
12
+ from adam.commands.cassandra.show_cassandra_status import ShowCassandraStatus
13
+ from adam.commands.cassandra.show_cassandra_version import ShowCassandraVersion
14
+ from adam.commands.cassandra.show_processes import ShowProcesses
15
+ from adam.commands.cassandra.show_storage import ShowStorage
16
+ from adam.commands.cassandra.watch import Watch
17
+ from adam.commands.cli.clipboard_copy import ClipboardCopy
18
+ from adam.commands.config.param_get import GetParam
19
+ from adam.commands.config.param_set import SetParam
20
+ from adam.commands.debug.show_offloaded_completes import ShowOffloadedCompletes
21
+ from adam.commands.diag.check import Check
22
+ from adam.commands.diag.generate_report import GenerateReport
23
+ from adam.commands.diag.issues import Issues
24
+ from adam.commands.fs.cat import Cat
25
+ from adam.commands.code import Code
26
+ from adam.commands.cql.alter_tables import AlterTables
27
+ from adam.commands.debug.debug import Debug
28
+ from adam.commands.cassandra.download_cassandra_log import DownloadCassandraLog
29
+ from adam.commands.fs.cat_local import CatLocal
30
+ from adam.commands.fs.download_file import DownloadFile
7
31
  from adam.commands.deploy.code_start import CodeStart
8
32
  from adam.commands.deploy.code_stop import CodeStop
9
33
  from adam.commands.deploy.deploy import Deploy
@@ -14,51 +38,59 @@ from adam.commands.deploy.undeploy import Undeploy
14
38
  from adam.commands.deploy.undeploy_frontend import UndeployFrontend
15
39
  from adam.commands.deploy.undeploy_pg_agent import UndeployPgAgent
16
40
  from adam.commands.deploy.undeploy_pod import UndeployPod
17
- from adam.commands.shell import Shell
18
- from adam.commands.show.show_app_queues import ShowAppQueues
19
- from adam.commands.cp import ClipboardCopy
20
- from adam.commands.bash import Bash
21
- from adam.commands.cd import Cd
22
- from adam.commands.check import Check
41
+ from adam.commands.devices.device_app import DeviceApp
42
+ from adam.commands.devices.device_auit_log import DeviceAuditLog
43
+ from adam.commands.devices.device_cass import DeviceCass
44
+ from adam.commands.devices.device_export import DeviceExport
45
+ from adam.commands.devices.device_postgres import DevicePostgres
46
+ from adam.commands.export.download_export_session import DownloadExportSession
47
+ from adam.commands.export.drop_export_database import DropExportDatabase
48
+ from adam.commands.export.export import ExportTables
49
+ from adam.commands.export.import_files import ImportCSVFiles
50
+ from adam.commands.export.import_session import ImportSession
51
+ from adam.commands.export.clean_up_export_sessions import CleanUpExportSessions
52
+ from adam.commands.export.clean_up_all_export_sessions import CleanUpAllExportSessions
53
+ from adam.commands.export.drop_export_databases import DropExportDatabases
54
+ from adam.commands.export.export_x_select import ExportXSelect
55
+ from adam.commands.export.export_use import ExportUse
56
+ from adam.commands.export.export_select import ExportSelect
57
+ from adam.commands.export.show_column_counts import ShowColumnCounts
58
+ from adam.commands.export.show_export_databases import ShowExportDatabases
59
+ from adam.commands.export.show_export_session import ShowExportSession
60
+ from adam.commands.export.show_export_sessions import ShowExportSessions
61
+ from adam.commands.fs.find_files import FindLocalFiles
62
+ from adam.commands.fs.find_processes import FindProcesses
63
+ from adam.commands.fs.head import Head
64
+ from adam.commands.fs.ls_local import LsLocal
65
+ from adam.commands.fs.rm import RmLocal
66
+ from adam.commands.kubectl import Kubectl
67
+ from adam.commands.fs.shell import Shell
68
+ from adam.commands.bash.bash import Bash
69
+ from adam.commands.fs.cd import Cd
23
70
  from adam.commands.command import Command
24
71
  from adam.commands.cql.cqlsh import Cqlsh
25
- from adam.commands.devices import DeviceApp, DeviceAuditLog, DeviceCass, DevicePostgres
26
72
  from adam.commands.exit import Exit
27
73
  from adam.commands.medusa.medusa import Medusa
28
- from adam.commands.param_get import GetParam
29
- from adam.commands.issues import Issues
30
- from adam.commands.ls import Ls
31
- from adam.commands.nodetool import NodeTool
32
- from adam.commands.postgres.postgres import Postgres
74
+ from adam.commands.fs.ls import Ls
75
+ from adam.commands.nodetool.nodetool import NodeTool
76
+ from adam.commands.postgres.postgres import Postgres, PostgresPg
33
77
  from adam.commands.preview_table import PreviewTable
34
- from adam.commands.pwd import Pwd
78
+ from adam.commands.fs.pwd import Pwd
35
79
  from adam.commands.reaper.reaper import Reaper
36
80
  from adam.commands.repair.repair import Repair
37
- from adam.commands.report import Report
38
- from adam.commands.restart import Restart
39
- from adam.commands.rollout import RollOut
40
- from adam.commands.param_set import SetParam
41
- from adam.commands.show.show import Show
42
- from adam.commands.show.show_app_actions import ShowAppActions
43
- from adam.commands.show.show_app_id import ShowAppId
44
- from adam.commands.show.show_cassandra_status import ShowCassandraStatus
45
- from adam.commands.show.show_cassandra_version import ShowCassandraVersion
46
- from adam.commands.show.show_commands import ShowKubectlCommands
47
- from adam.commands.show.show_host import ShowHost
48
- from adam.commands.show.show_login import ShowLogin
49
- from adam.commands.show.show_params import ShowParams
50
- from adam.commands.show.show_processes import ShowProcesses
51
- from adam.commands.show.show_repairs import ShowRepairs
52
- from adam.commands.show.show_storage import ShowStorage
53
- from adam.commands.show.show_adam import ShowAdam
54
- from adam.commands.watch import Watch
81
+ from adam.commands.cli.show_cli_commands import ShowKubectlCommands
82
+ from adam.commands.fs.show_host import ShowHost
83
+ from adam.commands.app.show_login import ShowLogin
84
+ from adam.commands.config.show_params import ShowParams
85
+ from adam.commands.fs.show_adam import ShowAdam
86
+ from adam.commands.show import Show
55
87
 
56
88
  class ReplCommands:
57
89
  def repl_cmd_list() -> list[Command]:
58
90
  cmds: list[Command] = ReplCommands.navigation() + ReplCommands.cassandra_ops() + ReplCommands.postgres_ops() + \
59
- ReplCommands.app_ops() + ReplCommands.audit_ops() + ReplCommands.tools() + ReplCommands.exit()
91
+ ReplCommands.app_ops() + ReplCommands.audit_ops() + ReplCommands.export_ops() + ReplCommands.tools() + ReplCommands.exit()
60
92
 
61
- intermediate_cmds: list[Command] = [App(), Audit(), Reaper(), Repair(), Deploy(), Show(), Undeploy()]
93
+ intermediate_cmds: list[Command] = [App(), Audit(), Reaper(), Repair(), Debug(), Deploy(), Show(), Undeploy()]
62
94
  ic = [c.command() for c in intermediate_cmds]
63
95
  # 1. dedup commands
64
96
  deduped = []
@@ -75,24 +107,33 @@ class ReplCommands:
75
107
  return deduped
76
108
 
77
109
  def navigation() -> list[Command]:
78
- return [Ls(), PreviewTable(), DeviceApp(), DevicePostgres(), DeviceCass(), DeviceAuditLog(), Cd(), Pwd(), ClipboardCopy(),
79
- GetParam(), SetParam(), ShowParams(), ShowKubectlCommands(), ShowLogin(), ShowAdam(), ShowHost()]
110
+ return [Ls(), LsLocal(), PreviewTable(), DeviceApp(), DevicePostgres(), DeviceCass(), DeviceAuditLog(), DeviceExport(),
111
+ Cd(), Cat(), CatLocal(), Head(), DownloadFile(), FindLocalFiles(), FindProcesses(), Pwd(), ClipboardCopy(),
112
+ GetParam(), SetParam(), ShowOffloadedCompletes(), ShowParams(), ShowKubectlCommands(), ShowLogin(), ShowAdam(), ShowHost()] + RmLocal().cmd_list()
80
113
 
81
114
  def cassandra_ops() -> list[Command]:
82
- return [Cqlsh(), ShowCassandraStatus(), ShowCassandraVersion(), ShowRepairs(), ShowStorage(), ShowProcesses(), Check(), Issues(), NodeTool(), Report()] + \
83
- [AlterTables()] + Medusa.cmd_list() + [Restart(), RollOut(), Watch()] + Reaper.cmd_list() + Repair.cmd_list()
115
+ return [Cqlsh(), DownloadCassandraLog(), ShowCassandraStatus(), ShowCassandraVersion(), ShowCassandraRepairs(), ShowStorage(), ShowProcesses(),
116
+ Check(), Issues(), NodeTool(), GenerateReport(), AlterTables(), Bash(),
117
+ ExportTables(), ExportXSelect(), ExportUse(), ShowExportDatabases(), ShowColumnCounts(),
118
+ DropExportDatabase(), DropExportDatabases(),
119
+ ShowExportSessions(), ShowExportSession(), DownloadExportSession(),
120
+ CleanUpExportSessions(), CleanUpAllExportSessions(), ImportSession(), ImportCSVFiles()] + \
121
+ Medusa().cmd_list() + [RestartNodes(), RestartNode(), RestartCluster(), RollOut(), Watch()] + Reaper().cmd_list() + Repair().cmd_list() + Debug().cmd_list()
84
122
 
85
123
  def postgres_ops() -> list[Command]:
86
- return [Postgres(), DeployPgAgent(), UndeployPgAgent()]
124
+ return [Postgres(), DeployPgAgent(), UndeployPgAgent(), PostgresPg()]
87
125
 
88
126
  def app_ops() -> list[Command]:
89
127
  return [ShowAppActions(), ShowAppId(), ShowAppQueues(), AppPing(), App()]
90
128
 
91
129
  def audit_ops() -> list[Command]:
92
- return [Audit()] + Audit.cmd_list()
130
+ return [Audit()] + Audit().cmd_list()
131
+
132
+ def export_ops() -> list[Command]:
133
+ return [ExportSelect(), DropExportDatabase(), DropExportDatabases(), ShowColumnCounts()]
93
134
 
94
135
  def tools() -> list[Command]:
95
- return [Bash(), Shell(), CodeStart(), CodeStop(), DeployFrontend(), UndeployFrontend(), DeployPod(), UndeployPod()]
136
+ return [Shell(), CodeStart(), CodeStop(), DeployFrontend(), UndeployFrontend(), DeployPod(), UndeployPod(), Kubectl(), Code()]
96
137
 
97
138
  def exit() -> list[Command]:
98
139
  return [Exit()]
adam/repl_session.py CHANGED
@@ -1,6 +1,9 @@
1
1
  from prompt_toolkit import PromptSession
2
2
  from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
3
3
 
4
+ from adam.config import Config
5
+ from adam.utils import ConfigHolder
6
+
4
7
  class ReplSession:
5
8
  # the singleton pattern
6
9
  def __new__(cls, *args, **kwargs):
@@ -10,4 +13,9 @@ class ReplSession:
10
13
 
11
14
  def __init__(self):
12
15
  if not hasattr(self, 'prompt_session'):
13
- self.prompt_session = PromptSession(auto_suggest=AutoSuggestFromHistory())
16
+ self.prompt_session = PromptSession(auto_suggest=AutoSuggestFromHistory())
17
+ ConfigHolder().append_command_history = self.append_history
18
+
19
+ def append_history(self, entry: str):
20
+ if entry and self.prompt_session and Config().get('repl.history.push-cat-remote-log-file', True):
21
+ self.prompt_session.history.append_string(entry)