Skip to content

Commit 915dc9f

Browse files
committed
feat: sprint 87 — Setup wizard: script de instalação da plataforma GreenCap no minikube
Programado em par com: Claude IA
1 parent e38b071 commit 915dc9f

12 files changed

Lines changed: 136 additions & 22 deletions

File tree

File renamed without changes.

.scratch/sprint-77/issues/01-ingress-topology-node.md renamed to .scratch/archive/sprint-77/issues/01-ingress-topology-node.md

File renamed without changes.

.scratch/sprint-77/issues/02-goto-resource-button.md renamed to .scratch/archive/sprint-77/issues/02-goto-resource-button.md

File renamed without changes.

.scratch/sprint-77/issues/03-prefilter-name-query-param.md renamed to .scratch/archive/sprint-77/issues/03-prefilter-name-query-param.md

File renamed without changes.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
---
2+
id: "87-01"
3+
title: "Setup wizard: script principal e teardown"
4+
status: done
5+
priority: high
6+
sprint: 87
7+
---
8+
9+
O GreenCap precisa de um ponto de entrada único para usuários que querem rodar a plataforma localmente via minikube. Atualmente não existe nenhum mecanismo de instalação além do docker-compose (que não usa Kubernetes).
10+
11+
O `setup/setup.sh` deve ser autoexplicativo, declarativo por etapas e re-executável sem efeitos colaterais em caso de re-run. O `setup/teardown.sh` permite ao usuário desfazer tudo com um único comando.
12+
13+
**Escopo do `setup.sh`:**
14+
15+
Etapa 1 — verifica se `docker`, `minikube` e `kubectl` estão instalados no PATH; em caso de ausência, exibe link de instalação e encerra.
16+
17+
Etapa 2 — exibe menu de perfil de instalação e aguarda escolha do usuário:
18+
- Minimal: 1 nó, 2 CPUs, 4 GB
19+
- Recommended: 3 nós, 2 CPUs, 3 GB/nó
20+
- Custom: usuário informa nós, CPUs e memória via `read`
21+
22+
Etapa 3 — inicia minikube com profile `greencap-platform` e o perfil escolhido (driver `docker`); idempotente — pula se o profile já existe.
23+
24+
Etapa 4 — habilita addons `metrics-server`, `ingress` e `registry`; aguarda o ingress-nginx controller ficar pronto; aplica PVC de 8 Gi para persistência do registry e faz patch no Deployment do registry (mesmo padrão do `cluster-provision.sh` do greencap-demo, com nodeSelector e volumeMount).
25+
26+
Etapa 5 — faz `docker build` do `docker/Dockerfile` e push para `localhost:5000/greencap-platform/platform:latest` via registry-proxy do minikube; idempotente — pula o push se a tag já existir no registry.
27+
28+
Etapa 6 — gera `GREENCAP_ENCRYPTION_KEY` e senha do Postgres via `openssl rand -hex 16` caso não estejam definidas como variáveis de ambiente; aplica o Secret `greencap-secrets` no namespace `greencap-platform`.
29+
30+
Etapa 7 — aplica os manifests em `setup/manifests/` (namespace, Postgres, GreenCap); aguarda rollout de todos os Deployments.
31+
32+
Etapa 8 — exibe resumo: URL (`http://greencap.local`), credenciais padrão (`admin`/`admin`), comando sudo para `/etc/hosts` e a `ENCRYPTION_KEY` gerada (com aviso de guarda).
33+
34+
**Escopo do `teardown.sh`:**
35+
36+
Exibe aviso de destruição e aguarda confirmação (`y/N`); deleta o minikube profile `greencap-platform` completamente.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
id: "87-02"
3+
title: "Manifests Kubernetes: Postgres e GreenCap no namespace greencap-platform"
4+
status: done
5+
priority: high
6+
sprint: 87
7+
---
8+
9+
O `setup.sh` aplica os manifests em `setup/manifests/` na ordem numérica. Cada manifest é responsável por um recurso específico da plataforma.
10+
11+
**Manifests necessários:**
12+
13+
`00-namespace.yaml` — namespace `greencap-platform`.
14+
15+
`01-secrets.yaml` — Secret `greencap-secrets` com `DB_PASSWORD` e `GREENCAP_ENCRYPTION_KEY`; os valores são placeholders substituídos pelo `setup.sh` via `envsubst` ou `kubectl create secret` imperativo antes do apply dos demais manifests.
16+
17+
`02-postgres-pvc.yaml` — PersistentVolumeClaim `postgres-data`, 2 Gi, ReadWriteOnce, StorageClass `standard`.
18+
19+
`03-postgres-deployment.yaml` — Deployment `postgres` com `postgres:16-alpine`; variáveis `POSTGRES_DB=greencap`, `POSTGRES_USER=greencap`, `POSTGRES_PASSWORD` lidas do Secret; volume montado em `/var/lib/postgresql/data`; readinessProbe via `pg_isready`.
20+
21+
`04-postgres-service.yaml` — Service ClusterIP `greencap-db` na porta 5432; sem exposição externa.
22+
23+
`05-greencap-deployment.yaml` — Deployment `greencap` com a imagem `localhost:5000/greencap-platform/platform:latest` (imagePullPolicy `Always`); variáveis de ambiente: `SPRING_PROFILES_ACTIVE=prod`, `SPRING_DATASOURCE_URL=jdbc:postgresql://greencap-db:5432/greencap`, `SPRING_DATASOURCE_USERNAME=greencap`, `SPRING_DATASOURCE_PASSWORD` e `GREENCAP_ENCRYPTION_KEY` lidas do Secret; readinessProbe via `/actuator/health`; 1 réplica.
24+
25+
`06-greencap-service.yaml` — Service ClusterIP `greencap` na porta 8080.
26+
27+
`07-greencap-ingress.yaml` — Ingress com host `greencap.local` apontando para o Service `greencap` na porta 8080; sem TLS; sem IngressClass explícita (usa o default do addon `ingress` do minikube).

docs/sprints-archive.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,3 +705,19 @@
705705
- `DeployApplicationView` (nova, rota `/deploy`): wizard 6 passos (Name, Image & Port, Resources, Volume, External Access, Review); sugestões de StorageClass e IngressClass carregadas do cluster; sugestão de host `<namespace>.greencap.local`; execução assíncrona em thread virtual; em sucesso navega para Topologia
706706
- `Permission.PROJECT_DEPLOY_APPLICATION` (novo): `V25__add_deploy_application_permission.sql`
707707
- Issues: `.scratch/archive/sprint-75/issues/`
708+
709+
710+
### Sprint 76 ✅ — Namespaces View: listagem com contagens de recursos, Create e Delete Namespace
711+
712+
- `NamespaceService`: `listNamespacesWithCounts()`, `createNamespace()`, `deleteNamespace()`; filtra namespaces em fase `Terminating` no combobox da navbar
713+
- `NamespacesView` (nova, rota `global/namespaces`): grid Name/Status/Pods/Deployments/Services/Age; Create com validação DNS; Delete type-to-confirm; system namespaces bloqueados; chama `MainLayout.refreshClusterState()` após operações
714+
- `Permission.GLOBAL_NAMESPACES_VIEW/WRITE/DELETE`; `V26__add_namespace_permissions.sql`
715+
- Issue: `.scratch/archive/sprint-76/issues/`
716+
717+
### Sprint 77 ✅ — Topologia: nó Ingress + botão "Go to resource" + pré-filtro ?name= nas views
718+
719+
- `TopologyService`: listagem de Ingresses via Fabric8; `ingressNode()` com ingressClass/hosts/TLS; `extractBackendServiceNames()`; `resourceViewUrl()` mapeia cada tipo para rota da view com `?name=`
720+
- `topology-graph.ts`: cor Ingress `#06B6D4`; cor de arestas `#64748B`; fcose separado da inicialização; `fixedNodeConstraint` desabilitado quando compound nodes presentes
721+
- `TopologyNodeDrawer`: bloco `isIngress` com Hosts, badge TLS, IngressClass; botão "Go to resource" substitui "Ver YAML"
722+
- `DeploymentsView`, `ReplicaSetView`, `ServicesView`, `PersistentVolumeClaimsView`, `IngressView`: `nameFilter` instância; `beforeEnter``?name=`
723+
- Issues: `.scratch/archive/sprint-77/issues/`

docs/sprints.md

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
| Sprint | Tema | Status |
1010
|--------|------|--------|
11-
| 77 | Topologia: nó Ingress + botão "Go to resource" + pré-filtro ?name= nas views | ✅ Concluído |
1211
| 78 | Topologia: correções de layout (randomize), tap em group nodes e botão Reset Positions | ✅ Concluído |
1312
| 79 | UX — Padronização de header: ClustersView e UserManagementView com buildSectionHeader | ✅ Concluído |
1413
| 80 | Add Cluster dialog — provider Minikube (Docker), aviso OpenShift e comando kubectl copiável | ✅ Concluído |
@@ -18,6 +17,7 @@
1817
| 84 | Bug fixes: Registry remove persistente (rm -rf do diretório após GC), Namespace Terminating bloqueado, seleção de linha ao clicar em View Tags | ✅ Concluído |
1918
| 85 | Deploy from Dockerfile — terceiro modo de deploy: wizard 6 passos, build Kaniko inline + provisão de recursos Kubernetes | ✅ Concluído |
2019
| 86 | EventsView — seletor de limite de Events exibidos (50/100/200/500/All, padrão 100) no section header | ✅ Concluído |
20+
| 87 | Setup wizard: script de instalação da plataforma GreenCap no minikube | ✅ Concluído |
2121

2222
---
2323

@@ -87,6 +87,16 @@
8787

8888
> Mostra apenas as últimas 10 sprints. Histórico completo em `docs/sprints-archive.md` (ver `docs/agents/sprint-archiving.md`).
8989
90+
### Sprint 87 ✅ — Setup wizard: script de instalação da plataforma GreenCap no minikube
91+
92+
- `setup/setup.sh`: script idempotente em 7 etapas — verifica/instala ferramentas ausentes (docker, kubectl, minikube) com `sg docker` para ativar grupo sem logout; menu de perfil (Minimal/Recommended/Custom); inicia minikube com driver docker; habilita addons metrics-server, ingress e registry (PVC 8 Gi + nodeSelector para persistência); build + push da imagem via registry-proxy; cria Secret `greencap-secrets` com `DB_PASSWORD`, `GREENCAP_ENCRYPTION_KEY` e `GREENCAP_SELF_CLUSTER_KUBECONFIG`; aplica manifests e aguarda rollout; adiciona entrada `greencap.local` no `/etc/hosts` automaticamente se ausente
93+
- `setup/teardown.sh`: exige confirmação `yes` antes de deletar o profile minikube `greencap-platform`
94+
- `setup/manifests/`: 7 manifests Kubernetes — namespace, PVC Postgres (2 Gi), Deployment Postgres 16, Service ClusterIP `greencap-db`, Deployment GreenCap (imagePullPolicy Always), Service ClusterIP `greencap`, Ingress `greencap.local`
95+
- `DataInitializer`: auto-registra o cluster `greencap-platform` na primeira inicialização quando `GREENCAP_SELF_CLUSTER_KUBECONFIG` está definido; define como cluster e namespace ativos do admin
96+
- `ClusterRepository`: método `existsByName(String)` para idempotência do auto-registro
97+
- `MainLayout`: namespace combobox alargado de 180 px para 220 px; fix de seleção do namespace inicial via dois ciclos de push separados (itens primeiro, valor depois)
98+
- Issues: `.scratch/sprint-87/issues/` (2 issues, ambas `done`)
99+
90100
### Sprint 86 ✅ — EventsView: seletor de limite de Events exibidos
91101

92102
- `ObservabilityService.listEvents()`: novo parâmetro `int limit` (0 = All); stream truncado após ordenação por `lastTimestamp` desc — garante sempre os N mais recentes
@@ -174,20 +184,6 @@
174184
- `CONTEXT.md`: entradas `Namespace`, `Create Namespace`, `Delete Namespace` detalhadas; `Global` atualizado para incluir Namespaces
175185
- Issue: `.scratch/sprint-76/issues/01-namespaces-view.md`
176186

177-
### Sprint 75 ✅ — Deploy Application: wizard multi-step para criar Namespace + Deployment + Service + PVC + Ingress
178-
179-
- `DeployApplicationService` (novo): cria Namespace → Deployment → Service → PVC → Ingress em sequência best-effort; falha parcial retorna `DeployApplicationResult` com recurso falho sem rollback (ver ADR 0009)
180-
- `DeployApplicationRequest` / `DeployApplicationResult` (novos DTOs em `kubernetes/dto/`)
181-
- `Permission.PROJECT_DEPLOY_APPLICATION` (novo, ADMIN/OPERATOR); `V25__add_deploy_application_permission.sql` concede a usuários com `GLOBAL_CLUSTERS_WRITE`
182-
- `NetworkingService.listIngressClassNames`: lista IngressClasses disponíveis no cluster via Fabric8
183-
- `DeployApplicationView`: wizard 6 passos (Name → Image & Port → Resources → Volume → External Access → Review); sugestões do Registry interno no `ComboBox` de imagem; StorageClass pré-selecionada com a default do cluster; host sugerido `<namespace>.greencap.local`; após sucesso navega para `TopologiaView` do novo Namespace
184-
- `DashboardView`: CTA "New Application" quando namespace não tem Deployments (visível apenas com permissão `PROJECT_DEPLOY_APPLICATION`)
185-
- `MainLayout`: item **"New Application"** com ícone `PLUS_CIRCLE` adicionado acima da seção PROJECT (renomeado de "Deploy Application", extraído para `SideNav` próprio, ícone diferenciado do Workloads/Deployments)
186-
- Fix: `PodLogsView` — polling para automaticamente ao receber `KubernetesOperationException` (ex: `ImagePullBackOff`, container em espera); exibe `[Polling stopped] <mensagem>` no corpo dos logs em vez de toast infinito a cada intervalo
187-
- Fix: `DeployApplicationView.REGISTRY_INTERNAL_HOST` corrigido de `registry.kube-system.svc.cluster.local:80` para `localhost:5000` — DNS de cluster não é resolvível no nível do kubelet/Docker daemon do nó; `registry-proxy` (DaemonSet) expõe o registry em `localhost:5000` via `hostPort` em cada nó
188-
- `docs/adr/0009-deploy-application-sem-rastreamento.md` (novo)
189-
- Issues: `.scratch/sprint-75/issues/01-deploy-application-backend.md`, `02-deploy-application-wizard-ui.md`
190-
191187
---
192188

193189
## Legenda

setup/setup.sh

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,12 @@ if [ "$GENERATED_KEY" = true ]; then
324324
echo ""
325325
fi
326326

327-
echo " Add to /etc/hosts (run once with sudo):"
328-
echo " echo \"$MINIKUBE_IP greencap.local\" | sudo tee -a /etc/hosts"
327+
HOSTS_ENTRY="$MINIKUBE_IP greencap.local # GreenCap K8s — managed by setup.sh"
328+
if grep -q "greencap.local" /etc/hosts 2>/dev/null; then
329+
ok "/etc/hosts already contains greencap.local — skipping"
330+
else
331+
echo " Adding greencap.local to /etc/hosts..."
332+
echo "$HOSTS_ENTRY" | $SUDO tee -a /etc/hosts > /dev/null
333+
ok "greencap.local → $MINIKUBE_IP added to /etc/hosts"
334+
fi
329335
echo ""

src/main/java/io/greencap/k8s/config/DataInitializer.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package io.greencap.k8s.config;
22

3+
import io.greencap.k8s.domain.cluster.ClusterProvider;
4+
import io.greencap.k8s.domain.cluster.ClusterRepository;
5+
import io.greencap.k8s.domain.cluster.ClusterService;
6+
import io.greencap.k8s.domain.cluster.CreateClusterRequest;
37
import io.greencap.k8s.domain.user.Permission;
48
import io.greencap.k8s.domain.user.UserRepository;
59
import io.greencap.k8s.domain.user.UserService;
@@ -14,14 +18,31 @@
1418
@RequiredArgsConstructor
1519
public class DataInitializer implements ApplicationRunner {
1620

21+
private static final String SELF_CLUSTER_NAME = "greencap-platform";
22+
private static final String SELF_CLUSTER_KUBECONFIG_ENV = "GREENCAP_SELF_CLUSTER_KUBECONFIG";
23+
1724
private final UserRepository userRepository;
1825
private final UserService userService;
26+
private final ClusterRepository clusterRepository;
27+
private final ClusterService clusterService;
1928

2029
@Override
2130
public void run(ApplicationArguments args) {
2231
if (!userRepository.existsByUsername("admin")) {
2332
userService.createUser("admin", "admin@greencap.local", "admin", Permission.allPermissions());
2433
log.info("Admin user created — login: admin / admin");
2534
}
35+
36+
String kubeconfig = System.getenv(SELF_CLUSTER_KUBECONFIG_ENV);
37+
if (kubeconfig != null && !kubeconfig.isBlank() && !clusterRepository.existsByName(SELF_CLUSTER_NAME)) {
38+
var cluster = clusterService.createCluster(new CreateClusterRequest(
39+
SELF_CLUSTER_NAME,
40+
ClusterProvider.MinikubeDocker,
41+
kubeconfig
42+
));
43+
userService.updateActiveCluster("admin", cluster);
44+
userService.updateActiveNamespace("admin", SELF_CLUSTER_NAME);
45+
log.info("Cluster '{}' auto-registered, set as active cluster and namespace for admin", SELF_CLUSTER_NAME);
46+
}
2647
}
2748
}

0 commit comments

Comments
 (0)