kaqing 1.77.0__py3-none-any.whl → 2.0.171__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.
- adam/__init__.py +1 -0
- adam/app_session.py +182 -0
- {walker → adam}/apps.py +8 -24
- {walker → adam}/batch.py +54 -97
- {walker → adam}/checks/check.py +3 -3
- {walker → adam}/checks/check_result.py +1 -1
- adam/checks/check_utils.py +65 -0
- {walker → adam}/checks/compactionstats.py +6 -6
- {walker → adam}/checks/cpu.py +14 -8
- adam/checks/cpu_metrics.py +52 -0
- {walker → adam}/checks/disk.py +6 -6
- {walker → adam}/checks/gossip.py +5 -5
- {walker → adam}/checks/memory.py +7 -7
- {walker → adam}/checks/status.py +5 -5
- {walker → adam}/cli.py +3 -3
- {walker → adam}/columns/column.py +1 -1
- adam/columns/columns.py +45 -0
- {walker → adam}/columns/compactions.py +5 -5
- {walker → adam}/columns/cpu.py +6 -4
- adam/columns/cpu_metrics.py +22 -0
- {walker → adam}/columns/dir_data.py +3 -3
- {walker → adam}/columns/dir_snapshots.py +3 -3
- {walker → adam}/columns/gossip.py +5 -5
- {walker → adam}/columns/host_id.py +3 -3
- {walker → adam}/columns/memory.py +3 -3
- {walker → adam}/columns/node_address.py +3 -3
- {walker → adam}/columns/node_load.py +3 -3
- {walker → adam}/columns/node_owns.py +3 -3
- {walker → adam}/columns/node_status.py +3 -3
- {walker → adam}/columns/node_tokens.py +3 -3
- {walker → adam}/columns/node_utils.py +2 -2
- {walker → adam}/columns/pod_name.py +2 -2
- {walker → adam}/columns/volume_cassandra.py +4 -4
- {walker → adam}/columns/volume_root.py +3 -3
- adam/commands/__init__.py +15 -0
- adam/commands/alter_tables.py +81 -0
- adam/commands/app_cmd.py +38 -0
- {walker → adam}/commands/app_ping.py +10 -16
- adam/commands/audit/audit.py +84 -0
- adam/commands/audit/audit_repair_tables.py +74 -0
- adam/commands/audit/audit_run.py +50 -0
- adam/commands/audit/show_last10.py +48 -0
- adam/commands/audit/show_slow10.py +47 -0
- adam/commands/audit/show_top10.py +45 -0
- adam/commands/audit/utils_show_top10.py +59 -0
- adam/commands/bash/__init__.py +5 -0
- adam/commands/bash/bash.py +36 -0
- adam/commands/bash/bash_completer.py +93 -0
- adam/commands/bash/utils_bash.py +16 -0
- adam/commands/cat.py +50 -0
- adam/commands/cd.py +43 -0
- adam/commands/check.py +73 -0
- {walker → adam}/commands/cli_commands.py +7 -8
- adam/commands/code.py +57 -0
- adam/commands/command.py +190 -0
- {walker → adam}/commands/command_helpers.py +1 -1
- {walker → adam}/commands/commands_utils.py +15 -25
- adam/commands/cp.py +89 -0
- adam/commands/cql/cql_completions.py +33 -0
- {walker/commands → adam/commands/cql}/cqlsh.py +20 -35
- adam/commands/cql/utils_cql.py +343 -0
- {walker/commands/frontend → adam/commands/deploy}/code_start.py +11 -14
- adam/commands/deploy/code_stop.py +40 -0
- {walker/commands/frontend → adam/commands/deploy}/code_utils.py +7 -9
- adam/commands/deploy/deploy.py +25 -0
- adam/commands/deploy/deploy_frontend.py +49 -0
- adam/commands/deploy/deploy_pg_agent.py +35 -0
- adam/commands/deploy/deploy_pod.py +108 -0
- adam/commands/deploy/deploy_utils.py +29 -0
- adam/commands/deploy/undeploy.py +25 -0
- adam/commands/deploy/undeploy_frontend.py +38 -0
- adam/commands/deploy/undeploy_pg_agent.py +39 -0
- adam/commands/deploy/undeploy_pod.py +48 -0
- adam/commands/devices/device.py +118 -0
- adam/commands/devices/device_app.py +173 -0
- adam/commands/devices/device_auit_log.py +49 -0
- adam/commands/devices/device_cass.py +185 -0
- adam/commands/devices/device_export.py +86 -0
- adam/commands/devices/device_postgres.py +144 -0
- adam/commands/devices/devices.py +25 -0
- {walker → adam}/commands/exit.py +3 -6
- adam/commands/export/clean_up_all_export_sessions.py +37 -0
- adam/commands/export/clean_up_export_sessions.py +51 -0
- adam/commands/export/drop_export_database.py +55 -0
- adam/commands/export/drop_export_databases.py +43 -0
- adam/commands/export/export.py +53 -0
- adam/commands/export/export_databases.py +170 -0
- adam/commands/export/export_handlers.py +71 -0
- adam/commands/export/export_select.py +81 -0
- adam/commands/export/export_select_x.py +54 -0
- adam/commands/export/export_use.py +52 -0
- adam/commands/export/exporter.py +352 -0
- adam/commands/export/import_session.py +40 -0
- adam/commands/export/importer.py +67 -0
- adam/commands/export/importer_athena.py +80 -0
- adam/commands/export/importer_sqlite.py +47 -0
- adam/commands/export/show_column_counts.py +54 -0
- adam/commands/export/show_export_databases.py +36 -0
- adam/commands/export/show_export_session.py +48 -0
- adam/commands/export/show_export_sessions.py +44 -0
- adam/commands/export/utils_export.py +314 -0
- {walker → adam}/commands/help.py +17 -12
- adam/commands/intermediate_command.py +49 -0
- adam/commands/issues.py +43 -0
- adam/commands/kubectl.py +38 -0
- adam/commands/login.py +70 -0
- {walker → adam}/commands/logs.py +8 -10
- adam/commands/ls.py +41 -0
- adam/commands/medusa/medusa.py +27 -0
- adam/commands/medusa/medusa_backup.py +57 -0
- adam/commands/medusa/medusa_restore.py +83 -0
- adam/commands/medusa/medusa_show_backupjobs.py +51 -0
- adam/commands/medusa/medusa_show_restorejobs.py +47 -0
- {walker → adam}/commands/nodetool.py +17 -21
- {walker → adam}/commands/param_get.py +15 -16
- adam/commands/param_set.py +43 -0
- adam/commands/postgres/postgres.py +104 -0
- adam/commands/postgres/postgres_context.py +274 -0
- {walker → adam}/commands/postgres/postgres_ls.py +7 -11
- {walker → adam}/commands/postgres/postgres_preview.py +8 -13
- adam/commands/postgres/psql_completions.py +10 -0
- adam/commands/postgres/utils_postgres.py +66 -0
- adam/commands/preview_table.py +37 -0
- adam/commands/pwd.py +47 -0
- adam/commands/reaper/reaper.py +35 -0
- adam/commands/reaper/reaper_forward.py +93 -0
- adam/commands/reaper/reaper_forward_session.py +6 -0
- {walker → adam}/commands/reaper/reaper_forward_stop.py +13 -19
- {walker → adam}/commands/reaper/reaper_restart.py +10 -17
- adam/commands/reaper/reaper_run_abort.py +46 -0
- adam/commands/reaper/reaper_runs.py +82 -0
- adam/commands/reaper/reaper_runs_abort.py +63 -0
- adam/commands/reaper/reaper_schedule_activate.py +45 -0
- adam/commands/reaper/reaper_schedule_start.py +45 -0
- adam/commands/reaper/reaper_schedule_stop.py +45 -0
- {walker → adam}/commands/reaper/reaper_schedules.py +6 -16
- {walker → adam}/commands/reaper/reaper_status.py +11 -19
- adam/commands/reaper/utils_reaper.py +196 -0
- adam/commands/repair/repair.py +26 -0
- {walker → adam}/commands/repair/repair_log.py +7 -10
- adam/commands/repair/repair_run.py +70 -0
- adam/commands/repair/repair_scan.py +71 -0
- {walker → adam}/commands/repair/repair_stop.py +8 -11
- adam/commands/report.py +61 -0
- adam/commands/restart.py +60 -0
- {walker → adam}/commands/rollout.py +25 -30
- adam/commands/shell.py +34 -0
- adam/commands/show/show.py +39 -0
- walker/commands/show/show_version.py → adam/commands/show/show_adam.py +14 -10
- adam/commands/show/show_app_actions.py +57 -0
- {walker → adam}/commands/show/show_app_id.py +12 -15
- {walker → adam}/commands/show/show_app_queues.py +9 -12
- adam/commands/show/show_cassandra_repairs.py +38 -0
- adam/commands/show/show_cassandra_status.py +124 -0
- {walker → adam}/commands/show/show_cassandra_version.py +6 -16
- adam/commands/show/show_commands.py +59 -0
- walker/commands/show/show_storage.py → adam/commands/show/show_host.py +11 -13
- adam/commands/show/show_login.py +62 -0
- {walker → adam}/commands/show/show_params.py +4 -4
- adam/commands/show/show_processes.py +51 -0
- adam/commands/show/show_storage.py +42 -0
- adam/commands/watch.py +82 -0
- {walker → adam}/config.py +10 -22
- {walker → adam}/embedded_apps.py +1 -1
- adam/embedded_params.py +2 -0
- adam/log.py +47 -0
- {walker → adam}/pod_exec_result.py +10 -2
- adam/repl.py +182 -0
- adam/repl_commands.py +124 -0
- adam/repl_state.py +458 -0
- adam/sql/__init__.py +0 -0
- adam/sql/sql_completer.py +120 -0
- adam/sql/sql_state_machine.py +618 -0
- adam/sql/term_completer.py +76 -0
- adam/sso/__init__.py +0 -0
- {walker → adam}/sso/authenticator.py +5 -1
- adam/sso/authn_ad.py +170 -0
- {walker → adam}/sso/authn_okta.py +39 -22
- adam/sso/cred_cache.py +60 -0
- adam/sso/id_token.py +23 -0
- adam/sso/idp.py +143 -0
- adam/sso/idp_login.py +50 -0
- adam/sso/idp_session.py +55 -0
- adam/sso/sso_config.py +63 -0
- adam/utils.py +679 -0
- adam/utils_app.py +98 -0
- adam/utils_athena.py +145 -0
- adam/utils_audits.py +106 -0
- adam/utils_issues.py +32 -0
- adam/utils_k8s/__init__.py +0 -0
- adam/utils_k8s/app_clusters.py +28 -0
- adam/utils_k8s/app_pods.py +33 -0
- adam/utils_k8s/cassandra_clusters.py +36 -0
- adam/utils_k8s/cassandra_nodes.py +33 -0
- adam/utils_k8s/config_maps.py +34 -0
- {walker/k8s_utils → adam/utils_k8s}/custom_resources.py +7 -2
- adam/utils_k8s/deployment.py +56 -0
- {walker/k8s_utils → adam/utils_k8s}/ingresses.py +3 -4
- {walker/k8s_utils → adam/utils_k8s}/jobs.py +3 -3
- adam/utils_k8s/k8s.py +87 -0
- {walker/k8s_utils → adam/utils_k8s}/kube_context.py +4 -4
- adam/utils_k8s/pods.py +290 -0
- {walker/k8s_utils → adam/utils_k8s}/secrets.py +8 -4
- adam/utils_k8s/service_accounts.py +170 -0
- {walker/k8s_utils → adam/utils_k8s}/services.py +3 -4
- {walker/k8s_utils → adam/utils_k8s}/statefulsets.py +6 -16
- {walker/k8s_utils → adam/utils_k8s}/volumes.py +10 -1
- adam/utils_net.py +24 -0
- adam/utils_repl/__init__.py +0 -0
- adam/utils_repl/automata_completer.py +48 -0
- adam/utils_repl/repl_completer.py +46 -0
- adam/utils_repl/state_machine.py +173 -0
- adam/utils_sqlite.py +109 -0
- adam/version.py +5 -0
- {kaqing-1.77.0.dist-info → kaqing-2.0.171.dist-info}/METADATA +1 -1
- kaqing-2.0.171.dist-info/RECORD +236 -0
- kaqing-2.0.171.dist-info/entry_points.txt +3 -0
- kaqing-2.0.171.dist-info/top_level.txt +1 -0
- kaqing-1.77.0.dist-info/RECORD +0 -159
- kaqing-1.77.0.dist-info/entry_points.txt +0 -3
- kaqing-1.77.0.dist-info/top_level.txt +0 -1
- walker/__init__.py +0 -3
- walker/app_session.py +0 -168
- walker/checks/check_utils.py +0 -97
- walker/columns/columns.py +0 -43
- walker/commands/add_user.py +0 -68
- walker/commands/app.py +0 -67
- walker/commands/bash.py +0 -87
- walker/commands/cd.py +0 -115
- walker/commands/check.py +0 -68
- walker/commands/command.py +0 -104
- walker/commands/cp.py +0 -95
- walker/commands/cql_utils.py +0 -53
- walker/commands/devices.py +0 -89
- walker/commands/frontend/code_stop.py +0 -57
- walker/commands/frontend/setup.py +0 -60
- walker/commands/frontend/setup_frontend.py +0 -58
- walker/commands/frontend/teardown.py +0 -61
- walker/commands/frontend/teardown_frontend.py +0 -42
- walker/commands/issues.py +0 -69
- walker/commands/login.py +0 -72
- walker/commands/ls.py +0 -145
- walker/commands/medusa/medusa.py +0 -69
- walker/commands/medusa/medusa_backup.py +0 -61
- walker/commands/medusa/medusa_restore.py +0 -86
- walker/commands/medusa/medusa_show_backupjobs.py +0 -52
- walker/commands/medusa/medusa_show_restorejobs.py +0 -52
- walker/commands/param_set.py +0 -44
- walker/commands/postgres/postgres.py +0 -113
- walker/commands/postgres/postgres_session.py +0 -225
- walker/commands/preview_table.py +0 -98
- walker/commands/processes.py +0 -53
- walker/commands/pwd.py +0 -64
- walker/commands/reaper/reaper.py +0 -78
- walker/commands/reaper/reaper_forward.py +0 -100
- walker/commands/reaper/reaper_run_abort.py +0 -65
- walker/commands/reaper/reaper_runs.py +0 -97
- walker/commands/reaper/reaper_runs_abort.py +0 -83
- walker/commands/reaper/reaper_schedule_activate.py +0 -64
- walker/commands/reaper/reaper_schedule_start.py +0 -64
- walker/commands/reaper/reaper_schedule_stop.py +0 -64
- walker/commands/reaper/reaper_session.py +0 -159
- walker/commands/repair/repair.py +0 -68
- walker/commands/repair/repair_run.py +0 -72
- walker/commands/repair/repair_scan.py +0 -79
- walker/commands/report.py +0 -57
- walker/commands/restart.py +0 -61
- walker/commands/show/show.py +0 -72
- walker/commands/show/show_app_actions.py +0 -53
- walker/commands/show/show_cassandra_status.py +0 -35
- walker/commands/show/show_commands.py +0 -58
- walker/commands/show/show_processes.py +0 -35
- walker/commands/show/show_repairs.py +0 -47
- walker/commands/status.py +0 -128
- walker/commands/storage.py +0 -52
- walker/commands/user_entry.py +0 -69
- walker/commands/watch.py +0 -85
- walker/embedded_params.py +0 -2
- walker/k8s_utils/cassandra_clusters.py +0 -48
- walker/k8s_utils/cassandra_nodes.py +0 -26
- walker/k8s_utils/pods.py +0 -211
- walker/repl.py +0 -165
- walker/repl_commands.py +0 -58
- walker/repl_state.py +0 -211
- walker/sso/authn_ad.py +0 -94
- walker/sso/idp.py +0 -150
- walker/sso/idp_login.py +0 -29
- walker/sso/sso_config.py +0 -45
- walker/utils.py +0 -194
- walker/version.py +0 -5
- {walker → adam}/checks/__init__.py +0 -0
- {walker → adam}/checks/check_context.py +0 -0
- {walker → adam}/checks/issue.py +0 -0
- {walker → adam}/cli_group.py +0 -0
- {walker → adam}/columns/__init__.py +0 -0
- {walker/commands → adam/commands/audit}/__init__.py +0 -0
- {walker/commands/frontend → adam/commands/cql}/__init__.py +0 -0
- {walker/commands/medusa → adam/commands/deploy}/__init__.py +0 -0
- {walker/commands/postgres → adam/commands/devices}/__init__.py +0 -0
- {walker/commands/reaper → adam/commands/export}/__init__.py +0 -0
- {walker/commands/repair → adam/commands/medusa}/__init__.py +0 -0
- {walker → adam}/commands/nodetool_commands.py +0 -0
- {walker/commands/show → adam/commands/postgres}/__init__.py +0 -0
- {walker/k8s_utils → adam/commands/reaper}/__init__.py +0 -0
- {walker/sso → adam/commands/repair}/__init__.py +0 -0
- /walker/medusa_show_restorejobs.py → /adam/commands/show/__init__.py +0 -0
- {walker → adam}/repl_session.py +0 -0
- {kaqing-1.77.0.dist-info → kaqing-2.0.171.dist-info}/WHEEL +0 -0
adam/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .version import __version__, __release__
|
adam/app_session.py
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import threading
|
|
3
|
+
import time
|
|
4
|
+
import traceback
|
|
5
|
+
import requests
|
|
6
|
+
from urllib.parse import urlparse
|
|
7
|
+
|
|
8
|
+
from adam.log import Log
|
|
9
|
+
from adam.repl_state import ReplState
|
|
10
|
+
from adam.sso.idp import Idp
|
|
11
|
+
from adam.sso.idp_login import IdpLogin
|
|
12
|
+
from adam.config import Config
|
|
13
|
+
from adam.utils import debug, json_to_csv, lines_to_tabular, log, log2
|
|
14
|
+
from adam.apps import Apps
|
|
15
|
+
|
|
16
|
+
class AppLogin:
|
|
17
|
+
def __init__(self, session: requests.Session, app_access_token: str, idp_uri: str, idp_login: IdpLogin = None):
|
|
18
|
+
self.session = session
|
|
19
|
+
self.app_access_token = app_access_token
|
|
20
|
+
self.idp_uri = idp_uri
|
|
21
|
+
self.idp_login = idp_login
|
|
22
|
+
|
|
23
|
+
class NoAppIngressException(Exception):
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
class AppSession:
|
|
27
|
+
sessions_by_host = {}
|
|
28
|
+
|
|
29
|
+
def __init__(self, host: str = None, env: str = None):
|
|
30
|
+
self.host = host
|
|
31
|
+
self.env = env
|
|
32
|
+
self.app_login: AppLogin = None
|
|
33
|
+
|
|
34
|
+
def create(env: str, app: str, namespace: str = None) -> 'AppSession':
|
|
35
|
+
if not(host := Apps.app_host(env, app, namespace)):
|
|
36
|
+
raise NoAppIngressException('Cannot locate ingress for app.')
|
|
37
|
+
|
|
38
|
+
key = f'{host}/{env}'
|
|
39
|
+
if key in AppSession.sessions_by_host:
|
|
40
|
+
return AppSession.sessions_by_host[key]
|
|
41
|
+
|
|
42
|
+
session = AppSession(host, env)
|
|
43
|
+
|
|
44
|
+
AppSession.sessions_by_host[key] = session
|
|
45
|
+
|
|
46
|
+
return session
|
|
47
|
+
|
|
48
|
+
def run(env: str, app: str, namespace: str, type: str, action: str, payload: any = None, forced = False):
|
|
49
|
+
app_session: AppSession = AppSession.create(env, app, namespace)
|
|
50
|
+
|
|
51
|
+
def run0(app_login: AppLogin, retried: bool):
|
|
52
|
+
if app_login:
|
|
53
|
+
with app_login.session as session:
|
|
54
|
+
uri = f'https://{app_session.host}/{env}/{app}/api/8/{type}/{action}'
|
|
55
|
+
r = session.post(uri, json=payload, headers={
|
|
56
|
+
'X-Request-Envelope': 'true'
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
if Config().is_debug():
|
|
60
|
+
log2(f'{r.status_code} {uri}')
|
|
61
|
+
log2(payload)
|
|
62
|
+
|
|
63
|
+
if r.status_code >= 200 and r.status_code < 300 or r.status_code == 400:
|
|
64
|
+
try:
|
|
65
|
+
js = r.json()
|
|
66
|
+
try:
|
|
67
|
+
header, lines = json_to_csv(js, delimiter='\t')
|
|
68
|
+
log(lines_to_tabular(lines, header=header, separator='\t'))
|
|
69
|
+
except Exception as e:
|
|
70
|
+
# traceback.print_exc(e)
|
|
71
|
+
log(js)
|
|
72
|
+
except:
|
|
73
|
+
if urlparse(r.url).hostname != urlparse(uri).hostname and not retried:
|
|
74
|
+
app_login = app_session.login(idp_uri=app_login.idp_uri, forced=forced, use_token_from_env=False, use_cached_creds=False)
|
|
75
|
+
retried = True
|
|
76
|
+
|
|
77
|
+
return run0(app_login, True)
|
|
78
|
+
|
|
79
|
+
if r.text:
|
|
80
|
+
log2(f'{r.status_code} {r.url} Failed parsing the results.')
|
|
81
|
+
debug(r.text)
|
|
82
|
+
else:
|
|
83
|
+
log2(r.status_code)
|
|
84
|
+
log2(r.text)
|
|
85
|
+
|
|
86
|
+
app_login = app_session.login(forced=forced)
|
|
87
|
+
run0(app_login, False)
|
|
88
|
+
|
|
89
|
+
def login(self, idp_uri: str = None, forced = False, use_token_from_env=True, use_cached_creds=True) -> AppLogin:
|
|
90
|
+
if not forced and self.app_login:
|
|
91
|
+
return self.app_login
|
|
92
|
+
|
|
93
|
+
idp_login: IdpLogin = Idp.login(self.host, idp_uri=idp_uri, forced=forced, use_token_from_env=use_token_from_env, use_cached_creds=use_cached_creds, verify=False)
|
|
94
|
+
if not idp_login:
|
|
95
|
+
log2(f"Invalid username/password.")
|
|
96
|
+
|
|
97
|
+
return None
|
|
98
|
+
|
|
99
|
+
if idp_login.state == 'EMPTY':
|
|
100
|
+
idp_login.state = IdpLogin.create_from_idp_uri(self.idp_redirect_url()).state
|
|
101
|
+
|
|
102
|
+
headers = {
|
|
103
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
104
|
+
}
|
|
105
|
+
form_data = {
|
|
106
|
+
'state': idp_login.state,
|
|
107
|
+
'id_token': idp_login.id_token
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
stop_event = threading.Event()
|
|
111
|
+
|
|
112
|
+
session = idp_login.session
|
|
113
|
+
if not session:
|
|
114
|
+
session = requests.Session()
|
|
115
|
+
|
|
116
|
+
def login0():
|
|
117
|
+
try:
|
|
118
|
+
# oidc/login may hang
|
|
119
|
+
timeout = Config().get('app.login.timeout', 5)
|
|
120
|
+
debug(f'-> {idp_login.app_login_url}')
|
|
121
|
+
session.post(idp_login.app_login_url, headers=headers, data=form_data, timeout=timeout)
|
|
122
|
+
except Exception:
|
|
123
|
+
pass
|
|
124
|
+
finally:
|
|
125
|
+
stop_event.set()
|
|
126
|
+
|
|
127
|
+
my_thread = threading.Thread(target=login0, daemon=True)
|
|
128
|
+
my_thread.start()
|
|
129
|
+
|
|
130
|
+
app_access_token = None
|
|
131
|
+
while not app_access_token and not stop_event.is_set():
|
|
132
|
+
time.sleep(1)
|
|
133
|
+
|
|
134
|
+
try:
|
|
135
|
+
check_uri = Config().get('app.login.session-check-url', 'https://{host}/{env}/{app}/api/8/C3/userSessionToken')
|
|
136
|
+
check_uri = check_uri.replace('{host}', self.host).replace('{env}', self.env).replace('{app}', 'c3')
|
|
137
|
+
r = session.get(check_uri)
|
|
138
|
+
debug(f'{r.status_code} {check_uri}')
|
|
139
|
+
|
|
140
|
+
res_text = r.text
|
|
141
|
+
js = json.loads(res_text)
|
|
142
|
+
if 'signedToken' not in js:
|
|
143
|
+
log2('Cannot get c3 access token, pleae re-login.')
|
|
144
|
+
break
|
|
145
|
+
|
|
146
|
+
app_access_token = js['signedToken']
|
|
147
|
+
debug(f'{r.text}')
|
|
148
|
+
|
|
149
|
+
self.app_login = AppLogin(session, app_access_token, idp_uri)
|
|
150
|
+
except Exception:
|
|
151
|
+
try:
|
|
152
|
+
need = urlparse(r.url).hostname
|
|
153
|
+
if idp_login.idp_uri:
|
|
154
|
+
idp_uri = r.url
|
|
155
|
+
has = urlparse(idp_login.idp_uri).hostname
|
|
156
|
+
msg = Config().get('app.login.another', "You're logged in to {has}. However, for this app, you need to log in to {need}.")
|
|
157
|
+
msg = msg.replace('{has}', has).replace('{need}', need)
|
|
158
|
+
log2(msg)
|
|
159
|
+
else:
|
|
160
|
+
log2(f"Invalid username/password.")
|
|
161
|
+
break
|
|
162
|
+
finally:
|
|
163
|
+
debug(traceback.format_exc())
|
|
164
|
+
|
|
165
|
+
if 'res_text' in locals():
|
|
166
|
+
Log.log_to_file(res_text)
|
|
167
|
+
|
|
168
|
+
return AppLogin(session, app_access_token, idp_uri, idp_login=idp_login)
|
|
169
|
+
|
|
170
|
+
def idp_redirect_url(self, show_endpoints = True) -> str:
|
|
171
|
+
# stgawsscpsr-c3-c3
|
|
172
|
+
uri = Config().get('app.login.url', 'https://{host}/{env}/{app}')
|
|
173
|
+
uri = uri.replace('{host}', self.host).replace('{env}', self.env).replace('{app}', 'c3')
|
|
174
|
+
r = requests.get(uri)
|
|
175
|
+
|
|
176
|
+
parsed_url = urlparse(r.url)
|
|
177
|
+
if show_endpoints:
|
|
178
|
+
log2(f'{r.status_code} {uri} <-> {parsed_url.hostname}...')
|
|
179
|
+
if r.status_code < 200 or r.status_code > 299:
|
|
180
|
+
return None
|
|
181
|
+
|
|
182
|
+
return r.url
|
{walker → adam}/apps.py
RENAMED
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
import copy
|
|
2
2
|
import functools
|
|
3
|
-
import importlib
|
|
4
|
-
import os
|
|
5
|
-
from pathlib import Path
|
|
6
3
|
import re
|
|
7
4
|
from typing import cast
|
|
8
5
|
import yaml
|
|
9
6
|
|
|
10
|
-
from
|
|
11
|
-
from
|
|
7
|
+
from adam.config import Config
|
|
8
|
+
from adam.utils_k8s.ingresses import Ingresses
|
|
12
9
|
|
|
13
10
|
from . import __version__
|
|
14
|
-
from
|
|
15
|
-
from
|
|
11
|
+
from adam.utils_k8s.services import Services
|
|
12
|
+
from adam.utils import copy_config_file
|
|
16
13
|
|
|
17
14
|
class AppAction:
|
|
18
15
|
def __init__(self, name: str, payload: str = None, args: dict[str, str] = None, help: str = None):
|
|
@@ -135,24 +132,11 @@ class Apps:
|
|
|
135
132
|
with open(path) as f:
|
|
136
133
|
self.actions = cast(dict[str, any], yaml.safe_load(f))
|
|
137
134
|
except:
|
|
138
|
-
|
|
135
|
+
with open(copy_config_file(f'apps.yaml.{__version__}', 'adam.embedded_apps')) as f:
|
|
136
|
+
self.actions = cast(dict[str, any], yaml.safe_load(f))
|
|
139
137
|
elif not hasattr(self, 'actions'):
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
def copy_apps_file(self):
|
|
143
|
-
dir = f'{Path.home()}/.kaqing'
|
|
144
|
-
path = f'{dir}/apps.yaml.{__version__}'
|
|
145
|
-
if not os.path.exists(path):
|
|
146
|
-
os.makedirs(dir, exist_ok=True)
|
|
147
|
-
module = importlib.import_module('walker.embedded_apps')
|
|
148
|
-
with open(path, 'w') as f:
|
|
149
|
-
yaml.dump(module.apps(), f, default_flow_style=False)
|
|
150
|
-
log2(f'Default apps.yaml has been written to {path}.')
|
|
151
|
-
|
|
152
|
-
with open(path) as f:
|
|
153
|
-
self.actions = cast(dict[str, any], yaml.safe_load(f))
|
|
154
|
-
|
|
155
|
-
return path
|
|
138
|
+
with open(copy_config_file(f'apps.yaml.{__version__}', 'adam.embedded_apps')) as f:
|
|
139
|
+
self.actions = cast(dict[str, any], yaml.safe_load(f))
|
|
156
140
|
|
|
157
141
|
def app_types(self) -> list[AppType]:
|
|
158
142
|
return AppType.create(self.actions)
|
{walker → adam}/batch.py
RENAMED
|
@@ -1,36 +1,42 @@
|
|
|
1
1
|
import click
|
|
2
2
|
|
|
3
|
-
from
|
|
4
|
-
from
|
|
5
|
-
from
|
|
6
|
-
from
|
|
7
|
-
from
|
|
8
|
-
from
|
|
9
|
-
from
|
|
10
|
-
from
|
|
11
|
-
from
|
|
12
|
-
from
|
|
13
|
-
from
|
|
14
|
-
from
|
|
15
|
-
from
|
|
16
|
-
from
|
|
17
|
-
from
|
|
18
|
-
from
|
|
19
|
-
from
|
|
20
|
-
from
|
|
21
|
-
from
|
|
22
|
-
from
|
|
23
|
-
from
|
|
24
|
-
from
|
|
25
|
-
from
|
|
26
|
-
from
|
|
27
|
-
from
|
|
28
|
-
from
|
|
29
|
-
from
|
|
30
|
-
from
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
3
|
+
from adam.commands.audit.audit import Audit, AuditCommandHelper
|
|
4
|
+
from adam.commands.bash.bash import Bash
|
|
5
|
+
from adam.commands.check import Check, CheckCommandHelper
|
|
6
|
+
from adam.commands.cp import ClipboardCopy, CopyCommandHelper
|
|
7
|
+
from adam.commands.command import Command
|
|
8
|
+
from adam.commands.command_helpers import ClusterCommandHelper, ClusterOrPodCommandHelper, PodCommandHelper
|
|
9
|
+
from adam.commands.cql.cqlsh import CqlCommandHelper, Cqlsh
|
|
10
|
+
from adam.commands.deploy.deploy import Deploy, DeployCommandHelper
|
|
11
|
+
from adam.commands.deploy.undeploy import Undeploy, UndeployCommandHelper
|
|
12
|
+
from adam.commands.issues import Issues
|
|
13
|
+
from adam.commands.login import Login
|
|
14
|
+
from adam.commands.logs import Logs
|
|
15
|
+
from adam.commands.ls import Ls
|
|
16
|
+
from adam.commands.medusa.medusa import Medusa
|
|
17
|
+
from adam.commands.nodetool import NodeTool, NodeToolCommandHelper
|
|
18
|
+
from adam.commands.postgres.postgres import Postgres, PostgresCommandHelper
|
|
19
|
+
from adam.commands.preview_table import PreviewTable
|
|
20
|
+
from adam.commands.reaper.reaper import Reaper, ReaperCommandHelper
|
|
21
|
+
from adam.commands.repair.repair import Repair, RepairCommandHelper
|
|
22
|
+
from adam.commands.report import Report
|
|
23
|
+
from adam.commands.restart import Restart
|
|
24
|
+
from adam.commands.rollout import RollOut
|
|
25
|
+
from adam.commands.show.show import Show, ShowCommandHelper
|
|
26
|
+
from adam.commands.watch import Watch
|
|
27
|
+
from adam.utils_k8s.kube_context import KubeContext
|
|
28
|
+
from adam.repl import enter_repl
|
|
29
|
+
from adam.repl_state import ReplState
|
|
30
|
+
from adam.cli_group import cli
|
|
31
|
+
|
|
32
|
+
@cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=AuditCommandHelper, help='Run audit functions.')
|
|
33
|
+
@click.option('--kubeconfig', '-k', required=False, metavar='path', help='path to kubeconfig file')
|
|
34
|
+
@click.option('--config', default='params.yaml', metavar='path', help='path to kaqing parameters file')
|
|
35
|
+
@click.option('--param', '-v', multiple=True, metavar='<key>=<value>', help='parameter override')
|
|
36
|
+
@click.argument('extra_args', nargs=-1, metavar='repair', type=click.UNPROCESSED)
|
|
37
|
+
def audit(kubeconfig: str, config: str, param: list[str], extra_args):
|
|
38
|
+
run_command(Audit(), kubeconfig, config, param, None, None, None, extra_args, device=ReplState.L)
|
|
39
|
+
|
|
34
40
|
|
|
35
41
|
@cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=ClusterOrPodCommandHelper, help='Run a single bash command.')
|
|
36
42
|
@click.option('--kubeconfig', '-k', required=False, metavar='path', help='path to kubeconfig file')
|
|
@@ -80,6 +86,16 @@ def cql(kubeconfig: str, config: str, param: list[str], cluster: str, namespace:
|
|
|
80
86
|
run_command(Cqlsh(), kubeconfig, config, param, cluster, namespace, pod, extra_args)
|
|
81
87
|
|
|
82
88
|
|
|
89
|
+
@cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=DeployCommandHelper, help='Setup.')
|
|
90
|
+
@click.option('--kubeconfig', '-k', required=False, metavar='path', help='path to kubeconfig file')
|
|
91
|
+
@click.option('--config', default='params.yaml', metavar='path', help='path to kaqing parameters file')
|
|
92
|
+
@click.option('--param', '-v', multiple=True, metavar='<key>=<value>', help='parameter override')
|
|
93
|
+
@click.option('--namespace', '-n', required=False, metavar='namespace', help='Kubernetes namespace')
|
|
94
|
+
@click.argument('extra_args', nargs=-1, metavar='<pod>', type=click.UNPROCESSED)
|
|
95
|
+
def deploy(kubeconfig: str, config: str, param: list[str], namespace: str, extra_args):
|
|
96
|
+
run_command(Deploy(), kubeconfig, config, param, None, namespace, None, extra_args)
|
|
97
|
+
|
|
98
|
+
|
|
83
99
|
@cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=ClusterOrPodCommandHelper, help="Print Qing's issues.")
|
|
84
100
|
@click.option('--kubeconfig', '-k', required=False, metavar='path', help='path to kubeconfig file')
|
|
85
101
|
@click.option('--config', default='params.yaml', metavar='path', help='path to kaqing parameters file')
|
|
@@ -93,7 +109,7 @@ def issues(kubeconfig: str, config: str, param: list[str], cluster: str, namespa
|
|
|
93
109
|
run_command(Issues(), kubeconfig, config, param, cluster, namespace, pod, ('-s',) + extra_args if show else extra_args)
|
|
94
110
|
|
|
95
111
|
|
|
96
|
-
@cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=PodCommandHelper, help='
|
|
112
|
+
@cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=PodCommandHelper, help='SSO login.')
|
|
97
113
|
@click.option('--kubeconfig', '-k', required=False, metavar='path', help='path to kubeconfig file')
|
|
98
114
|
@click.option('--config', default='params.yaml', metavar='path', help='path to kaqing parameters file')
|
|
99
115
|
@click.option('--param', '-v', multiple=True, metavar='<key>=<value>', help='parameter override')
|
|
@@ -173,19 +189,6 @@ def preview(kubeconfig: str, config: str, param: list[str], cluster: str, namesp
|
|
|
173
189
|
run_command(PreviewTable(), kubeconfig, config, param, cluster, namespace, pod, extra_args)
|
|
174
190
|
|
|
175
191
|
|
|
176
|
-
@cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=ClusterOrPodCommandHelper, help='Show process overview from Cassandra nodes.')
|
|
177
|
-
@click.option('--kubeconfig', '-k', required=False, metavar='path', help='path to kubeconfig file')
|
|
178
|
-
@click.option('--config', default='params.yaml', metavar='path', help='path to kaqing parameters file')
|
|
179
|
-
@click.option('--param', '-v', multiple=True, metavar='<key>=<value>', help='parameter override')
|
|
180
|
-
@click.option('--cluster', '-c', required=False, metavar='statefulset', help='Kubernetes statefulset name')
|
|
181
|
-
@click.option('--namespace', '-n', required=False, metavar='namespace', help='Kubernetes namespace')
|
|
182
|
-
@click.option('--pod', '-p', required=False, metavar='pod', help='Kubernetes pod name')
|
|
183
|
-
@click.option('--show', '-s', is_flag=True, help='show output from Cassandra nodes')
|
|
184
|
-
@click.argument('extra_args', nargs=-1, metavar='<cluster|pod>', type=click.UNPROCESSED)
|
|
185
|
-
def processes(kubeconfig: str, config: str, param: list[str], cluster: str, namespace: str, pod: str, show: bool, extra_args):
|
|
186
|
-
run_command(Processes(), kubeconfig, config, param, cluster, namespace, pod, ('-s',) + extra_args if show else extra_args)
|
|
187
|
-
|
|
188
|
-
|
|
189
192
|
@cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=ReaperCommandHelper, help='Execute Cassandra Reaper operations.')
|
|
190
193
|
@click.option('--kubeconfig', '-k', required=False, metavar='path', help='path to kubeconfig file')
|
|
191
194
|
@click.option('--config', default='params.yaml', metavar='path', help='path to kaqing parameters file')
|
|
@@ -245,16 +248,6 @@ def rollout(kubeconfig: str, config: str, param: list[str], cluster: str, namesp
|
|
|
245
248
|
run_command(RollOut(), kubeconfig, config, param, cluster, namespace, None, extra_args)
|
|
246
249
|
|
|
247
250
|
|
|
248
|
-
@cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=SetupCommandHelper, help='Setup.')
|
|
249
|
-
@click.option('--kubeconfig', '-k', required=False, metavar='path', help='path to kubeconfig file')
|
|
250
|
-
@click.option('--config', default='params.yaml', metavar='path', help='path to kaqing parameters file')
|
|
251
|
-
@click.option('--param', '-v', multiple=True, metavar='<key>=<value>', help='parameter override')
|
|
252
|
-
@click.option('--namespace', '-n', required=False, metavar='namespace', help='Kubernetes namespace')
|
|
253
|
-
@click.argument('extra_args', nargs=-1, metavar='<pod>', type=click.UNPROCESSED)
|
|
254
|
-
def setup(kubeconfig: str, config: str, param: list[str], namespace: str, extra_args):
|
|
255
|
-
run_command(Setup(), kubeconfig, config, param, None, namespace, None, extra_args)
|
|
256
|
-
|
|
257
|
-
|
|
258
251
|
@cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=ShowCommandHelper, help='Show configuration or kubectl commands.')
|
|
259
252
|
@click.option('--kubeconfig', '-k', required=False, metavar='path', help='path to kubeconfig file')
|
|
260
253
|
@click.option('--config', default='params.yaml', metavar='path', help='path to kaqing parameters file')
|
|
@@ -267,50 +260,14 @@ def show(kubeconfig: str, config: str, param: list[str], cluster: str, namespace
|
|
|
267
260
|
run_command(Show(), kubeconfig, config, param, cluster, namespace, pod, extra_args)
|
|
268
261
|
|
|
269
262
|
|
|
270
|
-
@cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=
|
|
271
|
-
@click.option('--kubeconfig', '-k', required=False, metavar='path', help='path to kubeconfig file')
|
|
272
|
-
@click.option('--config', default='params.yaml', metavar='path', help='path to kaqing parameters file')
|
|
273
|
-
@click.option('--param', '-v', multiple=True, metavar='<key>=<value>', help='parameter override')
|
|
274
|
-
@click.option('--cluster', '-c', required=False, metavar='statefulset', help='Kubernetes statefulset name')
|
|
275
|
-
@click.option('--namespace', '-n', required=False, metavar='namespace', help='Kubernetes namespace')
|
|
276
|
-
@click.option('--pod', '-p', required=False, metavar='pod', help='Kubernetes pod name')
|
|
277
|
-
@click.option('--show', '-s', is_flag=True, help='show output from Cassandra nodes')
|
|
278
|
-
@click.argument('extra_args', nargs=-1, metavar='<cluster|pod>', type=click.UNPROCESSED)
|
|
279
|
-
def status(kubeconfig: str, config: str, param: list[str], cluster: str, namespace: str, pod: str, show: bool, extra_args):
|
|
280
|
-
run_command(StatusCmd(), kubeconfig, config, param, cluster, namespace, pod, ('-s',) + extra_args if show else extra_args)
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
@cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=ClusterOrPodCommandHelper, help='Show storage overview from Cassandra nodes.')
|
|
284
|
-
@click.option('--kubeconfig', '-k', required=False, metavar='path', help='path to kubeconfig file')
|
|
285
|
-
@click.option('--config', default='params.yaml', metavar='path', help='path to kaqing parameters file')
|
|
286
|
-
@click.option('--param', '-v', multiple=True, metavar='<key>=<value>', help='parameter override')
|
|
287
|
-
@click.option('--cluster', '-c', required=False, metavar='statefulset', help='Kubernetes statefulset name')
|
|
288
|
-
@click.option('--namespace', '-n', required=False, metavar='namespace', help='Kubernetes namespace')
|
|
289
|
-
@click.option('--pod', '-p', required=False, metavar='pod', help='Kubernetes pod name')
|
|
290
|
-
@click.option('--show', '-s', is_flag=True, help='show output from Cassandra nodes')
|
|
291
|
-
@click.argument('extra_args', nargs=-1, metavar='<cluster|pod>', type=click.UNPROCESSED)
|
|
292
|
-
def storage(kubeconfig: str, config: str, param: list[str], cluster: str, namespace: str, pod: str, show: bool, extra_args):
|
|
293
|
-
run_command(Storage(), kubeconfig, config, param, cluster, namespace, pod, ('-s',) + extra_args if show else extra_args)
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
@cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=TearDownCommandHelper, help='Teardown.')
|
|
297
|
-
@click.option('--kubeconfig', '-k', required=False, metavar='path', help='path to kubeconfig file')
|
|
298
|
-
@click.option('--config', default='params.yaml', metavar='path', help='path to kaqing parameters file')
|
|
299
|
-
@click.option('--param', '-v', multiple=True, metavar='<key>=<value>', help='parameter override')
|
|
300
|
-
@click.option('--namespace', '-n', required=False, metavar='namespace', help='Kubernetes namespace')
|
|
301
|
-
@click.argument('extra_args', nargs=-1, metavar='<pod>', type=click.UNPROCESSED)
|
|
302
|
-
def teardown(kubeconfig: str, config: str, param: list[str], namespace: str, extra_args):
|
|
303
|
-
run_command(TearDown(), kubeconfig, config, param, None, namespace, None, extra_args)
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
@cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=PodCommandHelper, help='Get cassandra log.')
|
|
263
|
+
@cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=UndeployCommandHelper, help='Undeploy.')
|
|
307
264
|
@click.option('--kubeconfig', '-k', required=False, metavar='path', help='path to kubeconfig file')
|
|
308
265
|
@click.option('--config', default='params.yaml', metavar='path', help='path to kaqing parameters file')
|
|
309
266
|
@click.option('--param', '-v', multiple=True, metavar='<key>=<value>', help='parameter override')
|
|
310
267
|
@click.option('--namespace', '-n', required=False, metavar='namespace', help='Kubernetes namespace')
|
|
311
268
|
@click.argument('extra_args', nargs=-1, metavar='<pod>', type=click.UNPROCESSED)
|
|
312
|
-
def
|
|
313
|
-
run_command(
|
|
269
|
+
def undeploy(kubeconfig: str, config: str, param: list[str], namespace: str, extra_args):
|
|
270
|
+
run_command(Undeploy(), kubeconfig, config, param, None, namespace, None, extra_args)
|
|
314
271
|
|
|
315
272
|
|
|
316
273
|
@cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=ClusterOrPodCommandHelper, help='Watch pods in cluster.')
|
|
@@ -324,14 +281,14 @@ def watch(kubeconfig: str, config: str, param: list[str], cluster: str, namespac
|
|
|
324
281
|
run_command(Watch(), kubeconfig, config, param, cluster, namespace, None, extra_args)
|
|
325
282
|
|
|
326
283
|
|
|
327
|
-
def run_command(cmd: Command, kubeconfig: str, config: str, params: list[str], cluster:str, namespace: str, pod: str, extra_args):
|
|
328
|
-
is_user_entry =
|
|
284
|
+
def run_command(cmd: Command, kubeconfig: str, config: str, params: list[str], cluster:str, namespace: str, pod: str, extra_args, device=ReplState.C):
|
|
285
|
+
is_user_entry = False
|
|
329
286
|
|
|
330
287
|
KubeContext.init_config(kubeconfig, is_user_entry=is_user_entry)
|
|
331
288
|
if not KubeContext.init_params(config, params, is_user_entry=is_user_entry):
|
|
332
289
|
return
|
|
333
290
|
|
|
334
|
-
state = ReplState(ns_sts=cluster, pod=pod, namespace=namespace)
|
|
291
|
+
state = ReplState(device=device, ns_sts=cluster, pod=pod, namespace=namespace)
|
|
335
292
|
if cmd.command() == 'pg' and not extra_args:
|
|
336
293
|
state, _ = state.apply_args(extra_args)
|
|
337
294
|
state.device = ReplState.P
|
{walker → adam}/checks/check.py
RENAMED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
from abc import abstractmethod
|
|
2
2
|
|
|
3
|
-
from
|
|
4
|
-
from
|
|
5
|
-
from
|
|
3
|
+
from adam.checks.check_context import CheckContext
|
|
4
|
+
from adam.checks.check_result import CheckResult
|
|
5
|
+
from adam.checks.issue import Issue
|
|
6
6
|
|
|
7
7
|
class Check:
|
|
8
8
|
"""Abstract base class for checks"""
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
from adam.checks.check import Check
|
|
2
|
+
from adam.checks.check_context import CheckContext
|
|
3
|
+
from adam.checks.check_result import CheckResult
|
|
4
|
+
from adam.checks.compactionstats import CompactionStats
|
|
5
|
+
from adam.checks.cpu import Cpu
|
|
6
|
+
from adam.checks.disk import Disk
|
|
7
|
+
from adam.checks.gossip import Gossip
|
|
8
|
+
from adam.checks.issue import Issue
|
|
9
|
+
from adam.checks.memory import Memory
|
|
10
|
+
from adam.checks.status import Status
|
|
11
|
+
from adam.config import Config
|
|
12
|
+
from adam.utils_k8s.cassandra_nodes import CassandraNodes
|
|
13
|
+
from adam.utils_k8s.secrets import Secrets
|
|
14
|
+
from adam.utils_k8s.statefulsets import StatefulSets
|
|
15
|
+
from adam.utils import parallelize, log2
|
|
16
|
+
|
|
17
|
+
def all_checks() -> list[Check]:
|
|
18
|
+
return [CompactionStats(), Cpu(), Gossip(), Memory(), Disk(), Status()]
|
|
19
|
+
|
|
20
|
+
def checks_from_csv(check_str: str):
|
|
21
|
+
checks: list[Check] = []
|
|
22
|
+
|
|
23
|
+
checks_by_name = {c.name(): c for c in all_checks()}
|
|
24
|
+
|
|
25
|
+
if check_str:
|
|
26
|
+
for check_name in check_str.strip(' ').split(','):
|
|
27
|
+
if check_name in checks_by_name:
|
|
28
|
+
checks.append(checks_by_name[check_name])
|
|
29
|
+
else:
|
|
30
|
+
log2(f'Invalid check name: {check_name}.')
|
|
31
|
+
|
|
32
|
+
return None
|
|
33
|
+
|
|
34
|
+
return checks
|
|
35
|
+
|
|
36
|
+
def run_checks(cluster: str = None, namespace: str = None, pod: str = None, checks: list[Check] = None, show_out=True):
|
|
37
|
+
if not checks:
|
|
38
|
+
checks = all_checks()
|
|
39
|
+
|
|
40
|
+
sts_ns: list[tuple[str, str]] = StatefulSets.list_sts_name_and_ns()
|
|
41
|
+
|
|
42
|
+
sts_ns_pods: list[tuple[str, str, str]] = []
|
|
43
|
+
for sts, ns in sts_ns:
|
|
44
|
+
if (not cluster or cluster == sts) and (not namespace or namespace == ns):
|
|
45
|
+
pods = StatefulSets.pods(sts, ns)
|
|
46
|
+
for pod_name in [pod.metadata.name for pod in pods]:
|
|
47
|
+
if not pod or pod == pod_name:
|
|
48
|
+
sts_ns_pods.append((sts, ns, pod_name))
|
|
49
|
+
|
|
50
|
+
with parallelize(sts_ns_pods, Config().action_workers('issues', 30), msg='d`Running|Ran checks on {size} pods') as exec:
|
|
51
|
+
return exec.map(lambda sts_ns_pod: run_checks_on_pod(checks, sts_ns_pod[0], sts_ns_pod[1], sts_ns_pod[2], show_out))
|
|
52
|
+
|
|
53
|
+
def run_checks_on_pod(checks: list[Check], cluster: str = None, namespace: str = None, pod: str = None, show_out=True):
|
|
54
|
+
host_id = CassandraNodes.get_host_id(pod, namespace)
|
|
55
|
+
user, pw = Secrets.get_user_pass(pod, namespace)
|
|
56
|
+
results = {}
|
|
57
|
+
issues: list[Issue] = []
|
|
58
|
+
for c in checks:
|
|
59
|
+
check_results = c.check(CheckContext(cluster, host_id, pod, namespace, user, pw, show_output=show_out))
|
|
60
|
+
if check_results.details:
|
|
61
|
+
results = results | {check_results.name: check_results.details}
|
|
62
|
+
if check_results.issues:
|
|
63
|
+
issues.extend(check_results.issues)
|
|
64
|
+
|
|
65
|
+
return CheckResult(None, results, issues)
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import re
|
|
2
2
|
|
|
3
|
-
from
|
|
4
|
-
from
|
|
5
|
-
from
|
|
6
|
-
from
|
|
7
|
-
from
|
|
8
|
-
from
|
|
3
|
+
from adam.checks.check import Check
|
|
4
|
+
from adam.checks.check_context import CheckContext
|
|
5
|
+
from adam.checks.check_result import CheckResult
|
|
6
|
+
from adam.checks.issue import Issue
|
|
7
|
+
from adam.config import Config
|
|
8
|
+
from adam.utils_k8s.cassandra_nodes import CassandraNodes
|
|
9
9
|
|
|
10
10
|
class CompactionStats(Check):
|
|
11
11
|
def name(self):
|
{walker → adam}/checks/cpu.py
RENAMED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
from kubernetes.utils import parse_quantity
|
|
2
2
|
|
|
3
|
-
from
|
|
4
|
-
from
|
|
5
|
-
from
|
|
6
|
-
from
|
|
7
|
-
from
|
|
8
|
-
from
|
|
9
|
-
from
|
|
3
|
+
from adam.checks.check import Check
|
|
4
|
+
from adam.checks.check_context import CheckContext
|
|
5
|
+
from adam.checks.check_result import CheckResult
|
|
6
|
+
from adam.checks.issue import Issue
|
|
7
|
+
from adam.config import Config
|
|
8
|
+
from adam.utils_k8s.cassandra_nodes import CassandraNodes
|
|
9
|
+
from adam.utils_k8s.custom_resources import CustomResources
|
|
10
|
+
from adam.utils_k8s.pods import Pods
|
|
10
11
|
|
|
11
12
|
class Cpu(Check):
|
|
12
13
|
def name(self):
|
|
@@ -20,10 +21,15 @@ class Cpu(Check):
|
|
|
20
21
|
'namespace': ctx.namespace,
|
|
21
22
|
'statefulset': ctx.statefulset,
|
|
22
23
|
'cpu': 'Unknown',
|
|
23
|
-
'idle': 'Unknown'
|
|
24
|
+
'idle': 'Unknown',
|
|
25
|
+
'limit': 'NA'
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
try:
|
|
29
|
+
container = Pods.get_container(ctx.namespace, ctx.pod, container_name='cassandra')
|
|
30
|
+
if container.resources.limits and "cpu" in container.resources.limits:
|
|
31
|
+
details['limit'] = container.resources.limits["cpu"]
|
|
32
|
+
|
|
27
33
|
idle = 'Unknown'
|
|
28
34
|
result = CassandraNodes.exec(ctx.pod, ctx.namespace, "mpstat 5 2 | grep Average | awk '{print $NF}'", show_out=ctx.show_output)
|
|
29
35
|
lines = result.stdout.strip(' \r\n').split('\n')
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from kubernetes.utils import parse_quantity
|
|
2
|
+
|
|
3
|
+
from adam.checks.check import Check
|
|
4
|
+
from adam.checks.check_context import CheckContext
|
|
5
|
+
from adam.checks.check_result import CheckResult
|
|
6
|
+
from adam.checks.issue import Issue
|
|
7
|
+
from adam.config import Config
|
|
8
|
+
from adam.utils_k8s.custom_resources import CustomResources
|
|
9
|
+
from adam.utils_k8s.pods import Pods
|
|
10
|
+
|
|
11
|
+
class CpuMetrics(Check):
|
|
12
|
+
def name(self):
|
|
13
|
+
return 'cpu-metrics'
|
|
14
|
+
|
|
15
|
+
def check(self, ctx: CheckContext) -> CheckResult:
|
|
16
|
+
issues: list[Issue] = []
|
|
17
|
+
|
|
18
|
+
details = {
|
|
19
|
+
'name': ctx.pod,
|
|
20
|
+
'namespace': ctx.namespace,
|
|
21
|
+
'statefulset': ctx.statefulset,
|
|
22
|
+
'cpu': 'Unknown',
|
|
23
|
+
'limit': 'NA'
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
try:
|
|
27
|
+
container = Pods.get_container(ctx.namespace, ctx.pod, container_name='cassandra')
|
|
28
|
+
if container.resources.limits and "cpu" in container.resources.limits:
|
|
29
|
+
details['limit'] = container.resources.limits["cpu"]
|
|
30
|
+
|
|
31
|
+
metrics = CustomResources.get_metrics(ctx.namespace, ctx.pod, container_name='cassandra')
|
|
32
|
+
usage = 'Unknown'
|
|
33
|
+
if metrics:
|
|
34
|
+
usage = details['cpu'] = metrics["usage"]["cpu"]
|
|
35
|
+
|
|
36
|
+
cpu_threshold = Config().get('checks.cpu-threshold', 0.0)
|
|
37
|
+
if cpu_threshold != 0.0 and usage != "Unknown" and parse_quantity(usage) > cpu_threshold:
|
|
38
|
+
issues.append(Issue(
|
|
39
|
+
statefulset=ctx.statefulset,
|
|
40
|
+
namespace=ctx.namespace,
|
|
41
|
+
pod=ctx.pod,
|
|
42
|
+
category='cpu',
|
|
43
|
+
desc=f'CPU is too busy: {usage}',
|
|
44
|
+
suggestion=f"qing restart {ctx.pod}@{ctx.namespace}"
|
|
45
|
+
))
|
|
46
|
+
except Exception as e:
|
|
47
|
+
issues.append(self.issue_from_err(sts_name=ctx.statefulset, ns=ctx.namespace, pod_name=ctx.pod, exception=e))
|
|
48
|
+
|
|
49
|
+
return CheckResult(self.name(), details, issues)
|
|
50
|
+
|
|
51
|
+
def help(self):
|
|
52
|
+
return f'{CpuMetrics().name()}: check cpu busy percentage with metrics'
|