summaryrefslogtreecommitdiff
path: root/lib/spack/spack/container/__init__.py
blob: 988849d5f2eb1c15dbe3e7720ef29de6d99282c3 (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
# 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)
"""Package that provides functions and classes to
generate container recipes from a Spack environment
"""
import warnings

import spack.environment as ev
import spack.schema.env as env
import spack.util.spack_yaml as syaml

from .writers import recipe

__all__ = ["validate", "recipe"]


def validate(configuration_file):
    """Validate a Spack environment YAML file that is being used to generate a
    recipe for a container.

    Since a few attributes of the configuration must have specific values for
    the container recipe, this function returns a sanitized copy of the
    configuration in the input file. If any modification is needed, a warning
    will be issued.

    Args:
        configuration_file (str): path to the Spack environment YAML file

    Returns:
        A sanitized copy of the configuration stored in the input file
    """
    import jsonschema

    with open(configuration_file) as f:
        config = syaml.load(f)

    # Ensure we have a "container" attribute with sensible defaults set
    env_dict = config[ev.TOP_LEVEL_KEY]
    env_dict.setdefault(
        "container", {"format": "docker", "images": {"os": "ubuntu:22.04", "spack": "develop"}}
    )
    env_dict["container"].setdefault("format", "docker")
    env_dict["container"].setdefault("images", {"os": "ubuntu:22.04", "spack": "develop"})

    # Remove attributes that are not needed / allowed in the
    # container recipe
    for subsection in ("cdash", "gitlab_ci", "modules"):
        if subsection in env_dict:
            msg = (
                'the subsection "{0}" in "{1}" is not used when generating'
                " container recipes and will be discarded"
            )
            warnings.warn(msg.format(subsection, configuration_file))
            env_dict.pop(subsection)

    # Set the default value of the concretization strategy to unify and
    # warn if the user explicitly set another value
    env_dict.setdefault("concretizer", {"unify": True})
    if not env_dict["concretizer"]["unify"] is True:
        warnings.warn(
            '"concretizer:unify" is not set to "true", which means the '
            "generated image may contain different variants of the same "
            'packages. Set to "true" to get a consistent set of packages.'
        )

    # Check if the install tree was explicitly set to a custom value and warn
    # that it will be overridden
    environment_config = env_dict.get("config", {})
    if environment_config.get("install_tree", None):
        msg = (
            'the "config:install_tree" attribute has been set explicitly '
            "and will be overridden in the container image"
        )
        warnings.warn(msg)

    # Likewise for the view
    environment_view = env_dict.get("view", None)
    if environment_view:
        msg = (
            'the "view" attribute has been set explicitly '
            "and will be overridden in the container image"
        )
        warnings.warn(msg)

    jsonschema.validate(config, schema=env.schema)
    return config