mirror of
https://github.com/jupyter/docker-stacks.git
synced 2025-10-12 20:42:57 +00:00
Make start.sh
the entrypoint (#2087)
This commit is contained in:
@@ -225,21 +225,17 @@ docker run -it --rm \
|
|||||||
|
|
||||||
### `start.sh`
|
### `start.sh`
|
||||||
|
|
||||||
The `start-notebook.py` script inherits most of its option handling capability from a more generic `start.sh` script.
|
Most of the configuration options in the `start-notebook.py` script are handled by an internal `start.sh` script that automatically runs before the command provided to the container
|
||||||
The `start.sh` script supports all the features described above but allows you to specify an arbitrary command to execute.
|
(it's set as the container entrypoint).
|
||||||
|
This allows you to specify an arbitrary command that takes advantage of all these features.
|
||||||
For example, to run the text-based `ipython` console in a container, do the following:
|
For example, to run the text-based `ipython` console in a container, do the following:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -it --rm quay.io/jupyter/base-notebook start.sh ipython
|
docker run -it --rm quay.io/jupyter/base-notebook ipython
|
||||||
```
|
```
|
||||||
|
|
||||||
This script is handy when you derive a new Dockerfile from this image and install additional Jupyter applications with subcommands like `jupyter console`, `jupyter kernelgateway`, etc.
|
This script is handy when you derive a new Dockerfile from this image and install additional Jupyter applications with subcommands like `jupyter console`, `jupyter kernelgateway`, etc.
|
||||||
|
|
||||||
### Others
|
|
||||||
|
|
||||||
You can bypass the provided scripts and specify an arbitrary start command.
|
|
||||||
If you do, keep in mind that features, supported by the `start.sh` script and its kin, will not function (e.g., `GRANT_SUDO`).
|
|
||||||
|
|
||||||
## Conda Environments
|
## Conda Environments
|
||||||
|
|
||||||
The default Python 3.x [Conda environment](https://conda.io/projects/conda/en/latest/user-guide/concepts/environments.html) resides in `/opt/conda`.
|
The default Python 3.x [Conda environment](https://conda.io/projects/conda/en/latest/user-guide/concepts/environments.html) resides in `/opt/conda`.
|
||||||
|
@@ -34,8 +34,7 @@ It contains:
|
|||||||
- [mamba](https://github.com/mamba-org/mamba): "reimplementation of the conda package manager in C++". We use this package manager by default when installing packages.
|
- [mamba](https://github.com/mamba-org/mamba): "reimplementation of the conda package manager in C++". We use this package manager by default when installing packages.
|
||||||
- Unprivileged user `jovyan` (`uid=1000`, configurable, [see options in the common features section](./common.md) of this documentation) in group `users` (`gid=100`)
|
- Unprivileged user `jovyan` (`uid=1000`, configurable, [see options in the common features section](./common.md) of this documentation) in group `users` (`gid=100`)
|
||||||
with ownership over the `/home/jovyan` and `/opt/conda` paths
|
with ownership over the `/home/jovyan` and `/opt/conda` paths
|
||||||
- `tini` as the container entry point
|
- `tini` and a `start.sh` script as the container entry point - useful for running alternative commands in the container as applications are added (e.g. `ipython`, `jupyter kernelgateway`, `jupyter lab`)
|
||||||
- A `start.sh` script as the default command - useful for running alternative commands in the container as applications are added (e.g. `ipython`, `jupyter kernelgateway`, `jupyter lab`)
|
|
||||||
- A `run-hooks.sh` script, which can source/run files in a given directory
|
- A `run-hooks.sh` script, which can source/run files in a given directory
|
||||||
- Options for a passwordless sudo
|
- Options for a passwordless sudo
|
||||||
- Common system libraries like `bzip2`, `ca-certificates`, `locales`
|
- Common system libraries like `bzip2`, `ca-certificates`, `locales`
|
||||||
|
@@ -14,8 +14,8 @@ if "JUPYTERHUB_API_TOKEN" in os.environ:
|
|||||||
os.execvp(command[0], command)
|
os.execvp(command[0], command)
|
||||||
|
|
||||||
|
|
||||||
# Wrap everything in start.sh, no matter what
|
# Entrypoint is start.sh
|
||||||
command = ["/usr/local/bin/start.sh"]
|
command = []
|
||||||
|
|
||||||
# If we want to survive restarts, tell that to start.sh
|
# If we want to survive restarts, tell that to start.sh
|
||||||
if os.environ.get("RESTARTABLE") == "yes":
|
if os.environ.get("RESTARTABLE") == "yes":
|
||||||
@@ -40,4 +40,5 @@ if "NOTEBOOK_ARGS" in os.environ:
|
|||||||
command += sys.argv[1:]
|
command += sys.argv[1:]
|
||||||
|
|
||||||
# Execute the command!
|
# Execute the command!
|
||||||
|
print("Executing: " + " ".join(command))
|
||||||
os.execvp(command[0], command)
|
os.execvp(command[0], command)
|
||||||
|
@@ -5,7 +5,8 @@ import os
|
|||||||
import shlex
|
import shlex
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
command = ["/usr/local/bin/start.sh", "jupyterhub-singleuser"]
|
# Entrypoint is start.sh
|
||||||
|
command = ["jupyterhub-singleuser"]
|
||||||
|
|
||||||
# set default ip to 0.0.0.0
|
# set default ip to 0.0.0.0
|
||||||
if "--ip=" not in os.environ.get("NOTEBOOK_ARGS", ""):
|
if "--ip=" not in os.environ.get("NOTEBOOK_ARGS", ""):
|
||||||
@@ -20,4 +21,5 @@ if "NOTEBOOK_ARGS" in os.environ:
|
|||||||
command += sys.argv[1:]
|
command += sys.argv[1:]
|
||||||
|
|
||||||
# Execute the command!
|
# Execute the command!
|
||||||
|
print("Executing: " + " ".join(command))
|
||||||
os.execvp(command[0], command)
|
os.execvp(command[0], command)
|
||||||
|
@@ -124,8 +124,7 @@ RUN set -x && \
|
|||||||
fix-permissions "/home/${NB_USER}"
|
fix-permissions "/home/${NB_USER}"
|
||||||
|
|
||||||
# Configure container startup
|
# Configure container startup
|
||||||
ENTRYPOINT ["tini", "-g", "--"]
|
ENTRYPOINT ["tini", "-g", "--", "start.sh"]
|
||||||
CMD ["start.sh"]
|
|
||||||
|
|
||||||
# Copy local files as late as possible to avoid cache busting
|
# Copy local files as late as possible to avoid cache busting
|
||||||
COPY run-hooks.sh start.sh /usr/local/bin/
|
COPY run-hooks.sh start.sh /usr/local/bin/
|
||||||
|
@@ -34,6 +34,17 @@ else
|
|||||||
cmd=( "$@" )
|
cmd=( "$@" )
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Backwards compatibility: `start.sh` is executed by default in ENTRYPOINT
|
||||||
|
# so it should no longer be specified in CMD
|
||||||
|
if [ "${_START_SH_EXECUTED}" = "1" ]; then
|
||||||
|
_log "WARNING: start.sh is the default ENTRYPOINT, do not include it in CMD"
|
||||||
|
_log "Executing the command:" "${cmd[@]}"
|
||||||
|
exec "${cmd[@]}"
|
||||||
|
else
|
||||||
|
export _START_SH_EXECUTED=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
# NOTE: This hook will run as the user the container was started with!
|
# NOTE: This hook will run as the user the container was started with!
|
||||||
# shellcheck disable=SC1091
|
# shellcheck disable=SC1091
|
||||||
source /usr/local/bin/run-hooks.sh /usr/local/bin/start-notebook.d
|
source /usr/local/bin/run-hooks.sh /usr/local/bin/start-notebook.d
|
||||||
|
@@ -11,10 +11,14 @@ def check_r_mimetypes(container: TrackedContainer) -> None:
|
|||||||
"""Check if Rscript command can be executed"""
|
"""Check if Rscript command can be executed"""
|
||||||
LOGGER.info("Test that R command can be executed ...")
|
LOGGER.info("Test that R command can be executed ...")
|
||||||
R_MIMETYPES_CHECK_CMD = 'if (length(getOption("jupyter.plot_mimetypes")) != 5) {stop("missing jupyter.plot_mimetypes")}'
|
R_MIMETYPES_CHECK_CMD = 'if (length(getOption("jupyter.plot_mimetypes")) != 5) {stop("missing jupyter.plot_mimetypes")}'
|
||||||
|
command = ["Rscript", "-e", R_MIMETYPES_CHECK_CMD]
|
||||||
logs = container.run_and_wait(
|
logs = container.run_and_wait(
|
||||||
timeout=10,
|
timeout=10,
|
||||||
tty=True,
|
tty=True,
|
||||||
command=["Rscript", "-e", R_MIMETYPES_CHECK_CMD],
|
command=command,
|
||||||
)
|
)
|
||||||
LOGGER.debug(f"{logs=}")
|
LOGGER.debug(f"{logs=}")
|
||||||
assert len(logs) == 0, f"Command {R_MIMETYPES_CHECK_CMD=} failed"
|
# If there is any output after this it means there was an error
|
||||||
|
assert logs.splitlines()[-1] == "Executing the command: " + " ".join(
|
||||||
|
command
|
||||||
|
), f"Command {R_MIMETYPES_CHECK_CMD=} failed"
|
||||||
|
@@ -33,7 +33,7 @@ def test_nbconvert(container: TrackedContainer, test_file: str) -> None:
|
|||||||
timeout=60,
|
timeout=60,
|
||||||
volumes={str(host_data_dir): {"bind": cont_data_dir, "mode": "ro"}},
|
volumes={str(host_data_dir): {"bind": cont_data_dir, "mode": "ro"}},
|
||||||
tty=True,
|
tty=True,
|
||||||
command=["start.sh", "bash", "-c", command],
|
command=["bash", "-c", command],
|
||||||
)
|
)
|
||||||
|
|
||||||
expected_file = f"{output_dir}/{test_file}.md"
|
expected_file = f"{output_dir}/{test_file}.md"
|
||||||
|
@@ -35,7 +35,7 @@ def test_nb_user_change(container: TrackedContainer) -> None:
|
|||||||
tty=True,
|
tty=True,
|
||||||
user="root",
|
user="root",
|
||||||
environment=[f"NB_USER={nb_user}", "CHOWN_HOME=yes"],
|
environment=[f"NB_USER={nb_user}", "CHOWN_HOME=yes"],
|
||||||
command=["start.sh", "bash", "-c", "sleep infinity"],
|
command=["bash", "-c", "sleep infinity"],
|
||||||
)
|
)
|
||||||
|
|
||||||
# Give the chown time to complete.
|
# Give the chown time to complete.
|
||||||
|
@@ -12,6 +12,6 @@ def test_pandoc(container: TrackedContainer) -> None:
|
|||||||
logs = container.run_and_wait(
|
logs = container.run_and_wait(
|
||||||
timeout=10,
|
timeout=10,
|
||||||
tty=True,
|
tty=True,
|
||||||
command=["start.sh", "bash", "-c", 'echo "**BOLD**" | pandoc'],
|
command=["bash", "-c", 'echo "**BOLD**" | pandoc'],
|
||||||
)
|
)
|
||||||
assert "<p><strong>BOLD</strong></p>" in logs
|
assert "<p><strong>BOLD</strong></p>" in logs
|
||||||
|
@@ -53,7 +53,7 @@ def test_start_notebook(
|
|||||||
LOGGER.debug(logs)
|
LOGGER.debug(logs)
|
||||||
# checking that the expected command is launched
|
# checking that the expected command is launched
|
||||||
assert (
|
assert (
|
||||||
f"Executing the command: {expected_command}" in logs
|
f"Executing: {expected_command}" in logs
|
||||||
), f"Not the expected command ({expected_command}) was launched"
|
), f"Not the expected command ({expected_command}) was launched"
|
||||||
# checking errors and warnings in logs
|
# checking errors and warnings in logs
|
||||||
assert "ERROR" not in logs, "ERROR(s) found in logs"
|
assert "ERROR" not in logs, "ERROR(s) found in logs"
|
||||||
@@ -76,10 +76,7 @@ def test_tini_entrypoint(
|
|||||||
https://superuser.com/questions/632979/if-i-know-the-pid-number-of-a-process-how-can-i-get-its-name
|
https://superuser.com/questions/632979/if-i-know-the-pid-number-of-a-process-how-can-i-get-its-name
|
||||||
"""
|
"""
|
||||||
LOGGER.info(f"Test that {command} is launched as PID {pid} ...")
|
LOGGER.info(f"Test that {command} is launched as PID {pid} ...")
|
||||||
running_container = container.run_detached(
|
running_container = container.run_detached(tty=True)
|
||||||
tty=True,
|
|
||||||
command=["start.sh"],
|
|
||||||
)
|
|
||||||
# Select the PID 1 and get the corresponding command
|
# Select the PID 1 and get the corresponding command
|
||||||
cmd = running_container.exec_run(f"ps -p {pid} -o comm=")
|
cmd = running_container.exec_run(f"ps -p {pid} -o comm=")
|
||||||
output = cmd.output.decode("utf-8").strip("\n")
|
output = cmd.output.decode("utf-8").strip("\n")
|
||||||
|
@@ -21,17 +21,20 @@ Use `package_helper.installed_packages()` instead of `package_helper.requested_p
|
|||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
$ make test/base-notebook
|
$ make test/docker-stacks-foundation
|
||||||
|
|
||||||
# [...]
|
# [...]
|
||||||
# tests/base-notebook/test_packages.py::test_python_packages
|
# tests/docker-stacks-foundation/test_packages.py::test_python_packages
|
||||||
# ---------------------------------------------------------------------------------------------- live log setup ----------------------------------------------------------------------------------------------
|
# -------------------------------- live log setup --------------------------------
|
||||||
# 2023-11-04 23:59:01 [ INFO] Starting container quay.io/jupyter/base-notebook ... (package_helper.py:55)
|
# 2024-01-21 17:46:43 [ INFO] Starting container quay.io/jupyter/docker-stacks-foundation ... (package_helper.py:55)
|
||||||
# 2023-11-04 23:59:01 [ INFO] Running quay.io/jupyter/base-notebook with args {'detach': True, 'tty': True, 'command': ['start.sh', 'bash', '-c', 'sleep infinity']} ... (conftest.py:99)
|
# 2024-01-21 17:46:43 [ INFO] Running quay.io/jupyter/docker-stacks-foundation with args {'detach': True, 'tty': True, 'command': ['bash', '-c', 'sleep infinity']} ... (conftest.py:99)
|
||||||
# 2023-11-04 23:59:01 [ INFO] Grabbing the list of manually requested packages ... (package_helper.py:83)
|
# 2024-01-21 17:46:44 [ INFO] Grabbing the list of manually requested packages ... (package_helper.py:83)
|
||||||
# ---------------------------------------------------------------------------------------------- live log call -----------------------------------------------------------------------------------------------
|
# -------------------------------- live log call ---------------------------------
|
||||||
# 2023-11-04 23:59:02 [ INFO] Testing the import of packages ... (test_packages.py:152)
|
# 2024-01-21 17:46:44 [ INFO] Testing the import of packages ... (test_packages.py:151)
|
||||||
# 2023-11-04 23:59:02 [ INFO] Trying to import mamba (test_packages.py:154)
|
# 2024-01-21 17:46:44 [ INFO] Trying to import mamba (test_packages.py:153)
|
||||||
|
# 2024-01-21 17:46:44 [ INFO] Trying to import jupyter_core (test_packages.py:153)
|
||||||
|
PASSED [ 17%]
|
||||||
|
# ------------------------------ live log teardown -------------------------------
|
||||||
# [...]
|
# [...]
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@@ -17,8 +17,8 @@ def test_python_version(container: TrackedContainer) -> None:
|
|||||||
tty=True,
|
tty=True,
|
||||||
command=["python", "--version"],
|
command=["python", "--version"],
|
||||||
)
|
)
|
||||||
assert logs.startswith("Python ")
|
python = next(line for line in logs.splitlines() if line.startswith("Python "))
|
||||||
full_version = logs.split()[1]
|
full_version = python.split()[1]
|
||||||
major_minor_version = full_version[: full_version.rfind(".")]
|
major_minor_version = full_version[: full_version.rfind(".")]
|
||||||
|
|
||||||
assert major_minor_version == EXPECTED_PYTHON_VERSION
|
assert major_minor_version == EXPECTED_PYTHON_VERSION
|
||||||
@@ -31,4 +31,4 @@ def test_python_pinned_version(container: TrackedContainer) -> None:
|
|||||||
tty=True,
|
tty=True,
|
||||||
command=["cat", "/opt/conda/conda-meta/pinned"],
|
command=["cat", "/opt/conda/conda-meta/pinned"],
|
||||||
)
|
)
|
||||||
assert logs.startswith(f"python {EXPECTED_PYTHON_VERSION}.*")
|
assert f"python {EXPECTED_PYTHON_VERSION}.*" in logs
|
||||||
|
@@ -34,5 +34,5 @@ def test_units(container: TrackedContainer) -> None:
|
|||||||
timeout=30,
|
timeout=30,
|
||||||
volumes={str(host_data_dir): {"bind": cont_data_dir, "mode": "ro"}},
|
volumes={str(host_data_dir): {"bind": cont_data_dir, "mode": "ro"}},
|
||||||
tty=True,
|
tty=True,
|
||||||
command=["start.sh", "python", f"{cont_data_dir}/{test_file_name}"],
|
command=["python", f"{cont_data_dir}/{test_file_name}"],
|
||||||
)
|
)
|
||||||
|
@@ -18,7 +18,7 @@ def test_uid_change(container: TrackedContainer) -> None:
|
|||||||
tty=True,
|
tty=True,
|
||||||
user="root",
|
user="root",
|
||||||
environment=["NB_UID=1010"],
|
environment=["NB_UID=1010"],
|
||||||
command=["start.sh", "bash", "-c", "id && touch /opt/conda/test-file"],
|
command=["bash", "-c", "id && touch /opt/conda/test-file"],
|
||||||
)
|
)
|
||||||
assert "uid=1010(jovyan)" in logs
|
assert "uid=1010(jovyan)" in logs
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ def test_gid_change(container: TrackedContainer) -> None:
|
|||||||
tty=True,
|
tty=True,
|
||||||
user="root",
|
user="root",
|
||||||
environment=["NB_GID=110"],
|
environment=["NB_GID=110"],
|
||||||
command=["start.sh", "id"],
|
command=["id"],
|
||||||
)
|
)
|
||||||
assert "gid=110(jovyan)" in logs
|
assert "gid=110(jovyan)" in logs
|
||||||
assert "groups=110(jovyan),100(users)" in logs
|
assert "groups=110(jovyan),100(users)" in logs
|
||||||
@@ -43,7 +43,7 @@ def test_nb_user_change(container: TrackedContainer) -> None:
|
|||||||
tty=True,
|
tty=True,
|
||||||
user="root",
|
user="root",
|
||||||
environment=[f"NB_USER={nb_user}", "CHOWN_HOME=yes"],
|
environment=[f"NB_USER={nb_user}", "CHOWN_HOME=yes"],
|
||||||
command=["start.sh", "bash", "-c", "sleep infinity"],
|
command=["bash", "-c", "sleep infinity"],
|
||||||
)
|
)
|
||||||
|
|
||||||
# Give the chown time to complete.
|
# Give the chown time to complete.
|
||||||
@@ -99,7 +99,6 @@ def test_chown_extra(container: TrackedContainer) -> None:
|
|||||||
"CHOWN_EXTRA_OPTS=-R",
|
"CHOWN_EXTRA_OPTS=-R",
|
||||||
],
|
],
|
||||||
command=[
|
command=[
|
||||||
"start.sh",
|
|
||||||
"bash",
|
"bash",
|
||||||
"-c",
|
"-c",
|
||||||
"stat -c '%n:%u:%g' /home/jovyan/.bashrc /opt/conda/bin/jupyter",
|
"stat -c '%n:%u:%g' /home/jovyan/.bashrc /opt/conda/bin/jupyter",
|
||||||
@@ -123,7 +122,7 @@ def test_chown_home(container: TrackedContainer) -> None:
|
|||||||
"NB_UID=1010",
|
"NB_UID=1010",
|
||||||
"NB_GID=101",
|
"NB_GID=101",
|
||||||
],
|
],
|
||||||
command=["start.sh", "bash", "-c", "stat -c '%n:%u:%g' /home/kitten/.bashrc"],
|
command=["bash", "-c", "stat -c '%n:%u:%g' /home/kitten/.bashrc"],
|
||||||
)
|
)
|
||||||
assert "/home/kitten/.bashrc:1010:101" in logs
|
assert "/home/kitten/.bashrc:1010:101" in logs
|
||||||
|
|
||||||
@@ -135,7 +134,7 @@ def test_sudo(container: TrackedContainer) -> None:
|
|||||||
tty=True,
|
tty=True,
|
||||||
user="root",
|
user="root",
|
||||||
environment=["GRANT_SUDO=yes"],
|
environment=["GRANT_SUDO=yes"],
|
||||||
command=["start.sh", "sudo", "id"],
|
command=["sudo", "id"],
|
||||||
)
|
)
|
||||||
assert "uid=0(root)" in logs
|
assert "uid=0(root)" in logs
|
||||||
|
|
||||||
@@ -147,7 +146,7 @@ def test_sudo_path(container: TrackedContainer) -> None:
|
|||||||
tty=True,
|
tty=True,
|
||||||
user="root",
|
user="root",
|
||||||
environment=["GRANT_SUDO=yes"],
|
environment=["GRANT_SUDO=yes"],
|
||||||
command=["start.sh", "sudo", "which", "jupyter"],
|
command=["sudo", "which", "jupyter"],
|
||||||
)
|
)
|
||||||
assert logs.rstrip().endswith("/opt/conda/bin/jupyter")
|
assert logs.rstrip().endswith("/opt/conda/bin/jupyter")
|
||||||
|
|
||||||
@@ -158,7 +157,7 @@ def test_sudo_path_without_grant(container: TrackedContainer) -> None:
|
|||||||
timeout=10,
|
timeout=10,
|
||||||
tty=True,
|
tty=True,
|
||||||
user="root",
|
user="root",
|
||||||
command=["start.sh", "which", "jupyter"],
|
command=["which", "jupyter"],
|
||||||
)
|
)
|
||||||
assert logs.rstrip().endswith("/opt/conda/bin/jupyter")
|
assert logs.rstrip().endswith("/opt/conda/bin/jupyter")
|
||||||
|
|
||||||
@@ -173,7 +172,7 @@ def test_group_add(container: TrackedContainer) -> None:
|
|||||||
no_warnings=False,
|
no_warnings=False,
|
||||||
user="1010:1010",
|
user="1010:1010",
|
||||||
group_add=["users"], # Ensures write access to /home/jovyan
|
group_add=["users"], # Ensures write access to /home/jovyan
|
||||||
command=["start.sh", "id"],
|
command=["id"],
|
||||||
)
|
)
|
||||||
warnings = TrackedContainer.get_warnings(logs)
|
warnings = TrackedContainer.get_warnings(logs)
|
||||||
assert len(warnings) == 1
|
assert len(warnings) == 1
|
||||||
@@ -191,7 +190,7 @@ def test_set_uid(container: TrackedContainer) -> None:
|
|||||||
timeout=5,
|
timeout=5,
|
||||||
no_warnings=False,
|
no_warnings=False,
|
||||||
user="1010",
|
user="1010",
|
||||||
command=["start.sh", "id"],
|
command=["id"],
|
||||||
)
|
)
|
||||||
assert "uid=1010(jovyan) gid=0(root)" in logs
|
assert "uid=1010(jovyan) gid=0(root)" in logs
|
||||||
warnings = TrackedContainer.get_warnings(logs)
|
warnings = TrackedContainer.get_warnings(logs)
|
||||||
@@ -207,7 +206,7 @@ def test_set_uid_and_nb_user(container: TrackedContainer) -> None:
|
|||||||
user="1010",
|
user="1010",
|
||||||
environment=["NB_USER=kitten"],
|
environment=["NB_USER=kitten"],
|
||||||
group_add=["users"], # Ensures write access to /home/jovyan
|
group_add=["users"], # Ensures write access to /home/jovyan
|
||||||
command=["start.sh", "id"],
|
command=["id"],
|
||||||
)
|
)
|
||||||
assert "uid=1010(kitten) gid=0(root)" in logs
|
assert "uid=1010(kitten) gid=0(root)" in logs
|
||||||
warnings = TrackedContainer.get_warnings(logs)
|
warnings = TrackedContainer.get_warnings(logs)
|
||||||
@@ -236,7 +235,7 @@ def test_container_not_delete_bind_mount(
|
|||||||
"CHOWN_HOME=yes",
|
"CHOWN_HOME=yes",
|
||||||
],
|
],
|
||||||
volumes={d: {"bind": "/home/jovyan/data", "mode": "rw"}},
|
volumes={d: {"bind": "/home/jovyan/data", "mode": "rw"}},
|
||||||
command=["start.sh", "ls"],
|
command=["ls"],
|
||||||
)
|
)
|
||||||
assert p.read_text() == "some-content"
|
assert p.read_text() == "some-content"
|
||||||
assert len(list(tmp_path.iterdir())) == 1
|
assert len(list(tmp_path.iterdir())) == 1
|
||||||
@@ -259,7 +258,6 @@ def test_jupyter_env_vars_to_unset(
|
|||||||
"SECRET_FRUIT=mango",
|
"SECRET_FRUIT=mango",
|
||||||
],
|
],
|
||||||
command=[
|
command=[
|
||||||
"start.sh",
|
|
||||||
"bash",
|
"bash",
|
||||||
"-c",
|
"-c",
|
||||||
"echo I like ${FRUIT} and ${SECRET_FRUIT:-stuff}, and love ${SECRET_ANIMAL:-to keep secrets}!",
|
"echo I like ${FRUIT} and ${SECRET_FRUIT:-stuff}, and love ${SECRET_ANIMAL:-to keep secrets}!",
|
||||||
@@ -284,7 +282,26 @@ def test_secure_path(container: TrackedContainer, tmp_path: pathlib.Path) -> Non
|
|||||||
tty=True,
|
tty=True,
|
||||||
user="root",
|
user="root",
|
||||||
volumes={p: {"bind": "/usr/bin/python", "mode": "ro"}},
|
volumes={p: {"bind": "/usr/bin/python", "mode": "ro"}},
|
||||||
command=["start.sh", "python", "--version"],
|
command=["python", "--version"],
|
||||||
)
|
)
|
||||||
assert "Wrong python" not in logs
|
assert "Wrong python" not in logs
|
||||||
assert "Python" in logs
|
assert "Python" in logs
|
||||||
|
|
||||||
|
|
||||||
|
def test_startsh_multiple_exec(container: TrackedContainer) -> None:
|
||||||
|
"""If start.sh is executed multiple times check that configuration only occurs once."""
|
||||||
|
logs = container.run_and_wait(
|
||||||
|
timeout=10,
|
||||||
|
no_warnings=False,
|
||||||
|
tty=True,
|
||||||
|
user="root",
|
||||||
|
environment=["GRANT_SUDO=yes"],
|
||||||
|
command=["start.sh", "sudo", "id"],
|
||||||
|
)
|
||||||
|
assert "uid=0(root)" in logs
|
||||||
|
warnings = TrackedContainer.get_warnings(logs)
|
||||||
|
assert len(warnings) == 1
|
||||||
|
assert (
|
||||||
|
"WARNING: start.sh is the default ENTRYPOINT, do not include it in CMD"
|
||||||
|
in warnings[0]
|
||||||
|
)
|
||||||
|
@@ -28,7 +28,7 @@ def test_nbconvert(
|
|||||||
timeout=30,
|
timeout=30,
|
||||||
volumes={str(host_data_dir): {"bind": cont_data_dir, "mode": "ro"}},
|
volumes={str(host_data_dir): {"bind": cont_data_dir, "mode": "ro"}},
|
||||||
tty=True,
|
tty=True,
|
||||||
command=["start.sh", "bash", "-c", command],
|
command=["bash", "-c", command],
|
||||||
)
|
)
|
||||||
expected_file = f"{output_dir}/{test_file}.{output_format}"
|
expected_file = f"{output_dir}/{test_file}.{output_format}"
|
||||||
assert expected_file in logs, f"Expected file {expected_file} not generated"
|
assert expected_file in logs, f"Expected file {expected_file} not generated"
|
||||||
|
@@ -55,7 +55,7 @@ class CondaPackageHelper:
|
|||||||
LOGGER.info(f"Starting container {container.image_name} ...")
|
LOGGER.info(f"Starting container {container.image_name} ...")
|
||||||
return container.run_detached(
|
return container.run_detached(
|
||||||
tty=True,
|
tty=True,
|
||||||
command=["start.sh", "bash", "-c", "sleep infinity"],
|
command=["bash", "-c", "sleep infinity"],
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@@ -18,5 +18,5 @@ def run_command(
|
|||||||
return container.run_and_wait(
|
return container.run_and_wait(
|
||||||
timeout=timeout,
|
timeout=timeout,
|
||||||
tty=True,
|
tty=True,
|
||||||
command=["start.sh", "bash", "-c", command],
|
command=["bash", "-c", command],
|
||||||
)
|
)
|
||||||
|
@@ -16,7 +16,6 @@ def test_cython(container: TrackedContainer) -> None:
|
|||||||
volumes={str(host_data_dir): {"bind": cont_data_dir, "mode": "ro"}},
|
volumes={str(host_data_dir): {"bind": cont_data_dir, "mode": "ro"}},
|
||||||
tty=True,
|
tty=True,
|
||||||
command=[
|
command=[
|
||||||
"start.sh",
|
|
||||||
"bash",
|
"bash",
|
||||||
"-c",
|
"-c",
|
||||||
# We copy our data to a temporary folder to be able to modify the directory
|
# We copy our data to a temporary folder to be able to modify the directory
|
||||||
|
@@ -30,5 +30,5 @@ def test_check_extension(container: TrackedContainer, extension: str) -> None:
|
|||||||
container.run_and_wait(
|
container.run_and_wait(
|
||||||
timeout=10,
|
timeout=10,
|
||||||
tty=True,
|
tty=True,
|
||||||
command=["start.sh", "jupyter", "labextension", "check", extension],
|
command=["jupyter", "labextension", "check", extension],
|
||||||
)
|
)
|
||||||
|
@@ -42,7 +42,7 @@ def test_matplotlib(
|
|||||||
running_container = container.run_detached(
|
running_container = container.run_detached(
|
||||||
volumes={str(host_data_dir): {"bind": cont_data_dir, "mode": "ro"}},
|
volumes={str(host_data_dir): {"bind": cont_data_dir, "mode": "ro"}},
|
||||||
tty=True,
|
tty=True,
|
||||||
command=["start.sh", "bash", "-c", command],
|
command=["bash", "-c", command],
|
||||||
)
|
)
|
||||||
command = f"python {cont_data_dir}/{test_file}"
|
command = f"python {cont_data_dir}/{test_file}"
|
||||||
cmd = running_container.exec_run(command)
|
cmd = running_container.exec_run(command)
|
||||||
|
Reference in New Issue
Block a user