Skip to content

Commit 5ca90ac

Browse files
committed
feat: sprint 83 — Import Compose: wizard 3 passos para importar docker-compose.yml de Git Repository público
Programado em par com: Claude IA
1 parent 56e4589 commit 5ca90ac

19 files changed

Lines changed: 1672 additions & 2 deletions
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
title: Parser de docker-compose.yml a partir de Git Repository
3+
status: open
4+
sprint: 83
5+
---
6+
7+
O GreenCap precisa buscar e interpretar um `docker-compose.yml` a partir de uma URL de Git Repository público. O resultado do parse deve ser um modelo intermediário que represente os serviços, portas, variáveis de ambiente, volumes e instruções de build encontrados no arquivo, sem nenhum acoplamento à UI ou à camada Kubernetes.
8+
9+
O parser recebe a URL do repositório Git, o branch e o path opcional para o arquivo dentro do repositório (padrão: `docker-compose.yml` na raiz). O clone é feito de forma efêmera, apenas para leitura do arquivo.
10+
11+
A tradução de `environment:` segue a heurística de chave sensível: chaves contendo `PASSWORD`, `SECRET`, `TOKEN`, `KEY` ou `CREDENTIAL` (case-insensitive) são classificadas como sensíveis; as demais como não sensíveis.
12+
13+
Volumes do tipo named (sem prefixo `./` ou `/`) são classificados como candidatos a PVC. Volumes do tipo bind-mount são classificados como ignorados.
14+
15+
Diretivas não reconhecidas ou não suportadas (como `networks:`, `restart:`, `healthcheck:`, `deploy:`, `profiles:`, `logging:`, `ulimits:`) são coletadas em uma lista separada para exibição de aviso na tela de revisão.
16+
17+
O modelo intermediário resultante deve ser suficientemente completo para que a camada de revisão da UI possa renderizá-lo e permitir edição dos campos configuráveis (tamanho de PVC, StorageClass, nome de imagem para serviços com `build:`) antes de qualquer chamada ao cluster.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
title: ImportComposeService — tradução do modelo intermediário para recursos Kubernetes
3+
status: open
4+
sprint: 83
5+
---
6+
7+
O `ImportComposeService` recebe o modelo intermediário produzido pelo parser (issue 01) e um request de configuração editado pelo usuário na tela de revisão, e provisiona todos os recursos Kubernetes no cluster ativo.
8+
9+
Cada serviço do Compose resulta em um Deployment. Quando o serviço declara `ports:`, um Service ClusterIP é criado. Quando há variáveis de ambiente, um ConfigMap (`<service>-config`) e/ou um Secret (`<service>-secret`) são criados conforme a classificação do parser. Quando há named volumes, um PersistentVolumeClaim (`<service>-pvc`) é criado com o StorageClass e tamanho informados pelo usuário (default: StorageClass default do cluster, 1Gi).
10+
11+
Todos os recursos recebem as labels `app.kubernetes.io/part-of: <namespace>` e `app.kubernetes.io/component: <service-name>`.
12+
13+
Serviços com `build:` exigem que o Build Kaniko correspondente (issue 03) já tenha sido executado com sucesso antes da criação dos recursos — a imagem resultante é a referência usada no Deployment.
14+
15+
O serviço tenta criar os recursos de todos os serviços antes de retornar, mesmo que algum falhe. O resultado acumula os recursos criados com sucesso e os que falharam, sem rollback. A lógica de falha parcial segue o padrão de `DeployApplicationResult`.
16+
17+
O Namespace é criado antes de qualquer outro recurso, como pré-condição.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
title: Integração com Build Kaniko para serviços com `build:`
3+
status: open
4+
sprint: 83
5+
---
6+
7+
Serviços do Compose que declaram `build:` precisam ter sua imagem construída antes da criação dos recursos Kubernetes. O GreenCap reutiliza o mecanismo de Build Kaniko existente (ADR 0007): um Job in-cluster no namespace `greencap-system`, com contexto Git apontando para o mesmo repositório fornecido no passo 1 do wizard, e `--dockerfile` derivado do campo `context`/`dockerfile` do Compose.
8+
9+
O nome da imagem produzida usa `image:` do Compose quando declarado junto de `build:`; quando ausente, usa `<service-name>:latest` como default — valor editável pelo usuário na tela de revisão antes de iniciar os builds.
10+
11+
Quando há múltiplos serviços com `build:`, os builds são executados em sequência. Cada build exibe seu log em tempo real na tela de execução (passo 3 do wizard), seguindo o padrão de `BuildView`. Se um build falhar, os builds subsequentes ainda são tentados; o resultado acumula sucesso e falha por serviço.
12+
13+
Um serviço cujo build falhou não tem seus recursos Kubernetes criados — o Deployment não é provisionado sem a imagem.
14+
15+
A integração deve reutilizar a infraestrutura existente de `BuildService` / `BuildJobFactory` sem duplicar lógica de criação de Job Kaniko.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
title: ImportComposeView — wizard 3 passos integrado ao DeployApplicationView
3+
status: open
4+
sprint: 83
5+
---
6+
7+
A `DeployApplicationView` existente ganha um segundo modo de entrada: "Deploy from image" (fluxo atual) e "Import Compose" (novo). A seleção entre os dois modos é feita no topo da view, antes de qualquer passo do wizard.
8+
9+
O wizard de Import Compose tem três passos:
10+
11+
**Passo 1 — Fonte e destino:** o usuário informa a URL do Git Repository público, o branch (default: `main`) e o path opcional para o `docker-compose.yml` dentro do repositório (default: `docker-compose.yml`). Também informa o nome do Namespace de destino. Ao avançar, o GreenCap busca e faz o parse do arquivo; erros de fetch ou parse são exibidos inline sem avançar.
12+
13+
**Passo 2 — Revisão:** a tela mostra um painel por serviço com os recursos que serão criados (Deployment, Service, ConfigMap, Secret, PVC), com campos editáveis para: nome da imagem (serviços com `build:`), tamanho e StorageClass dos PVCs, e classificação sensível/não-sensível das variáveis de ambiente. Uma seção consolidada "Diretivas ignoradas" lista o que foi encontrado no Compose mas não traduzido (bind mounts, `depends_on:`, `networks:`, etc.) com aviso visual mas sem bloquear o avanço. Serviços com `build:` exibem o nome da imagem que será produzida, editável.
14+
15+
**Passo 3 — Execução:** para serviços com `build:`, os Jobs Kaniko são criados e acompanhados com log live sequencialmente. Após todos os builds concluírem (com sucesso ou falha), os recursos Kubernetes são criados para os serviços cujos builds tiveram sucesso. Um resumo final mostra o resultado por serviço e por recurso. Em sucesso total, navega automaticamente para a Topologia do Namespace criado. Em falha parcial, permanece na tela de resultado com botão "Ver Topologia" para navegação manual.
16+
17+
Notificações seguem `Notification.Position.BOTTOM_END`. A view é protegida por `PROJECT_DEPLOY_APPLICATION`.

CONTEXT.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,10 @@ The source of a Build — a publicly accessible Git repository identified by URL
234234
_Avoid_: Source code, project, "repository" alone (ambiguous with Repository, the Registry concept)
235235

236236
**Deploy Application**:
237-
A wizard-guided write operation that creates a new Namespace and provisions the Kubernetes resources needed to run an application from a container image: a Deployment (always), a Service ClusterIP (when a container port is specified), a PersistentVolumeClaim (optional), and an Ingress (optional, requires a port). The image source is a free-text field (`repository:tag`) with suggestions from the active Cluster's internal Registry. Ingress host is auto-suggested as `<namespace>.greencap.local` and editable; IngressClassName is selected from IngressClasses available in the cluster. PVC StorageClass is selected from StorageClasses available in the cluster, with the cluster default pre-selected; access mode is always ReadWriteOnce. On partial failure, GreenCap reports which resources were created and which failed — no rollback is attempted. On success, navigates to the Topologia view of the newly created Namespace. The resulting resources are standard Kubernetes objects with no special GreenCap tracking; they are managed individually through the existing views after creation.
237+
A wizard-guided write operation that creates a new Namespace and provisions the Kubernetes resources needed to run an application from a container image: a Deployment (always), a Service ClusterIP (when a container port is specified), a PersistentVolumeClaim (optional), and an Ingress (optional, requires a port). The image source is a free-text field (`repository:tag`) with suggestions from the active Cluster's internal Registry. Ingress host is auto-suggested as `<namespace>.greencap.local` and editable; IngressClassName is selected from IngressClasses available in the cluster. PVC StorageClass is selected from StorageClasses available in the cluster, with the cluster default pre-selected; access mode is always ReadWriteOnce. On partial failure, GreenCap reports which resources were created and which failed — no rollback is attempted. On success, navigates to the Topologia view of the newly created Namespace. The resulting resources are standard Kubernetes objects with no special GreenCap tracking; they are managed individually through the existing views after creation. One of two entry modes in `DeployApplicationView` — the other is Import Compose.
238238
_Avoid_: New project, create project, provision application
239239

240+
**Import Compose**:
241+
A wizard-guided write operation that translates a `docker-compose.yml` from a public Git Repository into Kubernetes resources and provisions them in a single Namespace. Entry point is the same `DeployApplicationView` as Deploy Application, selected as a second mode. The wizard runs in three steps: (1) Git Repository URL + branch + optional path to the Compose file + Namespace name — GreenCap fetches and parses the file; (2) review screen showing all resources to be created, editable PVC and Secret fields, warnings for unsupported or ignored directives, and pending Builds for services with `build:`; (3) execution — Kaniko Builds run first (one per service with `build:`, live log), then all Kubernetes resources are created, and a result summary is shown. Translation rules: each Compose `service` becomes a Deployment; `ports:` becomes a ClusterIP Service; `environment:` keys matching `PASSWORD`, `SECRET`, `TOKEN`, `KEY`, or `CREDENTIAL` (case-insensitive) go to a Secret (`<service>-secret`), the rest to a ConfigMap (`<service>-config`); named `volumes:` become PersistentVolumeClaims (`<service>-pvc`, defaulting to 1Gi and the cluster's default StorageClass, editable); bind-mount volumes are ignored with a warning; `depends_on:` is ignored with an informative warning; `build:` triggers a Kaniko Build using the same Git Repository as context, pushing to the Cluster's Registry — image name taken from `image:` if declared alongside `build:`, otherwise defaults to `<service-name>:latest` (editable); `image:` without `build:` is used as-is. All generated resources carry `app.kubernetes.io/part-of: <namespace>` and `app.kubernetes.io/component: <service-name>` labels so they appear grouped in Topologia. On full success, navigates to Topologia of the new Namespace; on partial failure, stays on an inline result screen. No rollback on failure. Protected by `PROJECT_DEPLOY_APPLICATION`.
242+
_Avoid_: Compose deploy, stack import, docker-compose import
243+

docs/sprints.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
| 80 | Add Cluster dialog — provider Minikube (Docker), aviso OpenShift e comando kubectl copiável | ✅ Concluído |
1919
| 81 | Testes automatizados: TestContainers + cobertura de services críticos | ✅ Concluído |
2020
| 82 | Karibu-Testing: testes de views Vaadin — dialogs destrutivos | ✅ Concluído |
21+
| 83 | Import Compose — wizard 3 passos para importar docker-compose.yml de Git Repository público e provisionar recursos Kubernetes | 🔄 Em andamento |
2122

2223
---
2324

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
FROM node:20-alpine
2+
WORKDIR /app
3+
COPY . .
4+
EXPOSE 3000
5+
CMD ["node", "server.js"]
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
const http = require('http');
2+
3+
const PORT = process.env.APP_PORT || 3000;
4+
const SERVICE = 'greencap-demo-api';
5+
6+
const server = http.createServer((req, res) => {
7+
const body = JSON.stringify({
8+
service: SERVICE,
9+
status: 'ok',
10+
timestamp: new Date().toISOString(),
11+
env: process.env.NODE_ENV || 'development',
12+
});
13+
res.writeHead(200, { 'Content-Type': 'application/json' });
14+
res.end(body);
15+
});
16+
17+
server.listen(PORT, () => {
18+
console.log(`[${SERVICE}] Listening on port ${PORT}`);
19+
});
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
services:
2+
3+
postgres:
4+
image: postgres:16-alpine
5+
ports:
6+
- "5432:5432"
7+
environment:
8+
POSTGRES_DB: taskdb
9+
POSTGRES_USER: appuser
10+
POSTGRES_PASSWORD: pg-super-secret-password
11+
volumes:
12+
- postgres-data:/var/lib/postgresql/data
13+
restart: unless-stopped
14+
healthcheck:
15+
test: ["CMD-SHELL", "pg_isready -U appuser -d taskdb"]
16+
interval: 10s
17+
timeout: 5s
18+
retries: 5
19+
20+
redis:
21+
image: redis:7-alpine
22+
ports:
23+
- "6379:6379"
24+
environment:
25+
- REDIS_PASSWORD=redis-secret-token
26+
volumes:
27+
- redis-data:/data
28+
restart: unless-stopped
29+
30+
api:
31+
build:
32+
context: ./api
33+
dockerfile: Dockerfile
34+
ports:
35+
- "3000:3000"
36+
environment:
37+
- NODE_ENV=production
38+
- APP_PORT=3000
39+
- LOG_LEVEL=info
40+
- DB_HOST=postgres
41+
- DB_PORT=5432
42+
- DB_NAME=taskdb
43+
- DB_USER=appuser
44+
- DB_PASSWORD=pg-super-secret-password
45+
- REDIS_HOST=redis
46+
- REDIS_PORT=6379
47+
- REDIS_PASSWORD=redis-secret-token
48+
- JWT_SECRET_KEY=jwt-signing-secret-key
49+
- API_TOKEN=internal-api-access-token
50+
volumes:
51+
- api-uploads:/app/uploads
52+
depends_on:
53+
- postgres
54+
- redis
55+
restart: unless-stopped
56+
57+
worker:
58+
build:
59+
context: ./worker
60+
dockerfile: Dockerfile
61+
environment:
62+
- NODE_ENV=production
63+
- LOG_LEVEL=info
64+
- DB_HOST=postgres
65+
- DB_PORT=5432
66+
- DB_NAME=taskdb
67+
- DB_USER=appuser
68+
- DB_PASSWORD=pg-super-secret-password
69+
- REDIS_HOST=redis
70+
- REDIS_PORT=6379
71+
- REDIS_PASSWORD=redis-secret-token
72+
- WORKER_CONCURRENCY=4
73+
- WORKER_QUEUE=tasks
74+
depends_on:
75+
- postgres
76+
- redis
77+
restart: unless-stopped
78+
79+
nginx:
80+
image: nginx:1.27-alpine
81+
ports:
82+
- "80:80"
83+
environment:
84+
- NGINX_WORKER_PROCESSES=auto
85+
volumes:
86+
- ./nginx.conf:/etc/nginx/conf.d/default.conf
87+
depends_on:
88+
- api
89+
restart: unless-stopped
90+
91+
networks:
92+
app-network:
93+
driver: bridge
94+
95+
volumes:
96+
postgres-data:
97+
redis-data:
98+
api-uploads:
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
FROM node:20-alpine
2+
WORKDIR /app
3+
COPY . .
4+
CMD ["node", "worker.js"]

0 commit comments

Comments
 (0)