Fix containerize view symlink issue (#39419)

This commit is contained in:
Harmen Stoppels 2023-08-14 18:02:48 +02:00 committed by GitHub
parent f0ed159a1b
commit a2a52dfb21
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 22 additions and 16 deletions

View File

@ -5,8 +5,8 @@
"""Writers for different kind of recipes and related """Writers for different kind of recipes and related
convenience functions. convenience functions.
""" """
import collections
import copy import copy
from collections import namedtuple
from typing import Optional from typing import Optional
import spack.environment as ev import spack.environment as ev
@ -159,13 +159,13 @@ def depfile(self):
@tengine.context_property @tengine.context_property
def run(self): def run(self):
"""Information related to the run image.""" """Information related to the run image."""
Run = collections.namedtuple("Run", ["image"]) Run = namedtuple("Run", ["image"])
return Run(image=self.final_image) return Run(image=self.final_image)
@tengine.context_property @tengine.context_property
def build(self): def build(self):
"""Information related to the build image.""" """Information related to the build image."""
Build = collections.namedtuple("Build", ["image"]) Build = namedtuple("Build", ["image"])
return Build(image=self.build_image) return Build(image=self.build_image)
@tengine.context_property @tengine.context_property
@ -176,12 +176,13 @@ def strip(self):
@tengine.context_property @tengine.context_property
def paths(self): def paths(self):
"""Important paths in the image""" """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( return Paths(
environment="/opt/spack-environment", environment="/opt/spack-environment",
store="/opt/software", store="/opt/software",
hidden_view="/opt/._view", view_parent="/opt/views",
view="/opt/view", view="/opt/views/view",
former_view="/opt/view", # /opt/view -> /opt/views/view for backward compatibility
) )
@tengine.context_property @tengine.context_property
@ -257,7 +258,7 @@ def _package_info_from(self, package_list):
update, install, clean = commands_for(os_pkg_manager) 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) return Packages(update=update, install=install, list=package_list, clean=clean)
def _os_pkg_manager(self): def _os_pkg_manager(self):
@ -273,7 +274,7 @@ def _os_pkg_manager(self):
@tengine.context_property @tengine.context_property
def extra_instructions(self): def extra_instructions(self):
Extras = collections.namedtuple("Extra", ["build", "final"]) Extras = namedtuple("Extra", ["build", "final"])
extras = self.container_config.get("extra_instructions", {}) extras = self.container_config.get("extra_instructions", {})
build, final = extras.get("build", None), extras.get("final", None) build, final = extras.get("build", None), extras.get("final", None)
return Extras(build=build, final=final) return Extras(build=build, final=final)
@ -295,7 +296,7 @@ def bootstrap(self):
context = {"bootstrap": {"image": self.bootstrap_image, "spack_checkout": command}} context = {"bootstrap": {"image": self.bootstrap_image, "spack_checkout": command}}
bootstrap_recipe = env.get_template(template_path).render(**context) 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) return Bootstrap(image=self.bootstrap_image, recipe=bootstrap_recipe)
@tengine.context_property @tengine.context_property
@ -303,7 +304,7 @@ def render_phase(self):
render_bootstrap = bool(self.bootstrap_image) render_bootstrap = bool(self.bootstrap_image)
render_build = not (self.last_phase == "bootstrap") render_build = not (self.last_phase == "bootstrap")
render_final = self.last_phase in (None, "final") 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) return Render(bootstrap=render_bootstrap, build=render_build, final=render_final)
def __call__(self): def __call__(self):

View File

@ -51,15 +51,17 @@ FROM {{ run.image }}
COPY --from=builder {{ paths.environment }} {{ paths.environment }} COPY --from=builder {{ paths.environment }} {{ paths.environment }}
COPY --from=builder {{ paths.store }} {{ paths.store }} 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 { \ RUN { \
echo '#!/bin/sh' \ echo '#!/bin/sh' \
&& echo '.' {{ paths.environment }}/activate.sh \ && echo '.' {{ paths.environment }}/activate.sh \
&& echo 'exec "$@"'; \ && echo 'exec "$@"'; \
} > /entrypoint.sh \ } > /entrypoint.sh \
&& chmod a+x /entrypoint.sh && chmod a+x /entrypoint.sh \
&& ln -s {{ paths.view }} {{ paths.former_view }}
{% block final_stage %} {% block final_stage %}

View File

@ -47,7 +47,7 @@ EOF
{% for application, help_text in apps.items() %} {% for application, help_text in apps.items() %}
%apprun {{ application }} %apprun {{ application }}
exec /opt/view/bin/{{ application }} "$@" exec {{ paths.view }}/bin/{{ application }} "$@"
%apphelp {{ application }} %apphelp {{ application }}
{{help_text }} {{help_text }}
@ -61,11 +61,14 @@ Stage: final
%files from build %files from build
{{ paths.environment }} /opt {{ paths.environment }} /opt
{{ paths.store }} /opt {{ paths.store }} /opt
{{ paths.hidden_view }} /opt {{ paths.view_parent }} /opt
{{ paths.view }} /opt
{{ paths.environment }}/environment_modifications.sh {{ paths.environment }}/environment_modifications.sh {{ paths.environment }}/environment_modifications.sh {{ paths.environment }}/environment_modifications.sh
%post %post
# Symlink the old view location
ln -s {{ paths.view }} {{ paths.former_view }}
{% block final_stage %} {% block final_stage %}
{% if os_packages_final.list %} {% if os_packages_final.list %}
# Update, install and cleanup of system packages needed at run-time # Update, install and cleanup of system packages needed at run-time