summaryrefslogtreecommitdiff
path: root/var/spack/repos/builtin/packages/singularityce/package.py
blob: d995b07f8761ddd3e125114bf03d1a27b3f992d8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# Copyright 2013-2023 Lawrence Livermore National Security, LLC and other
# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)

import os
import shutil

import llnl.util.tty as tty

from spack.package import *


class SingularityBase(MakefilePackage):
    variant("suid", default=True, description="install SUID binary")
    variant("network", default=True, description="install network plugins")

    depends_on("pkgconfig", type="build")
    depends_on("conmon", type=("build", "run"))
    depends_on("squashfs", type=("build", "run"))
    depends_on("go@1.16:")
    depends_on("uuid")
    depends_on("libgpg-error")
    depends_on("libseccomp")
    depends_on("squashfs", type="run")
    depends_on("git", when="@develop")  # mconfig uses it for version info
    depends_on("shadow", type="run", when="@3.3:")
    depends_on("cryptsetup", type=("build", "run"), when="@3.4:")

    conflicts("platform=darwin", msg="singularity requires a Linux VM on Windows & Mac")

    # Use these properties to buffer the renaming to Apptainer
    singularity_org = "sylabs"
    singularity_name = "singularity"
    singularity_security_urls = (
        "https://sylabs.io/guides/2.6/admin-guide/security.html",
        "https://sylabs.io/guides/3.2/admin-guide/admin_quickstart.html#singularity-security",
    )

    # Go has novel ideas about how projects should be organized.
    # We'll point GOPATH at the stage dir, and move the unpacked src
    # tree into the proper subdir in our overridden do_stage below.
    @property
    def gopath(self):
        return self.stage.path

    @property
    def singularity_gopath_dir(self):
        return join_path(
            self.gopath, "src", "github.com", self.singularity_org, self.singularity_name
        )

    # Unpack the tarball as usual, then move the src dir into
    # its home within GOPATH.
    def do_stage(self, mirror_only=False):
        super().do_stage(mirror_only)
        if not os.path.exists(self.singularity_gopath_dir):
            # Move the expanded source to its destination
            tty.debug(
                "Moving {0} to {1}".format(self.stage.source_path, self.singularity_gopath_dir)
            )
            shutil.move(self.stage.source_path, self.singularity_gopath_dir)

            # The build process still needs access to the source path,
            # so create a symlink.
            force_symlink(self.singularity_gopath_dir, self.stage.source_path)

    # MakefilePackage's stages use this via working_dir()
    @property
    def build_directory(self):
        return self.singularity_gopath_dir

    # Allow overriding config options
    @property
    def config_options(self):
        # Using conmon from spack
        return ["--without-conmon"]

    # Hijack the edit stage to run mconfig.
    def edit(self, spec, prefix):
        with working_dir(self.build_directory):
            _config_options = ["--prefix=%s" % prefix]
            _config_options += self.config_options
            if "~suid" in spec:
                _config_options += ["--without-suid"]
            if "~network" in spec:
                _config_options += ["--without-network"]
            configure = Executable("./mconfig")
            configure(*_config_options)

    # Set these for use by MakefilePackage's default build/install methods.
    build_targets = ["-C", "builddir", "parallel=False"]
    install_targets = ["install", "-C", "builddir", "parallel=False"]

    def setup_build_environment(self, env):
        # Point GOPATH at the top of the staging dir for the build step.
        env.prepend_path("GOPATH", self.gopath)

    # `singularity` has a fixed path where it will look for
    # mksquashfs.  If it lives somewhere else you need to specify the
    # full path in the config file.  This bit uses filter_file to edit
    # the config file, uncommenting and setting the mksquashfs path.
    @run_after("install")
    def fix_mksquashfs_path(self):
        prefix = self.spec.prefix
        squash_path = join_path(self.spec["squashfs"].prefix.bin, "mksquashfs")
        filter_file(
            r"^# mksquashfs path =",
            "mksquashfs path = {0}".format(squash_path),
            join_path(prefix.etc, self.singularity_name, self.singularity_name + ".conf"),
        )

    #
    # Assemble a script that fixes the ownership and permissions of several
    # key files, install it, and tty.warn() the user.
    # HEADSUP: https://github.com/spack/spack/pull/10412.
    #
    def perm_script(self):
        return "spack_perms_fix.sh"

    def perm_script_tmpl(self):
        return "{0}.j2".format(self.perm_script())

    def perm_script_path(self):
        return join_path(self.spec.prefix.bin, self.perm_script())

    def _build_script(self, filename, variable_data):
        with open(filename, "w") as f:
            env = spack.tengine.make_environment(dirs=self.package_dir)
            t = env.get_template(self.perm_script_tmpl())
            f.write(t.render(variable_data))

    @run_after("install")
    def build_perms_script(self):
        if self.spec.satisfies("+suid"):
            script = self.perm_script_path()
            chown_files = [
                fn.format(self.singularity_name)
                for fn in [
                    "libexec/{0}/bin/starter-suid",
                    "etc/{0}/{0}.conf",
                    "etc/{0}/capability.json",
                    "etc/{0}/ecl.toml",
                ]
            ]
            setuid_files = ["libexec/{0}/bin/starter-suid".format(self.singularity_name)]
            self._build_script(
                script,
                {
                    "prefix": self.spec.prefix,
                    "chown_files": chown_files,
                    "setuid_files": setuid_files,
                },
            )
            chmod = which("chmod")
            chmod("555", script)

    # Until tty output works better from build steps, this ends up in
    # the build log.  See https://github.com/spack/spack/pull/10412.
    @run_after("install")
    def caveats(self):
        if self.spec.satisfies("+suid"):
            tty.warn(
                """
            For full functionality, you'll need to chown and chmod some files
            after installing the package.  This has security implications.
            For details, see:
            {1}
            {2}

            We've installed a script that will make the necessary changes;
            read through it and then execute it as root (e.g. via sudo).

            The script is named:

            {0}
            """.format(
                    self.perm_script_path(), *self.singularity_security_urls
                )
            )


class Singularityce(SingularityBase):
    """Singularity is a container technology focused on building portable
    encapsulated environments to support "Mobility of Compute" For older
    versions of Singularity (pre 3.0) you should use singularity-legacy,
    which has a different install base (Autotools).

    Needs post-install chmod/chown steps to enable full functionality.
    See package definition or `spack-build-out.txt` build log for details,
    e.g.

    tail -15 $(spack location -i singularityce)/.spack/spack-build-out.txt
    """

    homepage = "https://sylabs.io/singularity/"
    url = "https://github.com/sylabs/singularity/releases/download/v3.9.1/singularity-ce-3.9.1.tar.gz"
    git = "https://github.com/sylabs/singularity.git"

    license("Apache-2.0")

    maintainers("alalazo")
    version("master", branch="master")

    version("3.11.3", sha256="a77ede063fd115f85f98f82d2e30459b5565db7d098665497bcd684bf8edaec9")
    version("3.10.3", sha256="f87d8e212ce209c5212d6faf253b97a24b5d0b6e6b17b5e58b316cdda27a332f")
    version("3.10.2", sha256="b4f279856ea4bf28a1f34f89320c02b545d6e57d4143679920e1ac4267f540e1")
    version("3.10.1", sha256="e3af12edc0260bc3a3a481459a3a4457de9235025e6b37288da80e3cdc011a7a")
    version("3.10.0", sha256="5e22e6cdad66c331668f6cff4544c83917bb3db90da3cf92403a394c5bf8cc8f")
    version("3.9.9", sha256="1381433d64138c08e93ffacdfb4844e82c2288f1e39a9d2c631a1c4021381f2a")
    version("3.9.1", sha256="1ba3bb1719a420f48e9b0a6afdb5011f6c786d0f107ef272528c632fff9fd153")
    version("3.8.0", sha256="5fa2c0e7ef2b814d8aa170826b833f91e5031a85d85cd1292a234e6c55da1be1")