kaqing 2.0.145__py3-none-any.whl → 2.0.189__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of kaqing might be problematic. Click here for more details.
- adam/__init__.py +0 -2
- adam/app_session.py +9 -12
- adam/apps.py +18 -4
- adam/batch.py +4 -4
- adam/checks/check_utils.py +16 -46
- adam/checks/cpu.py +7 -1
- adam/checks/cpu_metrics.py +52 -0
- adam/checks/disk.py +2 -3
- adam/columns/columns.py +3 -1
- adam/columns/cpu.py +3 -1
- adam/columns/cpu_metrics.py +22 -0
- adam/columns/memory.py +3 -4
- adam/commands/__init__.py +24 -0
- adam/commands/alter_tables.py +33 -48
- adam/commands/app/__init__.py +0 -0
- adam/commands/app/app.py +38 -0
- adam/commands/{app_ping.py → app/app_ping.py} +7 -13
- adam/commands/app/show_app_actions.py +49 -0
- adam/commands/{show → app}/show_app_id.py +8 -11
- adam/commands/{show → app}/show_app_queues.py +7 -14
- adam/commands/app/utils_app.py +106 -0
- adam/commands/audit/audit.py +21 -40
- adam/commands/audit/audit_repair_tables.py +14 -19
- adam/commands/audit/audit_run.py +14 -22
- adam/commands/audit/completions_l.py +15 -0
- adam/commands/audit/show_last10.py +4 -19
- adam/commands/audit/show_slow10.py +4 -18
- adam/commands/audit/show_top10.py +4 -16
- adam/commands/audit/utils_show_top10.py +15 -3
- adam/commands/bash/__init__.py +5 -0
- adam/commands/bash/bash.py +7 -104
- adam/commands/bash/utils_bash.py +16 -0
- adam/commands/cat.py +7 -27
- adam/commands/cd.py +7 -11
- adam/commands/check.py +15 -24
- adam/commands/cli_commands.py +8 -4
- adam/commands/clipboard_copy.py +87 -0
- adam/commands/code.py +21 -24
- adam/commands/command.py +207 -42
- adam/commands/commands_utils.py +25 -27
- adam/commands/cql/completions_c.py +28 -0
- adam/commands/cql/cqlsh.py +9 -33
- adam/commands/cql/{cql_utils.py → utils_cql.py} +111 -15
- adam/commands/deploy/code_start.py +7 -10
- adam/commands/deploy/code_stop.py +4 -21
- adam/commands/deploy/code_utils.py +3 -3
- adam/commands/deploy/deploy.py +4 -27
- adam/commands/deploy/deploy_frontend.py +14 -17
- adam/commands/deploy/deploy_pg_agent.py +3 -6
- adam/commands/deploy/deploy_pod.py +64 -68
- adam/commands/deploy/undeploy.py +4 -27
- adam/commands/deploy/undeploy_frontend.py +4 -7
- adam/commands/deploy/undeploy_pg_agent.py +5 -8
- adam/commands/deploy/undeploy_pod.py +9 -12
- adam/commands/devices/device.py +124 -2
- adam/commands/devices/device_app.py +41 -24
- adam/commands/devices/device_auit_log.py +10 -4
- adam/commands/devices/device_cass.py +48 -14
- adam/commands/devices/device_export.py +13 -12
- adam/commands/devices/device_postgres.py +105 -54
- adam/commands/download_file.py +47 -0
- adam/commands/exit.py +1 -4
- adam/commands/export/clean_up_all_export_sessions.py +37 -0
- adam/commands/export/clean_up_export_sessions.py +9 -10
- adam/commands/export/completions_x.py +11 -0
- adam/commands/export/download_export_session.py +40 -0
- adam/commands/export/drop_export_database.py +7 -26
- adam/commands/export/drop_export_databases.py +5 -14
- adam/commands/export/export.py +6 -52
- adam/commands/export/export_databases.py +108 -32
- adam/commands/export/export_select.py +8 -59
- adam/commands/export/export_sessions.py +209 -0
- adam/commands/export/export_use.py +14 -20
- adam/commands/export/export_x_select.py +48 -0
- adam/commands/export/exporter.py +135 -167
- adam/commands/export/import_files.py +44 -0
- adam/commands/export/import_session.py +11 -35
- adam/commands/export/importer.py +19 -5
- adam/commands/export/importer_athena.py +112 -44
- adam/commands/export/importer_sqlite.py +42 -22
- adam/commands/export/show_column_counts.py +13 -31
- adam/commands/export/show_export_databases.py +7 -7
- adam/commands/export/show_export_session.py +8 -20
- adam/commands/export/show_export_sessions.py +6 -16
- adam/commands/export/utils_export.py +64 -11
- adam/commands/find_files.py +51 -0
- adam/commands/find_processes.py +76 -0
- adam/commands/head.py +36 -0
- adam/commands/help.py +2 -2
- adam/commands/intermediate_command.py +52 -0
- adam/commands/issues.py +11 -43
- adam/commands/kubectl.py +3 -6
- adam/commands/login.py +22 -24
- adam/commands/logs.py +3 -6
- adam/commands/ls.py +9 -10
- adam/commands/medusa/medusa.py +4 -22
- adam/commands/medusa/medusa_backup.py +20 -27
- adam/commands/medusa/medusa_restore.py +49 -46
- adam/commands/medusa/medusa_show_backupjobs.py +16 -18
- adam/commands/medusa/medusa_show_restorejobs.py +13 -18
- adam/commands/medusa/utils_medusa.py +15 -0
- adam/commands/nodetool.py +7 -21
- adam/commands/param_get.py +11 -14
- adam/commands/param_set.py +8 -12
- adam/commands/postgres/completions_p.py +22 -0
- adam/commands/postgres/postgres.py +34 -57
- adam/commands/postgres/postgres_databases.py +270 -0
- adam/commands/postgres/postgres_ls.py +4 -8
- adam/commands/postgres/postgres_preview.py +5 -9
- adam/commands/postgres/utils_postgres.py +79 -0
- adam/commands/preview_table.py +8 -45
- adam/commands/pwd.py +13 -16
- adam/commands/reaper/reaper.py +4 -27
- adam/commands/reaper/reaper_forward.py +49 -56
- adam/commands/reaper/reaper_forward_session.py +6 -0
- adam/commands/reaper/reaper_forward_stop.py +10 -16
- adam/commands/reaper/reaper_restart.py +7 -14
- adam/commands/reaper/reaper_run_abort.py +8 -33
- adam/commands/reaper/reaper_runs.py +43 -58
- adam/commands/reaper/reaper_runs_abort.py +29 -49
- adam/commands/reaper/reaper_schedule_activate.py +14 -33
- adam/commands/reaper/reaper_schedule_start.py +9 -33
- adam/commands/reaper/reaper_schedule_stop.py +9 -33
- adam/commands/reaper/reaper_schedules.py +4 -14
- adam/commands/reaper/reaper_status.py +8 -16
- adam/commands/reaper/utils_reaper.py +203 -0
- adam/commands/repair/repair.py +4 -22
- adam/commands/repair/repair_log.py +5 -11
- adam/commands/repair/repair_run.py +27 -34
- adam/commands/repair/repair_scan.py +32 -40
- adam/commands/repair/repair_stop.py +5 -12
- adam/commands/report.py +27 -29
- adam/commands/restart.py +25 -26
- adam/commands/rollout.py +19 -24
- adam/commands/shell.py +12 -4
- adam/commands/show/show.py +11 -27
- adam/commands/show/show_adam.py +3 -3
- adam/commands/show/show_cassandra_repairs.py +37 -0
- adam/commands/show/show_cassandra_status.py +47 -51
- adam/commands/show/show_cassandra_version.py +5 -18
- adam/commands/show/show_cli_commands.py +56 -0
- adam/commands/show/show_host.py +1 -1
- adam/commands/show/show_login.py +20 -27
- adam/commands/show/show_params.py +2 -5
- adam/commands/show/show_processes.py +18 -21
- adam/commands/show/show_storage.py +11 -20
- adam/commands/watch.py +26 -29
- adam/config.py +5 -16
- adam/embedded_params.py +1 -1
- adam/log.py +4 -4
- adam/pod_exec_result.py +3 -3
- adam/repl.py +45 -39
- adam/repl_commands.py +26 -19
- adam/repl_session.py +8 -1
- adam/repl_state.py +85 -36
- adam/sql/lark_completer.py +284 -0
- adam/sql/lark_parser.py +604 -0
- adam/sql/sql_completer.py +4 -6
- adam/sql/sql_state_machine.py +29 -16
- adam/sso/authn_ad.py +6 -8
- adam/sso/authn_okta.py +4 -6
- adam/sso/cred_cache.py +3 -5
- adam/sso/idp.py +9 -12
- adam/utils.py +484 -37
- adam/utils_athena.py +19 -19
- adam/utils_audits.py +12 -12
- adam/utils_issues.py +32 -0
- adam/utils_k8s/app_clusters.py +14 -19
- adam/utils_k8s/app_pods.py +7 -2
- adam/utils_k8s/cassandra_clusters.py +30 -19
- adam/utils_k8s/cassandra_nodes.py +2 -2
- adam/utils_k8s/custom_resources.py +16 -17
- adam/utils_k8s/ingresses.py +2 -2
- adam/utils_k8s/jobs.py +7 -11
- adam/utils_k8s/k8s.py +96 -0
- adam/utils_k8s/kube_context.py +2 -2
- adam/utils_k8s/pods.py +37 -81
- adam/utils_k8s/secrets.py +4 -4
- adam/utils_k8s/service_accounts.py +5 -4
- adam/utils_k8s/services.py +2 -2
- adam/utils_k8s/statefulsets.py +6 -14
- adam/utils_local.py +4 -0
- adam/utils_repl/appendable_completer.py +6 -0
- adam/utils_repl/repl_completer.py +128 -2
- adam/utils_repl/state_machine.py +3 -3
- adam/utils_sqlite.py +78 -42
- adam/version.py +1 -1
- {kaqing-2.0.145.dist-info → kaqing-2.0.189.dist-info}/METADATA +1 -1
- kaqing-2.0.189.dist-info/RECORD +253 -0
- kaqing-2.0.189.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/app.py +0 -67
- adam/commands/cp.py +0 -95
- adam/commands/cql/cql_completions.py +0 -28
- adam/commands/export/clean_up_export_session.py +0 -53
- adam/commands/export/export_select_x.py +0 -54
- adam/commands/postgres/postgres_context.py +0 -248
- adam/commands/postgres/postgres_utils.py +0 -31
- adam/commands/postgres/psql_completions.py +0 -10
- adam/commands/reaper/reaper_session.py +0 -159
- adam/commands/show/show_app_actions.py +0 -56
- adam/commands/show/show_commands.py +0 -61
- adam/commands/show/show_repairs.py +0 -47
- kaqing-2.0.145.dist-info/RECORD +0 -227
- kaqing-2.0.145.dist-info/top_level.txt +0 -1
- {kaqing-2.0.145.dist-info → kaqing-2.0.189.dist-info}/WHEEL +0 -0
- {kaqing-2.0.145.dist-info → kaqing-2.0.189.dist-info}/entry_points.txt +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
from adam.commands import extract_options, extract_trailing_options
|
|
1
2
|
from adam.commands.command import Command
|
|
2
|
-
from adam.commands.
|
|
3
|
+
from adam.commands.cql.utils_cql import cassandra
|
|
3
4
|
from adam.config import Config
|
|
4
|
-
from adam.utils_k8s.statefulsets import StatefulSets
|
|
5
5
|
from adam.repl_state import ReplState, RequiredState
|
|
6
6
|
|
|
7
7
|
class ShowStorage(Command):
|
|
@@ -26,27 +26,18 @@ class ShowStorage(Command):
|
|
|
26
26
|
if not(args := self.args(cmd)):
|
|
27
27
|
return super().run(cmd, state)
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
with self.validate(args, state) as (args, state):
|
|
30
|
+
with extract_trailing_options(args, '&') as (args, backgrounded):
|
|
31
|
+
with extract_options(args, ['-s', '--show']) as (args, show_out):
|
|
32
|
+
cols = Config().get('storage.columns', 'pod,volume_root,volume_cassandra,snapshots,data,compactions')
|
|
33
|
+
header = Config().get('storage.header', 'POD_NAME,VOLUME /,VOLUME CASS,SNAPSHOTS,DATA,COMPACTIONS')
|
|
34
|
+
with cassandra(state) as pods:
|
|
35
|
+
pods.display_table(cols, header, show_out=show_out, backgrounded=backgrounded)
|
|
32
36
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
cols = Config().get('storage.columns', 'pod,volume_root,volume_cassandra,snapshots,data,compactions')
|
|
36
|
-
header = Config().get('storage.header', 'POD_NAME,VOLUME /,VOLUME CASS,SNAPSHOTS,DATA,COMPACTIONS')
|
|
37
|
-
if state.pod:
|
|
38
|
-
show_table(state, [state.pod], cols, header, show_output=show_output)
|
|
39
|
-
elif state.sts:
|
|
40
|
-
pod_names = [pod.metadata.name for pod in StatefulSets.pods(state.sts, state.namespace)]
|
|
41
|
-
show_table(state, pod_names, cols, header, show_output=show_output)
|
|
42
|
-
|
|
43
|
-
return state
|
|
37
|
+
return state
|
|
44
38
|
|
|
45
39
|
def completion(self, state: ReplState):
|
|
46
|
-
|
|
47
|
-
return {}
|
|
48
|
-
|
|
49
|
-
return super().completion(state)
|
|
40
|
+
return super().completion(state, {'-s': {'&': None}, '&': None})
|
|
50
41
|
|
|
51
42
|
def help(self, _: ReplState):
|
|
52
43
|
return f'{ShowStorage.COMMAND} [-s]\t show storage overview -s show commands on nodes'
|
adam/commands/watch.py
CHANGED
|
@@ -8,10 +8,10 @@ from adam.commands.commands_utils import show_pods, show_rollout
|
|
|
8
8
|
from adam.config import Config
|
|
9
9
|
from adam.utils_k8s.statefulsets import StatefulSets
|
|
10
10
|
from adam.repl_state import ReplState, RequiredState
|
|
11
|
-
from adam.utils import
|
|
11
|
+
from adam.utils import log2
|
|
12
12
|
|
|
13
13
|
class Watch(Command):
|
|
14
|
-
COMMAND = 'watch'
|
|
14
|
+
COMMAND = 'watch cassandra pods'
|
|
15
15
|
|
|
16
16
|
# the singleton pattern
|
|
17
17
|
def __new__(cls, *args, **kwargs):
|
|
@@ -26,37 +26,34 @@ class Watch(Command):
|
|
|
26
26
|
return Watch.COMMAND
|
|
27
27
|
|
|
28
28
|
def required(self):
|
|
29
|
-
return RequiredState.
|
|
29
|
+
return RequiredState.NAMESPACE
|
|
30
30
|
|
|
31
31
|
def run(self, cmd: str, state: ReplState):
|
|
32
32
|
if not(args := self.args(cmd)):
|
|
33
33
|
return super().run(cmd, state)
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if not pods:
|
|
41
|
-
log2("No pods are found.")
|
|
42
|
-
return state
|
|
35
|
+
with self.validate(args, state) as (args, state):
|
|
36
|
+
pods = StatefulSets.pods(state.sts, state.namespace)
|
|
37
|
+
if not pods:
|
|
38
|
+
log2("No pods are found.")
|
|
39
|
+
return state
|
|
43
40
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
stop_event = threading.Event()
|
|
42
|
+
thread = threading.Thread(target=self.loop, args=(stop_event, state.sts, pods, state.namespace), daemon=True)
|
|
43
|
+
thread.start()
|
|
47
44
|
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
try:
|
|
46
|
+
log2(f"Press Ctrl+C to break.")
|
|
50
47
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
48
|
+
time.sleep(Config().get('watch.timeout', 3600 * 1))
|
|
49
|
+
except KeyboardInterrupt:
|
|
50
|
+
pass
|
|
54
51
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
52
|
+
log2("Stopping watch...")
|
|
53
|
+
stop_event.set()
|
|
54
|
+
thread.join()
|
|
58
55
|
|
|
59
|
-
|
|
56
|
+
return state
|
|
60
57
|
|
|
61
58
|
def loop(self, stop_flag: threading.Event, sts: str, pods: List[client.V1Pod], ns: str):
|
|
62
59
|
show_pods(pods, ns)
|
|
@@ -73,13 +70,13 @@ class Watch(Command):
|
|
|
73
70
|
cnt = Config().get('watch.interval', 10)
|
|
74
71
|
|
|
75
72
|
def completion(self, state: ReplState):
|
|
76
|
-
if state
|
|
77
|
-
|
|
73
|
+
if sc := super().completion(state):
|
|
74
|
+
if state.sts:
|
|
75
|
+
return sc
|
|
78
76
|
|
|
79
|
-
|
|
80
|
-
return {Watch.COMMAND: {n: None for n in StatefulSets.list_sts_names()}}
|
|
77
|
+
return super().completion(state, {n: None for n in StatefulSets.list_sts_names()})
|
|
81
78
|
|
|
82
|
-
return {
|
|
79
|
+
return {}
|
|
83
80
|
|
|
84
81
|
def help(self, _: ReplState):
|
|
85
|
-
return f'{Watch.COMMAND}\t watch pod changes'
|
|
82
|
+
return f'{Watch.COMMAND}\t watch Cassandra pod changes'
|
adam/config.py
CHANGED
|
@@ -3,15 +3,16 @@ from typing import TypeVar, cast
|
|
|
3
3
|
import yaml
|
|
4
4
|
|
|
5
5
|
from . import __version__
|
|
6
|
-
from adam.utils import copy_config_file, get_deep_keys, log2
|
|
6
|
+
from adam.utils import LogConfig, copy_config_file, get_deep_keys, log2
|
|
7
7
|
|
|
8
8
|
T = TypeVar('T')
|
|
9
9
|
|
|
10
10
|
class Config:
|
|
11
11
|
EMBEDDED_PARAMS = {}
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
LogConfig.is_debug = lambda: Config().is_debug()
|
|
14
|
+
LogConfig.is_debug_complete = lambda: Config().get('debugs.complete', False)
|
|
15
|
+
LogConfig.is_debug_timing = lambda: Config().get('debugs.timings', False)
|
|
15
16
|
|
|
16
17
|
# the singleton pattern
|
|
17
18
|
def __new__(cls, *args, **kwargs):
|
|
@@ -44,10 +45,6 @@ class Config:
|
|
|
44
45
|
def is_debug(self):
|
|
45
46
|
return os.getenv('QING_DEV', 'false').lower() == 'true' or Config().get('debug', False)
|
|
46
47
|
|
|
47
|
-
def debug(self, s: None):
|
|
48
|
-
if self.is_debug():
|
|
49
|
-
log2(f'DEBUG {s}')
|
|
50
|
-
|
|
51
48
|
def get(self, key: str, default: T) -> T:
|
|
52
49
|
# params['nodetool']['status']['max-nodes']
|
|
53
50
|
d = self.params
|
|
@@ -88,12 +85,4 @@ class Config:
|
|
|
88
85
|
log2(f'incorrect path: {key}')
|
|
89
86
|
return None
|
|
90
87
|
|
|
91
|
-
return v if v else 'false'
|
|
92
|
-
|
|
93
|
-
def wait_log(self, msg: str):
|
|
94
|
-
if hasattr(self, 'wait_log_flag') and not self.wait_log_flag:
|
|
95
|
-
log2(msg)
|
|
96
|
-
self.wait_log_flag = True
|
|
97
|
-
|
|
98
|
-
def clear_wait_log_flag(self):
|
|
99
|
-
self.wait_log_flag = False
|
|
88
|
+
return v if v else 'false'
|
adam/embedded_params.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
def config():
|
|
2
|
-
return {'app': {'console-endpoint': 'https://{host}/{env}/{app}/static/console/index.html', 'container-name': 'c3-server', 'cr': {'cluster-regex': '(.*?-.*?)-.*', 'group': 'ops.c3.ai', 'v': 'v2', 'plural': 'c3cassandras'}, 'label': 'c3__app_id-0', 'login': {'admin-group': '{host}/C3.ClusterAdmin', 'ingress': '{app_id}-k8singr-appleader-001', 'timeout': 5, 'session-check-url': 'https://{host}/{env}/{app}/api/8/C3/userSessionToken', 'cache-creds': True, 'cache-username': True, 'url': 'https://{host}/{env}/{app}', 'another': "You're logged in to {has}. However, for this app, you need to log in to {need}.", 'token-server-url': 'http://localhost:{port}', 'password-max-length': 128}, 'strip': '0'}, 'audit': {'endpoint': 'https://4psvtaxlcb.execute-api.us-west-2.amazonaws.com/prod/', 'workers': 3, 'timeout': 10, 'log-audit-queries': False, 'athena': {'auto-repair': {'elapsed_hours': 12}, 'region': 'us-west-2', 'catalog': 'AwsDataCatalog', 'database': 'audit', 'repair-partition-tables': 'audit', 'output': 's3://s3.ops--audit/ddl/results', 'repair-cluster-tables': 'cluster'}}, 'bash': {'workers': 32}, 'cassandra': {'service-name': 'all-pods-service'}, 'cql': {'workers': 32, 'samples': 3, 'secret': {'cluster-regex': '(.*?-.*?)-.*', 'name': '{cluster}-superuser', 'password-item': 'password'}, 'alter-tables': {'excludes': 'system_auth,system_traces,reaper_db,system_distributed,system_views,system,system_schema,system_virtual_schema', 'gc-grace-periods': '3600,86400,864000,7776000', 'batching': True}}, '
|
|
2
|
+
return {'app': {'console-endpoint': 'https://{host}/{env}/{app}/static/console/index.html', 'container-name': 'c3-server', 'cr': {'cluster-regex': '(.*?-.*?)-.*', 'group': 'ops.c3.ai', 'v': 'v2', 'plural': 'c3cassandras'}, 'label': 'c3__app_id-0', 'login': {'admin-group': '{host}/C3.ClusterAdmin', 'ingress': '{app_id}-k8singr-appleader-001', 'timeout': 5, 'session-check-url': 'https://{host}/{env}/{app}/api/8/C3/userSessionToken', 'cache-creds': True, 'cache-username': True, 'url': 'https://{host}/{env}/{app}', 'another': "You're logged in to {has}. However, for this app, you need to log in to {need}.", 'token-server-url': 'http://localhost:{port}', 'password-max-length': 128}, 'strip': '0'}, 'audit': {'endpoint': 'https://4psvtaxlcb.execute-api.us-west-2.amazonaws.com/prod/', 'workers': 3, 'timeout': 10, 'log-audit-queries': False, 'athena': {'auto-repair': {'elapsed_hours': 12}, 'region': 'us-west-2', 'catalog': 'AwsDataCatalog', 'database': 'audit', 'repair-partition-tables': 'audit', 'output': 's3://s3.ops--audit/ddl/results', 'repair-cluster-tables': 'cluster'}, 'queries': {'last10': "SELECT * FROM audit\nWHERE drive <> 'z' and ({date_condition})\nORDER BY ts DESC LIMIT {limit}", 'slow10': "SELECT * FROM audit\nWHERE drive <> 'z' and ({date_condition})\nORDER BY CAST(duration AS REAL) DESC LIMIT {limit}", 'top10': "SELECT min(c) AS cluster, line, COUNT(*) AS cnt, avg(CAST(duration AS REAL)) AS duration\nFROM audit WHERE drive <> 'z' and ({date_condition})\nGROUP BY line ORDER BY cnt DESC LIMIT {limit}"}}, 'bash': {'workers': 32}, 'cassandra': {'service-name': 'all-pods-service'}, 'cql': {'workers': 32, 'samples': 3, 'secret': {'cluster-regex': '(.*?-.*?)-.*', 'name': '{cluster}-superuser', 'password-item': 'password'}, 'alter-tables': {'excludes': 'system_auth,system_traces,reaper_db,system_distributed,system_views,system,system_schema,system_virtual_schema', 'gc-grace-periods': '3600,86400,864000,7776000', 'batching': True}}, 'checks': {'compactions-threshold': 250, 'cpu-busy-threshold': 98.0, 'cpu-threshold': 0.0, 'cassandra-data-path': '/c3/cassandra', 'root-disk-threshold': 50, 'cassandra-disk-threshold': 50, 'snapshot-size-cmd': "ls /c3/cassandra/data/data/*/*/snapshots | grep snapshots | sed 's/:$//g' | xargs -I {} du -sk {} | awk '{print $1}' | awk '{s+=$1} END {print s}'", 'snapshot-size-threshold': '40G', 'table-sizes-cmd': "ls -Al /c3/cassandra/data/data/ | awk '{print $9}' | sed 's/\\^r//g' | xargs -I {} du -sk /c3/cassandra/data/data/{}"}, 'download': {'workers': 8}, 'export': {'workers': 8, 'csv_dir': '/c3/cassandra/tmp', 'column_counts_query': 'select id, count(id) as columns from {table} group by id order by columns desc limit 10', 'default-importer': 'sqlite', 'sqlite': {'workers': 8, 'columns': '<row-key>', 'local-db-dir': '/tmp/qing-db'}, 'athena': {'workers': 8, 'columns': '<keys>', 'bucket': 'c3.ops--qing'}, 'csv': {'workers': 8, 'columns': '<row-key>'}, 'log-prefix': '/tmp/qing'}, 'get-host-id': {'workers': 32}, 'idps': {'ad': {'email-pattern': '.*@c3.ai', 'uri': 'https://login.microsoftonline.com/53ad779a-93e7-485c-ba20-ac8290d7252b/oauth2/v2.0/authorize?response_type=id_token&response_mode=form_post&client_id=00ff94a8-6b0a-4715-98e0-95490012d818&scope=openid+email+profile&redirect_uri=https%3A%2F%2Fplat.c3ci.cloud%2Fc3%2Fc3%2Foidc%2Flogin&nonce={nonce}&state=EMPTY', 'jwks-uri': 'https://login.microsoftonline.com/common/discovery/keys', 'contact': 'Please contact ted.tran@c3.ai.', 'whitelist-file': '/kaqing/members'}, 'okta': {'default': True, 'email-pattern': '.*@c3iot.com', 'uri': 'https://c3energy.okta.com/oauth2/v1/authorize?response_type=id_token&response_mode=form_post&client_id={client_id}&scope=openid+email+profile+groups&redirect_uri=https%3A%2F%2F{host}%2Fc3%2Fc3%2Foidc%2Flogin&nonce={nonce}&state=EMPTY', 'jwks-uri': 'https://c3energy.okta.com/oauth2/v1/keys'}}, 'issues': {'workers': 32}, 'local-tmp-dir': '/tmp/qing-db', 'logs': {'path': '/c3/cassandra/logs/system.log'}, 'log-prefix': '/tmp/qing', 'nodetool': {'workers': 96, 'commands_in_line': 40, 'status': {'workers': 32, 'samples': 3, 'commands_in_line': 40}}, 'pg': {'name-pattern': '^{namespace}.*-k8spg-.*', 'excludes': '.helm., -admin-secret', 'agent': {'name': 'ops-pg-agent', 'just-in-time': False, 'timeout': 86400, 'image': 'seanahnsf/kaqing'}, 'default-db': 'postgres', 'default-schema': 'postgres', 'secret': {'endpoint-key': 'postgres-db-endpoint', 'port-key': 'postgres-db-port', 'username-key': 'postgres-admin-username', 'password-key': 'postgres-admin-password'}}, 'pod': {'name': 'ops', 'image': 'seanahnsf/kaqing-cloud', 'sa': {'name': 'ops', 'proto': 'c3', 'additional-cluster-roles': 'c3aiops-k8ssandra-operator'}, 'label-selector': 'run=ops'}, 'preview': {'rows': 10}, 'processes': {'columns': 'pod,cpu-metrics,mem', 'header': 'POD_NAME,M_CPU(USAGE/LIMIT),MEM/LIMIT'}, 'processes-qing': {'columns': 'pod,cpu,mem', 'header': 'POD_NAME,Q_CPU/TOTAL,MEM/LIMIT'}, 'reaper': {'service-name': 'reaper-service', 'port-forward': {'timeout': 86400, 'local-port': 9001}, 'abort-runs-batch': 10, 'show-runs-batch': 100, 'pod': {'cluster-regex': '(.*?-.*?-.*?-.*?)-.*', 'label-selector': 'k8ssandra.io/reaper={cluster}-reaper'}, 'secret': {'cluster-regex': '(.*?-.*?)-.*', 'name': '{cluster}-reaper-ui', 'password-item': 'password'}}, 'repair': {'log-path': '/home/cassrepair/logs/', 'image': 'ci-registry.c3iot.io/cloudops/cassrepair:2.0.14', 'secret': 'ciregistryc3iotio', 'env': {'interval': 24, 'timeout': 60, 'pr': False, 'runs': 1}}, 'repl': {'start-drive': 'c', 'a': {'auto-enter': 'c3/c3'}, 'c': {'auto-enter': 'cluster'}, 'x': {'auto-enter': 'latest'}, 'history': {'push-cat-log-file': True, 'push-cat-remote-log-file': True}, 'background-process': {'auto-nohup': True}}, 'status': {'columns': 'status,address,load,tokens,owns,host_id,gossip,compactions', 'header': '--,Address,Load,Tokens,Owns,Host ID,GOSSIP,COMPACTIONS'}, 'storage': {'columns': 'pod,volume_root,volume_cassandra,snapshots,data,compactions', 'header': 'POD_NAME,VOLUME /,VOLUME CASS,SNAPSHOTS,DATA,COMPACTIONS'}, 'watch': {'auto': 'rollout', 'timeout': 3600, 'interval': 10}, 'auto-complete': {'c': {'tables': 'lazy'}, 'x': {'tables': 'lazy'}, 'cli': {'cp': 'jit'}, 'export': {'databases': 'jit'}, 'medusa': {'backups': 'jit'}, 'reaper': {'schedules': 'lazy'}}, 'debug': False, 'debugs': {'timings': False, 'exit-on-error': False, 'show-parallelism': False}}
|
adam/log.py
CHANGED
|
@@ -4,6 +4,8 @@ import os
|
|
|
4
4
|
import sys
|
|
5
5
|
import click
|
|
6
6
|
|
|
7
|
+
from adam.utils import log_exc
|
|
8
|
+
|
|
7
9
|
class Log:
|
|
8
10
|
DEBUG = False
|
|
9
11
|
|
|
@@ -28,7 +30,7 @@ class Log:
|
|
|
28
30
|
print(file=sys.stderr)
|
|
29
31
|
|
|
30
32
|
def log_to_file(config: dict[any, any]):
|
|
31
|
-
|
|
33
|
+
with log_exc():
|
|
32
34
|
base = f"/tmp/logs"
|
|
33
35
|
os.makedirs(base, exist_ok=True)
|
|
34
36
|
|
|
@@ -42,6 +44,4 @@ class Log:
|
|
|
42
44
|
except:
|
|
43
45
|
f.write(config)
|
|
44
46
|
else:
|
|
45
|
-
f.write(config)
|
|
46
|
-
except:
|
|
47
|
-
pass
|
|
47
|
+
f.write(config)
|
adam/pod_exec_result.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import yaml
|
|
2
2
|
|
|
3
|
+
from adam.utils import log_exc
|
|
4
|
+
|
|
3
5
|
class PodExecResult:
|
|
4
6
|
# {
|
|
5
7
|
# 'metadata': {},
|
|
@@ -27,10 +29,8 @@ class PodExecResult:
|
|
|
27
29
|
def exit_code(self) -> int:
|
|
28
30
|
code = 0
|
|
29
31
|
|
|
30
|
-
|
|
32
|
+
with log_exc(False):
|
|
31
33
|
code = self.error['details']['causes'][0]['message']
|
|
32
|
-
except:
|
|
33
|
-
pass
|
|
34
34
|
|
|
35
35
|
return code
|
|
36
36
|
|
adam/repl.py
CHANGED
|
@@ -1,30 +1,31 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import time
|
|
3
|
-
import traceback
|
|
4
3
|
from typing import cast
|
|
5
4
|
import click
|
|
6
|
-
import concurrent
|
|
7
5
|
from prompt_toolkit.key_binding import KeyBindings
|
|
8
6
|
|
|
9
7
|
from adam.cli_group import cli
|
|
10
|
-
from adam.commands.command import Command
|
|
8
|
+
from adam.commands.command import Command, InvalidArgumentsException, InvalidStateException
|
|
11
9
|
from adam.commands.command_helpers import ClusterCommandHelper
|
|
12
10
|
from adam.commands.devices.devices import Devices
|
|
13
11
|
from adam.commands.help import Help
|
|
14
12
|
from adam.config import Config
|
|
15
13
|
from adam.utils_audits import Audits
|
|
16
|
-
from adam.utils_k8s.app_pods import AppPods
|
|
17
14
|
from adam.utils_k8s.kube_context import KubeContext
|
|
18
|
-
from adam.utils_k8s.statefulsets import StatefulSets
|
|
19
15
|
from adam.log import Log
|
|
20
16
|
from adam.repl_commands import ReplCommands
|
|
21
17
|
from adam.repl_session import ReplSession
|
|
22
18
|
from adam.repl_state import ReplState
|
|
23
|
-
from adam.utils import
|
|
19
|
+
from adam.utils import clear_wait_log_flag, debug_trace, deep_sort_dict, tabulize, log2, log_exc, log_timing
|
|
24
20
|
from adam.apps import Apps
|
|
25
|
-
from adam.utils_repl.repl_completer import ReplCompleter
|
|
21
|
+
from adam.utils_repl.repl_completer import ReplCompleter, merge_completions
|
|
26
22
|
from . import __version__
|
|
27
23
|
|
|
24
|
+
import nest_asyncio
|
|
25
|
+
nest_asyncio.apply()
|
|
26
|
+
|
|
27
|
+
import asyncio
|
|
28
|
+
|
|
28
29
|
def enter_repl(state: ReplState):
|
|
29
30
|
if os.getenv('QING_DROPPED', 'false') == 'true':
|
|
30
31
|
log2('You have dropped to bash from another qing instance. Please enter "exit" to go back to qing.')
|
|
@@ -50,34 +51,32 @@ def enter_repl(state: ReplState):
|
|
|
50
51
|
def _(event):
|
|
51
52
|
event.app.current_buffer.text = ''
|
|
52
53
|
|
|
53
|
-
with
|
|
54
|
+
with Audits.offload() as exec:
|
|
54
55
|
# warm up AWS lambda - this log line may timeout and get lost, which is fine
|
|
55
|
-
|
|
56
|
+
exec.submit(Audits.log, 'entering kaqing repl', state.namespace, 'z', 0.0)
|
|
56
57
|
|
|
57
58
|
s0 = time.time()
|
|
58
59
|
|
|
59
60
|
# use sorted command list only for auto-completion
|
|
60
61
|
sorted_cmds = sorted(cmd_list, key=lambda cmd: cmd.command())
|
|
61
62
|
while True:
|
|
63
|
+
cmd: str = None
|
|
62
64
|
result = None
|
|
63
65
|
try:
|
|
64
66
|
completer = ReplCompleter.from_nested_dict({})
|
|
65
67
|
if not state.bash_session:
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
# print(json.dumps(completions, indent=4))
|
|
80
|
-
completer = ReplCompleter.from_nested_dict(completions)
|
|
68
|
+
with log_timing('completion-calcs'):
|
|
69
|
+
completions = {}
|
|
70
|
+
# app commands are available only on a: drive
|
|
71
|
+
if state.device == ReplState.A and state.app_app:
|
|
72
|
+
completions = log_timing('actions', lambda: Apps(path='apps.yaml').commands())
|
|
73
|
+
|
|
74
|
+
for c in sorted_cmds:
|
|
75
|
+
with log_exc(f'* {c.command()} command returned None completions.'):
|
|
76
|
+
completions = log_timing(c.command(), lambda: deep_sort_dict(merge_completions(completions, c.completion(state))))
|
|
77
|
+
|
|
78
|
+
# print(json.dumps(completions, indent=4))
|
|
79
|
+
completer = ReplCompleter.from_nested_dict(completions)
|
|
81
80
|
|
|
82
81
|
cmd = session.prompt(prompt_msg(), completer=completer, key_bindings=kb)
|
|
83
82
|
s0 = time.time()
|
|
@@ -94,17 +93,17 @@ def enter_repl(state: ReplState):
|
|
|
94
93
|
return state, cmd
|
|
95
94
|
|
|
96
95
|
if state.device == ReplState.A and state.app_app or state.device == ReplState.P:
|
|
97
|
-
state.push()
|
|
96
|
+
state.push(pod_targetted=True)
|
|
98
97
|
|
|
99
98
|
state.app_pod = arry[0].strip('@')
|
|
100
99
|
cmd = ' '.join(arry[1:])
|
|
101
100
|
elif state.device == ReplState.P:
|
|
102
|
-
state.push()
|
|
101
|
+
state.push(pod_targetted=True)
|
|
103
102
|
|
|
104
103
|
state.app_pod = arry[0].strip('@')
|
|
105
104
|
cmd = ' '.join(arry[1:])
|
|
106
105
|
elif state.sts:
|
|
107
|
-
state.push()
|
|
106
|
+
state.push(pod_targetted=True)
|
|
108
107
|
|
|
109
108
|
state.pod = arry[0].strip('@')
|
|
110
109
|
cmd = ' '.join(arry[1:])
|
|
@@ -112,8 +111,13 @@ def enter_repl(state: ReplState):
|
|
|
112
111
|
return (state, cmd)
|
|
113
112
|
|
|
114
113
|
target, cmd = targetted(state, cmd)
|
|
115
|
-
|
|
116
|
-
|
|
114
|
+
try:
|
|
115
|
+
if cmd and cmd.strip(' ') and not (result := cmds.run(cmd, target)):
|
|
116
|
+
result = try_device_default_action(target, cmds, cmd_list, cmd)
|
|
117
|
+
except InvalidStateException:
|
|
118
|
+
pass
|
|
119
|
+
except InvalidArgumentsException:
|
|
120
|
+
pass
|
|
117
121
|
|
|
118
122
|
if result and type(result) is ReplState and (s := cast(ReplState, result).export_session) != state.export_session:
|
|
119
123
|
state.export_session = s
|
|
@@ -125,27 +129,26 @@ def enter_repl(state: ReplState):
|
|
|
125
129
|
raise e
|
|
126
130
|
else:
|
|
127
131
|
log2(e)
|
|
128
|
-
|
|
132
|
+
debug_trace()
|
|
129
133
|
finally:
|
|
130
134
|
if not state.bash_session:
|
|
131
135
|
state.pop()
|
|
132
136
|
|
|
133
|
-
|
|
134
|
-
if
|
|
135
|
-
|
|
137
|
+
clear_wait_log_flag()
|
|
138
|
+
if cmd:
|
|
139
|
+
log_timing(f'command {cmd}', s0=s0)
|
|
136
140
|
|
|
137
141
|
# offload audit logging
|
|
138
142
|
if cmd and (state.device != ReplState.L or Config().get('audit.log-audit-queries', False)):
|
|
139
|
-
|
|
143
|
+
exec.submit(Audits.log, cmd, state.namespace, state.device, time.time() - s0, get_audit_extra(result))
|
|
140
144
|
|
|
141
145
|
def try_device_default_action(state: ReplState, cmds: Command, cmd_list: list[Command], cmd: str):
|
|
142
|
-
|
|
146
|
+
action_taken, result = Devices.device(state).try_fallback_action(cmds, state, cmd)
|
|
143
147
|
|
|
144
|
-
if not
|
|
148
|
+
if not action_taken:
|
|
145
149
|
log2(f'* Invalid command: {cmd}')
|
|
146
150
|
log2()
|
|
147
|
-
|
|
148
|
-
log2(lines_to_tabular(lines, separator='\t'))
|
|
151
|
+
tabulize([c.help(state) for c in cmd_list if c.help(state)], separator='\t', to=2)
|
|
149
152
|
|
|
150
153
|
return result
|
|
151
154
|
|
|
@@ -177,6 +180,9 @@ def repl(kubeconfig: str, config: str, param: list[str], cluster:str, namespace:
|
|
|
177
180
|
if not KubeContext.init_params(config, param):
|
|
178
181
|
return
|
|
179
182
|
|
|
180
|
-
state = ReplState(
|
|
183
|
+
state = ReplState(ns_sts=cluster, namespace=namespace, in_repl=True)
|
|
181
184
|
state, _ = state.apply_device_arg(extra_args)
|
|
185
|
+
if not state.device:
|
|
186
|
+
state.device=Config().get('repl.start-drive', 'a')
|
|
187
|
+
|
|
182
188
|
enter_repl(state)
|
adam/repl_commands.py
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
from adam.commands.alter_tables import AlterTables
|
|
2
|
-
from adam.commands.app import App
|
|
3
|
-
from adam.commands.app_ping import AppPing
|
|
2
|
+
from adam.commands.app.app import App
|
|
3
|
+
from adam.commands.app.app_ping import AppPing
|
|
4
|
+
from adam.commands.app.show_app_actions import ShowAppActions
|
|
5
|
+
from adam.commands.app.show_app_id import ShowAppId
|
|
6
|
+
from adam.commands.app.show_app_queues import ShowAppQueues
|
|
4
7
|
from adam.commands.audit.audit import Audit
|
|
5
8
|
from adam.commands.cat import Cat
|
|
6
9
|
from adam.commands.code import Code
|
|
10
|
+
from adam.commands.download_file import DownloadFile
|
|
7
11
|
from adam.commands.deploy.code_start import CodeStart
|
|
8
12
|
from adam.commands.deploy.code_stop import CodeStop
|
|
9
13
|
from adam.commands.deploy.deploy import Deploy
|
|
@@ -19,23 +23,27 @@ from adam.commands.devices.device_auit_log import DeviceAuditLog
|
|
|
19
23
|
from adam.commands.devices.device_cass import DeviceCass
|
|
20
24
|
from adam.commands.devices.device_export import DeviceExport
|
|
21
25
|
from adam.commands.devices.device_postgres import DevicePostgres
|
|
26
|
+
from adam.commands.export.download_export_session import DownloadExportSession
|
|
22
27
|
from adam.commands.export.drop_export_database import DropExportDatabase
|
|
23
28
|
from adam.commands.export.export import ExportTables
|
|
29
|
+
from adam.commands.export.import_files import ImportCSVFiles
|
|
24
30
|
from adam.commands.export.import_session import ImportSession
|
|
25
|
-
from adam.commands.export.clean_up_export_session import CleanUpExportSession
|
|
26
31
|
from adam.commands.export.clean_up_export_sessions import CleanUpExportSessions
|
|
32
|
+
from adam.commands.export.clean_up_all_export_sessions import CleanUpAllExportSessions
|
|
27
33
|
from adam.commands.export.drop_export_databases import DropExportDatabases
|
|
28
|
-
from adam.commands.export.
|
|
34
|
+
from adam.commands.export.export_x_select import ExportXSelect
|
|
29
35
|
from adam.commands.export.export_use import ExportUse
|
|
30
|
-
from adam.commands.export.
|
|
36
|
+
from adam.commands.export.export_select import ExportSelect
|
|
31
37
|
from adam.commands.export.show_column_counts import ShowColumnCounts
|
|
32
38
|
from adam.commands.export.show_export_databases import ShowExportDatabases
|
|
33
39
|
from adam.commands.export.show_export_session import ShowExportSession
|
|
34
40
|
from adam.commands.export.show_export_sessions import ShowExportSessions
|
|
41
|
+
from adam.commands.find_files import FindLocalFiles
|
|
42
|
+
from adam.commands.find_processes import FindProcesses
|
|
43
|
+
from adam.commands.head import Head
|
|
35
44
|
from adam.commands.kubectl import Kubectl
|
|
36
45
|
from adam.commands.shell import Shell
|
|
37
|
-
from adam.commands.
|
|
38
|
-
from adam.commands.cp import ClipboardCopy
|
|
46
|
+
from adam.commands.clipboard_copy import ClipboardCopy
|
|
39
47
|
from adam.commands.bash.bash import Bash
|
|
40
48
|
from adam.commands.cd import Cd
|
|
41
49
|
from adam.commands.check import Check
|
|
@@ -57,16 +65,14 @@ from adam.commands.restart import Restart
|
|
|
57
65
|
from adam.commands.rollout import RollOut
|
|
58
66
|
from adam.commands.param_set import SetParam
|
|
59
67
|
from adam.commands.show.show import Show
|
|
60
|
-
from adam.commands.show.show_app_actions import ShowAppActions
|
|
61
|
-
from adam.commands.show.show_app_id import ShowAppId
|
|
62
68
|
from adam.commands.show.show_cassandra_status import ShowCassandraStatus
|
|
63
69
|
from adam.commands.show.show_cassandra_version import ShowCassandraVersion
|
|
64
|
-
from adam.commands.show.
|
|
70
|
+
from adam.commands.show.show_cli_commands import ShowKubectlCommands
|
|
65
71
|
from adam.commands.show.show_host import ShowHost
|
|
66
72
|
from adam.commands.show.show_login import ShowLogin
|
|
67
73
|
from adam.commands.show.show_params import ShowParams
|
|
68
74
|
from adam.commands.show.show_processes import ShowProcesses
|
|
69
|
-
from adam.commands.show.
|
|
75
|
+
from adam.commands.show.show_cassandra_repairs import ShowCassandraRepairs
|
|
70
76
|
from adam.commands.show.show_storage import ShowStorage
|
|
71
77
|
from adam.commands.show.show_adam import ShowAdam
|
|
72
78
|
from adam.commands.watch import Watch
|
|
@@ -93,17 +99,18 @@ class ReplCommands:
|
|
|
93
99
|
return deduped
|
|
94
100
|
|
|
95
101
|
def navigation() -> list[Command]:
|
|
96
|
-
return [Ls(), PreviewTable(), DeviceApp(), DevicePostgres(), DeviceCass(), DeviceAuditLog(), DeviceExport(),
|
|
102
|
+
return [Ls(), PreviewTable(), DeviceApp(), DevicePostgres(), DeviceCass(), DeviceAuditLog(), DeviceExport(),
|
|
103
|
+
Cd(), Cat(), Head(), DownloadFile(), FindLocalFiles(), FindProcesses(), Pwd(), ClipboardCopy(),
|
|
97
104
|
GetParam(), SetParam(), ShowParams(), ShowKubectlCommands(), ShowLogin(), ShowAdam(), ShowHost()]
|
|
98
105
|
|
|
99
106
|
def cassandra_ops() -> list[Command]:
|
|
100
|
-
return [Cqlsh(), ShowCassandraStatus(), ShowCassandraVersion(),
|
|
107
|
+
return [Cqlsh(), ShowCassandraStatus(), ShowCassandraVersion(), ShowCassandraRepairs(), ShowStorage(), ShowProcesses(),
|
|
101
108
|
Check(), Issues(), NodeTool(), Report(), AlterTables(), Bash(),
|
|
102
|
-
ExportTables(),
|
|
109
|
+
ExportTables(), ExportXSelect(), ExportUse(), ShowExportDatabases(), ShowColumnCounts(),
|
|
103
110
|
DropExportDatabase(), DropExportDatabases(),
|
|
104
|
-
ShowExportSessions(), ShowExportSession(),
|
|
105
|
-
|
|
106
|
-
Medusa.cmd_list() + [Restart(), RollOut(), Watch()] + Reaper.cmd_list() + Repair.cmd_list()
|
|
111
|
+
ShowExportSessions(), ShowExportSession(), DownloadExportSession(),
|
|
112
|
+
CleanUpExportSessions(), CleanUpAllExportSessions(), ImportSession(), ImportCSVFiles()] + \
|
|
113
|
+
Medusa().cmd_list() + [Restart(), RollOut(), Watch()] + Reaper().cmd_list() + Repair().cmd_list()
|
|
107
114
|
|
|
108
115
|
def postgres_ops() -> list[Command]:
|
|
109
116
|
return [Postgres(), DeployPgAgent(), UndeployPgAgent(), PostgresPg()]
|
|
@@ -112,10 +119,10 @@ class ReplCommands:
|
|
|
112
119
|
return [ShowAppActions(), ShowAppId(), ShowAppQueues(), AppPing(), App()]
|
|
113
120
|
|
|
114
121
|
def audit_ops() -> list[Command]:
|
|
115
|
-
return [Audit()] + Audit.cmd_list()
|
|
122
|
+
return [Audit()] + Audit().cmd_list()
|
|
116
123
|
|
|
117
124
|
def export_ops() -> list[Command]:
|
|
118
|
-
return [
|
|
125
|
+
return [ExportSelect(), DropExportDatabase(), DropExportDatabases(), ShowColumnCounts()]
|
|
119
126
|
|
|
120
127
|
def tools() -> list[Command]:
|
|
121
128
|
return [Shell(), CodeStart(), CodeStop(), DeployFrontend(), UndeployFrontend(), DeployPod(), UndeployPod(), Kubectl(), Code()]
|
adam/repl_session.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
from prompt_toolkit import PromptSession
|
|
2
2
|
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
|
|
3
3
|
|
|
4
|
+
from adam.config import Config
|
|
5
|
+
|
|
4
6
|
class ReplSession:
|
|
5
7
|
# the singleton pattern
|
|
6
8
|
def __new__(cls, *args, **kwargs):
|
|
@@ -10,4 +12,9 @@ class ReplSession:
|
|
|
10
12
|
|
|
11
13
|
def __init__(self):
|
|
12
14
|
if not hasattr(self, 'prompt_session'):
|
|
13
|
-
self.prompt_session = PromptSession(auto_suggest=AutoSuggestFromHistory())
|
|
15
|
+
self.prompt_session = PromptSession(auto_suggest=AutoSuggestFromHistory())
|
|
16
|
+
|
|
17
|
+
def append_history(self, entry: str):
|
|
18
|
+
if entry and Config().get('repl.history.push-cat-remote-log-file', True):
|
|
19
|
+
if self.prompt_session:
|
|
20
|
+
self.prompt_session.history.append_string(entry)
|