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

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

Potentially problematic release.


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

Files changed (152) hide show
  1. adam/app_session.py +1 -1
  2. adam/batch.py +15 -15
  3. adam/commands/app/app.py +2 -2
  4. adam/commands/app/show_app_actions.py +1 -1
  5. adam/commands/{show → app}/show_login.py +1 -1
  6. adam/commands/app/utils_app.py +9 -1
  7. adam/commands/audit/audit.py +6 -20
  8. adam/commands/audit/audit_repair_tables.py +1 -1
  9. adam/commands/audit/audit_run.py +1 -1
  10. adam/commands/audit/completions_l.py +15 -0
  11. adam/commands/audit/show_last10.py +0 -1
  12. adam/commands/bash/bash.py +1 -1
  13. adam/commands/bash/utils_bash.py +1 -1
  14. adam/commands/cassandra/download_cassandra_log.py +45 -0
  15. adam/commands/cassandra/restart_cluster.py +47 -0
  16. adam/commands/cassandra/restart_node.py +51 -0
  17. adam/commands/cassandra/restart_nodes.py +47 -0
  18. adam/commands/{rollout.py → cassandra/rollout.py} +1 -1
  19. adam/commands/{show → cassandra}/show_cassandra_repairs.py +5 -3
  20. adam/commands/{show → cassandra}/show_cassandra_status.py +22 -15
  21. adam/commands/cassandra/show_processes.py +50 -0
  22. adam/commands/{show → cassandra}/show_storage.py +10 -8
  23. adam/commands/cli/__init__.py +0 -0
  24. adam/commands/{cli_commands.py → cli/cli_commands.py} +6 -1
  25. adam/commands/{clipboard_copy.py → cli/clipboard_copy.py} +2 -2
  26. adam/commands/{show/show_commands.py → cli/show_cli_commands.py} +2 -2
  27. adam/commands/command.py +22 -9
  28. adam/commands/commands_utils.py +14 -6
  29. adam/commands/config/__init__.py +0 -0
  30. adam/commands/{show → config}/show_params.py +1 -1
  31. adam/commands/{alter_tables.py → cql/alter_tables.py} +1 -1
  32. adam/commands/cql/completions_c.py +29 -0
  33. adam/commands/cql/cqlsh.py +2 -6
  34. adam/commands/cql/utils_cql.py +26 -17
  35. adam/commands/debug/__init__.py +0 -0
  36. adam/commands/debug/debug.py +22 -0
  37. adam/commands/debug/debug_completes.py +35 -0
  38. adam/commands/debug/debug_timings.py +35 -0
  39. adam/commands/debug/show_offloaded_completes.py +45 -0
  40. adam/commands/devices/device.py +30 -4
  41. adam/commands/devices/device_app.py +1 -1
  42. adam/commands/devices/device_export.py +5 -2
  43. adam/commands/devices/device_postgres.py +13 -3
  44. adam/commands/devices/devices.py +1 -1
  45. adam/commands/diag/__init__.py +0 -0
  46. adam/commands/{check.py → diag/check.py} +1 -1
  47. adam/commands/diag/generate_report.py +52 -0
  48. adam/commands/export/completions_x.py +11 -0
  49. adam/commands/export/download_export_session.py +2 -1
  50. adam/commands/export/export.py +0 -16
  51. adam/commands/export/export_databases.py +16 -10
  52. adam/commands/export/export_select.py +8 -33
  53. adam/commands/export/export_sessions.py +12 -11
  54. adam/commands/export/export_use.py +3 -3
  55. adam/commands/export/export_x_select.py +48 -0
  56. adam/commands/export/exporter.py +140 -53
  57. adam/commands/export/import_files.py +2 -2
  58. adam/commands/export/import_session.py +0 -4
  59. adam/commands/export/importer.py +11 -11
  60. adam/commands/export/importer_athena.py +15 -35
  61. adam/commands/export/importer_sqlite.py +19 -8
  62. adam/commands/export/show_column_counts.py +10 -10
  63. adam/commands/export/show_export_databases.py +2 -1
  64. adam/commands/export/show_export_session.py +1 -1
  65. adam/commands/export/show_export_sessions.py +1 -1
  66. adam/commands/export/utils_export.py +38 -15
  67. adam/commands/fs/__init__.py +0 -0
  68. adam/commands/{cat.py → fs/cat.py} +2 -2
  69. adam/commands/fs/cat_local.py +42 -0
  70. adam/commands/{cd.py → fs/cd.py} +2 -2
  71. adam/commands/{download_file.py → fs/download_file.py} +5 -5
  72. adam/commands/{find_files.py → fs/find_files.py} +4 -4
  73. adam/commands/{find_processes.py → fs/find_processes.py} +3 -3
  74. adam/commands/{head.py → fs/head.py} +2 -2
  75. adam/commands/{ls.py → fs/ls.py} +2 -2
  76. adam/commands/fs/ls_local.py +40 -0
  77. adam/commands/fs/rm.py +18 -0
  78. adam/commands/fs/rm_downloads.py +39 -0
  79. adam/commands/fs/rm_logs.py +38 -0
  80. adam/commands/{show → fs}/show_adam.py +1 -1
  81. adam/commands/intermediate_command.py +3 -0
  82. adam/commands/medusa/medusa_restore.py +2 -16
  83. adam/commands/medusa/utils_medusa.py +15 -0
  84. adam/commands/nodetool/__init__.py +0 -0
  85. adam/commands/{nodetool.py → nodetool/nodetool.py} +3 -8
  86. adam/commands/postgres/completions_p.py +22 -0
  87. adam/commands/postgres/postgres.py +7 -14
  88. adam/commands/postgres/postgres_databases.py +3 -3
  89. adam/commands/postgres/postgres_ls.py +1 -1
  90. adam/commands/postgres/utils_postgres.py +12 -2
  91. adam/commands/preview_table.py +1 -1
  92. adam/commands/reaper/reaper_schedule_activate.py +6 -2
  93. adam/commands/reaper/reaper_schedule_start.py +1 -2
  94. adam/commands/reaper/reaper_schedule_stop.py +1 -2
  95. adam/commands/reaper/utils_reaper.py +10 -1
  96. adam/commands/repair/repair_scan.py +0 -2
  97. adam/commands/repair/repair_stop.py +0 -1
  98. adam/commands/{show/show.py → show.py} +12 -11
  99. adam/config.py +4 -5
  100. adam/embedded_params.py +1 -1
  101. adam/repl.py +22 -9
  102. adam/repl_commands.py +50 -42
  103. adam/repl_session.py +9 -1
  104. adam/repl_state.py +16 -1
  105. adam/sql/async_executor.py +62 -0
  106. adam/sql/lark_completer.py +286 -0
  107. adam/sql/lark_parser.py +604 -0
  108. adam/sql/qingl.lark +1076 -0
  109. adam/sso/cred_cache.py +2 -5
  110. adam/utils.py +216 -79
  111. adam/utils_k8s/app_clusters.py +11 -4
  112. adam/utils_k8s/app_pods.py +10 -5
  113. adam/utils_k8s/cassandra_clusters.py +8 -4
  114. adam/utils_k8s/cassandra_nodes.py +14 -5
  115. adam/utils_k8s/k8s.py +9 -0
  116. adam/utils_k8s/kube_context.py +1 -4
  117. adam/{pod_exec_result.py → utils_k8s/pod_exec_result.py} +8 -2
  118. adam/utils_k8s/pods.py +83 -24
  119. adam/utils_k8s/statefulsets.py +5 -2
  120. adam/utils_local.py +78 -2
  121. adam/utils_repl/appendable_completer.py +6 -0
  122. adam/utils_repl/repl_completer.py +51 -4
  123. adam/utils_sqlite.py +3 -8
  124. adam/version.py +1 -1
  125. {kaqing-2.0.184.dist-info → kaqing-2.0.214.dist-info}/METADATA +1 -1
  126. kaqing-2.0.214.dist-info/RECORD +272 -0
  127. kaqing-2.0.214.dist-info/top_level.txt +2 -0
  128. teddy/__init__.py +0 -0
  129. teddy/lark_parser.py +436 -0
  130. teddy/lark_parser2.py +618 -0
  131. adam/commands/cql/cql_completions.py +0 -32
  132. adam/commands/export/export_select_x.py +0 -54
  133. adam/commands/logs.py +0 -37
  134. adam/commands/postgres/psql_completions.py +0 -11
  135. adam/commands/report.py +0 -61
  136. adam/commands/restart.py +0 -60
  137. adam/commands/show/show_processes.py +0 -49
  138. kaqing-2.0.184.dist-info/RECORD +0 -244
  139. kaqing-2.0.184.dist-info/top_level.txt +0 -1
  140. /adam/commands/{login.py → app/login.py} +0 -0
  141. /adam/commands/{show → cassandra}/__init__.py +0 -0
  142. /adam/commands/{show → cassandra}/show_cassandra_version.py +0 -0
  143. /adam/commands/{watch.py → cassandra/watch.py} +0 -0
  144. /adam/commands/{param_get.py → config/param_get.py} +0 -0
  145. /adam/commands/{param_set.py → config/param_set.py} +0 -0
  146. /adam/commands/{issues.py → diag/issues.py} +0 -0
  147. /adam/commands/{pwd.py → fs/pwd.py} +0 -0
  148. /adam/commands/{shell.py → fs/shell.py} +0 -0
  149. /adam/commands/{show → fs}/show_host.py +0 -0
  150. /adam/commands/{nodetool_commands.py → nodetool/nodetool_commands.py} +0 -0
  151. {kaqing-2.0.184.dist-info → kaqing-2.0.214.dist-info}/WHEEL +0 -0
  152. {kaqing-2.0.184.dist-info → kaqing-2.0.214.dist-info}/entry_points.txt +0 -0
@@ -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,7 +27,7 @@ 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
 
@@ -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
44
  def help(self, _: ReplState):
41
45
  return f'{ReaperScheduleActivate.COMMAND} <schedule-id>\t resume reaper schedule'
@@ -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
39
  def help(self, _: ReplState):
41
40
  return f'{ReaperScheduleStart.COMMAND} <schedule-id>\t start reaper runs for schedule'
@@ -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
39
  def help(self, _: ReplState):
41
40
  return f'{ReaperScheduleStop.COMMAND} <schedule-id>\t pause reaper schedule'
@@ -191,4 +191,13 @@ 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')
@@ -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
@@ -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'
@@ -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'}, 'get-host-id': {'workers': 32}, 'idps': {'ad': {'email-pattern': '.*@c3.ai', 'uri': 'https://login.microsoftonline.com/53ad779a-93e7-485c-ba20-ac8290d7252b/oauth2/v2.0/authorize?response_type=id_token&response_mode=form_post&client_id=00ff94a8-6b0a-4715-98e0-95490012d818&scope=openid+email+profile&redirect_uri=https%3A%2F%2Fplat.c3ci.cloud%2Fc3%2Fc3%2Foidc%2Flogin&nonce={nonce}&state=EMPTY', 'jwks-uri': 'https://login.microsoftonline.com/common/discovery/keys', 'contact': 'Please contact ted.tran@c3.ai.', 'whitelist-file': '/kaqing/members'}, 'okta': {'default': True, 'email-pattern': '.*@c3iot.com', 'uri': 'https://c3energy.okta.com/oauth2/v1/authorize?response_type=id_token&response_mode=form_post&client_id={client_id}&scope=openid+email+profile+groups&redirect_uri=https%3A%2F%2F{host}%2Fc3%2Fc3%2Foidc%2Flogin&nonce={nonce}&state=EMPTY', 'jwks-uri': 'https://c3energy.okta.com/oauth2/v1/keys'}}, 'issues': {'workers': 32}, 'local-qing-dir': '/tmp/qing-db/q', 'local-downloads-dir': '/tmp/qing-db/q/downloads', 'logs': {'path': '/c3/cassandra/logs/system.log'}, 'log-dir': '/tmp/qing-db/q/logs', 'nodetool': {'workers': 96, 'commands_in_line': 40, 'status': {'workers': 32, 'samples': 3, 'commands_in_line': 40}}, 'pg': {'name-pattern': '^{namespace}.*-k8spg-.*', 'excludes': '.helm., -admin-secret', 'agent': {'name': 'ops-pg-agent', 'just-in-time': False, 'timeout': 86400, 'image': 'seanahnsf/kaqing'}, 'default-db': 'postgres', 'default-schema': 'postgres', 'secret': {'endpoint-key': 'postgres-db-endpoint', 'port-key': 'postgres-db-port', 'username-key': 'postgres-admin-username', 'password-key': 'postgres-admin-password'}}, 'pod': {'name': 'ops', 'image': 'seanahnsf/kaqing-cloud', 'sa': {'name': 'ops', 'proto': 'c3', 'additional-cluster-roles': 'c3aiops-k8ssandra-operator'}, 'label-selector': 'run=ops'}, 'preview': {'rows': 10}, 'processes': {'columns': 'pod,cpu-metrics,mem', 'header': 'POD_NAME,M_CPU(USAGE/LIMIT),MEM/LIMIT'}, 'processes-qing': {'columns': 'pod,cpu,mem', 'header': 'POD_NAME,Q_CPU/TOTAL,MEM/LIMIT'}, 'reaper': {'service-name': 'reaper-service', 'port-forward': {'timeout': 86400, 'local-port': 9001}, 'abort-runs-batch': 10, 'show-runs-batch': 100, 'pod': {'cluster-regex': '(.*?-.*?-.*?-.*?)-.*', 'label-selector': 'k8ssandra.io/reaper={cluster}-reaper'}, 'secret': {'cluster-regex': '(.*?-.*?)-.*', 'name': '{cluster}-reaper-ui', 'password-item': 'password'}}, 'repair': {'log-path': '/home/cassrepair/logs/', 'image': 'ci-registry.c3iot.io/cloudops/cassrepair:2.0.14', 'secret': 'ciregistryc3iotio', 'env': {'interval': 24, 'timeout': 60, 'pr': False, 'runs': 1}}, 'repl': {'start-drive': 'c', 'a': {'auto-enter': 'c3/c3'}, 'c': {'auto-enter': 'cluster'}, 'x': {'auto-enter': 'latest'}, 'history': {'push-cat-log-file': True, 'push-cat-remote-log-file': True}, 'background-process': {'auto-nohup': True}}, 'status': {'columns': 'status,address,load,tokens,owns,host_id,gossip,compactions', 'header': '--,Address,Load,Tokens,Owns,Host ID,GOSSIP,COMPACTIONS'}, 'storage': {'columns': 'pod,volume_root,volume_cassandra,snapshots,data,compactions', 'header': 'POD_NAME,VOLUME /,VOLUME CASS,SNAPSHOTS,DATA,COMPACTIONS'}, 'watch': {'auto': 'rollout', 'timeout': 3600, 'interval': 10}, 'auto-complete': {'c': {'tables': 'lazy', 'table-props-value': 'jit'}, 'x': {'tables': 'lazy'}, 'cli': {'cp': 'jit'}, 'export': {'databases': 'jit'}, 'medusa': {'backups': 'jit'}, 'reaper': {'schedules': 'jit'}}, 'debug': False, 'debugs': {'complete': False, 'timings': False, 'exit-on-error': False}}
adam/repl.py CHANGED
@@ -10,17 +10,23 @@ from adam.commands.command_helpers import ClusterCommandHelper
10
10
  from adam.commands.devices.devices import Devices
11
11
  from adam.commands.help import Help
12
12
  from adam.config import Config
13
+ from adam.sql.async_executor import AsyncExecutor
13
14
  from adam.utils_audits import Audits
14
15
  from adam.utils_k8s.kube_context import KubeContext
15
16
  from adam.log import Log
16
17
  from adam.repl_commands import ReplCommands
17
18
  from adam.repl_session import ReplSession
18
19
  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
20
+ from adam.utils import CommandLog, clear_wait_log_flag, debug_trace, deep_sort_dict, tabulize, log2, log_exc, log_timing
20
21
  from adam.apps import Apps
21
- from adam.utils_repl.repl_completer import ReplCompleter
22
+ from adam.utils_repl.repl_completer import ReplCompleter, merge_completions
22
23
  from . import __version__
23
24
 
25
+ import nest_asyncio
26
+ nest_asyncio.apply()
27
+
28
+ import asyncio
29
+
24
30
  def enter_repl(state: ReplState):
25
31
  if os.getenv('QING_DROPPED', 'false') == 'true':
26
32
  log2('You have dropped to bash from another qing instance. Please enter "exit" to go back to qing.')
@@ -38,7 +44,7 @@ def enter_repl(state: ReplState):
38
44
 
39
45
  Log.log2(f'kaqing {__version__}')
40
46
 
41
- Devices.device(state).enter(state)
47
+ Devices.of(state).enter(state)
42
48
 
43
49
  kb = KeyBindings()
44
50
 
@@ -55,6 +61,8 @@ def enter_repl(state: ReplState):
55
61
  # use sorted command list only for auto-completion
56
62
  sorted_cmds = sorted(cmd_list, key=lambda cmd: cmd.command())
57
63
  while True:
64
+ AsyncExecutor.reset()
65
+
58
66
  cmd: str = None
59
67
  result = None
60
68
  try:
@@ -68,7 +76,7 @@ def enter_repl(state: ReplState):
68
76
 
69
77
  for c in sorted_cmds:
70
78
  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))))
79
+ completions = log_timing(c.command(), lambda: deep_sort_dict(merge_completions(completions, c.completion(state))))
72
80
 
73
81
  # print(json.dumps(completions, indent=4))
74
82
  completer = ReplCompleter.from_nested_dict(completions)
@@ -88,17 +96,17 @@ def enter_repl(state: ReplState):
88
96
  return state, cmd
89
97
 
90
98
  if state.device == ReplState.A and state.app_app or state.device == ReplState.P:
91
- state.push()
99
+ state.push(pod_targetted=True)
92
100
 
93
101
  state.app_pod = arry[0].strip('@')
94
102
  cmd = ' '.join(arry[1:])
95
103
  elif state.device == ReplState.P:
96
- state.push()
104
+ state.push(pod_targetted=True)
97
105
 
98
106
  state.app_pod = arry[0].strip('@')
99
107
  cmd = ' '.join(arry[1:])
100
108
  elif state.sts:
101
- state.push()
109
+ state.push(pod_targetted=True)
102
110
 
103
111
  state.pod = arry[0].strip('@')
104
112
  cmd = ' '.join(arry[1:])
@@ -137,8 +145,10 @@ def enter_repl(state: ReplState):
137
145
  if cmd and (state.device != ReplState.L or Config().get('audit.log-audit-queries', False)):
138
146
  exec.submit(Audits.log, cmd, state.namespace, state.device, time.time() - s0, get_audit_extra(result))
139
147
 
148
+ CommandLog.close_log_file()
149
+
140
150
  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)
151
+ action_taken, result = Devices.of(state).try_fallback_action(cmds, state, cmd)
142
152
 
143
153
  if not action_taken:
144
154
  log2(f'* Invalid command: {cmd}')
@@ -175,6 +185,9 @@ def repl(kubeconfig: str, config: str, param: list[str], cluster:str, namespace:
175
185
  if not KubeContext.init_params(config, param):
176
186
  return
177
187
 
178
- state = ReplState(device=Config().get('repl.start-drive', 'a'), ns_sts=cluster, namespace=namespace, in_repl=True)
188
+ state = ReplState(ns_sts=cluster, namespace=namespace, in_repl=True)
179
189
  state, _ = state.apply_device_arg(extra_args)
190
+ if not state.device:
191
+ state.device=Config().get('repl.start-drive', 'a')
192
+
180
193
  enter_repl(state)
adam/repl_commands.py CHANGED
@@ -1,13 +1,33 @@
1
- from adam.commands.alter_tables import AlterTables
2
1
  from adam.commands.app.app import App
3
2
  from adam.commands.app.app_ping import AppPing
4
3
  from adam.commands.app.show_app_actions import ShowAppActions
5
4
  from adam.commands.app.show_app_id import ShowAppId
6
5
  from adam.commands.app.show_app_queues import ShowAppQueues
7
6
  from adam.commands.audit.audit import Audit
8
- from adam.commands.cat import Cat
7
+ from adam.commands.cassandra.restart_cluster import RestartCluster
8
+ from adam.commands.cassandra.restart_node import RestartNode
9
+ from adam.commands.cassandra.restart_nodes import RestartNodes
10
+ from adam.commands.cassandra.rollout import RollOut
11
+ from adam.commands.cassandra.show_cassandra_repairs import ShowCassandraRepairs
12
+ from adam.commands.cassandra.show_cassandra_status import ShowCassandraStatus
13
+ from adam.commands.cassandra.show_cassandra_version import ShowCassandraVersion
14
+ from adam.commands.cassandra.show_processes import ShowProcesses
15
+ from adam.commands.cassandra.show_storage import ShowStorage
16
+ from adam.commands.cassandra.watch import Watch
17
+ from adam.commands.cli.clipboard_copy import ClipboardCopy
18
+ from adam.commands.config.param_get import GetParam
19
+ from adam.commands.config.param_set import SetParam
20
+ from adam.commands.debug.show_offloaded_completes import ShowOffloadedCompletes
21
+ from adam.commands.diag.check import Check
22
+ from adam.commands.diag.generate_report import GenerateReport
23
+ from adam.commands.diag.issues import Issues
24
+ from adam.commands.fs.cat import Cat
9
25
  from adam.commands.code import Code
10
- from adam.commands.download_file import DownloadFile
26
+ from adam.commands.cql.alter_tables import AlterTables
27
+ from adam.commands.debug.debug import Debug
28
+ from adam.commands.cassandra.download_cassandra_log import DownloadCassandraLog
29
+ from adam.commands.fs.cat_local import CatLocal
30
+ from adam.commands.fs.download_file import DownloadFile
11
31
  from adam.commands.deploy.code_start import CodeStart
12
32
  from adam.commands.deploy.code_stop import CodeStop
13
33
  from adam.commands.deploy.deploy import Deploy
@@ -31,58 +51,46 @@ from adam.commands.export.import_session import ImportSession
31
51
  from adam.commands.export.clean_up_export_sessions import CleanUpExportSessions
32
52
  from adam.commands.export.clean_up_all_export_sessions import CleanUpAllExportSessions
33
53
  from adam.commands.export.drop_export_databases import DropExportDatabases
34
- from adam.commands.export.export_select import ExportSelect
54
+ from adam.commands.export.export_x_select import ExportXSelect
35
55
  from adam.commands.export.export_use import ExportUse
36
- from adam.commands.export.export_select_x import ExportSelectX
56
+ from adam.commands.export.export_select import ExportSelect
37
57
  from adam.commands.export.show_column_counts import ShowColumnCounts
38
58
  from adam.commands.export.show_export_databases import ShowExportDatabases
39
59
  from adam.commands.export.show_export_session import ShowExportSession
40
60
  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
61
+ from adam.commands.fs.find_files import FindLocalFiles
62
+ from adam.commands.fs.find_processes import FindProcesses
63
+ from adam.commands.fs.head import Head
64
+ from adam.commands.fs.ls_local import LsLocal
65
+ from adam.commands.fs.rm import RmLocal
44
66
  from adam.commands.kubectl import Kubectl
45
- from adam.commands.shell import Shell
46
- from adam.commands.clipboard_copy import ClipboardCopy
67
+ from adam.commands.fs.shell import Shell
47
68
  from adam.commands.bash.bash import Bash
48
- from adam.commands.cd import Cd
49
- from adam.commands.check import Check
69
+ from adam.commands.fs.cd import Cd
50
70
  from adam.commands.command import Command
51
71
  from adam.commands.cql.cqlsh import Cqlsh
52
72
  from adam.commands.exit import Exit
53
73
  from adam.commands.medusa.medusa import Medusa
54
- from adam.commands.param_get import GetParam
55
- from adam.commands.issues import Issues
56
- from adam.commands.ls import Ls
57
- from adam.commands.nodetool import NodeTool
74
+ from adam.commands.fs.ls import Ls
75
+ from adam.commands.nodetool.nodetool import NodeTool
58
76
  from adam.commands.postgres.postgres import Postgres, PostgresPg
59
77
  from adam.commands.preview_table import PreviewTable
60
- from adam.commands.pwd import Pwd
78
+ from adam.commands.fs.pwd import Pwd
61
79
  from adam.commands.reaper.reaper import Reaper
62
80
  from adam.commands.repair.repair import Repair
63
- from adam.commands.report import Report
64
- from adam.commands.restart import Restart
65
- from adam.commands.rollout import RollOut
66
- from adam.commands.param_set import SetParam
67
- from adam.commands.show.show import Show
68
- from adam.commands.show.show_cassandra_status import ShowCassandraStatus
69
- from adam.commands.show.show_cassandra_version import ShowCassandraVersion
70
- from adam.commands.show.show_commands import ShowKubectlCommands
71
- from adam.commands.show.show_host import ShowHost
72
- from adam.commands.show.show_login import ShowLogin
73
- from adam.commands.show.show_params import ShowParams
74
- from adam.commands.show.show_processes import ShowProcesses
75
- from adam.commands.show.show_cassandra_repairs import ShowCassandraRepairs
76
- from adam.commands.show.show_storage import ShowStorage
77
- from adam.commands.show.show_adam import ShowAdam
78
- from adam.commands.watch import Watch
81
+ from adam.commands.cli.show_cli_commands import ShowKubectlCommands
82
+ from adam.commands.fs.show_host import ShowHost
83
+ from adam.commands.app.show_login import ShowLogin
84
+ from adam.commands.config.show_params import ShowParams
85
+ from adam.commands.fs.show_adam import ShowAdam
86
+ from adam.commands.show import Show
79
87
 
80
88
  class ReplCommands:
81
89
  def repl_cmd_list() -> list[Command]:
82
90
  cmds: list[Command] = ReplCommands.navigation() + ReplCommands.cassandra_ops() + ReplCommands.postgres_ops() + \
83
91
  ReplCommands.app_ops() + ReplCommands.audit_ops() + ReplCommands.export_ops() + ReplCommands.tools() + ReplCommands.exit()
84
92
 
85
- intermediate_cmds: list[Command] = [App(), Audit(), Reaper(), Repair(), Deploy(), Show(), Undeploy()]
93
+ intermediate_cmds: list[Command] = [App(), Audit(), Reaper(), Repair(), Debug(), Deploy(), Show(), Undeploy()]
86
94
  ic = [c.command() for c in intermediate_cmds]
87
95
  # 1. dedup commands
88
96
  deduped = []
@@ -99,18 +107,18 @@ class ReplCommands:
99
107
  return deduped
100
108
 
101
109
  def navigation() -> list[Command]:
102
- return [Ls(), PreviewTable(), DeviceApp(), DevicePostgres(), DeviceCass(), DeviceAuditLog(), DeviceExport(),
103
- Cd(), Cat(), Head(), DownloadFile(), FindLocalFiles(), FindProcesses(), Pwd(), ClipboardCopy(),
104
- GetParam(), SetParam(), ShowParams(), ShowKubectlCommands(), ShowLogin(), ShowAdam(), ShowHost()]
110
+ return [Ls(), LsLocal(), PreviewTable(), DeviceApp(), DevicePostgres(), DeviceCass(), DeviceAuditLog(), DeviceExport(),
111
+ Cd(), Cat(), CatLocal(), Head(), DownloadFile(), FindLocalFiles(), FindProcesses(), Pwd(), ClipboardCopy(),
112
+ GetParam(), SetParam(), ShowOffloadedCompletes(), ShowParams(), ShowKubectlCommands(), ShowLogin(), ShowAdam(), ShowHost()] + RmLocal().cmd_list()
105
113
 
106
114
  def cassandra_ops() -> list[Command]:
107
- return [Cqlsh(), ShowCassandraStatus(), ShowCassandraVersion(), ShowCassandraRepairs(), ShowStorage(), ShowProcesses(),
108
- Check(), Issues(), NodeTool(), Report(), AlterTables(), Bash(),
109
- ExportTables(), ExportSelect(), ExportUse(), ShowExportDatabases(), ShowColumnCounts(),
115
+ return [Cqlsh(), DownloadCassandraLog(), ShowCassandraStatus(), ShowCassandraVersion(), ShowCassandraRepairs(), ShowStorage(), ShowProcesses(),
116
+ Check(), Issues(), NodeTool(), GenerateReport(), AlterTables(), Bash(),
117
+ ExportTables(), ExportXSelect(), ExportUse(), ShowExportDatabases(), ShowColumnCounts(),
110
118
  DropExportDatabase(), DropExportDatabases(),
111
119
  ShowExportSessions(), ShowExportSession(), DownloadExportSession(),
112
120
  CleanUpExportSessions(), CleanUpAllExportSessions(), ImportSession(), ImportCSVFiles()] + \
113
- Medusa().cmd_list() + [Restart(), RollOut(), Watch()] + Reaper().cmd_list() + Repair().cmd_list()
121
+ Medusa().cmd_list() + [RestartNodes(), RestartNode(), RestartCluster(), RollOut(), Watch()] + Reaper().cmd_list() + Repair().cmd_list() + Debug().cmd_list()
114
122
 
115
123
  def postgres_ops() -> list[Command]:
116
124
  return [Postgres(), DeployPgAgent(), UndeployPgAgent(), PostgresPg()]
@@ -122,7 +130,7 @@ class ReplCommands:
122
130
  return [Audit()] + Audit().cmd_list()
123
131
 
124
132
  def export_ops() -> list[Command]:
125
- return [ExportSelectX(), DropExportDatabase(), DropExportDatabases(), ShowColumnCounts()]
133
+ return [ExportSelect(), DropExportDatabase(), DropExportDatabases(), ShowColumnCounts()]
126
134
 
127
135
  def tools() -> list[Command]:
128
136
  return [Shell(), CodeStart(), CodeStop(), DeployFrontend(), UndeployFrontend(), DeployPod(), UndeployPod(), Kubectl(), Code()]
adam/repl_session.py CHANGED
@@ -1,6 +1,9 @@
1
1
  from prompt_toolkit import PromptSession
2
2
  from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
3
3
 
4
+ from adam.config import Config
5
+ from adam.utils import ConfigHolder
6
+
4
7
  class ReplSession:
5
8
  # the singleton pattern
6
9
  def __new__(cls, *args, **kwargs):
@@ -10,4 +13,9 @@ class ReplSession:
10
13
 
11
14
  def __init__(self):
12
15
  if not hasattr(self, 'prompt_session'):
13
- self.prompt_session = PromptSession(auto_suggest=AutoSuggestFromHistory())
16
+ self.prompt_session = PromptSession(auto_suggest=AutoSuggestFromHistory())
17
+ ConfigHolder().append_command_history = self.append_history
18
+
19
+ def append_history(self, entry: str):
20
+ if entry and self.prompt_session and Config().get('repl.history.push-cat-remote-log-file', True):
21
+ self.prompt_session.history.append_string(entry)
adam/repl_state.py CHANGED
@@ -61,6 +61,7 @@ class ReplState:
61
61
  self.bash_session = bash_session
62
62
  self.remote_dir = remote_dir
63
63
  self.original_state: ReplState = None
64
+ self.pod_targetted = False
64
65
 
65
66
  self.export_session: str = None
66
67
 
@@ -392,9 +393,10 @@ class ReplState:
392
393
  self.pop()
393
394
  self.bash_session = None
394
395
 
395
- def push(self):
396
+ def push(self, pod_targetted=False):
396
397
  if not self.original_state:
397
398
  self.original_state = copy(self)
399
+ self.pod_targetted = pod_targetted
398
400
 
399
401
  def pop(self):
400
402
  if o := self.original_state:
@@ -409,6 +411,7 @@ class ReplState:
409
411
  self.namespace = o.namespace
410
412
 
411
413
  self.original_state = None
414
+ self.pod_targetted = False
412
415
 
413
416
  def pg_host_n_database(self):
414
417
  host = None
@@ -422,6 +425,18 @@ class ReplState:
422
425
 
423
426
  return host, database
424
427
 
428
+ def with_no_pod(self):
429
+ state1 = copy(self)
430
+ state1.pod = None
431
+
432
+ return state1
433
+
434
+ def with_pod(self, pod: str):
435
+ state1 = copy(self)
436
+ state1.pod = pod
437
+
438
+ return state1
439
+
425
440
  class DevicePodService:
426
441
  def __init__(self, handler: 'DeviceExecHandler'):
427
442
  self.handler = handler
@@ -0,0 +1,62 @@
1
+ import asyncio
2
+ from concurrent.futures import ThreadPoolExecutor
3
+ from copy import copy
4
+ import inspect
5
+ import threading
6
+ import time
7
+ import traceback
8
+
9
+ from adam.utils import log2, log_timing
10
+
11
+ class AsyncExecutor:
12
+ # some lib does not handle asyncio loop properly, as sync exec submit does not work, use another async loop
13
+
14
+ lock = threading.Lock()
15
+ in_queue = set()
16
+ processed: dict[str, float] = {}
17
+ first_processed_at: float = None
18
+ last_processed_at: float = None
19
+
20
+ loop: asyncio.AbstractEventLoop = None
21
+ async_exec: ThreadPoolExecutor = None
22
+
23
+ def preload(action: callable, log_key: str = None):
24
+ with AsyncExecutor.lock:
25
+ if not AsyncExecutor.loop:
26
+ AsyncExecutor.loop = asyncio.new_event_loop()
27
+ AsyncExecutor.async_exec = ThreadPoolExecutor(max_workers=6, thread_name_prefix='async')
28
+ AsyncExecutor.loop.set_default_executor(AsyncExecutor.async_exec)
29
+
30
+ async def a():
31
+ try:
32
+ t0 = time.time()
33
+
34
+ arg_needed = len(action.__code__.co_varnames)
35
+
36
+ if log_key:
37
+ with log_timing(log_key):
38
+ r = action(None) if arg_needed else action()
39
+ else:
40
+ r = action(None) if arg_needed else action()
41
+ if inspect.isawaitable(r):
42
+ await r
43
+
44
+ AsyncExecutor.in_queue.remove(log_key)
45
+ if log_key not in AsyncExecutor.processed:
46
+ AsyncExecutor.processed[log_key] = time.time() - t0
47
+ AsyncExecutor.last_processed_at = time.time()
48
+ except Exception as e:
49
+ log2('preloading error', e, inspect.getsourcelines(action)[0][0])
50
+ traceback.print_exc()
51
+
52
+ if log_key not in AsyncExecutor.in_queue:
53
+ AsyncExecutor.in_queue.add(log_key)
54
+ AsyncExecutor.async_exec.submit(lambda: AsyncExecutor.loop.run_until_complete(a()))
55
+
56
+ def entries_in_queue():
57
+ # no locking
58
+ return copy(AsyncExecutor.in_queue), copy(AsyncExecutor.processed), AsyncExecutor.first_processed_at, AsyncExecutor.last_processed_at
59
+
60
+ def reset():
61
+ AsyncExecutor.first_processed_at = time.time()
62
+ AsyncExecutor.processed.clear()