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
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import requests
|
|
2
|
-
|
|
3
|
-
from walker.commands.command import Command
|
|
4
|
-
from .reaper_session import ReaperSession
|
|
5
|
-
from walker.config import Config
|
|
6
|
-
from walker.repl_state import ReplState, RequiredState
|
|
7
|
-
from walker.utils import convert_seconds, epoch, lines_to_tabular, log, log2
|
|
8
|
-
|
|
9
|
-
class ReaperRuns(Command):
|
|
10
|
-
COMMAND = 'reaper show runs'
|
|
11
|
-
reaper_login = None
|
|
12
|
-
|
|
13
|
-
# the singleton pattern
|
|
14
|
-
def __new__(cls, *args, **kwargs):
|
|
15
|
-
if not hasattr(cls, 'instance'): cls.instance = super(ReaperRuns, cls).__new__(cls)
|
|
16
|
-
|
|
17
|
-
return cls.instance
|
|
18
|
-
|
|
19
|
-
def __init__(self, successor: Command=None):
|
|
20
|
-
super().__init__(successor)
|
|
21
|
-
|
|
22
|
-
def command(self):
|
|
23
|
-
return ReaperRuns.COMMAND
|
|
24
|
-
|
|
25
|
-
def required(self):
|
|
26
|
-
return RequiredState.CLUSTER
|
|
27
|
-
|
|
28
|
-
def run(self, cmd: str, state: ReplState):
|
|
29
|
-
if not(args := self.args(cmd)):
|
|
30
|
-
return super().run(cmd, state)
|
|
31
|
-
|
|
32
|
-
state, args = self.apply_state(args, state)
|
|
33
|
-
if not self.validate_state(state):
|
|
34
|
-
return state
|
|
35
|
-
|
|
36
|
-
if not(reaper := ReaperSession.create(state)):
|
|
37
|
-
return state
|
|
38
|
-
|
|
39
|
-
self.show_runs(state, reaper)
|
|
40
|
-
|
|
41
|
-
return state
|
|
42
|
-
|
|
43
|
-
def show_runs(self, state: ReplState, reaper: ReaperSession):
|
|
44
|
-
def body(uri: str, headers: dict[str, str]):
|
|
45
|
-
return requests.get(uri, headers=headers, params={
|
|
46
|
-
'cluster_name': 'all',
|
|
47
|
-
'limit': Config().get('reaper.show-runs-batch', 10)
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
def line(run):
|
|
51
|
-
state = run['state']
|
|
52
|
-
start_time = run['start_time']
|
|
53
|
-
end_time = run['end_time']
|
|
54
|
-
duration = '-'
|
|
55
|
-
if state == 'DONE' and end_time:
|
|
56
|
-
hours, minutes, seconds = convert_seconds(epoch(end_time) - epoch(start_time))
|
|
57
|
-
if hours:
|
|
58
|
-
duration = f"{hours:2d}h {minutes:2d}m {seconds:2d}s"
|
|
59
|
-
elif minutes:
|
|
60
|
-
duration = f"{minutes:2d}m {seconds:2d}s"
|
|
61
|
-
else:
|
|
62
|
-
duration = f"{seconds:2d}s"
|
|
63
|
-
|
|
64
|
-
return f"{start_time},{duration},{state},{run['cluster_name']},{run['keyspace_name']},{len(run['column_families'])},{run['segments_repaired']}/{run['total_segments']}"
|
|
65
|
-
|
|
66
|
-
# PAUSED, RUNNING, ABORTED
|
|
67
|
-
response = reaper.port_forwarded(state, 'repair_run?state=RUNNING', body, method='GET')
|
|
68
|
-
if not response:
|
|
69
|
-
return
|
|
70
|
-
|
|
71
|
-
header = 'Start,Duration,State,Cluster,Keyspace,Tables,Repaired'
|
|
72
|
-
|
|
73
|
-
runs = response.json()
|
|
74
|
-
if runs:
|
|
75
|
-
log(lines_to_tabular(sorted([line(run) for run in runs], reverse=True), header, separator=","))
|
|
76
|
-
else:
|
|
77
|
-
log2('No running runs found.')
|
|
78
|
-
log2()
|
|
79
|
-
|
|
80
|
-
response = reaper.port_forwarded(state, 'repair_run?state=PAUSED,ABORTED,DONE', body, method='GET')
|
|
81
|
-
if not response:
|
|
82
|
-
return
|
|
83
|
-
|
|
84
|
-
runs = response.json()
|
|
85
|
-
if runs:
|
|
86
|
-
log(lines_to_tabular(sorted([line(run) for run in runs], reverse=True), header, separator=","))
|
|
87
|
-
else:
|
|
88
|
-
log2('No runs found.')
|
|
89
|
-
|
|
90
|
-
def completion(self, state: ReplState):
|
|
91
|
-
if state.sts:
|
|
92
|
-
return super().completion(state)
|
|
93
|
-
|
|
94
|
-
return {}
|
|
95
|
-
|
|
96
|
-
def help(self, _: ReplState):
|
|
97
|
-
return f'{ReaperRuns.COMMAND}\t show reaper runs'
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import requests
|
|
2
|
-
|
|
3
|
-
from walker.commands.command import Command
|
|
4
|
-
from .reaper_session import ReaperSession
|
|
5
|
-
from walker.config import Config
|
|
6
|
-
from walker.repl_state import ReplState, RequiredState
|
|
7
|
-
from walker.utils import log2
|
|
8
|
-
|
|
9
|
-
class ReaperRunsAbort(Command):
|
|
10
|
-
COMMAND = 'reaper abort runs'
|
|
11
|
-
reaper_login = None
|
|
12
|
-
|
|
13
|
-
# the singleton pattern
|
|
14
|
-
def __new__(cls, *args, **kwargs):
|
|
15
|
-
if not hasattr(cls, 'instance'): cls.instance = super(ReaperRunsAbort, cls).__new__(cls)
|
|
16
|
-
|
|
17
|
-
return cls.instance
|
|
18
|
-
|
|
19
|
-
def __init__(self, successor: Command=None):
|
|
20
|
-
super().__init__(successor)
|
|
21
|
-
|
|
22
|
-
def command(self):
|
|
23
|
-
return ReaperRunsAbort.COMMAND
|
|
24
|
-
|
|
25
|
-
def required(self):
|
|
26
|
-
return RequiredState.CLUSTER
|
|
27
|
-
|
|
28
|
-
def run(self, cmd: str, state: ReplState):
|
|
29
|
-
if not(args := self.args(cmd)):
|
|
30
|
-
return super().run(cmd, state)
|
|
31
|
-
|
|
32
|
-
state, args = self.apply_state(args, state)
|
|
33
|
-
if not self.validate_state(state):
|
|
34
|
-
return state
|
|
35
|
-
|
|
36
|
-
if not(reaper := ReaperSession.create(state)):
|
|
37
|
-
return state
|
|
38
|
-
|
|
39
|
-
self.stop_runs(state, reaper)
|
|
40
|
-
|
|
41
|
-
return state
|
|
42
|
-
|
|
43
|
-
def stop_runs(self, state: ReplState, reaper: ReaperSession):
|
|
44
|
-
def body_list(uri: str, headers: dict[str, str]):
|
|
45
|
-
return requests.get(uri, headers=headers, params={
|
|
46
|
-
'cluster_name': 'all',
|
|
47
|
-
'limit': Config().get('reaper.abort-runs-batch', 10)
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
def body_abort(uri: str, headers: dict[str, str]):
|
|
51
|
-
return requests.put(uri, headers=headers)
|
|
52
|
-
|
|
53
|
-
# PAUSED, RUNNING, ABORTED
|
|
54
|
-
aborted = 0
|
|
55
|
-
while True == True:
|
|
56
|
-
response = reaper.port_forwarded(state, 'repair_run?state=RUNNING', body_list, method='GET')
|
|
57
|
-
if not response:
|
|
58
|
-
break
|
|
59
|
-
|
|
60
|
-
runs = response.json()
|
|
61
|
-
if not runs:
|
|
62
|
-
break
|
|
63
|
-
|
|
64
|
-
for run in runs:
|
|
65
|
-
run_id = run['id']
|
|
66
|
-
# PUT /repair_run/{id}/state/{state}
|
|
67
|
-
reaper.port_forwarded(state, f'repair_run/{run_id}/state/ABORTED', body_abort, method='PUT')
|
|
68
|
-
log2(f'Aborted {len(runs)} runs.')
|
|
69
|
-
aborted += 1
|
|
70
|
-
|
|
71
|
-
if aborted:
|
|
72
|
-
log2(f'Aborted {aborted} runs in total.')
|
|
73
|
-
else:
|
|
74
|
-
log2('No running repair runs found.')
|
|
75
|
-
|
|
76
|
-
def completion(self, state: ReplState):
|
|
77
|
-
if state.sts:
|
|
78
|
-
return super().completion(state)
|
|
79
|
-
|
|
80
|
-
return {}
|
|
81
|
-
|
|
82
|
-
def help(self, _: ReplState):
|
|
83
|
-
return f'{ReaperRunsAbort.COMMAND}\t abort all running reaper runs'
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import requests
|
|
2
|
-
|
|
3
|
-
from walker.commands.command import Command
|
|
4
|
-
from .reaper_session import ReaperSession
|
|
5
|
-
from walker.repl_state import ReplState, RequiredState
|
|
6
|
-
from walker.utils import log2
|
|
7
|
-
|
|
8
|
-
class ReaperScheduleActivate(Command):
|
|
9
|
-
COMMAND = 'reaper activate schedule'
|
|
10
|
-
reaper_login = None
|
|
11
|
-
|
|
12
|
-
# the singleton pattern
|
|
13
|
-
def __new__(cls, *args, **kwargs):
|
|
14
|
-
if not hasattr(cls, 'instance'): cls.instance = super(ReaperScheduleActivate, cls).__new__(cls)
|
|
15
|
-
|
|
16
|
-
return cls.instance
|
|
17
|
-
|
|
18
|
-
def __init__(self, successor: Command=None):
|
|
19
|
-
super().__init__(successor)
|
|
20
|
-
|
|
21
|
-
def command(self):
|
|
22
|
-
return ReaperScheduleActivate.COMMAND
|
|
23
|
-
|
|
24
|
-
def required(self):
|
|
25
|
-
return RequiredState.CLUSTER
|
|
26
|
-
|
|
27
|
-
def run(self, cmd: str, state: ReplState):
|
|
28
|
-
if not(args := self.args(cmd)):
|
|
29
|
-
return super().run(cmd, state)
|
|
30
|
-
|
|
31
|
-
state, args = self.apply_state(args, state)
|
|
32
|
-
if not self.validate_state(state):
|
|
33
|
-
return state
|
|
34
|
-
|
|
35
|
-
if not args:
|
|
36
|
-
log2('Specify schedule to activate.')
|
|
37
|
-
|
|
38
|
-
return state
|
|
39
|
-
|
|
40
|
-
schedule_id = args[0]
|
|
41
|
-
if not(reaper := ReaperSession.create(state)):
|
|
42
|
-
return state
|
|
43
|
-
|
|
44
|
-
self.activate_schedule(state, reaper, schedule_id)
|
|
45
|
-
|
|
46
|
-
return schedule_id
|
|
47
|
-
|
|
48
|
-
def activate_schedule(self, state: ReplState, reaper: ReaperSession, schedule_id: str):
|
|
49
|
-
def body(uri: str, headers: dict[str, str]):
|
|
50
|
-
return requests.put(uri, headers=headers)
|
|
51
|
-
|
|
52
|
-
reaper.port_forwarded(state, f'repair_schedule/{schedule_id}?state=ACTIVE', body, method='PUT')
|
|
53
|
-
reaper.show_schedule(state, schedule_id)
|
|
54
|
-
|
|
55
|
-
def completion(self, state: ReplState):
|
|
56
|
-
if state.sts:
|
|
57
|
-
leaf = {id: None for id in ReaperSession.cached_schedule_ids(state)}
|
|
58
|
-
|
|
59
|
-
return super().completion(state, leaf)
|
|
60
|
-
|
|
61
|
-
return {}
|
|
62
|
-
|
|
63
|
-
def help(self, _: ReplState):
|
|
64
|
-
return f'{ReaperScheduleActivate.COMMAND} <schedule-id>\t resume reaper schedule'
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import requests
|
|
2
|
-
|
|
3
|
-
from walker.commands.command import Command
|
|
4
|
-
from .reaper_session import ReaperSession
|
|
5
|
-
from walker.repl_state import ReplState, RequiredState
|
|
6
|
-
from walker.utils import log2
|
|
7
|
-
|
|
8
|
-
class ReaperScheduleStart(Command):
|
|
9
|
-
COMMAND = 'reaper start schedule'
|
|
10
|
-
reaper_login = None
|
|
11
|
-
|
|
12
|
-
# the singleton pattern
|
|
13
|
-
def __new__(cls, *args, **kwargs):
|
|
14
|
-
if not hasattr(cls, 'instance'): cls.instance = super(ReaperScheduleStart, cls).__new__(cls)
|
|
15
|
-
|
|
16
|
-
return cls.instance
|
|
17
|
-
|
|
18
|
-
def __init__(self, successor: Command=None):
|
|
19
|
-
super().__init__(successor)
|
|
20
|
-
|
|
21
|
-
def command(self):
|
|
22
|
-
return ReaperScheduleStart.COMMAND
|
|
23
|
-
|
|
24
|
-
def required(self):
|
|
25
|
-
return RequiredState.CLUSTER
|
|
26
|
-
|
|
27
|
-
def run(self, cmd: str, state: ReplState):
|
|
28
|
-
if not(args := self.args(cmd)):
|
|
29
|
-
return super().run(cmd, state)
|
|
30
|
-
|
|
31
|
-
state, args = self.apply_state(args, state)
|
|
32
|
-
if not self.validate_state(state):
|
|
33
|
-
return state
|
|
34
|
-
|
|
35
|
-
if not args:
|
|
36
|
-
log2('Specify schedule to activate.')
|
|
37
|
-
|
|
38
|
-
return state
|
|
39
|
-
|
|
40
|
-
schedule_id = args[0]
|
|
41
|
-
if not(reaper := ReaperSession.create(state)):
|
|
42
|
-
return schedule_id
|
|
43
|
-
|
|
44
|
-
self.start_schedule(state, reaper, schedule_id)
|
|
45
|
-
|
|
46
|
-
return schedule_id
|
|
47
|
-
|
|
48
|
-
def start_schedule(self, state: ReplState, reaper: ReaperSession, schedule_id: str):
|
|
49
|
-
def body(uri: str, headers: dict[str, str]):
|
|
50
|
-
return requests.post(uri, headers=headers)
|
|
51
|
-
|
|
52
|
-
reaper.port_forwarded(state, f'repair_schedule/start/{schedule_id}', body, method='POST')
|
|
53
|
-
reaper.show_schedule(state, schedule_id)
|
|
54
|
-
|
|
55
|
-
def completion(self, state: ReplState):
|
|
56
|
-
if state.sts:
|
|
57
|
-
leaf = {id: None for id in ReaperSession.cached_schedule_ids(state)}
|
|
58
|
-
|
|
59
|
-
return super().completion(state, leaf)
|
|
60
|
-
|
|
61
|
-
return {}
|
|
62
|
-
|
|
63
|
-
def help(self, _: ReplState):
|
|
64
|
-
return f'{ReaperScheduleStart.COMMAND} <schedule-id>\t start reaper runs for schedule'
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import requests
|
|
2
|
-
|
|
3
|
-
from walker.commands.command import Command
|
|
4
|
-
from .reaper_session import ReaperSession
|
|
5
|
-
from walker.repl_state import ReplState, RequiredState
|
|
6
|
-
from walker.utils import log2
|
|
7
|
-
|
|
8
|
-
class ReaperScheduleStop(Command):
|
|
9
|
-
COMMAND = 'reaper stop schedule'
|
|
10
|
-
reaper_login = None
|
|
11
|
-
|
|
12
|
-
# the singleton pattern
|
|
13
|
-
def __new__(cls, *args, **kwargs):
|
|
14
|
-
if not hasattr(cls, 'instance'): cls.instance = super(ReaperScheduleStop, cls).__new__(cls)
|
|
15
|
-
|
|
16
|
-
return cls.instance
|
|
17
|
-
|
|
18
|
-
def __init__(self, successor: Command=None):
|
|
19
|
-
super().__init__(successor)
|
|
20
|
-
|
|
21
|
-
def command(self):
|
|
22
|
-
return ReaperScheduleStop.COMMAND
|
|
23
|
-
|
|
24
|
-
def required(self):
|
|
25
|
-
return RequiredState.CLUSTER
|
|
26
|
-
|
|
27
|
-
def run(self, cmd: str, state: ReplState):
|
|
28
|
-
if not(args := self.args(cmd)):
|
|
29
|
-
return super().run(cmd, state)
|
|
30
|
-
|
|
31
|
-
state, args = self.apply_state(args, state)
|
|
32
|
-
if not self.validate_state(state):
|
|
33
|
-
return state
|
|
34
|
-
|
|
35
|
-
if not args:
|
|
36
|
-
log2('Specify run schedule to stop.')
|
|
37
|
-
|
|
38
|
-
return state
|
|
39
|
-
|
|
40
|
-
schedule_id = args[0]
|
|
41
|
-
if not(reaper := ReaperSession.create(state)):
|
|
42
|
-
return schedule_id
|
|
43
|
-
|
|
44
|
-
self.stop_schedule(state, reaper, schedule_id)
|
|
45
|
-
|
|
46
|
-
return schedule_id
|
|
47
|
-
|
|
48
|
-
def stop_schedule(self, state: ReplState, reaper: ReaperSession, schedule_id: str):
|
|
49
|
-
def body(uri: str, headers: dict[str, str]):
|
|
50
|
-
return requests.put(uri, headers=headers)
|
|
51
|
-
|
|
52
|
-
reaper.port_forwarded(state, f'repair_schedule/{schedule_id}?state=PAUSED', body, method='PUT')
|
|
53
|
-
reaper.show_schedule(state, schedule_id)
|
|
54
|
-
|
|
55
|
-
def completion(self, state: ReplState):
|
|
56
|
-
if state.sts:
|
|
57
|
-
leaf = {id: None for id in ReaperSession.cached_schedule_ids(state)}
|
|
58
|
-
|
|
59
|
-
return super().completion(state, leaf)
|
|
60
|
-
|
|
61
|
-
return {}
|
|
62
|
-
|
|
63
|
-
def help(self, _: ReplState):
|
|
64
|
-
return f'{ReaperScheduleStop.COMMAND} <schedule-id>\t pause reaper schedule'
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
from collections.abc import Callable
|
|
2
|
-
import threading
|
|
3
|
-
from kubernetes import client
|
|
4
|
-
import portforward
|
|
5
|
-
import re
|
|
6
|
-
import requests
|
|
7
|
-
from typing import List, cast
|
|
8
|
-
|
|
9
|
-
from walker.config import Config
|
|
10
|
-
from walker.k8s_utils.kube_context import KubeContext
|
|
11
|
-
from walker.repl_state import ReplState
|
|
12
|
-
from walker.utils import lines_to_tabular, log2
|
|
13
|
-
|
|
14
|
-
class ReaperSession:
|
|
15
|
-
is_forwarding = False
|
|
16
|
-
stopping = threading.Event()
|
|
17
|
-
schedules_ids_by_cluster: dict[str, list[str]] = {}
|
|
18
|
-
|
|
19
|
-
def __init__(self, pod: str, headers: dict[str, str] = None):
|
|
20
|
-
self.pod = pod
|
|
21
|
-
self.headers = headers
|
|
22
|
-
|
|
23
|
-
def login(self, state: ReplState, local_addr: str, remote_addr: str, show_output = True) -> str :
|
|
24
|
-
user, pw = state.user_pass(secret_path='reaper.secret')
|
|
25
|
-
|
|
26
|
-
response = requests.post(f'http://{local_addr}/login', headers={
|
|
27
|
-
'Accept': '*'
|
|
28
|
-
},data={
|
|
29
|
-
'username':user,
|
|
30
|
-
'password':pw})
|
|
31
|
-
if show_output:
|
|
32
|
-
log2(f'POST {remote_addr}/login')
|
|
33
|
-
log2(f' username={user}&password={pw}')
|
|
34
|
-
|
|
35
|
-
if int(response.status_code / 100) != 2:
|
|
36
|
-
if show_output:
|
|
37
|
-
log2("login failed")
|
|
38
|
-
return None
|
|
39
|
-
|
|
40
|
-
return response.headers['Set-Cookie']
|
|
41
|
-
|
|
42
|
-
def port_forwarded(self, state: ReplState, path: str, body: Callable[[str, dict[str, str]], requests.Response], method: str = None, show_output = True):
|
|
43
|
-
local_port = Config().get('reaper.port-forward.local-port', 9001)
|
|
44
|
-
target_port = 8080
|
|
45
|
-
|
|
46
|
-
def f(local_addr: str, remote_addr: str):
|
|
47
|
-
if not self.headers:
|
|
48
|
-
self.headers = self.cookie_header(state, local_addr, remote_addr, show_output=show_output)
|
|
49
|
-
|
|
50
|
-
if show_output and method:
|
|
51
|
-
log2(f'{method} {remote_addr}/{path}')
|
|
52
|
-
response = body(f'http://{local_addr}/{path}', self.headers)
|
|
53
|
-
|
|
54
|
-
if response:
|
|
55
|
-
if int(response.status_code / 100) != 2:
|
|
56
|
-
if show_output:
|
|
57
|
-
log2(response.status_code)
|
|
58
|
-
return response
|
|
59
|
-
|
|
60
|
-
if show_output:
|
|
61
|
-
log2()
|
|
62
|
-
|
|
63
|
-
return response if response else 'no-response'
|
|
64
|
-
|
|
65
|
-
if KubeContext.in_cluster():
|
|
66
|
-
# cs-a526330d23-cs-a526330d23-default-sts-0 ->
|
|
67
|
-
# curl http://cs-a526330d23-cs-a526330d23-reaper-service.stgawsscpsr.svc.cluster.local:8080
|
|
68
|
-
groups = re.match(r'^(.*?-.*?-.*?-.*?-).*', state.sts)
|
|
69
|
-
if groups:
|
|
70
|
-
svc_name = Config().get('reaper.service-name', 'reaper-service')
|
|
71
|
-
svc = f'{groups[1]}{svc_name}.{state.namespace}.svc.cluster.local:{target_port}'
|
|
72
|
-
return f(local_addr=svc, remote_addr=svc)
|
|
73
|
-
else:
|
|
74
|
-
return None
|
|
75
|
-
else:
|
|
76
|
-
with portforward.forward(state.namespace, self.pod, local_port, target_port):
|
|
77
|
-
return f(local_addr=f'localhost:{local_port}', remote_addr=f'{self.pod}:{target_port}')
|
|
78
|
-
|
|
79
|
-
def cookie_header(self, state: ReplState, local_addr, remote_addr, show_output = True):
|
|
80
|
-
return {'Cookie': self.login(state, local_addr, remote_addr, show_output=show_output)}
|
|
81
|
-
|
|
82
|
-
def create(state: ReplState) -> 'ReaperSession':
|
|
83
|
-
pods = ReaperSession.list_reaper_pods(state.sts if state.sts else state.pod, state.namespace)
|
|
84
|
-
if pods:
|
|
85
|
-
return ReaperSession(pods[0].metadata.name)
|
|
86
|
-
else:
|
|
87
|
-
log2('No reaper found.')
|
|
88
|
-
|
|
89
|
-
return None
|
|
90
|
-
|
|
91
|
-
def list_reaper_pods(sts_name: str, namespace: str) -> List[client.V1Pod]:
|
|
92
|
-
v1 = client.CoreV1Api()
|
|
93
|
-
|
|
94
|
-
# k8ssandra.io/reaper: cs-d0767a536f-cs-d0767a536f-reaper
|
|
95
|
-
groups = re.match(Config().get('reaper.pod.cluster-regex', r'(.*?-.*?-.*?-.*?)-.*'), sts_name)
|
|
96
|
-
label_selector = Config().get('reaper.pod.label-selector', 'k8ssandra.io/reaper={cluster}-reaper').replace('{cluster}', groups[1])
|
|
97
|
-
|
|
98
|
-
return cast(List[client.V1Pod], v1.list_namespaced_pod(namespace, label_selector=label_selector).items)
|
|
99
|
-
|
|
100
|
-
def show_schedules(self, state: ReplState, filter: Callable[[list[dict]], dict] = None):
|
|
101
|
-
schedules = self.list_schedules(state, filter=filter)
|
|
102
|
-
# forced refresh of schedule list
|
|
103
|
-
if not filter:
|
|
104
|
-
self.schedules_ids_by_cluster[state.sts] = [schedule['id'] for schedule in schedules]
|
|
105
|
-
self.show_schedules_tabular(schedules)
|
|
106
|
-
|
|
107
|
-
def schedule_ids(self, state: ReplState, show_output = True, filter: Callable[[list[dict]], dict] = None):
|
|
108
|
-
schedules = self.list_schedules(state, show_output=show_output, filter=filter)
|
|
109
|
-
return [schedule['id'] for schedule in schedules]
|
|
110
|
-
|
|
111
|
-
def list_schedules(self, state: ReplState, show_output = True, filter: Callable[[list[dict]], dict] = None) -> list[dict]:
|
|
112
|
-
def body(uri: str, headers: dict[str, str]):
|
|
113
|
-
return requests.get(uri, headers=headers)
|
|
114
|
-
|
|
115
|
-
response = self.port_forwarded(state, 'repair_schedule', body, method='GET', show_output=show_output)
|
|
116
|
-
if not response:
|
|
117
|
-
return
|
|
118
|
-
|
|
119
|
-
res = response.json()
|
|
120
|
-
if filter:
|
|
121
|
-
res = filter(res)
|
|
122
|
-
|
|
123
|
-
return res
|
|
124
|
-
|
|
125
|
-
def show_schedules_tabular(self, schedules: list[dict]):
|
|
126
|
-
log2(lines_to_tabular([f"{schedule['id']} {schedule['state']} {schedule['cluster_name']} {schedule['keyspace_name']}" for schedule in schedules], 'ID STATE CLUSTER KEYSPACE'))
|
|
127
|
-
|
|
128
|
-
def show_schedule(self, state: ReplState, schedule_id: str):
|
|
129
|
-
def filter(schedules: list[dict]):
|
|
130
|
-
return [schedule for schedule in schedules if schedule['id'] == schedule_id]
|
|
131
|
-
|
|
132
|
-
self.show_schedules(state, filter)
|
|
133
|
-
|
|
134
|
-
def reaper_spec(self, state: ReplState) -> dict[str, any]:
|
|
135
|
-
user, pw = state.user_pass(secret_path='reaper.secret')
|
|
136
|
-
local_port = Config().get('reaper.port-forward.local-port', 9001)
|
|
137
|
-
|
|
138
|
-
return {
|
|
139
|
-
'pod': self.pod,
|
|
140
|
-
'exec': f'kubectl exec -it {self.pod} -n {state.namespace} -- bash',
|
|
141
|
-
'forward': f'kubectl port-forward pods/{self.pod} -n {state.namespace} {local_port}:8080',
|
|
142
|
-
'web-uri': f'http://localhost:{local_port}/webui',
|
|
143
|
-
'username': user,
|
|
144
|
-
'password': pw
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
def cached_schedule_ids(state: ReplState) -> list[str]:
|
|
148
|
-
if state.sts in ReaperSession.schedules_ids_by_cluster:
|
|
149
|
-
return ReaperSession.schedules_ids_by_cluster[state.sts]
|
|
150
|
-
|
|
151
|
-
if reaper := ReaperSession.create(state):
|
|
152
|
-
state.wait_log("Inspecting Cassandra Reaper...")
|
|
153
|
-
|
|
154
|
-
schedules = reaper.schedule_ids(state, show_output = False)
|
|
155
|
-
ReaperSession.schedules_ids_by_cluster[state.sts] = schedules
|
|
156
|
-
|
|
157
|
-
return schedules
|
|
158
|
-
|
|
159
|
-
return []
|
walker/commands/repair/repair.py
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import click
|
|
2
|
-
|
|
3
|
-
from walker.commands.command import Command
|
|
4
|
-
from walker.commands.command_helpers import ClusterCommandHelper
|
|
5
|
-
from .repair_run import RepairRun
|
|
6
|
-
from .repair_scan import RepairScan
|
|
7
|
-
from .repair_stop import RepairStop
|
|
8
|
-
from .repair_log import RepairLog
|
|
9
|
-
from walker.repl_state import ReplState, RequiredState
|
|
10
|
-
from walker.utils import lines_to_tabular, log, log2
|
|
11
|
-
|
|
12
|
-
class Repair(Command):
|
|
13
|
-
COMMAND = 'repair'
|
|
14
|
-
|
|
15
|
-
# the singleton pattern
|
|
16
|
-
def __new__(cls, *args, **kwargs):
|
|
17
|
-
if not hasattr(cls, 'instance'): cls.instance = super(Repair, cls).__new__(cls)
|
|
18
|
-
|
|
19
|
-
return cls.instance
|
|
20
|
-
|
|
21
|
-
def __init__(self, successor: Command=None):
|
|
22
|
-
super().__init__(successor)
|
|
23
|
-
|
|
24
|
-
def command(self):
|
|
25
|
-
return Repair.COMMAND
|
|
26
|
-
|
|
27
|
-
def required(self):
|
|
28
|
-
return RequiredState.CLUSTER
|
|
29
|
-
|
|
30
|
-
def run(self, cmd: str, state: ReplState):
|
|
31
|
-
if not(args := self.args(cmd)):
|
|
32
|
-
return super().run(cmd, state)
|
|
33
|
-
|
|
34
|
-
state, args = self.apply_state(args, state)
|
|
35
|
-
if not self.validate_state(state):
|
|
36
|
-
return state
|
|
37
|
-
|
|
38
|
-
if state.in_repl:
|
|
39
|
-
log(lines_to_tabular([c.help(ReplState()) for c in Repair.cmd_list()], separator=':'))
|
|
40
|
-
|
|
41
|
-
return 'command-missing'
|
|
42
|
-
else:
|
|
43
|
-
# head with the Chain of Responsibility pattern
|
|
44
|
-
cmds = Command.chain(Repair.cmd_list())
|
|
45
|
-
if not cmds.run(cmd, state):
|
|
46
|
-
log2('* Command is missing.')
|
|
47
|
-
Command.display_help()
|
|
48
|
-
|
|
49
|
-
def cmd_list():
|
|
50
|
-
return [RepairRun(), RepairScan(), RepairStop(), RepairLog()]
|
|
51
|
-
|
|
52
|
-
def completion(self, state: ReplState):
|
|
53
|
-
if state.sts:
|
|
54
|
-
return super().completion(state)
|
|
55
|
-
return {}
|
|
56
|
-
|
|
57
|
-
def help(self, _: ReplState):
|
|
58
|
-
return None
|
|
59
|
-
|
|
60
|
-
class RepairCommandHelper(click.Command):
|
|
61
|
-
def get_help(self, ctx: click.Context):
|
|
62
|
-
log(super().get_help(ctx))
|
|
63
|
-
log()
|
|
64
|
-
log('Sub-Commands:')
|
|
65
|
-
|
|
66
|
-
log(lines_to_tabular([c.help(ReplState()).replace(f'{Repair.COMMAND} ', ' ', 1) for c in Repair.cmd_list()], separator=':'))
|
|
67
|
-
log()
|
|
68
|
-
ClusterCommandHelper.cluster_help()
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
from walker.commands.command import Command
|
|
2
|
-
from walker.k8s_utils.jobs import Jobs
|
|
3
|
-
from walker.k8s_utils.volumes import Volumes
|
|
4
|
-
from walker.repl_state import ReplState, RequiredState
|
|
5
|
-
from walker.config import Config
|
|
6
|
-
from walker.commands.reaper.reaper_session import ReaperSession
|
|
7
|
-
from walker.commands.reaper.reaper_runs_abort import ReaperRunsAbort
|
|
8
|
-
from walker.commands.reaper.reaper_schedule_stop import ReaperScheduleStop
|
|
9
|
-
from walker.utils import log2
|
|
10
|
-
|
|
11
|
-
class RepairRun(Command):
|
|
12
|
-
COMMAND = 'repair run'
|
|
13
|
-
|
|
14
|
-
# the singleton pattern
|
|
15
|
-
def __new__(cls, *args, **kwargs):
|
|
16
|
-
if not hasattr(cls, 'instance'): cls.instance = super(RepairRun, cls).__new__(cls)
|
|
17
|
-
|
|
18
|
-
return cls.instance
|
|
19
|
-
|
|
20
|
-
def __init__(self, successor: Command=None):
|
|
21
|
-
super().__init__(successor)
|
|
22
|
-
|
|
23
|
-
def command(self):
|
|
24
|
-
return RepairRun.COMMAND
|
|
25
|
-
|
|
26
|
-
def required(self):
|
|
27
|
-
return RequiredState.CLUSTER
|
|
28
|
-
|
|
29
|
-
def run(self, cmd: str, state: ReplState):
|
|
30
|
-
if not(args := self.args(cmd)):
|
|
31
|
-
return super().run(cmd, state)
|
|
32
|
-
|
|
33
|
-
state, args = self.apply_state(args, state)
|
|
34
|
-
if not self.validate_state(state):
|
|
35
|
-
return state
|
|
36
|
-
|
|
37
|
-
replace = False
|
|
38
|
-
if len(args) == 1:
|
|
39
|
-
replace = args[0] == 'replace'
|
|
40
|
-
|
|
41
|
-
log2("Stopping all reaper schedules...")
|
|
42
|
-
reaper = ReaperSession.create(state)
|
|
43
|
-
schedules = reaper.schedule_ids(state)
|
|
44
|
-
for schedule_id in schedules:
|
|
45
|
-
ReaperScheduleStop().run(f'reaper stop schedule {schedule_id}', state)
|
|
46
|
-
log2("Aborting all reaper runs...")
|
|
47
|
-
state = ReaperRunsAbort().run('reaper abort runs', state)
|
|
48
|
-
|
|
49
|
-
image = Config().get('repair.image', 'ci-registry.c3iot.io/cloudops/cassrepair:2.0.11')
|
|
50
|
-
secret = Config().get('repair.secret', 'ciregistryc3iotio')
|
|
51
|
-
log_path = Config().get('repair.log-path', '/home/cassrepair/logs/')
|
|
52
|
-
user, _ = state.user_pass()
|
|
53
|
-
ns = state.namespace
|
|
54
|
-
env = Config().get('repair.env', {})
|
|
55
|
-
env["cluster"] = ns
|
|
56
|
-
env_from = {"username": user, "password": user}
|
|
57
|
-
pvc_name ='cassrepair-log-' + state.sts
|
|
58
|
-
Volumes.create_pvc(pvc_name, 30, ns)
|
|
59
|
-
if replace:
|
|
60
|
-
Jobs.delete('cassrepair-'+state.sts, ns)
|
|
61
|
-
Jobs.create('cassrepair-'+state.sts, ns, image, secret, env, env_from, 'cassrepair', pvc_name, log_path)
|
|
62
|
-
|
|
63
|
-
return state
|
|
64
|
-
|
|
65
|
-
def completion(self, state: ReplState):
|
|
66
|
-
if state.sts:
|
|
67
|
-
return super().completion(state)
|
|
68
|
-
|
|
69
|
-
return {}
|
|
70
|
-
|
|
71
|
-
def help(self, _: ReplState):
|
|
72
|
-
return f'{RepairRun.COMMAND} [replace]\t start a repair job, default not replacing'
|