kaqing 1.98.15__py3-none-any.whl → 2.0.145__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of kaqing might be problematic. Click here for more details.
- adam/app_session.py +1 -1
- adam/apps.py +2 -2
- adam/batch.py +30 -31
- adam/checks/check_utils.py +4 -4
- adam/checks/compactionstats.py +1 -1
- adam/checks/cpu.py +2 -2
- adam/checks/disk.py +1 -1
- adam/checks/gossip.py +1 -1
- adam/checks/memory.py +3 -3
- adam/checks/status.py +1 -1
- adam/commands/alter_tables.py +81 -0
- adam/commands/app.py +3 -3
- adam/commands/app_ping.py +2 -2
- adam/commands/audit/audit.py +86 -0
- adam/commands/audit/audit_repair_tables.py +77 -0
- adam/commands/audit/audit_run.py +58 -0
- adam/commands/audit/show_last10.py +51 -0
- adam/commands/audit/show_slow10.py +50 -0
- adam/commands/audit/show_top10.py +48 -0
- adam/commands/audit/utils_show_top10.py +59 -0
- adam/commands/bash/bash.py +133 -0
- adam/commands/bash/bash_completer.py +93 -0
- adam/commands/cat.py +56 -0
- adam/commands/cd.py +12 -82
- adam/commands/check.py +6 -0
- adam/commands/cli_commands.py +3 -3
- adam/commands/code.py +60 -0
- adam/commands/command.py +48 -12
- adam/commands/commands_utils.py +4 -5
- adam/commands/cql/cql_completions.py +28 -0
- adam/commands/cql/cql_utils.py +209 -0
- adam/commands/{cqlsh.py → cql/cqlsh.py} +15 -10
- adam/commands/deploy/__init__.py +0 -0
- adam/commands/{frontend → deploy}/code_start.py +1 -1
- adam/commands/{frontend → deploy}/code_stop.py +1 -1
- adam/commands/{frontend → deploy}/code_utils.py +2 -2
- adam/commands/deploy/deploy.py +48 -0
- adam/commands/deploy/deploy_frontend.py +52 -0
- adam/commands/deploy/deploy_pg_agent.py +38 -0
- adam/commands/deploy/deploy_pod.py +110 -0
- adam/commands/deploy/deploy_utils.py +29 -0
- adam/commands/deploy/undeploy.py +48 -0
- adam/commands/deploy/undeploy_frontend.py +41 -0
- adam/commands/deploy/undeploy_pg_agent.py +42 -0
- adam/commands/deploy/undeploy_pod.py +51 -0
- adam/commands/devices/__init__.py +0 -0
- adam/commands/devices/device.py +27 -0
- adam/commands/devices/device_app.py +146 -0
- adam/commands/devices/device_auit_log.py +43 -0
- adam/commands/devices/device_cass.py +145 -0
- adam/commands/devices/device_export.py +86 -0
- adam/commands/devices/device_postgres.py +109 -0
- adam/commands/devices/devices.py +25 -0
- adam/commands/export/__init__.py +0 -0
- adam/commands/export/clean_up_export_session.py +53 -0
- adam/commands/{frontend/teardown_frontend.py → export/clean_up_export_sessions.py} +9 -11
- adam/commands/export/drop_export_database.py +58 -0
- adam/commands/export/drop_export_databases.py +46 -0
- adam/commands/export/export.py +83 -0
- adam/commands/export/export_databases.py +170 -0
- adam/commands/export/export_select.py +85 -0
- adam/commands/export/export_select_x.py +54 -0
- adam/commands/export/export_use.py +55 -0
- adam/commands/export/exporter.py +364 -0
- adam/commands/export/import_session.py +68 -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 +63 -0
- adam/commands/export/show_export_databases.py +39 -0
- adam/commands/export/show_export_session.py +51 -0
- adam/commands/export/show_export_sessions.py +47 -0
- adam/commands/export/utils_export.py +291 -0
- adam/commands/help.py +12 -7
- adam/commands/issues.py +6 -0
- adam/commands/kubectl.py +41 -0
- adam/commands/login.py +9 -5
- adam/commands/logs.py +2 -1
- adam/commands/ls.py +4 -107
- adam/commands/medusa/medusa.py +2 -26
- adam/commands/medusa/medusa_backup.py +2 -2
- adam/commands/medusa/medusa_restore.py +3 -4
- adam/commands/medusa/medusa_show_backupjobs.py +4 -3
- adam/commands/medusa/medusa_show_restorejobs.py +3 -3
- adam/commands/nodetool.py +9 -4
- adam/commands/param_set.py +1 -1
- adam/commands/postgres/postgres.py +42 -43
- adam/commands/postgres/postgres_context.py +248 -0
- adam/commands/postgres/postgres_preview.py +0 -1
- adam/commands/postgres/postgres_utils.py +31 -0
- adam/commands/postgres/psql_completions.py +10 -0
- adam/commands/preview_table.py +18 -40
- adam/commands/pwd.py +2 -28
- adam/commands/reaper/reaper.py +4 -24
- adam/commands/reaper/reaper_restart.py +1 -1
- adam/commands/reaper/reaper_session.py +2 -2
- adam/commands/repair/repair.py +3 -27
- adam/commands/repair/repair_log.py +1 -1
- adam/commands/repair/repair_run.py +2 -2
- adam/commands/repair/repair_scan.py +2 -7
- adam/commands/repair/repair_stop.py +1 -1
- adam/commands/report.py +6 -0
- adam/commands/restart.py +2 -2
- adam/commands/rollout.py +1 -1
- adam/commands/shell.py +33 -0
- adam/commands/show/show.py +11 -26
- adam/commands/show/show_app_actions.py +3 -0
- adam/commands/show/show_app_id.py +1 -1
- adam/commands/show/show_app_queues.py +3 -2
- adam/commands/show/show_cassandra_status.py +3 -3
- adam/commands/show/show_cassandra_version.py +3 -3
- adam/commands/show/show_commands.py +4 -1
- adam/commands/show/show_host.py +33 -0
- adam/commands/show/show_login.py +3 -0
- adam/commands/show/show_processes.py +1 -1
- adam/commands/show/show_repairs.py +2 -2
- adam/commands/show/show_storage.py +1 -1
- adam/commands/watch.py +1 -1
- adam/config.py +16 -3
- adam/embedded_params.py +1 -1
- adam/pod_exec_result.py +10 -2
- adam/repl.py +132 -117
- adam/repl_commands.py +62 -18
- adam/repl_state.py +276 -55
- adam/sql/__init__.py +0 -0
- adam/sql/sql_completer.py +120 -0
- adam/sql/sql_state_machine.py +617 -0
- adam/sql/term_completer.py +76 -0
- adam/sso/authenticator.py +1 -1
- adam/sso/authn_ad.py +36 -56
- adam/sso/authn_okta.py +6 -32
- adam/sso/cred_cache.py +1 -1
- adam/sso/idp.py +74 -9
- adam/sso/idp_login.py +2 -2
- adam/sso/idp_session.py +10 -7
- adam/utils.py +85 -4
- adam/utils_athena.py +145 -0
- adam/utils_audits.py +102 -0
- adam/utils_k8s/__init__.py +0 -0
- adam/utils_k8s/app_clusters.py +33 -0
- adam/utils_k8s/app_pods.py +31 -0
- adam/{k8s_utils → utils_k8s}/cassandra_clusters.py +6 -21
- adam/{k8s_utils → utils_k8s}/cassandra_nodes.py +12 -5
- adam/utils_k8s/config_maps.py +34 -0
- adam/utils_k8s/deployment.py +56 -0
- adam/{k8s_utils → utils_k8s}/jobs.py +1 -1
- adam/{k8s_utils → utils_k8s}/kube_context.py +1 -1
- adam/utils_k8s/pods.py +342 -0
- adam/{k8s_utils → utils_k8s}/secrets.py +4 -0
- adam/utils_k8s/service_accounts.py +169 -0
- adam/{k8s_utils → utils_k8s}/statefulsets.py +5 -4
- adam/{k8s_utils → utils_k8s}/volumes.py +9 -0
- 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 +101 -0
- adam/version.py +1 -1
- {kaqing-1.98.15.dist-info → kaqing-2.0.145.dist-info}/METADATA +1 -1
- kaqing-2.0.145.dist-info/RECORD +227 -0
- adam/commands/bash.py +0 -87
- adam/commands/cql_utils.py +0 -53
- adam/commands/devices.py +0 -89
- adam/commands/frontend/setup.py +0 -60
- adam/commands/frontend/setup_frontend.py +0 -58
- adam/commands/frontend/teardown.py +0 -61
- adam/commands/postgres/postgres_session.py +0 -225
- adam/commands/user_entry.py +0 -77
- adam/k8s_utils/pods.py +0 -211
- kaqing-1.98.15.dist-info/RECORD +0 -160
- /adam/commands/{frontend → audit}/__init__.py +0 -0
- /adam/{k8s_utils → commands/bash}/__init__.py +0 -0
- /adam/{medusa_show_restorejobs.py → commands/cql/__init__.py} +0 -0
- /adam/{k8s_utils → utils_k8s}/custom_resources.py +0 -0
- /adam/{k8s_utils → utils_k8s}/ingresses.py +0 -0
- /adam/{k8s_utils → utils_k8s}/services.py +0 -0
- {kaqing-1.98.15.dist-info → kaqing-2.0.145.dist-info}/WHEEL +0 -0
- {kaqing-1.98.15.dist-info → kaqing-2.0.145.dist-info}/entry_points.txt +0 -0
- {kaqing-1.98.15.dist-info → kaqing-2.0.145.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
from kubernetes import client
|
|
2
|
+
|
|
3
|
+
from adam.commands.command import Command
|
|
4
|
+
from adam.commands.deploy.deploy_utils import deploy_frontend, gen_labels
|
|
5
|
+
from adam.commands.deploy.undeploy_pod import UndeployPod
|
|
6
|
+
from adam.config import Config
|
|
7
|
+
from adam.utils_k8s.config_maps import ConfigMaps
|
|
8
|
+
from adam.utils_k8s.deployment import Deployments
|
|
9
|
+
from adam.utils_k8s.kube_context import KubeContext
|
|
10
|
+
from adam.utils_k8s.pods import Pods
|
|
11
|
+
from adam.utils_k8s.service_accounts import ServiceAccounts
|
|
12
|
+
from adam.utils_k8s.volumes import ConfigMapMount
|
|
13
|
+
from adam.repl_state import ReplState, RequiredState
|
|
14
|
+
from adam.utils import ing, log2
|
|
15
|
+
|
|
16
|
+
class DeployPod(Command):
|
|
17
|
+
COMMAND = 'deploy pod'
|
|
18
|
+
|
|
19
|
+
# the singleton pattern
|
|
20
|
+
def __new__(cls, *args, **kwargs):
|
|
21
|
+
if not hasattr(cls, 'instance'): cls.instance = super(DeployPod, cls).__new__(cls)
|
|
22
|
+
|
|
23
|
+
return cls.instance
|
|
24
|
+
|
|
25
|
+
def __init__(self, successor: Command=None):
|
|
26
|
+
super().__init__(successor)
|
|
27
|
+
|
|
28
|
+
def command(self):
|
|
29
|
+
return DeployPod.COMMAND
|
|
30
|
+
|
|
31
|
+
def required(self):
|
|
32
|
+
return RequiredState.NAMESPACE
|
|
33
|
+
|
|
34
|
+
def run(self, cmd: str, state: ReplState):
|
|
35
|
+
if not(args := self.args(cmd)):
|
|
36
|
+
return super().run(cmd, state)
|
|
37
|
+
|
|
38
|
+
state, args = self.apply_state(args, state)
|
|
39
|
+
if not self.validate_state(state):
|
|
40
|
+
return state
|
|
41
|
+
|
|
42
|
+
args, forced = Command.extract_options(args, '--force')
|
|
43
|
+
if forced:
|
|
44
|
+
UndeployPod().run(UndeployPod.COMMAND, state)
|
|
45
|
+
|
|
46
|
+
if KubeContext.in_cluster():
|
|
47
|
+
log2('This is doable only from outside of the Kubernetes cluster.')
|
|
48
|
+
return state
|
|
49
|
+
|
|
50
|
+
sa_name = Config().get('pod.sa.name', 'ops')
|
|
51
|
+
sa_proto = Config().get('pod.sa.proto', 'c3')
|
|
52
|
+
additional_cluster_roles = Config().get('pod.sa.additional-cluster-roles', 'c3aiops-k8ssandra-operator').split(',')
|
|
53
|
+
label_selector = Config().get('pod.label-selector', 'run=ops')
|
|
54
|
+
labels = gen_labels(label_selector)
|
|
55
|
+
|
|
56
|
+
with ing('Creating service account'):
|
|
57
|
+
ServiceAccounts.replicate(sa_name, state.namespace, sa_proto, labels=labels, add_cluster_roles=additional_cluster_roles)
|
|
58
|
+
|
|
59
|
+
settings_filename = 'settings.yaml'
|
|
60
|
+
settings_path = f'/kaqing/{settings_filename}'
|
|
61
|
+
settings_data = None
|
|
62
|
+
try:
|
|
63
|
+
with open(settings_filename, 'r') as file:
|
|
64
|
+
settings_data = file.read()
|
|
65
|
+
except:
|
|
66
|
+
try:
|
|
67
|
+
with open(settings_path, 'r') as file:
|
|
68
|
+
settings_data = file.read()
|
|
69
|
+
except:
|
|
70
|
+
pass
|
|
71
|
+
|
|
72
|
+
if not settings_data:
|
|
73
|
+
log2(f'{settings_filename} not found.')
|
|
74
|
+
return state
|
|
75
|
+
|
|
76
|
+
cm_name = Config().get('pod.cm.name', 'ops')
|
|
77
|
+
map_data = {
|
|
78
|
+
settings_filename : settings_data
|
|
79
|
+
}
|
|
80
|
+
with ing('Creating config map'):
|
|
81
|
+
ConfigMaps.create(cm_name, state.namespace, map_data, labels=labels)
|
|
82
|
+
|
|
83
|
+
pod_name = Config().get('pod.name', 'ops')
|
|
84
|
+
image = Config().get('pod.image', 'seanahnsf/kaqing')
|
|
85
|
+
security_context = client.V1SecurityContext(
|
|
86
|
+
capabilities=client.V1Capabilities(
|
|
87
|
+
add=["SYS_PTRACE"]
|
|
88
|
+
)
|
|
89
|
+
)
|
|
90
|
+
with ing('Creating deployment'):
|
|
91
|
+
Deployments.create(state.namespace,
|
|
92
|
+
pod_name,
|
|
93
|
+
image,
|
|
94
|
+
env={'NAMESPACE': state.namespace},
|
|
95
|
+
container_security_context=security_context,
|
|
96
|
+
labels=labels,
|
|
97
|
+
sa_name=sa_name,
|
|
98
|
+
config_map_mount=ConfigMapMount(cm_name, settings_filename, settings_path))
|
|
99
|
+
|
|
100
|
+
uri = deploy_frontend(pod_name, state.namespace, label_selector)
|
|
101
|
+
|
|
102
|
+
Pods.wait_for_running(state.namespace, pod_name, msg=f'In moments, ops pod will be available at {uri}.', label_selector=label_selector)
|
|
103
|
+
|
|
104
|
+
return state
|
|
105
|
+
|
|
106
|
+
def completion(self, state: ReplState):
|
|
107
|
+
return super().completion(state, {'--force': None})
|
|
108
|
+
|
|
109
|
+
def help(self, _: ReplState):
|
|
110
|
+
return f'{DeployPod.COMMAND} [--force]\t deploy Ops pod, --force to undeploy first'
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from adam.app_session import AppSession
|
|
2
|
+
from adam.utils import ing
|
|
3
|
+
from adam.utils_k8s.ingresses import Ingresses
|
|
4
|
+
from adam.utils_k8s.services import Services
|
|
5
|
+
|
|
6
|
+
def deploy_frontend(name: str, namespace: str, label_selector: str):
|
|
7
|
+
app_session: AppSession = AppSession.create('c3', 'c3', namespace)
|
|
8
|
+
port = 7678
|
|
9
|
+
labels = gen_labels(label_selector)
|
|
10
|
+
with ing('Creating service'):
|
|
11
|
+
Services.create_service(name, namespace, port, labels, labels=labels)
|
|
12
|
+
with ing('Creating ingress'):
|
|
13
|
+
Ingresses.create_ingress(name, namespace, app_session.host, '/c3/c3/ops($|/)', port, annotations={
|
|
14
|
+
'kubernetes.io/ingress.class': 'nginx',
|
|
15
|
+
'nginx.ingress.kubernetes.io/use-regex': 'true',
|
|
16
|
+
'nginx.ingress.kubernetes.io/rewrite-target': '/'
|
|
17
|
+
}, labels=labels)
|
|
18
|
+
|
|
19
|
+
return f'https://{app_session.host}/c3/c3/ops'
|
|
20
|
+
|
|
21
|
+
def undeploy_frontend(namespace: str, label_selector: str):
|
|
22
|
+
with ing('Deleting ingress'):
|
|
23
|
+
Ingresses.delete_ingresses(namespace, label_selector=label_selector)
|
|
24
|
+
with ing('Deleting service'):
|
|
25
|
+
Services.delete_services(namespace, label_selector=label_selector)
|
|
26
|
+
|
|
27
|
+
def gen_labels(label_selector: str):
|
|
28
|
+
kv = label_selector.split('=')
|
|
29
|
+
return {kv[0]: kv[1]}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from adam.commands.command import Command
|
|
4
|
+
from adam.commands.deploy.undeploy_frontend import UndeployFrontend
|
|
5
|
+
from adam.commands.deploy.undeploy_pg_agent import UndeployPgAgent
|
|
6
|
+
from adam.commands.deploy.undeploy_pod import UndeployPod
|
|
7
|
+
from adam.repl_state import ReplState, RequiredState
|
|
8
|
+
|
|
9
|
+
class Undeploy(Command):
|
|
10
|
+
COMMAND = 'undeploy'
|
|
11
|
+
reaper_login = None
|
|
12
|
+
|
|
13
|
+
# the singleton pattern
|
|
14
|
+
def __new__(cls, *args, **kwargs):
|
|
15
|
+
if not hasattr(cls, 'instance'): cls.instance = super(Undeploy, 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 Undeploy.COMMAND
|
|
24
|
+
|
|
25
|
+
def required(self):
|
|
26
|
+
return RequiredState.NAMESPACE
|
|
27
|
+
|
|
28
|
+
def run(self, cmd: str, state: ReplState):
|
|
29
|
+
if not(args := self.args(cmd)):
|
|
30
|
+
return super().run(cmd, state)
|
|
31
|
+
|
|
32
|
+
if not self.validate_state(state):
|
|
33
|
+
return state
|
|
34
|
+
|
|
35
|
+
return super().intermediate_run(cmd, state, args, Undeploy.cmd_list())
|
|
36
|
+
|
|
37
|
+
def cmd_list():
|
|
38
|
+
return [UndeployFrontend(), UndeployPod(), UndeployPgAgent()]
|
|
39
|
+
|
|
40
|
+
def completion(self, state: ReplState):
|
|
41
|
+
if state.sts:
|
|
42
|
+
return super().completion(state)
|
|
43
|
+
|
|
44
|
+
return {}
|
|
45
|
+
|
|
46
|
+
class UndeployCommandHelper(click.Command):
|
|
47
|
+
def get_help(self, ctx: click.Context):
|
|
48
|
+
Command.intermediate_help(super().get_help(ctx), Undeploy.COMMAND, Undeploy.cmd_list())
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from adam.commands.command import Command
|
|
2
|
+
from adam.commands.deploy.deploy_utils import undeploy_frontend
|
|
3
|
+
from adam.config import Config
|
|
4
|
+
from adam.repl_state import ReplState, RequiredState
|
|
5
|
+
|
|
6
|
+
class UndeployFrontend(Command):
|
|
7
|
+
COMMAND = 'undeploy frontend'
|
|
8
|
+
|
|
9
|
+
# the singleton pattern
|
|
10
|
+
def __new__(cls, *args, **kwargs):
|
|
11
|
+
if not hasattr(cls, 'instance'): cls.instance = super(UndeployFrontend, cls).__new__(cls)
|
|
12
|
+
|
|
13
|
+
return cls.instance
|
|
14
|
+
|
|
15
|
+
def __init__(self, successor: Command=None):
|
|
16
|
+
super().__init__(successor)
|
|
17
|
+
|
|
18
|
+
def command(self):
|
|
19
|
+
return UndeployFrontend.COMMAND
|
|
20
|
+
|
|
21
|
+
def required(self):
|
|
22
|
+
return RequiredState.NAMESPACE
|
|
23
|
+
|
|
24
|
+
def run(self, cmd: str, state: ReplState):
|
|
25
|
+
if not(args := self.args(cmd)):
|
|
26
|
+
return super().run(cmd, state)
|
|
27
|
+
|
|
28
|
+
state, args = self.apply_state(args, state)
|
|
29
|
+
if not self.validate_state(state):
|
|
30
|
+
return state
|
|
31
|
+
|
|
32
|
+
label_selector = Config().get('pod.label-selector', 'run=ops')
|
|
33
|
+
undeploy_frontend(state.namespace, label_selector)
|
|
34
|
+
|
|
35
|
+
return state
|
|
36
|
+
|
|
37
|
+
def completion(self, state: ReplState):
|
|
38
|
+
return super().completion(state)
|
|
39
|
+
|
|
40
|
+
def help(self, _: ReplState):
|
|
41
|
+
return f'{UndeployFrontend.COMMAND}\t undeploy Web frontend'
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from adam.commands.command import Command
|
|
2
|
+
from adam.commands.postgres.postgres_context import PostgresContext
|
|
3
|
+
from adam.config import Config
|
|
4
|
+
from adam.repl_state import ReplState, RequiredState
|
|
5
|
+
from adam.utils import ing
|
|
6
|
+
|
|
7
|
+
class UndeployPgAgent(Command):
|
|
8
|
+
COMMAND = 'undeploy pg-agent'
|
|
9
|
+
|
|
10
|
+
# the singleton pattern
|
|
11
|
+
def __new__(cls, *args, **kwargs):
|
|
12
|
+
if not hasattr(cls, 'instance'): cls.instance = super(UndeployPgAgent, cls).__new__(cls)
|
|
13
|
+
|
|
14
|
+
return cls.instance
|
|
15
|
+
|
|
16
|
+
def __init__(self, successor: Command=None):
|
|
17
|
+
super().__init__(successor)
|
|
18
|
+
|
|
19
|
+
def command(self):
|
|
20
|
+
return UndeployPgAgent.COMMAND
|
|
21
|
+
|
|
22
|
+
def required(self):
|
|
23
|
+
return RequiredState.NAMESPACE
|
|
24
|
+
|
|
25
|
+
def run(self, cmd: str, state: ReplState):
|
|
26
|
+
if not(args := self.args(cmd)):
|
|
27
|
+
return super().run(cmd, state)
|
|
28
|
+
|
|
29
|
+
state, args = self.apply_state(args, state)
|
|
30
|
+
if not self.validate_state(state):
|
|
31
|
+
return state
|
|
32
|
+
|
|
33
|
+
with ing('Deleting pod'):
|
|
34
|
+
PostgresContext.undeploy_pg_agent(Config().get('pg.agent.name', 'ops-pg-agent'), state.namespace)
|
|
35
|
+
|
|
36
|
+
return state
|
|
37
|
+
|
|
38
|
+
def completion(self, state: ReplState):
|
|
39
|
+
return super().completion(state)
|
|
40
|
+
|
|
41
|
+
def help(self, _: ReplState):
|
|
42
|
+
return f'{UndeployPgAgent.COMMAND}\t undeploy Postgres agent'
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from adam.commands.command import Command
|
|
2
|
+
from adam.commands.deploy.deploy_utils import undeploy_frontend
|
|
3
|
+
from adam.config import Config
|
|
4
|
+
from adam.utils import ing
|
|
5
|
+
from adam.utils_k8s.config_maps import ConfigMaps
|
|
6
|
+
from adam.utils_k8s.deployment import Deployments
|
|
7
|
+
from adam.utils_k8s.pods import Pods
|
|
8
|
+
from adam.utils_k8s.service_accounts import ServiceAccounts
|
|
9
|
+
from adam.repl_state import ReplState, RequiredState
|
|
10
|
+
|
|
11
|
+
class UndeployPod(Command):
|
|
12
|
+
COMMAND = 'undeploy pod'
|
|
13
|
+
|
|
14
|
+
# the singleton pattern
|
|
15
|
+
def __new__(cls, *args, **kwargs):
|
|
16
|
+
if not hasattr(cls, 'instance'): cls.instance = super(UndeployPod, 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 UndeployPod.COMMAND
|
|
25
|
+
|
|
26
|
+
def required(self):
|
|
27
|
+
return RequiredState.NAMESPACE
|
|
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
|
+
label_selector = Config().get('pod.label-selector', 'run=ops')
|
|
38
|
+
with ing('Deleting service account'):
|
|
39
|
+
ServiceAccounts.delete(state.namespace, label_selector=label_selector)
|
|
40
|
+
with ing('Deleting config map'): ConfigMaps.delete_with_selector(state.namespace, label_selector)
|
|
41
|
+
with ing('Deleting deployment'): Deployments.delete_with_selector(state.namespace, label_selector, grace_period_seconds=0)
|
|
42
|
+
with ing('Deleting pod'): Pods.delete_with_selector(state.namespace, label_selector, grace_period_seconds=0)
|
|
43
|
+
undeploy_frontend(state.namespace, label_selector)
|
|
44
|
+
|
|
45
|
+
return state
|
|
46
|
+
|
|
47
|
+
def completion(self, state: ReplState):
|
|
48
|
+
return super().completion(state)
|
|
49
|
+
|
|
50
|
+
def help(self, _: ReplState):
|
|
51
|
+
return f'{UndeployPod.COMMAND}\t undeploy Ops pod'
|
|
File without changes
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
from adam.commands.command import Command
|
|
3
|
+
from adam.repl_state import ReplState
|
|
4
|
+
|
|
5
|
+
class Device:
|
|
6
|
+
@abstractmethod
|
|
7
|
+
def ls(self, cmd: str, state: ReplState):
|
|
8
|
+
pass
|
|
9
|
+
|
|
10
|
+
def ls_completion(self, cmd: str, state: ReplState, default: dict = {}):
|
|
11
|
+
return default
|
|
12
|
+
|
|
13
|
+
def cd(self, dir: str, state: ReplState):
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
def cd_completion(self, cmd: str, state: ReplState, default: dict = {}):
|
|
17
|
+
return default
|
|
18
|
+
|
|
19
|
+
@abstractmethod
|
|
20
|
+
def pwd(self, state: ReplState):
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
def try_fallback_action(self, chain: Command, state: ReplState, cmd: str):
|
|
24
|
+
return False, None
|
|
25
|
+
|
|
26
|
+
def enter(state: ReplState):
|
|
27
|
+
pass
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
from adam.apps import Apps
|
|
2
|
+
from adam.commands.bash.bash import Bash
|
|
3
|
+
from adam.commands.command import Command
|
|
4
|
+
from adam.commands.devices.device import Device
|
|
5
|
+
from adam.config import Config
|
|
6
|
+
from adam.repl_state import ReplState
|
|
7
|
+
from adam.utils import lines_to_tabular, log
|
|
8
|
+
from adam.utils_k8s.app_pods import AppPods
|
|
9
|
+
from adam.utils_k8s.ingresses import Ingresses
|
|
10
|
+
|
|
11
|
+
class DeviceApp(Command, Device):
|
|
12
|
+
COMMAND = f'{ReplState.A}:'
|
|
13
|
+
|
|
14
|
+
# the singleton pattern
|
|
15
|
+
def __new__(cls, *args, **kwargs):
|
|
16
|
+
if not hasattr(cls, 'instance'): cls.instance = super(DeviceApp, 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 DeviceApp.COMMAND
|
|
25
|
+
|
|
26
|
+
def run(self, cmd: str, state: ReplState):
|
|
27
|
+
if not self.args(cmd):
|
|
28
|
+
return super().run(cmd, state)
|
|
29
|
+
|
|
30
|
+
state.device = ReplState.A
|
|
31
|
+
|
|
32
|
+
return state
|
|
33
|
+
|
|
34
|
+
def completion(self, state: ReplState):
|
|
35
|
+
return super().completion(state)
|
|
36
|
+
|
|
37
|
+
def help(self, _: ReplState):
|
|
38
|
+
return f'{DeviceApp.COMMAND}\t move to App Operations device'
|
|
39
|
+
|
|
40
|
+
def ls(self, cmd: str, state: ReplState):
|
|
41
|
+
if state.app_pod:
|
|
42
|
+
return Bash().run('bash ' + cmd, state)
|
|
43
|
+
elif state.app_app:
|
|
44
|
+
pods = AppPods.pod_names(state.namespace, state.app_env, state.app_app)
|
|
45
|
+
|
|
46
|
+
log(lines_to_tabular(pods, 'POD_NAME'))
|
|
47
|
+
elif state.app_env:
|
|
48
|
+
def line(n: str, ns: str):
|
|
49
|
+
host = Ingresses.get_host(Config().get('app.login.ingress', '{app_id}-k8singr-appleader-001').replace('{app_id}', f'{ns}-{n}'), ns)
|
|
50
|
+
if not host:
|
|
51
|
+
return None
|
|
52
|
+
|
|
53
|
+
endpoint = Config().get('app.login.url', 'https://{host}/{env}/{app}').replace('{host}', host).replace('{env}', state.app_env).replace('{app}', 'c3')
|
|
54
|
+
if not endpoint:
|
|
55
|
+
return None
|
|
56
|
+
|
|
57
|
+
return f"{n.split('-')[1]},{Ingresses.get_host(f'{ns}-{n}-k8singr-appleader-001', ns)},{endpoint}"
|
|
58
|
+
|
|
59
|
+
svcs = [l for l in [line(n, ns) for n, ns in Apps.apps(state.app_env)] if l]
|
|
60
|
+
|
|
61
|
+
log(lines_to_tabular(svcs, 'APP,HOST,ENDPOINT', separator=','))
|
|
62
|
+
else:
|
|
63
|
+
svcs = [n for n, ns in Apps.envs()]
|
|
64
|
+
|
|
65
|
+
log(lines_to_tabular(svcs, 'ENV', separator=','))
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def ls_completion(self, cmd, state, default: dict = {}):
|
|
69
|
+
if state.app_app:
|
|
70
|
+
def pod_names():
|
|
71
|
+
return [p for p in AppPods.pod_names(state.namespace, state.app_env, state.app_app)]
|
|
72
|
+
|
|
73
|
+
return super().completion(state) | {f'@{p}': {cmd: None} for p in pod_names()}
|
|
74
|
+
|
|
75
|
+
return default
|
|
76
|
+
|
|
77
|
+
def cd(self, dir: str, state: ReplState):
|
|
78
|
+
if dir == '':
|
|
79
|
+
state.app_env = None
|
|
80
|
+
state.app_app = None
|
|
81
|
+
state.app_pod = None
|
|
82
|
+
elif dir == '..':
|
|
83
|
+
if state.app_pod:
|
|
84
|
+
state.app_pod = None
|
|
85
|
+
elif state.app_app:
|
|
86
|
+
state.app_app = None
|
|
87
|
+
else:
|
|
88
|
+
state.app_env = None
|
|
89
|
+
else:
|
|
90
|
+
if state.app_app:
|
|
91
|
+
state.app_pod = dir
|
|
92
|
+
elif not state.app_env:
|
|
93
|
+
tks = dir.split('@')
|
|
94
|
+
if len(tks) > 1:
|
|
95
|
+
state.namespace = tks[1]
|
|
96
|
+
|
|
97
|
+
state.app_env = dir.split('@')[0]
|
|
98
|
+
else:
|
|
99
|
+
state.app_app = dir
|
|
100
|
+
|
|
101
|
+
def cd_completion(self, cmd: str, state: ReplState, default: dict = {}):
|
|
102
|
+
if state.app_app:
|
|
103
|
+
return {cmd: {'..': None} | {pod: None for pod in AppPods.pod_names(state.namespace, state.app_env, state.app_app)}}
|
|
104
|
+
elif state.app_env:
|
|
105
|
+
return {cmd: {'..': None} | {app[0].split('-')[1]: None for app in Apps.apps(state.app_env)}}
|
|
106
|
+
else:
|
|
107
|
+
return {cmd: {'..': None} | {env[0]: None for env in Apps.envs()}}
|
|
108
|
+
|
|
109
|
+
def pwd(self, state: ReplState):
|
|
110
|
+
words = []
|
|
111
|
+
|
|
112
|
+
if state.app_env:
|
|
113
|
+
words.append(f'env/{state.app_env}')
|
|
114
|
+
if state.app_app:
|
|
115
|
+
words.append(f'app/{state.app_app}')
|
|
116
|
+
|
|
117
|
+
return '\t'.join([f'{ReplState.X}:>'] + (words if words else ['/']))
|
|
118
|
+
|
|
119
|
+
def try_fallback_action(self, chain: Command, state: ReplState, cmd: str):
|
|
120
|
+
if state.app_app:
|
|
121
|
+
return True, chain.run(f'app {cmd}', state)
|
|
122
|
+
|
|
123
|
+
return False, None
|
|
124
|
+
|
|
125
|
+
def enter(self, state: ReplState):
|
|
126
|
+
if not state.app_env:
|
|
127
|
+
if auto_enter := Config().get('repl.a.auto-enter', 'c3/c3/*'):
|
|
128
|
+
if auto_enter != 'no':
|
|
129
|
+
ea = auto_enter.split('/')
|
|
130
|
+
state.app_env = ea[0]
|
|
131
|
+
if len(ea) > 2:
|
|
132
|
+
state.app_app = ea[1]
|
|
133
|
+
state.app_pod = ea[2]
|
|
134
|
+
if state.app_pod == '*':
|
|
135
|
+
if (pods := AppPods.pod_names(state.namespace, ea[0], ea[1])):
|
|
136
|
+
state.app_pod = pods[0]
|
|
137
|
+
Config().wait_log(f'Moving to {state.app_env}/{state.app_app}/{state.app_pod}...')
|
|
138
|
+
else:
|
|
139
|
+
Config().wait_log(f'No pods found, moving to {state.app_env}/{state.app_app}...')
|
|
140
|
+
else:
|
|
141
|
+
Config().wait_log(f'Moving to {state.app_env}/{state.app_app}/{state.app_pod}...')
|
|
142
|
+
elif len(ea) > 1:
|
|
143
|
+
state.app_app = ea[1]
|
|
144
|
+
Config().wait_log(f'Moving to {state.app_env}/{state.app_app}...')
|
|
145
|
+
else:
|
|
146
|
+
Config().wait_log(f'Moving to {state.app_env}...')
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from adam.commands.command import Command
|
|
2
|
+
from adam.commands.devices.device import Device
|
|
3
|
+
from adam.repl_state import ReplState
|
|
4
|
+
from adam.utils import lines_to_tabular, log
|
|
5
|
+
from adam.utils_athena import Athena
|
|
6
|
+
|
|
7
|
+
class DeviceAuditLog(Command, Device):
|
|
8
|
+
COMMAND = f'{ReplState.L}:'
|
|
9
|
+
|
|
10
|
+
# the singleton pattern
|
|
11
|
+
def __new__(cls, *args, **kwargs):
|
|
12
|
+
if not hasattr(cls, 'instance'): cls.instance = super(DeviceAuditLog, cls).__new__(cls)
|
|
13
|
+
|
|
14
|
+
return cls.instance
|
|
15
|
+
|
|
16
|
+
def __init__(self, successor: Command=None):
|
|
17
|
+
super().__init__(successor)
|
|
18
|
+
|
|
19
|
+
def command(self):
|
|
20
|
+
return DeviceAuditLog.COMMAND
|
|
21
|
+
|
|
22
|
+
def run(self, cmd: str, state: ReplState):
|
|
23
|
+
if not self.args(cmd):
|
|
24
|
+
return super().run(cmd, state)
|
|
25
|
+
|
|
26
|
+
state.device = ReplState.L
|
|
27
|
+
|
|
28
|
+
return state
|
|
29
|
+
|
|
30
|
+
def completion(self, state: ReplState):
|
|
31
|
+
return super().completion(state)
|
|
32
|
+
|
|
33
|
+
def help(self, _: ReplState):
|
|
34
|
+
return f'{DeviceAuditLog.COMMAND}\t move to Audit Log Operations device'
|
|
35
|
+
|
|
36
|
+
def ls(self, cmd: str, _: ReplState):
|
|
37
|
+
log(lines_to_tabular(Athena.table_names(), 'NAME', separator=','))
|
|
38
|
+
|
|
39
|
+
def pwd(self, state: ReplState):
|
|
40
|
+
return '\t'.join([f'{ReplState.L}:>', '/'])
|
|
41
|
+
|
|
42
|
+
def try_fallback_action(self, chain: Command, state: ReplState, cmd: str):
|
|
43
|
+
return True, chain.run(f'audit {cmd}', state)
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
from adam.commands.bash.bash import Bash
|
|
2
|
+
from adam.commands.command import Command
|
|
3
|
+
from adam.commands.commands_utils import show_pods, show_rollout
|
|
4
|
+
from adam.commands.devices.device import Device
|
|
5
|
+
from adam.config import Config
|
|
6
|
+
from adam.repl_state import ReplState
|
|
7
|
+
from adam.utils import lines_to_tabular, log, log2
|
|
8
|
+
from adam.utils_k8s.cassandra_clusters import CassandraClusters
|
|
9
|
+
from adam.utils_k8s.custom_resources import CustomResources
|
|
10
|
+
from adam.utils_k8s.kube_context import KubeContext
|
|
11
|
+
from adam.utils_k8s.statefulsets import StatefulSets
|
|
12
|
+
|
|
13
|
+
class DeviceCass(Command, Device):
|
|
14
|
+
COMMAND = f'{ReplState.C}:'
|
|
15
|
+
|
|
16
|
+
# the singleton pattern
|
|
17
|
+
def __new__(cls, *args, **kwargs):
|
|
18
|
+
if not hasattr(cls, 'instance'): cls.instance = super(DeviceCass, cls).__new__(cls)
|
|
19
|
+
|
|
20
|
+
return cls.instance
|
|
21
|
+
|
|
22
|
+
def __init__(self, successor: Command=None):
|
|
23
|
+
super().__init__(successor)
|
|
24
|
+
|
|
25
|
+
def command(self):
|
|
26
|
+
return DeviceCass.COMMAND
|
|
27
|
+
|
|
28
|
+
def run(self, cmd: str, state: ReplState):
|
|
29
|
+
if not self.args(cmd):
|
|
30
|
+
return super().run(cmd, state)
|
|
31
|
+
|
|
32
|
+
state.device = ReplState.C
|
|
33
|
+
|
|
34
|
+
return state
|
|
35
|
+
|
|
36
|
+
def completion(self, state: ReplState):
|
|
37
|
+
return super().completion(state)
|
|
38
|
+
|
|
39
|
+
def help(self, _: ReplState):
|
|
40
|
+
return f'{DeviceCass.COMMAND}\t move to Cassandra Operations device'
|
|
41
|
+
|
|
42
|
+
def ls(self, cmd: str, state: ReplState):
|
|
43
|
+
if state.pod:
|
|
44
|
+
return Bash().run('bash ' + cmd, state)
|
|
45
|
+
elif state.sts and state.namespace:
|
|
46
|
+
show_pods(StatefulSets.pods(state.sts, state.namespace), state.namespace, show_namespace=not KubeContext.in_cluster_namespace())
|
|
47
|
+
show_rollout(state.sts, state.namespace)
|
|
48
|
+
else:
|
|
49
|
+
self.show_statefulsets()
|
|
50
|
+
|
|
51
|
+
def ls_completion(self, cmd: str, state: ReplState, default: dict = {}):
|
|
52
|
+
def pod_names():
|
|
53
|
+
return [p for p in StatefulSets.pod_names(state.sts, state.namespace)]
|
|
54
|
+
|
|
55
|
+
if state.sts:
|
|
56
|
+
return super().completion(state) | {f'@{p}': {'ls': None} for p in pod_names()}
|
|
57
|
+
else:
|
|
58
|
+
return {cmd: {n: None for n in StatefulSets.list_sts_names()}}
|
|
59
|
+
|
|
60
|
+
def show_statefulsets(self):
|
|
61
|
+
ss = StatefulSets.list_sts_names()
|
|
62
|
+
if len(ss) == 0:
|
|
63
|
+
log2('No Cassandra clusters found.')
|
|
64
|
+
return
|
|
65
|
+
|
|
66
|
+
app_ids = CustomResources.get_app_ids()
|
|
67
|
+
list = []
|
|
68
|
+
for s in ss:
|
|
69
|
+
cr_name = CustomResources.get_cr_name(s)
|
|
70
|
+
app_id = 'Unknown'
|
|
71
|
+
if cr_name in app_ids:
|
|
72
|
+
app_id = app_ids[cr_name]
|
|
73
|
+
list.append(f"{s} {app_id}")
|
|
74
|
+
|
|
75
|
+
header = 'STATEFULSET_NAME@NAMESPACE APP_ID'
|
|
76
|
+
if KubeContext.in_cluster_namespace():
|
|
77
|
+
header = 'STATEFULSET_NAME APP_ID'
|
|
78
|
+
log(lines_to_tabular(list, header))
|
|
79
|
+
|
|
80
|
+
def cd(self, dir: str, state: ReplState):
|
|
81
|
+
if dir == '':
|
|
82
|
+
state.sts = None
|
|
83
|
+
state.pod = None
|
|
84
|
+
elif dir == '..':
|
|
85
|
+
if state.pod:
|
|
86
|
+
state.pod = None
|
|
87
|
+
else:
|
|
88
|
+
state.sts = None
|
|
89
|
+
else:
|
|
90
|
+
if not state.sts:
|
|
91
|
+
ss_and_ns = dir.split('@')
|
|
92
|
+
state.sts = ss_and_ns[0]
|
|
93
|
+
if len(ss_and_ns) > 1:
|
|
94
|
+
state.namespace = ss_and_ns[1]
|
|
95
|
+
elif not state.pod:
|
|
96
|
+
p, _ = KubeContext.is_pod_name(dir)
|
|
97
|
+
if p:
|
|
98
|
+
state.pod = p
|
|
99
|
+
else:
|
|
100
|
+
names = CassandraClusters.pod_names_by_host_id(state.sts, state.namespace);
|
|
101
|
+
if dir in names:
|
|
102
|
+
state.pod = names[dir]
|
|
103
|
+
else:
|
|
104
|
+
log2('Not a valid pod name or host id.')
|
|
105
|
+
|
|
106
|
+
def cd_completion(self, cmd: str, state: ReplState, default: dict = {}):
|
|
107
|
+
if state.pod:
|
|
108
|
+
return {cmd: {'..': None}}
|
|
109
|
+
elif state.sts:
|
|
110
|
+
return {cmd: {'..': None} | {p: None for p in StatefulSets.pod_names(state.sts, state.namespace)}}
|
|
111
|
+
else:
|
|
112
|
+
return {cmd: {p: None for p in StatefulSets.list_sts_names()}}
|
|
113
|
+
|
|
114
|
+
def pwd(self, state: ReplState):
|
|
115
|
+
words = []
|
|
116
|
+
|
|
117
|
+
if state.sts:
|
|
118
|
+
words.append(f'sts/{state.sts}')
|
|
119
|
+
if state.pod:
|
|
120
|
+
words.append(f'pod/{state.pod}')
|
|
121
|
+
|
|
122
|
+
return '\t'.join([f'{ReplState.C}:>'] + (words if words else ['/']))
|
|
123
|
+
|
|
124
|
+
def try_fallback_action(self, chain: Command, state: ReplState, cmd: str):
|
|
125
|
+
if state.sts:
|
|
126
|
+
return True, chain.run(f'cql {cmd}', state)
|
|
127
|
+
|
|
128
|
+
return False, None
|
|
129
|
+
|
|
130
|
+
def enter(self, state: ReplState):
|
|
131
|
+
auto_enter = Config().get('repl.c.auto-enter', 'cluster')
|
|
132
|
+
if auto_enter and auto_enter in ['cluster', 'first-pod']:
|
|
133
|
+
sts = StatefulSets.list_sts_name_and_ns()
|
|
134
|
+
if not sts:
|
|
135
|
+
log2("No Cassandra clusters found.")
|
|
136
|
+
elif not state.sts and len(sts) == 1:
|
|
137
|
+
cluster = sts[0]
|
|
138
|
+
state.sts = cluster[0]
|
|
139
|
+
state.namespace = cluster[1]
|
|
140
|
+
if auto_enter == 'first-pod':
|
|
141
|
+
state.pod = f'{state.sts}-0'
|
|
142
|
+
if KubeContext().in_cluster_namespace:
|
|
143
|
+
Config().wait_log(f'Moving to the only Cassandra cluster: {state.sts}...')
|
|
144
|
+
else:
|
|
145
|
+
Config().wait_log(f'Moving to the only Cassandra cluster: {state.sts}@{state.namespace}...')
|