From a2a52dfb2103d12e4348dec6824d4eaf68a68f58 Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Mon, 14 Aug 2023 18:02:48 +0200 Subject: Fix containerize view symlink issue (#39419) --- lib/spack/spack/container/writers/__init__.py | 21 +++++++++++---------- share/spack/templates/container/Dockerfile | 8 +++++--- share/spack/templates/container/singularity.def | 9 ++++++--- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/lib/spack/spack/container/writers/__init__.py b/lib/spack/spack/container/writers/__init__.py index 710021cb06..4e15ae6f58 100644 --- a/lib/spack/spack/container/writers/__init__.py +++ b/lib/spack/spack/container/writers/__init__.py @@ -5,8 +5,8 @@ """Writers for different kind of recipes and related convenience functions. """ -import collections import copy +from collections import namedtuple from typing import Optional import spack.environment as ev @@ -159,13 +159,13 @@ class PathContext(tengine.Context): @tengine.context_property def run(self): """Information related to the run image.""" - Run = collections.namedtuple("Run", ["image"]) + Run = namedtuple("Run", ["image"]) return Run(image=self.final_image) @tengine.context_property def build(self): """Information related to the build image.""" - Build = collections.namedtuple("Build", ["image"]) + Build = namedtuple("Build", ["image"]) return Build(image=self.build_image) @tengine.context_property @@ -176,12 +176,13 @@ class PathContext(tengine.Context): @tengine.context_property def paths(self): """Important paths in the image""" - Paths = collections.namedtuple("Paths", ["environment", "store", "hidden_view", "view"]) + Paths = namedtuple("Paths", ["environment", "store", "view_parent", "view", "former_view"]) return Paths( environment="/opt/spack-environment", store="/opt/software", - hidden_view="/opt/._view", - view="/opt/view", + view_parent="/opt/views", + view="/opt/views/view", + former_view="/opt/view", # /opt/view -> /opt/views/view for backward compatibility ) @tengine.context_property @@ -257,7 +258,7 @@ class PathContext(tengine.Context): update, install, clean = commands_for(os_pkg_manager) - Packages = collections.namedtuple("Packages", ["update", "install", "list", "clean"]) + Packages = namedtuple("Packages", ["update", "install", "list", "clean"]) return Packages(update=update, install=install, list=package_list, clean=clean) def _os_pkg_manager(self): @@ -273,7 +274,7 @@ class PathContext(tengine.Context): @tengine.context_property def extra_instructions(self): - Extras = collections.namedtuple("Extra", ["build", "final"]) + Extras = namedtuple("Extra", ["build", "final"]) extras = self.container_config.get("extra_instructions", {}) build, final = extras.get("build", None), extras.get("final", None) return Extras(build=build, final=final) @@ -295,7 +296,7 @@ class PathContext(tengine.Context): context = {"bootstrap": {"image": self.bootstrap_image, "spack_checkout": command}} bootstrap_recipe = env.get_template(template_path).render(**context) - Bootstrap = collections.namedtuple("Bootstrap", ["image", "recipe"]) + Bootstrap = namedtuple("Bootstrap", ["image", "recipe"]) return Bootstrap(image=self.bootstrap_image, recipe=bootstrap_recipe) @tengine.context_property @@ -303,7 +304,7 @@ class PathContext(tengine.Context): render_bootstrap = bool(self.bootstrap_image) render_build = not (self.last_phase == "bootstrap") render_final = self.last_phase in (None, "final") - Render = collections.namedtuple("Render", ["bootstrap", "build", "final"]) + Render = namedtuple("Render", ["bootstrap", "build", "final"]) return Render(bootstrap=render_bootstrap, build=render_build, final=render_final) def __call__(self): diff --git a/share/spack/templates/container/Dockerfile b/share/spack/templates/container/Dockerfile index 92e89668e0..27c2dbf5cf 100644 --- a/share/spack/templates/container/Dockerfile +++ b/share/spack/templates/container/Dockerfile @@ -51,15 +51,17 @@ FROM {{ run.image }} COPY --from=builder {{ paths.environment }} {{ paths.environment }} COPY --from=builder {{ paths.store }} {{ paths.store }} -COPY --from=builder {{ paths.hidden_view }} {{ paths.hidden_view }} -COPY --from=builder {{ paths.view }} {{ paths.view }} + +# paths.view is a symlink, so copy the parent to avoid dereferencing and duplicating it +COPY --from=builder {{ paths.view_parent }} {{ paths.view_parent }} RUN { \ echo '#!/bin/sh' \ && echo '.' {{ paths.environment }}/activate.sh \ && echo 'exec "$@"'; \ } > /entrypoint.sh \ -&& chmod a+x /entrypoint.sh +&& chmod a+x /entrypoint.sh \ +&& ln -s {{ paths.view }} {{ paths.former_view }} {% block final_stage %} diff --git a/share/spack/templates/container/singularity.def b/share/spack/templates/container/singularity.def index a67d25783d..4184db92b6 100644 --- a/share/spack/templates/container/singularity.def +++ b/share/spack/templates/container/singularity.def @@ -47,7 +47,7 @@ EOF {% for application, help_text in apps.items() %} %apprun {{ application }} - exec /opt/view/bin/{{ application }} "$@" + exec {{ paths.view }}/bin/{{ application }} "$@" %apphelp {{ application }} {{help_text }} @@ -61,11 +61,14 @@ Stage: final %files from build {{ paths.environment }} /opt {{ paths.store }} /opt - {{ paths.hidden_view }} /opt - {{ paths.view }} /opt + {{ paths.view_parent }} /opt {{ paths.environment }}/environment_modifications.sh {{ paths.environment }}/environment_modifications.sh %post + + # Symlink the old view location + ln -s {{ paths.view }} {{ paths.former_view }} + {% block final_stage %} {% if os_packages_final.list %} # Update, install and cleanup of system packages needed at run-time -- cgit v1.2.3-70-g09d2