Fase 2 — Hallazgos (data plane S3 ejecutado)
Resultado: ✅ transferencia S3→S3 (MinIO) y ✅ MONEY SHOT contra R2 REAL, ambas verificadas. El data plane S3 de EDC escribe en el R2 del lakehouse bajo contrato. Nuestro launcher propio compila y arranca.
Ejecutado el 2026-07-02. Approach: fase-2-approach.md · Arnés:services/edc-service/⚠️ HISTÓRICO (spike Fase 2, 2026-07-02). Runtime real hoy =
rest→Lakekeeper (ver ../INFRA.md). Las creds R2 de los scripts EDC ahora salen de.env.local(no de.env.lakehouse, retirado). Registro histórico.
1. Qué se logró
- Launcher propio (
services/edc-service/connector/build.gradle.kts) = conector base de Fase 1 +data-plane-aws-s3, inyectado en el árbol de Samples pineado y compilado. Un solo jar para provider y consumer. - MinIO como stand-in de R2 (S3-compatible, OSS, self-hostable).
- Ciclo DSP + transfer
AmazonS3-PUSHcompleto:Asset S3 → catálogo → negociación (INITIAL→VERIFYING→FINALIZED) → acuerdo → transfer S3-PUSH (INITIAL→STARTED→COMPLETED) → objeto sample.parquet aparece en consumer-inbox ✓ (verificado con mc)
Reproducible: docker compose up -d --build + bash run-cycle-s3.sh.
2. Versiones (el pin)
| Cosa | Valor |
|---|---|
| EDC core | 0.17.0 |
data-plane-aws-s3 | org.eclipse.edc.aws:data-plane-aws-s3:0.17.0 (misma versión que el core — version.ref="edc"; el riesgo de desalineación no existía) |
| Samples pin (SHA) | cc7a7e35dd37eae5f3646d0d87c1593e9f573f0e |
| Management API | v3 (el transfer S3 se ejecutó en v3, que funciona) |
| DSP | 2025-1 |
3. Formas de API nuevas (para edc-client.ts)
DataAddress AmazonS3 (source en el asset, y destino en el transfer):
{
"type": "AmazonS3",
"region": "us-east-1",
"bucketName": "provider-src",
"keyName": "sample.parquet",
"endpointOverride": "http://minio:9000",
"accessKeyId": "minioadmin",
"secretAccessKey": "minioadmin"
}
endpointOverrideen el DataAddress → apunta a MinIO/R2. Confirmado que funciona ahí (no sólo config global).- Credenciales inline en el DataAddress funcionan para el PoC. En producción → vault (referenciar por alias), nunca inline.
Transfer AmazonS3-PUSH (v3): mismo TransferRequestDto de Fase 1 + transferType: "AmazonS3-PUSH" + dataDestination con el DataAddress S3.
Estados de PUSH: INITIAL → STARTED → COMPLETED (en pull de Fase 1 se quedaba en STARTED; el push sí llega a COMPLETED). Dato para el worker (Fase 4): en push, esperar COMPLETED.
4. Respuestas a las sondas de riesgo
| Sonda | Resultado |
|---|---|
| Data plane S3 → object storage | ✅ Resuelto. EDC copia un objeto a un store S3-compatible vía endpointOverride. Riesgo técnico #1 del proyecto retirado. |
| R2 real | ✅ HECHO (money shot). MinIO→R2 real: el data plane de EDC escribió un objeto en el bucket del lakehouse en R2, verificado con aws-cli, y luego borrado (R2 impoluto). Ejecutado con run-cycle-r2.sh reutilizando las creds del lakehouse. Endpoint estándar R2 + region=auto → funcionó con virtual-host addressing (no hizo falta forzar path-style). |
| Recaptura API v4 | 🟡 Pendiente. El transfer S3 se hizo en v3 (funciona). v4alpha sigue para Fase 3, antes de escribir edc-client.ts. |
| Gancho DataSource Iceberg (Fase 5) | ✅ Confirmado el patrón: el módulo S3 se enchufa igual que se enchufará un DataSource Lakekeeper (misma mecánica de registro de data plane). |
5. R2 real — config lista (gated)
Para el money shot (ejecutar con tus creds, contra un prefijo scratch aislado):
"dataDestination": {
"type": "AmazonS3",
"region": "auto", // R2 sólo acepta "auto"
"bucketName": "<bucket-del-lakehouse>",
"keyName": "dataspace-inbox/sample.parquet", // prefijo scratch aislado
"endpointOverride": "https://<ACCOUNT_ID>.eu.r2.cloudflarestorage.com", // jurisdicción EU = residencia UE
"accessKeyId": "<R2_ACCESS_KEY_ID>", // vía .env, NUNCA en el repo
"secretAccessKey": "<R2_SECRET>"
}
A verificar en R2: path-style addressing (forcePathStyle) — con el SDK AWS v2 que usa EDC puede requerir un flag; si salta 403/HeadBucket, es esto. El endpoint .eu. es el ángulo soberanía vendible: el dato se queda en la UE por infraestructura.
6. Sorpresas / notas operativas
- Conflicto de puertos con Fase 1: el stack
poc/(Fase 1) ocupa 19193/29193. Bajarlo antes (docker compose -f poc/docker-compose.yml down) o los conectores de Fase 2 no bindean. minio/mctienemccomo entrypoint → para scripts hay que usar--entrypoint sh. (Corregido enrun-cycle-s3.sh.)- cwd + compose: usar
docker compose -f <ruta absoluta>para no depender del directorio actual (el shell resetea cwd entre llamadas). - Java host 1.8 → todo el build en Docker (igual que Fase 1).
- ⚠️ El sink S3 de EDC 0.17 ignora el prefijo del
keyNamede destino → escribe el objeto con el nombre base del source en la raíz del bucket (pedimosdataspace-inbox/sample.parquet, aterrizó comosample.parquet). Controlar la clave/prefijo de destino es un tema de Fase 4 (al aterrizar en rutas del lakehouse importará; investigarobjectName/prefijo del sink). Por eso el money-shot escribe en raíz y limpia el objeto tras verificar. - Reutilizamos las creds del lakehouse (
services/ml-runner/.env.lakehouse):LAKEHOUSE_S3_ENDPOINT/_ACCESS_KEY_ID/_SECRET_ACCESS_KEY/_REGION/_WAREHOUSE. No hizo falta setear nada nuevo. El script las lee de ahí y nunca las imprime (van sólo aout/, gitignored).
7. Definition of Done
- Launcher propio (
services/edc-service/) compila y arranca 2 conectores con módulo S3. - Transfer S3→S3 contra MinIO verificado (objeto en
consumer-inbox). - Transfer contra R2 real verificado (objeto en el bucket del lakehouse, luego borrado). ✅ money shot.
- Recaptura API v4alpha — pendiente (movida a Fase 3).
- Credenciales fuera de git (
.gitignore); reutilizadas del lakehouse; nunca impresas.
8. Cómo reproducir
cd services/edc-service
docker compose up -d --build # 2 conectores (S3) + MinIO + buckets
bash run-cycle-s3.sh # ciclo + transfer S3→S3 (MinIO) + verificación
bash run-cycle-r2.sh # MONEY SHOT: transfer → R2 real + verifica + limpia
# (lee creds de ../ml-runner/.env.lakehouse)
docker compose down -v # limpiar
9. Puente a la Fase 3
- Superficie de API (v3) capturada incl. DataAddress S3 → recapturar en v4 y construir
lib/dataspaces/edc-client.ts. - Executor
edc.executor.ts+ rutasapp/api/dataspaces/*para manejar el conector desde Node. - R2 real: cerrar el money-shot cuando haya creds/confirmación (§5).