diff --git a/mock/py/mockbuild/buildroot.py b/mock/py/mockbuild/buildroot.py index 2cb3eaf5a..b495a90e6 100644 --- a/mock/py/mockbuild/buildroot.py +++ b/mock/py/mockbuild/buildroot.py @@ -21,10 +21,10 @@ from . import uid from . import util from .exception import (BuildRootLocked, Error, ResultDirNotAccessible, - BadCmdline, BootstrapError) + BadCmdline, BootstrapError, RootError) from .package_manager import package_manager from .trace_decorator import getLog, traceLog -from .podman import Podman +from .podman import Podman, PodmanError from .shadow_utils import ShadowUtils @@ -110,8 +110,8 @@ def __init__(self, config, uid_manager, state, plugins, bootstrap_buildroot=None self.env.update(proxy_env) os.environ.update(proxy_env) - self.use_bootstrap_image = self.config['use_bootstrap_image'] - self.bootstrap_image = self.config['bootstrap_image'] + self.use_chroot_image = self.config['use_bootstrap_image'] + self.chroot_image = self.config['bootstrap_image'] self.pkg_manager = None self.mounts = mounts.Mounts(self) @@ -246,7 +246,7 @@ def _load_from_container_image(self): getLog().info( "It seems that you run Mock in a Docker container. Mock " "though uses container tooling itself (namely Podman) for " - "downloading bootstrap image. This might require you to " + "downloading container image. This might require you to " "run Mock in 'docker run --privileged'.") class _FallbackException(Exception): @@ -256,25 +256,26 @@ class _FallbackException(Exception): def _fallback(message): try: yield - except BootstrapError as exc: + except PodmanError as exc: if not self.config["image_fallback"]: - raise + err = BootstrapError if self.is_bootstrap else RootError + raise err from exc raise _FallbackException( - f"{message}, falling back to bootstrap installation: {exc}" + f"{message}, falling back to chroot installation: {exc}" ) from exc try: with _fallback("Can't work with Podman"): - podman = Podman(self, self.bootstrap_image) + podman = Podman(self, self.chroot_image) - with _fallback("Can't initialize from bootstrap image"): + with _fallback("Can't initialize from container image"): if not self.config["image_skip_pull"]: podman.retry_image_pull(self.config["image_keep_getting"]) else: getLog().info("Using local image %s (pull skipped)", - self.bootstrap_image) + self.chroot_image) - if self.config["hermetic_build"]: + if self.is_bootstrap and self.config["hermetic_build"]: tarball = os.path.join(self.config["offline_local_repository"], "bootstrap.tar") podman.import_tarball(tarball) @@ -289,12 +290,15 @@ def _fallback(message): f"Expected digest for image {podman.image} is" f"{digest_expected}, but {digest} found.") + if self.is_bootstrap and not podman.check_native_image_architecture(): + raise BootstrapError("Container image architecture check failed") + podman.cp(self.make_chroot_path(), self.config["tar_binary"]) file_util.unlink_if_exists(os.path.join(self.make_chroot_path(), "etc/rpm/macros.image-language-conf")) except _FallbackException as exc: getLog().warning("%s", exc) - self.use_bootstrap_image = False + self.use_chroot_image = False @traceLog() @@ -1063,7 +1067,7 @@ def delete(self): @property def uses_bootstrap_image(self): - return self.is_bootstrap and self.use_bootstrap_image + return self.is_bootstrap and self.use_chroot_image @property def bootstrap_image_is_ready(self): diff --git a/mock/py/mockbuild/package_manager.py b/mock/py/mockbuild/package_manager.py index fa3001dd6..f88b3e6a5 100644 --- a/mock/py/mockbuild/package_manager.py +++ b/mock/py/mockbuild/package_manager.py @@ -202,7 +202,7 @@ def _do(comment, *args, **kwargs): # We want to know the package versions in bootstrap if self.bootstrap_buildroot: - if self.bootstrap_buildroot.use_bootstrap_image: + if self.bootstrap_buildroot.use_chroot_image: # rpm installed from the bootstrap image _do("downloaded with a bootstrap image", cmd, chrootPath=self.bootstrap_buildroot.make_chroot_path()) diff --git a/mock/py/mockbuild/podman.py b/mock/py/mockbuild/podman.py index 7b96c3c6a..b13fb87f7 100644 --- a/mock/py/mockbuild/podman.py +++ b/mock/py/mockbuild/podman.py @@ -9,7 +9,12 @@ import backoff from mockbuild.trace_decorator import getLog, traceLog from mockbuild import util -from mockbuild.exception import BootstrapError + + +class PodmanError(Exception): + """ + Exception raised by mockbuild.podman.Podman + """ def podman_check_native_image_architecture(image, logger=None, podman_binary=None): @@ -51,12 +56,12 @@ class Podman: def __init__(self, buildroot, image): self.podman_binary = "/usr/bin/podman" if not os.path.exists(self.podman_binary): - raise BootstrapError(f"'{self.podman_binary}' not installed") + raise PodmanError(f"'{self.podman_binary}' not installed") self.buildroot = buildroot self.image = image self.container_id = None - getLog().info("Using bootstrap image: %s", image) + getLog().info("Using container image: %s", image) @traceLog() def pull_image(self): @@ -74,7 +79,7 @@ def import_tarball(self, tarball): """ Import tarball using podman into the local database. """ - getLog().info("Loading bootstrap image from %s", tarball) + getLog().info("Loading container image from %s", tarball) cmd = [self.podman_binary, "load", "-i", tarball] util.do_with_status(cmd, env=self.buildroot.env) @@ -91,7 +96,7 @@ def mounted_image(self): """ Using the "podman image mount" command, mount the image as a temporary read-only directory so we can copy-paste the contents into the final - bootstrap chroot directory. + chroot directory. """ logger = getLog() cmd_mount = [self.podman_binary, "image", "mount", self.image] @@ -101,7 +106,7 @@ def mounted_image(self): encoding="utf8") if result.returncode: message = "Podman mount failed: " + result.stderr - raise BootstrapError(message) + raise PodmanError(message) mountpoint = result.stdout.strip() logger.info("mounting %s with podman image mount", self.image) @@ -124,27 +129,30 @@ def get_image_digest(self): stderr=subprocess.PIPE, check=False, encoding="utf8") if result.returncode: - raise BootstrapError(f"Can't get {self.image} podman image digest: {result.stderr}") + raise PodmanError(f"Can't get {self.image} podman image digest: {result.stderr}") result = result.stdout.strip() if len(result.splitlines()) != 1: - raise BootstrapError(f"The digest of {self.image} image is not a single-line string") + raise PodmanError(f"The digest of {self.image} image is not a single-line string") return result + def check_native_image_architecture(self): + """ + Check that self.image has been generated for the current + host's architecture. + """ + return podman_check_native_image_architecture(self.image, getLog()) + @traceLog() def cp(self, destination, tar_cmd): """ copy content of container to destination directory """ - logger = getLog() - logger.info("Copy content of container %s to %s", self.image, destination) - - if not podman_check_native_image_architecture(self.image, logger): - raise BootstrapError("Container image architecture check failed") + getLog().info("Copy content of container %s to %s", self.image, destination) with self.mounted_image() as mount_path: # pipe-out the temporary mountpoint with the help of tar utility cmd_podman = [tar_cmd, "-C", mount_path, "-c", "."] with subprocess.Popen(cmd_podman, stdout=subprocess.PIPE) as podman: # read the tarball from stdin, and extract to the destination - # directory (bootstrap chroot directory) + # directory (chroot directory) cmd_tar = [tar_cmd, "-xC", destination, "-f", "-"] with subprocess.Popen(cmd_tar, stdin=podman.stdout) as tar: tar.communicate()