-
Notifications
You must be signed in to change notification settings - Fork 203
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3975 from boegel/apptainer
extend (experimental) support for generating container images with Apptainer
- Loading branch information
Showing
5 changed files
with
212 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
# documentation: https://help.github.com/en/articles/workflow-syntax-for-github-actions | ||
name: Tests for Apptainer container support | ||
on: [push, pull_request] | ||
|
||
permissions: | ||
contents: read # to fetch code (actions/checkout) | ||
|
||
concurrency: | ||
group: ${{format('{0}:{1}:{2}', github.repository, github.ref, github.workflow)}} | ||
cancel-in-progress: true | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-22.04 | ||
strategy: | ||
matrix: | ||
python: [2.7, 3.7] | ||
apptainer: [1.0.0, 1.1.7] | ||
fail-fast: false | ||
steps: | ||
- uses: actions/checkout@v2 | ||
|
||
- name: set up Python | ||
uses: actions/setup-python@v2 | ||
with: | ||
python-version: ${{matrix.python}} | ||
architecture: x64 | ||
|
||
- name: install OS & Python packages | ||
run: | | ||
# for building CentOS 7 container images | ||
sudo apt-get install rpm | ||
sudo apt-get install dnf | ||
# for modules tool | ||
sudo apt-get install lua5.2 liblua5.2-dev lua-filesystem lua-posix tcl tcl-dev | ||
# fix for lua-posix packaging issue, see https://bugs.launchpad.net/ubuntu/+source/lua-posix/+bug/1752082 | ||
# needed for Ubuntu 18.04, but not for Ubuntu 20.04, so skipping symlinking if posix.so already exists | ||
if [ ! -e /usr/lib/x86_64-linux-gnu/lua/5.2/posix.so ] ; then | ||
sudo ln -s /usr/lib/x86_64-linux-gnu/lua/5.2/posix_c.so /usr/lib/x86_64-linux-gnu/lua/5.2/posix.so | ||
fi | ||
- name: install Lmod | ||
run: | | ||
# avoid downloading modules tool sources into easybuild-framework dir | ||
cd $HOME | ||
export INSTALL_DEP=$GITHUB_WORKSPACE/easybuild/scripts/install_eb_dep.sh | ||
# install Lmod | ||
source $INSTALL_DEP Lmod-8.4.27 $HOME | ||
# changes in environment are not passed to other steps, so need to create files... | ||
echo $MOD_INIT > mod_init | ||
echo $PATH > path | ||
if [ ! -z $MODULESHOME ]; then echo $MODULESHOME > moduleshome; fi | ||
- name: install Apptainer | ||
run: | | ||
curl -OL https://github.com/apptainer/apptainer/releases/download/v${{matrix.apptainer}}/apptainer_${{matrix.apptainer}}_amd64.deb | ||
sudo apt install ./apptainer*.deb | ||
# Apptainer provides both apptainer and singularity commands | ||
apptainer --version | ||
singularity --version | ||
- name: install sources | ||
run: | | ||
# install from source distribution tarball, to test release as published on PyPI | ||
python setup.py sdist | ||
ls dist | ||
export PREFIX=/tmp/$USER/$GITHUB_SHA | ||
pip install --prefix $PREFIX dist/easybuild-framework*tar.gz | ||
pip install --prefix $PREFIX https://github.com/easybuilders/easybuild-easyblocks/archive/develop.tar.gz | ||
- name: run test | ||
run: | | ||
# run tests *outside* of checked out easybuild-framework directory, | ||
# to ensure we're testing installed version (see previous step) | ||
cd $HOME | ||
# initialize environment for modules tool | ||
if [ -f $HOME/moduleshome ]; then export MODULESHOME=$(cat $HOME/moduleshome); fi | ||
source $(cat $HOME/mod_init); type module | ||
# make sure 'eb' is available via $PATH, and that $PYTHONPATH is set (some tests expect that); | ||
# also pick up changes to $PATH set by sourcing $MOD_INIT | ||
export PREFIX=/tmp/$USER/$GITHUB_SHA | ||
export PATH=$PREFIX/bin:$(cat $HOME/path) | ||
export PYTHONPATH=$PREFIX/lib/python${{matrix.python}}/site-packages:$PYTHONPATH | ||
eb --version | ||
# create $HOME/.rpmmacros, see also https://github.com/apptainer/singularity/issues/241 | ||
echo '%_var /var' > $HOME/.rpmmacros | ||
echo '%_dbpath %{_var}/lib/rpm' >> $HOME/.rpmmacros | ||
# build CentOS 7 container image for bzip2 1.0.8 using EasyBuild; | ||
# see https://docs.easybuild.io/en/latest/Containers.html | ||
curl -OL https://raw.githubusercontent.com/easybuilders/easybuild-easyconfigs/develop/easybuild/easyconfigs/b/bzip2/bzip2-1.0.8.eb | ||
export EASYBUILD_CONTAINERPATH=$PWD | ||
export EASYBUILD_CONTAINER_CONFIG='bootstrap=docker,from=ghcr.io/easybuilders/centos-7.9-python3-amd64' | ||
export EASYBUILD_CONTAINER_TYPE='apptainer' | ||
eb bzip2-1.0.8.eb --containerize --experimental --container-build-image | ||
apptainer exec bzip2-1.0.8.sif command -v bzip2 | grep '/app/software/bzip2/1.0.8/bin/bzip2' || (echo "Path to bzip2 '$which_bzip2' is not correct" && exit 1) | ||
apptainer exec bzip2-1.0.8.sif bzip2 --help |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
# Copyright 2022-2023 Ghent University | ||
# | ||
# This file is part of EasyBuild, | ||
# originally created by the HPC team of Ghent University (http://ugent.be/hpc/en), | ||
# with support of Ghent University (http://ugent.be/hpc), | ||
# the Flemish Supercomputer Centre (VSC) (https://www.vscentrum.be), | ||
# Flemish Research Foundation (FWO) (http://www.fwo.be/en) | ||
# and the Department of Economy, Science and Innovation (EWI) (http://www.ewi-vlaanderen.be/en). | ||
# | ||
# https://github.com/easybuilders/easybuild | ||
# | ||
# EasyBuild is free software: you can redistribute it and/or modify | ||
# it under the terms of the GNU General Public License as published by | ||
# the Free Software Foundation v2. | ||
# | ||
# EasyBuild is distributed in the hope that it will be useful, | ||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
# GNU General Public License for more details. | ||
# | ||
# You should have received a copy of the GNU General Public License | ||
# along with EasyBuild. If not, see <http://www.gnu.org/licenses/>. | ||
# | ||
""" | ||
Support for generating Apptainer container recipes and creating container images | ||
:author: Kenneth Hoste (HPC-UGent) | ||
""" | ||
import os | ||
import re | ||
|
||
from easybuild.tools.build_log import EasyBuildError, print_msg | ||
from easybuild.tools.containers.singularity import SingularityContainer | ||
from easybuild.tools.config import CONT_IMAGE_FORMAT_EXT3, CONT_IMAGE_FORMAT_SANDBOX | ||
from easybuild.tools.config import CONT_IMAGE_FORMAT_SIF, CONT_IMAGE_FORMAT_SQUASHFS | ||
from easybuild.tools.config import build_option, container_path | ||
from easybuild.tools.filetools import remove_file, which | ||
from easybuild.tools.run import run_cmd | ||
|
||
|
||
class ApptainerContainer(SingularityContainer): | ||
|
||
TOOLS = {'apptainer': '1.0', 'sudo': None} | ||
|
||
RECIPE_FILE_NAME = 'Apptainer' | ||
|
||
@staticmethod | ||
def apptainer_version(): | ||
"""Get Apptainer version.""" | ||
version_cmd = "apptainer --version" | ||
out, ec = run_cmd(version_cmd, simple=False, trace=False, force_in_dry_run=True) | ||
if ec: | ||
raise EasyBuildError("Error running '%s': %s for tool {1} with output: {2}" % (version_cmd, out)) | ||
|
||
res = re.search(r"\d+\.\d+(\.\d+)?", out.strip()) | ||
if not res: | ||
raise EasyBuildError("Error parsing Apptainer version: %s" % out) | ||
|
||
return res.group(0) | ||
|
||
def build_image(self, recipe_path): | ||
"""Build container image by calling out to 'sudo apptainer build'.""" | ||
|
||
cont_path = container_path() | ||
def_file = os.path.basename(recipe_path) | ||
|
||
# use --imagename if specified, otherwise derive based on filename of recipe | ||
img_name = self.img_name | ||
if img_name is None: | ||
# definition file Apptainer.<app>-<version, container name <app>-<version>.<img|simg> | ||
img_name = def_file.split('.', 1)[1] | ||
|
||
cmd_opts = '' | ||
|
||
image_format = self.image_format | ||
|
||
# singularity image format (default for Apptainer) | ||
if image_format in [None, CONT_IMAGE_FORMAT_SQUASHFS, CONT_IMAGE_FORMAT_SIF]: | ||
img_path = os.path.join(cont_path, img_name + '.sif') | ||
|
||
# ext3 image format, creating as writable container | ||
elif image_format == CONT_IMAGE_FORMAT_EXT3: | ||
raise EasyBuildError("ext3 image format is not supported with Apptainer") | ||
|
||
# sandbox image format, creates as a directory but acts like a container | ||
elif image_format == CONT_IMAGE_FORMAT_SANDBOX: | ||
img_path = os.path.join(cont_path, img_name) | ||
cmd_opts = '--sandbox' | ||
|
||
else: | ||
raise EasyBuildError("Unknown container image format specified for Apptainer: %s" % image_format) | ||
|
||
if os.path.exists(img_path): | ||
if build_option('force'): | ||
print_msg("WARNING: overwriting existing container image at %s due to --force" % img_path) | ||
remove_file(img_path) | ||
else: | ||
raise EasyBuildError("Container image already exists at %s, not overwriting it without --force", | ||
img_path) | ||
|
||
# resolve full path to 'apptainer' binary, since it may not be available via $PATH under sudo... | ||
apptainer = which('apptainer') | ||
cmd_env = '' | ||
|
||
apptainer_tmpdir = self.tmpdir | ||
if apptainer_tmpdir: | ||
cmd_env += 'APPTAINER_TMPDIR=%s' % apptainer_tmpdir | ||
|
||
cmd = ' '.join(['sudo', cmd_env, apptainer, 'build', cmd_opts, img_path, recipe_path]) | ||
print_msg("Running '%s', you may need to enter your 'sudo' password..." % cmd) | ||
run_cmd(cmd, stream_output=True) | ||
print_msg("Apptainer image created at %s" % img_path, log=self.log) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters