raijin-server 0.2.25__py3-none-any.whl → 0.2.27__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 raijin-server might be problematic. Click here for more details.
- raijin_server/__init__.py +1 -1
- raijin_server/cli.py +253 -1
- raijin_server/module_manager.py +311 -0
- raijin_server/modules/istio.py +3 -4
- raijin_server/modules/kong.py +208 -37
- raijin_server/modules/kubernetes.py +32 -1
- raijin_server/validators.py +77 -0
- {raijin_server-0.2.25.dist-info → raijin_server-0.2.27.dist-info}/METADATA +1 -1
- {raijin_server-0.2.25.dist-info → raijin_server-0.2.27.dist-info}/RECORD +13 -12
- {raijin_server-0.2.25.dist-info → raijin_server-0.2.27.dist-info}/WHEEL +0 -0
- {raijin_server-0.2.25.dist-info → raijin_server-0.2.27.dist-info}/entry_points.txt +0 -0
- {raijin_server-0.2.25.dist-info → raijin_server-0.2.27.dist-info}/licenses/LICENSE +0 -0
- {raijin_server-0.2.25.dist-info → raijin_server-0.2.27.dist-info}/top_level.txt +0 -0
raijin_server/__init__.py
CHANGED
raijin_server/cli.py
CHANGED
|
@@ -4,7 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
6
|
from pathlib import Path
|
|
7
|
-
from typing import Callable, Dict, Optional
|
|
7
|
+
from typing import Callable, Dict, List, Optional
|
|
8
8
|
|
|
9
9
|
import subprocess
|
|
10
10
|
|
|
@@ -49,6 +49,7 @@ from raijin_server.utils import ExecutionContext, logger, active_log_file, avail
|
|
|
49
49
|
from raijin_server.validators import validate_system_requirements, check_module_dependencies, MODULE_DEPENDENCIES
|
|
50
50
|
from raijin_server.healthchecks import run_health_check
|
|
51
51
|
from raijin_server.config import ConfigManager
|
|
52
|
+
from raijin_server import module_manager
|
|
52
53
|
|
|
53
54
|
app = typer.Typer(add_completion=False, help="Automacao de setup e hardening para Ubuntu Server")
|
|
54
55
|
console = Console()
|
|
@@ -838,6 +839,257 @@ def validate(skip_root: bool = typer.Option(False, "--skip-root", help="Pula val
|
|
|
838
839
|
raise typer.Exit(code=1)
|
|
839
840
|
|
|
840
841
|
|
|
842
|
+
# ============================================================================
|
|
843
|
+
# Comandos Install / Uninstall / List
|
|
844
|
+
# ============================================================================
|
|
845
|
+
|
|
846
|
+
def _get_available_modules() -> List[str]:
|
|
847
|
+
"""Retorna lista de modulos disponiveis (excluindo full_install)."""
|
|
848
|
+
return [m for m in MODULES.keys() if m != "full_install"]
|
|
849
|
+
|
|
850
|
+
|
|
851
|
+
def _register_uninstall_handlers() -> None:
|
|
852
|
+
"""Registra handlers de uninstall dos modulos que os possuem."""
|
|
853
|
+
# Mapeamento de modulos para suas funcoes de uninstall
|
|
854
|
+
handlers = {
|
|
855
|
+
"kong": kong._uninstall_kong,
|
|
856
|
+
"grafana": grafana._uninstall_grafana,
|
|
857
|
+
"velero": velero._uninstall_velero,
|
|
858
|
+
"metallb": metallb._uninstall_metallb,
|
|
859
|
+
"minio": minio._uninstall_minio,
|
|
860
|
+
"loki": loki._uninstall_loki,
|
|
861
|
+
"prometheus": lambda ctx: prometheus._uninstall_prometheus(ctx, "monitoring"),
|
|
862
|
+
"traefik": traefik._uninstall_traefik,
|
|
863
|
+
"istio": istio._uninstall_istio,
|
|
864
|
+
"kafka": kafka._uninstall_kafka,
|
|
865
|
+
"cert_manager": cert_manager._uninstall_cert_manager,
|
|
866
|
+
"calico": lambda ctx: _generic_uninstall(ctx, "calico", "calico-system", ["calico"]),
|
|
867
|
+
"secrets": lambda ctx: _uninstall_secrets(ctx),
|
|
868
|
+
"harness": lambda ctx: harness._uninstall_delegate(ctx, "harness", "harness-delegate"),
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
module_manager.UNINSTALL_HANDLERS.update(handlers)
|
|
872
|
+
|
|
873
|
+
|
|
874
|
+
def _uninstall_secrets(ctx: ExecutionContext) -> None:
|
|
875
|
+
"""Handler de uninstall para secrets (sealed-secrets + external-secrets)."""
|
|
876
|
+
secrets._uninstall_sealed_secrets(ctx, "sealed-secrets")
|
|
877
|
+
secrets._uninstall_external_secrets(ctx, "external-secrets")
|
|
878
|
+
|
|
879
|
+
|
|
880
|
+
def _generic_uninstall(ctx: ExecutionContext, module: str, namespace: str, releases: List[str]) -> None:
|
|
881
|
+
"""Handler generico de uninstall para modulos Helm."""
|
|
882
|
+
for release in releases:
|
|
883
|
+
module_manager.generic_helm_uninstall(release, namespace, ctx)
|
|
884
|
+
module_manager.cleanup_namespace(namespace, ctx)
|
|
885
|
+
|
|
886
|
+
|
|
887
|
+
@app.command()
|
|
888
|
+
def install(
|
|
889
|
+
ctx: typer.Context,
|
|
890
|
+
module: str = typer.Argument(..., help="Nome do modulo a instalar"),
|
|
891
|
+
force: bool = typer.Option(False, "--force", "-f", help="Ignora dependencias faltantes"),
|
|
892
|
+
) -> None:
|
|
893
|
+
"""Instala um modulo especifico.
|
|
894
|
+
|
|
895
|
+
Exemplo:
|
|
896
|
+
raijin-server install kong
|
|
897
|
+
raijin-server install prometheus --force
|
|
898
|
+
"""
|
|
899
|
+
available = _get_available_modules()
|
|
900
|
+
|
|
901
|
+
# Normaliza nome do modulo (aceita hifens)
|
|
902
|
+
module_normalized = module.replace("-", "_")
|
|
903
|
+
|
|
904
|
+
if module_normalized not in available:
|
|
905
|
+
typer.secho(f"Modulo '{module}' nao encontrado.", fg=typer.colors.RED)
|
|
906
|
+
typer.echo(f"\nModulos disponiveis:")
|
|
907
|
+
for m in sorted(available):
|
|
908
|
+
typer.echo(f" - {m}")
|
|
909
|
+
raise typer.Exit(code=1)
|
|
910
|
+
|
|
911
|
+
exec_ctx = ctx.obj or ExecutionContext()
|
|
912
|
+
|
|
913
|
+
# Verifica dependencias
|
|
914
|
+
if not force:
|
|
915
|
+
if not check_module_dependencies(module_normalized, exec_ctx):
|
|
916
|
+
typer.echo("\nUse --force para ignorar dependencias faltantes.")
|
|
917
|
+
raise typer.Exit(code=1)
|
|
918
|
+
|
|
919
|
+
# Mostra dependencias
|
|
920
|
+
module_manager.show_dependency_tree(module_normalized)
|
|
921
|
+
|
|
922
|
+
# Confirma instalacao
|
|
923
|
+
if not typer.confirm(f"\nInstalar modulo '{module_normalized}'?", default=True):
|
|
924
|
+
typer.secho("Instalacao cancelada.", fg=typer.colors.YELLOW)
|
|
925
|
+
raise typer.Exit(code=0)
|
|
926
|
+
|
|
927
|
+
# Executa instalacao
|
|
928
|
+
_run_module(ctx, module_normalized)
|
|
929
|
+
|
|
930
|
+
|
|
931
|
+
@app.command()
|
|
932
|
+
def uninstall(
|
|
933
|
+
ctx: typer.Context,
|
|
934
|
+
module: str = typer.Argument(..., help="Nome do modulo a desinstalar"),
|
|
935
|
+
force: bool = typer.Option(False, "--force", "-f", help="Ignora avisos de seguranca"),
|
|
936
|
+
cascade: bool = typer.Option(False, "--cascade", help="Remove tambem modulos dependentes"),
|
|
937
|
+
yes: bool = typer.Option(False, "--yes", "-y", help="Confirma automaticamente"),
|
|
938
|
+
) -> None:
|
|
939
|
+
"""Desinstala um modulo e seus recursos.
|
|
940
|
+
|
|
941
|
+
Analisa dependencias e mostra impacto antes de remover.
|
|
942
|
+
|
|
943
|
+
Exemplo:
|
|
944
|
+
raijin-server uninstall kong
|
|
945
|
+
raijin-server uninstall kubernetes --cascade
|
|
946
|
+
raijin-server uninstall prometheus --force -y
|
|
947
|
+
"""
|
|
948
|
+
available = _get_available_modules()
|
|
949
|
+
|
|
950
|
+
# Normaliza nome do modulo
|
|
951
|
+
module_normalized = module.replace("-", "_")
|
|
952
|
+
|
|
953
|
+
if module_normalized not in available:
|
|
954
|
+
typer.secho(f"Modulo '{module}' nao encontrado.", fg=typer.colors.RED)
|
|
955
|
+
raise typer.Exit(code=1)
|
|
956
|
+
|
|
957
|
+
# Registra handlers de uninstall
|
|
958
|
+
_register_uninstall_handlers()
|
|
959
|
+
|
|
960
|
+
exec_ctx = ctx.obj or ExecutionContext()
|
|
961
|
+
|
|
962
|
+
# Verifica se esta instalado
|
|
963
|
+
if not module_manager.is_module_installed(module_normalized):
|
|
964
|
+
typer.secho(f"Modulo '{module_normalized}' nao esta instalado.", fg=typer.colors.YELLOW)
|
|
965
|
+
|
|
966
|
+
# Mesmo assim, oferece limpar recursos
|
|
967
|
+
if typer.confirm("Deseja tentar limpar recursos orfaos mesmo assim?", default=False):
|
|
968
|
+
if module_normalized in module_manager.UNINSTALL_HANDLERS:
|
|
969
|
+
module_manager.UNINSTALL_HANDLERS[module_normalized](exec_ctx)
|
|
970
|
+
typer.secho("Limpeza concluida.", fg=typer.colors.GREEN)
|
|
971
|
+
raise typer.Exit(code=0)
|
|
972
|
+
|
|
973
|
+
# Mostra arvore de dependencias
|
|
974
|
+
module_manager.show_dependency_tree(module_normalized)
|
|
975
|
+
|
|
976
|
+
# Analisa impacto
|
|
977
|
+
is_safe, affected = module_manager.show_uninstall_impact(module_normalized)
|
|
978
|
+
|
|
979
|
+
if not is_safe and not force:
|
|
980
|
+
typer.secho(
|
|
981
|
+
f"\n⚠️ ATENCAO: Remover '{module_normalized}' pode quebrar {len(affected)} modulo(s)!",
|
|
982
|
+
fg=typer.colors.YELLOW,
|
|
983
|
+
bold=True,
|
|
984
|
+
)
|
|
985
|
+
|
|
986
|
+
if cascade:
|
|
987
|
+
typer.echo(f"\nModo --cascade: os seguintes modulos serao removidos primeiro:")
|
|
988
|
+
for dep in affected:
|
|
989
|
+
typer.echo(f" - {dep}")
|
|
990
|
+
|
|
991
|
+
# Confirmacao
|
|
992
|
+
if not yes:
|
|
993
|
+
if cascade and affected:
|
|
994
|
+
confirm_msg = f"Remover '{module_normalized}' e {len(affected)} dependente(s)?"
|
|
995
|
+
else:
|
|
996
|
+
confirm_msg = f"Remover '{module_normalized}'?"
|
|
997
|
+
|
|
998
|
+
if not typer.confirm(f"\n{confirm_msg}", default=False):
|
|
999
|
+
typer.secho("Operacao cancelada.", fg=typer.colors.YELLOW)
|
|
1000
|
+
raise typer.Exit(code=0)
|
|
1001
|
+
|
|
1002
|
+
# Executa uninstall
|
|
1003
|
+
success = module_manager.uninstall_module(
|
|
1004
|
+
module_normalized,
|
|
1005
|
+
exec_ctx,
|
|
1006
|
+
force=force,
|
|
1007
|
+
cascade=cascade,
|
|
1008
|
+
)
|
|
1009
|
+
|
|
1010
|
+
if success:
|
|
1011
|
+
typer.secho(f"\n✓ Modulo '{module_normalized}' removido com sucesso!", fg=typer.colors.GREEN, bold=True)
|
|
1012
|
+
else:
|
|
1013
|
+
typer.secho(f"\n✗ Falha ao remover modulo '{module_normalized}'.", fg=typer.colors.RED)
|
|
1014
|
+
raise typer.Exit(code=1)
|
|
1015
|
+
|
|
1016
|
+
|
|
1017
|
+
@app.command(name="list")
|
|
1018
|
+
def list_modules(
|
|
1019
|
+
ctx: typer.Context,
|
|
1020
|
+
installed_only: bool = typer.Option(False, "--installed", "-i", help="Mostra apenas modulos instalados"),
|
|
1021
|
+
show_deps: bool = typer.Option(False, "--deps", "-d", help="Mostra dependencias detalhadas"),
|
|
1022
|
+
) -> None:
|
|
1023
|
+
"""Lista todos os modulos e seus status de instalacao.
|
|
1024
|
+
|
|
1025
|
+
Exemplo:
|
|
1026
|
+
raijin-server list
|
|
1027
|
+
raijin-server list --installed
|
|
1028
|
+
raijin-server list --deps
|
|
1029
|
+
"""
|
|
1030
|
+
from rich.table import Table
|
|
1031
|
+
|
|
1032
|
+
table = Table(title="Modulos Raijin Server")
|
|
1033
|
+
table.add_column("Modulo", style="cyan")
|
|
1034
|
+
table.add_column("Status", justify="center")
|
|
1035
|
+
|
|
1036
|
+
if show_deps:
|
|
1037
|
+
table.add_column("Dependencias", style="yellow")
|
|
1038
|
+
table.add_column("Dependentes", style="magenta")
|
|
1039
|
+
|
|
1040
|
+
table.add_column("Descricao", style="dim", max_width=40)
|
|
1041
|
+
|
|
1042
|
+
status = module_manager.get_module_status()
|
|
1043
|
+
|
|
1044
|
+
for module_name in sorted(status.keys()):
|
|
1045
|
+
installed = status[module_name]
|
|
1046
|
+
|
|
1047
|
+
if installed_only and not installed:
|
|
1048
|
+
continue
|
|
1049
|
+
|
|
1050
|
+
status_icon = "[green]✓ Instalado[/green]" if installed else "[dim]○ Pendente[/dim]"
|
|
1051
|
+
desc = MODULE_DESCRIPTIONS.get(module_name, "")
|
|
1052
|
+
|
|
1053
|
+
if show_deps:
|
|
1054
|
+
deps = MODULE_DEPENDENCIES.get(module_name, [])
|
|
1055
|
+
deps_str = ", ".join(deps) if deps else "-"
|
|
1056
|
+
|
|
1057
|
+
from raijin_server.validators import get_reverse_dependencies
|
|
1058
|
+
rev_deps = get_reverse_dependencies(module_name)
|
|
1059
|
+
rev_deps_str = ", ".join(rev_deps) if rev_deps else "-"
|
|
1060
|
+
|
|
1061
|
+
table.add_row(module_name, status_icon, deps_str, rev_deps_str, desc)
|
|
1062
|
+
else:
|
|
1063
|
+
table.add_row(module_name, status_icon, desc)
|
|
1064
|
+
|
|
1065
|
+
console.print(table)
|
|
1066
|
+
|
|
1067
|
+
# Resumo
|
|
1068
|
+
total = len(status)
|
|
1069
|
+
installed_count = sum(1 for v in status.values() if v)
|
|
1070
|
+
console.print(f"\n[dim]Total: {total} modulos | Instalados: {installed_count} | Pendentes: {total - installed_count}[/dim]")
|
|
1071
|
+
|
|
1072
|
+
|
|
1073
|
+
@app.command()
|
|
1074
|
+
def deps(
|
|
1075
|
+
module: str = typer.Argument(..., help="Nome do modulo"),
|
|
1076
|
+
) -> None:
|
|
1077
|
+
"""Mostra arvore de dependencias de um modulo.
|
|
1078
|
+
|
|
1079
|
+
Exemplo:
|
|
1080
|
+
raijin-server deps grafana
|
|
1081
|
+
raijin-server deps kong
|
|
1082
|
+
"""
|
|
1083
|
+
available = _get_available_modules()
|
|
1084
|
+
module_normalized = module.replace("-", "_")
|
|
1085
|
+
|
|
1086
|
+
if module_normalized not in available:
|
|
1087
|
+
typer.secho(f"Modulo '{module}' nao encontrado.", fg=typer.colors.RED)
|
|
1088
|
+
raise typer.Exit(code=1)
|
|
1089
|
+
|
|
1090
|
+
module_manager.show_dependency_tree(module_normalized)
|
|
1091
|
+
|
|
1092
|
+
|
|
841
1093
|
def main_entrypoint() -> None:
|
|
842
1094
|
"""Ponto de entrada para console_scripts."""
|
|
843
1095
|
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
"""Gerenciador de instalacao e desinstalacao de modulos."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Callable, Dict, List, Optional, Tuple
|
|
8
|
+
|
|
9
|
+
import typer
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
from rich.panel import Panel
|
|
12
|
+
from rich.table import Table
|
|
13
|
+
|
|
14
|
+
from raijin_server.utils import ExecutionContext, run_cmd, logger
|
|
15
|
+
from raijin_server.validators import (
|
|
16
|
+
MODULE_DEPENDENCIES,
|
|
17
|
+
get_reverse_dependencies,
|
|
18
|
+
get_installed_dependents,
|
|
19
|
+
check_uninstall_safety,
|
|
20
|
+
check_module_dependencies,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
console = Console()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# Mapeamento de modulos para suas funcoes de uninstall
|
|
27
|
+
# Sera populado dinamicamente pelo CLI
|
|
28
|
+
UNINSTALL_HANDLERS: Dict[str, Callable[[ExecutionContext], None]] = {}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def get_state_dir() -> Path:
|
|
32
|
+
"""Retorna diretorio de estado."""
|
|
33
|
+
state_dir = Path(os.environ.get("RAIJIN_STATE_DIR", "/var/lib/raijin-server/state"))
|
|
34
|
+
if state_dir.exists():
|
|
35
|
+
return state_dir
|
|
36
|
+
alt_dir = Path.home() / ".local/share/raijin-server/state"
|
|
37
|
+
return alt_dir
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def is_module_installed(module: str) -> bool:
|
|
41
|
+
"""Verifica se um modulo esta instalado (tem arquivo .done)."""
|
|
42
|
+
state_dir = get_state_dir()
|
|
43
|
+
state_file = state_dir / f"{module}.done"
|
|
44
|
+
return state_file.exists()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def mark_module_uninstalled(module: str) -> None:
|
|
48
|
+
"""Remove marcador de instalacao do modulo."""
|
|
49
|
+
state_dir = get_state_dir()
|
|
50
|
+
state_file = state_dir / f"{module}.done"
|
|
51
|
+
if state_file.exists():
|
|
52
|
+
state_file.unlink()
|
|
53
|
+
logger.info(f"Marcador de estado removido: {state_file}")
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def get_module_status() -> Dict[str, bool]:
|
|
57
|
+
"""Retorna status de instalacao de todos os modulos."""
|
|
58
|
+
from raijin_server.cli import MODULES
|
|
59
|
+
|
|
60
|
+
status = {}
|
|
61
|
+
for module in MODULES.keys():
|
|
62
|
+
if module == "full_install":
|
|
63
|
+
continue
|
|
64
|
+
status[module] = is_module_installed(module)
|
|
65
|
+
return status
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def show_dependency_tree(module: str) -> None:
|
|
69
|
+
"""Exibe arvore de dependencias de um modulo."""
|
|
70
|
+
console.print(f"\n[bold cyan]Arvore de dependencias para '{module}':[/bold cyan]")
|
|
71
|
+
|
|
72
|
+
# Dependencias (o que este modulo precisa)
|
|
73
|
+
deps = MODULE_DEPENDENCIES.get(module, [])
|
|
74
|
+
if deps:
|
|
75
|
+
console.print(f"\n[yellow]Requer (dependencias):[/yellow]")
|
|
76
|
+
for dep in deps:
|
|
77
|
+
installed = "✓" if is_module_installed(dep) else "✗"
|
|
78
|
+
color = "green" if is_module_installed(dep) else "red"
|
|
79
|
+
console.print(f" [{color}]{installed}[/{color}] {dep}")
|
|
80
|
+
else:
|
|
81
|
+
console.print(f"\n[dim]Nenhuma dependencia[/dim]")
|
|
82
|
+
|
|
83
|
+
# Dependentes (quem depende deste modulo)
|
|
84
|
+
dependents = get_reverse_dependencies(module)
|
|
85
|
+
if dependents:
|
|
86
|
+
console.print(f"\n[yellow]Dependentes (quem usa este modulo):[/yellow]")
|
|
87
|
+
for dep in dependents:
|
|
88
|
+
installed = "✓" if is_module_installed(dep) else "○"
|
|
89
|
+
color = "green" if is_module_installed(dep) else "dim"
|
|
90
|
+
console.print(f" [{color}]{installed}[/{color}] {dep}")
|
|
91
|
+
else:
|
|
92
|
+
console.print(f"\n[dim]Nenhum modulo depende deste[/dim]")
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def show_uninstall_impact(module: str) -> Tuple[bool, List[str]]:
|
|
96
|
+
"""Mostra impacto da remocao e retorna se e seguro."""
|
|
97
|
+
is_safe, affected, warning = check_uninstall_safety(module)
|
|
98
|
+
|
|
99
|
+
if not is_safe:
|
|
100
|
+
console.print(Panel(
|
|
101
|
+
warning,
|
|
102
|
+
title="⚠️ AVISO DE IMPACTO",
|
|
103
|
+
border_style="yellow",
|
|
104
|
+
))
|
|
105
|
+
|
|
106
|
+
# Mostra arvore de impacto detalhada
|
|
107
|
+
table = Table(title="Modulos que serao afetados")
|
|
108
|
+
table.add_column("Modulo", style="red")
|
|
109
|
+
table.add_column("Status", style="yellow")
|
|
110
|
+
table.add_column("Depende de", style="cyan")
|
|
111
|
+
|
|
112
|
+
for mod in affected:
|
|
113
|
+
deps = MODULE_DEPENDENCIES.get(mod, [])
|
|
114
|
+
relevant_deps = [d for d in deps if d == module or d in affected]
|
|
115
|
+
table.add_row(
|
|
116
|
+
mod,
|
|
117
|
+
"Instalado" if is_module_installed(mod) else "Nao instalado",
|
|
118
|
+
", ".join(relevant_deps)
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
console.print(table)
|
|
122
|
+
console.print()
|
|
123
|
+
|
|
124
|
+
return is_safe, affected
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def uninstall_module(
|
|
128
|
+
module: str,
|
|
129
|
+
ctx: ExecutionContext,
|
|
130
|
+
force: bool = False,
|
|
131
|
+
cascade: bool = False,
|
|
132
|
+
) -> bool:
|
|
133
|
+
"""Desinstala um modulo com verificacao de seguranca.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
module: Nome do modulo a desinstalar
|
|
137
|
+
ctx: Contexto de execucao
|
|
138
|
+
force: Ignora avisos de seguranca
|
|
139
|
+
cascade: Remove tambem os modulos dependentes
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
True se desinstalou com sucesso
|
|
143
|
+
"""
|
|
144
|
+
if not is_module_installed(module):
|
|
145
|
+
typer.secho(f"Modulo '{module}' nao esta instalado.", fg=typer.colors.YELLOW)
|
|
146
|
+
return False
|
|
147
|
+
|
|
148
|
+
# Verifica seguranca
|
|
149
|
+
is_safe, affected = show_uninstall_impact(module)
|
|
150
|
+
|
|
151
|
+
if not is_safe and not force:
|
|
152
|
+
if cascade:
|
|
153
|
+
# Desinstala dependentes primeiro (ordem reversa)
|
|
154
|
+
console.print(f"\n[yellow]Modo cascade: removendo dependentes primeiro...[/yellow]")
|
|
155
|
+
for dep in reversed(affected):
|
|
156
|
+
if is_module_installed(dep):
|
|
157
|
+
console.print(f"\n[cyan]Removendo {dep}...[/cyan]")
|
|
158
|
+
uninstall_module(dep, ctx, force=True, cascade=False)
|
|
159
|
+
else:
|
|
160
|
+
confirm = typer.confirm(
|
|
161
|
+
"\nDeseja continuar mesmo assim? (os modulos afetados podem parar de funcionar)",
|
|
162
|
+
default=False,
|
|
163
|
+
)
|
|
164
|
+
if not confirm:
|
|
165
|
+
typer.secho("Operacao cancelada.", fg=typer.colors.YELLOW)
|
|
166
|
+
return False
|
|
167
|
+
|
|
168
|
+
# Executa uninstall especifico se disponivel
|
|
169
|
+
if module in UNINSTALL_HANDLERS:
|
|
170
|
+
typer.echo(f"\nExecutando uninstall de '{module}'...")
|
|
171
|
+
try:
|
|
172
|
+
UNINSTALL_HANDLERS[module](ctx)
|
|
173
|
+
except Exception as e:
|
|
174
|
+
typer.secho(f"Erro durante uninstall: {e}", fg=typer.colors.RED)
|
|
175
|
+
if not force:
|
|
176
|
+
return False
|
|
177
|
+
else:
|
|
178
|
+
# Uninstall generico - apenas remove marcador
|
|
179
|
+
typer.secho(
|
|
180
|
+
f"Modulo '{module}' nao tem handler de uninstall especifico.",
|
|
181
|
+
fg=typer.colors.YELLOW,
|
|
182
|
+
)
|
|
183
|
+
typer.echo("Apenas o marcador de estado sera removido.")
|
|
184
|
+
typer.echo("Recursos no cluster podem precisar de remocao manual.")
|
|
185
|
+
|
|
186
|
+
# Remove marcador de estado
|
|
187
|
+
mark_module_uninstalled(module)
|
|
188
|
+
typer.secho(f"✓ Modulo '{module}' marcado como desinstalado.", fg=typer.colors.GREEN)
|
|
189
|
+
|
|
190
|
+
return True
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def list_modules_status() -> None:
|
|
194
|
+
"""Lista todos os modulos e seus status."""
|
|
195
|
+
from raijin_server.cli import MODULE_DESCRIPTIONS
|
|
196
|
+
|
|
197
|
+
table = Table(title="Status dos Modulos Raijin")
|
|
198
|
+
table.add_column("Modulo", style="cyan")
|
|
199
|
+
table.add_column("Status", justify="center")
|
|
200
|
+
table.add_column("Dependencias")
|
|
201
|
+
table.add_column("Descricao", style="dim")
|
|
202
|
+
|
|
203
|
+
status = get_module_status()
|
|
204
|
+
|
|
205
|
+
for module, installed in sorted(status.items()):
|
|
206
|
+
status_icon = "[green]✓ Instalado[/green]" if installed else "[dim]○ Nao instalado[/dim]"
|
|
207
|
+
deps = MODULE_DEPENDENCIES.get(module, [])
|
|
208
|
+
deps_str = ", ".join(deps) if deps else "-"
|
|
209
|
+
desc = MODULE_DESCRIPTIONS.get(module, "")[:40]
|
|
210
|
+
if len(MODULE_DESCRIPTIONS.get(module, "")) > 40:
|
|
211
|
+
desc += "..."
|
|
212
|
+
|
|
213
|
+
table.add_row(module, status_icon, deps_str, desc)
|
|
214
|
+
|
|
215
|
+
console.print(table)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def check_kubernetes_resource(resource_type: str, name: str, namespace: str = "") -> bool:
|
|
219
|
+
"""Verifica se um recurso Kubernetes existe."""
|
|
220
|
+
cmd = ["kubectl", "get", resource_type, name]
|
|
221
|
+
if namespace:
|
|
222
|
+
cmd.extend(["-n", namespace])
|
|
223
|
+
|
|
224
|
+
import subprocess
|
|
225
|
+
result = subprocess.run(cmd, capture_output=True, text=True)
|
|
226
|
+
return result.returncode == 0
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def generic_helm_uninstall(release_name: str, namespace: str, ctx: ExecutionContext) -> bool:
|
|
230
|
+
"""Desinstala um release Helm de forma generica."""
|
|
231
|
+
typer.echo(f"Removendo release Helm '{release_name}' do namespace '{namespace}'...")
|
|
232
|
+
|
|
233
|
+
# Verifica se existe
|
|
234
|
+
result = run_cmd(
|
|
235
|
+
["helm", "status", release_name, "-n", namespace],
|
|
236
|
+
ctx,
|
|
237
|
+
check=False,
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
if result.returncode != 0:
|
|
241
|
+
typer.echo(f"Release '{release_name}' nao encontrado.")
|
|
242
|
+
return False
|
|
243
|
+
|
|
244
|
+
# Remove release
|
|
245
|
+
result = run_cmd(
|
|
246
|
+
["helm", "uninstall", release_name, "-n", namespace],
|
|
247
|
+
ctx,
|
|
248
|
+
check=False,
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
if result.returncode == 0:
|
|
252
|
+
typer.secho(f"✓ Release '{release_name}' removido.", fg=typer.colors.GREEN)
|
|
253
|
+
return True
|
|
254
|
+
else:
|
|
255
|
+
typer.secho(f"✗ Falha ao remover release '{release_name}'.", fg=typer.colors.RED)
|
|
256
|
+
return False
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def cleanup_namespace(namespace: str, ctx: ExecutionContext, wait: bool = True) -> bool:
|
|
260
|
+
"""Remove um namespace do Kubernetes."""
|
|
261
|
+
typer.echo(f"Removendo namespace '{namespace}'...")
|
|
262
|
+
|
|
263
|
+
result = run_cmd(
|
|
264
|
+
["kubectl", "delete", "namespace", namespace, "--ignore-not-found"],
|
|
265
|
+
ctx,
|
|
266
|
+
check=False,
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
if wait and result.returncode == 0:
|
|
270
|
+
import time
|
|
271
|
+
# Aguarda namespace ser removido
|
|
272
|
+
deadline = time.time() + 60
|
|
273
|
+
while time.time() < deadline:
|
|
274
|
+
check = run_cmd(
|
|
275
|
+
["kubectl", "get", "namespace", namespace],
|
|
276
|
+
ctx,
|
|
277
|
+
check=False,
|
|
278
|
+
)
|
|
279
|
+
if check.returncode != 0:
|
|
280
|
+
break
|
|
281
|
+
time.sleep(5)
|
|
282
|
+
|
|
283
|
+
return result.returncode == 0
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def cleanup_crds(pattern: str, ctx: ExecutionContext) -> int:
|
|
287
|
+
"""Remove CRDs que correspondem ao padrao."""
|
|
288
|
+
import subprocess
|
|
289
|
+
|
|
290
|
+
# Lista CRDs
|
|
291
|
+
result = subprocess.run(
|
|
292
|
+
["kubectl", "get", "crd", "-o", "name"],
|
|
293
|
+
capture_output=True,
|
|
294
|
+
text=True,
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
if result.returncode != 0:
|
|
298
|
+
return 0
|
|
299
|
+
|
|
300
|
+
removed = 0
|
|
301
|
+
for line in result.stdout.strip().split("\n"):
|
|
302
|
+
if pattern in line:
|
|
303
|
+
crd_name = line.replace("customresourcedefinition.apiextensions.k8s.io/", "")
|
|
304
|
+
run_cmd(
|
|
305
|
+
["kubectl", "delete", "crd", crd_name, "--ignore-not-found"],
|
|
306
|
+
ctx,
|
|
307
|
+
check=False,
|
|
308
|
+
)
|
|
309
|
+
removed += 1
|
|
310
|
+
|
|
311
|
+
return removed
|
raijin_server/modules/istio.py
CHANGED
|
@@ -147,6 +147,9 @@ metadata:
|
|
|
147
147
|
namespace: istio-system
|
|
148
148
|
spec:
|
|
149
149
|
profile: {profile}
|
|
150
|
+
meshConfig:
|
|
151
|
+
defaultConfig:
|
|
152
|
+
holdApplicationUntilProxyStarts: true
|
|
150
153
|
components:
|
|
151
154
|
pilot:
|
|
152
155
|
enabled: true
|
|
@@ -175,10 +178,6 @@ spec:
|
|
|
175
178
|
kubernetes.io/hostname: {node_name}
|
|
176
179
|
service:
|
|
177
180
|
type: {service_type}
|
|
178
|
-
values:
|
|
179
|
-
global:
|
|
180
|
-
proxy:
|
|
181
|
-
holdApplicationUntilProxyStarts: true
|
|
182
181
|
"""
|
|
183
182
|
|
|
184
183
|
config_path = Path("/tmp/raijin-istio-config.yaml")
|
raijin_server/modules/kong.py
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import socket
|
|
4
4
|
import time
|
|
5
|
+
from pathlib import Path
|
|
5
6
|
|
|
6
7
|
import typer
|
|
7
8
|
|
|
8
|
-
from raijin_server.utils import ExecutionContext, helm_upgrade_install, require_root, run_cmd
|
|
9
|
+
from raijin_server.utils import ExecutionContext, helm_upgrade_install, require_root, run_cmd, write_file
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
def _detect_node_name(ctx: ExecutionContext) -> str:
|
|
@@ -20,6 +21,26 @@ def _detect_node_name(ctx: ExecutionContext) -> str:
|
|
|
20
21
|
return socket.gethostname()
|
|
21
22
|
|
|
22
23
|
|
|
24
|
+
def _check_metallb_installed(ctx: ExecutionContext) -> bool:
|
|
25
|
+
"""Verifica se MetalLB está instalado no cluster."""
|
|
26
|
+
result = run_cmd(
|
|
27
|
+
["kubectl", "get", "deployment", "metallb-controller", "-n", "metallb-system"],
|
|
28
|
+
ctx,
|
|
29
|
+
check=False,
|
|
30
|
+
)
|
|
31
|
+
return result.returncode == 0
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _check_cert_manager_installed(ctx: ExecutionContext) -> bool:
|
|
35
|
+
"""Verifica se cert-manager está instalado no cluster."""
|
|
36
|
+
result = run_cmd(
|
|
37
|
+
["kubectl", "get", "deployment", "cert-manager", "-n", "cert-manager"],
|
|
38
|
+
ctx,
|
|
39
|
+
check=False,
|
|
40
|
+
)
|
|
41
|
+
return result.returncode == 0
|
|
42
|
+
|
|
43
|
+
|
|
23
44
|
def _check_existing_kong(ctx: ExecutionContext) -> bool:
|
|
24
45
|
"""Verifica se existe instalacao do Kong."""
|
|
25
46
|
result = run_cmd(
|
|
@@ -30,6 +51,42 @@ def _check_existing_kong(ctx: ExecutionContext) -> bool:
|
|
|
30
51
|
return result.returncode == 0
|
|
31
52
|
|
|
32
53
|
|
|
54
|
+
def _check_orphan_crds(ctx: ExecutionContext) -> list[str]:
|
|
55
|
+
"""Detecta CRDs orfaos do Kong (sem ownership do Helm)."""
|
|
56
|
+
result = run_cmd(
|
|
57
|
+
["kubectl", "get", "crd", "-o", "name"],
|
|
58
|
+
ctx,
|
|
59
|
+
check=False,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
if result.returncode != 0:
|
|
63
|
+
return []
|
|
64
|
+
|
|
65
|
+
kong_crds = []
|
|
66
|
+
for line in (result.stdout or "").strip().split("\n"):
|
|
67
|
+
if "konghq.com" in line:
|
|
68
|
+
# Extrai nome do CRD
|
|
69
|
+
crd_name = line.replace("customresourcedefinition.apiextensions.k8s.io/", "")
|
|
70
|
+
kong_crds.append(crd_name)
|
|
71
|
+
|
|
72
|
+
return kong_crds
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _cleanup_orphan_crds(ctx: ExecutionContext, crds: list[str]) -> None:
|
|
76
|
+
"""Remove CRDs orfaos do Kong."""
|
|
77
|
+
typer.echo(f"Removendo {len(crds)} CRDs orfaos do Kong...")
|
|
78
|
+
|
|
79
|
+
for crd in crds:
|
|
80
|
+
run_cmd(
|
|
81
|
+
["kubectl", "delete", "crd", crd, "--ignore-not-found"],
|
|
82
|
+
ctx,
|
|
83
|
+
check=False,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
time.sleep(3)
|
|
87
|
+
typer.secho(" CRDs orfaos removidos.", fg=typer.colors.GREEN)
|
|
88
|
+
|
|
89
|
+
|
|
33
90
|
def _uninstall_kong(ctx: ExecutionContext) -> None:
|
|
34
91
|
"""Remove instalacao anterior do Kong."""
|
|
35
92
|
typer.echo("Removendo instalacao anterior do Kong...")
|
|
@@ -100,45 +157,121 @@ def run(ctx: ExecutionContext) -> None:
|
|
|
100
157
|
)
|
|
101
158
|
if cleanup:
|
|
102
159
|
_uninstall_kong(ctx)
|
|
160
|
+
|
|
161
|
+
# Verificar CRDs orfaos (sem ownership do Helm)
|
|
162
|
+
orphan_crds = _check_orphan_crds(ctx)
|
|
163
|
+
if orphan_crds:
|
|
164
|
+
typer.secho(
|
|
165
|
+
f"\n⚠️ Detectados {len(orphan_crds)} CRDs orfaos do Kong (sem ownership do Helm):",
|
|
166
|
+
fg=typer.colors.YELLOW,
|
|
167
|
+
)
|
|
168
|
+
for crd in orphan_crds[:5]:
|
|
169
|
+
typer.echo(f" - {crd}")
|
|
170
|
+
if len(orphan_crds) > 5:
|
|
171
|
+
typer.echo(f" ... e mais {len(orphan_crds) - 5}")
|
|
172
|
+
|
|
173
|
+
cleanup_crds = typer.confirm(
|
|
174
|
+
"\nRemover CRDs orfaos para permitir instalacao limpa?",
|
|
175
|
+
default=True,
|
|
176
|
+
)
|
|
177
|
+
if cleanup_crds:
|
|
178
|
+
_cleanup_orphan_crds(ctx, orphan_crds)
|
|
179
|
+
else:
|
|
180
|
+
typer.secho(
|
|
181
|
+
"AVISO: A instalacao pode falhar devido aos CRDs orfaos.",
|
|
182
|
+
fg=typer.colors.YELLOW,
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
# Detectar dependencias
|
|
186
|
+
has_metallb = _check_metallb_installed(ctx)
|
|
187
|
+
has_cert_manager = _check_cert_manager_installed(ctx)
|
|
188
|
+
|
|
189
|
+
# Tipo de servico baseado na presenca do MetalLB
|
|
190
|
+
if has_metallb:
|
|
191
|
+
typer.secho("✓ MetalLB detectado. Kong usará LoadBalancer.", fg=typer.colors.GREEN)
|
|
192
|
+
service_type = "LoadBalancer"
|
|
193
|
+
else:
|
|
194
|
+
typer.secho("⚠ MetalLB não detectado. Kong usará NodePort.", fg=typer.colors.YELLOW)
|
|
195
|
+
service_type = "NodePort"
|
|
196
|
+
|
|
197
|
+
if has_cert_manager:
|
|
198
|
+
typer.secho("✓ cert-manager detectado. TLS automático disponível.", fg=typer.colors.GREEN)
|
|
199
|
+
else:
|
|
200
|
+
typer.secho("⚠ cert-manager não detectado. Configure TLS manualmente.", fg=typer.colors.YELLOW)
|
|
103
201
|
|
|
104
202
|
# Configuracoes interativas
|
|
105
203
|
enable_admin = typer.confirm("Habilitar Admin API (para gerenciamento)?", default=True)
|
|
204
|
+
enable_metrics = typer.confirm("Habilitar métricas Prometheus?", default=True)
|
|
106
205
|
db_mode = typer.prompt(
|
|
107
206
|
"Modo de banco de dados (dbless/postgres)",
|
|
108
|
-
default="
|
|
207
|
+
default="postgres",
|
|
109
208
|
)
|
|
110
209
|
|
|
111
210
|
node_name = _detect_node_name(ctx)
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
211
|
+
|
|
212
|
+
# Usar arquivo YAML para configurações complexas (mais confiável que --set)
|
|
213
|
+
values_yaml = f"""env:
|
|
214
|
+
database: {db_mode}
|
|
215
|
+
|
|
216
|
+
ingressController:
|
|
217
|
+
installCRDs: true
|
|
218
|
+
enabled: true
|
|
219
|
+
|
|
220
|
+
proxy:
|
|
221
|
+
enabled: true
|
|
222
|
+
type: {service_type}
|
|
223
|
+
http:
|
|
224
|
+
enabled: true
|
|
225
|
+
containerPort: 8000
|
|
226
|
+
servicePort: 80
|
|
227
|
+
tls:
|
|
228
|
+
enabled: true
|
|
229
|
+
containerPort: 8443
|
|
230
|
+
servicePort: 443
|
|
231
|
+
|
|
232
|
+
admin:
|
|
233
|
+
enabled: {str(enable_admin).lower()}
|
|
234
|
+
type: ClusterIP
|
|
235
|
+
http:
|
|
236
|
+
enabled: true
|
|
237
|
+
|
|
238
|
+
tolerations:
|
|
239
|
+
- key: node-role.kubernetes.io/control-plane
|
|
240
|
+
operator: Exists
|
|
241
|
+
effect: NoSchedule
|
|
242
|
+
- key: node-role.kubernetes.io/master
|
|
243
|
+
operator: Exists
|
|
244
|
+
effect: NoSchedule
|
|
245
|
+
|
|
246
|
+
nodeSelector:
|
|
247
|
+
kubernetes.io/hostname: {node_name}
|
|
248
|
+
|
|
249
|
+
resources:
|
|
250
|
+
requests:
|
|
251
|
+
memory: 256Mi
|
|
252
|
+
cpu: 100m
|
|
253
|
+
limits:
|
|
254
|
+
memory: 1Gi
|
|
255
|
+
"""
|
|
256
|
+
|
|
257
|
+
# Adicionar métricas se habilitado
|
|
258
|
+
if enable_metrics:
|
|
259
|
+
values_yaml += """
|
|
260
|
+
serviceMonitor:
|
|
261
|
+
enabled: true
|
|
262
|
+
namespace: kong
|
|
263
|
+
labels:
|
|
264
|
+
release: kube-prometheus-stack
|
|
265
|
+
|
|
266
|
+
podAnnotations:
|
|
267
|
+
prometheus.io/scrape: "true"
|
|
268
|
+
prometheus.io/port: "8100"
|
|
269
|
+
"""
|
|
270
|
+
|
|
271
|
+
values_path = Path("/tmp/raijin-kong-values.yaml")
|
|
272
|
+
write_file(values_path, values_yaml, ctx)
|
|
273
|
+
|
|
274
|
+
run_cmd(["kubectl", "create", "namespace", "kong"], ctx, check=False)
|
|
142
275
|
|
|
143
276
|
helm_upgrade_install(
|
|
144
277
|
release="kong",
|
|
@@ -147,7 +280,8 @@ def run(ctx: ExecutionContext) -> None:
|
|
|
147
280
|
repo="kong",
|
|
148
281
|
repo_url="https://charts.konghq.com",
|
|
149
282
|
ctx=ctx,
|
|
150
|
-
values=
|
|
283
|
+
values=[],
|
|
284
|
+
extra_args=["-f", str(values_path)],
|
|
151
285
|
)
|
|
152
286
|
|
|
153
287
|
# Aguarda pods ficarem prontos
|
|
@@ -155,9 +289,46 @@ def run(ctx: ExecutionContext) -> None:
|
|
|
155
289
|
_wait_for_kong_ready(ctx)
|
|
156
290
|
|
|
157
291
|
# Mostra informacoes uteis
|
|
158
|
-
typer.secho("\n✓ Kong instalado com sucesso.", fg=typer.colors.GREEN, bold=True)
|
|
159
|
-
|
|
160
|
-
typer.echo("
|
|
292
|
+
typer.secho("\n✓ Kong Gateway instalado com sucesso.", fg=typer.colors.GREEN, bold=True)
|
|
293
|
+
|
|
294
|
+
typer.echo("\n📌 Acesso ao Kong Proxy:")
|
|
295
|
+
if service_type == "LoadBalancer":
|
|
296
|
+
typer.echo(" kubectl -n kong get svc kong-kong-proxy # Aguarde EXTERNAL-IP")
|
|
297
|
+
else:
|
|
298
|
+
typer.echo(" kubectl -n kong get svc kong-kong-proxy # Use NodePort")
|
|
299
|
+
|
|
161
300
|
if enable_admin:
|
|
162
|
-
typer.echo("\
|
|
301
|
+
typer.echo("\n📌 Admin API (port-forward):")
|
|
163
302
|
typer.echo(" kubectl -n kong port-forward svc/kong-kong-admin 8001:8001")
|
|
303
|
+
typer.echo(" curl http://localhost:8001/status")
|
|
304
|
+
|
|
305
|
+
if enable_metrics:
|
|
306
|
+
typer.echo("\n📌 Métricas Prometheus:")
|
|
307
|
+
typer.echo(" ServiceMonitor criado - métricas serão coletadas automaticamente")
|
|
308
|
+
|
|
309
|
+
if has_cert_manager:
|
|
310
|
+
typer.echo("\n📌 TLS com cert-manager (exemplo de Ingress):")
|
|
311
|
+
typer.echo(""" ---
|
|
312
|
+
apiVersion: networking.k8s.io/v1
|
|
313
|
+
kind: Ingress
|
|
314
|
+
metadata:
|
|
315
|
+
name: my-api
|
|
316
|
+
annotations:
|
|
317
|
+
cert-manager.io/cluster-issuer: letsencrypt-prod
|
|
318
|
+
konghq.com/strip-path: "true"
|
|
319
|
+
spec:
|
|
320
|
+
ingressClassName: kong
|
|
321
|
+
tls:
|
|
322
|
+
- hosts: [api.example.com]
|
|
323
|
+
secretName: api-tls
|
|
324
|
+
rules:
|
|
325
|
+
- host: api.example.com
|
|
326
|
+
http:
|
|
327
|
+
paths:
|
|
328
|
+
- path: /
|
|
329
|
+
pathType: Prefix
|
|
330
|
+
backend:
|
|
331
|
+
service:
|
|
332
|
+
name: my-service
|
|
333
|
+
port:
|
|
334
|
+
number: 80""")
|
|
@@ -269,7 +269,7 @@ scheduler: {{}}
|
|
|
269
269
|
---
|
|
270
270
|
apiVersion: kubeproxy.config.k8s.io/v1alpha1
|
|
271
271
|
kind: KubeProxyConfiguration
|
|
272
|
-
mode:
|
|
272
|
+
mode: iptables
|
|
273
273
|
---
|
|
274
274
|
apiVersion: kubelet.config.k8s.io/v1beta1
|
|
275
275
|
kind: KubeletConfiguration
|
|
@@ -331,3 +331,34 @@ cgroupDriver: systemd
|
|
|
331
331
|
"--all",
|
|
332
332
|
"--timeout=180s",
|
|
333
333
|
], ctx, check=False)
|
|
334
|
+
|
|
335
|
+
# Em clusters single-node, perguntar se deve remover taint do control-plane
|
|
336
|
+
# para permitir que workloads rodem no mesmo node
|
|
337
|
+
typer.secho("\n📌 Configuração de Single-Node Cluster", fg=typer.colors.CYAN, bold=True)
|
|
338
|
+
typer.echo("Se este for um cluster single-node (apenas este servidor),")
|
|
339
|
+
typer.echo("é necessário remover o taint do control-plane para permitir workloads.")
|
|
340
|
+
|
|
341
|
+
remove_taint = typer.confirm(
|
|
342
|
+
"Remover taint do control-plane (necessário para single-node)?",
|
|
343
|
+
default=True,
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
if remove_taint:
|
|
347
|
+
typer.echo("Removendo taint node-role.kubernetes.io/control-plane...")
|
|
348
|
+
run_cmd(
|
|
349
|
+
["kubectl", "taint", "nodes", "--all", "node-role.kubernetes.io/control-plane-", "--overwrite"],
|
|
350
|
+
ctx,
|
|
351
|
+
check=False,
|
|
352
|
+
)
|
|
353
|
+
typer.secho("✓ Taint removido. Workloads podem rodar neste node.", fg=typer.colors.GREEN)
|
|
354
|
+
else:
|
|
355
|
+
typer.secho(
|
|
356
|
+
"⚠ Taint mantido. Workloads precisarão de tolerations ou worker nodes.",
|
|
357
|
+
fg=typer.colors.YELLOW,
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
typer.secho("\n✓ Kubernetes instalado com sucesso!", fg=typer.colors.GREEN, bold=True)
|
|
361
|
+
typer.echo("\nPróximos passos:")
|
|
362
|
+
typer.echo(" raijin-server install metallb # LoadBalancer para bare-metal")
|
|
363
|
+
typer.echo(" raijin-server install traefik # Ingress Controller")
|
|
364
|
+
typer.echo(" raijin-server install cert-manager # Certificados TLS automáticos")
|
raijin_server/validators.py
CHANGED
|
@@ -269,3 +269,80 @@ def check_module_dependencies(module: str, ctx: ExecutionContext) -> bool:
|
|
|
269
269
|
return False
|
|
270
270
|
|
|
271
271
|
return True
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def get_reverse_dependencies(module: str) -> List[str]:
|
|
275
|
+
"""Retorna lista de modulos que dependem do modulo especificado.
|
|
276
|
+
|
|
277
|
+
Args:
|
|
278
|
+
module: Nome do modulo para verificar dependencias reversas
|
|
279
|
+
|
|
280
|
+
Returns:
|
|
281
|
+
Lista de modulos que dependem deste modulo
|
|
282
|
+
"""
|
|
283
|
+
dependents = []
|
|
284
|
+
for mod, deps in MODULE_DEPENDENCIES.items():
|
|
285
|
+
if module in deps:
|
|
286
|
+
dependents.append(mod)
|
|
287
|
+
return dependents
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def get_installed_dependents(module: str) -> List[str]:
|
|
291
|
+
"""Retorna lista de modulos instalados que dependem do modulo especificado.
|
|
292
|
+
|
|
293
|
+
Args:
|
|
294
|
+
module: Nome do modulo para verificar
|
|
295
|
+
|
|
296
|
+
Returns:
|
|
297
|
+
Lista de modulos instalados que dependem deste modulo
|
|
298
|
+
"""
|
|
299
|
+
state_dir = Path(os.environ.get("RAIJIN_STATE_DIR", "/var/lib/raijin-server/state"))
|
|
300
|
+
if not state_dir.exists():
|
|
301
|
+
state_dir = Path.home() / ".local/share/raijin-server/state"
|
|
302
|
+
|
|
303
|
+
dependents = get_reverse_dependencies(module)
|
|
304
|
+
installed = []
|
|
305
|
+
|
|
306
|
+
for dep in dependents:
|
|
307
|
+
state_file = state_dir / f"{dep}.done"
|
|
308
|
+
if state_file.exists():
|
|
309
|
+
installed.append(dep)
|
|
310
|
+
|
|
311
|
+
return installed
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def check_uninstall_safety(module: str) -> Tuple[bool, List[str], str]:
|
|
315
|
+
"""Verifica se e seguro remover um modulo.
|
|
316
|
+
|
|
317
|
+
Args:
|
|
318
|
+
module: Nome do modulo a ser removido
|
|
319
|
+
|
|
320
|
+
Returns:
|
|
321
|
+
Tupla (is_safe, affected_modules, warning_message)
|
|
322
|
+
"""
|
|
323
|
+
installed_dependents = get_installed_dependents(module)
|
|
324
|
+
|
|
325
|
+
if not installed_dependents:
|
|
326
|
+
return True, [], ""
|
|
327
|
+
|
|
328
|
+
# Constroi arvore de impacto (recursivo)
|
|
329
|
+
all_affected = set(installed_dependents)
|
|
330
|
+
to_check = list(installed_dependents)
|
|
331
|
+
|
|
332
|
+
while to_check:
|
|
333
|
+
current = to_check.pop(0)
|
|
334
|
+
sub_dependents = get_installed_dependents(current)
|
|
335
|
+
for sub in sub_dependents:
|
|
336
|
+
if sub not in all_affected:
|
|
337
|
+
all_affected.add(sub)
|
|
338
|
+
to_check.append(sub)
|
|
339
|
+
|
|
340
|
+
affected_list = sorted(list(all_affected))
|
|
341
|
+
|
|
342
|
+
warning = f"AVISO: Remover '{module}' afetara os seguintes modulos instalados:\n"
|
|
343
|
+
for dep in affected_list:
|
|
344
|
+
warning += f" - {dep}\n"
|
|
345
|
+
warning += "\nEstes modulos podem parar de funcionar corretamente!"
|
|
346
|
+
|
|
347
|
+
return False, affected_list, warning
|
|
348
|
+
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
raijin_server/__init__.py,sha256=
|
|
2
|
-
raijin_server/cli.py,sha256=
|
|
1
|
+
raijin_server/__init__.py,sha256=ZjIsech_uw8wSidEG2vZITmdC6GCiNK6nsXDMvlyVog,95
|
|
2
|
+
raijin_server/cli.py,sha256=2m7q1znMLbBdnUwN6oOUrCZXEqC2e7SfbjYkymbP4lQ,37884
|
|
3
3
|
raijin_server/config.py,sha256=QNiEVvrbW56XgvNn5-h3bkJm46Xc8mjNqPbvixXD8N0,4829
|
|
4
4
|
raijin_server/healthchecks.py,sha256=lzXdFw6S0hOYbUKbqksh4phb04lXgXdTspP1Dsz4dx8,15401
|
|
5
|
+
raijin_server/module_manager.py,sha256=Wmhj603CN0XGUVr7_Fo8CHzKd9yIbS9x5BJLqDj78kw,10259
|
|
5
6
|
raijin_server/utils.py,sha256=9RnGnPoUTYOpMVRLNa4P4lIQrJNQLkSkPUxycZRGv78,20827
|
|
6
|
-
raijin_server/validators.py,sha256=
|
|
7
|
+
raijin_server/validators.py,sha256=EATYPy2pllAb6IX4gUZKnELvospWwyGV3DHrzxb_RMg,11761
|
|
7
8
|
raijin_server/modules/__init__.py,sha256=e_IbkhLGPcF8to9QUmIESP6fpcTOYcIhaXLKIvqRJMY,920
|
|
8
9
|
raijin_server/modules/apokolips_demo.py,sha256=8ltsXRbVDwlDwLMIvh02NG-FeAfBWw_v6lh7IGOyNqs,13725
|
|
9
10
|
raijin_server/modules/bootstrap.py,sha256=oVIGNRW_JbgY8zXNHGAIP0vGbbHNHyQexthxo5zhbcw,9762
|
|
@@ -15,10 +16,10 @@ raijin_server/modules/full_install.py,sha256=xiKe2GLuZ97c4YdTmhP-kwDVuJJ9Xq3dlgc
|
|
|
15
16
|
raijin_server/modules/grafana.py,sha256=DdDLxmTeFnDRvcRLkpg1RuR9o1ZAArk2W-DTLLyfWHg,6009
|
|
16
17
|
raijin_server/modules/hardening.py,sha256=4hz3ifkMhPlXa2n7gPxN0gitQgzALZ-073vuU3LM4RI,1616
|
|
17
18
|
raijin_server/modules/harness.py,sha256=uWTxTVJlY_VB6xi4ftMtTSaIb96HA8WJQS-RbyxU45M,5391
|
|
18
|
-
raijin_server/modules/istio.py,sha256=
|
|
19
|
+
raijin_server/modules/istio.py,sha256=o0K5-Fw4LRs-kbAVgwzYxHzEt_aPFJG8suqOqvg2748,7297
|
|
19
20
|
raijin_server/modules/kafka.py,sha256=n7ZpLPWv6sKBJhdBiPe7VgeDB24YiCIOWvOQkWwt03Y,5664
|
|
20
|
-
raijin_server/modules/kong.py,sha256=
|
|
21
|
-
raijin_server/modules/kubernetes.py,sha256=
|
|
21
|
+
raijin_server/modules/kong.py,sha256=s6g8Qq_SyUBy_AIXXSTAb9XyqaQrK3eDOU_xS5merRw,9825
|
|
22
|
+
raijin_server/modules/kubernetes.py,sha256=9E6zV0zGQWZW92NVpxwYctpi-4JDmi6YzF3tKRI4HlU,13343
|
|
22
23
|
raijin_server/modules/loki.py,sha256=aNiUpnOFppZMXoQwYhn7IoPMzwUz4aHi6pbiqj1PRjc,5022
|
|
23
24
|
raijin_server/modules/metallb.py,sha256=uUuklc_RsQ-W2qDVRMQAxQm9HKGEqso444b1IwBpM6w,8554
|
|
24
25
|
raijin_server/modules/minio.py,sha256=wxL8U1Zl3XtI-wymIeZonmi561v1zf-bY4TTVPKisLA,6221
|
|
@@ -37,9 +38,9 @@ raijin_server/scripts/checklist.sh,sha256=j6E0Kmk1EfjLvKK1VpCqzXJAXI_7Bm67LK4ndy
|
|
|
37
38
|
raijin_server/scripts/install.sh,sha256=Y1ickbQ4siQ0NIPs6UgrqUr8WWy7U0LHmaTQbEgavoI,3949
|
|
38
39
|
raijin_server/scripts/log_size_metric.sh,sha256=Iv4SsX8AuCYRou-klYn32mX41xB6j0xJGLBO6riw4rU,1208
|
|
39
40
|
raijin_server/scripts/pre-deploy-check.sh,sha256=XqMo7IMIpwUHF17YEmU0-cVmTDMoCGMBFnmS39FidI4,4912
|
|
40
|
-
raijin_server-0.2.
|
|
41
|
-
raijin_server-0.2.
|
|
42
|
-
raijin_server-0.2.
|
|
43
|
-
raijin_server-0.2.
|
|
44
|
-
raijin_server-0.2.
|
|
45
|
-
raijin_server-0.2.
|
|
41
|
+
raijin_server-0.2.27.dist-info/licenses/LICENSE,sha256=kJsMCjOiRZE0AQNtxWqBa32z9kMAaF4EUxyHj3hKaJo,1105
|
|
42
|
+
raijin_server-0.2.27.dist-info/METADATA,sha256=zvRHWIQU7Lere-1GwtkxnNNtcReyE5BFUqpMyKPEgk8,22476
|
|
43
|
+
raijin_server-0.2.27.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
44
|
+
raijin_server-0.2.27.dist-info/entry_points.txt,sha256=3ZvxDX4pvcjkIRsXAJ69wIfVmKa78LKo-C3QhqN2KVM,56
|
|
45
|
+
raijin_server-0.2.27.dist-info/top_level.txt,sha256=Yz1xneCRtsZOzbPIcTAcrSxd-1p80pohMXYAZ74dpok,14
|
|
46
|
+
raijin_server-0.2.27.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|