Unity-Glue-Reverse-Sync is a proof-of-concept Open Lakehouse Data Federation pipeline. It demonstrates how to achieve a "single copy of data" architecture by writing Delta Lake tables into Unity Catalog (OSS) and seamlessly exposing those exact same Parquet data files to the AWS ecosystem (AWS Glue / Athena) as first-class Apache Iceberg tables.
This project bridges the gap between Databricks-centric and AWS-centric data architectures using purely open-source technologies, explicitly bypassing known structural limitations in the open-source Delta UniForm converter when operating outside of managed Hive Metastores.
- Single Copy of Data: Write once (in Delta format) and query instantly from both Unity Catalog and Iceberg/Glue without data duplication or ETL pipelines.
- REST API Registration: Uses Unity Catalog's Native REST API to explicitly register tables, avoiding bugs in the Spark
UCSingleCatalogintegration. - Zero-ETL Iceberg Adoption: Leverages Iceberg's
add_filesprocedure to dynamically wrap Delta-generated Parquet files into a valid Iceberg catalog without requiring Delta's internalIcebergConverterhooks. - Fully Local Multi-Catalog Stack: Entirely containerized architecture running Spark, Unity Catalog OSS Server, Iceberg REST Catalog, and AWS LocalStack (S3 + Glue) using Docker Compose.
- Immutable Pipeline: 100% reproducible Jupyter Notebook phases for step-by-step validation of data state across engines.
The pipeline runs across a containerized multi-engine stack orchestrated by docker-compose:
| Service | Technology | Description |
|---|---|---|
| Compute Engine | PySpark (Jupyter) | Data processing and catalog operations orchestrator. |
| Delta Catalog | Unity Catalog (OSS) | Primary governance catalog for Delta tables. |
| Iceberg Catalog | Iceberg REST Catalog | Intermediate metadata layer for Iceberg. |
| AWS Cloud (Sim) | LocalStack | Provides S3-compatible storage and AWS Glue endpoints. |
| Data Format | Delta / Iceberg | Open table formats leveraging shared Parquet files. |
Due to limitations in OSS Delta's IcebergConverter against embedded Derby metastores, this pipeline uses an explicit adoption strategy:
- Delta Write: Standard Delta files are written to S3.
- UC Registration: Table is registered in Unity Catalog.
- Iceberg Adoption: An empty Iceberg table is created in the Central Catalog (Glue). Iceberg's
add_filesprocedure scans the Delta directory and adopts the Parquet files into the Iceberg manifest, bypassing the broken Delta converter entirely.
Unity-Glue-Reverse-Sync/
├── phase2_pipeline.ipynb # Phase 2: Data generation, Delta write, and UC REST API registration
├── phase3_reverse_sync.ipynb # Phase 3: Iceberg table creation and add_files adoption
├── .gitignore # Git exclusions for metastores and logs
├── docker-compose.yaml # Multi-catalog infrastructure definition
├── init.sh # Setup script to provision LocalStack S3 buckets
├── unity_server.properties # Configuration for the Unity Catalog OSS server
└── LICENSE.md # GPLv3 License
To run this pipeline locally, you will need:
- Docker Engine & Docker Compose (v2)
- A system capable of allocating at least 8GB of RAM to Docker.
-
Clone the repository:
git clone https://github.com/rdrishabh38/Unity-Glue-Reverse-Sync.git cd Unity-Glue-Reverse-Sync -
Launch the Infrastructure: Bring up the Spark, Unity Catalog, Iceberg REST, and LocalStack containers.
docker-compose up -d
-
Initialize S3 Storage: Run the initialization script to provision the required S3 buckets in LocalStack.
./init.sh
-
Execute the Pipeline:
- Open your browser and navigate to
http://localhost:8888to access the Jupyter environment. - Open and run
phase2_pipeline.ipynbto generate the mock data, write the Delta table, and register it in Unity Catalog. - Open and run
phase3_reverse_sync.ipynbto execute the reverse-sync into the Iceberg/Glue central catalog.
- Open your browser and navigate to
This project uses just to automate common development tasks.
| Recipe | Description | Command |
|---|---|---|
just build |
Build all the Docker images. | docker compose build |
just up |
Start all services in detached mode. | docker compose up -d |
just reset |
Wipe out containers/volumes (keep images), then start fresh. | docker compose down -v ... |
just down |
Stop all running services. | docker compose down |
just status |
Check the health/status of running containers. | docker compose ps |
just logs |
Follow logs for all active services. | docker compose logs -f |
just nuke |
Danger: Stop and remove all containers, images, and volumes. | docker compose down -v --rmi all ... |
The pipeline executes in sequential phases to ensure structural integrity across catalogs:
- Phase 2 (Delta -> Unity Catalog):
- Mock data is generated via PySpark.
- Data is written to LocalStack S3 natively as standard Delta format
df.write.format("delta"). - The Spark schema is converted to Unity Catalog's expected JSON format.
- The table is explicitly registered in Unity Catalog via
POST /api/2.1/unity-catalog/tablesto bypass Spark UC plugin bugs.
- Phase 3 (Delta -> Iceberg Reverse Sync):
- The pipeline connects to the
central_catalog(Iceberg REST/Glue). - It infers the schema directly from the underlying Parquet files written by Delta (
AS SELECT * FROM parquet... WHERE 1=0). - The
CALL central_catalog.system.add_filesprocedure natively adopts the physical Parquet files into the Iceberg table manifest.
- The pipeline connects to the
- Phase 4 (Validation):
- A simulated Athena read is executed via Spark SQL
SELECT * FROM central_catalog...to prove end-to-end compatibility.
- A simulated Athena read is executed via Spark SQL
This pipeline was designed specifically to bypass several blocking bugs and structural limitations in the current OSS Lakehouse ecosystem (Delta 3.2.x, Unity Catalog OSS 0.2.0):
-
Unity Catalog OSS Spark Integration Bug:
- Issue: The
UCSingleCatalogSpark plugin fails to properly inject AWS credentials during path-based table creations, andReplaceTableAsSelectcommands fail with unresolved external paths. - Workaround: We bypass the Spark catalog plugin entirely for the write path. We use native Spark
df.write.format("delta").save()to write the files to S3, and then explicitly call the Unity Catalog REST API (POST /api/2.1/unity-catalog/tables) to register the external table.
- Issue: The
-
Delta UniForm Metadata Generation Failure:
- Issue: Delta OSS UniForm relies on an asynchronous post-commit hook (
IcebergConverter) to generate Iceberg metadata. This converter is hardcoded to expect a fully-featured Hive Metastore. When running against an embedded Derby metastore or Unity Catalog, the converter encounters a fatalNullPointerExceptionwhen callingHiveTableOperations.getSd()because the simulated Hive table lacks aStorageDescriptor. Worse, when the commit fails, Iceberg's transaction rollback automatically deletes the orphaned.metadata.jsonfile. - Context: This is a known structural limitation corroborated by delta-io/delta#3217.
- Workaround: We completely dropped the Delta UniForm dependency (
UPGRADE UNIFORM (ICEBERG_COMPAT_VERSION=2)). Instead, we natively construct the Iceberg table in the Central Catalog and use Iceberg'sadd_filesprocedure to adopt the raw Delta Parquet files.
- Issue: Delta OSS UniForm relies on an asynchronous post-commit hook (
Copyright (C) 2026 Rishabh Dixit. All Rights Reserved.
This project is licensed under the GNU General Public License v3.0. See the LICENSE.md file for details.
- OSS UniForm Limitations: This pipeline specifically acts as a workaround for structural limitations in OSS Delta Lake 3.2.x
IcebergConverterwhen operating outside of a managed Hive Metastore. - Column Mapping: Delta Column Mapping (
namemode) must remain disabled for thisadd_filesarchitecture to function, as Iceberg requires the physical Parquet column names to match the logical schema.