From 8ad22eff946073c43a1f85f25f0a6301d0e52bd5 Mon Sep 17 00:00:00 2001 From: Mish <10400064+mishushakov@users.noreply.github.com> Date: Sat, 26 Apr 2025 11:36:55 +0200 Subject: [PATCH 01/16] wip --- template/Dockerfile | 19 ++++++++++--------- template/e2b.toml | 17 ++++++++--------- template/server/main.py | 2 +- template/start-up.sh | 12 ++++++------ template/test.Dockerfile | 30 ++++++++++++++++-------------- 5 files changed, 41 insertions(+), 39 deletions(-) diff --git a/template/Dockerfile b/template/Dockerfile index b023150d..bde01d27 100644 --- a/template/Dockerfile +++ b/template/Dockerfile @@ -3,12 +3,14 @@ FROM python:3.10.14 RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y --no-install-recommends \ build-essential curl git util-linux jq sudo nodejs npm fonts-noto-cjk +RUN mkdir -p /home/user/.jupyter /home/user/.ipython /home/user/.server + ENV PIP_DEFAULT_TIMEOUT=100 \ PIP_DISABLE_PIP_VERSION_CHECK=1 \ PIP_NO_CACHE_DIR=1 \ - JUPYTER_CONFIG_PATH="/root/.jupyter" \ - IPYTHON_CONFIG_PATH="/root/.ipython" \ - SERVER_PATH="/root/.server" \ + JUPYTER_CONFIG_PATH="/home/user/.jupyter" \ + IPYTHON_CONFIG_PATH="/home/user/.ipython" \ + SERVER_PATH="/home/user/.server" \ R_VERSION=4.4.2 ENV R_HOME=/opt/R/${R_VERSION} \ @@ -19,9 +21,9 @@ COPY ./requirements.txt requirements.txt RUN pip install --no-cache-dir -r requirements.txt && ipython kernel install --name "python3" --user # R Kernel -RUN curl -O https://cdn.rstudio.com/r/debian-12/pkgs/r-${R_VERSION}_1_amd64.deb && sudo apt-get update && sudo apt-get install -y ./r-${R_VERSION}_1_amd64.deb && ln -s ${R_HOME}/bin/R /usr/bin/R -RUN R -e "install.packages('IRkernel', repos='https://cloud.r-project.org')" -RUN R -e "IRkernel::installspec(user = FALSE, name = 'r', displayname = 'R')" +# RUN curl -O https://cdn.rstudio.com/r/debian-12/pkgs/r-${R_VERSION}_1_amd64.deb && sudo apt-get update && sudo apt-get install -y ./r-${R_VERSION}_1_amd64.deb && ln -s ${R_HOME}/bin/R /usr/bin/R +# RUN R -e "install.packages('IRkernel', repos='https://cloud.r-project.org')" +# RUN R -e "IRkernel::installspec(user = FALSE, name = 'r', displayname = 'R')" # Javascript Kernel RUN npm install -g node-gyp @@ -32,7 +34,7 @@ RUN ijsinstall --install=global COPY --from=denoland/deno:bin-2.0.4 /deno /usr/bin/deno RUN chmod +x /usr/bin/deno RUN deno jupyter --unstable --install -COPY ./deno.json /root/.local/share/jupyter/kernels/deno/kernel.json +COPY ./deno.json /home/user/.local/share/jupyter/kernels/deno/kernel.json # Bash Kernel RUN pip install bash_kernel @@ -42,13 +44,12 @@ RUN python -m bash_kernel.install RUN python -m venv $SERVER_PATH/.venv # Copy server and its requirements -RUN mkdir -p $SERVER_PATH/ COPY ./server/requirements.txt $SERVER_PATH RUN $SERVER_PATH/.venv/bin/pip install --no-cache-dir -r $SERVER_PATH/requirements.txt COPY ./server $SERVER_PATH # Copy matplotlibrc -COPY matplotlibrc /root/.config/matplotlib/.matplotlibrc +COPY matplotlibrc /home/user/.config/matplotlib/.matplotlibrc # Copy Jupyter configuration COPY ./start-up.sh $JUPYTER_CONFIG_PATH/ diff --git a/template/e2b.toml b/template/e2b.toml index a488e5d9..a25b3058 100644 --- a/template/e2b.toml +++ b/template/e2b.toml @@ -1,18 +1,17 @@ # This is a config for E2B sandbox template. -# You can use template ID (nlhz8vlwyupq845jsdg9) or template name (code-interpreter-v1) to create a sandbox: +# You can use template ID (8cvk102nkxqyd5l3kelv) to create a sandbox: # Python SDK # from e2b import Sandbox, AsyncSandbox -# sandbox = Sandbox("code-interpreter-v1") # Sync sandbox -# sandbox = await AsyncSandbox.create("code-interpreter-v1") # Async sandbox +# sandbox = Sandbox("8cvk102nkxqyd5l3kelv") # Sync sandbox +# sandbox = await AsyncSandbox.create("8cvk102nkxqyd5l3kelv") # Async sandbox # JS SDK # import { Sandbox } from 'e2b' -# const sandbox = await Sandbox.create('code-interpreter-v1') +# const sandbox = await Sandbox.create('8cvk102nkxqyd5l3kelv') -team_id = "460355b3-4f64-48f9-9a16-4442817f79f5" +team_id = "400a4584-3d22-4b70-82ee-0bc6cce4aaa5" memory_mb = 1_024 -start_cmd = "/root/.jupyter/start-up.sh" -dockerfile = "e2b.Dockerfile" -template_name = "code-interpreter-v1" -template_id = "nlhz8vlwyupq845jsdg9" +start_cmd = "/home/user/.jupyter/start-up.sh" +dockerfile = "Dockerfile" +template_id = "8cvk102nkxqyd5l3kelv" diff --git a/template/server/main.py b/template/server/main.py index fa7760a9..8b6586b9 100644 --- a/template/server/main.py +++ b/template/server/main.py @@ -34,7 +34,7 @@ async def lifespan(app: FastAPI): global client client = httpx.AsyncClient() - with open("/root/.jupyter/kernel_id") as file: + with open("/home/user/.jupyter/kernel_id") as file: default_context_id = file.read().strip() default_ws = ContextWebSocket( diff --git a/template/start-up.sh b/template/start-up.sh index fb45f470..e08be4b2 100644 --- a/template/start-up.sh +++ b/template/start-up.sh @@ -20,15 +20,15 @@ function start_jupyter_server() { exit 1 fi - sudo mkdir -p /root/.jupyter + mkdir -p /home/user/.jupyter kernel_id=$(echo "${response}" | jq -r '.kernel.id') - sudo echo "${kernel_id}" | sudo tee /root/.jupyter/kernel_id >/dev/null - sudo echo "${response}" | sudo tee /root/.jupyter/.session_info >/dev/null + echo "${kernel_id}" > /home/user/.jupyter/kernel_id + echo "${response}" > /home/user/.jupyter/.session_info - cd /root/.server/ - /root/.server/.venv/bin/uvicorn main:app --host 0.0.0.0 --port 49999 --workers 1 --no-access-log --no-use-colors + cd /home/user/.server/ + /home/user/.server/.venv/bin/uvicorn main:app --host 0.0.0.0 --port 49999 --workers 1 --no-access-log --no-use-colors } echo "Starting Code Interpreter server..." start_jupyter_server & -MATPLOTLIBRC=/root/.config/matplotlib/.matplotlibrc jupyter server --IdentityProvider.token="" >/dev/null 2>&1 +MATPLOTLIBRC=/home/user/.config/matplotlib/.matplotlibrc jupyter server --IdentityProvider.token="" >/dev/null 2>&1 diff --git a/template/test.Dockerfile b/template/test.Dockerfile index f3647911..17bba19f 100644 --- a/template/test.Dockerfile +++ b/template/test.Dockerfile @@ -7,15 +7,17 @@ ENV PATH="${JAVA_HOME}/bin:${PATH}" RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y --no-install-recommends \ build-essential curl git util-linux jq sudo nodejs npm fonts-noto-cjk +RUN mkdir -p /home/user/.jupyter /home/user/.ipython /home/user/.server + ENV PIP_DEFAULT_TIMEOUT=100 \ PIP_DISABLE_PIP_VERSION_CHECK=1 \ PIP_NO_CACHE_DIR=1 \ - JUPYTER_CONFIG_PATH="/root/.jupyter" \ - IPYTHON_CONFIG_PATH="/root/.ipython" \ - SERVER_PATH="/root/.server" + JUPYTER_CONFIG_PATH="/home/user/.jupyter" \ + IPYTHON_CONFIG_PATH="/home/user/.ipython" \ + SERVER_PATH="/home/user/.server" # Install Jupyter -COPY ./template/requirements.txt requirements.txt +COPY ./requirements.txt requirements.txt RUN pip install --no-cache-dir -r requirements.txt && ipython kernel install --name "python3" --user # Javascript Kernel @@ -27,34 +29,34 @@ RUN ijsinstall --install=global COPY --from=denoland/deno:bin-2.0.4 /deno /usr/bin/deno RUN chmod +x /usr/bin/deno RUN deno jupyter --unstable --install -COPY ./template/deno.json /root/.local/share/jupyter/kernels/deno/kernel.json +COPY ./deno.json /home/user/.local/share/jupyter/kernels/deno/kernel.json # Create separate virtual environment for server RUN python -m venv $SERVER_PATH/.venv # Copy server and its requirements RUN mkdir -p $SERVER_PATH/ -COPY ./template/server/requirements.txt $SERVER_PATH +COPY ./server/requirements.txt $SERVER_PATH RUN $SERVER_PATH/.venv/bin/pip install --no-cache-dir -r $SERVER_PATH/requirements.txt -COPY ./template/server $SERVER_PATH +COPY ./server $SERVER_PATH # Copy matplotlibrc -COPY ./template/matplotlibrc /root/.config/matplotlib/matplotlibrc +COPY ./matplotlibrc /home/user/.config/matplotlib/matplotlibrc # Copy Jupyter configuration -COPY ./template/start-up.sh $JUPYTER_CONFIG_PATH/ +COPY ./start-up.sh $JUPYTER_CONFIG_PATH/ RUN chmod +x $JUPYTER_CONFIG_PATH/start-up.sh -COPY ./template/jupyter_server_config.py $JUPYTER_CONFIG_PATH/ +COPY ./jupyter_server_config.py $JUPYTER_CONFIG_PATH/ RUN mkdir -p $IPYTHON_CONFIG_PATH/profile_default -COPY ./template/ipython_kernel_config.py $IPYTHON_CONFIG_PATH/profile_default/ +COPY ./ipython_kernel_config.py $IPYTHON_CONFIG_PATH/profile_default/ RUN mkdir -p $IPYTHON_CONFIG_PATH/profile_default/startup -COPY ./template/startup_scripts/* $IPYTHON_CONFIG_PATH/profile_default/startup +COPY ./startup_scripts/* $IPYTHON_CONFIG_PATH/profile_default/startup # Setup entrypoint for local development WORKDIR /home/user -COPY ./chart_data_extractor ./chart_data_extractor -RUN pip install -e ./chart_data_extractor +# COPY ./chart_data_extractor ./chart_data_extractor +# RUN pip install -e ./chart_data_extractor ENTRYPOINT $JUPYTER_CONFIG_PATH/start-up.sh From 14e0c51476e0f3010b7f2d9c2bf4baf0e3e88a91 Mon Sep 17 00:00:00 2001 From: Mish <10400064+mishushakov@users.noreply.github.com> Date: Sat, 26 Apr 2025 12:32:02 +0200 Subject: [PATCH 02/16] fix file paths --- template/test.Dockerfile | 45 ++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/template/test.Dockerfile b/template/test.Dockerfile index 17bba19f..5ffd49d6 100644 --- a/template/test.Dockerfile +++ b/template/test.Dockerfile @@ -1,23 +1,25 @@ FROM python:3.10.14 +# Create a non-root user +RUN useradd -m -s /bin/bash user +ENV HOME=/home/user + ENV JAVA_HOME=/opt/java/openjdk COPY --from=eclipse-temurin:11-jdk $JAVA_HOME $JAVA_HOME ENV PATH="${JAVA_HOME}/bin:${PATH}" RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y --no-install-recommends \ - build-essential curl git util-linux jq sudo nodejs npm fonts-noto-cjk - -RUN mkdir -p /home/user/.jupyter /home/user/.ipython /home/user/.server + build-essential curl git util-linux jq nodejs npm fonts-noto-cjk ENV PIP_DEFAULT_TIMEOUT=100 \ PIP_DISABLE_PIP_VERSION_CHECK=1 \ PIP_NO_CACHE_DIR=1 \ - JUPYTER_CONFIG_PATH="/home/user/.jupyter" \ - IPYTHON_CONFIG_PATH="/home/user/.ipython" \ - SERVER_PATH="/home/user/.server" + JUPYTER_CONFIG_PATH="$HOME/.jupyter" \ + IPYTHON_CONFIG_PATH="$HOME/.ipython" \ + SERVER_PATH="$HOME/.server" # Install Jupyter -COPY ./requirements.txt requirements.txt +COPY ./template/requirements.txt requirements.txt RUN pip install --no-cache-dir -r requirements.txt && ipython kernel install --name "python3" --user # Javascript Kernel @@ -29,34 +31,41 @@ RUN ijsinstall --install=global COPY --from=denoland/deno:bin-2.0.4 /deno /usr/bin/deno RUN chmod +x /usr/bin/deno RUN deno jupyter --unstable --install -COPY ./deno.json /home/user/.local/share/jupyter/kernels/deno/kernel.json +COPY ./template/deno.json $HOME/.local/share/jupyter/kernels/deno/kernel.json # Create separate virtual environment for server RUN python -m venv $SERVER_PATH/.venv # Copy server and its requirements RUN mkdir -p $SERVER_PATH/ -COPY ./server/requirements.txt $SERVER_PATH +COPY ./template/server/requirements.txt $SERVER_PATH RUN $SERVER_PATH/.venv/bin/pip install --no-cache-dir -r $SERVER_PATH/requirements.txt -COPY ./server $SERVER_PATH +COPY ./template/server $SERVER_PATH # Copy matplotlibrc -COPY ./matplotlibrc /home/user/.config/matplotlib/matplotlibrc +COPY ./template/matplotlibrc $HOME/.config/matplotlib/matplotlibrc # Copy Jupyter configuration -COPY ./start-up.sh $JUPYTER_CONFIG_PATH/ +COPY ./template/start-up.sh $JUPYTER_CONFIG_PATH/ RUN chmod +x $JUPYTER_CONFIG_PATH/start-up.sh -COPY ./jupyter_server_config.py $JUPYTER_CONFIG_PATH/ +COPY ./template/jupyter_server_config.py $JUPYTER_CONFIG_PATH/ RUN mkdir -p $IPYTHON_CONFIG_PATH/profile_default -COPY ./ipython_kernel_config.py $IPYTHON_CONFIG_PATH/profile_default/ +COPY ./template/ipython_kernel_config.py $IPYTHON_CONFIG_PATH/profile_default/ RUN mkdir -p $IPYTHON_CONFIG_PATH/profile_default/startup -COPY ./startup_scripts/* $IPYTHON_CONFIG_PATH/profile_default/startup +COPY ./template/startup_scripts/* $IPYTHON_CONFIG_PATH/profile_default/startup # Setup entrypoint for local development -WORKDIR /home/user -# COPY ./chart_data_extractor ./chart_data_extractor -# RUN pip install -e ./chart_data_extractor +WORKDIR $HOME +COPY ./chart_data_extractor ./chart_data_extractor +RUN pip install -e ./chart_data_extractor + +# Set ownership of all files to the user +RUN chown -R user:user $HOME + +# Switch to non-root user +USER user + ENTRYPOINT $JUPYTER_CONFIG_PATH/start-up.sh From 9d737892f017a333f0b951b6d39ad15e9e1ca165 Mon Sep 17 00:00:00 2001 From: Mish <10400064+mishushakov@users.noreply.github.com> Date: Mon, 28 Apr 2025 13:44:35 +0200 Subject: [PATCH 03/16] fixes start command, adds logging, removes useradd in prod Docker --- template/Dockerfile | 15 ++++++++------- template/e2b.toml | 2 +- template/start-up.sh | 4 ++-- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/template/Dockerfile b/template/Dockerfile index bde01d27..6736ead0 100644 --- a/template/Dockerfile +++ b/template/Dockerfile @@ -1,16 +1,18 @@ FROM python:3.10.14 +ENV HOME=/home/user + RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y --no-install-recommends \ build-essential curl git util-linux jq sudo nodejs npm fonts-noto-cjk -RUN mkdir -p /home/user/.jupyter /home/user/.ipython /home/user/.server +RUN mkdir -p $HOME/.jupyter $HOME/.ipython $HOME/.server ENV PIP_DEFAULT_TIMEOUT=100 \ PIP_DISABLE_PIP_VERSION_CHECK=1 \ PIP_NO_CACHE_DIR=1 \ - JUPYTER_CONFIG_PATH="/home/user/.jupyter" \ - IPYTHON_CONFIG_PATH="/home/user/.ipython" \ - SERVER_PATH="/home/user/.server" \ + JUPYTER_CONFIG_PATH="$HOME/.jupyter" \ + IPYTHON_CONFIG_PATH="$HOME/.ipython" \ + SERVER_PATH="$HOME/.server" \ R_VERSION=4.4.2 ENV R_HOME=/opt/R/${R_VERSION} \ @@ -34,7 +36,7 @@ RUN ijsinstall --install=global COPY --from=denoland/deno:bin-2.0.4 /deno /usr/bin/deno RUN chmod +x /usr/bin/deno RUN deno jupyter --unstable --install -COPY ./deno.json /home/user/.local/share/jupyter/kernels/deno/kernel.json +COPY ./deno.json $HOME/.local/share/jupyter/kernels/deno/kernel.json # Bash Kernel RUN pip install bash_kernel @@ -49,7 +51,7 @@ RUN $SERVER_PATH/.venv/bin/pip install --no-cache-dir -r $SERVER_PATH/requiremen COPY ./server $SERVER_PATH # Copy matplotlibrc -COPY matplotlibrc /home/user/.config/matplotlib/.matplotlibrc +COPY matplotlibrc $HOME/.config/matplotlib/matplotlibrc # Copy Jupyter configuration COPY ./start-up.sh $JUPYTER_CONFIG_PATH/ @@ -63,7 +65,6 @@ COPY ipython_kernel_config.py $IPYTHON_CONFIG_PATH/profile_default/ RUN mkdir -p $IPYTHON_CONFIG_PATH/profile_default/startup COPY startup_scripts/* $IPYTHON_CONFIG_PATH/profile_default/startup - COPY --from=eclipse-temurin:11-jdk $JAVA_HOME $JAVA_HOME RUN ln -s ${JAVA_HOME}/bin/java /usr/bin/java diff --git a/template/e2b.toml b/template/e2b.toml index a25b3058..175b0a05 100644 --- a/template/e2b.toml +++ b/template/e2b.toml @@ -12,6 +12,6 @@ team_id = "400a4584-3d22-4b70-82ee-0bc6cce4aaa5" memory_mb = 1_024 -start_cmd = "/home/user/.jupyter/start-up.sh" +start_cmd = "sudo -u user /home/user/.jupyter/start-up.sh" dockerfile = "Dockerfile" template_id = "8cvk102nkxqyd5l3kelv" diff --git a/template/start-up.sh b/template/start-up.sh index e08be4b2..492cb4bd 100644 --- a/template/start-up.sh +++ b/template/start-up.sh @@ -26,9 +26,9 @@ function start_jupyter_server() { echo "${response}" > /home/user/.jupyter/.session_info cd /home/user/.server/ - /home/user/.server/.venv/bin/uvicorn main:app --host 0.0.0.0 --port 49999 --workers 1 --no-access-log --no-use-colors + /home/user/.server/.venv/bin/uvicorn main:app --host 0.0.0.0 --port 49999 --workers 1 --no-access-log --no-use-colors >> /home/user/uvicorn_server.log 2>&1 } echo "Starting Code Interpreter server..." start_jupyter_server & -MATPLOTLIBRC=/home/user/.config/matplotlib/.matplotlibrc jupyter server --IdentityProvider.token="" >/dev/null 2>&1 +MATPLOTLIBRC=/home/user/.config/matplotlib/.matplotlibrc jupyter server --IdentityProvider.token="" >> /home/user/jupyter_server.log 2>&1 From e6edde7081a91b4ea33d4b3df6701fd5091ba978 Mon Sep 17 00:00:00 2001 From: Mish <10400064+mishushakov@users.noreply.github.com> Date: Mon, 28 Apr 2025 14:08:40 +0200 Subject: [PATCH 04/16] undo some changes to e2b.toml, bring back r kernel --- template/Dockerfile | 6 +++--- template/e2b.toml | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/template/Dockerfile b/template/Dockerfile index 6736ead0..773e90e3 100644 --- a/template/Dockerfile +++ b/template/Dockerfile @@ -23,9 +23,9 @@ COPY ./requirements.txt requirements.txt RUN pip install --no-cache-dir -r requirements.txt && ipython kernel install --name "python3" --user # R Kernel -# RUN curl -O https://cdn.rstudio.com/r/debian-12/pkgs/r-${R_VERSION}_1_amd64.deb && sudo apt-get update && sudo apt-get install -y ./r-${R_VERSION}_1_amd64.deb && ln -s ${R_HOME}/bin/R /usr/bin/R -# RUN R -e "install.packages('IRkernel', repos='https://cloud.r-project.org')" -# RUN R -e "IRkernel::installspec(user = FALSE, name = 'r', displayname = 'R')" +RUN curl -O https://cdn.rstudio.com/r/debian-12/pkgs/r-${R_VERSION}_1_amd64.deb && sudo apt-get update && sudo apt-get install -y ./r-${R_VERSION}_1_amd64.deb && ln -s ${R_HOME}/bin/R /usr/bin/R +RUN R -e "install.packages('IRkernel', repos='https://cloud.r-project.org')" +RUN R -e "IRkernel::installspec(user = FALSE, name = 'r', displayname = 'R')" # Javascript Kernel RUN npm install -g node-gyp diff --git a/template/e2b.toml b/template/e2b.toml index 175b0a05..9a6db623 100644 --- a/template/e2b.toml +++ b/template/e2b.toml @@ -1,17 +1,17 @@ # This is a config for E2B sandbox template. -# You can use template ID (8cvk102nkxqyd5l3kelv) to create a sandbox: +# You can use template ID (nlhz8vlwyupq845jsdg9) or template name (code-interpreter-v1) to create a sandbox: # Python SDK # from e2b import Sandbox, AsyncSandbox -# sandbox = Sandbox("8cvk102nkxqyd5l3kelv") # Sync sandbox -# sandbox = await AsyncSandbox.create("8cvk102nkxqyd5l3kelv") # Async sandbox +# sandbox = Sandbox("code-interpreter-v1") # Sync sandbox +# sandbox = await AsyncSandbox.create("code-interpreter-v1") # Async sandbox # JS SDK # import { Sandbox } from 'e2b' -# const sandbox = await Sandbox.create('8cvk102nkxqyd5l3kelv') - -team_id = "400a4584-3d22-4b70-82ee-0bc6cce4aaa5" +# const sandbox = await Sandbox.create('code-interpreter-v1') +team_id = "460355b3-4f64-48f9-9a16-4442817f79f5" memory_mb = 1_024 start_cmd = "sudo -u user /home/user/.jupyter/start-up.sh" -dockerfile = "Dockerfile" -template_id = "8cvk102nkxqyd5l3kelv" +dockerfile = "e2b.Dockerfile" +template_name = "code-interpreter-v1" +template_id = "nlhz8vlwyupq845jsdg9" \ No newline at end of file From 4aeaeef1968cf1a092c94d1ae6f0a743932e00ea Mon Sep 17 00:00:00 2001 From: Mish <10400064+mishushakov@users.noreply.github.com> Date: Tue, 29 Apr 2025 15:52:24 +0200 Subject: [PATCH 05/16] wip --- template/Dockerfile | 5 +++-- template/server/main.py | 4 ++-- template/start-up.sh | 14 +++++++------- template/test.Dockerfile | 22 ++++++++++------------ 4 files changed, 22 insertions(+), 23 deletions(-) diff --git a/template/Dockerfile b/template/Dockerfile index 773e90e3..292f9356 100644 --- a/template/Dockerfile +++ b/template/Dockerfile @@ -20,7 +20,7 @@ ENV R_HOME=/opt/R/${R_VERSION} \ # Install Jupyter COPY ./requirements.txt requirements.txt -RUN pip install --no-cache-dir -r requirements.txt && ipython kernel install --name "python3" --user +RUN pip install --no-cache-dir -r requirements.txt && ipython kernel install --name "python3" # R Kernel RUN curl -O https://cdn.rstudio.com/r/debian-12/pkgs/r-${R_VERSION}_1_amd64.deb && sudo apt-get update && sudo apt-get install -y ./r-${R_VERSION}_1_amd64.deb && ln -s ${R_HOME}/bin/R /usr/bin/R @@ -36,7 +36,8 @@ RUN ijsinstall --install=global COPY --from=denoland/deno:bin-2.0.4 /deno /usr/bin/deno RUN chmod +x /usr/bin/deno RUN deno jupyter --unstable --install -COPY ./deno.json $HOME/.local/share/jupyter/kernels/deno/kernel.json +RUN mkdir -p /usr/local/share/jupyter/kernels/deno +COPY ./kernel/deno.json /usr/local/share/jupyter/kernels/deno/kernel.json # Bash Kernel RUN pip install bash_kernel diff --git a/template/server/main.py b/template/server/main.py index 8b6586b9..f26ae2e3 100644 --- a/template/server/main.py +++ b/template/server/main.py @@ -34,14 +34,14 @@ async def lifespan(app: FastAPI): global client client = httpx.AsyncClient() - with open("/home/user/.jupyter/kernel_id") as file: + with open("/root/.jupyter/kernel_id") as file: default_context_id = file.read().strip() default_ws = ContextWebSocket( default_context_id, str(uuid.uuid4()), "python", - "/home/user", + "/root", ) default_websockets["python"] = default_context_id websockets["default"] = default_ws diff --git a/template/start-up.sh b/template/start-up.sh index 492cb4bd..4b716a56 100644 --- a/template/start-up.sh +++ b/template/start-up.sh @@ -13,22 +13,22 @@ function start_jupyter_server() { response=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:8888/api/status") done - response=$(curl -s -X POST "localhost:8888/api/sessions" -H "Content-Type: application/json" -d '{"path": "/home/user", "kernel": {"name": "python3"}, "type": "notebook", "name": "default"}') + response=$(curl -s -X POST "localhost:8888/api/sessions" -H "Content-Type: application/json" -d '{"path": "/root", "kernel": {"name": "python3"}, "type": "notebook", "name": "default"}') status=$(echo "${response}" | jq -r '.kernel.execution_state') if [[ ${status} != "starting" ]]; then echo "Error creating kernel: ${response} ${status}" exit 1 fi - mkdir -p /home/user/.jupyter + mkdir -p /root/.jupyter kernel_id=$(echo "${response}" | jq -r '.kernel.id') - echo "${kernel_id}" > /home/user/.jupyter/kernel_id - echo "${response}" > /home/user/.jupyter/.session_info + echo "${kernel_id}" > /root/.jupyter/kernel_id + echo "${response}" > /root/.jupyter/.session_info - cd /home/user/.server/ - /home/user/.server/.venv/bin/uvicorn main:app --host 0.0.0.0 --port 49999 --workers 1 --no-access-log --no-use-colors >> /home/user/uvicorn_server.log 2>&1 + cd /root/.server/ + /root/.server/.venv/bin/uvicorn main:app --host 0.0.0.0 --port 49999 --workers 1 --no-access-log --no-use-colors } echo "Starting Code Interpreter server..." start_jupyter_server & -MATPLOTLIBRC=/home/user/.config/matplotlib/.matplotlibrc jupyter server --IdentityProvider.token="" >> /home/user/jupyter_server.log 2>&1 +MATPLOTLIBRC=/root/.config/matplotlib/.matplotlibrc jupyter server --IdentityProvider.token="" diff --git a/template/test.Dockerfile b/template/test.Dockerfile index 5ffd49d6..b130996f 100644 --- a/template/test.Dockerfile +++ b/template/test.Dockerfile @@ -1,8 +1,6 @@ FROM python:3.10.14 -# Create a non-root user -RUN useradd -m -s /bin/bash user -ENV HOME=/home/user +ENV HOME=/root ENV JAVA_HOME=/opt/java/openjdk COPY --from=eclipse-temurin:11-jdk $JAVA_HOME $JAVA_HOME @@ -20,7 +18,7 @@ ENV PIP_DEFAULT_TIMEOUT=100 \ # Install Jupyter COPY ./template/requirements.txt requirements.txt -RUN pip install --no-cache-dir -r requirements.txt && ipython kernel install --name "python3" --user +RUN pip install --no-cache-dir -r requirements.txt && ipython kernel install --name "python3" # Javascript Kernel RUN npm install -g node-gyp @@ -30,8 +28,14 @@ RUN ijsinstall --install=global # Deno Kernel COPY --from=denoland/deno:bin-2.0.4 /deno /usr/bin/deno RUN chmod +x /usr/bin/deno -RUN deno jupyter --unstable --install -COPY ./template/deno.json $HOME/.local/share/jupyter/kernels/deno/kernel.json +RUN deno jupyter --unstable --install && \ + mkdir -p /usr/local/share/jupyter/kernels/deno && \ + mv $HOME/.local/share/jupyter/kernels/deno/* /usr/local/share/jupyter/kernels/deno/ && \ + rmdir $HOME/.local/share/jupyter/kernels/deno +# COPY ./template/kernel/deno.json /usr/local/share/jupyter/kernels/deno/kernel.json + +# Copy non-root kernels +COPY ./template/kernel/python3_user.json /usr/local/share/jupyter/kernels/python3_user/kernel.json # Create separate virtual environment for server RUN python -m venv $SERVER_PATH/.venv @@ -62,10 +66,4 @@ WORKDIR $HOME COPY ./chart_data_extractor ./chart_data_extractor RUN pip install -e ./chart_data_extractor -# Set ownership of all files to the user -RUN chown -R user:user $HOME - -# Switch to non-root user -USER user - ENTRYPOINT $JUPYTER_CONFIG_PATH/start-up.sh From 741e0e5a529f6eec01bf62e90fa76b57c88d6e9a Mon Sep 17 00:00:00 2001 From: Mish <10400064+mishushakov@users.noreply.github.com> Date: Tue, 29 Apr 2025 16:45:09 +0200 Subject: [PATCH 06/16] wip --- template/{ => kernel}/deno.json | 0 template/kernel/python3_user.json | 17 +++++++++++++++++ template/test.Dockerfile | 10 +++++++++- 3 files changed, 26 insertions(+), 1 deletion(-) rename template/{ => kernel}/deno.json (100%) create mode 100644 template/kernel/python3_user.json diff --git a/template/deno.json b/template/kernel/deno.json similarity index 100% rename from template/deno.json rename to template/kernel/deno.json diff --git a/template/kernel/python3_user.json b/template/kernel/python3_user.json new file mode 100644 index 00000000..7d98f23a --- /dev/null +++ b/template/kernel/python3_user.json @@ -0,0 +1,17 @@ +{ + "argv": [ + "sudo", + "-u", + "user", + "/usr/local/bin/python", + "-m", + "ipykernel_launcher", + "-f", + "{connection_file}" + ], + "display_name": "Python 3 (user)", + "language": "python", + "metadata": { + "debugger": true + } +} diff --git a/template/test.Dockerfile b/template/test.Dockerfile index b130996f..63558f00 100644 --- a/template/test.Dockerfile +++ b/template/test.Dockerfile @@ -7,7 +7,15 @@ COPY --from=eclipse-temurin:11-jdk $JAVA_HOME $JAVA_HOME ENV PATH="${JAVA_HOME}/bin:${PATH}" RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y --no-install-recommends \ - build-essential curl git util-linux jq nodejs npm fonts-noto-cjk + build-essential curl git util-linux jq nodejs npm fonts-noto-cjk sudo + +# Create new user with root privileges while keeping root user +RUN useradd -m -s /bin/bash user && \ + echo 'user ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers && \ + echo 'user:password' | chpasswd && \ + usermod -aG sudo user && \ + chmod -R o+rx /root && \ + chown -R user:user /root ENV PIP_DEFAULT_TIMEOUT=100 \ PIP_DISABLE_PIP_VERSION_CHECK=1 \ From 822beda37ce88514ad33f4b82338e4424433fbf0 Mon Sep 17 00:00:00 2001 From: Mish <10400064+mishushakov@users.noreply.github.com> Date: Tue, 29 Apr 2025 16:58:25 +0200 Subject: [PATCH 07/16] qip --- .../{python3_user.json => python3_sudo.json} | 2 -- template/server/main.py | 4 ++-- template/start-up.sh | 14 +++++++------- template/test.Dockerfile | 15 ++++++++------- 4 files changed, 17 insertions(+), 18 deletions(-) rename template/kernel/{python3_user.json => python3_sudo.json} (91%) diff --git a/template/kernel/python3_user.json b/template/kernel/python3_sudo.json similarity index 91% rename from template/kernel/python3_user.json rename to template/kernel/python3_sudo.json index 7d98f23a..67b76067 100644 --- a/template/kernel/python3_user.json +++ b/template/kernel/python3_sudo.json @@ -1,8 +1,6 @@ { "argv": [ "sudo", - "-u", - "user", "/usr/local/bin/python", "-m", "ipykernel_launcher", diff --git a/template/server/main.py b/template/server/main.py index f26ae2e3..8b6586b9 100644 --- a/template/server/main.py +++ b/template/server/main.py @@ -34,14 +34,14 @@ async def lifespan(app: FastAPI): global client client = httpx.AsyncClient() - with open("/root/.jupyter/kernel_id") as file: + with open("/home/user/.jupyter/kernel_id") as file: default_context_id = file.read().strip() default_ws = ContextWebSocket( default_context_id, str(uuid.uuid4()), "python", - "/root", + "/home/user", ) default_websockets["python"] = default_context_id websockets["default"] = default_ws diff --git a/template/start-up.sh b/template/start-up.sh index 4b716a56..9d2cb4c0 100644 --- a/template/start-up.sh +++ b/template/start-up.sh @@ -13,22 +13,22 @@ function start_jupyter_server() { response=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:8888/api/status") done - response=$(curl -s -X POST "localhost:8888/api/sessions" -H "Content-Type: application/json" -d '{"path": "/root", "kernel": {"name": "python3"}, "type": "notebook", "name": "default"}') + response=$(curl -s -X POST "localhost:8888/api/sessions" -H "Content-Type: application/json" -d '{"path": "'$HOME'", "kernel": {"name": "python3"}, "type": "notebook", "name": "default"}') status=$(echo "${response}" | jq -r '.kernel.execution_state') if [[ ${status} != "starting" ]]; then echo "Error creating kernel: ${response} ${status}" exit 1 fi - mkdir -p /root/.jupyter + mkdir -p $HOME/.jupyter kernel_id=$(echo "${response}" | jq -r '.kernel.id') - echo "${kernel_id}" > /root/.jupyter/kernel_id - echo "${response}" > /root/.jupyter/.session_info + echo "${kernel_id}" > $HOME/.jupyter/kernel_id + echo "${response}" > $HOME/.jupyter/.session_info - cd /root/.server/ - /root/.server/.venv/bin/uvicorn main:app --host 0.0.0.0 --port 49999 --workers 1 --no-access-log --no-use-colors + cd $HOME/.server/ + $HOME/.server/.venv/bin/uvicorn main:app --host 0.0.0.0 --port 49999 --workers 1 --no-access-log --no-use-colors } echo "Starting Code Interpreter server..." start_jupyter_server & -MATPLOTLIBRC=/root/.config/matplotlib/.matplotlibrc jupyter server --IdentityProvider.token="" +MATPLOTLIBRC=$HOME/.config/matplotlib/.matplotlibrc jupyter server --IdentityProvider.token="" diff --git a/template/test.Dockerfile b/template/test.Dockerfile index 63558f00..275a1be5 100644 --- a/template/test.Dockerfile +++ b/template/test.Dockerfile @@ -1,6 +1,6 @@ FROM python:3.10.14 -ENV HOME=/root +ENV HOME=/home/user ENV JAVA_HOME=/opt/java/openjdk COPY --from=eclipse-temurin:11-jdk $JAVA_HOME $JAVA_HOME @@ -13,9 +13,7 @@ RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y --no-ins RUN useradd -m -s /bin/bash user && \ echo 'user ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers && \ echo 'user:password' | chpasswd && \ - usermod -aG sudo user && \ - chmod -R o+rx /root && \ - chown -R user:user /root + usermod -aG sudo user ENV PIP_DEFAULT_TIMEOUT=100 \ PIP_DISABLE_PIP_VERSION_CHECK=1 \ @@ -40,10 +38,9 @@ RUN deno jupyter --unstable --install && \ mkdir -p /usr/local/share/jupyter/kernels/deno && \ mv $HOME/.local/share/jupyter/kernels/deno/* /usr/local/share/jupyter/kernels/deno/ && \ rmdir $HOME/.local/share/jupyter/kernels/deno -# COPY ./template/kernel/deno.json /usr/local/share/jupyter/kernels/deno/kernel.json -# Copy non-root kernels -COPY ./template/kernel/python3_user.json /usr/local/share/jupyter/kernels/python3_user/kernel.json +# Copy sudo kernels +COPY ./template/kernel/python3_sudo.json /usr/local/share/jupyter/kernels/python3_sudo/kernel.json # Create separate virtual environment for server RUN python -m venv $SERVER_PATH/.venv @@ -74,4 +71,8 @@ WORKDIR $HOME COPY ./chart_data_extractor ./chart_data_extractor RUN pip install -e ./chart_data_extractor +# Change ownership of all files to user +RUN chown -R user:user $HOME + +USER user ENTRYPOINT $JUPYTER_CONFIG_PATH/start-up.sh From 162c3de63df1c0efa75a3e7d3376e20b907f85fb Mon Sep 17 00:00:00 2001 From: Mish <10400064+mishushakov@users.noreply.github.com> Date: Tue, 29 Apr 2025 17:26:50 +0200 Subject: [PATCH 08/16] sync'd some changes from test.Dockerfile to Dockerfile --- template/Dockerfile | 6 ++++-- template/{kernel => }/deno.json | 0 template/kernel/python3_sudo.json | 15 --------------- template/start-up.sh | 25 +++++++++++++++++++++++++ template/test.Dockerfile | 3 +-- 5 files changed, 30 insertions(+), 19 deletions(-) rename template/{kernel => }/deno.json (100%) delete mode 100644 template/kernel/python3_sudo.json diff --git a/template/Dockerfile b/template/Dockerfile index 292f9356..e03cc62d 100644 --- a/template/Dockerfile +++ b/template/Dockerfile @@ -35,8 +35,10 @@ RUN ijsinstall --install=global # Deno Kernel COPY --from=denoland/deno:bin-2.0.4 /deno /usr/bin/deno RUN chmod +x /usr/bin/deno -RUN deno jupyter --unstable --install -RUN mkdir -p /usr/local/share/jupyter/kernels/deno +RUN deno jupyter --unstable --install && \ + mkdir -p /usr/local/share/jupyter/kernels/deno && \ + mv $HOME/.local/share/jupyter/kernels/deno/* /usr/local/share/jupyter/kernels/deno/ && \ + rmdir $HOME/.local/share/jupyter/kernels/deno COPY ./kernel/deno.json /usr/local/share/jupyter/kernels/deno/kernel.json # Bash Kernel diff --git a/template/kernel/deno.json b/template/deno.json similarity index 100% rename from template/kernel/deno.json rename to template/deno.json diff --git a/template/kernel/python3_sudo.json b/template/kernel/python3_sudo.json deleted file mode 100644 index 67b76067..00000000 --- a/template/kernel/python3_sudo.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "argv": [ - "sudo", - "/usr/local/bin/python", - "-m", - "ipykernel_launcher", - "-f", - "{connection_file}" - ], - "display_name": "Python 3 (user)", - "language": "python", - "metadata": { - "debugger": true - } -} diff --git a/template/start-up.sh b/template/start-up.sh index 9d2cb4c0..c1d2a134 100644 --- a/template/start-up.sh +++ b/template/start-up.sh @@ -1,5 +1,27 @@ #!/bin/bash +function create_root_kernels() { + # Get all installed kernels + kernels=$(jupyter kernelspec list --json | jq -r '.kernelspecs | keys[]') + + for kernel in $kernels; do + # Get the kernel directory + kernel_dir=$(jupyter kernelspec list --json | jq -r ".kernelspecs[\"$kernel\"].resource_dir") + + # Create directory for root kernel if it doesn't exist + root_kernel_dir="/usr/local/share/jupyter/kernels/${kernel}_root" + sudo mkdir -p "$root_kernel_dir" + + # Copy all files from original kernel first + sudo cp -r "$kernel_dir"/* "$root_kernel_dir/" 2>/dev/null || true + + # Create and write the modified kernel.json + cat "$kernel_dir/kernel.json" | jq '.argv = ["sudo"] + .argv | .display_name = .display_name + " (root)"' | sudo tee "$root_kernel_dir/kernel.json" > /dev/null + + echo "Created root version of kernel: ${kernel}_root" + done +} + function start_jupyter_server() { counter=0 response=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:8888/api/status") @@ -29,6 +51,9 @@ function start_jupyter_server() { $HOME/.server/.venv/bin/uvicorn main:app --host 0.0.0.0 --port 49999 --workers 1 --no-access-log --no-use-colors } +echo "Creating root versions of kernels..." +create_root_kernels + echo "Starting Code Interpreter server..." start_jupyter_server & MATPLOTLIBRC=$HOME/.config/matplotlib/.matplotlibrc jupyter server --IdentityProvider.token="" diff --git a/template/test.Dockerfile b/template/test.Dockerfile index 275a1be5..93e14ae0 100644 --- a/template/test.Dockerfile +++ b/template/test.Dockerfile @@ -39,8 +39,7 @@ RUN deno jupyter --unstable --install && \ mv $HOME/.local/share/jupyter/kernels/deno/* /usr/local/share/jupyter/kernels/deno/ && \ rmdir $HOME/.local/share/jupyter/kernels/deno -# Copy sudo kernels -COPY ./template/kernel/python3_sudo.json /usr/local/share/jupyter/kernels/python3_sudo/kernel.json +COPY ./template/deno.json /usr/local/share/jupyter/kernels/deno/kernel.json # Create separate virtual environment for server RUN python -m venv $SERVER_PATH/.venv From f1c427d3c30fc9468a92618185a8f88798e19b22 Mon Sep 17 00:00:00 2001 From: Mish <10400064+mishushakov@users.noreply.github.com> Date: Tue, 29 Apr 2025 17:33:01 +0200 Subject: [PATCH 09/16] changed deno kernel path --- template/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/template/Dockerfile b/template/Dockerfile index e03cc62d..7faad9aa 100644 --- a/template/Dockerfile +++ b/template/Dockerfile @@ -39,7 +39,7 @@ RUN deno jupyter --unstable --install && \ mkdir -p /usr/local/share/jupyter/kernels/deno && \ mv $HOME/.local/share/jupyter/kernels/deno/* /usr/local/share/jupyter/kernels/deno/ && \ rmdir $HOME/.local/share/jupyter/kernels/deno -COPY ./kernel/deno.json /usr/local/share/jupyter/kernels/deno/kernel.json +COPY ./deno.json /usr/local/share/jupyter/kernels/deno/kernel.json # Bash Kernel RUN pip install bash_kernel From 38ee9c7b0d0a4f078be6d8a02e3ac39c9013b44d Mon Sep 17 00:00:00 2001 From: Mish <10400064+mishushakov@users.noreply.github.com> Date: Thu, 1 May 2025 11:34:37 +0200 Subject: [PATCH 10/16] change user in new context --- template/server/api/models/context.py | 1 + template/server/api/models/create_context.py | 4 ++++ template/server/contexts.py | 12 +++++++++--- template/server/main.py | 5 +++-- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/template/server/api/models/context.py b/template/server/api/models/context.py index 5efb850e..c3e6a25f 100644 --- a/template/server/api/models/context.py +++ b/template/server/api/models/context.py @@ -6,6 +6,7 @@ class Context(BaseModel): id: StrictStr = Field(description="Context ID") language: StrictStr = Field(description="Language of the context") cwd: StrictStr = Field(description="Current working directory of the context") + user: StrictStr = Field(description="User of the context") def __hash__(self): return hash(self.id) diff --git a/template/server/api/models/create_context.py b/template/server/api/models/create_context.py index 1e1fefb7..f002d490 100644 --- a/template/server/api/models/create_context.py +++ b/template/server/api/models/create_context.py @@ -4,6 +4,10 @@ class CreateContext(BaseModel): + user: Optional[StrictStr] = Field( + default="root", + description="User to run the context", + ) cwd: Optional[StrictStr] = Field( default="/home/user", description="Current working directory", diff --git a/template/server/contexts.py b/template/server/contexts.py index 3af317d3..37d015be 100644 --- a/template/server/contexts.py +++ b/template/server/contexts.py @@ -24,10 +24,16 @@ def normalize_language(language: Optional[str]) -> str: return language -async def create_context(client, websockets: dict, language: str, cwd: str) -> Context: +def get_kernel_name(language: str, user: str) -> str: + if user == "root": + return language+"_root" + return language + + +async def create_context(client, websockets: dict, language: str, cwd: str, user: str) -> Context: data = { "path": str(uuid.uuid4()), - "kernel": {"name": language}, + "kernel": {"name": get_kernel_name(language, user)}, # replace with root kernel when user is root "type": "notebook", "name": str(uuid.uuid4()), } @@ -59,4 +65,4 @@ async def create_context(client, websockets: dict, language: str, cwd: str) -> C status_code=500, ) - return Context(language=language, id=context_id, cwd=cwd) + return Context(language=language, id=context_id, cwd=cwd, user=user) diff --git a/template/server/main.py b/template/server/main.py index 8b6586b9..5065398e 100644 --- a/template/server/main.py +++ b/template/server/main.py @@ -91,7 +91,7 @@ async def post_execute(request: ExecutionRequest): if not context_id: try: context = await create_context( - client, websockets, language, "/home/user" + client, websockets, language, "/home/user", "root" ) except Exception as e: return PlainTextResponse(str(e), status_code=500) @@ -127,9 +127,10 @@ async def post_contexts(request: CreateContext) -> Context: language = normalize_language(request.language) cwd = request.cwd or "/home/user" + user = request.user or "root" try: - return await create_context(client, websockets, language, cwd) + return await create_context(client, websockets, language, cwd, user) except Exception as e: return PlainTextResponse(str(e), status_code=500) From 23f58eab0ef54ea4a0680c860a4388b2bc241abf Mon Sep 17 00:00:00 2001 From: Mish <10400064+mishushakov@users.noreply.github.com> Date: Wed, 14 May 2025 16:01:56 +0200 Subject: [PATCH 11/16] start default kernel as root to avoid breaking change --- template/server/contexts.py | 2 +- template/start-up.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/template/server/contexts.py b/template/server/contexts.py index 774bbd53..660faeac 100644 --- a/template/server/contexts.py +++ b/template/server/contexts.py @@ -42,7 +42,7 @@ async def create_context(client, websockets: dict, language: str, cwd: str, user "type": "notebook", "name": str(uuid.uuid4()), } - logger.debug(f"Creating new {language} context") + logger.debug(f"Creating new {language} context for user {user}") response = await client.post(f"{JUPYTER_BASE_URL}/api/sessions", json=data) diff --git a/template/start-up.sh b/template/start-up.sh index 2bf2eb21..23951666 100644 --- a/template/start-up.sh +++ b/template/start-up.sh @@ -35,7 +35,7 @@ function start_jupyter_server() { response=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:8888/api/status") done - response=$(curl -s -X POST "localhost:8888/api/sessions" -H "Content-Type: application/json" -d '{"path": "'$HOME'", "kernel": {"name": "python3"}, "type": "notebook", "name": "default"}') + response=$(curl -s -X POST "localhost:8888/api/sessions" -H "Content-Type: application/json" -d '{"path": "'$HOME'", "kernel": {"name": "python3_root"}, "type": "notebook", "name": "default"}') status=$(echo "${response}" | jq -r '.kernel.execution_state') if [[ ${status} != "starting" ]]; then echo "Error creating kernel: ${response} ${status}" From 4a8c98a6dd32f0cbfb0496f560aabfe677554f33 Mon Sep 17 00:00:00 2001 From: Mish <10400064+mishushakov@users.noreply.github.com> Date: Wed, 14 May 2025 16:07:19 +0200 Subject: [PATCH 12/16] adds ability to pass user to the createCodeContext SDK method --- js/src/sandbox.ts | 7 +++++++ python/e2b_code_interpreter/code_interpreter_async.py | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/js/src/sandbox.ts b/js/src/sandbox.ts index 74db4c9e..89132c47 100644 --- a/js/src/sandbox.ts +++ b/js/src/sandbox.ts @@ -78,6 +78,12 @@ export interface CreateCodeContextOpts { * @default python */ language?: string, + /** + * User for the context. + * + * @default root + */ + user?: "root" | "user", /** * Timeout for the request in **milliseconds**. * @@ -269,6 +275,7 @@ export class Sandbox extends BaseSandbox { body: JSON.stringify({ language: opts?.language, cwd: opts?.cwd, + user: opts?.user, }), keepalive: true, signal: this.connectionConfig.getSignal(opts?.requestTimeoutMs), diff --git a/python/e2b_code_interpreter/code_interpreter_async.py b/python/e2b_code_interpreter/code_interpreter_async.py index c521af83..493a406b 100644 --- a/python/e2b_code_interpreter/code_interpreter_async.py +++ b/python/e2b_code_interpreter/code_interpreter_async.py @@ -231,6 +231,7 @@ async def create_code_context( self, cwd: Optional[str] = None, language: Optional[str] = None, + user: Optional[Literal["root", "user"]] = None, request_timeout: Optional[float] = None, ) -> Context: """ @@ -238,6 +239,7 @@ async def create_code_context( :param cwd: Set the current working directory for the context, defaults to `/home/user` :param language: Language of the context. If not specified, defaults to Python + :param user: User of the context. If not specified, defaults to `root` :param request_timeout: Timeout for the request in **milliseconds** :return: Context object @@ -249,6 +251,8 @@ async def create_code_context( data["language"] = language if cwd: data["cwd"] = cwd + if user: + data["user"] = user try: response = await self._client.post( From 44c2a42fbdf4b7309cac7a8350e0d5061f35df48 Mon Sep 17 00:00:00 2001 From: Mish <10400064+mishushakov@users.noreply.github.com> Date: Wed, 14 May 2025 16:15:02 +0200 Subject: [PATCH 13/16] added changeset --- .changeset/five-jobs-cry.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/five-jobs-cry.md diff --git a/.changeset/five-jobs-cry.md b/.changeset/five-jobs-cry.md new file mode 100644 index 00000000..f576343f --- /dev/null +++ b/.changeset/five-jobs-cry.md @@ -0,0 +1,7 @@ +--- +'@e2b/code-interpreter-template': patch +'@e2b/code-interpreter-python': patch +'@e2b/code-interpreter': patch +--- + +adds the ability to set the user for new contexts From d49ea96e086dd21672f4e9cf9b373ef567e866f9 Mon Sep 17 00:00:00 2001 From: Mish <10400064+mishushakov@users.noreply.github.com> Date: Wed, 14 May 2025 16:57:25 +0200 Subject: [PATCH 14/16] changed default user to "user" as per @jakubno --- js/src/sandbox.ts | 4 ++-- python/e2b_code_interpreter/code_interpreter_async.py | 4 ++-- template/server/api/models/create_context.py | 2 +- template/server/main.py | 4 ++-- template/start-up.sh | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/js/src/sandbox.ts b/js/src/sandbox.ts index 89132c47..024c5855 100644 --- a/js/src/sandbox.ts +++ b/js/src/sandbox.ts @@ -81,9 +81,9 @@ export interface CreateCodeContextOpts { /** * User for the context. * - * @default root + * @default user */ - user?: "root" | "user", + user?: "user" | "root", /** * Timeout for the request in **milliseconds**. * diff --git a/python/e2b_code_interpreter/code_interpreter_async.py b/python/e2b_code_interpreter/code_interpreter_async.py index 493a406b..79e7a809 100644 --- a/python/e2b_code_interpreter/code_interpreter_async.py +++ b/python/e2b_code_interpreter/code_interpreter_async.py @@ -231,7 +231,7 @@ async def create_code_context( self, cwd: Optional[str] = None, language: Optional[str] = None, - user: Optional[Literal["root", "user"]] = None, + user: Optional[Literal["user", "root"]] = None, request_timeout: Optional[float] = None, ) -> Context: """ @@ -239,7 +239,7 @@ async def create_code_context( :param cwd: Set the current working directory for the context, defaults to `/home/user` :param language: Language of the context. If not specified, defaults to Python - :param user: User of the context. If not specified, defaults to `root` + :param user: User of the context. If not specified, defaults to `user` :param request_timeout: Timeout for the request in **milliseconds** :return: Context object diff --git a/template/server/api/models/create_context.py b/template/server/api/models/create_context.py index f002d490..26808bac 100644 --- a/template/server/api/models/create_context.py +++ b/template/server/api/models/create_context.py @@ -5,7 +5,7 @@ class CreateContext(BaseModel): user: Optional[StrictStr] = Field( - default="root", + default="user", description="User to run the context", ) cwd: Optional[StrictStr] = Field( diff --git a/template/server/main.py b/template/server/main.py index 5065398e..bfce52dd 100644 --- a/template/server/main.py +++ b/template/server/main.py @@ -91,7 +91,7 @@ async def post_execute(request: ExecutionRequest): if not context_id: try: context = await create_context( - client, websockets, language, "/home/user", "root" + client, websockets, language, "/home/user", "user" ) except Exception as e: return PlainTextResponse(str(e), status_code=500) @@ -127,7 +127,7 @@ async def post_contexts(request: CreateContext) -> Context: language = normalize_language(request.language) cwd = request.cwd or "/home/user" - user = request.user or "root" + user = request.user or "user" try: return await create_context(client, websockets, language, cwd, user) diff --git a/template/start-up.sh b/template/start-up.sh index 23951666..2bf2eb21 100644 --- a/template/start-up.sh +++ b/template/start-up.sh @@ -35,7 +35,7 @@ function start_jupyter_server() { response=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:8888/api/status") done - response=$(curl -s -X POST "localhost:8888/api/sessions" -H "Content-Type: application/json" -d '{"path": "'$HOME'", "kernel": {"name": "python3_root"}, "type": "notebook", "name": "default"}') + response=$(curl -s -X POST "localhost:8888/api/sessions" -H "Content-Type: application/json" -d '{"path": "'$HOME'", "kernel": {"name": "python3"}, "type": "notebook", "name": "default"}') status=$(echo "${response}" | jq -r '.kernel.execution_state') if [[ ${status} != "starting" ]]; then echo "Error creating kernel: ${response} ${status}" From f4fc0725ef0fac39e4cabd272cd8e511d8ef005e Mon Sep 17 00:00:00 2001 From: Mish <10400064+mishushakov@users.noreply.github.com> Date: Wed, 14 May 2025 17:08:01 +0200 Subject: [PATCH 15/16] change default cwd depending on the user if cwd is not provided --- template/server/contexts.py | 7 +++++++ template/server/main.py | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/template/server/contexts.py b/template/server/contexts.py index 660faeac..b3051f2b 100644 --- a/template/server/contexts.py +++ b/template/server/contexts.py @@ -11,6 +11,13 @@ logger = logging.Logger(__name__) +def get_user_cwd(user: str, cwd: Optional[str]) -> str: + if not cwd: + if user == "root": + return "/root" + return "/home/user" + return cwd + def normalize_language(language: Optional[str]) -> str: if not language: return "python" diff --git a/template/server/main.py b/template/server/main.py index bfce52dd..d3264026 100644 --- a/template/server/main.py +++ b/template/server/main.py @@ -13,7 +13,7 @@ from api.models.create_context import CreateContext from api.models.execution_request import ExecutionRequest from consts import JUPYTER_BASE_URL -from contexts import create_context, normalize_language +from contexts import create_context, normalize_language, get_user_cwd from messaging import ContextWebSocket from stream import StreamingListJsonResponse from utils.locks import LockedMap @@ -126,8 +126,8 @@ async def post_contexts(request: CreateContext) -> Context: logger.info(f"Creating a new context") language = normalize_language(request.language) - cwd = request.cwd or "/home/user" user = request.user or "user" + cwd = get_user_cwd(user, request.cwd) try: return await create_context(client, websockets, language, cwd, user) From feb767eaf7094d08ae609db31eae5e4a2cb58555 Mon Sep 17 00:00:00 2001 From: Mish <10400064+mishushakov@users.noreply.github.com> Date: Wed, 14 May 2025 21:31:16 +0200 Subject: [PATCH 16/16] changed template to code-interpreter-v1beta1 --- template/e2b.toml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/template/e2b.toml b/template/e2b.toml index 9a6db623..0ab84f55 100644 --- a/template/e2b.toml +++ b/template/e2b.toml @@ -1,17 +1,18 @@ # This is a config for E2B sandbox template. -# You can use template ID (nlhz8vlwyupq845jsdg9) or template name (code-interpreter-v1) to create a sandbox: +# You can use template ID (n1vc02i7rx9xg0lao9nx) or template name (code-interpreter-v1beta1) to create a sandbox: # Python SDK # from e2b import Sandbox, AsyncSandbox -# sandbox = Sandbox("code-interpreter-v1") # Sync sandbox -# sandbox = await AsyncSandbox.create("code-interpreter-v1") # Async sandbox +# sandbox = Sandbox("code-interpreter-v1beta1") # Sync sandbox +# sandbox = await AsyncSandbox.create("code-interpreter-v1beta1") # Async sandbox # JS SDK # import { Sandbox } from 'e2b' -# const sandbox = await Sandbox.create('code-interpreter-v1') +# const sandbox = await Sandbox.create('code-interpreter-v1beta1') + team_id = "460355b3-4f64-48f9-9a16-4442817f79f5" memory_mb = 1_024 start_cmd = "sudo -u user /home/user/.jupyter/start-up.sh" -dockerfile = "e2b.Dockerfile" -template_name = "code-interpreter-v1" -template_id = "nlhz8vlwyupq845jsdg9" \ No newline at end of file +dockerfile = "Dockerfile" +template_name = "code-interpreter-v1beta1" +template_id = "n1vc02i7rx9xg0lao9nx"