summaryrefslogtreecommitdiff
path: root/src/buildstream/sandbox/_config.py
blob: 6f832345392b25def55d3f30bc612545cfb8d8ef (plain)
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
#
#  Copyright (C) 2020 Codethink Limited
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU Lesser General Public
#  License as published by the Free Software Foundation; either
#  version 2 of the License, or (at your option) any later version.
#
#  This library 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
#  Lesser General Public License for more details.
#
#  You should have received a copy of the GNU Lesser General Public
#  License along with this library. If not, see <http://www.gnu.org/licenses/>.
#
#  Authors:
#        Jim MacArthur <jim.macarthur@codethink.co.uk>
#        Tristan Van Berkom <tristan.vanberkom@codethink.co.uk>
#

from typing import TYPE_CHECKING, Dict, Optional, Union
from .._platform import Platform

if TYPE_CHECKING:
    from ..node import Node, MappingNode


# SandboxConfig
#
# The Sandbox configuration parameters, this object carries configuration
# required to instantiate the correct type of sandbox, and assert that
# the local or remote worker sandbox has the capabilities required.
#
# Args:
#    build_os: The build OS name
#    build_arch: A canonical machine architecture name, as defined by Platform.canonicalize_arch()
#    build_uid: The UID for the sandbox process
#    build_gid: The GID for the sandbox process
#
# If the build_uid or build_gid is unspecified, then the underlying sandbox implementation
# does not guarantee what UID/GID will be used, but generally UID/GID 0 will be used in a
# sandbox implementation which supports UID/GID control.
#
# If the build_uid or build_gid is specified, then the UID/GID is guaranteed to match
# the specified UID/GID, if the underlying sandbox implementation does not support UID/GID
# control, then an error will be raised when attempting to configure the sandbox.
#
class SandboxConfig:
    def __init__(
        self, *, build_os: str, build_arch: str, build_uid: Optional[int] = None, build_gid: Optional[int] = None
    ):
        self.build_os = build_os
        self.build_arch = build_arch
        self.build_uid = build_uid
        self.build_gid = build_gid

    # to_dict():
    #
    # Represent the SandboxConfig as a dictionary.
    #
    # This dictionary will be stored in the corresponding artifact
    # whenever an artifact is cached. When loading an element from
    # an artifact, then this dict will be loaded as a MappingNode
    # and interpreted by SandboxConfig.new_from_node().
    #
    # This function is also used to contribute to the owning element's cache key.
    #
    # Returns:
    #    A dictionary representation of this SandboxConfig
    #
    def to_dict(self) -> Dict[str, Union[str, int]]:

        # Assign mandatory portions of the sandbox configuration
        #
        # /!\ No additional mandatory members can ever be added to
        #     the sandbox configuration, as that would result in
        #     breaking cache key stability.
        #
        sandbox_dict: Dict[str, Union[str, int]] = {"build-os": self.build_os, "build-arch": self.build_arch}

        # Assign optional portions of the sandbox configuration
        #
        # /!\ In order to preserve cache key stability, these attributes
        #     are only ever added to the dictionary if they have been
        #     explicitly set, unset values must not affect the dictionary.
        #
        if self.build_uid is not None:
            sandbox_dict["build-uid"] = self.build_uid
        if self.build_gid is not None:
            sandbox_dict["build-gid"] = self.build_gid

        return sandbox_dict

    # new_from_node():
    #
    # Instantiate a new SandboxConfig from YAML configuration.
    #
    # If the Platform is specified, then we expect to be loading
    # from project definitions, and some defaults will be derived
    # from the Platform. Otherwise, we expect to be loading from
    # a cached artifact, and values are expected to exist on the
    # given node.
    #
    # Args:
    #    config: The YAML configuration node
    #    platform: The host Platform instance, or None
    #
    # Returns:
    #    A new SandboxConfig instance
    #
    @classmethod
    def new_from_node(cls, config: "MappingNode[Node]", *, platform: Optional[Platform] = None) -> "SandboxConfig":
        config.validate_keys(["build-uid", "build-gid", "build-os", "build-arch"])

        build_os: str
        build_arch: str

        if platform:
            tmp = config.get_str("build-os", None)
            if tmp:
                build_os = tmp.lower()
            else:
                build_os = platform.get_host_os()

            tmp = config.get_str("build-arch", None)
            if tmp:
                build_arch = Platform.canonicalize_arch(tmp)
            else:
                build_arch = platform.get_host_arch()
        else:
            build_os = config.get_str("build-os")
            build_arch = config.get_str("build-arch")

        build_uid = config.get_int("build-uid", None)
        build_gid = config.get_int("build-gid", None)

        return cls(build_os=build_os, build_arch=build_arch, build_uid=build_uid, build_gid=build_gid)