kaqing 2.0.184__py3-none-any.whl → 2.0.227__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 (205) hide show
  1. adam/app_session.py +1 -1
  2. adam/batch.py +15 -15
  3. adam/checks/compactionstats.py +2 -1
  4. adam/checks/cpu.py +2 -1
  5. adam/checks/disk.py +6 -5
  6. adam/checks/gossip.py +2 -1
  7. adam/checks/memory.py +2 -1
  8. adam/checks/status.py +2 -1
  9. adam/commands/app/app.py +4 -4
  10. adam/commands/app/app_ping.py +2 -2
  11. adam/commands/{login.py → app/login.py} +2 -2
  12. adam/commands/app/show_app_actions.py +3 -3
  13. adam/commands/app/show_app_id.py +2 -2
  14. adam/commands/app/show_app_queues.py +2 -2
  15. adam/commands/{show → app}/show_login.py +3 -3
  16. adam/commands/app/utils_app.py +9 -1
  17. adam/commands/audit/audit.py +8 -24
  18. adam/commands/audit/audit_repair_tables.py +3 -3
  19. adam/commands/audit/audit_run.py +3 -3
  20. adam/commands/audit/completions_l.py +15 -0
  21. adam/commands/audit/show_last10.py +2 -3
  22. adam/commands/audit/show_slow10.py +2 -2
  23. adam/commands/audit/show_top10.py +2 -2
  24. adam/commands/bash/bash.py +3 -3
  25. adam/commands/bash/utils_bash.py +1 -1
  26. adam/commands/cassandra/download_cassandra_log.py +45 -0
  27. adam/commands/cassandra/restart_cluster.py +47 -0
  28. adam/commands/cassandra/restart_node.py +51 -0
  29. adam/commands/cassandra/restart_nodes.py +47 -0
  30. adam/commands/{rollout.py → cassandra/rollout.py} +3 -3
  31. adam/commands/{show → cassandra}/show_cassandra_repairs.py +7 -5
  32. adam/commands/{show → cassandra}/show_cassandra_status.py +24 -17
  33. adam/commands/{show → cassandra}/show_cassandra_version.py +2 -2
  34. adam/commands/cassandra/show_processes.py +50 -0
  35. adam/commands/cassandra/show_storage.py +44 -0
  36. adam/commands/{watch.py → cassandra/watch.py} +2 -2
  37. adam/commands/cli/__init__.py +0 -0
  38. adam/commands/{cli_commands.py → cli/cli_commands.py} +6 -1
  39. adam/commands/{clipboard_copy.py → cli/clipboard_copy.py} +4 -4
  40. adam/commands/{show/show_commands.py → cli/show_cli_commands.py} +5 -5
  41. adam/commands/code.py +2 -2
  42. adam/commands/command.py +54 -14
  43. adam/commands/commands_utils.py +14 -6
  44. adam/commands/config/__init__.py +0 -0
  45. adam/commands/{param_get.py → config/param_get.py} +2 -2
  46. adam/commands/{param_set.py → config/param_set.py} +2 -2
  47. adam/commands/{show → config}/show_params.py +3 -3
  48. adam/commands/{alter_tables.py → cql/alter_tables.py} +3 -3
  49. adam/commands/cql/completions_c.py +29 -0
  50. adam/commands/cql/cqlsh.py +4 -8
  51. adam/commands/cql/utils_cql.py +36 -17
  52. adam/commands/debug/__init__.py +0 -0
  53. adam/commands/debug/debug.py +22 -0
  54. adam/commands/debug/debug_completes.py +35 -0
  55. adam/commands/debug/debug_timings.py +35 -0
  56. adam/commands/debug/show_offloaded_completes.py +45 -0
  57. adam/commands/deploy/code_start.py +2 -2
  58. adam/commands/deploy/code_stop.py +2 -2
  59. adam/commands/deploy/deploy_frontend.py +2 -2
  60. adam/commands/deploy/deploy_pg_agent.py +2 -2
  61. adam/commands/deploy/deploy_pod.py +2 -2
  62. adam/commands/deploy/undeploy_frontend.py +2 -2
  63. adam/commands/deploy/undeploy_pg_agent.py +2 -2
  64. adam/commands/deploy/undeploy_pod.py +2 -2
  65. adam/commands/devices/device.py +37 -11
  66. adam/commands/devices/device_app.py +7 -7
  67. adam/commands/devices/device_auit_log.py +2 -2
  68. adam/commands/devices/device_cass.py +6 -6
  69. adam/commands/devices/device_export.py +7 -4
  70. adam/commands/devices/device_postgres.py +19 -9
  71. adam/commands/devices/devices.py +1 -1
  72. adam/commands/diag/__init__.py +0 -0
  73. adam/commands/{check.py → diag/check.py} +3 -3
  74. adam/commands/diag/generate_report.py +52 -0
  75. adam/commands/{issues.py → diag/issues.py} +3 -2
  76. adam/commands/exit.py +2 -2
  77. adam/commands/export/clean_up_all_export_sessions.py +2 -2
  78. adam/commands/export/clean_up_export_sessions.py +2 -2
  79. adam/commands/export/completions_x.py +11 -0
  80. adam/commands/export/download_export_session.py +5 -5
  81. adam/commands/export/drop_export_database.py +2 -2
  82. adam/commands/export/drop_export_databases.py +2 -2
  83. adam/commands/export/export.py +3 -19
  84. adam/commands/export/export_databases.py +20 -11
  85. adam/commands/export/export_select.py +9 -34
  86. adam/commands/export/export_sessions.py +13 -11
  87. adam/commands/export/export_use.py +6 -6
  88. adam/commands/export/export_x_select.py +48 -0
  89. adam/commands/export/exporter.py +140 -53
  90. adam/commands/export/import_files.py +3 -7
  91. adam/commands/export/import_session.py +2 -6
  92. adam/commands/export/importer.py +12 -13
  93. adam/commands/export/importer_athena.py +15 -35
  94. adam/commands/export/importer_sqlite.py +19 -8
  95. adam/commands/export/show_column_counts.py +11 -12
  96. adam/commands/export/show_export_databases.py +4 -4
  97. adam/commands/export/show_export_session.py +5 -5
  98. adam/commands/export/show_export_sessions.py +4 -4
  99. adam/commands/export/utils_export.py +40 -25
  100. adam/commands/fs/__init__.py +0 -0
  101. adam/commands/{cat.py → fs/cat.py} +4 -4
  102. adam/commands/fs/cat_local.py +42 -0
  103. adam/commands/{cd.py → fs/cd.py} +4 -4
  104. adam/commands/{download_file.py → fs/download_file.py} +7 -7
  105. adam/commands/{find_files.py → fs/find_files.py} +7 -7
  106. adam/commands/{find_processes.py → fs/find_processes.py} +14 -22
  107. adam/commands/{head.py → fs/head.py} +5 -5
  108. adam/commands/fs/head_local.py +46 -0
  109. adam/commands/{ls.py → fs/ls.py} +4 -4
  110. adam/commands/fs/ls_local.py +40 -0
  111. adam/commands/{pwd.py → fs/pwd.py} +2 -2
  112. adam/commands/fs/rm.py +18 -0
  113. adam/commands/fs/rm_downloads.py +39 -0
  114. adam/commands/fs/rm_logs.py +44 -0
  115. adam/commands/fs/rm_logs_local.py +38 -0
  116. adam/commands/{shell.py → fs/shell.py} +2 -2
  117. adam/commands/{show → fs}/show_adam.py +3 -3
  118. adam/commands/{show → fs}/show_host.py +2 -2
  119. adam/commands/fs/show_last_results.py +39 -0
  120. adam/commands/fs/tail.py +36 -0
  121. adam/commands/fs/tail_local.py +46 -0
  122. adam/commands/fs/utils_fs.py +192 -0
  123. adam/commands/help.py +2 -2
  124. adam/commands/intermediate_command.py +3 -0
  125. adam/commands/kubectl.py +2 -2
  126. adam/commands/medusa/medusa_backup.py +2 -2
  127. adam/commands/medusa/medusa_restore.py +4 -18
  128. adam/commands/medusa/medusa_show_backupjobs.py +2 -2
  129. adam/commands/medusa/medusa_show_restorejobs.py +2 -2
  130. adam/commands/medusa/utils_medusa.py +15 -0
  131. adam/commands/nodetool/__init__.py +0 -0
  132. adam/commands/nodetool/nodetool.py +87 -0
  133. adam/commands/nodetool/utils_nodetool.py +44 -0
  134. adam/commands/postgres/completions_p.py +22 -0
  135. adam/commands/postgres/postgres.py +10 -20
  136. adam/commands/postgres/postgres_databases.py +3 -3
  137. adam/commands/postgres/postgres_ls.py +3 -3
  138. adam/commands/postgres/postgres_preview.py +2 -2
  139. adam/commands/postgres/utils_postgres.py +12 -2
  140. adam/commands/preview_table.py +3 -4
  141. adam/commands/reaper/reaper_forward.py +2 -2
  142. adam/commands/reaper/reaper_forward_stop.py +2 -2
  143. adam/commands/reaper/reaper_restart.py +2 -2
  144. adam/commands/reaper/reaper_run_abort.py +2 -2
  145. adam/commands/reaper/reaper_runs.py +14 -12
  146. adam/commands/reaper/reaper_runs_abort.py +2 -2
  147. adam/commands/reaper/reaper_schedule_activate.py +8 -4
  148. adam/commands/reaper/reaper_schedule_start.py +3 -4
  149. adam/commands/reaper/reaper_schedule_stop.py +3 -4
  150. adam/commands/reaper/reaper_schedules.py +2 -2
  151. adam/commands/reaper/reaper_status.py +2 -2
  152. adam/commands/reaper/utils_reaper.py +41 -6
  153. adam/commands/repair/repair_log.py +2 -2
  154. adam/commands/repair/repair_run.py +2 -2
  155. adam/commands/repair/repair_scan.py +2 -4
  156. adam/commands/repair/repair_stop.py +2 -3
  157. adam/commands/{show/show.py → show.py} +12 -11
  158. adam/config.py +4 -5
  159. adam/embedded_params.py +1 -1
  160. adam/repl.py +24 -10
  161. adam/repl_commands.py +68 -45
  162. adam/repl_session.py +16 -1
  163. adam/repl_state.py +16 -1
  164. adam/sql/async_executor.py +62 -0
  165. adam/sql/lark_completer.py +286 -0
  166. adam/sql/lark_parser.py +604 -0
  167. adam/sql/qingl.lark +1075 -0
  168. adam/sso/cred_cache.py +2 -5
  169. adam/utils.py +259 -82
  170. adam/utils_async_job.py +73 -0
  171. adam/utils_k8s/app_clusters.py +11 -4
  172. adam/utils_k8s/app_pods.py +10 -5
  173. adam/utils_k8s/cassandra_clusters.py +19 -7
  174. adam/utils_k8s/cassandra_nodes.py +16 -6
  175. adam/utils_k8s/k8s.py +9 -0
  176. adam/utils_k8s/kube_context.py +1 -4
  177. adam/{pod_exec_result.py → utils_k8s/pod_exec_result.py} +8 -2
  178. adam/utils_k8s/pods.py +189 -29
  179. adam/utils_k8s/statefulsets.py +5 -2
  180. adam/utils_local.py +78 -2
  181. adam/utils_repl/appendable_completer.py +6 -0
  182. adam/utils_repl/repl_completer.py +51 -4
  183. adam/utils_sqlite.py +3 -8
  184. adam/version.py +1 -1
  185. {kaqing-2.0.184.dist-info → kaqing-2.0.227.dist-info}/METADATA +1 -1
  186. kaqing-2.0.227.dist-info/RECORD +280 -0
  187. kaqing-2.0.227.dist-info/top_level.txt +2 -0
  188. teddy/__init__.py +0 -0
  189. teddy/lark_parser.py +436 -0
  190. teddy/lark_parser2.py +618 -0
  191. adam/commands/cql/cql_completions.py +0 -32
  192. adam/commands/export/export_select_x.py +0 -54
  193. adam/commands/logs.py +0 -37
  194. adam/commands/nodetool.py +0 -69
  195. adam/commands/postgres/psql_completions.py +0 -11
  196. adam/commands/report.py +0 -61
  197. adam/commands/restart.py +0 -60
  198. adam/commands/show/show_processes.py +0 -49
  199. adam/commands/show/show_storage.py +0 -42
  200. kaqing-2.0.184.dist-info/RECORD +0 -244
  201. kaqing-2.0.184.dist-info/top_level.txt +0 -1
  202. /adam/commands/{show → cassandra}/__init__.py +0 -0
  203. /adam/commands/{nodetool_commands.py → nodetool/nodetool_commands.py} +0 -0
  204. {kaqing-2.0.184.dist-info → kaqing-2.0.227.dist-info}/WHEEL +0 -0
  205. {kaqing-2.0.184.dist-info → kaqing-2.0.227.dist-info}/entry_points.txt +0 -0
@@ -1,5 +1,5 @@
1
1
  from adam.commands.command import Command
2
- from adam.commands.ls import Ls
2
+ from adam.commands.fs.ls import Ls
3
3
  from adam.repl_state import ReplState, RequiredState
4
4
 
5
5
  class PostgresLs(Command):
@@ -37,5 +37,5 @@ class PostgresLs(Command):
37
37
 
38
38
  return {}
39
39
 
40
- def help(self, _: ReplState):
41
- return f'{PostgresLs.COMMAND}\t list postgres hosts, databases or tables'
40
+ def help(self, state: ReplState):
41
+ return super().help(state, 'list postgres hosts, databases or tables')
@@ -37,5 +37,5 @@ class PostgresPreview(Command):
37
37
 
38
38
  return {}
39
39
 
40
- def help(self, _: ReplState):
41
- return f'{PostgresPreview.COMMAND}\t preview postgres table'
40
+ def help(self, state: ReplState):
41
+ return super().help(state, 'preview postgres table')
@@ -1,12 +1,22 @@
1
1
  import functools
2
2
 
3
- from adam.commands.postgres.postgres_databases import PostgresDatabases
3
+ from adam.commands.postgres.postgres_databases import PostgresDatabases, pg_path
4
+ from adam.config import Config
4
5
  from adam.repl_state import ReplState
5
6
  from adam.utils import log2, wait_log
6
7
  from adam.utils_k8s.pods import Pods
7
8
 
8
9
  TestPG = [False]
9
10
 
11
+ def direct_dirs(state: ReplState) -> list[str]:
12
+ with pg_path(state) as (host, database):
13
+ if database:
14
+ return ['..']
15
+ elif host:
16
+ return ['..'] + pg_database_names(state)
17
+ else:
18
+ return PostgresDatabases.host_names(state.namespace)
19
+
10
20
  def pg_database_names(state: ReplState):
11
21
  # cache on pg_path
12
22
  return _pg_database_names(state, state.pg_path)
@@ -53,7 +63,7 @@ class PostgresPodService:
53
63
  if isinstance(args, list):
54
64
  query = ' '.join(args)
55
65
 
56
- PostgresDatabases.run_sql(state, query, backgrounded=backgrounded)
66
+ PostgresDatabases.run_sql(state, query, show_out=Config().is_debug(), backgrounded=backgrounded)
57
67
 
58
68
  class PostgresExecHandler:
59
69
  def __init__(self, state: ReplState, backgrounded=False):
@@ -27,13 +27,12 @@ class PreviewTable(Command):
27
27
 
28
28
  with self.validate(args, state) as (args, state):
29
29
  with validate_args(args, state, at_least=1) as table:
30
- Devices.device(state).preview(table, state)
30
+ Devices.of(state).preview(table, state)
31
31
 
32
32
  return state
33
33
 
34
34
  def completion(self, _: ReplState):
35
- # taken care of by the sql completer
36
35
  return {}
37
36
 
38
- def help(self, _: ReplState):
39
- return f'{PreviewTable.COMMAND} TABLE\t preview table'
37
+ def help(self, state: ReplState):
38
+ return super().help(state, 'preview table', args='TABLE')
@@ -89,5 +89,5 @@ class ReaperForward(Command):
89
89
  def completion(self, state: ReplState):
90
90
  return super().completion(state)
91
91
 
92
- def help(self, _: ReplState):
93
- return f'{ReaperForward.COMMAND}\t port-forward to reaper'
92
+ def help(self, state: ReplState):
93
+ return super().help(state, 'port-forward to reaper')
@@ -39,5 +39,5 @@ class ReaperForwardStop(Command):
39
39
  def completion(self, state: ReplState):
40
40
  return super().completion(state)
41
41
 
42
- def help(self, _: ReplState):
43
- return f'{ReaperForwardStop.COMMAND}\t stop port-forward to reaper'
42
+ def help(self, state: ReplState):
43
+ return super().help(state, 'stop port-forward to reaper')
@@ -36,5 +36,5 @@ class ReaperRestart(Command):
36
36
  def completion(self, state: ReplState):
37
37
  return super().completion(state)
38
38
 
39
- def help(self, _: ReplState):
40
- return f'{ReaperRestart.COMMAND}\t restart reaper'
39
+ def help(self, state: ReplState):
40
+ return super().help(state, 'restart reaper')
@@ -36,5 +36,5 @@ class ReaperRunAbort(Command):
36
36
  def completion(self, state: ReplState):
37
37
  return super().completion(state)
38
38
 
39
- def help(self, _: ReplState):
40
- return f'{ReaperRunAbort.COMMAND} <run-id>\t abort reaper run'
39
+ def help(self, state: ReplState):
40
+ return super().help(state, 'abort reaper run', args='<run-id>')
@@ -1,8 +1,8 @@
1
1
  from adam.commands.command import Command
2
- from adam.commands.reaper.utils_reaper import reaper
2
+ from adam.commands.reaper.utils_reaper import reaper, Reapers
3
3
  from adam.config import Config
4
4
  from adam.repl_state import ReplState, RequiredState
5
- from adam.utils import convert_seconds, epoch, tabulize, log, log2
5
+ from adam.utils import convert_seconds, epoch, log2
6
6
 
7
7
  class ReaperRuns(Command):
8
8
  COMMAND = 'reaper show runs'
@@ -52,10 +52,11 @@ class ReaperRuns(Command):
52
52
  'limit': Config().get('reaper.show-runs-batch', 10)
53
53
  })
54
54
 
55
- runs = response.json()
56
- if runs:
57
- tabulize(sorted([line(run) for run in runs], reverse=True), header=header, separator=",")
58
- else:
55
+ if not Reapers.tabulize_runs(state, response):
56
+ # runs = response.json()
57
+ # if runs:
58
+ # tabulize(sorted([line(run) for run in runs], reverse=True), header=header, separator=",")
59
+ # else:
59
60
  log2('No running runs found.')
60
61
  log2()
61
62
 
@@ -64,10 +65,11 @@ class ReaperRuns(Command):
64
65
  'limit': Config().get('reaper.show-runs-batch', 10)
65
66
  })
66
67
 
67
- runs = response.json()
68
- if runs:
69
- tabulize(sorted([line(run) for run in runs], reverse=True), header=header, separator=",")
70
- else:
68
+ if not Reapers.tabulize_runs(state, response):
69
+ # runs = response.json()
70
+ # if runs:
71
+ # tabulize(sorted([line(run) for run in runs], reverse=True), header=header, separator=",")
72
+ # else:
71
73
  log2('No runs found.')
72
74
 
73
75
  return state
@@ -78,5 +80,5 @@ class ReaperRuns(Command):
78
80
 
79
81
  return {}
80
82
 
81
- def help(self, _: ReplState):
82
- return f'{ReaperRuns.COMMAND}\t show reaper runs'
83
+ def help(self, state: ReplState):
84
+ return super().help(state, 'show reaper runs')
@@ -59,5 +59,5 @@ class ReaperRunsAbort(Command):
59
59
  def completion(self, state: ReplState):
60
60
  return super().completion(state)
61
61
 
62
- def help(self, _: ReplState):
63
- return f'{ReaperRunsAbort.COMMAND}\t abort all running reaper runs'
62
+ def help(self, state: ReplState):
63
+ return super().help(state, 'abort all running reaper runs')
@@ -2,7 +2,11 @@ from adam.commands import validate_args
2
2
  from adam.commands.command import Command
3
3
  from adam.commands.reaper.utils_reaper import Reapers, reaper
4
4
  from adam.repl_state import ReplState, RequiredState
5
- from adam.utils import log2
5
+
6
+ import nest_asyncio
7
+ nest_asyncio.apply()
8
+
9
+ import asyncio
6
10
 
7
11
  class ReaperScheduleActivate(Command):
8
12
  COMMAND = 'reaper activate schedule'
@@ -35,7 +39,7 @@ class ReaperScheduleActivate(Command):
35
39
  return schedule_id
36
40
 
37
41
  def completion(self, state: ReplState):
38
- return super().completion(state, lambda: {id: None for id in Reapers.cached_schedule_ids(state)})
42
+ return super().completion(state, lambda: {id: None for id in Reapers.cached_schedule_ids(state)}, auto_key='reaper.schedules')
39
43
 
40
- def help(self, _: ReplState):
41
- return f'{ReaperScheduleActivate.COMMAND} <schedule-id>\t resume reaper schedule'
44
+ def help(self, state: ReplState):
45
+ return super().help(state, 'resume reaper schedule', args='<schedule-id>')
@@ -2,7 +2,6 @@ from adam.commands import validate_args
2
2
  from adam.commands.command import Command
3
3
  from adam.commands.reaper.utils_reaper import Reapers, reaper
4
4
  from adam.repl_state import ReplState, RequiredState
5
- from adam.utils import log2
6
5
 
7
6
  class ReaperScheduleStart(Command):
8
7
  COMMAND = 'reaper start schedule'
@@ -35,7 +34,7 @@ class ReaperScheduleStart(Command):
35
34
  return schedule_id
36
35
 
37
36
  def completion(self, state: ReplState):
38
- return super().completion(state, lambda: {id: None for id in Reapers.cached_schedule_ids(state)})
37
+ return super().completion(state, lambda: {id: None for id in Reapers.cached_schedule_ids(state)}, auto_key='reaper.schedules')
39
38
 
40
- def help(self, _: ReplState):
41
- return f'{ReaperScheduleStart.COMMAND} <schedule-id>\t start reaper runs for schedule'
39
+ def help(self, state: ReplState):
40
+ return super().help(state, 'start reaper runs for schedule', args='<schedule-id>')
@@ -2,7 +2,6 @@ from adam.commands import validate_args
2
2
  from adam.commands.command import Command
3
3
  from adam.commands.reaper.utils_reaper import Reapers, reaper
4
4
  from adam.repl_state import ReplState, RequiredState
5
- from adam.utils import log2
6
5
 
7
6
  class ReaperScheduleStop(Command):
8
7
  COMMAND = 'reaper stop schedule'
@@ -35,7 +34,7 @@ class ReaperScheduleStop(Command):
35
34
  return schedule_id
36
35
 
37
36
  def completion(self, state: ReplState):
38
- return super().completion(state, lambda: {id: None for id in Reapers.cached_schedule_ids(state)})
37
+ return super().completion(state, lambda: {id: None for id in Reapers.cached_schedule_ids(state)}, auto_key='reaper.schedules')
39
38
 
40
- def help(self, _: ReplState):
41
- return f'{ReaperScheduleStop.COMMAND} <schedule-id>\t pause reaper schedule'
39
+ def help(self, state: ReplState):
40
+ return super().help(state, 'pause reaper schedule', args='<schedule-id>')
@@ -32,5 +32,5 @@ class ReaperSchedules(Command):
32
32
  def completion(self, state: ReplState):
33
33
  return super().completion(state)
34
34
 
35
- def help(self, _: ReplState):
36
- return f'{ReaperSchedules.COMMAND}\t show reaper schedules'
35
+ def help(self, state: ReplState):
36
+ return super().help(state, 'show reaper schedules')
@@ -52,5 +52,5 @@ class ReaperStatus(Command):
52
52
  def completion(self, state: ReplState):
53
53
  return super().completion(state)
54
54
 
55
- def help(self, _: ReplState):
56
- return f'{ReaperStatus.COMMAND}\t show reaper status'
55
+ def help(self, state: ReplState):
56
+ return super().help(state, 'show reaper status')
@@ -7,7 +7,7 @@ import re
7
7
  import requests
8
8
  from adam.config import Config
9
9
  from adam.repl_state import ReplState
10
- from adam.utils import tabulize, log2, wait_log
10
+ from adam.utils import Color, convert_seconds, epoch, tabulize, log2, wait_log
11
11
  from adam.utils_k8s.k8s import port_forwarding
12
12
 
13
13
  class ReaperService:
@@ -41,7 +41,7 @@ class ReaperLogginHandler:
41
41
  self.svc.headers = Reapers.cookie_header(self.svc.state, self.svc.local_addr, self.svc.remote_addr, show_output=self.svc.show_out)
42
42
 
43
43
  if self.svc.show_out and self.method:
44
- log2(f'{self.method} {self.svc.remote_addr}/{self.path}')
44
+ log2(f'{self.method} {self.svc.remote_addr}/{self.path}', text_color=Color.gray)
45
45
 
46
46
  return (f'http://{self.svc.local_addr}/{self.path}', self.svc.headers)
47
47
 
@@ -139,12 +139,12 @@ class Reapers:
139
139
  'username':user,
140
140
  'password':pw})
141
141
  if show_output:
142
- log2(f'POST {remote_addr}/login')
143
- log2(f' username={user}&password={pw}')
142
+ log2(f'POST {remote_addr}/login', text_color=Color.gray)
143
+ log2(f' username={user}&password={pw}', text_color=Color.gray)
144
144
 
145
145
  if int(response.status_code / 100) != 2:
146
146
  if show_output:
147
- log2("login failed")
147
+ log2("login failed", text_color=Color.gray)
148
148
  return None
149
149
 
150
150
  return response.headers['Set-Cookie']
@@ -191,4 +191,39 @@ class Reapers:
191
191
  if is_service:
192
192
  return Reapers.svc_name()
193
193
  else:
194
- return Reapers.pod_name(state)
194
+ return Reapers.pod_name(state)
195
+
196
+ def schedules_auto_completion(ids: callable):
197
+ auto = Config().get('reaper.schedules-auto-complete', 'off')
198
+
199
+ leaf = None
200
+ if auto == 'on':
201
+ leaf = {id: None for id in ids()}
202
+
203
+ return (leaf, auto == 'lazy')
204
+
205
+ def tabulize_runs(state: ReplState, response: dict) -> dict[str, any]:
206
+ header = 'ID,START,DURATION,STATE,CLUSTER,KEYSPACE,TABLES,REPAIRED'
207
+
208
+ def line(run):
209
+ id = run['id']
210
+ state = run['state']
211
+ start_time = run['start_time']
212
+ end_time = run['end_time']
213
+ duration = '-'
214
+ if state == 'DONE' and end_time:
215
+ hours, minutes, seconds = convert_seconds(epoch(end_time) - epoch(start_time))
216
+ if hours:
217
+ duration = f"{hours:2d}h {minutes:2d}m {seconds:2d}s"
218
+ elif minutes:
219
+ duration = f"{minutes:2d}m {seconds:2d}s"
220
+ else:
221
+ duration = f"{seconds:2d}s"
222
+
223
+ return f"{id},{start_time},{duration},{state},{run['cluster_name']},{run['keyspace_name']},{len(run['column_families'])},{run['segments_repaired']}/{run['total_segments']}"
224
+
225
+ runs = response.json()
226
+ if runs:
227
+ tabulize(sorted([line(run) for run in runs], reverse=True), header=header, separator=",")
228
+
229
+ return runs
@@ -33,5 +33,5 @@ class RepairLog(Command):
33
33
  def completion(self, state: ReplState):
34
34
  return super().completion(state)
35
35
 
36
- def help(self, _: ReplState):
37
- return f'{RepairLog.COMMAND}\t get repair job logs'
36
+ def help(self, state: ReplState):
37
+ return super().help(state, 'get repair job logs')
@@ -61,5 +61,5 @@ class RepairRun(Command):
61
61
  def completion(self, state: ReplState):
62
62
  return super().completion(state)
63
63
 
64
- def help(self, _: ReplState):
65
- return f'{RepairRun.COMMAND} [replace]\t start a repair job, default not replacing'
64
+ def help(self, state: ReplState):
65
+ return super().help(state, 'start a repair job, default not replacing', args='[replace]')
@@ -1,5 +1,3 @@
1
- import time
2
-
3
1
  from adam.commands.command import Command
4
2
  from adam.utils_k8s.pods import Pods
5
3
  from adam.repl_state import ReplState, RequiredState
@@ -64,5 +62,5 @@ class RepairScan(Command):
64
62
  def completion(self, state: ReplState):
65
63
  return super().completion(state)
66
64
 
67
- def help(self, _: ReplState):
68
- return f'{RepairScan.COMMAND} [n]\t scan last n days repair log, default 7 days'
65
+ def help(self, state: ReplState):
66
+ return super().help(state, 'scan last n days repair log, default 7 days')
@@ -1,7 +1,6 @@
1
1
  from adam.commands.command import Command
2
2
  from adam.utils_k8s.jobs import Jobs
3
3
  from adam.repl_state import ReplState, RequiredState
4
- from adam.config import Config
5
4
 
6
5
  class RepairStop(Command):
7
6
  COMMAND = 'repair stop'
@@ -34,5 +33,5 @@ class RepairStop(Command):
34
33
  def completion(self, state: ReplState):
35
34
  return super().completion(state)
36
35
 
37
- def help(self, _: ReplState):
38
- return f'{RepairStop.COMMAND}\t delete a repair job'
36
+ def help(self, state: ReplState):
37
+ return super().help(state, 'delete a repair job')
@@ -3,19 +3,20 @@ import click
3
3
  from adam.commands.app.show_app_actions import ShowAppActions
4
4
  from adam.commands.app.show_app_id import ShowAppId
5
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
6
15
  from adam.commands.intermediate_command import IntermediateCommand
7
16
  from adam.commands.medusa.medusa_show_backupjobs import MedusaShowBackupJobs
8
17
  from adam.commands.medusa.medusa_show_restorejobs import MedusaShowRestoreJobs
9
- from adam.commands.show.show_host import ShowHost
10
- from adam.commands.show.show_login import ShowLogin
11
- from .show_params import ShowParams
12
- from .show_cassandra_status import ShowCassandraStatus
13
- from .show_cassandra_version import ShowCassandraVersion
14
- from .show_commands import ShowKubectlCommands
15
- from .show_processes import ShowProcesses
16
- from .show_cassandra_repairs import ShowCassandraRepairs
17
- from .show_storage import ShowStorage
18
- from .show_adam import ShowAdam
18
+ from adam.commands.fs.show_host import ShowHost
19
+ from adam.commands.app.show_login import ShowLogin
19
20
 
20
21
  class Show(IntermediateCommand):
21
22
  COMMAND = 'show'
@@ -30,7 +31,7 @@ class Show(IntermediateCommand):
30
31
  return Show.COMMAND
31
32
 
32
33
  def cmd_list(self):
33
- return [ShowAppActions(), ShowAppId(), ShowAppQueues(), ShowHost(), ShowLogin(), ShowKubectlCommands(),
34
+ return [ShowAppActions(), ShowAppId(), ShowAppQueues(), ShowOffloadedCompletes(), ShowHost(), ShowLogin(), ShowKubectlCommands(),
34
35
  ShowParams(), ShowProcesses(), ShowCassandraRepairs(), ShowStorage(), ShowAdam(),
35
36
  ShowCassandraStatus(), ShowCassandraVersion(), MedusaShowRestoreJobs(), MedusaShowBackupJobs()]
36
37
 
adam/config.py CHANGED
@@ -3,16 +3,13 @@ from typing import TypeVar, cast
3
3
  import yaml
4
4
 
5
5
  from . import __version__
6
- from adam.utils import LogConfig, 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
- LogConfig.is_debug = lambda: Config().is_debug()
14
- LogConfig.is_debug_timing = lambda: Config().get('debugs.timings', False)
15
-
16
13
  # the singleton pattern
17
14
  def __new__(cls, *args, **kwargs):
18
15
  if not hasattr(cls, 'instance'): cls.instance = super(Config, cls).__new__(cls)
@@ -28,6 +25,8 @@ class Config:
28
25
  except:
29
26
  with open(copy_config_file(f'params.yaml.{__version__}', 'adam.embedded_params', show_out=not is_user_entry)) as f:
30
27
  self.params = cast(dict[str, any], yaml.safe_load(f))
28
+
29
+ ConfigHolder().config = self
31
30
  elif not hasattr(self, 'params'):
32
31
  with open(copy_config_file(f'params.yaml.{__version__}', 'adam.embedded_params', show_out=not is_user_entry)) as f:
33
32
  self.params = cast(dict[str, any], yaml.safe_load(f))
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'}, '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', 'medusa': {'restore-auto-complete': False}, '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}, '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', 'remote': {'log-dir': '/tmp/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}, 'job': {'log-to-pods': True}, '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, 'grace-period-after-abort': 10, '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-mpstat': {'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/repl.py CHANGED
@@ -3,6 +3,7 @@ import time
3
3
  from typing import cast
4
4
  import click
5
5
  from prompt_toolkit.key_binding import KeyBindings
6
+ from prompt_toolkit import HTML
6
7
 
7
8
  from adam.cli_group import cli
8
9
  from adam.commands.command import Command, InvalidArgumentsException, InvalidStateException
@@ -10,17 +11,23 @@ from adam.commands.command_helpers import ClusterCommandHelper
10
11
  from adam.commands.devices.devices import Devices
11
12
  from adam.commands.help import Help
12
13
  from adam.config import Config
14
+ from adam.sql.async_executor import AsyncExecutor
13
15
  from adam.utils_audits import Audits
14
16
  from adam.utils_k8s.kube_context import KubeContext
15
17
  from adam.log import Log
16
18
  from adam.repl_commands import ReplCommands
17
19
  from adam.repl_session import ReplSession
18
20
  from adam.repl_state import ReplState
19
- from adam.utils import clear_wait_log_flag, debug_trace, deep_merge_dicts, deep_sort_dict, tabulize, log2, log_exc, log_timing
21
+ from adam.utils import CommandLog, clear_wait_log_flag, debug_trace, deep_sort_dict, tabulize, log2, log_exc, log_timing
20
22
  from adam.apps import Apps
21
- from adam.utils_repl.repl_completer import ReplCompleter
23
+ from adam.utils_repl.repl_completer import ReplCompleter, merge_completions
22
24
  from . import __version__
23
25
 
26
+ import nest_asyncio
27
+ nest_asyncio.apply()
28
+
29
+ import asyncio
30
+
24
31
  def enter_repl(state: ReplState):
25
32
  if os.getenv('QING_DROPPED', 'false') == 'true':
26
33
  log2('You have dropped to bash from another qing instance. Please enter "exit" to go back to qing.')
@@ -38,7 +45,7 @@ def enter_repl(state: ReplState):
38
45
 
39
46
  Log.log2(f'kaqing {__version__}')
40
47
 
41
- Devices.device(state).enter(state)
48
+ Devices.of(state).enter(state)
42
49
 
43
50
  kb = KeyBindings()
44
51
 
@@ -55,6 +62,8 @@ def enter_repl(state: ReplState):
55
62
  # use sorted command list only for auto-completion
56
63
  sorted_cmds = sorted(cmd_list, key=lambda cmd: cmd.command())
57
64
  while True:
65
+ AsyncExecutor.reset()
66
+
58
67
  cmd: str = None
59
68
  result = None
60
69
  try:
@@ -68,12 +77,12 @@ def enter_repl(state: ReplState):
68
77
 
69
78
  for c in sorted_cmds:
70
79
  with log_exc(f'* {c.command()} command returned None completions.'):
71
- completions = log_timing(c.command(), lambda: deep_sort_dict(deep_merge_dicts(completions, c.completion(state))))
80
+ completions = log_timing(c.command(), lambda: deep_sort_dict(merge_completions(completions, c.completion(state))))
72
81
 
73
82
  # print(json.dumps(completions, indent=4))
74
83
  completer = ReplCompleter.from_nested_dict(completions)
75
84
 
76
- cmd = session.prompt(prompt_msg(), completer=completer, key_bindings=kb)
85
+ cmd = session.prompt(HTML(f'<ansibrightblue>{prompt_msg()}</ansibrightblue>'), completer=completer, key_bindings=kb)
77
86
  s0 = time.time()
78
87
 
79
88
  if state.bash_session:
@@ -88,17 +97,17 @@ def enter_repl(state: ReplState):
88
97
  return state, cmd
89
98
 
90
99
  if state.device == ReplState.A and state.app_app or state.device == ReplState.P:
91
- state.push()
100
+ state.push(pod_targetted=True)
92
101
 
93
102
  state.app_pod = arry[0].strip('@')
94
103
  cmd = ' '.join(arry[1:])
95
104
  elif state.device == ReplState.P:
96
- state.push()
105
+ state.push(pod_targetted=True)
97
106
 
98
107
  state.app_pod = arry[0].strip('@')
99
108
  cmd = ' '.join(arry[1:])
100
109
  elif state.sts:
101
- state.push()
110
+ state.push(pod_targetted=True)
102
111
 
103
112
  state.pod = arry[0].strip('@')
104
113
  cmd = ' '.join(arry[1:])
@@ -137,8 +146,10 @@ def enter_repl(state: ReplState):
137
146
  if cmd and (state.device != ReplState.L or Config().get('audit.log-audit-queries', False)):
138
147
  exec.submit(Audits.log, cmd, state.namespace, state.device, time.time() - s0, get_audit_extra(result))
139
148
 
149
+ CommandLog.close_log_file()
150
+
140
151
  def try_device_default_action(state: ReplState, cmds: Command, cmd_list: list[Command], cmd: str):
141
- action_taken, result = Devices.device(state).try_fallback_action(cmds, state, cmd)
152
+ action_taken, result = Devices.of(state).try_fallback_action(cmds, state, cmd)
142
153
 
143
154
  if not action_taken:
144
155
  log2(f'* Invalid command: {cmd}')
@@ -175,6 +186,9 @@ def repl(kubeconfig: str, config: str, param: list[str], cluster:str, namespace:
175
186
  if not KubeContext.init_params(config, param):
176
187
  return
177
188
 
178
- state = ReplState(device=Config().get('repl.start-drive', 'a'), ns_sts=cluster, namespace=namespace, in_repl=True)
189
+ state = ReplState(ns_sts=cluster, namespace=namespace, in_repl=True)
179
190
  state, _ = state.apply_device_arg(extra_args)
191
+ if not state.device:
192
+ state.device=Config().get('repl.start-drive', 'a')
193
+
180
194
  enter_repl(state)