raijin-server 0.2.37__py3-none-any.whl → 0.2.39__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 CHANGED
@@ -1,5 +1,5 @@
1
1
  """Pacote principal do CLI Raijin Server."""
2
2
 
3
- __version__ = "0.2.37"
3
+ __version__ = "0.2.39"
4
4
 
5
5
  __all__ = ["__version__"]
@@ -2,12 +2,21 @@
2
2
 
3
3
  import secrets
4
4
  import socket
5
+ import tempfile
5
6
  import time
7
+ from pathlib import Path
8
+ import textwrap
6
9
 
7
10
  import typer
8
11
 
9
12
  from raijin_server.utils import ExecutionContext, helm_upgrade_install, require_root, run_cmd
10
13
 
14
+ LOCAL_PATH_PROVISIONER_URL = (
15
+ "https://raw.githubusercontent.com/rancher/local-path-provisioner/"
16
+ "v0.0.30/deploy/local-path-storage.yaml"
17
+ )
18
+ RAIJIN_LOCAL_PATH_SC_NAME = "raijin-local-path"
19
+
11
20
 
12
21
  def _detect_node_name(ctx: ExecutionContext) -> str:
13
22
  """Detecta nome do node para nodeSelector."""
@@ -26,6 +35,198 @@ def _generate_secret(length: int = 32) -> str:
26
35
  return secrets.token_urlsafe(length)[:length]
27
36
 
28
37
 
38
+ def _apply_manifest(ctx: ExecutionContext, manifest: str, description: str) -> bool:
39
+ """Aplica manifest YAML temporario com kubectl."""
40
+ tmp_path = None
41
+ try:
42
+ with tempfile.NamedTemporaryFile("w", delete=False, suffix=".yaml") as tmp:
43
+ tmp.write(manifest)
44
+ tmp.flush()
45
+ tmp_path = Path(tmp.name)
46
+ result = run_cmd(
47
+ ["kubectl", "apply", "-f", str(tmp_path)],
48
+ ctx,
49
+ check=False,
50
+ )
51
+ if result.returncode != 0:
52
+ typer.secho(f" Falha ao aplicar {description}.", fg=typer.colors.RED)
53
+ return False
54
+ typer.secho(f" ✓ {description} aplicado.", fg=typer.colors.GREEN)
55
+ return True
56
+ finally:
57
+ if tmp_path and tmp_path.exists():
58
+ tmp_path.unlink(missing_ok=True)
59
+
60
+
61
+ def _create_raijin_local_path_sc(ctx: ExecutionContext) -> bool:
62
+ """Cria StorageClass com volumeBindingMode=Immediate baseada no local-path."""
63
+ manifest = textwrap.dedent(
64
+ f"""
65
+ apiVersion: storage.k8s.io/v1
66
+ kind: StorageClass
67
+ metadata:
68
+ name: {RAIJIN_LOCAL_PATH_SC_NAME}
69
+ provisioner: rancher.io/local-path
70
+ reclaimPolicy: Delete
71
+ volumeBindingMode: Immediate
72
+ allowVolumeExpansion: true
73
+ parameters:
74
+ type: ""
75
+ """
76
+ ).strip()
77
+ typer.echo(
78
+ f"Criando StorageClass '{RAIJIN_LOCAL_PATH_SC_NAME}' com binding imediato para PVCs do MinIO..."
79
+ )
80
+ return _apply_manifest(ctx, manifest, f"StorageClass {RAIJIN_LOCAL_PATH_SC_NAME}")
81
+
82
+
83
+ def _get_default_storage_class(ctx: ExecutionContext) -> str:
84
+ """Retorna o nome da StorageClass default do cluster, se existir."""
85
+ result = run_cmd(
86
+ [
87
+ "kubectl", "get", "storageclass",
88
+ "-o", "jsonpath={.items[?(@.metadata.annotations.storageclass\\.kubernetes\\.io/is-default-class=='true')].metadata.name}",
89
+ ],
90
+ ctx,
91
+ check=False,
92
+ )
93
+ if result.returncode == 0 and (result.stdout or "").strip():
94
+ return (result.stdout or "").strip()
95
+ return ""
96
+
97
+
98
+ def _list_storage_classes(ctx: ExecutionContext) -> list:
99
+ """Lista todas as StorageClasses disponiveis."""
100
+ result = run_cmd(
101
+ ["kubectl", "get", "storageclass", "-o", "jsonpath={.items[*].metadata.name}"],
102
+ ctx,
103
+ check=False,
104
+ )
105
+ if result.returncode == 0 and (result.stdout or "").strip():
106
+ return (result.stdout or "").strip().split()
107
+ return []
108
+
109
+
110
+ def _install_local_path_provisioner(ctx: ExecutionContext) -> bool:
111
+ """Instala local-path-provisioner para usar storage local (NVMe/SSD)."""
112
+ typer.echo("Instalando local-path-provisioner para storage local...")
113
+
114
+ result = run_cmd(
115
+ ["kubectl", "apply", "-f", LOCAL_PATH_PROVISIONER_URL],
116
+ ctx,
117
+ check=False,
118
+ )
119
+ if result.returncode != 0:
120
+ typer.secho(" Falha ao instalar local-path-provisioner.", fg=typer.colors.RED)
121
+ return False
122
+
123
+ # Aguarda deployment ficar pronto
124
+ typer.echo(" Aguardando local-path-provisioner ficar Ready...")
125
+ run_cmd(
126
+ [
127
+ "kubectl", "-n", "local-path-storage", "rollout", "status",
128
+ "deployment/local-path-provisioner", "--timeout=60s",
129
+ ],
130
+ ctx,
131
+ check=False,
132
+ )
133
+
134
+ typer.secho(" ✓ local-path-provisioner instalado.", fg=typer.colors.GREEN)
135
+ return True
136
+
137
+
138
+ def _set_default_storage_class(ctx: ExecutionContext, name: str) -> None:
139
+ """Define uma StorageClass como default."""
140
+ # Remove default de outras classes primeiro
141
+ existing = _list_storage_classes(ctx)
142
+ for sc in existing:
143
+ if sc != name:
144
+ run_cmd(
145
+ [
146
+ "kubectl", "annotate", "storageclass", sc,
147
+ "storageclass.kubernetes.io/is-default-class-",
148
+ "--overwrite",
149
+ ],
150
+ ctx,
151
+ check=False,
152
+ )
153
+
154
+ # Define a nova como default
155
+ run_cmd(
156
+ [
157
+ "kubectl", "annotate", "storageclass", name,
158
+ "storageclass.kubernetes.io/is-default-class=true",
159
+ "--overwrite",
160
+ ],
161
+ ctx,
162
+ check=True,
163
+ )
164
+ typer.secho(f" ✓ StorageClass '{name}' definida como default.", fg=typer.colors.GREEN)
165
+
166
+
167
+ def _ensure_storage_class(ctx: ExecutionContext) -> str:
168
+ """Garante que existe uma StorageClass disponivel, instalando local-path se necessario."""
169
+ default_sc = _get_default_storage_class(ctx)
170
+ available = _list_storage_classes(ctx)
171
+
172
+ # Se ja houver StorageClass dedicada do Raijin, usa ela
173
+ if default_sc == RAIJIN_LOCAL_PATH_SC_NAME:
174
+ typer.echo(f"StorageClass default detectada: {default_sc}")
175
+ return default_sc
176
+ if RAIJIN_LOCAL_PATH_SC_NAME in available:
177
+ typer.echo(f"StorageClass '{RAIJIN_LOCAL_PATH_SC_NAME}' detectada.")
178
+ _set_default_storage_class(ctx, RAIJIN_LOCAL_PATH_SC_NAME)
179
+ return RAIJIN_LOCAL_PATH_SC_NAME
180
+
181
+ # Se ja existir default diferente de local-path, respeita configuracao do cluster
182
+ if default_sc and default_sc != "local-path":
183
+ typer.echo(f"StorageClass default detectada: {default_sc}")
184
+ return default_sc
185
+
186
+ # Se local-path estiver disponivel (default ou nao), cria uma classe dedicada com binding imediato
187
+ if "local-path" in available or default_sc == "local-path":
188
+ if _create_raijin_local_path_sc(ctx):
189
+ _set_default_storage_class(ctx, RAIJIN_LOCAL_PATH_SC_NAME)
190
+ return RAIJIN_LOCAL_PATH_SC_NAME
191
+ typer.echo("Nao foi possivel criar StorageClass dedicada; usando 'local-path'.")
192
+ _set_default_storage_class(ctx, "local-path")
193
+ return "local-path"
194
+
195
+ if available:
196
+ typer.echo(f"StorageClasses disponiveis (sem default): {', '.join(available)}")
197
+ choice = typer.prompt(
198
+ f"Qual StorageClass usar? ({'/'.join(available)})",
199
+ default=available[0],
200
+ )
201
+ return choice
202
+
203
+ # Nenhuma StorageClass disponivel - instala local-path automaticamente
204
+ typer.secho(
205
+ "Nenhuma StorageClass encontrada no cluster.",
206
+ fg=typer.colors.YELLOW,
207
+ )
208
+ install = typer.confirm(
209
+ "Instalar local-path-provisioner para usar armazenamento local (NVMe/SSD)?",
210
+ default=True,
211
+ )
212
+ if not install:
213
+ typer.secho(
214
+ "Abortando: MinIO requer uma StorageClass para PVCs.",
215
+ fg=typer.colors.RED,
216
+ )
217
+ raise typer.Exit(1)
218
+
219
+ if not _install_local_path_provisioner(ctx):
220
+ raise typer.Exit(1)
221
+
222
+ if _create_raijin_local_path_sc(ctx):
223
+ _set_default_storage_class(ctx, RAIJIN_LOCAL_PATH_SC_NAME)
224
+ return RAIJIN_LOCAL_PATH_SC_NAME
225
+
226
+ _set_default_storage_class(ctx, "local-path")
227
+ return "local-path"
228
+
229
+
29
230
  def _check_existing_minio(ctx: ExecutionContext) -> bool:
30
231
  """Verifica se existe instalacao do MinIO."""
31
232
  result = run_cmd(
@@ -119,6 +320,9 @@ def run(ctx: ExecutionContext) -> None:
119
320
  if cleanup:
120
321
  _uninstall_minio(ctx)
121
322
 
323
+ # Garante que existe StorageClass (instala local-path-provisioner se necessario)
324
+ storage_class = _ensure_storage_class(ctx)
325
+
122
326
  # Configuracoes interativas
123
327
  mode = typer.prompt(
124
328
  "Modo de operacao (standalone/distributed)",
@@ -165,10 +369,15 @@ def run(ctx: ExecutionContext) -> None:
165
369
  typer.secho(f" Password gerado: {root_password}", fg=typer.colors.CYAN)
166
370
 
167
371
  persistence_size = typer.prompt("Tamanho do storage (ex: 10Gi, 50Gi)", default="10Gi")
168
- storage_class = typer.prompt(
169
- "StorageClass para os PVCs (ENTER para usar o default do cluster)",
170
- default="",
372
+
373
+ # Permite override da StorageClass detectada
374
+ storage_class_override = typer.prompt(
375
+ f"StorageClass para os PVCs (detectada: {storage_class})",
376
+ default=storage_class,
171
377
  ).strip()
378
+ if storage_class_override:
379
+ storage_class = storage_class_override
380
+
172
381
  enable_console = typer.confirm("Habilitar Console Web?", default=True)
173
382
 
174
383
  node_name = _detect_node_name(ctx)
@@ -180,7 +389,7 @@ def run(ctx: ExecutionContext) -> None:
180
389
  # Persistence
181
390
  "persistence.enabled=true",
182
391
  f"persistence.size={persistence_size}",
183
- # Se o cluster tiver StorageClass padrao, deixe em branco; caso contrario, defina aqui
392
+ f"persistence.storageClass={storage_class}",
184
393
  # Resources
185
394
  f"resources.requests.memory={resources_req_mem}",
186
395
  f"resources.requests.cpu={resources_req_cpu}",
@@ -205,9 +414,6 @@ def run(ctx: ExecutionContext) -> None:
205
414
  f"postJob.nodeSelector.kubernetes\\.io/hostname={node_name}",
206
415
  ]
207
416
 
208
- if storage_class:
209
- values.append(f"persistence.storageClass={storage_class}")
210
-
211
417
  if is_distributed:
212
418
  values.append(f"replicas={replicas}")
213
419
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: raijin-server
3
- Version: 0.2.37
3
+ Version: 0.2.39
4
4
  Summary: CLI para automacao de setup e hardening de servidores Ubuntu Server.
5
5
  Home-page: https://example.com/raijin-server
6
6
  Author: Equipe Raijin
@@ -46,6 +46,7 @@ CLI em Python (Typer) para automatizar setup e hardening de servidores Ubuntu Se
46
46
  - Segurança: [SECURITY.md](SECURITY.md)
47
47
  - Acesso SSH (Windows): [docs/SSH_WINDOWS.md](docs/SSH_WINDOWS.md)
48
48
  - VPN para acesso remoto (WireGuard): [docs/VPN_REMOTE_ACCESS.md](docs/VPN_REMOTE_ACCESS.md)
49
+ - MinIO (monitorar/testar): [docs/MINIO_OPERATIONS.md](docs/MINIO_OPERATIONS.md)
49
50
 
50
51
  ## Destaques
51
52
 
@@ -1,4 +1,4 @@
1
- raijin_server/__init__.py,sha256=Nn-ioNsT9kpwGoiVgXVrJZwwadoBlBcz2yNeqKUeXSo,95
1
+ raijin_server/__init__.py,sha256=xacey6j4K59BQrjBoDCtOtRtB9BSq7vxACgXc8_pFlg,95
2
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
@@ -22,7 +22,7 @@ raijin_server/modules/kong.py,sha256=eDSagvEP9_BCs9pZ-pCVs1BDdlYOoJfY5PnUSiTvvgc
22
22
  raijin_server/modules/kubernetes.py,sha256=9E6zV0zGQWZW92NVpxwYctpi-4JDmi6YzF3tKRI4HlU,13343
23
23
  raijin_server/modules/loki.py,sha256=aNiUpnOFppZMXoQwYhn7IoPMzwUz4aHi6pbiqj1PRjc,5022
24
24
  raijin_server/modules/metallb.py,sha256=uUuklc_RsQ-W2qDVRMQAxQm9HKGEqso444b1IwBpM6w,8554
25
- raijin_server/modules/minio.py,sha256=vjbgzKMRTL5EwzaBFfnd_0Wn_P5DpCwHCdf2pP9pki4,8057
25
+ raijin_server/modules/minio.py,sha256=KSpoFP7RhXpDCaubHLo0amy6NWWVfdp5tuj8qVDB4tQ,15265
26
26
  raijin_server/modules/network.py,sha256=QRlYdcryCCPAWG3QQ_W7ld9gJgETI7H8gwntOU7UqFE,4818
27
27
  raijin_server/modules/observability_dashboards.py,sha256=fVz0WEOQrUTF5rJ__Nu_onyBuwL_exFmysWMmg8AE9w,7319
28
28
  raijin_server/modules/observability_ingress.py,sha256=Fh1rlFWueBNHnOkHuoHYyhILmpO-iQXINybSUYbYsHQ,5738
@@ -38,9 +38,9 @@ raijin_server/scripts/checklist.sh,sha256=j6E0Kmk1EfjLvKK1VpCqzXJAXI_7Bm67LK4ndy
38
38
  raijin_server/scripts/install.sh,sha256=Y1ickbQ4siQ0NIPs6UgrqUr8WWy7U0LHmaTQbEgavoI,3949
39
39
  raijin_server/scripts/log_size_metric.sh,sha256=Iv4SsX8AuCYRou-klYn32mX41xB6j0xJGLBO6riw4rU,1208
40
40
  raijin_server/scripts/pre-deploy-check.sh,sha256=XqMo7IMIpwUHF17YEmU0-cVmTDMoCGMBFnmS39FidI4,4912
41
- raijin_server-0.2.37.dist-info/licenses/LICENSE,sha256=kJsMCjOiRZE0AQNtxWqBa32z9kMAaF4EUxyHj3hKaJo,1105
42
- raijin_server-0.2.37.dist-info/METADATA,sha256=xywTXHV-N6hyEuCOuJTd82eNcVviCdD9BhRIdxhX7ao,22770
43
- raijin_server-0.2.37.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
44
- raijin_server-0.2.37.dist-info/entry_points.txt,sha256=3ZvxDX4pvcjkIRsXAJ69wIfVmKa78LKo-C3QhqN2KVM,56
45
- raijin_server-0.2.37.dist-info/top_level.txt,sha256=Yz1xneCRtsZOzbPIcTAcrSxd-1p80pohMXYAZ74dpok,14
46
- raijin_server-0.2.37.dist-info/RECORD,,
41
+ raijin_server-0.2.39.dist-info/licenses/LICENSE,sha256=kJsMCjOiRZE0AQNtxWqBa32z9kMAaF4EUxyHj3hKaJo,1105
42
+ raijin_server-0.2.39.dist-info/METADATA,sha256=5CikB8uMIOaqFLxSS3kQyQMbmu5C1TkpJy-l9JrLEfQ,22851
43
+ raijin_server-0.2.39.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
44
+ raijin_server-0.2.39.dist-info/entry_points.txt,sha256=3ZvxDX4pvcjkIRsXAJ69wIfVmKa78LKo-C3QhqN2KVM,56
45
+ raijin_server-0.2.39.dist-info/top_level.txt,sha256=Yz1xneCRtsZOzbPIcTAcrSxd-1p80pohMXYAZ74dpok,14
46
+ raijin_server-0.2.39.dist-info/RECORD,,