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.
- adam/app_session.py +1 -1
- adam/batch.py +15 -15
- adam/commands/app/app.py +2 -2
- adam/commands/app/show_app_actions.py +1 -1
- adam/commands/{show → app}/show_login.py +1 -1
- adam/commands/app/utils_app.py +9 -1
- adam/commands/audit/audit.py +6 -20
- adam/commands/audit/audit_repair_tables.py +1 -1
- adam/commands/audit/audit_run.py +1 -1
- adam/commands/audit/completions_l.py +15 -0
- adam/commands/audit/show_last10.py +0 -1
- adam/commands/bash/bash.py +1 -1
- adam/commands/bash/utils_bash.py +1 -1
- adam/commands/cassandra/download_cassandra_log.py +45 -0
- adam/commands/cassandra/restart_cluster.py +47 -0
- adam/commands/cassandra/restart_node.py +51 -0
- adam/commands/cassandra/restart_nodes.py +47 -0
- adam/commands/{rollout.py → cassandra/rollout.py} +1 -1
- adam/commands/{show → cassandra}/show_cassandra_repairs.py +5 -3
- adam/commands/{show → cassandra}/show_cassandra_status.py +22 -15
- adam/commands/cassandra/show_processes.py +50 -0
- adam/commands/{show → cassandra}/show_storage.py +10 -8
- adam/commands/cli/__init__.py +0 -0
- adam/commands/{cli_commands.py → cli/cli_commands.py} +6 -1
- adam/commands/{clipboard_copy.py → cli/clipboard_copy.py} +2 -2
- adam/commands/{show/show_commands.py → cli/show_cli_commands.py} +2 -2
- adam/commands/command.py +22 -9
- adam/commands/commands_utils.py +14 -6
- adam/commands/config/__init__.py +0 -0
- adam/commands/{show → config}/show_params.py +1 -1
- adam/commands/{alter_tables.py → cql/alter_tables.py} +1 -1
- adam/commands/cql/completions_c.py +29 -0
- adam/commands/cql/cqlsh.py +2 -6
- adam/commands/cql/utils_cql.py +26 -17
- adam/commands/debug/__init__.py +0 -0
- adam/commands/debug/debug.py +22 -0
- adam/commands/debug/debug_completes.py +35 -0
- adam/commands/debug/debug_timings.py +35 -0
- adam/commands/debug/show_offloaded_completes.py +45 -0
- adam/commands/devices/device.py +30 -4
- adam/commands/devices/device_app.py +1 -1
- adam/commands/devices/device_export.py +5 -2
- adam/commands/devices/device_postgres.py +13 -3
- adam/commands/devices/devices.py +1 -1
- adam/commands/diag/__init__.py +0 -0
- adam/commands/{check.py → diag/check.py} +1 -1
- adam/commands/diag/generate_report.py +52 -0
- adam/commands/export/completions_x.py +11 -0
- adam/commands/export/download_export_session.py +2 -1
- adam/commands/export/export.py +0 -16
- adam/commands/export/export_databases.py +16 -10
- adam/commands/export/export_select.py +8 -33
- adam/commands/export/export_sessions.py +12 -11
- adam/commands/export/export_use.py +3 -3
- adam/commands/export/export_x_select.py +48 -0
- adam/commands/export/exporter.py +140 -53
- adam/commands/export/import_files.py +2 -2
- adam/commands/export/import_session.py +0 -4
- adam/commands/export/importer.py +11 -11
- adam/commands/export/importer_athena.py +15 -35
- adam/commands/export/importer_sqlite.py +19 -8
- adam/commands/export/show_column_counts.py +10 -10
- adam/commands/export/show_export_databases.py +2 -1
- adam/commands/export/show_export_session.py +1 -1
- adam/commands/export/show_export_sessions.py +1 -1
- adam/commands/export/utils_export.py +38 -15
- adam/commands/fs/__init__.py +0 -0
- adam/commands/{cat.py → fs/cat.py} +2 -2
- adam/commands/fs/cat_local.py +42 -0
- adam/commands/{cd.py → fs/cd.py} +2 -2
- adam/commands/{download_file.py → fs/download_file.py} +5 -5
- adam/commands/{find_files.py → fs/find_files.py} +4 -4
- adam/commands/{find_processes.py → fs/find_processes.py} +3 -3
- adam/commands/{head.py → fs/head.py} +2 -2
- adam/commands/{ls.py → fs/ls.py} +2 -2
- adam/commands/fs/ls_local.py +40 -0
- adam/commands/fs/rm.py +18 -0
- adam/commands/fs/rm_downloads.py +39 -0
- adam/commands/fs/rm_logs.py +38 -0
- adam/commands/{show → fs}/show_adam.py +1 -1
- adam/commands/intermediate_command.py +3 -0
- adam/commands/medusa/medusa_restore.py +2 -16
- adam/commands/medusa/utils_medusa.py +15 -0
- adam/commands/nodetool/__init__.py +0 -0
- adam/commands/{nodetool.py → nodetool/nodetool.py} +3 -8
- adam/commands/postgres/completions_p.py +22 -0
- adam/commands/postgres/postgres.py +7 -14
- adam/commands/postgres/postgres_databases.py +3 -3
- adam/commands/postgres/postgres_ls.py +1 -1
- adam/commands/postgres/utils_postgres.py +12 -2
- adam/commands/preview_table.py +1 -1
- adam/commands/reaper/reaper_schedule_activate.py +6 -2
- adam/commands/reaper/reaper_schedule_start.py +1 -2
- adam/commands/reaper/reaper_schedule_stop.py +1 -2
- adam/commands/reaper/utils_reaper.py +10 -1
- adam/commands/repair/repair_scan.py +0 -2
- adam/commands/repair/repair_stop.py +0 -1
- adam/commands/{show/show.py → show.py} +12 -11
- adam/config.py +4 -5
- adam/embedded_params.py +1 -1
- adam/repl.py +22 -9
- adam/repl_commands.py +50 -42
- adam/repl_session.py +9 -1
- adam/repl_state.py +16 -1
- adam/sql/async_executor.py +62 -0
- adam/sql/lark_completer.py +286 -0
- adam/sql/lark_parser.py +604 -0
- adam/sql/qingl.lark +1076 -0
- adam/sso/cred_cache.py +2 -5
- adam/utils.py +216 -79
- adam/utils_k8s/app_clusters.py +11 -4
- adam/utils_k8s/app_pods.py +10 -5
- adam/utils_k8s/cassandra_clusters.py +8 -4
- adam/utils_k8s/cassandra_nodes.py +14 -5
- adam/utils_k8s/k8s.py +9 -0
- adam/utils_k8s/kube_context.py +1 -4
- adam/{pod_exec_result.py → utils_k8s/pod_exec_result.py} +8 -2
- adam/utils_k8s/pods.py +83 -24
- adam/utils_k8s/statefulsets.py +5 -2
- adam/utils_local.py +78 -2
- adam/utils_repl/appendable_completer.py +6 -0
- adam/utils_repl/repl_completer.py +51 -4
- adam/utils_sqlite.py +3 -8
- adam/version.py +1 -1
- {kaqing-2.0.184.dist-info → kaqing-2.0.214.dist-info}/METADATA +1 -1
- kaqing-2.0.214.dist-info/RECORD +272 -0
- kaqing-2.0.214.dist-info/top_level.txt +2 -0
- teddy/__init__.py +0 -0
- teddy/lark_parser.py +436 -0
- teddy/lark_parser2.py +618 -0
- adam/commands/cql/cql_completions.py +0 -32
- adam/commands/export/export_select_x.py +0 -54
- adam/commands/logs.py +0 -37
- adam/commands/postgres/psql_completions.py +0 -11
- adam/commands/report.py +0 -61
- adam/commands/restart.py +0 -60
- adam/commands/show/show_processes.py +0 -49
- kaqing-2.0.184.dist-info/RECORD +0 -244
- kaqing-2.0.184.dist-info/top_level.txt +0 -1
- /adam/commands/{login.py → app/login.py} +0 -0
- /adam/commands/{show → cassandra}/__init__.py +0 -0
- /adam/commands/{show → cassandra}/show_cassandra_version.py +0 -0
- /adam/commands/{watch.py → cassandra/watch.py} +0 -0
- /adam/commands/{param_get.py → config/param_get.py} +0 -0
- /adam/commands/{param_set.py → config/param_set.py} +0 -0
- /adam/commands/{issues.py → diag/issues.py} +0 -0
- /adam/commands/{pwd.py → fs/pwd.py} +0 -0
- /adam/commands/{shell.py → fs/shell.py} +0 -0
- /adam/commands/{show → fs}/show_host.py +0 -0
- /adam/commands/{nodetool_commands.py → nodetool/nodetool_commands.py} +0 -0
- {kaqing-2.0.184.dist-info → kaqing-2.0.214.dist-info}/WHEEL +0 -0
- {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):
|
adam/commands/preview_table.py
CHANGED
|
@@ -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
|
-
|
|
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')
|
|
@@ -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.
|
|
10
|
-
from adam.commands.
|
|
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
|
|
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-
|
|
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,
|
|
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.
|
|
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(
|
|
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.
|
|
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(
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
55
|
-
from adam.commands.
|
|
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.
|
|
64
|
-
from adam.commands.
|
|
65
|
-
from adam.commands.
|
|
66
|
-
from adam.commands.
|
|
67
|
-
from adam.commands.
|
|
68
|
-
from adam.commands.show
|
|
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(),
|
|
109
|
-
ExportTables(),
|
|
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() + [
|
|
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 [
|
|
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()
|