raijin-server 0.3.4__py3-none-any.whl → 0.3.7__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 +6 -25
- raijin_server/healthchecks.py +1 -55
- raijin_server/minio_utils.py +562 -0
- raijin_server/modules/__init__.py +4 -6
- raijin_server/modules/full_install.py +11 -19
- raijin_server/modules/harbor.py +669 -0
- raijin_server/modules/secrets.py +392 -96
- raijin_server/modules/velero.py +49 -2
- raijin_server/validators.py +1 -1
- {raijin_server-0.3.4.dist-info → raijin_server-0.3.7.dist-info}/METADATA +1 -1
- {raijin_server-0.3.4.dist-info → raijin_server-0.3.7.dist-info}/RECORD +16 -17
- raijin_server/modules/apokolips_demo.py +0 -414
- raijin_server/modules/observability_dashboards.py +0 -233
- raijin_server/modules/observability_ingress.py +0 -246
- {raijin_server-0.3.4.dist-info → raijin_server-0.3.7.dist-info}/WHEEL +0 -0
- {raijin_server-0.3.4.dist-info → raijin_server-0.3.7.dist-info}/entry_points.txt +0 -0
- {raijin_server-0.3.4.dist-info → raijin_server-0.3.7.dist-info}/licenses/LICENSE +0 -0
- {raijin_server-0.3.4.dist-info → raijin_server-0.3.7.dist-info}/top_level.txt +0 -0
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
"""Provisiona dashboards opinativos do Grafana e alertas padrao do Prometheus/Alertmanager."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import json
|
|
6
|
-
import textwrap
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
|
|
9
|
-
import typer
|
|
10
|
-
|
|
11
|
-
from raijin_server.utils import (
|
|
12
|
-
ExecutionContext,
|
|
13
|
-
kubectl_apply,
|
|
14
|
-
kubectl_create_ns,
|
|
15
|
-
require_root,
|
|
16
|
-
write_file,
|
|
17
|
-
)
|
|
18
|
-
|
|
19
|
-
MANIFEST_PATH = Path("/tmp/raijin-observability-dashboards.yaml")
|
|
20
|
-
|
|
21
|
-
CLUSTER_DASHBOARD = {
|
|
22
|
-
"title": "Raijin Cluster Overview",
|
|
23
|
-
"uid": "raijin-cluster",
|
|
24
|
-
"timezone": "browser",
|
|
25
|
-
"schemaVersion": 39,
|
|
26
|
-
"panels": [
|
|
27
|
-
{
|
|
28
|
-
"type": "timeseries",
|
|
29
|
-
"title": "Node CPU %",
|
|
30
|
-
"datasource": "Prometheus",
|
|
31
|
-
"targets": [
|
|
32
|
-
{
|
|
33
|
-
"expr": '100 - (avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)',
|
|
34
|
-
"legendFormat": "{{instance}}",
|
|
35
|
-
}
|
|
36
|
-
],
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
"type": "timeseries",
|
|
40
|
-
"title": "Node Memory %",
|
|
41
|
-
"datasource": "Prometheus",
|
|
42
|
-
"targets": [
|
|
43
|
-
{
|
|
44
|
-
"expr": '((node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes) * 100',
|
|
45
|
-
"legendFormat": "{{instance}}",
|
|
46
|
-
}
|
|
47
|
-
],
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
"type": "stat",
|
|
51
|
-
"title": "API Server Errors (5m)",
|
|
52
|
-
"datasource": "Prometheus",
|
|
53
|
-
"targets": [
|
|
54
|
-
{
|
|
55
|
-
"expr": 'sum(rate(apiserver_request_total{code=~"5.."}[5m]))',
|
|
56
|
-
}
|
|
57
|
-
],
|
|
58
|
-
},
|
|
59
|
-
],
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
SLO_DASHBOARD = {
|
|
63
|
-
"title": "Raijin SLO - Workloads",
|
|
64
|
-
"uid": "raijin-slo",
|
|
65
|
-
"schemaVersion": 39,
|
|
66
|
-
"panels": [
|
|
67
|
-
{
|
|
68
|
-
"type": "timeseries",
|
|
69
|
-
"title": "Pod Restarts (1h)",
|
|
70
|
-
"datasource": "Prometheus",
|
|
71
|
-
"targets": [
|
|
72
|
-
{
|
|
73
|
-
"expr": 'increase(kube_pod_container_status_restarts_total[1h])',
|
|
74
|
-
"legendFormat": "{{namespace}}/{{pod}}",
|
|
75
|
-
}
|
|
76
|
-
],
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
"type": "timeseries",
|
|
80
|
-
"title": "Ingress HTTP 5xx Rate",
|
|
81
|
-
"datasource": "Prometheus",
|
|
82
|
-
"targets": [
|
|
83
|
-
{
|
|
84
|
-
"expr": 'sum(rate(traefik_service_requests_total{code=~"5.."}[5m])) by (service)',
|
|
85
|
-
"legendFormat": "{{service}}",
|
|
86
|
-
}
|
|
87
|
-
],
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
"type": "gauge",
|
|
91
|
-
"title": "Cluster CPU Pressure",
|
|
92
|
-
"datasource": "Prometheus",
|
|
93
|
-
"targets": [
|
|
94
|
-
{
|
|
95
|
-
"expr": 'avg(node_pressure_cpu_waiting_seconds_total)',
|
|
96
|
-
}
|
|
97
|
-
],
|
|
98
|
-
},
|
|
99
|
-
],
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
def _json_block(obj: dict) -> str:
|
|
104
|
-
return json.dumps(obj, indent=2, separators=(",", ": "))
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
def _alertmanager_block(contact_email: str, webhook_url: str) -> str:
|
|
108
|
-
receivers = ["receivers:", " - name: default"]
|
|
109
|
-
if contact_email:
|
|
110
|
-
receivers.append(" email_configs:")
|
|
111
|
-
receivers.append(f" - to: {contact_email}")
|
|
112
|
-
receivers.append(" send_resolved: true")
|
|
113
|
-
if webhook_url:
|
|
114
|
-
receivers.append(" webhook_configs:")
|
|
115
|
-
receivers.append(f" - url: {webhook_url}")
|
|
116
|
-
receivers.append(" send_resolved: true")
|
|
117
|
-
receivers_str = "\n".join(receivers) if len(receivers) > 2 else "receivers:\n - name: default"
|
|
118
|
-
return textwrap.dedent(
|
|
119
|
-
f"""
|
|
120
|
-
route:
|
|
121
|
-
receiver: default
|
|
122
|
-
group_by: ['alertname']
|
|
123
|
-
group_wait: 30s
|
|
124
|
-
group_interval: 5m
|
|
125
|
-
repeat_interval: 4h
|
|
126
|
-
{receivers_str}
|
|
127
|
-
"""
|
|
128
|
-
).strip()
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
def _build_manifest(namespace: str, contact_email: str, webhook_url: str) -> str:
|
|
132
|
-
cluster_json = textwrap.indent(_json_block(CLUSTER_DASHBOARD), " ")
|
|
133
|
-
slo_json = textwrap.indent(_json_block(SLO_DASHBOARD), " ")
|
|
134
|
-
alertmanager_yaml = textwrap.indent(_alertmanager_block(contact_email, webhook_url), " ")
|
|
135
|
-
|
|
136
|
-
prometheus_rules = textwrap.dedent(
|
|
137
|
-
f"""
|
|
138
|
-
apiVersion: monitoring.coreos.com/v1
|
|
139
|
-
kind: PrometheusRule
|
|
140
|
-
metadata:
|
|
141
|
-
name: raijin-default-alerts
|
|
142
|
-
namespace: {namespace}
|
|
143
|
-
spec:
|
|
144
|
-
groups:
|
|
145
|
-
- name: raijin-cluster-health
|
|
146
|
-
rules:
|
|
147
|
-
- alert: NodeDown
|
|
148
|
-
expr: kube_node_status_condition{{condition="Ready",status="true"}} == 0
|
|
149
|
-
for: 5m
|
|
150
|
-
labels:
|
|
151
|
-
severity: critical
|
|
152
|
-
annotations:
|
|
153
|
-
summary: "Node fora do cluster"
|
|
154
|
-
description: "O node {{ $labels.node }} nao reporta Ready ha 5 minutos."
|
|
155
|
-
- alert: HighNodeCPU
|
|
156
|
-
expr: avg(node_load1) by (instance) > count(node_cpu_seconds_total{{mode="system"}}) by (instance)
|
|
157
|
-
for: 10m
|
|
158
|
-
labels:
|
|
159
|
-
severity: warning
|
|
160
|
-
annotations:
|
|
161
|
-
summary: "CPU elevada em {{ $labels.instance }}"
|
|
162
|
-
description: "Load1 superior ao numero de cores ha 10 minutos."
|
|
163
|
-
- alert: APIServerErrorRate
|
|
164
|
-
expr: sum(rate(apiserver_request_total{{code=~"5.."}}[5m])) > 5
|
|
165
|
-
for: 5m
|
|
166
|
-
labels:
|
|
167
|
-
severity: warning
|
|
168
|
-
annotations:
|
|
169
|
-
summary: "API Server retornando 5xx"
|
|
170
|
-
description: "Taxa de erros 5xx do API Server acima de 5 req/s."
|
|
171
|
-
"""
|
|
172
|
-
).strip()
|
|
173
|
-
|
|
174
|
-
grafana_cm = textwrap.dedent(
|
|
175
|
-
f"""
|
|
176
|
-
apiVersion: v1
|
|
177
|
-
kind: ConfigMap
|
|
178
|
-
metadata:
|
|
179
|
-
name: grafana-dashboards-raijin
|
|
180
|
-
namespace: {namespace}
|
|
181
|
-
labels:
|
|
182
|
-
grafana_dashboard: "1"
|
|
183
|
-
data:
|
|
184
|
-
cluster-overview.json: |
|
|
185
|
-
{cluster_json}
|
|
186
|
-
slo-workloads.json: |
|
|
187
|
-
{slo_json}
|
|
188
|
-
"""
|
|
189
|
-
).strip()
|
|
190
|
-
|
|
191
|
-
alertmanager_cm = textwrap.dedent(
|
|
192
|
-
f"""
|
|
193
|
-
apiVersion: v1
|
|
194
|
-
kind: ConfigMap
|
|
195
|
-
metadata:
|
|
196
|
-
name: alertmanager-raijin
|
|
197
|
-
namespace: {namespace}
|
|
198
|
-
labels:
|
|
199
|
-
app.kubernetes.io/name: alertmanager
|
|
200
|
-
data:
|
|
201
|
-
alertmanager.yml: |
|
|
202
|
-
{alertmanager_yaml}
|
|
203
|
-
"""
|
|
204
|
-
).strip()
|
|
205
|
-
|
|
206
|
-
documents = "\n---\n".join([grafana_cm, alertmanager_cm, prometheus_rules])
|
|
207
|
-
return documents + "\n"
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
def run(ctx: ExecutionContext) -> None:
|
|
211
|
-
require_root(ctx)
|
|
212
|
-
typer.echo("Aplicando dashboards e alertas opinativos...")
|
|
213
|
-
|
|
214
|
-
namespace = typer.prompt("Namespace de observabilidade", default="observability")
|
|
215
|
-
contact_email = typer.prompt(
|
|
216
|
-
"Email para receber alertas (ENTER para ignorar)",
|
|
217
|
-
default="",
|
|
218
|
-
)
|
|
219
|
-
webhook_url = typer.prompt(
|
|
220
|
-
"Webhook HTTP (Slack/Teams) para Alertmanager (ENTER para ignorar)",
|
|
221
|
-
default="",
|
|
222
|
-
)
|
|
223
|
-
|
|
224
|
-
kubectl_create_ns(namespace, ctx)
|
|
225
|
-
|
|
226
|
-
manifest = _build_manifest(namespace, contact_email, webhook_url)
|
|
227
|
-
write_file(MANIFEST_PATH, manifest, ctx)
|
|
228
|
-
kubectl_apply(str(MANIFEST_PATH), ctx)
|
|
229
|
-
|
|
230
|
-
typer.secho("Dashboards e alertas aplicados no namespace de observabilidade.", fg=typer.colors.GREEN)
|
|
231
|
-
typer.echo("Grafana: ConfigMap 'grafana-dashboards-raijin'")
|
|
232
|
-
typer.echo("Alertmanager: ConfigMap 'alertmanager-raijin'")
|
|
233
|
-
typer.echo("Prometheus: PrometheusRule 'raijin-default-alerts'")
|
|
@@ -1,246 +0,0 @@
|
|
|
1
|
-
"""Provisiona ingressos seguros para Grafana, Prometheus e Alertmanager."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import base64
|
|
6
|
-
import subprocess
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
from typing import Dict, List
|
|
9
|
-
|
|
10
|
-
import typer
|
|
11
|
-
|
|
12
|
-
from raijin_server.utils import (
|
|
13
|
-
ExecutionContext,
|
|
14
|
-
kubectl_apply,
|
|
15
|
-
kubectl_create_ns,
|
|
16
|
-
require_root,
|
|
17
|
-
write_file,
|
|
18
|
-
)
|
|
19
|
-
|
|
20
|
-
MANIFEST_PATH = Path("/tmp/raijin-observability-ingress.yaml")
|
|
21
|
-
|
|
22
|
-
COMPONENTS: List[Dict[str, object]] = [
|
|
23
|
-
{
|
|
24
|
-
"key": "grafana",
|
|
25
|
-
"label": "Grafana",
|
|
26
|
-
"service": "grafana",
|
|
27
|
-
"port": 80,
|
|
28
|
-
"default_host": "grafana.example.com",
|
|
29
|
-
"default_tls": "grafana-tls",
|
|
30
|
-
"auth_secret": "grafana-basic-auth",
|
|
31
|
-
"middleware": "grafana-auth",
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
"key": "prometheus",
|
|
35
|
-
"label": "Prometheus",
|
|
36
|
-
"service": "kube-prometheus-stack-prometheus",
|
|
37
|
-
"port": 9090,
|
|
38
|
-
"default_host": "prometheus.example.com",
|
|
39
|
-
"default_tls": "prometheus-tls",
|
|
40
|
-
"auth_secret": "prometheus-basic-auth",
|
|
41
|
-
"middleware": "prometheus-auth",
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
"key": "alertmanager",
|
|
45
|
-
"label": "Alertmanager",
|
|
46
|
-
"service": "kube-prometheus-stack-alertmanager",
|
|
47
|
-
"port": 9093,
|
|
48
|
-
"default_host": "alerts.example.com",
|
|
49
|
-
"default_tls": "alertmanager-tls",
|
|
50
|
-
"auth_secret": "alertmanager-basic-auth",
|
|
51
|
-
"middleware": "alertmanager-auth",
|
|
52
|
-
},
|
|
53
|
-
]
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def _generate_htpasswd(username: str, password: str) -> str:
|
|
57
|
-
try:
|
|
58
|
-
result = subprocess.run(
|
|
59
|
-
["openssl", "passwd", "-6", password],
|
|
60
|
-
capture_output=True,
|
|
61
|
-
text=True,
|
|
62
|
-
check=True,
|
|
63
|
-
)
|
|
64
|
-
hashed = result.stdout.strip()
|
|
65
|
-
except Exception:
|
|
66
|
-
import crypt
|
|
67
|
-
|
|
68
|
-
hashed = crypt.crypt(password, crypt.mksalt(crypt.METHOD_SHA512))
|
|
69
|
-
return f"{username}:{hashed}"
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
def _build_manifest(
|
|
73
|
-
namespace: str,
|
|
74
|
-
ingress_class: str,
|
|
75
|
-
services: List[Dict[str, object]],
|
|
76
|
-
encoded_users: str,
|
|
77
|
-
issuer_name: str,
|
|
78
|
-
issuer_kind: str,
|
|
79
|
-
) -> str:
|
|
80
|
-
documents: List[str] = []
|
|
81
|
-
|
|
82
|
-
for svc in services:
|
|
83
|
-
host = svc["host"]
|
|
84
|
-
tls_secret = svc["tls_secret"]
|
|
85
|
-
auth_secret = svc["auth_secret"]
|
|
86
|
-
middleware = svc["middleware"]
|
|
87
|
-
service_name = svc["service"]
|
|
88
|
-
port = svc["port"]
|
|
89
|
-
name = svc["key"]
|
|
90
|
-
|
|
91
|
-
documents.append(
|
|
92
|
-
f"""apiVersion: v1
|
|
93
|
-
kind: Secret
|
|
94
|
-
metadata:
|
|
95
|
-
name: {auth_secret}
|
|
96
|
-
namespace: {namespace}
|
|
97
|
-
type: Opaque
|
|
98
|
-
data:
|
|
99
|
-
users: {encoded_users}
|
|
100
|
-
"""
|
|
101
|
-
)
|
|
102
|
-
|
|
103
|
-
documents.append(
|
|
104
|
-
f"""apiVersion: traefik.containo.us/v1alpha1
|
|
105
|
-
kind: Middleware
|
|
106
|
-
metadata:
|
|
107
|
-
name: {middleware}
|
|
108
|
-
namespace: {namespace}
|
|
109
|
-
spec:
|
|
110
|
-
basicAuth:
|
|
111
|
-
secret: {auth_secret}
|
|
112
|
-
removeHeader: true
|
|
113
|
-
"""
|
|
114
|
-
)
|
|
115
|
-
|
|
116
|
-
if issuer_name:
|
|
117
|
-
documents.append(
|
|
118
|
-
f"""apiVersion: cert-manager.io/v1
|
|
119
|
-
kind: Certificate
|
|
120
|
-
metadata:
|
|
121
|
-
name: {name}-ingress-cert
|
|
122
|
-
namespace: {namespace}
|
|
123
|
-
spec:
|
|
124
|
-
secretName: {tls_secret}
|
|
125
|
-
dnsNames:
|
|
126
|
-
- {host}
|
|
127
|
-
issuerRef:
|
|
128
|
-
name: {issuer_name}
|
|
129
|
-
kind: {issuer_kind}
|
|
130
|
-
"""
|
|
131
|
-
)
|
|
132
|
-
|
|
133
|
-
documents.append(
|
|
134
|
-
f"""apiVersion: networking.k8s.io/v1
|
|
135
|
-
kind: Ingress
|
|
136
|
-
metadata:
|
|
137
|
-
name: {name}-secure
|
|
138
|
-
namespace: {namespace}
|
|
139
|
-
annotations:
|
|
140
|
-
traefik.ingress.kubernetes.io/router.middlewares: {namespace}-{middleware}@kubernetescrd
|
|
141
|
-
spec:
|
|
142
|
-
ingressClassName: {ingress_class}
|
|
143
|
-
rules:
|
|
144
|
-
- host: {host}
|
|
145
|
-
http:
|
|
146
|
-
paths:
|
|
147
|
-
- path: /
|
|
148
|
-
pathType: Prefix
|
|
149
|
-
backend:
|
|
150
|
-
service:
|
|
151
|
-
name: {service_name}
|
|
152
|
-
port:
|
|
153
|
-
number: {port}
|
|
154
|
-
tls:
|
|
155
|
-
- secretName: {tls_secret}
|
|
156
|
-
hosts:
|
|
157
|
-
- {host}
|
|
158
|
-
"""
|
|
159
|
-
)
|
|
160
|
-
|
|
161
|
-
return "---\n".join(documents)
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
def run(ctx: ExecutionContext) -> None:
|
|
165
|
-
require_root(ctx)
|
|
166
|
-
|
|
167
|
-
typer.secho("⚠️ AVISO DE SEGURANÇA", fg=typer.colors.RED, bold=True)
|
|
168
|
-
typer.secho(
|
|
169
|
-
"\nExpor ferramentas de observabilidade publicamente é um RISCO DE SEGURANÇA significativo!",
|
|
170
|
-
fg=typer.colors.YELLOW,
|
|
171
|
-
)
|
|
172
|
-
typer.secho(
|
|
173
|
-
"Mesmo com TLS e BasicAuth, você estará expondo informações sensíveis do cluster.\n",
|
|
174
|
-
fg=typer.colors.YELLOW,
|
|
175
|
-
)
|
|
176
|
-
typer.secho("✅ RECOMENDAÇÃO FORTE:", fg=typer.colors.GREEN, bold=True)
|
|
177
|
-
typer.echo("1. Configure VPN: sudo raijin vpn")
|
|
178
|
-
typer.echo("2. Use port-forward via VPN para acesso seguro")
|
|
179
|
-
typer.echo("3. Mantenha os dashboards APENAS na rede interna\n")
|
|
180
|
-
|
|
181
|
-
proceed = typer.confirm(
|
|
182
|
-
"Você REALMENTE quer expor os dashboards publicamente?",
|
|
183
|
-
default=False
|
|
184
|
-
)
|
|
185
|
-
|
|
186
|
-
if not proceed:
|
|
187
|
-
typer.secho("\n✓ Boa decisão! Use VPN para acesso seguro.", fg=typer.colors.GREEN)
|
|
188
|
-
typer.echo("\nPara acessar via VPN + port-forward:")
|
|
189
|
-
typer.echo(" kubectl -n observability port-forward svc/grafana 3000:80")
|
|
190
|
-
typer.echo(" kubectl -n observability port-forward svc/kube-prometheus-stack-prometheus 9090:9090")
|
|
191
|
-
typer.echo(" kubectl -n observability port-forward svc/kube-prometheus-stack-alertmanager 9093:9093")
|
|
192
|
-
raise typer.Exit(0)
|
|
193
|
-
|
|
194
|
-
typer.echo("\nProvisionando ingress seguro para observabilidade...")
|
|
195
|
-
|
|
196
|
-
namespace = typer.prompt("Namespace dos componentes", default="observability")
|
|
197
|
-
ingress_class = typer.prompt("IngressClass dedicada", default="traefik")
|
|
198
|
-
username = typer.prompt("Usuario para basic auth", default="observability")
|
|
199
|
-
password = typer.prompt(
|
|
200
|
-
"Senha para basic auth",
|
|
201
|
-
hide_input=True,
|
|
202
|
-
confirmation_prompt=True,
|
|
203
|
-
)
|
|
204
|
-
|
|
205
|
-
configured: List[Dict[str, object]] = []
|
|
206
|
-
for comp in COMPONENTS:
|
|
207
|
-
host = typer.prompt(f"Host para {comp['label']}", default=comp["default_host"])
|
|
208
|
-
tls_secret = typer.prompt(
|
|
209
|
-
f"Secret TLS para {comp['label']}",
|
|
210
|
-
default=comp["default_tls"],
|
|
211
|
-
)
|
|
212
|
-
configured.append({**comp, "host": host, "tls_secret": tls_secret})
|
|
213
|
-
|
|
214
|
-
issue_certs = typer.confirm("Gerar Certificates via cert-manager?", default=True)
|
|
215
|
-
issuer_name = ""
|
|
216
|
-
issuer_kind = "ClusterIssuer"
|
|
217
|
-
if issue_certs:
|
|
218
|
-
issuer_name = typer.prompt("Nome do issuer (cert-manager)", default="letsencrypt-prod")
|
|
219
|
-
issuer_kind = typer.prompt("Tipo do issuer (Issuer/ClusterIssuer)", default="ClusterIssuer")
|
|
220
|
-
|
|
221
|
-
secret_line = _generate_htpasswd(username, password)
|
|
222
|
-
encoded_users = base64.b64encode(secret_line.encode()).decode()
|
|
223
|
-
|
|
224
|
-
kubectl_create_ns(namespace, ctx)
|
|
225
|
-
|
|
226
|
-
manifest = _build_manifest(
|
|
227
|
-
namespace,
|
|
228
|
-
ingress_class,
|
|
229
|
-
configured,
|
|
230
|
-
encoded_users,
|
|
231
|
-
issuer_name,
|
|
232
|
-
issuer_kind,
|
|
233
|
-
)
|
|
234
|
-
|
|
235
|
-
write_file(MANIFEST_PATH, manifest, ctx)
|
|
236
|
-
kubectl_apply(str(MANIFEST_PATH), ctx)
|
|
237
|
-
|
|
238
|
-
typer.secho("Ingress seguro aplicado com sucesso.", fg=typer.colors.GREEN)
|
|
239
|
-
typer.echo("Hosts publicados:")
|
|
240
|
-
for svc in configured:
|
|
241
|
-
typer.echo(f" - {svc['label']}: https://{svc['host']}")
|
|
242
|
-
if not issuer_name:
|
|
243
|
-
typer.secho(
|
|
244
|
-
"Certificados nao foram criados automaticamente. Certifique-se de que os secrets TLS existem.",
|
|
245
|
-
fg=typer.colors.YELLOW,
|
|
246
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|