Source code for dockeroo.docker.gentoo_bootstrap


# -*- coding: utf-8 -*-
#
# Copyright (c) 2016, Giacomo Cariello. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


from zc.buildout import UserError

from dockeroo import BaseGroupRecipe
from dockeroo.docker import BaseDockerSubRecipe, Archive
from dockeroo.utils import merge, string_as_bool


class DockerGentooBootstrapSubRecipe(BaseDockerSubRecipe): # pylint: disable=too-many-instance-attributes

    def initialize(self):
        super(DockerGentooBootstrapSubRecipe, self).initialize()
        if ':' not in self.name:
            self.name += ':latest'

        self.command = self.options.get("command", "/bin/freeze")
        self.commit = string_as_bool(self.options.get('commit', False))
        self.container = self.options.get('container',
                                          "{}_bootstrap".format(self.name.replace(':', '_')))
        self.keep = string_as_bool(self.options.get('keep', False))
        self.layout = self.options.get('layout', None)
        self.crossdev_platform = self.options.get(
            'crossdev-platform', self.engine.platform)
        self.build_shell = self.options.get('build-shell', self.shell)
        self.build_script = "#!{}\n{}".format(
            self.build_shell,
            '\n'.join([_f for _f in
                       [x.strip() for x in
                        self.options.get('build-script').replace('$$', '$').splitlines()]
                       if _f])) \
            if self.options.get('build-script', None) is not None else None
        self.tty = string_as_bool(self.options.get('tty', False))
        self.archives = []
        for url, prefix, md5sum in [merge([None, None, None], x.split())[:3] for x in
                                    [_f for _f in
                                     [x.strip() for x in
                                      self.options.get(
                                          'archives', self.options.get('archive', '')).splitlines()]
                                     if _f]]:
            if prefix == '/':
                prefix = None
            self.archives.append(
                Archive(url=url, prefix=prefix, md5sum=md5sum))
        self.volumes = [y for y in [x.strip().split(
            ':', 1) for x in self.options.get('volumes', '').splitlines()] if y[0]]
        self.volumes_from = self.options.get('volumes-from', None)

    def install(self):
        if not any([x for x in self.engine.images() if self.name == x['image']]):
            if not self.archives:
                raise UserError(
                    "Image does not exist and no source specified.")
            for archive in self.archives:
                archive.download(self.recipe.buildout)
            self.engine.import_archives(self.name, *self.archives)

        if not self.engine.containers(include_stopped=True, name=self.container):
            self.engine.create_container(self.container,
                                         self.name, command=self.command,
                                         privileged=True, tty=self.tty, volumes=self.volumes,
                                         volumes_from=self.volumes_from)
        # else:
        #    raise RuntimeError("Container \"{}\" already exists".format(self.container))

        self.engine.install_freeze(self.container)

        if self.layout:
            self.engine.load_layout(self.container, self.layout)

        self.engine.start_container(self.container)

        if self.build_script:
            if self.crossdev_platform != self.engine.platform:
                self.engine.config_binfmt(self.container, self.crossdev_platform)
            self.engine.run_script(self.container, self.build_script)

        if self.commit:
            self.engine.commit_container(self.container, self.name)
            self.engine.remove_container(self.container)
            self.engine.clean_stale_images()

        return self.mark_completed()

    def update(self):
        if (self.layout and self.is_layout_updated(self.layout)) or \
            not next(self.engine.images(name=self.name), None):
            return self.install()
        return self.mark_completed()

    def uninstall(self):
        self.engine.remove_container(self.container)
        if not self.keep:
            self.engine.remove_image(self.name)


[docs]class DockerGentooBootstrapRecipe(BaseGroupRecipe): """ This recipe creates a docker image that contains a full operating system (typically Gentoo). Such builder image can be used to create further docker images with :py:class:`dockeroo.docker.gentoo_build.DockerGentooBuildRecipe` recipe. The recipe executes the following tasks: 1. Extract **archives** into a docker image. 2. Create a container from such image. 3. Install "freeze" binary into the container. This is a simple no-op binary executable. 4. If a **layout** is defined, copy layout contents onto container's root. 5. Execute **build-script**. 6. If **commit** is enabled, commit modifications of image. .. describe:: Usage The following example buildout part shows how to build a full Gentoo amd64 docker image. .. code-block:: ini [crossdev_builder.img] crossdev-arch = x86_64 crossdev-platform = x86_64 crossdev-processor = x86_64 crossdev-variant = docker crossdev-abi = gnu crossdev-gentoo-profile = no-multilib crossdev-gentoo-platform = amd64 crossdev-gentoo-platform-flavor = amd64 recipe = dockeroo:docker.gentoo-bootstrap image = dockeroo/builder_${:crossdev-arch}:latest container = dockeroo_builder_${:crossdev-arch} volumes-from = ${distfiles:container} gentoo-platform = amd64 gentoo-platform-flavor = amd64-nomultilib gentoo-version = 20160414 archives = http://distfiles.gentoo.org/releases/${:gentoo-platform}/autobuilds/${:gentoo-version}/stage3-${:gentoo-platform-flavor}-${:gentoo-version}.tar.bz2 commit = true keep = true layout = ${buildout:containers-directory}/builder_${:crossdev-arch} build-script = test -d /usr/portage/profiles || emerge-webrsync emerge --sync emerge -uDNvkb world emerge -nNuvkb sys-devel/crossdev test -e /usr/${:crossdev-processor}-${:crossdev-variant}-linux-${:crossdev-abi}/.crossdev || \ crossdev -S -v -t ${:crossdev-processor}-${:crossdev-variant}-linux-${:crossdev-abi} --ov-output /usr/local/portage-crossdev-${:crossdev-arch} -P -kb && \ touch /usr/${:crossdev-processor}-${:crossdev-variant}-linux-${:crossdev-abi}/.crossdev (cd /usr/${:crossdev-processor}-${:crossdev-variant}-linux-${:crossdev-abi}/etc/portage && \ rm -f make.profile && ln -s /usr/portage/profiles/default/linux/${:crossdev-gentoo-platform}/13.0/${:crossdev-gentoo-profile} make.profile) ROOT=/usr/${:crossdev-processor}-${:crossdev-variant}-linux-${:crossdev-abi} \ ${:crossdev-processor}-${:crossdev-variant}-linux-${:crossdev-abi}-emerge -nuvkb1 --keep-going sys-apps/baselayout ROOT=/usr/${:crossdev-processor}-${:crossdev-variant}-linux-${:crossdev-abi} \ ${:crossdev-processor}-${:crossdev-variant}-linux-${:crossdev-abi}-emerge -nuvkb1 --keep-going $(egrep '^[a-z]+' /usr/portage/profiles/default/linux/packages.build) ROOT=/usr/${:crossdev-processor}-${:crossdev-variant}-linux-${:crossdev-abi} \ ${:crossdev-processor}-${:crossdev-variant}-linux-${:crossdev-abi}-emerge -nuvkb1 --keep-going sys-apps/portage sys-apps/openrc net-misc/netifrc app-portage/gentoolkit chroot-${:crossdev-arch}-docker -c locale-gen chroot-${:crossdev-arch}-docker -c env-update To use the above part, several other files are necessary, to be copied in via **layout**:: /etc/locale.gen /etc/portage/repos.conf/crossdev.conf /etc/portage/repos.conf/local.conf /usr/local/bin/chroot-x86_64-docker /usr/local/portage-crossdev-x86_64/metadata/layout.conf /usr/local/portage-crossdev-x86_64/profiles/repo_name /usr/x86_64-docker-linux-gnu/dockeroo-root/.keep /usr/x86_64-docker-linux-gnu/etc/bash/bashrc.d/emerge-chroot /usr/x86_64-docker-linux-gnu/etc/locale.gen /usr/x86_64-docker-linux-gnu/etc/portage/make.conf Here's an example of chroot-x86_64-docker script, useful to build docker images with :py:class:`dockeroo.docker.gentoo_build.DockerGentooBuildRecipe` recipe: .. code-block:: bash #!/bin/sh cd /usr/x86_64-docker-linux-gnu set -e mkdir -p dev proc sys tmp etc/portage/repos.conf usr/portage usr/local/portage-crossdev-x86_64/packages var/lib/layman mount -o bind /dev dev mount -o bind /dev/pts dev/pts mount -o bind /dev/shm dev/shm mount -o bind /etc/portage/repos.conf etc/portage/repos.conf mount -o bind /proc proc mount -o bind /sys sys mount -o bind /tmp tmp mount -o bind /usr/portage usr/portage mount -o bind /usr/portage/distfiles usr/portage/distfiles mount -o bind /usr/local/portage-crossdev-x86_64 usr/local/portage-crossdev-x86_64 mount -o bind /usr/local/portage-crossdev-x86_64/packages usr/local/portage-crossdev-x86_64/packages mount -o bind /var/lib/layman var/lib/layman cp /etc/resolv.conf etc/resolv.conf set +e chroot . /bin/bash --login "$@" ret=$? set -e umount var/lib/layman umount usr/local/portage-crossdev-x86_64/packages umount usr/local/portage-crossdev-x86_64 umount usr/portage/distfiles umount usr/portage umount tmp umount sys umount proc umount etc/portage/repos.conf umount dev/shm umount dev/pts umount dev set +e exit $ret .. describe:: Configuration options archives List of URLs of operating system initial filesystem contents (Gentoo stageX). crossdev-platform Name of destination platform. If enabled, allows automatic configuration of QEMU binfmt mapping. command Command to execute upon container starting. Defaults to "/bin/freeze". commit Commit image changes after recipe install execution. Defaults to false. container Name of build container. keep Don't delete image upon uninstall. layout Copies a local folder to container's root with **docker cp**. machine-name Docker machine where **build-image** and **base-image** reside. Defaults to DOCKER_MACHINE_NAME environment variable or "default" if unset. name Name of destination image. Defaults to part name. build-script Execute this script after extraction of archives filesystem and import of layout. timeout **docker** command timeout. tty Assign a **Pseudo-TTY** to the container. volumes Volumes to bind mount, one per line. Format is <path>:<mountpoint>. volumes-from Mount volumes from specified container. """ subrecipe_class = DockerGentooBootstrapSubRecipe