kaqing 2.0.171__py3-none-any.whl → 2.0.203__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.
Files changed (194) hide show
  1. adam/app_session.py +5 -10
  2. adam/apps.py +18 -4
  3. adam/batch.py +7 -7
  4. adam/checks/check_utils.py +3 -1
  5. adam/checks/disk.py +2 -3
  6. adam/columns/memory.py +3 -4
  7. adam/commands/__init__.py +15 -6
  8. adam/commands/alter_tables.py +26 -41
  9. adam/commands/app/__init__.py +0 -0
  10. adam/commands/{app_cmd.py → app/app.py} +2 -2
  11. adam/commands/{show → app}/show_app_actions.py +7 -15
  12. adam/commands/{show → app}/show_app_queues.py +1 -4
  13. adam/{utils_app.py → commands/app/utils_app.py} +9 -1
  14. adam/commands/audit/audit.py +9 -26
  15. adam/commands/audit/audit_repair_tables.py +5 -7
  16. adam/commands/audit/audit_run.py +1 -1
  17. adam/commands/audit/completions_l.py +15 -0
  18. adam/commands/audit/show_last10.py +2 -14
  19. adam/commands/audit/show_slow10.py +2 -13
  20. adam/commands/audit/show_top10.py +2 -11
  21. adam/commands/audit/utils_show_top10.py +15 -3
  22. adam/commands/bash/bash.py +1 -1
  23. adam/commands/bash/utils_bash.py +1 -1
  24. adam/commands/cassandra/__init__.py +0 -0
  25. adam/commands/cassandra/download_cassandra_log.py +45 -0
  26. adam/commands/cassandra/nodetool.py +64 -0
  27. adam/commands/cassandra/nodetool_commands.py +120 -0
  28. adam/commands/cassandra/restart_cluster.py +47 -0
  29. adam/commands/cassandra/restart_node.py +51 -0
  30. adam/commands/cassandra/restart_nodes.py +47 -0
  31. adam/commands/cassandra/rollout.py +88 -0
  32. adam/commands/cat.py +5 -19
  33. adam/commands/cd.py +7 -9
  34. adam/commands/check.py +10 -18
  35. adam/commands/cli_commands.py +6 -1
  36. adam/commands/{cp.py → clipboard_copy.py} +34 -36
  37. adam/commands/code.py +2 -2
  38. adam/commands/command.py +139 -22
  39. adam/commands/commands_utils.py +14 -12
  40. adam/commands/cql/alter_tables.py +66 -0
  41. adam/commands/cql/completions_c.py +29 -0
  42. adam/commands/cql/cqlsh.py +3 -7
  43. adam/commands/cql/utils_cql.py +23 -61
  44. adam/commands/debug/__init__.py +0 -0
  45. adam/commands/debug/debug.py +22 -0
  46. adam/commands/debug/debug_completes.py +35 -0
  47. adam/commands/debug/debug_timings.py +35 -0
  48. adam/commands/deploy/deploy_pg_agent.py +2 -2
  49. adam/commands/deploy/deploy_pod.py +2 -4
  50. adam/commands/deploy/undeploy_pg_agent.py +2 -2
  51. adam/commands/devices/device.py +40 -9
  52. adam/commands/devices/device_app.py +19 -29
  53. adam/commands/devices/device_auit_log.py +3 -3
  54. adam/commands/devices/device_cass.py +17 -23
  55. adam/commands/devices/device_export.py +12 -11
  56. adam/commands/devices/device_postgres.py +79 -63
  57. adam/commands/devices/devices.py +1 -1
  58. adam/commands/download_cassandra_log.py +45 -0
  59. adam/commands/download_file.py +47 -0
  60. adam/commands/export/clean_up_all_export_sessions.py +3 -3
  61. adam/commands/export/clean_up_export_sessions.py +7 -19
  62. adam/commands/export/completions_x.py +11 -0
  63. adam/commands/export/download_export_session.py +40 -0
  64. adam/commands/export/drop_export_database.py +6 -22
  65. adam/commands/export/drop_export_databases.py +3 -9
  66. adam/commands/export/export.py +1 -17
  67. adam/commands/export/export_databases.py +109 -32
  68. adam/commands/export/export_select.py +8 -55
  69. adam/commands/export/export_sessions.py +211 -0
  70. adam/commands/export/export_use.py +13 -16
  71. adam/commands/export/export_x_select.py +48 -0
  72. adam/commands/export/exporter.py +176 -167
  73. adam/commands/export/import_files.py +44 -0
  74. adam/commands/export/import_session.py +10 -6
  75. adam/commands/export/importer.py +24 -9
  76. adam/commands/export/importer_athena.py +114 -44
  77. adam/commands/export/importer_sqlite.py +45 -23
  78. adam/commands/export/show_column_counts.py +11 -20
  79. adam/commands/export/show_export_databases.py +5 -2
  80. adam/commands/export/show_export_session.py +6 -15
  81. adam/commands/export/show_export_sessions.py +4 -11
  82. adam/commands/export/utils_export.py +79 -27
  83. adam/commands/find_files.py +51 -0
  84. adam/commands/find_processes.py +76 -0
  85. adam/commands/generate_report.py +52 -0
  86. adam/commands/head.py +36 -0
  87. adam/commands/help.py +2 -2
  88. adam/commands/intermediate_command.py +6 -3
  89. adam/commands/login.py +3 -6
  90. adam/commands/ls.py +2 -2
  91. adam/commands/medusa/medusa_backup.py +13 -16
  92. adam/commands/medusa/medusa_restore.py +26 -37
  93. adam/commands/medusa/medusa_show_backupjobs.py +7 -7
  94. adam/commands/medusa/medusa_show_restorejobs.py +6 -6
  95. adam/commands/medusa/utils_medusa.py +15 -0
  96. adam/commands/nodetool.py +3 -8
  97. adam/commands/os/__init__.py +0 -0
  98. adam/commands/os/cat.py +36 -0
  99. adam/commands/os/download_file.py +47 -0
  100. adam/commands/os/find_files.py +51 -0
  101. adam/commands/os/find_processes.py +76 -0
  102. adam/commands/os/head.py +36 -0
  103. adam/commands/os/shell.py +41 -0
  104. adam/commands/param_get.py +10 -12
  105. adam/commands/param_set.py +7 -10
  106. adam/commands/postgres/completions_p.py +22 -0
  107. adam/commands/postgres/postgres.py +25 -40
  108. adam/commands/postgres/postgres_databases.py +269 -0
  109. adam/commands/postgres/utils_postgres.py +33 -20
  110. adam/commands/preview_table.py +4 -2
  111. adam/commands/pwd.py +4 -6
  112. adam/commands/reaper/reaper_forward.py +2 -2
  113. adam/commands/reaper/reaper_run_abort.py +4 -10
  114. adam/commands/reaper/reaper_runs.py +3 -3
  115. adam/commands/reaper/reaper_schedule_activate.py +12 -12
  116. adam/commands/reaper/reaper_schedule_start.py +7 -12
  117. adam/commands/reaper/reaper_schedule_stop.py +7 -12
  118. adam/commands/reaper/utils_reaper.py +13 -6
  119. adam/commands/repair/repair_log.py +1 -4
  120. adam/commands/repair/repair_run.py +3 -8
  121. adam/commands/repair/repair_scan.py +1 -6
  122. adam/commands/repair/repair_stop.py +1 -5
  123. adam/commands/restart_cluster.py +47 -0
  124. adam/commands/restart_node.py +51 -0
  125. adam/commands/restart_nodes.py +47 -0
  126. adam/commands/shell.py +9 -2
  127. adam/commands/show/show.py +4 -4
  128. adam/commands/show/show_adam.py +3 -3
  129. adam/commands/show/show_cassandra_repairs.py +5 -6
  130. adam/commands/show/show_cassandra_status.py +29 -29
  131. adam/commands/show/show_cassandra_version.py +1 -4
  132. adam/commands/show/{show_commands.py → show_cli_commands.py} +3 -6
  133. adam/commands/show/show_login.py +3 -9
  134. adam/commands/show/show_params.py +2 -5
  135. adam/commands/show/show_processes.py +15 -16
  136. adam/commands/show/show_storage.py +9 -8
  137. adam/config.py +4 -5
  138. adam/embedded_params.py +1 -1
  139. adam/log.py +4 -4
  140. adam/repl.py +26 -18
  141. adam/repl_commands.py +32 -20
  142. adam/repl_session.py +9 -1
  143. adam/repl_state.py +39 -10
  144. adam/sql/async_executor.py +44 -0
  145. adam/sql/lark_completer.py +286 -0
  146. adam/sql/lark_parser.py +604 -0
  147. adam/sql/qingl.lark +1076 -0
  148. adam/sql/sql_completer.py +4 -6
  149. adam/sql/sql_state_machine.py +25 -13
  150. adam/sso/authn_ad.py +2 -5
  151. adam/sso/authn_okta.py +2 -4
  152. adam/sso/cred_cache.py +2 -5
  153. adam/sso/idp.py +8 -11
  154. adam/utils.py +299 -105
  155. adam/utils_athena.py +18 -18
  156. adam/utils_audits.py +3 -7
  157. adam/utils_issues.py +2 -2
  158. adam/utils_k8s/app_clusters.py +4 -4
  159. adam/utils_k8s/app_pods.py +8 -6
  160. adam/utils_k8s/cassandra_clusters.py +16 -5
  161. adam/utils_k8s/cassandra_nodes.py +9 -6
  162. adam/utils_k8s/custom_resources.py +11 -17
  163. adam/utils_k8s/jobs.py +7 -11
  164. adam/utils_k8s/k8s.py +14 -5
  165. adam/utils_k8s/kube_context.py +3 -6
  166. adam/{pod_exec_result.py → utils_k8s/pod_exec_result.py} +4 -4
  167. adam/utils_k8s/pods.py +85 -23
  168. adam/utils_k8s/statefulsets.py +5 -2
  169. adam/utils_local.py +42 -0
  170. adam/utils_repl/appendable_completer.py +6 -0
  171. adam/utils_repl/repl_completer.py +45 -2
  172. adam/utils_repl/state_machine.py +3 -3
  173. adam/utils_sqlite.py +58 -30
  174. adam/version.py +1 -1
  175. {kaqing-2.0.171.dist-info → kaqing-2.0.203.dist-info}/METADATA +1 -1
  176. kaqing-2.0.203.dist-info/RECORD +277 -0
  177. kaqing-2.0.203.dist-info/top_level.txt +2 -0
  178. teddy/__init__.py +0 -0
  179. teddy/lark_parser.py +436 -0
  180. teddy/lark_parser2.py +618 -0
  181. adam/commands/cql/cql_completions.py +0 -33
  182. adam/commands/export/export_handlers.py +0 -71
  183. adam/commands/export/export_select_x.py +0 -54
  184. adam/commands/logs.py +0 -37
  185. adam/commands/postgres/postgres_context.py +0 -274
  186. adam/commands/postgres/psql_completions.py +0 -10
  187. adam/commands/report.py +0 -61
  188. adam/commands/restart.py +0 -60
  189. kaqing-2.0.171.dist-info/RECORD +0 -236
  190. kaqing-2.0.171.dist-info/top_level.txt +0 -1
  191. /adam/commands/{app_ping.py → app/app_ping.py} +0 -0
  192. /adam/commands/{show → app}/show_app_id.py +0 -0
  193. {kaqing-2.0.171.dist-info → kaqing-2.0.203.dist-info}/WHEEL +0 -0
  194. {kaqing-2.0.171.dist-info → kaqing-2.0.203.dist-info}/entry_points.txt +0 -0
@@ -1,17 +1,17 @@
1
1
  import click
2
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
3
6
  from adam.commands.intermediate_command import IntermediateCommand
4
7
  from adam.commands.medusa.medusa_show_backupjobs import MedusaShowBackupJobs
5
8
  from adam.commands.medusa.medusa_show_restorejobs import MedusaShowRestoreJobs
6
- from adam.commands.show.show_app_actions import ShowAppActions
7
- from adam.commands.show.show_app_queues import ShowAppQueues
8
9
  from adam.commands.show.show_host import ShowHost
9
10
  from adam.commands.show.show_login import ShowLogin
10
11
  from .show_params import ShowParams
11
- from .show_app_id import ShowAppId
12
12
  from .show_cassandra_status import ShowCassandraStatus
13
13
  from .show_cassandra_version import ShowCassandraVersion
14
- from .show_commands import ShowKubectlCommands
14
+ from .show_cli_commands import ShowKubectlCommands
15
15
  from .show_processes import ShowProcesses
16
16
  from .show_cassandra_repairs import ShowCassandraRepairs
17
17
  from .show_storage import ShowStorage
@@ -1,7 +1,7 @@
1
1
  import sys
2
2
  import os
3
3
 
4
- from adam.utils import lines_to_tabular, log2
4
+ from adam.utils import tabulize, log2
5
5
 
6
6
  current_dir = os.path.dirname(os.path.abspath(__file__))
7
7
 
@@ -34,10 +34,10 @@ class ShowAdam(Command):
34
34
 
35
35
  package = os.path.dirname(os.path.abspath(__file__))
36
36
  package = package.split('/adam/')[0] + '/adam'
37
- log2(lines_to_tabular([
37
+ tabulize([
38
38
  f'version\t{__version__}',
39
39
  f'source\t{package}'
40
- ], separator='\t'))
40
+ ], separator='\t', to=2)
41
41
 
42
42
  return state
43
43
 
@@ -1,3 +1,4 @@
1
+ from adam.commands import extract_trailing_options
1
2
  from adam.commands.command import Command
2
3
  from adam.commands.cql.utils_cql import cassandra
3
4
  from adam.repl_state import ReplState, RequiredState
@@ -25,14 +26,12 @@ class ShowCassandraRepairs(Command):
25
26
  return super().run(cmd, state)
26
27
 
27
28
  with self.validate(args, state) as (args, state):
28
- with cassandra(state) as pods:
29
- return pods.nodetool('repair_admin list')
29
+ with extract_trailing_options(args, '&') as (args, backgrounded):
30
+ with cassandra(state) as pods:
31
+ return pods.nodetool('repair_admin list', backgrounded=backgrounded)
30
32
 
31
33
  def completion(self, state: ReplState):
32
- if state.sts:
33
- return super().completion(state)
34
-
35
- return {}
34
+ return super().completion(state, {'&': None})
36
35
 
37
36
  def help(self, _: ReplState):
38
37
  return f'{ShowCassandraRepairs.COMMAND}\t show Cassandra repairs'
@@ -1,3 +1,4 @@
1
+ from datetime import datetime
1
2
  import sys
2
3
 
3
4
  from adam.checks.check_result import CheckResult
@@ -5,14 +6,15 @@ from adam.checks.check_utils import run_checks
5
6
  from adam.checks.compactionstats import CompactionStats
6
7
  from adam.checks.gossip import Gossip
7
8
  from adam.columns.columns import Columns
8
- from adam.commands import extract_options
9
+ from adam.commands import extract_options, extract_trailing_options
9
10
  from adam.commands.command import Command
10
11
  from adam.commands.cql.utils_cql import cassandra
11
12
  from adam.config import Config
13
+ from adam.repl_session import ReplSession
12
14
  from adam.utils_issues import IssuesUtils
13
15
  from adam.utils_k8s.statefulsets import StatefulSets
14
16
  from adam.repl_state import ReplState, RequiredState
15
- from adam.utils import lines_to_tabular, log, log2
17
+ from adam.utils import SORT, tabulize, log2, log_exc
16
18
  from adam.checks.status import parse_nodetool_status
17
19
 
18
20
  class ShowCassandraStatus(Command):
@@ -38,32 +40,31 @@ class ShowCassandraStatus(Command):
38
40
  return super().run(cmd, state)
39
41
 
40
42
  with self.validate(args, state) as (args, state):
41
- with extract_options(args, ['-s', '--show']) as (args, show_out):
42
- if state.namespace and state.pod:
43
- self.show_single_pod(state, show_out=show_out)
44
- elif state.namespace and state.sts:
45
- self.merge(state, Config().get('nodetool.samples', sys.maxsize), show_output=show_out)
43
+ with extract_trailing_options(args, '&') as (args, backgrounded):
44
+ with extract_options(args, ['-s', '--show']) as (args, show_out):
45
+ if state.namespace and state.pod:
46
+ self.show_single_pod(state, show_out=show_out, backgrounded=backgrounded)
47
+ elif state.namespace and state.sts:
48
+ self.merge(state, Config().get('nodetool.samples', sys.maxsize), show_output=show_out, backgrounded=backgrounded)
46
49
 
47
- return state
50
+ return state
48
51
 
49
- def show_single_pod(self, state: ReplState, show_out = False):
50
- try:
52
+ def show_single_pod(self, state: ReplState, show_out = False, backgrounded = False):
53
+ with log_exc(True):
51
54
  with cassandra(state) as pods:
52
55
  result = pods.nodetool('status', show_out=False)
53
56
  status = parse_nodetool_status(result.stdout)
54
57
  check_results = run_checks(cluster=state.sts, namespace=state.namespace, checks=[CompactionStats(), Gossip()], show_out=show_out)
55
- self.show_table(status, check_results)
56
- except Exception as e:
57
- log2(e)
58
+ self.show_table(status, check_results, backgrounded=backgrounded)
58
59
 
59
- def merge(self, state: ReplState, samples: int, show_output=False):
60
+ def merge(self, state: ReplState, samples: int, show_output=False, backgrounded = False):
60
61
  statuses: list[list[dict]] = []
61
62
 
62
63
  pod_names = StatefulSets.pod_names(state.sts, state.namespace)
63
64
  for pod_name in pod_names:
64
65
  pod_name = pod_name.split('(')[0]
65
66
 
66
- try:
67
+ with log_exc(True):
67
68
  with cassandra(state, pod=pod_name) as pods:
68
69
  result = pods.nodetool('status', show_out=False)
69
70
  status = parse_nodetool_status(result.stdout)
@@ -71,13 +72,11 @@ class ShowCassandraStatus(Command):
71
72
  statuses.append(status)
72
73
  if samples <= len(statuses) and len(pod_names) != len(statuses):
73
74
  break
74
- except Exception as e:
75
- log2(e)
76
75
 
77
76
  combined_status = self.merge_status(statuses)
78
77
  log2(f'Showing merged status from {len(statuses)}/{len(pod_names)} nodes...')
79
78
  check_results = run_checks(cluster=state.sts, namespace=state.namespace, checks=[CompactionStats(), Gossip()], show_out=show_output)
80
- self.show_table(combined_status, check_results)
79
+ self.show_table(combined_status, check_results, backgrounded=backgrounded)
81
80
 
82
81
  return combined_status
83
82
 
@@ -98,27 +97,28 @@ class ShowCassandraStatus(Command):
98
97
 
99
98
  return combined
100
99
 
101
- def show_table(self, status: list[dict[str, any]], check_results: list[CheckResult]):
100
+ def show_table(self, status: list[dict[str, any]], check_results: list[CheckResult], backgrounded=False):
102
101
  cols = Config().get('status.columns', 'status,address,load,tokens,owns,host_id,gossip,compactions')
103
102
  header = Config().get('status.header', '--,Address,Load,Tokens,Owns,Host ID,GOSSIP,COMPACTIONS')
104
103
  columns = Columns.create_columns(cols)
105
104
 
106
- def line(status: dict):
107
- cells = [c.host_value(check_results, status) for c in columns]
108
- return ','.join(cells)
105
+ r = tabulize(status, lambda s: ','.join([c.host_value(check_results, s) for c in columns]), header=header, separator=',', sorted=SORT, to = 0 if backgrounded else 1)
109
106
 
110
- lines = [line(d) for d in status]
111
- lines.sort()
107
+ if backgrounded:
108
+ log_prefix = Config().get('log-prefix', '/tmp/qing')
109
+ log_file = f'{log_prefix}-{datetime.now().strftime("%d%H%M%S")}.log'
112
110
 
113
- log(lines_to_tabular(lines, header, separator=','))
111
+ with open(log_file, 'w') as f:
112
+ f.write(r)
113
+
114
+ ReplSession().append_history(f':sh cat {log_file}')
115
+
116
+ r = log_file
114
117
 
115
118
  IssuesUtils.show(check_results)
116
119
 
117
120
  def completion(self, state: ReplState):
118
- if state.sts:
119
- return super().completion(state, {'-s': None})
120
-
121
- return {}
121
+ return super().completion(state, {'-s': {'&': None}, '&': None})
122
122
 
123
123
  def help(self, _: ReplState):
124
124
  return f'{ShowCassandraStatus.COMMAND} [-s]\t show merged nodetool status -s show commands on nodes'
@@ -29,10 +29,7 @@ class ShowCassandraVersion(Command):
29
29
  return pods.cql('show version', show_out=True, on_any=True)
30
30
 
31
31
  def completion(self, state: ReplState):
32
- if state.sts:
33
- return super().completion(state)
34
-
35
- return {}
32
+ return super().completion(state)
36
33
 
37
34
  def help(self, _: ReplState):
38
35
  return f'{ShowCassandraVersion.COMMAND}\t show Cassandra version'
@@ -1,7 +1,7 @@
1
1
  from adam.commands.command import Command
2
2
  from adam.commands.cli_commands import CliCommands
3
3
  from adam.repl_state import ReplState, RequiredState
4
- from adam.utils import lines_to_tabular, log
4
+ from adam.utils import tabulize, log
5
5
 
6
6
  class ShowKubectlCommands(Command):
7
7
  COMMAND = 'show cli-commands'
@@ -22,7 +22,7 @@ class ShowKubectlCommands(Command):
22
22
  return RequiredState.CLUSTER_OR_POD
23
23
 
24
24
  def run(self, cmd: str, state: ReplState):
25
- if not self.args(cmd):
25
+ if not (args := self.args(cmd)):
26
26
  return super().run(cmd, state)
27
27
 
28
28
  with self.validate(args, state) as (args, state):
@@ -45,14 +45,11 @@ class ShowKubectlCommands(Command):
45
45
 
46
46
  cmds += [f'{k},{v0}' for k, v0 in v.items() if k.startswith('pg-')]
47
47
 
48
- log(lines_to_tabular(cmds, separator=','))
48
+ tabulize(cmds, separator=',')
49
49
 
50
50
  return cmds
51
51
 
52
52
  def completion(self, state: ReplState):
53
- if not state.sts:
54
- return {}
55
-
56
53
  return super().completion(state)
57
54
 
58
55
  def help(self, _: ReplState):
@@ -1,13 +1,11 @@
1
1
  import time
2
- import traceback
3
2
 
4
3
  from adam.apps import Apps
5
- from adam.config import Config
6
4
  from adam.sso.idp import Idp
7
5
  from adam.sso.idp_login import IdpLogin
8
6
  from adam.commands.command import Command
9
7
  from adam.repl_state import ReplState
10
- from adam.utils import duration, lines_to_tabular, log, log2
8
+ from adam.utils import duration, tabulize, log, log2, log_exc
11
9
 
12
10
  class ShowLogin(Command):
13
11
  COMMAND = 'show login'
@@ -33,7 +31,7 @@ class ShowLogin(Command):
33
31
 
34
32
  with self.validate(args, state) as (args, state):
35
33
  login: IdpLogin = None
36
- try:
34
+ with log_exc(True):
37
35
  if not(host := Apps.app_host('c3', 'c3', state.namespace)):
38
36
  log2('Cannot locate ingress for app.')
39
37
  return state
@@ -47,11 +45,7 @@ class ShowLogin(Command):
47
45
  f'IDP expires in\t{duration(time.time(), it.exp)}',
48
46
  f'IDP Groups\t{",".join(it.groups)}'
49
47
  ]
50
- log(lines_to_tabular(lines, separator='\t'))
51
- except Exception as e:
52
- log2(e)
53
- if Config().is_debug():
54
- log2(traceback.format_exc())
48
+ tabulize(lines, separator='\t')
55
49
 
56
50
  return state
57
51
 
@@ -1,7 +1,7 @@
1
1
  from adam.commands.command import Command
2
2
  from adam.config import Config
3
3
  from adam.repl_state import ReplState
4
- from adam.utils import lines_to_tabular, log
4
+ from adam.utils import tabulize
5
5
 
6
6
  class ShowParams(Command):
7
7
  COMMAND = 'show params'
@@ -22,10 +22,7 @@ class ShowParams(Command):
22
22
  if not self.args(cmd):
23
23
  return super().run(cmd, state)
24
24
 
25
- lines = [f'{key}\t{Config().get(key, None)}' for key in Config().keys()]
26
- log(lines_to_tabular(lines, separator='\t'))
27
-
28
- return lines
25
+ return tabulize(Config().keys(), lambda k: f'{k}\t{Config().get(k, None)}', separator='\t')
29
26
 
30
27
  def completion(self, state: ReplState):
31
28
  return super().completion(state)
@@ -1,9 +1,7 @@
1
- from adam.commands import extract_options
1
+ from adam.commands import extract_options, extract_sequence, extract_trailing_options
2
2
  from adam.commands.command import Command
3
- from adam.commands.commands_utils import show_table
4
3
  from adam.commands.cql.utils_cql import cassandra
5
4
  from adam.config import Config
6
- from adam.utils_k8s.statefulsets import StatefulSets
7
5
  from adam.repl_state import ReplState, RequiredState
8
6
 
9
7
  class ShowProcesses(Command):
@@ -29,23 +27,24 @@ class ShowProcesses(Command):
29
27
  return super().run(cmd, state)
30
28
 
31
29
  with self.validate(args, state) as (args, state):
32
- with extract_options(args, ['-s', '--show']) as (args, show_out):
33
- cols = Config().get('processes.columns', 'pod,cpu-metrics,mem')
34
- header = Config().get('processes.header', 'POD_NAME,M_CPU(USAGE/LIMIT),MEM/LIMIT')
30
+ with extract_trailing_options(args, '&') as (args, backgrounded):
31
+ with extract_options(args, ['-s', '--show']) as (args, show_out):
32
+ with extract_sequence(args, ['with', 'recipe', '=', 'qing']) as (_, recipe_qing):
33
+ cols = Config().get('processes.columns', 'pod,cpu-metrics,mem')
34
+ header = Config().get('processes.header', 'POD_NAME,M_CPU(USAGE/LIMIT),MEM/LIMIT')
35
+ if recipe_qing:
36
+ cols = Config().get('processes-qing.columns', 'pod,cpu,mem')
37
+ header = Config().get('processes-qing.header', 'POD_NAME,Q_CPU/TOTAL,MEM/LIMIT')
35
38
 
36
- qing_args = ['qing', 'recipe', 'with']
37
- args, _, recipe_qing = Command.extract_options(args, options=qing_args)
38
- if set(recipe_qing) == set(qing_args):
39
- cols = Config().get('processes-qing.columns', 'pod,cpu,mem')
40
- header = Config().get('processes-qing.header', 'POD_NAME,Q_CPU/TOTAL,MEM/LIMIT')
39
+ with cassandra(state) as pods:
40
+ pods.display_table(cols, header, show_out=show_out, backgrounded=backgrounded)
41
41
 
42
- with cassandra(state) as pods:
43
- pods.show_table(cols, header, show_out=show_out)
44
-
45
- return state
42
+ return state
46
43
 
47
44
  def completion(self, state: ReplState):
48
- return super().completion(state, {'with': {'recipe': {'metrics': {'-s': None}, 'qing': {'-s': None}}}, '-s': None})
45
+ recipes = ['metrics', 'qing']
46
+ return super().completion(state, {'with': {'recipe': {'=': {r: {'-s': {'&': None}, '&': None} for r in recipes}}}, '-s': {'&': None}, '&': None})
47
+ # return super().completion(state, {'with': {'recipe': {'=': {'metrics': {'-s': {'&': None}, '&': None}, 'qing': {'-s': {'&': None}}}}}, '-s': {'&': None}, '&': None})
49
48
 
50
49
  def help(self, _: ReplState):
51
50
  return f'{ShowProcesses.COMMAND} [with recipe qing|metrics] [-s]\t show process overview -s show commands on nodes'
@@ -1,4 +1,4 @@
1
- from adam.commands import extract_options
1
+ from adam.commands import extract_options, extract_trailing_options
2
2
  from adam.commands.command import Command
3
3
  from adam.commands.cql.utils_cql import cassandra
4
4
  from adam.config import Config
@@ -27,16 +27,17 @@ class ShowStorage(Command):
27
27
  return super().run(cmd, state)
28
28
 
29
29
  with self.validate(args, state) as (args, state):
30
- with extract_options(args, ['-s', '--show']) as (args, show_out):
31
- cols = Config().get('storage.columns', 'pod,volume_root,volume_cassandra,snapshots,data,compactions')
32
- header = Config().get('storage.header', 'POD_NAME,VOLUME /,VOLUME CASS,SNAPSHOTS,DATA,COMPACTIONS')
33
- with cassandra(state) as pods:
34
- pods.show_table(cols, header, show_out=show_out)
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)
35
36
 
36
- return state
37
+ return state
37
38
 
38
39
  def completion(self, state: ReplState):
39
- return super().completion(state, {'-s': None})
40
+ return super().completion(state, {'-s': {'&': None}, '&': None})
40
41
 
41
42
  def help(self, _: ReplState):
42
43
  return f'{ShowStorage.COMMAND} [-s]\t show storage overview -s show commands on nodes'
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'}}, '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', '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>'}}, '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-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-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, 'via-sh': True, 'via-sh-excludes': ''}}, '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': '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,12 +1,11 @@
1
1
  import os
2
2
  import time
3
- import traceback
4
3
  from typing import cast
5
4
  import click
6
5
  from prompt_toolkit.key_binding import KeyBindings
7
6
 
8
7
  from adam.cli_group import cli
9
- from adam.commands.command import Command, InvalidState
8
+ from adam.commands.command import Command, InvalidArgumentsException, InvalidStateException
10
9
  from adam.commands.command_helpers import ClusterCommandHelper
11
10
  from adam.commands.devices.devices import Devices
12
11
  from adam.commands.help import Help
@@ -17,11 +16,16 @@ from adam.log import Log
17
16
  from adam.repl_commands import ReplCommands
18
17
  from adam.repl_session import ReplSession
19
18
  from adam.repl_state import ReplState
20
- from adam.utils import clear_wait_log_flag, debug, deep_merge_dicts, deep_sort_dict, lines_to_tabular, log2, log_timing
19
+ from adam.utils import CommandLog, clear_wait_log_flag, debug_trace, deep_sort_dict, tabulize, log2, log_exc, log_timing
21
20
  from adam.apps import Apps
22
- from adam.utils_repl.repl_completer import ReplCompleter
21
+ from adam.utils_repl.repl_completer import ReplCompleter, merge_completions
23
22
  from . import __version__
24
23
 
24
+ import nest_asyncio
25
+ nest_asyncio.apply()
26
+
27
+ import asyncio
28
+
25
29
  def enter_repl(state: ReplState):
26
30
  if os.getenv('QING_DROPPED', 'false') == 'true':
27
31
  log2('You have dropped to bash from another qing instance. Please enter "exit" to go back to qing.')
@@ -39,7 +43,7 @@ def enter_repl(state: ReplState):
39
43
 
40
44
  Log.log2(f'kaqing {__version__}')
41
45
 
42
- Devices.device(state).enter(state)
46
+ Devices.of(state).enter(state)
43
47
 
44
48
  kb = KeyBindings()
45
49
 
@@ -68,10 +72,8 @@ def enter_repl(state: ReplState):
68
72
  completions = log_timing('actions', lambda: Apps(path='apps.yaml').commands())
69
73
 
70
74
  for c in sorted_cmds:
71
- try:
72
- completions = log_timing(c.command(), lambda: deep_sort_dict(deep_merge_dicts(completions, c.completion(state))))
73
- except:
74
- log2(f'* {c.command()} command returned None completions.')
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))))
75
77
 
76
78
  # print(json.dumps(completions, indent=4))
77
79
  completer = ReplCompleter.from_nested_dict(completions)
@@ -91,17 +93,17 @@ def enter_repl(state: ReplState):
91
93
  return state, cmd
92
94
 
93
95
  if state.device == ReplState.A and state.app_app or state.device == ReplState.P:
94
- state.push()
96
+ state.push(pod_targetted=True)
95
97
 
96
98
  state.app_pod = arry[0].strip('@')
97
99
  cmd = ' '.join(arry[1:])
98
100
  elif state.device == ReplState.P:
99
- state.push()
101
+ state.push(pod_targetted=True)
100
102
 
101
103
  state.app_pod = arry[0].strip('@')
102
104
  cmd = ' '.join(arry[1:])
103
105
  elif state.sts:
104
- state.push()
106
+ state.push(pod_targetted=True)
105
107
 
106
108
  state.pod = arry[0].strip('@')
107
109
  cmd = ' '.join(arry[1:])
@@ -112,7 +114,9 @@ def enter_repl(state: ReplState):
112
114
  try:
113
115
  if cmd and cmd.strip(' ') and not (result := cmds.run(cmd, target)):
114
116
  result = try_device_default_action(target, cmds, cmd_list, cmd)
115
- except InvalidState:
117
+ except InvalidStateException:
118
+ pass
119
+ except InvalidArgumentsException:
116
120
  pass
117
121
 
118
122
  if result and type(result) is ReplState and (s := cast(ReplState, result).export_session) != state.export_session:
@@ -125,7 +129,7 @@ def enter_repl(state: ReplState):
125
129
  raise e
126
130
  else:
127
131
  log2(e)
128
- debug(traceback.format_exc())
132
+ debug_trace()
129
133
  finally:
130
134
  if not state.bash_session:
131
135
  state.pop()
@@ -138,14 +142,15 @@ def enter_repl(state: ReplState):
138
142
  if cmd and (state.device != ReplState.L or Config().get('audit.log-audit-queries', False)):
139
143
  exec.submit(Audits.log, cmd, state.namespace, state.device, time.time() - s0, get_audit_extra(result))
140
144
 
145
+ CommandLog.close_log_file()
146
+
141
147
  def try_device_default_action(state: ReplState, cmds: Command, cmd_list: list[Command], cmd: str):
142
- action_taken, result = Devices.device(state).try_fallback_action(cmds, state, cmd)
148
+ action_taken, result = Devices.of(state).try_fallback_action(cmds, state, cmd)
143
149
 
144
150
  if not action_taken:
145
151
  log2(f'* Invalid command: {cmd}')
146
152
  log2()
147
- lines = [c.help(state) for c in cmd_list if c.help(state)]
148
- log2(lines_to_tabular(lines, separator='\t'))
153
+ tabulize([c.help(state) for c in cmd_list if c.help(state)], separator='\t', to=2)
149
154
 
150
155
  return result
151
156
 
@@ -177,6 +182,9 @@ def repl(kubeconfig: str, config: str, param: list[str], cluster:str, namespace:
177
182
  if not KubeContext.init_params(config, param):
178
183
  return
179
184
 
180
- state = ReplState(device=Config().get('repl.start-drive', 'a'), ns_sts=cluster, namespace=namespace, in_repl=True)
185
+ state = ReplState(ns_sts=cluster, namespace=namespace, in_repl=True)
181
186
  state, _ = state.apply_device_arg(extra_args)
187
+ if not state.device:
188
+ state.device=Config().get('repl.start-drive', 'a')
189
+
182
190
  enter_repl(state)