kaqing 2.0.145__py3-none-any.whl → 2.0.189__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 (209) 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 +4 -4
  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/alter_tables.py +33 -48
  15. adam/commands/app/__init__.py +0 -0
  16. adam/commands/app/app.py +38 -0
  17. adam/commands/{app_ping.py → app/app_ping.py} +7 -13
  18. adam/commands/app/show_app_actions.py +49 -0
  19. adam/commands/{show → app}/show_app_id.py +8 -11
  20. adam/commands/{show → app}/show_app_queues.py +7 -14
  21. adam/commands/app/utils_app.py +106 -0
  22. adam/commands/audit/audit.py +21 -40
  23. adam/commands/audit/audit_repair_tables.py +14 -19
  24. adam/commands/audit/audit_run.py +14 -22
  25. adam/commands/audit/completions_l.py +15 -0
  26. adam/commands/audit/show_last10.py +4 -19
  27. adam/commands/audit/show_slow10.py +4 -18
  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 +7 -104
  32. adam/commands/bash/utils_bash.py +16 -0
  33. adam/commands/cat.py +7 -27
  34. adam/commands/cd.py +7 -11
  35. adam/commands/check.py +15 -24
  36. adam/commands/cli_commands.py +8 -4
  37. adam/commands/clipboard_copy.py +87 -0
  38. adam/commands/code.py +21 -24
  39. adam/commands/command.py +207 -42
  40. adam/commands/commands_utils.py +25 -27
  41. adam/commands/cql/completions_c.py +28 -0
  42. adam/commands/cql/cqlsh.py +9 -33
  43. adam/commands/cql/{cql_utils.py → utils_cql.py} +111 -15
  44. adam/commands/deploy/code_start.py +7 -10
  45. adam/commands/deploy/code_stop.py +4 -21
  46. adam/commands/deploy/code_utils.py +3 -3
  47. adam/commands/deploy/deploy.py +4 -27
  48. adam/commands/deploy/deploy_frontend.py +14 -17
  49. adam/commands/deploy/deploy_pg_agent.py +3 -6
  50. adam/commands/deploy/deploy_pod.py +64 -68
  51. adam/commands/deploy/undeploy.py +4 -27
  52. adam/commands/deploy/undeploy_frontend.py +4 -7
  53. adam/commands/deploy/undeploy_pg_agent.py +5 -8
  54. adam/commands/deploy/undeploy_pod.py +9 -12
  55. adam/commands/devices/device.py +124 -2
  56. adam/commands/devices/device_app.py +41 -24
  57. adam/commands/devices/device_auit_log.py +10 -4
  58. adam/commands/devices/device_cass.py +48 -14
  59. adam/commands/devices/device_export.py +13 -12
  60. adam/commands/devices/device_postgres.py +105 -54
  61. adam/commands/download_file.py +47 -0
  62. adam/commands/exit.py +1 -4
  63. adam/commands/export/clean_up_all_export_sessions.py +37 -0
  64. adam/commands/export/clean_up_export_sessions.py +9 -10
  65. adam/commands/export/completions_x.py +11 -0
  66. adam/commands/export/download_export_session.py +40 -0
  67. adam/commands/export/drop_export_database.py +7 -26
  68. adam/commands/export/drop_export_databases.py +5 -14
  69. adam/commands/export/export.py +6 -52
  70. adam/commands/export/export_databases.py +108 -32
  71. adam/commands/export/export_select.py +8 -59
  72. adam/commands/export/export_sessions.py +209 -0
  73. adam/commands/export/export_use.py +14 -20
  74. adam/commands/export/export_x_select.py +48 -0
  75. adam/commands/export/exporter.py +135 -167
  76. adam/commands/export/import_files.py +44 -0
  77. adam/commands/export/import_session.py +11 -35
  78. adam/commands/export/importer.py +19 -5
  79. adam/commands/export/importer_athena.py +112 -44
  80. adam/commands/export/importer_sqlite.py +42 -22
  81. adam/commands/export/show_column_counts.py +13 -31
  82. adam/commands/export/show_export_databases.py +7 -7
  83. adam/commands/export/show_export_session.py +8 -20
  84. adam/commands/export/show_export_sessions.py +6 -16
  85. adam/commands/export/utils_export.py +64 -11
  86. adam/commands/find_files.py +51 -0
  87. adam/commands/find_processes.py +76 -0
  88. adam/commands/head.py +36 -0
  89. adam/commands/help.py +2 -2
  90. adam/commands/intermediate_command.py +52 -0
  91. adam/commands/issues.py +11 -43
  92. adam/commands/kubectl.py +3 -6
  93. adam/commands/login.py +22 -24
  94. adam/commands/logs.py +3 -6
  95. adam/commands/ls.py +9 -10
  96. adam/commands/medusa/medusa.py +4 -22
  97. adam/commands/medusa/medusa_backup.py +20 -27
  98. adam/commands/medusa/medusa_restore.py +49 -46
  99. adam/commands/medusa/medusa_show_backupjobs.py +16 -18
  100. adam/commands/medusa/medusa_show_restorejobs.py +13 -18
  101. adam/commands/medusa/utils_medusa.py +15 -0
  102. adam/commands/nodetool.py +7 -21
  103. adam/commands/param_get.py +11 -14
  104. adam/commands/param_set.py +8 -12
  105. adam/commands/postgres/completions_p.py +22 -0
  106. adam/commands/postgres/postgres.py +34 -57
  107. adam/commands/postgres/postgres_databases.py +270 -0
  108. adam/commands/postgres/postgres_ls.py +4 -8
  109. adam/commands/postgres/postgres_preview.py +5 -9
  110. adam/commands/postgres/utils_postgres.py +79 -0
  111. adam/commands/preview_table.py +8 -45
  112. adam/commands/pwd.py +13 -16
  113. adam/commands/reaper/reaper.py +4 -27
  114. adam/commands/reaper/reaper_forward.py +49 -56
  115. adam/commands/reaper/reaper_forward_session.py +6 -0
  116. adam/commands/reaper/reaper_forward_stop.py +10 -16
  117. adam/commands/reaper/reaper_restart.py +7 -14
  118. adam/commands/reaper/reaper_run_abort.py +8 -33
  119. adam/commands/reaper/reaper_runs.py +43 -58
  120. adam/commands/reaper/reaper_runs_abort.py +29 -49
  121. adam/commands/reaper/reaper_schedule_activate.py +14 -33
  122. adam/commands/reaper/reaper_schedule_start.py +9 -33
  123. adam/commands/reaper/reaper_schedule_stop.py +9 -33
  124. adam/commands/reaper/reaper_schedules.py +4 -14
  125. adam/commands/reaper/reaper_status.py +8 -16
  126. adam/commands/reaper/utils_reaper.py +203 -0
  127. adam/commands/repair/repair.py +4 -22
  128. adam/commands/repair/repair_log.py +5 -11
  129. adam/commands/repair/repair_run.py +27 -34
  130. adam/commands/repair/repair_scan.py +32 -40
  131. adam/commands/repair/repair_stop.py +5 -12
  132. adam/commands/report.py +27 -29
  133. adam/commands/restart.py +25 -26
  134. adam/commands/rollout.py +19 -24
  135. adam/commands/shell.py +12 -4
  136. adam/commands/show/show.py +11 -27
  137. adam/commands/show/show_adam.py +3 -3
  138. adam/commands/show/show_cassandra_repairs.py +37 -0
  139. adam/commands/show/show_cassandra_status.py +47 -51
  140. adam/commands/show/show_cassandra_version.py +5 -18
  141. adam/commands/show/show_cli_commands.py +56 -0
  142. adam/commands/show/show_host.py +1 -1
  143. adam/commands/show/show_login.py +20 -27
  144. adam/commands/show/show_params.py +2 -5
  145. adam/commands/show/show_processes.py +18 -21
  146. adam/commands/show/show_storage.py +11 -20
  147. adam/commands/watch.py +26 -29
  148. adam/config.py +5 -16
  149. adam/embedded_params.py +1 -1
  150. adam/log.py +4 -4
  151. adam/pod_exec_result.py +3 -3
  152. adam/repl.py +45 -39
  153. adam/repl_commands.py +26 -19
  154. adam/repl_session.py +8 -1
  155. adam/repl_state.py +85 -36
  156. adam/sql/lark_completer.py +284 -0
  157. adam/sql/lark_parser.py +604 -0
  158. adam/sql/sql_completer.py +4 -6
  159. adam/sql/sql_state_machine.py +29 -16
  160. adam/sso/authn_ad.py +6 -8
  161. adam/sso/authn_okta.py +4 -6
  162. adam/sso/cred_cache.py +3 -5
  163. adam/sso/idp.py +9 -12
  164. adam/utils.py +484 -37
  165. adam/utils_athena.py +19 -19
  166. adam/utils_audits.py +12 -12
  167. adam/utils_issues.py +32 -0
  168. adam/utils_k8s/app_clusters.py +14 -19
  169. adam/utils_k8s/app_pods.py +7 -2
  170. adam/utils_k8s/cassandra_clusters.py +30 -19
  171. adam/utils_k8s/cassandra_nodes.py +2 -2
  172. adam/utils_k8s/custom_resources.py +16 -17
  173. adam/utils_k8s/ingresses.py +2 -2
  174. adam/utils_k8s/jobs.py +7 -11
  175. adam/utils_k8s/k8s.py +96 -0
  176. adam/utils_k8s/kube_context.py +2 -2
  177. adam/utils_k8s/pods.py +37 -81
  178. adam/utils_k8s/secrets.py +4 -4
  179. adam/utils_k8s/service_accounts.py +5 -4
  180. adam/utils_k8s/services.py +2 -2
  181. adam/utils_k8s/statefulsets.py +6 -14
  182. adam/utils_local.py +4 -0
  183. adam/utils_repl/appendable_completer.py +6 -0
  184. adam/utils_repl/repl_completer.py +128 -2
  185. adam/utils_repl/state_machine.py +3 -3
  186. adam/utils_sqlite.py +78 -42
  187. adam/version.py +1 -1
  188. {kaqing-2.0.145.dist-info → kaqing-2.0.189.dist-info}/METADATA +1 -1
  189. kaqing-2.0.189.dist-info/RECORD +253 -0
  190. kaqing-2.0.189.dist-info/top_level.txt +2 -0
  191. teddy/__init__.py +0 -0
  192. teddy/lark_parser.py +436 -0
  193. teddy/lark_parser2.py +618 -0
  194. adam/commands/app.py +0 -67
  195. adam/commands/cp.py +0 -95
  196. adam/commands/cql/cql_completions.py +0 -28
  197. adam/commands/export/clean_up_export_session.py +0 -53
  198. adam/commands/export/export_select_x.py +0 -54
  199. adam/commands/postgres/postgres_context.py +0 -248
  200. adam/commands/postgres/postgres_utils.py +0 -31
  201. adam/commands/postgres/psql_completions.py +0 -10
  202. adam/commands/reaper/reaper_session.py +0 -159
  203. adam/commands/show/show_app_actions.py +0 -56
  204. adam/commands/show/show_commands.py +0 -61
  205. adam/commands/show/show_repairs.py +0 -47
  206. kaqing-2.0.145.dist-info/RECORD +0 -227
  207. kaqing-2.0.145.dist-info/top_level.txt +0 -1
  208. {kaqing-2.0.145.dist-info → kaqing-2.0.189.dist-info}/WHEEL +0 -0
  209. {kaqing-2.0.145.dist-info → kaqing-2.0.189.dist-info}/entry_points.txt +0 -0
@@ -1,7 +1,7 @@
1
+ from adam.commands import extract_options, extract_trailing_options
1
2
  from adam.commands.command import Command
2
- from adam.commands.commands_utils import show_table
3
+ from adam.commands.cql.utils_cql import cassandra
3
4
  from adam.config import Config
4
- from adam.utils_k8s.statefulsets import StatefulSets
5
5
  from adam.repl_state import ReplState, RequiredState
6
6
 
7
7
  class ShowStorage(Command):
@@ -26,27 +26,18 @@ class ShowStorage(Command):
26
26
  if not(args := self.args(cmd)):
27
27
  return super().run(cmd, state)
28
28
 
29
- state, args = self.apply_state(args, state)
30
- if not self.validate_state(state):
31
- return state
29
+ with self.validate(args, state) as (args, state):
30
+ with extract_trailing_options(args, '&') as (args, backgrounded):
31
+ with extract_options(args, ['-s', '--show']) as (args, show_out):
32
+ cols = Config().get('storage.columns', 'pod,volume_root,volume_cassandra,snapshots,data,compactions')
33
+ header = Config().get('storage.header', 'POD_NAME,VOLUME /,VOLUME CASS,SNAPSHOTS,DATA,COMPACTIONS')
34
+ with cassandra(state) as pods:
35
+ pods.display_table(cols, header, show_out=show_out, backgrounded=backgrounded)
32
36
 
33
- args, show_output = Command.extract_options(args, ['-s', '--show'])
34
-
35
- cols = Config().get('storage.columns', 'pod,volume_root,volume_cassandra,snapshots,data,compactions')
36
- header = Config().get('storage.header', 'POD_NAME,VOLUME /,VOLUME CASS,SNAPSHOTS,DATA,COMPACTIONS')
37
- if state.pod:
38
- show_table(state, [state.pod], cols, header, show_output=show_output)
39
- elif state.sts:
40
- pod_names = [pod.metadata.name for pod in StatefulSets.pods(state.sts, state.namespace)]
41
- show_table(state, pod_names, cols, header, show_output=show_output)
42
-
43
- return state
37
+ return state
44
38
 
45
39
  def completion(self, state: ReplState):
46
- if not state.sts:
47
- return {}
48
-
49
- return super().completion(state)
40
+ return super().completion(state, {'-s': {'&': None}, '&': None})
50
41
 
51
42
  def help(self, _: ReplState):
52
43
  return f'{ShowStorage.COMMAND} [-s]\t show storage overview -s show commands on nodes'
adam/commands/watch.py CHANGED
@@ -8,10 +8,10 @@ from adam.commands.commands_utils import show_pods, show_rollout
8
8
  from adam.config import Config
9
9
  from adam.utils_k8s.statefulsets import StatefulSets
10
10
  from adam.repl_state import ReplState, RequiredState
11
- from adam.utils import convert_seconds, log2
11
+ from adam.utils import log2
12
12
 
13
13
  class Watch(Command):
14
- COMMAND = 'watch'
14
+ COMMAND = 'watch cassandra pods'
15
15
 
16
16
  # the singleton pattern
17
17
  def __new__(cls, *args, **kwargs):
@@ -26,37 +26,34 @@ class Watch(Command):
26
26
  return Watch.COMMAND
27
27
 
28
28
  def required(self):
29
- return RequiredState.CLUSTER_OR_POD
29
+ return RequiredState.NAMESPACE
30
30
 
31
31
  def run(self, cmd: str, state: ReplState):
32
32
  if not(args := self.args(cmd)):
33
33
  return super().run(cmd, state)
34
34
 
35
- state, args = self.apply_state(args, state)
36
- if not self.validate_state(state):
37
- return state
38
-
39
- pods = StatefulSets.pods(state.sts, state.namespace)
40
- if not pods:
41
- log2("No pods are found.")
42
- return state
35
+ with self.validate(args, state) as (args, state):
36
+ pods = StatefulSets.pods(state.sts, state.namespace)
37
+ if not pods:
38
+ log2("No pods are found.")
39
+ return state
43
40
 
44
- stop_event = threading.Event()
45
- thread = threading.Thread(target=self.loop, args=(stop_event, state.sts, pods, state.namespace), daemon=True)
46
- thread.start()
41
+ stop_event = threading.Event()
42
+ thread = threading.Thread(target=self.loop, args=(stop_event, state.sts, pods, state.namespace), daemon=True)
43
+ thread.start()
47
44
 
48
- try:
49
- log2(f"Press Ctrl+C to break.")
45
+ try:
46
+ log2(f"Press Ctrl+C to break.")
50
47
 
51
- time.sleep(Config().get('watch.timeout', 3600 * 1))
52
- except KeyboardInterrupt:
53
- pass
48
+ time.sleep(Config().get('watch.timeout', 3600 * 1))
49
+ except KeyboardInterrupt:
50
+ pass
54
51
 
55
- log2("Stopping watch...")
56
- stop_event.set()
57
- thread.join()
52
+ log2("Stopping watch...")
53
+ stop_event.set()
54
+ thread.join()
58
55
 
59
- return state
56
+ return state
60
57
 
61
58
  def loop(self, stop_flag: threading.Event, sts: str, pods: List[client.V1Pod], ns: str):
62
59
  show_pods(pods, ns)
@@ -73,13 +70,13 @@ class Watch(Command):
73
70
  cnt = Config().get('watch.interval', 10)
74
71
 
75
72
  def completion(self, state: ReplState):
76
- if state.pod:
77
- return {}
73
+ if sc := super().completion(state):
74
+ if state.sts:
75
+ return sc
78
76
 
79
- if not state.sts:
80
- return {Watch.COMMAND: {n: None for n in StatefulSets.list_sts_names()}}
77
+ return super().completion(state, {n: None for n in StatefulSets.list_sts_names()})
81
78
 
82
- return {Watch.COMMAND: None}
79
+ return {}
83
80
 
84
81
  def help(self, _: ReplState):
85
- return f'{Watch.COMMAND}\t watch pod changes'
82
+ return f'{Watch.COMMAND}\t watch Cassandra pod changes'
adam/config.py CHANGED
@@ -3,15 +3,16 @@ 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, is_debug_holder
6
+ from adam.utils import LogConfig, copy_config_file, get_deep_keys, log2
7
7
 
8
8
  T = TypeVar('T')
9
9
 
10
10
  class Config:
11
11
  EMBEDDED_PARAMS = {}
12
12
 
13
- global is_debug_holder
14
- is_debug_holder[0] = lambda: Config().is_debug()
13
+ LogConfig.is_debug = lambda: Config().is_debug()
14
+ LogConfig.is_debug_complete = lambda: Config().get('debugs.complete', False)
15
+ LogConfig.is_debug_timing = lambda: Config().get('debugs.timings', False)
15
16
 
16
17
  # the singleton pattern
17
18
  def __new__(cls, *args, **kwargs):
@@ -44,10 +45,6 @@ class Config:
44
45
  def is_debug(self):
45
46
  return os.getenv('QING_DEV', 'false').lower() == 'true' or Config().get('debug', False)
46
47
 
47
- def debug(self, s: None):
48
- if self.is_debug():
49
- log2(f'DEBUG {s}')
50
-
51
48
  def get(self, key: str, default: T) -> T:
52
49
  # params['nodetool']['status']['max-nodes']
53
50
  d = self.params
@@ -88,12 +85,4 @@ class Config:
88
85
  log2(f'incorrect path: {key}')
89
86
  return None
90
87
 
91
- return v if v else 'false'
92
-
93
- def wait_log(self, msg: str):
94
- if hasattr(self, 'wait_log_flag') and not self.wait_log_flag:
95
- log2(msg)
96
- self.wait_log_flag = True
97
-
98
- def clear_wait_log_flag(self):
99
- self.wait_log_flag = False
88
+ 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', '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'}}, '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}}, 'export': {'workers': 8, 'csv_dir': '/c3/cassandra/tmp', 'default-importer': 'sqlite', 'sqlite': {'workers': 8, 'columns': '<row-key>', 'local-db-dir': '/tmp/qing-db', 'column_counts_query': 'select id, count(id) as columns from {table} group by id order by columns desc limit 10'}, 'athena': {'workers': 8, 'columns': '<keys>', 'bucket': 'c3.ops--qing', 'column_counts_query': 'select id, count(id) as columns from {table} group by id order by columns desc limit 10'}, 'csv': {'workers': 8, 'columns': '<row-key>'}}, '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'}, 'log-prefix': '/tmp/qing', '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': 'c', 'a': {'auto-enter': 'c3/c3/*'}, 'c': {'auto-enter': 'cluster'}, 'x': {'auto-enter': 'latest'}, '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'}, 'athena': {'workers': 8, 'columns': '<keys>', 'bucket': 'c3.ops--qing'}, 'csv': {'workers': 8, 'columns': '<row-key>'}, 'log-prefix': '/tmp/qing'}, '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-tmp-dir': '/tmp/qing-db', 'logs': {'path': '/c3/cassandra/logs/system.log'}, 'log-prefix': '/tmp/qing', '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'}, 'x': {'tables': 'lazy'}, 'cli': {'cp': 'jit'}, 'export': {'databases': 'jit'}, 'medusa': {'backups': 'jit'}, 'reaper': {'schedules': 'lazy'}}, 'debug': False, 'debugs': {'timings': False, 'exit-on-error': False, 'show-parallelism': 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/pod_exec_result.py CHANGED
@@ -1,5 +1,7 @@
1
1
  import yaml
2
2
 
3
+ from adam.utils import log_exc
4
+
3
5
  class PodExecResult:
4
6
  # {
5
7
  # 'metadata': {},
@@ -27,10 +29,8 @@ class PodExecResult:
27
29
  def exit_code(self) -> int:
28
30
  code = 0
29
31
 
30
- try:
32
+ with log_exc(False):
31
33
  code = self.error['details']['causes'][0]['message']
32
- except:
33
- pass
34
34
 
35
35
  return code
36
36
 
adam/repl.py CHANGED
@@ -1,30 +1,31 @@
1
1
  import os
2
2
  import time
3
- import traceback
4
3
  from typing import cast
5
4
  import click
6
- import concurrent
7
5
  from prompt_toolkit.key_binding import KeyBindings
8
6
 
9
7
  from adam.cli_group import cli
10
- from adam.commands.command import Command
8
+ from adam.commands.command import Command, InvalidArgumentsException, InvalidStateException
11
9
  from adam.commands.command_helpers import ClusterCommandHelper
12
10
  from adam.commands.devices.devices import Devices
13
11
  from adam.commands.help import Help
14
12
  from adam.config import Config
15
13
  from adam.utils_audits import Audits
16
- from adam.utils_k8s.app_pods import AppPods
17
14
  from adam.utils_k8s.kube_context import KubeContext
18
- from adam.utils_k8s.statefulsets import StatefulSets
19
15
  from adam.log import Log
20
16
  from adam.repl_commands import ReplCommands
21
17
  from adam.repl_session import ReplSession
22
18
  from adam.repl_state import ReplState
23
- from adam.utils import deep_merge_dicts, deep_sort_dict, lines_to_tabular, log2
19
+ from adam.utils import clear_wait_log_flag, debug_trace, deep_sort_dict, tabulize, log2, log_exc, log_timing
24
20
  from adam.apps import Apps
25
- from adam.utils_repl.repl_completer import ReplCompleter
21
+ from adam.utils_repl.repl_completer import ReplCompleter, merge_completions
26
22
  from . import __version__
27
23
 
24
+ import nest_asyncio
25
+ nest_asyncio.apply()
26
+
27
+ import asyncio
28
+
28
29
  def enter_repl(state: ReplState):
29
30
  if os.getenv('QING_DROPPED', 'false') == 'true':
30
31
  log2('You have dropped to bash from another qing instance. Please enter "exit" to go back to qing.')
@@ -50,34 +51,32 @@ def enter_repl(state: ReplState):
50
51
  def _(event):
51
52
  event.app.current_buffer.text = ''
52
53
 
53
- with concurrent.futures.ThreadPoolExecutor(max_workers=Config().get('audit.workers', 3)) as executor:
54
+ with Audits.offload() as exec:
54
55
  # warm up AWS lambda - this log line may timeout and get lost, which is fine
55
- executor.submit(Audits.log, 'entering kaqing repl', state.namespace, 'z', 0.0)
56
+ exec.submit(Audits.log, 'entering kaqing repl', state.namespace, 'z', 0.0)
56
57
 
57
58
  s0 = time.time()
58
59
 
59
60
  # use sorted command list only for auto-completion
60
61
  sorted_cmds = sorted(cmd_list, key=lambda cmd: cmd.command())
61
62
  while True:
63
+ cmd: str = None
62
64
  result = None
63
65
  try:
64
66
  completer = ReplCompleter.from_nested_dict({})
65
67
  if not state.bash_session:
66
- completions = {}
67
- # app commands are available only on a: drive
68
- if state.device == ReplState.A and state.app_app:
69
- completions = Apps(path='apps.yaml').commands()
70
-
71
- for cmd in sorted_cmds:
72
- s1 = time.time()
73
- try:
74
- completions = deep_sort_dict(deep_merge_dicts(completions, cmd.completion(state)))
75
- finally:
76
- if Config().get('debugs.timings', False):
77
- log2(f'Timing auto-completion-calc {cmd.command()}: {time.time() - s1:.2f}')
78
-
79
- # print(json.dumps(completions, indent=4))
80
- completer = ReplCompleter.from_nested_dict(completions)
68
+ with log_timing('completion-calcs'):
69
+ completions = {}
70
+ # app commands are available only on a: drive
71
+ if state.device == ReplState.A and state.app_app:
72
+ completions = log_timing('actions', lambda: Apps(path='apps.yaml').commands())
73
+
74
+ for c in sorted_cmds:
75
+ with log_exc(f'* {c.command()} command returned None completions.'):
76
+ completions = log_timing(c.command(), lambda: deep_sort_dict(merge_completions(completions, c.completion(state))))
77
+
78
+ # print(json.dumps(completions, indent=4))
79
+ completer = ReplCompleter.from_nested_dict(completions)
81
80
 
82
81
  cmd = session.prompt(prompt_msg(), completer=completer, key_bindings=kb)
83
82
  s0 = time.time()
@@ -94,17 +93,17 @@ def enter_repl(state: ReplState):
94
93
  return state, cmd
95
94
 
96
95
  if state.device == ReplState.A and state.app_app or state.device == ReplState.P:
97
- state.push()
96
+ state.push(pod_targetted=True)
98
97
 
99
98
  state.app_pod = arry[0].strip('@')
100
99
  cmd = ' '.join(arry[1:])
101
100
  elif state.device == ReplState.P:
102
- state.push()
101
+ state.push(pod_targetted=True)
103
102
 
104
103
  state.app_pod = arry[0].strip('@')
105
104
  cmd = ' '.join(arry[1:])
106
105
  elif state.sts:
107
- state.push()
106
+ state.push(pod_targetted=True)
108
107
 
109
108
  state.pod = arry[0].strip('@')
110
109
  cmd = ' '.join(arry[1:])
@@ -112,8 +111,13 @@ def enter_repl(state: ReplState):
112
111
  return (state, cmd)
113
112
 
114
113
  target, cmd = targetted(state, cmd)
115
- if cmd and cmd.strip(' ') and not (result := cmds.run(cmd, target)):
116
- result = try_device_default_action(target, cmds, cmd_list, cmd)
114
+ try:
115
+ if cmd and cmd.strip(' ') and not (result := cmds.run(cmd, target)):
116
+ result = try_device_default_action(target, cmds, cmd_list, cmd)
117
+ except InvalidStateException:
118
+ pass
119
+ except InvalidArgumentsException:
120
+ pass
117
121
 
118
122
  if result and type(result) is ReplState and (s := cast(ReplState, result).export_session) != state.export_session:
119
123
  state.export_session = s
@@ -125,27 +129,26 @@ def enter_repl(state: ReplState):
125
129
  raise e
126
130
  else:
127
131
  log2(e)
128
- Config().debug(traceback.format_exc())
132
+ debug_trace()
129
133
  finally:
130
134
  if not state.bash_session:
131
135
  state.pop()
132
136
 
133
- Config().clear_wait_log_flag()
134
- if Config().get('debugs.timings', False) and 'cmd' in locals() and 's0' in locals():
135
- log2(f'Timing command {cmd}: {time.time() - s0:.2f}')
137
+ clear_wait_log_flag()
138
+ if cmd:
139
+ log_timing(f'command {cmd}', s0=s0)
136
140
 
137
141
  # offload audit logging
138
142
  if cmd and (state.device != ReplState.L or Config().get('audit.log-audit-queries', False)):
139
- executor.submit(Audits.log, cmd, state.namespace, state.device, time.time() - s0, get_audit_extra(result))
143
+ exec.submit(Audits.log, cmd, state.namespace, state.device, time.time() - s0, get_audit_extra(result))
140
144
 
141
145
  def try_device_default_action(state: ReplState, cmds: Command, cmd_list: list[Command], cmd: str):
142
- default_action_tried, result = Devices.device(state).try_fallback_action(cmds, state, cmd)
146
+ action_taken, result = Devices.device(state).try_fallback_action(cmds, state, cmd)
143
147
 
144
- if not default_action_tried:
148
+ if not action_taken:
145
149
  log2(f'* Invalid command: {cmd}')
146
150
  log2()
147
- lines = [c.help(state) for c in cmd_list if c.help(state)]
148
- log2(lines_to_tabular(lines, separator='\t'))
151
+ tabulize([c.help(state) for c in cmd_list if c.help(state)], separator='\t', to=2)
149
152
 
150
153
  return result
151
154
 
@@ -177,6 +180,9 @@ def repl(kubeconfig: str, config: str, param: list[str], cluster:str, namespace:
177
180
  if not KubeContext.init_params(config, param):
178
181
  return
179
182
 
180
- state = ReplState(device=Config().get('repl.start-drive', 'a'), ns_sts=cluster, namespace=namespace, in_repl=True)
183
+ state = ReplState(ns_sts=cluster, namespace=namespace, in_repl=True)
181
184
  state, _ = state.apply_device_arg(extra_args)
185
+ if not state.device:
186
+ state.device=Config().get('repl.start-drive', 'a')
187
+
182
188
  enter_repl(state)
adam/repl_commands.py CHANGED
@@ -1,9 +1,13 @@
1
1
  from adam.commands.alter_tables import AlterTables
2
- from adam.commands.app import App
3
- from adam.commands.app_ping import AppPing
2
+ from adam.commands.app.app import App
3
+ from adam.commands.app.app_ping import AppPing
4
+ from adam.commands.app.show_app_actions import ShowAppActions
5
+ from adam.commands.app.show_app_id import ShowAppId
6
+ from adam.commands.app.show_app_queues import ShowAppQueues
4
7
  from adam.commands.audit.audit import Audit
5
8
  from adam.commands.cat import Cat
6
9
  from adam.commands.code import Code
10
+ from adam.commands.download_file import DownloadFile
7
11
  from adam.commands.deploy.code_start import CodeStart
8
12
  from adam.commands.deploy.code_stop import CodeStop
9
13
  from adam.commands.deploy.deploy import Deploy
@@ -19,23 +23,27 @@ from adam.commands.devices.device_auit_log import DeviceAuditLog
19
23
  from adam.commands.devices.device_cass import DeviceCass
20
24
  from adam.commands.devices.device_export import DeviceExport
21
25
  from adam.commands.devices.device_postgres import DevicePostgres
26
+ from adam.commands.export.download_export_session import DownloadExportSession
22
27
  from adam.commands.export.drop_export_database import DropExportDatabase
23
28
  from adam.commands.export.export import ExportTables
29
+ from adam.commands.export.import_files import ImportCSVFiles
24
30
  from adam.commands.export.import_session import ImportSession
25
- from adam.commands.export.clean_up_export_session import CleanUpExportSession
26
31
  from adam.commands.export.clean_up_export_sessions import CleanUpExportSessions
32
+ from adam.commands.export.clean_up_all_export_sessions import CleanUpAllExportSessions
27
33
  from adam.commands.export.drop_export_databases import DropExportDatabases
28
- from adam.commands.export.export_select import ExportSelect
34
+ from adam.commands.export.export_x_select import ExportXSelect
29
35
  from adam.commands.export.export_use import ExportUse
30
- from adam.commands.export.export_select_x import ExportSelectX
36
+ from adam.commands.export.export_select import ExportSelect
31
37
  from adam.commands.export.show_column_counts import ShowColumnCounts
32
38
  from adam.commands.export.show_export_databases import ShowExportDatabases
33
39
  from adam.commands.export.show_export_session import ShowExportSession
34
40
  from adam.commands.export.show_export_sessions import ShowExportSessions
41
+ from adam.commands.find_files import FindLocalFiles
42
+ from adam.commands.find_processes import FindProcesses
43
+ from adam.commands.head import Head
35
44
  from adam.commands.kubectl import Kubectl
36
45
  from adam.commands.shell import Shell
37
- from adam.commands.show.show_app_queues import ShowAppQueues
38
- from adam.commands.cp import ClipboardCopy
46
+ from adam.commands.clipboard_copy import ClipboardCopy
39
47
  from adam.commands.bash.bash import Bash
40
48
  from adam.commands.cd import Cd
41
49
  from adam.commands.check import Check
@@ -57,16 +65,14 @@ from adam.commands.restart import Restart
57
65
  from adam.commands.rollout import RollOut
58
66
  from adam.commands.param_set import SetParam
59
67
  from adam.commands.show.show import Show
60
- from adam.commands.show.show_app_actions import ShowAppActions
61
- from adam.commands.show.show_app_id import ShowAppId
62
68
  from adam.commands.show.show_cassandra_status import ShowCassandraStatus
63
69
  from adam.commands.show.show_cassandra_version import ShowCassandraVersion
64
- from adam.commands.show.show_commands import ShowKubectlCommands
70
+ from adam.commands.show.show_cli_commands import ShowKubectlCommands
65
71
  from adam.commands.show.show_host import ShowHost
66
72
  from adam.commands.show.show_login import ShowLogin
67
73
  from adam.commands.show.show_params import ShowParams
68
74
  from adam.commands.show.show_processes import ShowProcesses
69
- from adam.commands.show.show_repairs import ShowRepairs
75
+ from adam.commands.show.show_cassandra_repairs import ShowCassandraRepairs
70
76
  from adam.commands.show.show_storage import ShowStorage
71
77
  from adam.commands.show.show_adam import ShowAdam
72
78
  from adam.commands.watch import Watch
@@ -93,17 +99,18 @@ class ReplCommands:
93
99
  return deduped
94
100
 
95
101
  def navigation() -> list[Command]:
96
- return [Ls(), PreviewTable(), DeviceApp(), DevicePostgres(), DeviceCass(), DeviceAuditLog(), DeviceExport(), Cd(), Cat(), Pwd(), ClipboardCopy(),
102
+ return [Ls(), PreviewTable(), DeviceApp(), DevicePostgres(), DeviceCass(), DeviceAuditLog(), DeviceExport(),
103
+ Cd(), Cat(), Head(), DownloadFile(), FindLocalFiles(), FindProcesses(), Pwd(), ClipboardCopy(),
97
104
  GetParam(), SetParam(), ShowParams(), ShowKubectlCommands(), ShowLogin(), ShowAdam(), ShowHost()]
98
105
 
99
106
  def cassandra_ops() -> list[Command]:
100
- return [Cqlsh(), ShowCassandraStatus(), ShowCassandraVersion(), ShowRepairs(), ShowStorage(), ShowProcesses(),
107
+ return [Cqlsh(), ShowCassandraStatus(), ShowCassandraVersion(), ShowCassandraRepairs(), ShowStorage(), ShowProcesses(),
101
108
  Check(), Issues(), NodeTool(), Report(), AlterTables(), Bash(),
102
- ExportTables(), ExportSelect(), ExportUse(), ShowExportDatabases(), ShowColumnCounts(),
109
+ ExportTables(), ExportXSelect(), ExportUse(), ShowExportDatabases(), ShowColumnCounts(),
103
110
  DropExportDatabase(), DropExportDatabases(),
104
- ShowExportSessions(), ShowExportSession(),
105
- CleanUpExportSession(), CleanUpExportSessions(), ImportSession()] + \
106
- Medusa.cmd_list() + [Restart(), RollOut(), Watch()] + Reaper.cmd_list() + Repair.cmd_list()
111
+ ShowExportSessions(), ShowExportSession(), DownloadExportSession(),
112
+ CleanUpExportSessions(), CleanUpAllExportSessions(), ImportSession(), ImportCSVFiles()] + \
113
+ Medusa().cmd_list() + [Restart(), RollOut(), Watch()] + Reaper().cmd_list() + Repair().cmd_list()
107
114
 
108
115
  def postgres_ops() -> list[Command]:
109
116
  return [Postgres(), DeployPgAgent(), UndeployPgAgent(), PostgresPg()]
@@ -112,10 +119,10 @@ class ReplCommands:
112
119
  return [ShowAppActions(), ShowAppId(), ShowAppQueues(), AppPing(), App()]
113
120
 
114
121
  def audit_ops() -> list[Command]:
115
- return [Audit()] + Audit.cmd_list()
122
+ return [Audit()] + Audit().cmd_list()
116
123
 
117
124
  def export_ops() -> list[Command]:
118
- return [ExportSelectX(), DropExportDatabase(), DropExportDatabases(), ShowColumnCounts()]
125
+ return [ExportSelect(), DropExportDatabase(), DropExportDatabases(), ShowColumnCounts()]
119
126
 
120
127
  def tools() -> list[Command]:
121
128
  return [Shell(), CodeStart(), CodeStop(), DeployFrontend(), UndeployFrontend(), DeployPod(), UndeployPod(), Kubectl(), Code()]
adam/repl_session.py CHANGED
@@ -1,6 +1,8 @@
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
+
4
6
  class ReplSession:
5
7
  # the singleton pattern
6
8
  def __new__(cls, *args, **kwargs):
@@ -10,4 +12,9 @@ class ReplSession:
10
12
 
11
13
  def __init__(self):
12
14
  if not hasattr(self, 'prompt_session'):
13
- self.prompt_session = PromptSession(auto_suggest=AutoSuggestFromHistory())
15
+ self.prompt_session = PromptSession(auto_suggest=AutoSuggestFromHistory())
16
+
17
+ def append_history(self, entry: str):
18
+ if entry and Config().get('repl.history.push-cat-remote-log-file', True):
19
+ if self.prompt_session:
20
+ self.prompt_session.history.append_string(entry)