Пример #1
0
class BuildEnv (object):
    def __init__(self, xml, path, build_sources=False, clean=False, arch="default"):

        # pylint: disable=too-many-arguments

        self.xml = xml
        self.path = path
        self.rpcaptcache = None
        self.arch = arch

        self.rfs = BuildImgFs(path, xml.defs["userinterpr"])

        if clean:
            self.rfs.rmtree("")

        # TODO think about reinitialization if elbe_version differs
        if not self.rfs.isfile("etc/elbe_version"):
            # avoid starting daemons inside the buildenv
            self.rfs.mkdir_p("usr/sbin")
            # grub-legacy postinst will fail if /boot/grub does not exist
            self.rfs.mkdir_p("boot/grub")
            self.rfs.write_file(
                "usr/sbin/policy-rc.d",
                0o755,
                "#!/bin/sh\nexit 101\n")
            self.debootstrap(arch)
            self.fresh_debootstrap = True
            self.need_dumpdebootstrap = True
        else:
            self.fresh_debootstrap = False
            self.need_dumpdebootstrap = False

        self.initialize_dirs(build_sources=build_sources)
        create_apt_prefs(self.xml, self.rfs)

    def cdrom_umount(self):
        if self.xml.prj.has("mirror/cdrom"):
            cdrompath = self.rfs.fname("cdrom")
            do('umount "%s"' % cdrompath)
            do("rm -f %s/etc/apt/trusted.gpg.d/elbe-cdrepo.gpg" %
               self.path)
            do("rm -f %s/etc/apt/trusted.gpg.d/elbe-cdtargetrepo.gpg" %
               self.path)

    def cdrom_mount(self):
        if self.xml.has("project/mirror/cdrom"):
            cdrompath = self.rfs.fname("cdrom")
            do('mkdir -p "%s"' % cdrompath)
            do('mount -o loop "%s" "%s"' %
               (self.xml.text("project/mirror/cdrom"), cdrompath))

    def __enter__(self):
        if os.path.exists(self.path + '/../repo/pool'):
            do("mv %s/../repo %s" % (self.path, self.path))
            do('echo "deb copy:///repo %s main" > '
               '%s/etc/apt/sources.list.d/local.list' %
               (self.xml.text("project/suite"), self.path))
            do('echo "deb-src copy:///repo %s main" >> '
               '%s/etc/apt/sources.list.d/local.list' %
               (self.xml.text("project/suite"), self.path))

        self.cdrom_mount()
        self.rfs.__enter__()

        if self.xml.has("project/mirror/cdrom"):
            chroot(self.rfs.path,
                   'apt-key '
                   '--keyring /etc/apt/trusted.gpg.d/elbe-cdrepo.gpg '
                   'add /cdrom/repo.pub')
            chroot(self.rfs.path,
                   'apt-key '
                   '--keyring /etc/apt/trusted.gpg.d/elbe-cdtargetrepo.gpg '
                   'add /cdrom/targetrepo/repo.pub')

        if os.path.exists(os.path.join(self.rfs.path, 'repo/pool')):
            chroot(self.rfs.path,
                   'apt-key '
                   '--keyring /etc/apt/trusted.gpg.d/elbe-localrepo.gpg '
                   'add /repo/repo.pub')
        return self

    def __exit__(self, typ, value, traceback):
        self.rfs.__exit__(typ, value, traceback)
        self.cdrom_umount()
        if os.path.exists(self.path + '/repo'):
            do("mv %s/repo %s/../" % (self.path, self.path))
            do("rm %s/etc/apt/sources.list.d/local.list" % self.path)
            do("rm %s/etc/apt/trusted.gpg.d/elbe-localrepo.gpg" % self.path)

    def debootstrap(self, arch="default"):

        # pylint: disable=too-many-statements
        # pylint: disable=too-many-branches

        cleanup = False
        suite = self.xml.prj.text("suite")

        primary_mirror = self.xml.get_primary_mirror(
            self.rfs.fname('/cdrom/targetrepo'))

        if self.xml.prj.has("mirror/primary_proxy"):
            os.environ["no_proxy"] = "10.0.2.2,localhost,127.0.0.1"
            proxy = self.xml.prj.text("mirror/primary_proxy")
            proxy = proxy.strip().replace("LOCALMACHINE", "localhost")
            os.environ["http_proxy"] = proxy
            os.environ["https_proxy"] = proxy
        else:
            os.environ["no_proxy"] = ""
            os.environ["http_proxy"] = ""
            os.environ["https_proxy"] = ""

        os.environ["LANG"] = "C"
        os.environ["LANGUAGE"] = "C"
        os.environ["LC_ALL"] = "C"
        os.environ["DEBIAN_FRONTEND"] = "noninteractive"
        os.environ["DEBONF_NONINTERACTIVE_SEEN"] = "true"

        logging.info("Debootstrap log")

        if arch == "default":
            arch = self.xml.text("project/buildimage/arch", key="arch")

        host_arch = get_command_out("dpkg --print-architecture").strip().decode()

        includepkgs = None
        strapcmd  = 'debootstrap '
        if self.xml.has("target/debootstrapvariant"):
            bootstrapvariant = self.xml.text("target/debootstrapvariant")
            includepkgs = self.xml.node("target/debootstrapvariant").et.get("includepkgs")
            strapcmd += '--variant="%s" ' % bootstrapvariant

        if includepkgs and not "gnupg" in includepkgs.split(','):
            includepkgs += ",gnupg"
        if not includepkgs:
            includepkgs = "gnupg"

        strapcmd += ' --include="%s"' % includepkgs

        if not self.xml.is_cross(host_arch):
            # ignore gpg verification if install from cdrom, cause debootstrap
            # seems to ignore /etc/apt/trusted.gpg.d/elbe-keyring.gpg
            # 01/2017 manut
            if self.xml.has(
                    "project/noauth") or self.xml.has("project/mirror/cdrom"):
                cmd = '%s --no-check-gpg --arch=%s "%s" "%s" "%s"' % (
                    strapcmd, arch, suite, self.rfs.path, primary_mirror)
            else:
                cmd = '%s --arch=%s "%s" "%s" "%s"' % (
                    strapcmd, arch, suite, self.rfs.path, primary_mirror)

            try:
                self.cdrom_mount()
                do(cmd)
            except CommandError:
                cleanup = True
                raise DebootstrapException()
            finally:
                self.cdrom_umount()
                if cleanup:
                    self.rfs.rmtree("/")

            return

        if self.xml.has("project/noauth"):
            cmd = '%s --no-check-gpg --foreign --arch=%s "%s" "%s" "%s"' % (
                strapcmd, arch, suite, self.rfs.path, primary_mirror)
        else:
            if self.xml.has("project/mirror/cdrom"):
                keyring = ' --keyring="%s/targetrepo/elbe-keyring.gpg"' % (
                    self.rfs.fname("cdrom"))
            else:
                keyring = ''

            cmd = '%s --foreign --arch=%s %s "%s" "%s" "%s"' % (
                strapcmd, arch, keyring, suite, self.rfs.path, primary_mirror)

        try:
            self.cdrom_mount()
            do(cmd)

            ui = "/usr/share/elbe/qemu-elbe/" + self.xml.defs["userinterpr"]

            if not os.path.exists(ui):
                ui = "/usr/bin/" + self.xml.defs["userinterpr"]

            do('cp %s %s' % (ui, self.rfs.fname("usr/bin")))

            if self.xml.has("project/noauth"):
                chroot(self.rfs.path,
                       '/debootstrap/debootstrap --no-check-gpg --second-stage')
            else:
                chroot(self.rfs.path,
                       '/debootstrap/debootstrap --second-stage')

            chroot(self.rfs.path, 'dpkg --configure -a')

        except CommandError:
            cleanup = True
            raise DebootstrapException()
        finally:
            self.cdrom_umount()
            if cleanup:
                self.rfs.rmtree("/")

    def virtapt_init_dirs(self):
        self.rfs.mkdir_p("/cache/archives/partial")
        self.rfs.mkdir_p("/etc/apt/preferences.d")
        self.rfs.mkdir_p("/db")
        self.rfs.mkdir_p("/log")
        self.rfs.mkdir_p("/state/lists/partial")
        self.rfs.touch_file("/state/status")

    def add_key(self, key):
        cmd = 'echo "%s" > %s' % (key, self.rfs.fname("tmp/key.pub"))
        clean = 'rm -f %s' % self.rfs.fname("tmp/key.pub")
        do(cmd)
        with self.rfs:
            chroot(self.rfs.path, 'apt-key add /tmp/key.pub')
        do(clean)

    def import_keys(self):
        if self.xml.has('project/mirror/url-list'):
            # Should we use self.xml.prj.has("noauth")???
            #
            # If so, this is related to issue #220 -
            # https://github.com/Linutronix/elbe/issues/220
            #
            # I could make a none global 'noauth' flag for mirrors
            for url in self.xml.node('project/mirror/url-list'):
                if url.has('raw-key'):
                    key = "\n".join(line.strip(" \t") for line in url.text('raw-key').splitlines()[1:-1])
                    self.add_key(key)

    def initialize_dirs(self, build_sources=False):
        mirror = self.xml.create_apt_sources_list(build_sources=build_sources)

        if self.rfs.lexists("etc/apt/sources.list"):
            self.rfs.remove("etc/apt/sources.list")

        self.rfs.write_file("etc/apt/sources.list", 0o644, mirror)

        self.rfs.mkdir_p("var/cache/elbe")

        preseed = get_preseed(self.xml)
        preseed_txt = preseed_to_text(preseed)
        self.rfs.write_file("var/cache/elbe/preseed.txt", 0o644, preseed_txt)
        with self.rfs:
            cmd = ('debconf-set-selections < %s' %
                   self.rfs.fname("var/cache/elbe/preseed.txt"))
            chroot(self.rfs.path, cmd)


    def seed_etc(self):
        passwd = self.xml.text("target/passwd").encode(encoding='utf-8')
        stdin = "%s\n%s\n" % (passwd, passwd)
        chroot(self.rfs.path, "passwd", stdin=stdin)

        hostname = self.xml.text("target/hostname")
        fqdn = hostname
        if self.xml.has("target/domain"):
            fqdn = ("%s.%s" % (hostname, self.xml.text("target/domain")))

        chroot(self.rfs.path,
               """/bin/sh -c 'echo "127.0.1.1 %s %s elbe-daemon" >> """
               """/etc/hosts'""" % (fqdn,hostname))

        chroot(self.rfs.path,
               """/bin/sh -c 'echo "%s" > /etc/hostname'""" % hostname)

        chroot(self.rfs.path,
               """/bin/sh -c 'echo "%s" > """
               """/etc/mailname'""" % (fqdn))

        if self.xml.has("target/console"):
            serial_con, serial_baud = self.xml.text(
                "target/console").split(',')
            if serial_baud:
                chroot(self.rfs.path,
                       """/bin/sh -c '[ -f /etc/inittab ] && """
                       """echo "T0:23:respawn:/sbin/getty -L %s %s vt100" >> """
                       """/etc/inittab'""" % (serial_con, serial_baud),
                       allow_fail=True)

                chroot(self.rfs.path,
                       """/bin/sh -c """
                       """'[ -f /lib/systemd/system/[email protected] ] && """
                       """ln -s /lib/systemd/system/[email protected] """
                       """/etc/systemd/system/getty.target.wants/"""
                       """serial-getty@%s.service'""" % serial_con,
                       allow_fail=True)
            else:
                logging.error("parsing console tag failed, needs to be of "
                              "'/dev/ttyS0,115200' format.")