-
Notifications
You must be signed in to change notification settings - Fork 162
feat(python-notebook-migration): add JupyterLab docker for notebook migration tool #5256
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
67e5a82
added Docker related files for the Jupyter server
zyratlo e118ca4
Merge branch 'main' into migration-tool-jupyter-docker
zyratlo 52c4df2
Merge branch 'main' into migration-tool-jupyter-docker
zyratlo ca80390
Merge branch 'main' into migration-tool-jupyter-docker
zyratlo 4011ea7
Merge branch 'main' into migration-tool-jupyter-docker
zyratlo c7b7671
prevent duplicate cell click handlers on kernel restart
zyratlo ce77336
add restart policy and healthcheck to jupyter service
zyratlo 288c3cc
make texera origin configurable via TEXERA_ORIGIN env var
zyratlo f0c1624
require a token to access the jupyter server
zyratlo cd7d661
Merge branch 'main' into migration-tool-jupyter-docker
zyratlo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| # Licensed to the Apache Software Foundation (ASF) under one | ||
| # or more contributor license agreements. See the NOTICE file | ||
| # distributed with this work for additional information | ||
| # regarding copyright ownership. The ASF licenses this file | ||
| # to you under the Apache License, Version 2.0 (the | ||
| # "License"); you may not use this file except in compliance | ||
| # with the License. You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, | ||
| # software distributed under the License is distributed on an | ||
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| # KIND, either express or implied. See the License for the | ||
| # specific language governing permissions and limitations | ||
| # under the License. | ||
|
|
||
| FROM jupyter/base-notebook:notebook-6.5.4 | ||
|
|
||
| # Copy custom JavaScript for Jupyter and the startup script | ||
| COPY custom.js /home/jovyan/.jupyter/custom/custom.js | ||
| COPY start-texera-jupyter.sh /usr/local/bin/start-texera-jupyter.sh | ||
|
|
||
| # Ensure correct permissions. custom.js must stay writable by jovyan so the | ||
| # startup script can substitute the origin placeholder at runtime. | ||
| USER root | ||
| RUN mkdir -p /home/jovyan/.jupyter/custom && \ | ||
| chown -R jovyan:users /home/jovyan/.jupyter && \ | ||
| chmod +x /usr/local/bin/start-texera-jupyter.sh | ||
|
|
||
| USER jovyan |
103 changes: 103 additions & 0 deletions
103
notebook-migration-service/src/main/resources/custom.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| /** | ||
| * Licensed to the Apache Software Foundation (ASF) under one | ||
| * or more contributor license agreements. See the NOTICE file | ||
| * distributed with this work for additional information | ||
| * regarding copyright ownership. The ASF licenses this file | ||
| * to you under the Apache License, Version 2.0 (the | ||
| * "License"); you may not use this file except in compliance | ||
| * with the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, | ||
| * software distributed under the License is distributed on an | ||
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| * KIND, either express or implied. See the License for the | ||
| * specific language governing permissions and limitations | ||
| * under the License. | ||
| */ | ||
|
|
||
| // The Texera app origin. The "__TEXERA_ORIGIN__" placeholder is substituted at | ||
| // container startup by start-texera-jupyter.sh from the TEXERA_ORIGIN env var | ||
| // (defaults to http://localhost:4200), so deployments under a real hostname work | ||
| // without editing this file. | ||
| const TEXERA_ORIGIN = "__TEXERA_ORIGIN__"; | ||
|
|
||
| // Use Jupyter's event system to ensure the notebook is fully loaded | ||
| require(["base/js/events"], function (events) { | ||
| events.on("kernel_ready.Kernel", function () { | ||
|
|
||
| // Attach click event listener to cells. kernel_ready.Kernel fires on every | ||
| // kernel (re)start, so remove any previously bound handler first to avoid | ||
| // stacking duplicate listeners that would post N messages per click. | ||
| $("#notebook-container").off("click", ".cell").on("click", ".cell", function (event) { | ||
| const cell = $(this); | ||
| const index = $(".cell").index(cell); | ||
| const cellContent = cell.find(".input_area").text(); | ||
|
|
||
| // Get the UUID from the cell's metadata, or use "N/A" if it doesn't exist | ||
| const cellUUID = Jupyter.notebook.get_cell(index).metadata.uuid || 'N/A'; | ||
|
|
||
| // Send a message to the parent window (Texera app) | ||
| window.parent.postMessage( | ||
| { action: "cellClicked", cellIndex: index, cellContent: cellContent, cellUUID: cellUUID }, | ||
| TEXERA_ORIGIN | ||
| ); | ||
| }); | ||
|
mengw15 marked this conversation as resolved.
|
||
| }); | ||
| }); | ||
|
|
||
| // Listen for messages from the Texera app (or parent window) | ||
| window.addEventListener("message", function (event) { | ||
| // Verify the message origin | ||
| if (event.origin !== TEXERA_ORIGIN) { | ||
| console.warn("Message received from unrecognized origin:", event.origin); | ||
| return; | ||
| } | ||
|
|
||
| if (event.data.action === "triggerCellClick") { | ||
| const operatorCellUUIDs = event.data.operators || []; | ||
|
|
||
| if (!operatorCellUUIDs.length) { | ||
| console.error("No valid operator UUIDs provided in the message."); | ||
| return; // Exit if no UUIDs are provided | ||
| } | ||
|
|
||
| operatorCellUUIDs.forEach((cellUUID) => { | ||
| // Search for the cell by UUID | ||
| const allCells = Jupyter.notebook.get_cells(); | ||
| const targetCell = allCells.find((cell) => cell.metadata.uuid === cellUUID); | ||
|
|
||
| if (targetCell) { | ||
| const cellIndex = Jupyter.notebook.find_cell_index(targetCell); | ||
|
|
||
| // Scroll to and highlight the cell | ||
| let cell = document.querySelectorAll(".cell")[cellIndex]; | ||
| if (cell) { | ||
| cell.scrollIntoView({ behavior: 'smooth', block: 'center' }); | ||
| cell.classList.add("highlighted"); | ||
|
|
||
| // Remove the highlight after 3 seconds | ||
| setTimeout(() => { | ||
| cell.classList.remove("highlighted"); | ||
| }, 3000); | ||
| } else { | ||
| console.error(`Cell not found in the DOM for index ${cellIndex}.`); | ||
| } | ||
| } else { | ||
| console.error(`No cell found with UUID: ${cellUUID}`); | ||
| } | ||
| }); | ||
| } else { | ||
| console.warn("Received unknown action:", event.data.action); | ||
| } | ||
| }, false); | ||
|
|
||
| // Add custom CSS for highlighted cells | ||
| const style = document.createElement('style'); | ||
| style.innerHTML = ` | ||
| .cell.highlighted { | ||
| background-color: lightyellow; | ||
| } | ||
| `; | ||
| document.head.appendChild(style); | ||
44 changes: 44 additions & 0 deletions
44
notebook-migration-service/src/main/resources/docker-compose.yml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| # Licensed to the Apache Software Foundation (ASF) under one | ||
| # or more contributor license agreements. See the NOTICE file | ||
| # distributed with this work for additional information | ||
| # regarding copyright ownership. The ASF licenses this file | ||
| # to you under the Apache License, Version 2.0 (the | ||
| # "License"); you may not use this file except in compliance | ||
| # with the License. You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, | ||
| # software distributed under the License is distributed on an | ||
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| # KIND, either express or implied. See the License for the | ||
| # specific language governing permissions and limitations | ||
| # under the License. | ||
|
|
||
| name: texera-jupyter | ||
| services: | ||
|
|
||
| jupyter: | ||
| build: | ||
| context: . | ||
| dockerfile: Dockerfile | ||
| container_name: texera-jupyter | ||
|
mengw15 marked this conversation as resolved.
|
||
| restart: unless-stopped | ||
| ports: | ||
| - "9100:8888" | ||
| environment: | ||
| # Texera app origin, used for the iframe CSP frame-ancestors and the | ||
| # postMessage origin checks in custom.js. Override for non-local deployments. | ||
| - TEXERA_ORIGIN=http://localhost:4200 | ||
| # Weak default token so the server is not fully open. The Texera-side iframe | ||
| # URL must pass this through ?token=<value>. | ||
| - JUPYTER_TOKEN=texera | ||
| command: ["start-texera-jupyter.sh"] | ||
| healthcheck: | ||
| # /api returns the server version without requiring the token, so it is a | ||
| # reliable liveness probe even with auth enabled. | ||
| test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8888/api')"] | ||
| interval: 10s | ||
| timeout: 5s | ||
| retries: 5 | ||
| start_period: 15s | ||
38 changes: 38 additions & 0 deletions
38
notebook-migration-service/src/main/resources/start-texera-jupyter.sh
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| #!/bin/bash | ||
| # Licensed to the Apache Software Foundation (ASF) under one | ||
| # or more contributor license agreements. See the NOTICE file | ||
| # distributed with this work for additional information | ||
| # regarding copyright ownership. The ASF licenses this file | ||
| # to you under the Apache License, Version 2.0 (the | ||
| # "License"); you may not use this file except in compliance | ||
| # with the License. You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, | ||
| # software distributed under the License is distributed on an | ||
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| # KIND, either express or implied. See the License for the | ||
| # specific language governing permissions and limitations | ||
| # under the License. | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| # Texera app origin used by custom.js (postMessage targetOrigin + inbound origin | ||
| # check) and by the iframe CSP frame-ancestors. Override TEXERA_ORIGIN for | ||
| # deployments under a real hostname; defaults to the local dev origin. | ||
| TEXERA_ORIGIN="${TEXERA_ORIGIN:-http://localhost:4200}" | ||
|
|
||
| # Weak default token so the server is not fully open to anyone reachable on the | ||
| # published port. The Texera-side iframe URL must pass this through ?token=<value>. | ||
| JUPYTER_TOKEN="${JUPYTER_TOKEN:-texera}" | ||
|
|
||
| # Substitute the origin placeholder in custom.js before the server starts serving it. | ||
| sed -i "s|__TEXERA_ORIGIN__|${TEXERA_ORIGIN}|g" /home/jovyan/.jupyter/custom/custom.js | ||
|
|
||
| exec start-notebook.sh \ | ||
| --NotebookApp.token="${JUPYTER_TOKEN}" \ | ||
| --NotebookApp.password='' \ | ||
| --NotebookApp.disable_check_xsrf=True \ | ||
| --NotebookApp.tornado_settings="{'headers': {'Content-Security-Policy': 'frame-ancestors ${TEXERA_ORIGIN}'}}" \ | ||
| --NotebookApp.default_url=/tree |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.