diff --git a/.gitignore b/.gitignore index 552631d2e..14f07bf56 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,9 @@ MANIFEST pip-log.txt pip-delete-this-directory.txt +# Test logs +logs/pytest-logs.txt + # Unit test / coverage reports htmlcov/ .tox/ diff --git a/jupyter/datascience/ubi9-python-3.11/Dockerfile.cpu b/jupyter/datascience/ubi9-python-3.11/Dockerfile.cpu index b401666be..07542d824 100644 --- a/jupyter/datascience/ubi9-python-3.11/Dockerfile.cpu +++ b/jupyter/datascience/ubi9-python-3.11/Dockerfile.cpu @@ -49,6 +49,14 @@ WORKDIR /opt/app-root/bin COPY ${JUPYTER_REUSABLE_UTILS} utils/ COPY ${MINIMAL_SOURCE_CODE}/start-notebook.sh ./ +USER 0 + +# Dependencies for PDF export +RUN ./utils/install_pdf_deps.sh +ENV PATH="/usr/local/texlive/bin/x86_64-linux:/usr/local/pandoc/bin:$PATH" + +USER 1001 + WORKDIR /opt/app-root/src ENTRYPOINT ["start-notebook.sh"] @@ -107,6 +115,8 @@ RUN echo "Installing softwares and packages" && \ rm /opt/app-root/share/jupyter/metadata/runtime-images/*.json && \ # Replace Notebook's launcher, "(ipykernel)" with Python's version 3.x.y \ sed -i -e "s/Python.*/$(python --version | cut -d '.' -f-2)\",/" /opt/app-root/share/jupyter/kernels/python3/kernel.json && \ + # copy jupyter configuration + cp /opt/app-root/bin/utils/jupyter_server_config.py /opt/app-root/etc/jupyter && \ # Disable announcement plugin of jupyterlab \ jupyter labextension disable "@jupyterlab/apputils-extension:announcements" && \ # Apply JupyterLab addons \ diff --git a/jupyter/minimal/ubi9-python-3.11/Dockerfile.cpu b/jupyter/minimal/ubi9-python-3.11/Dockerfile.cpu index b1be0bc41..f148c0a09 100644 --- a/jupyter/minimal/ubi9-python-3.11/Dockerfile.cpu +++ b/jupyter/minimal/ubi9-python-3.11/Dockerfile.cpu @@ -19,7 +19,7 @@ RUN pip install --no-cache-dir -U "micropipenv[toml]" # Install the oc client RUN curl -L https://mirror.openshift.com/pub/openshift-v4/$(uname -m)/clients/ocp/stable/openshift-client-linux.tar.gz \ - -o /tmp/openshift-client-linux.tar.gz && \ + -o /tmp/openshift-client-linux.tar.gz && \ tar -xzvf /tmp/openshift-client-linux.tar.gz oc && \ rm -f /tmp/openshift-client-linux.tar.gz @@ -45,6 +45,14 @@ WORKDIR /opt/app-root/bin COPY ${JUPYTER_REUSABLE_UTILS} utils/ +USER 0 + +# Dependencies for PDF export +RUN ./utils/install_pdf_deps.sh +ENV PATH="/usr/local/texlive/bin/x86_64-linux:/usr/local/pandoc/bin:$PATH" + +USER 1001 + COPY ${MINIMAL_SOURCE_CODE}/Pipfile.lock ${MINIMAL_SOURCE_CODE}/start-notebook.sh ./ # Install Python dependencies from Pipfile.lock file @@ -55,12 +63,14 @@ RUN echo "Installing softwares and packages" && \ jupyter labextension disable "@jupyterlab/apputils-extension:announcements" && \ # Replace Notebook's launcher, "(ipykernel)" with Python's version 3.x.y \ sed -i -e "s/Python.*/$(python --version | cut -d '.' -f-2)\",/" /opt/app-root/share/jupyter/kernels/python3/kernel.json && \ + # copy jupyter configuration + cp /opt/app-root/bin/utils/jupyter_server_config.py /opt/app-root/etc/jupyter && \ # Fix permissions to support pip in Openshift environments \ chmod -R g+w /opt/app-root/lib/python3.11/site-packages && \ fix-permissions /opt/app-root -P && \ # Apply JupyterLab addons \ /opt/app-root/bin/utils/addons/apply.sh - + WORKDIR /opt/app-root/src ENTRYPOINT ["start-notebook.sh"] \ No newline at end of file diff --git a/jupyter/minimal/ubi9-python-3.11/Dockerfile.cuda b/jupyter/minimal/ubi9-python-3.11/Dockerfile.cuda index baa668268..9b11e7ba3 100644 --- a/jupyter/minimal/ubi9-python-3.11/Dockerfile.cuda +++ b/jupyter/minimal/ubi9-python-3.11/Dockerfile.cuda @@ -165,6 +165,14 @@ WORKDIR /opt/app-root/bin COPY ${JUPYTER_REUSABLE_UTILS} utils/ +USER 0 + +# Dependencies for PDF export +RUN ./utils/install_pdf_deps.sh +ENV PATH="/usr/local/texlive/bin/x86_64-linux:/usr/local/pandoc/bin:$PATH" + +USER 1001 + COPY ${MINIMAL_SOURCE_CODE}/Pipfile.lock ${MINIMAL_SOURCE_CODE}/start-notebook.sh ./ # Install Python dependencies from Pipfile.lock file @@ -175,6 +183,8 @@ RUN echo "Installing softwares and packages" && \ jupyter labextension disable "@jupyterlab/apputils-extension:announcements" && \ # Replace Notebook's launcher, "(ipykernel)" with Python's version 3.x.y \ sed -i -e "s/Python.*/$(python --version | cut -d '.' -f-2)\",/" /opt/app-root/share/jupyter/kernels/python3/kernel.json && \ + # copy jupyter configuration + cp /opt/app-root/bin/utils/jupyter_server_config.py /opt/app-root/etc/jupyter && \ # Fix permissions to support pip in Openshift environments \ chmod -R g+w /opt/app-root/lib/python3.11/site-packages && \ fix-permissions /opt/app-root -P && \ diff --git a/jupyter/minimal/ubi9-python-3.11/Dockerfile.rocm b/jupyter/minimal/ubi9-python-3.11/Dockerfile.rocm index 64d51898e..ff7e7835a 100644 --- a/jupyter/minimal/ubi9-python-3.11/Dockerfile.rocm +++ b/jupyter/minimal/ubi9-python-3.11/Dockerfile.rocm @@ -79,6 +79,14 @@ WORKDIR /opt/app-root/bin COPY ${JUPYTER_REUSABLE_UTILS} utils/ +USER 0 + +# Dependencies for PDF export +RUN ./utils/install_pdf_deps.sh +ENV PATH="/usr/local/texlive/bin/x86_64-linux:/usr/local/pandoc/bin:$PATH" + +USER 1001 + COPY ${MINIMAL_SOURCE_CODE}/Pipfile.lock ${MINIMAL_SOURCE_CODE}/start-notebook.sh ./ # Install Python dependencies from Pipfile.lock file @@ -89,6 +97,8 @@ RUN echo "Installing softwares and packages" && \ jupyter labextension disable "@jupyterlab/apputils-extension:announcements" && \ # Replace Notebook's launcher, "(ipykernel)" with Python's version 3.x.y \ sed -i -e "s/Python.*/$(python --version | cut -d '.' -f-2)\",/" /opt/app-root/share/jupyter/kernels/python3/kernel.json && \ + # copy jupyter configuration + cp /opt/app-root/bin/utils/jupyter_server_config.py /opt/app-root/etc/jupyter && \ # Fix permissions to support pip in Openshift environments \ chmod -R g+w /opt/app-root/lib/python3.11/site-packages && \ fix-permissions /opt/app-root -P && \ diff --git a/jupyter/pytorch/ubi9-python-3.11/Dockerfile.cuda b/jupyter/pytorch/ubi9-python-3.11/Dockerfile.cuda index c15fd401f..09d1a5d61 100644 --- a/jupyter/pytorch/ubi9-python-3.11/Dockerfile.cuda +++ b/jupyter/pytorch/ubi9-python-3.11/Dockerfile.cuda @@ -170,6 +170,14 @@ COPY ${JUPYTER_REUSABLE_UTILS} utils/ COPY ${MINIMAL_SOURCE_CODE}/start-notebook.sh ./ +USER 0 + +# Dependencies for PDF export +RUN ./utils/install_pdf_deps.sh +ENV PATH="/usr/local/texlive/bin/x86_64-linux:/usr/local/pandoc/bin:$PATH" + +USER 1001 + WORKDIR /opt/app-root/src ENTRYPOINT ["start-notebook.sh"] @@ -239,6 +247,8 @@ RUN echo "Installing softwares and packages" && \ rm /opt/app-root/share/jupyter/metadata/runtime-images/*.json && \ # Replace Notebook's launcher, "(ipykernel)" with Python's version 3.x.y \ sed -i -e "s/Python.*/$(python --version | cut -d '.' -f-2)\",/" /opt/app-root/share/jupyter/kernels/python3/kernel.json && \ + # copy jupyter configuration + cp /opt/app-root/bin/utils/jupyter_server_config.py /opt/app-root/etc/jupyter && \ # Disable announcement plugin of jupyterlab \ jupyter labextension disable "@jupyterlab/apputils-extension:announcements" && \ # Apply JupyterLab addons \ diff --git a/jupyter/rocm/pytorch/ubi9-python-3.11/Dockerfile.rocm b/jupyter/rocm/pytorch/ubi9-python-3.11/Dockerfile.rocm index 02767c49b..722dd58f7 100644 --- a/jupyter/rocm/pytorch/ubi9-python-3.11/Dockerfile.rocm +++ b/jupyter/rocm/pytorch/ubi9-python-3.11/Dockerfile.rocm @@ -84,6 +84,14 @@ COPY ${JUPYTER_REUSABLE_UTILS} utils/ COPY ${MINIMAL_SOURCE_CODE}/start-notebook.sh ./ +USER 0 + +# Dependencies for PDF export +RUN ./utils/install_pdf_deps.sh +ENV PATH="/usr/local/texlive/bin/x86_64-linux:/usr/local/pandoc/bin:$PATH" + +USER 1001 + WORKDIR /opt/app-root/src ENTRYPOINT ["start-notebook.sh"] @@ -153,6 +161,8 @@ RUN echo "Installing softwares and packages" && \ rm /opt/app-root/share/jupyter/metadata/runtime-images/*.json && \ # Replace Notebook's launcher, "(ipykernel)" with Python's version 3.x.y \ sed -i -e "s/Python.*/$(python --version | cut -d '.' -f-2)\",/" /opt/app-root/share/jupyter/kernels/python3/kernel.json && \ + # copy jupyter configuration + cp /opt/app-root/bin/utils/jupyter_server_config.py /opt/app-root/etc/jupyter && \ # Disable announcement plugin of jupyterlab \ jupyter labextension disable "@jupyterlab/apputils-extension:announcements" && \ # Apply JupyterLab addons \ diff --git a/jupyter/rocm/tensorflow/ubi9-python-3.11/Dockerfile.rocm b/jupyter/rocm/tensorflow/ubi9-python-3.11/Dockerfile.rocm index ab96cfda0..d489effc0 100644 --- a/jupyter/rocm/tensorflow/ubi9-python-3.11/Dockerfile.rocm +++ b/jupyter/rocm/tensorflow/ubi9-python-3.11/Dockerfile.rocm @@ -82,6 +82,14 @@ WORKDIR /opt/app-root/bin COPY ${JUPYTER_REUSABLE_UTILS} utils/ +USER 0 + +# Dependencies for PDF export +RUN ./utils/install_pdf_deps.sh +ENV PATH="/usr/local/texlive/bin/x86_64-linux:/usr/local/pandoc/bin:$PATH" + +USER 1001 + COPY ${MINIMAL_SOURCE_CODE}/start-notebook.sh ./ WORKDIR /opt/app-root/src @@ -153,6 +161,8 @@ RUN echo "Installing softwares and packages" && \ rm /opt/app-root/share/jupyter/metadata/runtime-images/*.json && \ # Replace Notebook's launcher, "(ipykernel)" with Python's version 3.x.y \ sed -i -e "s/Python.*/$(python --version | cut -d '.' -f-2)\",/" /opt/app-root/share/jupyter/kernels/python3/kernel.json && \ + # copy jupyter configuration + cp /opt/app-root/bin/utils/jupyter_server_config.py /opt/app-root/etc/jupyter && \ # Disable announcement plugin of jupyterlab \ jupyter labextension disable "@jupyterlab/apputils-extension:announcements" && \ # Apply JupyterLab addons \ diff --git a/jupyter/tensorflow/ubi9-python-3.11/Dockerfile.cuda b/jupyter/tensorflow/ubi9-python-3.11/Dockerfile.cuda index 6a116b3ea..82389635d 100644 --- a/jupyter/tensorflow/ubi9-python-3.11/Dockerfile.cuda +++ b/jupyter/tensorflow/ubi9-python-3.11/Dockerfile.cuda @@ -170,6 +170,14 @@ COPY ${JUPYTER_REUSABLE_UTILS} utils/ COPY ${MINIMAL_SOURCE_CODE}/start-notebook.sh ./ +USER 0 + +# Dependencies for PDF export +RUN ./utils/install_pdf_deps.sh +ENV PATH="/usr/local/texlive/bin/x86_64-linux:/usr/local/pandoc/bin:$PATH" + +USER 1001 + WORKDIR /opt/app-root/src ENTRYPOINT ["start-notebook.sh"] @@ -239,6 +247,8 @@ RUN echo "Installing softwares and packages" && \ rm /opt/app-root/share/jupyter/metadata/runtime-images/*.json && \ # Replace Notebook's launcher, "(ipykernel)" with Python's version 3.x.y \ sed -i -e "s/Python.*/$(python --version | cut -d '.' -f-2)\",/" /opt/app-root/share/jupyter/kernels/python3/kernel.json && \ + # copy jupyter configuration + cp /opt/app-root/bin/utils/jupyter_server_config.py /opt/app-root/etc/jupyter && \ # Disable announcement plugin of jupyterlab \ jupyter labextension disable "@jupyterlab/apputils-extension:announcements" && \ # Apply JupyterLab addons \ diff --git a/jupyter/trustyai/ubi9-python-3.11/Dockerfile.cpu b/jupyter/trustyai/ubi9-python-3.11/Dockerfile.cpu index fac213518..5b99b9900 100644 --- a/jupyter/trustyai/ubi9-python-3.11/Dockerfile.cpu +++ b/jupyter/trustyai/ubi9-python-3.11/Dockerfile.cpu @@ -49,6 +49,14 @@ WORKDIR /opt/app-root/bin COPY ${JUPYTER_REUSABLE_UTILS} utils/ COPY ${MINIMAL_SOURCE_CODE}/start-notebook.sh ./ +USER 0 + +# Dependencies for PDF export +RUN ./utils/install_pdf_deps.sh +ENV PATH="/usr/local/texlive/bin/x86_64-linux:/usr/local/pandoc/bin:$PATH" + +USER 1001 + WORKDIR /opt/app-root/src ENTRYPOINT ["start-notebook.sh"] @@ -126,6 +134,8 @@ RUN echo "Installing softwares and packages" && \ rm /opt/app-root/share/jupyter/metadata/runtime-images/*.json && \ # Replace Notebook's launcher, "(ipykernel)" with Python's version 3.x.y \ sed -i -e "s/Python.*/$(python --version | cut -d '.' -f-2)\",/" /opt/app-root/share/jupyter/kernels/python3/kernel.json && \ + # copy jupyter configuration + cp /opt/app-root/bin/utils/jupyter_server_config.py /opt/app-root/etc/jupyter && \ # Disable announcement plugin of jupyterlab \ jupyter labextension disable "@jupyterlab/apputils-extension:announcements" && \ # Apply JupyterLab addons \ diff --git a/jupyter/utils/install_pdf_deps.sh b/jupyter/utils/install_pdf_deps.sh new file mode 100755 index 000000000..40c290755 --- /dev/null +++ b/jupyter/utils/install_pdf_deps.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +# Install dependencies required for Notebooks PDF exports + +# tex live installation +echo "Installing TexLive to allow PDf export from Notebooks" +curl -L https://mirror.ctan.org/systems/texlive/tlnet/install-tl-unx.tar.gz -o install-tl-unx.tar.gz +zcat < install-tl-unx.tar.gz | tar xf - +cd install-tl-2* +perl ./install-tl --no-interaction --scheme=scheme-small --texdir=/usr/local/texlive +cd /usr/local/texlive/bin/x86_64-linux +./tlmgr install tcolorbox pdfcol adjustbox titling enumitem soul ucs collection-fontsrecommended + +# pandoc installation +curl -L https://github.com/jgm/pandoc/releases/download/3.7.0.2/pandoc-3.7.0.2-linux-amd64.tar.gz -o /tmp/pandoc.tar.gz +mkdir -p /usr/local/pandoc +tar xvzf /tmp/pandoc.tar.gz --strip-components 1 -C /usr/local/pandoc/ +rm -f /tmp/pandoc.tar.gz \ No newline at end of file diff --git a/jupyter/utils/jupyter_server_config.py b/jupyter/utils/jupyter_server_config.py new file mode 100644 index 000000000..62e828683 --- /dev/null +++ b/jupyter/utils/jupyter_server_config.py @@ -0,0 +1,6 @@ +# https://github.com/opendatahub-io-contrib/workbench-images/blob/main/snippets/ides/1-jupyter/files/etc/jupyter_notebook_config.py +c = get_config() +# Disable unsupported exporters +c.WebPDFExporter.enabled = False +c.QtPDFExporter.enabled = False +c.QtPNGExporter.enabled = False diff --git a/scripts/check-payload/config.toml b/scripts/check-payload/config.toml index ddb46eb22..0a07e12c4 100644 --- a/scripts/check-payload/config.toml +++ b/scripts/check-payload/config.toml @@ -250,6 +250,7 @@ error = "ErrNotDynLinked" files = [ # executable is not dynamically linked "/opt/app-root/bin/py-spy", + "/usr/local/pandoc/bin/pandoc", ] [[rpm.code-server.ignore]] diff --git a/tests/containers/workbenches/jupyterlab/jupyterlab_test.py b/tests/containers/workbenches/jupyterlab/jupyterlab_test.py index 509be198f..dda7b5b45 100644 --- a/tests/containers/workbenches/jupyterlab/jupyterlab_test.py +++ b/tests/containers/workbenches/jupyterlab/jupyterlab_test.py @@ -1,5 +1,8 @@ from __future__ import annotations +import pathlib +import tempfile + import allure import pytest import requests @@ -51,6 +54,51 @@ def test_spinner_html_loaded(self, jupyterlab_image: conftest.Image) -> None: finally: docker_utils.NotebookContainer(container).stop(timeout=0) + @allure.issue("RHOAIENG-16568") + @allure.description("Check that PDF export is working correctly") + def test_pdf_export(self, jupyterlab_image: conftest.Image) -> None: + container = WorkbenchContainer(image=jupyterlab_image.name, user=4321, group_add=[0]) + test_file_name = "test.ipybn" + test_file_content = """{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "# Hello World" ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ "Hello World\n" ] + } + ], + "source": [ "print('Hello World')" ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 + } + """.replace("\n", "") + try: + container.start(wait_for_readiness=True) + with tempfile.TemporaryDirectory() as tmpdir: + tmpdir = pathlib.Path(tmpdir) + (tmpdir / test_file_name).write_text(test_file_content) + docker_utils.container_cp( + container.get_wrapped_container(), src=str(tmpdir / test_file_name), dst=self.APP_ROOT_HOME + ) + exit_code, convert_output = container.exec(["jupyter", "nbconvert", test_file_name, "--to", "pdf"]) + assert "PDF successfully created" in convert_output.decode() + assert 0 == exit_code + finally: + docker_utils.NotebookContainer(container).stop(timeout=0) + @allure.issue("RHOAIENG-24348") @allure.description("Check that custom-built (to be FIPS-compliant) mongocli binary runs.") def test_mongocli_binary_runs(self, jupyterlab_image: conftest.Image) -> None: