blob: 6f832345392b25def55d3f30bc612545cfb8d8ef [file] [log] [blame]
#
# 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)