zyratlo opened a new pull request, #7932: URL: https://github.com/apache/texera/pull/7932
### What changes were proposed in this PR? The notebook migration tool shipped its backend service and workspace UI, but nothing deployed them. This PR makes the tool work out of the box in the single-node Docker Compose stack: it publishes images for the service and for the customized JupyterLab server, runs both in the stack, and routes the tool's API traffic through the existing nginx proxy. **`StorageConfig`, `NotebookMigrationResource` (one Jupyter URL becomes two)** - `storage.jupyter.url` splits into `internal-url` and `public-url`. The service calls Jupyter at the internal address (health probes, notebook upload and delete); the iframe URL handed to the browser is built from the public one. A containerized deployment needs both at once, since the in-network service name does not resolve from the browser. - `public-url` defaults to `internal-url`, so native local development and every existing deployment are unchanged. The old key had a single consumer and appeared in no deployment configuration, so no compatibility alias is kept. - The existing note about this service still targeting one Jupyter per process (#7665) is updated to name which URL is which. **`bin/dockerfiles/notebook-migration-service.dockerfile` (new)** - Follows `config-service.dockerfile`, which copies the shared config resources the service reads at startup. Omits the `.git` copy that exists elsewhere for jgit calls from `OPVersion`: that lives in `workflow-core` and `workflow-operator`, which this service does not depend on. **`bin/dockerfiles/jupyter.dockerfile` (new)** - Builds the customized JupyterLab image from the files that already live with the service, so the image can be published rather than built by hand. - Replaces `notebook-migration-service/src/main/resources/Dockerfile` and the standalone `docker-compose.yml` beside it, both now deleted. Every compose file in the repo consumes published images, so the per-service compose file had no remaining role once the image is built by CI. **`build-and-push-images.yml`** - Adds image name mappings for both new dockerfiles. Without them the discovery step falls through to its default and publishes under bare names, missing the `texera-` prefix every other image uses. **`bin/single-node/`** - `docker-compose.yml` runs `notebook-migration-service` and `jupyter`, the latter publishing its port because the browser loads it directly rather than through nginx. - The Jupyter container deliberately does not receive `env_file`. Users execute arbitrary code there, so it gets only the two values it needs instead of the whole environment, which carries the database, S3, lakeFS and LiteLLM credentials. This also keeps `JUPYTER_PORT` out of that container, which the base image would otherwise read and use to move the server off its expected port. - `nginx.conf` routes `/api/notebook-migration/` to the service. Longest prefix matching gives it priority over the `/api/` catch all. - `.env` gains the published port, the Jupyter token, the internal Jupyter address, and the GUI toggle for the tool. Values needing interpolation are set in the compose file instead, matching how lakeFS composes its browser facing presigned endpoint. **Docs** - `bin/single-node/README.md` covers the new port in all three places ports are listed, how to use and disable the tool, and a warning that all users share one JupyterLab server and one token, which is acceptable on a single machine but must not be carried into a multi-user deployment. ### Any related issues, documentation, discussions? Closes #7931 Parent issue #4301 ### How was this PR tested? Added a test in `StorageConfigSpec.scala` pinning that the public Jupyter URL defaults to the internal one, so splitting them stays a no-op outside containerized deployments. The rest of this PR is deployment configuration, which the existing suites do not cover. Existing suites pass: `NotebookMigrationService/test` (42), `Config/testOnly StorageConfigSpec`, and `bin/single-node/tests/test_single_node_sh.sh`. Manually verified by running the full stack with `bin/single-node.sh up`: - All containers reach a healthy state, including both new ones. - Authenticated through nginx, then called `/api/notebook-migration/get-jupyter-url`, which returned the browser reachable address rather than the in-network one. That request also confirms the internal direction, since the endpoint only succeeds after its reachability probe to Jupyter passes. - `POST /api/notebook-migration/set-notebook` through nginx succeeded and the notebook landed inside the Jupyter container. The iframe URL then returned 200 with the expected `frame-ancestors` header naming the Texera origin. - Confirmed no credentials are present in the Jupyter container's environment. - The existing routes (`/api/dataset`, `/api/computing-unit`, `/api/models`, `/api/compile`, `/`) are unaffected. - With an API key configured, a live model call through the tool's LLM path returned successfully. ### Was this PR authored or co-authored using generative AI tooling? Generated-by: Claude Code (Claude Opus 5) -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
