Exemple #1
0
    def _mount_instroot(self, base_on = None):
        parts = self._get_parts()
        self.__instloop = PartitionedMount(self._instroot)

        for p in parts:
            self.__instloop.add_partition(int(p.size),
                                          p.disk,
                                          p.mountpoint,
                                          p.fstype,
                                          p.label,
                                          fsopts = p.fsopts,
                                          boot = p.active,
                                          align = p.align,
                                          part_type = p.part_type)

        self.__instloop.layout_partitions(self._ptable_format)

        # Create the disks
        self.__imgdir = self._mkdtemp()
        for disk_name, disk in self.__instloop.disks.items():
            full_path = self._full_path(self.__imgdir, disk_name, "raw")
            msger.debug("Adding disk %s as %s with size %s bytes" \
                        % (disk_name, full_path, disk['min_size']))

            disk_obj = fs_related.SparseLoopbackDisk(full_path,
                                                     disk['min_size'])
            self.__disks[disk_name] = disk_obj
            self.__instloop.add_disk(disk_name, disk_obj)

        self.__instloop.mount()
        self._create_mkinitrd_config()
Exemple #2
0
    def _mount_instroot(self, base_on=None):
        self.__imgdir = self._mkdtemp()

        parts = self._get_parts()

        #create disk
        for item in self.get_diskinfo():
            msger.debug("Adding disk %s as %s/%s-%s.raw" %
                        (item['name'], self.__imgdir, self.name, item['name']))
            disk = fs_related.SparseLoopbackDisk(
                "%s/%s-%s.raw" % (self.__imgdir, self.name, item['name']),
                item['size'])
            self.__disks[item['name']] = disk

        self.__instloop = PartitionedMount(self.__disks, self._instroot)

        for p in parts:
            self.__instloop.add_partition(int(p.size),
                                          p.disk,
                                          p.mountpoint,
                                          p.fstype,
                                          fsopts=p.fsopts,
                                          boot=p.active)

        self.__instloop.mount()
        self._create_mkinitrd_config()
Exemple #3
0
    def do_unpack(cls, srcimg):
        srcimgsize = (misc.get_file_size(srcimg)) * 1024L * 1024L
        srcmnt = misc.mkdtemp("srcmnt")
        disk = fs_related.SparseLoopbackDisk(srcimg, srcimgsize)
        srcloop = PartitionedMount({'/dev/sdb': disk}, srcmnt, skipformat=True)

        srcloop.add_partition(srcimgsize / 1024 / 1024,
                              "/dev/sdb",
                              "/",
                              "ext3",
                              boot=False)
        try:
            srcloop.mount()

        except errors.MountError:
            srcloop.cleanup()
            raise

        image = os.path.join(tempfile.mkdtemp(dir="/var/tmp", prefix="tmp"),
                             "target.img")
        args = [
            'dd',
            "if=%s" % srcloop.partitions[0]['device'],
            "of=%s" % image
        ]

        msger.info("`dd` image ...")
        rc = runner.show(args)
        srcloop.cleanup()
        shutil.rmtree(os.path.dirname(srcmnt), ignore_errors=True)

        if rc != 0:
            raise errors.CreatorError("Failed to dd")
        else:
            return image
Exemple #4
0
    def do_unpack(cls, srcimg):
        srcimgsize = (misc.get_file_size(srcimg)) * 1024L * 1024L
        srcmnt = misc.mkdtemp("srcmnt")
        disk = fs_related.SparseLoopbackDisk(srcimg, srcimgsize)
        srcloop = PartitionedMount({'/dev/sdb':disk}, srcmnt, skipformat = True)

        srcloop.add_partition(srcimgsize/1024/1024, "/dev/sdb", "/", "ext3", boot=False)
        try:
            srcloop.mount()

        except errors.MountError:
            srcloop.cleanup()
            raise

        image = os.path.join(tempfile.mkdtemp(dir = "/var/tmp", prefix = "tmp"), "target.img")
        args = ['dd', "if=%s" % srcloop.partitions[0]['device'], "of=%s" % image]

        msger.info("`dd` image ...")
        rc = runner.show(args)
        srcloop.cleanup()
        shutil.rmtree(os.path.dirname(srcmnt), ignore_errors = True)

        if rc != 0:
            raise errors.CreatorError("Failed to dd")
        else:
            return image
Exemple #5
0
    def do_unpack(cls, srcimg):
        img = srcimg
        imgsize = misc.get_file_size(img) * 1024L * 1024L
        imgmnt = misc.mkdtemp()
        disk = fs_related.SparseLoopbackDisk(img, imgsize)
        imgloop = PartitionedMount({'/dev/sdb': disk}, imgmnt, skipformat=True)
        imgloop.add_partition(imgsize / 1024 / 1024,
                              "/dev/sdb",
                              "/",
                              "vfat",
                              boot=False)
        try:
            imgloop.mount()
        except errors.MountError:
            imgloop.cleanup()
            raise

        # legacy LiveOS filesystem layout support, remove for F9 or F10
        if os.path.exists(imgmnt + "/squashfs.img"):
            squashimg = imgmnt + "/squashfs.img"
        else:
            squashimg = imgmnt + "/LiveOS/squashfs.img"

        tmpoutdir = misc.mkdtemp()
        # unsquashfs requires outdir mustn't exist
        shutil.rmtree(tmpoutdir, ignore_errors=True)
        misc.uncompress_squashfs(squashimg, tmpoutdir)

        try:
            # legacy LiveOS filesystem layout support, remove for F9 or F10
            if os.path.exists(tmpoutdir + "/os.img"):
                os_image = tmpoutdir + "/os.img"
            else:
                os_image = tmpoutdir + "/LiveOS/ext3fs.img"

            if not os.path.exists(os_image):
                raise errors.CreatorError(
                    "'%s' is not a valid live CD ISO : neither "
                    "LiveOS/ext3fs.img nor os.img exist" % img)
            imgname = os.path.basename(srcimg)
            imgname = os.path.splitext(imgname)[0] + ".img"
            rtimage = os.path.join(
                tempfile.mkdtemp(dir="/var/tmp", prefix="tmp"), imgname)
            shutil.copyfile(os_image, rtimage)

        finally:
            imgloop.cleanup()
            shutil.rmtree(tmpoutdir, ignore_errors=True)
            shutil.rmtree(imgmnt, ignore_errors=True)

        return rtimage
Exemple #6
0
    def _mount_instroot(self, base_on = None):
        parts = self._get_parts()
        self.__instloop = PartitionedMount(self._instroot)

        for p in parts:
            self.__instloop.add_partition(int(p.size),
                                          p.disk,
                                          p.mountpoint,
                                          p.fstype,
                                          p.label,
                                          fsopts = p.fsopts,
                                          boot = p.active,
                                          align = p.align,
                                          part_type = p.part_type)

        self.__instloop.layout_partitions(self._ptable_format)

        # Create the disks
        self.__imgdir = self._mkdtemp()
        for disk_name, disk in self.__instloop.disks.items():
            full_path = self._full_path(self.__imgdir, disk_name, "raw")
            msger.debug("Adding disk %s as %s with size %s bytes" \
                        % (disk_name, full_path, disk['min_size']))

            disk_obj = fs_related.SparseLoopbackDisk(full_path,
                                                     disk['min_size'])
            self.__disks[disk_name] = disk_obj
            self.__instloop.add_disk(disk_name, disk_obj)

        self.__instloop.mount()
        self._create_mkinitrd_config()
Exemple #7
0
Fichier : raw.py Projet : lbt/mic
    def _mount_instroot(self, base_on = None):
        self.__imgdir = self._mkdtemp()

        parts = self._get_parts()

        #create disk
        for item in self.get_diskinfo():
            msger.debug("Adding disk %s as %s/%s-%s.raw with size %s bytes" %
                        (item['name'], self.__imgdir, self.name, item['name'],
                         item['size']))

            disk = fs_related.SparseLoopbackDisk("%s/%s-%s.raw" % (
                                                                self.__imgdir,
                                                                self.name,
                                                                item['name']),
                                                 item['size'])
            self.__disks[item['name']] = disk

        self.__instloop = PartitionedMount(self.__disks, self._instroot)

        for p in parts:
            self.__instloop.add_partition(int(p.size),
                                          p.disk,
                                          p.mountpoint,
                                          p.fstype,
                                          fsopts = p.fsopts,
                                          boot = p.active,
                                          align = p.align)

        self.__instloop.mount()
        self._create_mkinitrd_config()
Exemple #8
0
    def do_unpack(cls, srcimg):
        img = srcimg
        imgsize = misc.get_file_size(img) * 1024L * 1024L
        imgmnt = misc.mkdtemp()
        disk = fs_related.SparseLoopbackDisk(img, imgsize)
        imgloop = PartitionedMount({"/dev/sdb": disk}, imgmnt, skipformat=True)
        imgloop.add_partition(imgsize / 1024 / 1024, "/dev/sdb", "/", "vfat", boot=False)
        try:
            imgloop.mount()
        except errors.MountError:
            imgloop.cleanup()
            raise

        # legacy LiveOS filesystem layout support, remove for F9 or F10
        if os.path.exists(imgmnt + "/squashfs.img"):
            squashimg = imgmnt + "/squashfs.img"
        else:
            squashimg = imgmnt + "/LiveOS/squashfs.img"

        tmpoutdir = misc.mkdtemp()
        # unsquashfs requires outdir mustn't exist
        shutil.rmtree(tmpoutdir, ignore_errors=True)
        misc.uncompress_squashfs(squashimg, tmpoutdir)

        try:
            # legacy LiveOS filesystem layout support, remove for F9 or F10
            if os.path.exists(tmpoutdir + "/os.img"):
                os_image = tmpoutdir + "/os.img"
            else:
                os_image = tmpoutdir + "/LiveOS/ext3fs.img"

            if not os.path.exists(os_image):
                raise errors.CreatorError(
                    "'%s' is not a valid live CD ISO : neither " "LiveOS/ext3fs.img nor os.img exist" % img
                )
            imgname = os.path.basename(srcimg)
            imgname = os.path.splitext(imgname)[0] + ".img"
            rtimage = os.path.join(tempfile.mkdtemp(dir="/var/tmp", prefix="tmp"), imgname)
            shutil.copyfile(os_image, rtimage)

        finally:
            imgloop.cleanup()
            shutil.rmtree(tmpoutdir, ignore_errors=True)
            shutil.rmtree(imgmnt, ignore_errors=True)

        return rtimage
Exemple #9
0
    def _mount_instroot(self, base_on = None):
        self.__imgdir = self._mkdtemp()

        #Set a default partition if no partition is given out
        if not self.ks.handler.partition.partitions:
            partstr = "part / --size 1900 --ondisk sda --fstype=ext3"
            args = partstr.split()
            pd = self.ks.handler.partition.parse(args[1:])
            if pd not in self.ks.handler.partition.partitions:
                self.ks.handler.partition.partitions.append(pd)

        #list of partitions from kickstart file
        parts = kickstart.get_partitions(self.ks)

        #list of disks where a disk is an dict with name: and size
        disks = []

        for i in range(len(parts)):
            if parts[i].disk:
                disk = parts[i].disk
            else:
                raise CreatorError("Failed to create disks, no --ondisk specified in partition line of ks file")

            if not parts[i].fstype:
                 raise CreatorError("Failed to create disks, no --fstype specified in partition line of ks file")

            size =   parts[i].size * 1024L * 1024L

            found = False
            for j in range(len(disks)):
                if disks[j]['name'] == disk:
                    disks[j]['size'] = disks[j]['size'] + size
                    found = True
                    break
                else:
                    found = False
            if not found:
                disks.append({ 'name': disk, 'size': size })

        #create disk
        for item in disks:
            msger.debug("Adding disk %s as %s/%s-%s.raw" % (item['name'], self.__imgdir,self.name, item['name']))
            disk = fs_related.SparseLoopbackDisk("%s/%s-%s.raw" % (self.__imgdir,self.name, item['name']),item['size'])
            self.__disks[item['name']] = disk

        self.__instloop = PartitionedMount(self.__disks, self._instroot)

        for p in parts:
            self.__instloop.add_partition(int(p.size), p.disk, p.mountpoint, p.fstype, fsopts = p.fsopts, boot = p.active)

        self.__instloop.mount()
        self._create_mkinitrd_config()
Exemple #10
0
class RawImageCreator(BaseImageCreator):
    """Installs a system into a file containing a partitioned disk image.

    ApplianceImageCreator is an advanced ImageCreator subclass; a sparse file
    is formatted with a partition table, each partition loopback mounted
    and the system installed into an virtual disk. The disk image can
    subsequently be booted in a virtual machine or accessed with kpartx
    """
    def __init__(self, *args):
        """Initialize a ApplianceImageCreator instance.

            This method takes the same arguments as ImageCreator.__init__()
        """
        BaseImageCreator.__init__(self, *args)

        self.__instloop = None
        self.__imgdir = None
        self.__disks = {}
        self.__disk_format = "raw"
        self._diskinfo = []
        self.vmem = 512
        self.vcpu = 1
        self.checksum = False
        self.appliance_version = None
        self.appliance_release = None
        #self.getsource = False
        #self.listpkg = False

        self._dep_checks.extend(["sync", "kpartx", "parted", "extlinux"])

    def configure(self, repodata=None):
        import subprocess

        def chroot():
            os.chroot(self._instroot)
            os.chdir("/")

        if os.path.exists(self._instroot + "/usr/bin/Xorg"):
            subprocess.call(["/bin/chmod", "u+s", "/usr/bin/Xorg"],
                            preexec_fn=chroot)

        BaseImageCreator.configure(self, repodata)

    def _get_fstab(self):
        s = ""
        for mp in self.__instloop.mountOrder:
            p = None
            for p1 in self.__instloop.partitions:
                if p1['mountpoint'] == mp:
                    p = p1
                    break

            s += "%(device)s  %(mountpoint)s  %(fstype)s  %(fsopts)s 0 0\n" % {
                'device': "/dev/%s%-d" % (p['disk'], p['num']),
                'mountpoint': p['mountpoint'],
                'fstype': p['fstype'],
                'fsopts':
                "defaults,noatime" if not p['fsopts'] else p['fsopts']
            }

            if p['mountpoint'] == "/":
                for subvol in self.__instloop.subvolumes:
                    if subvol['mountpoint'] == "/":
                        continue
                    s += "%(device)s  %(mountpoint)s  %(fstype)s  %(fsopts)s 0 0\n" % {
                        'device':
                        "/dev/%s%-d" % (p['disk'], p['num']),
                        'mountpoint':
                        subvol['mountpoint'],
                        'fstype':
                        p['fstype'],
                        'fsopts':
                        "defaults,noatime"
                        if not subvol['fsopts'] else subvol['fsopts']
                    }

        s += "devpts     /dev/pts  devpts  gid=5,mode=620   0 0\n"
        s += "tmpfs      /dev/shm  tmpfs   defaults         0 0\n"
        s += "proc       /proc     proc    defaults         0 0\n"
        s += "sysfs      /sys      sysfs   defaults         0 0\n"
        return s

    def _create_mkinitrd_config(self):
        #write  to tell which modules to be included in initrd

        mkinitrd = ""
        mkinitrd += "PROBE=\"no\"\n"
        mkinitrd += "MODULES+=\"ext3 ata_piix sd_mod libata scsi_mod\"\n"
        mkinitrd += "rootfs=\"ext3\"\n"
        mkinitrd += "rootopts=\"defaults\"\n"

        msger.debug("Writing mkinitrd config %s/etc/sysconfig/mkinitrd" \
                    % self._instroot)
        os.makedirs(self._instroot + "/etc/sysconfig/", mode=644)
        cfg = open(self._instroot + "/etc/sysconfig/mkinitrd", "w")
        cfg.write(mkinitrd)
        cfg.close()

    def _get_parts(self):
        if not self.ks:
            raise CreatorError("Failed to get partition info, "
                               "please check your kickstart setting.")

        # Set a default partition if no partition is given out
        if not self.ks.handler.partition.partitions:
            partstr = "part / --size 1900 --ondisk sda --fstype=ext3"
            args = partstr.split()
            pd = self.ks.handler.partition.parse(args[1:])
            if pd not in self.ks.handler.partition.partitions:
                self.ks.handler.partition.partitions.append(pd)

        # partitions list from kickstart file
        return kickstart.get_partitions(self.ks)

    def get_diskinfo(self):

        if self._diskinfo:
            return self._diskinfo

        #get partition info from ks handler
        parts = self._get_parts()

        for i in range(len(parts)):
            if parts[i].disk:
                disk = parts[i].disk
            else:
                raise CreatorError("Failed to create disks, no --ondisk "
                                   "specified in partition line of ks file")

            if not parts[i].fstype:
                raise CreatorError("Failed to create disks, no --fstype "
                                   "specified in partition line of ks file")

            size = parts[i].size * 1024L * 1024L

            found = False
            for j in range(len(self._diskinfo)):
                if self._diskinfo[j]['name'] == disk:
                    self._diskinfo[j][
                        'size'] = self._diskinfo[j]['size'] + size
                    found = True
                    break
                else:
                    found = False

            if not found:
                self._diskinfo.append({'name': disk, 'size': size})

        return self._diskinfo

    #
    # Actual implemention
    #
    def _mount_instroot(self, base_on=None):
        self.__imgdir = self._mkdtemp()

        parts = self._get_parts()

        #create disk
        for item in self.get_diskinfo():
            msger.debug("Adding disk %s as %s/%s-%s.raw" %
                        (item['name'], self.__imgdir, self.name, item['name']))
            disk = fs_related.SparseLoopbackDisk(
                "%s/%s-%s.raw" % (self.__imgdir, self.name, item['name']),
                item['size'])
            self.__disks[item['name']] = disk

        self.__instloop = PartitionedMount(self.__disks, self._instroot)

        for p in parts:
            self.__instloop.add_partition(int(p.size),
                                          p.disk,
                                          p.mountpoint,
                                          p.fstype,
                                          fsopts=p.fsopts,
                                          boot=p.active)

        self.__instloop.mount()
        self._create_mkinitrd_config()

    def _get_required_packages(self):
        required_packages = BaseImageCreator._get_required_packages(self)
        if not self.target_arch or not self.target_arch.startswith("arm"):
            required_packages += ["syslinux", "syslinux-extlinux"]
        return required_packages

    def _get_excluded_packages(self):
        return BaseImageCreator._get_excluded_packages(self)

    def _get_syslinux_boot_config(self):
        bootdevnum = None
        rootdevnum = None
        rootdev = None
        for p in self.__instloop.partitions:
            if p['mountpoint'] == "/boot":
                bootdevnum = p['num'] - 1
            elif p['mountpoint'] == "/" and bootdevnum is None:
                bootdevnum = p['num'] - 1

            if p['mountpoint'] == "/":
                rootdevnum = p['num'] - 1
                rootdev = "/dev/%s%-d" % (p['disk'], p['num'])

        prefix = ""
        if bootdevnum == rootdevnum:
            prefix = "/boot"

        return (bootdevnum, rootdevnum, rootdev, prefix)

    def _create_syslinux_config(self):
        #Copy splash
        splash = "%s/usr/lib/anaconda-runtime/syslinux-vesa-splash.jpg" \
                 % self._instroot

        if os.path.exists(splash):
            shutil.copy(splash, "%s%s/splash.jpg" \
                                % (self._instroot, "/boot/extlinux"))
            splashline = "menu background splash.jpg"
        else:
            splashline = ""

        (bootdevnum, rootdevnum, rootdev, prefix) = \
                                            self._get_syslinux_boot_config()
        options = self.ks.handler.bootloader.appendLine

        #XXX don't hardcode default kernel - see livecd code
        syslinux_conf = ""
        syslinux_conf += "prompt 0\n"
        syslinux_conf += "timeout 1\n"
        syslinux_conf += "\n"
        syslinux_conf += "default vesamenu.c32\n"
        syslinux_conf += "menu autoboot Starting %s...\n" % self.distro_name
        syslinux_conf += "menu hidden\n"
        syslinux_conf += "\n"
        syslinux_conf += "%s\n" % splashline
        syslinux_conf += "menu title Welcome to %s!\n" % self.distro_name
        syslinux_conf += "menu color border 0 #ffffffff #00000000\n"
        syslinux_conf += "menu color sel 7 #ffffffff #ff000000\n"
        syslinux_conf += "menu color title 0 #ffffffff #00000000\n"
        syslinux_conf += "menu color tabmsg 0 #ffffffff #00000000\n"
        syslinux_conf += "menu color unsel 0 #ffffffff #00000000\n"
        syslinux_conf += "menu color hotsel 0 #ff000000 #ffffffff\n"
        syslinux_conf += "menu color hotkey 7 #ffffffff #ff000000\n"
        syslinux_conf += "menu color timeout_msg 0 #ffffffff #00000000\n"
        syslinux_conf += "menu color timeout 0 #ffffffff #00000000\n"
        syslinux_conf += "menu color cmdline 0 #ffffffff #00000000\n"

        versions = []
        kernels = self._get_kernel_versions()
        for kernel in kernels:
            for version in kernels[kernel]:
                versions.append(version)

        footlabel = 0
        for v in versions:
            shutil.copy(
                "%s/boot/vmlinuz-%s" % (self._instroot, v),
                "%s%s/vmlinuz-%s" % (self._instroot, "/boot/extlinux/", v))
            syslinux_conf += "label %s%d\n" \
                             % (self.distro_name.lower(), footlabel)
            syslinux_conf += "\tmenu label %s (%s)\n" % (self.distro_name, v)
            syslinux_conf += "\tkernel vmlinuz-%s\n" % v
            syslinux_conf += "\tappend ro root=%s quiet vga=current %s\n" \
                             % (rootdev, options)
            if footlabel == 0:
                syslinux_conf += "\tmenu default\n"
            footlabel += 1

        msger.debug("Writing syslinux config %s/boot/extlinux/extlinux.conf" \
                    % self._instroot)
        cfg = open(self._instroot + "/boot/extlinux/extlinux.conf", "w")
        cfg.write(syslinux_conf)
        cfg.close()

    def _install_syslinux(self):
        i = 0
        for name in self.__disks.keys():
            loopdev = self.__disks[name].device
            i = i + 1

        msger.debug("Installing syslinux bootloader to %s" % loopdev)

        (bootdevnum, rootdevnum, rootdev, prefix) = \
                                    self._get_syslinux_boot_config()

        #Set MBR
        mbrsize = os.stat("%s/usr/share/syslinux/mbr.bin" \
                          % self._instroot)[stat.ST_SIZE]
        rc = runner.show([
            'dd',
            'if=%s/usr/share/syslinux/mbr.bin' % self._instroot,
            'of=' + loopdev
        ])
        if rc != 0:
            raise MountError("Unable to set MBR to %s" % loopdev)

        #Set Bootable flag
        parted = fs_related.find_binary_path("parted")
        rc = runner.quiet([
            parted, "-s", loopdev, "set",
            "%d" % (bootdevnum + 1), "boot", "on"
        ])
        #XXX disabled return code check because parted always fails to
        #reload part table with loop devices. Annoying because we can't
        #distinguish this failure from real partition failures :-(
        if rc != 0 and 1 == 0:
            raise MountError("Unable to set bootable flag to %sp%d" \
                             % (loopdev, (bootdevnum + 1)))

        #Ensure all data is flushed to disk before doing syslinux install
        runner.quiet('sync')

        fullpathsyslinux = fs_related.find_binary_path("extlinux")
        rc = runner.show(
            [fullpathsyslinux, "-i",
             "%s/boot/extlinux" % self._instroot])
        if rc != 0:
            raise MountError("Unable to install syslinux bootloader to %sp%d" \
                             % (loopdev, (bootdevnum + 1)))

    def _create_bootconfig(self):
        #If syslinux is available do the required configurations.
        if os.path.exists("%s/usr/share/syslinux/" % (self._instroot)) \
           and os.path.exists("%s/boot/extlinux/" % (self._instroot)):
            self._create_syslinux_config()
            self._install_syslinux()

    def _unmount_instroot(self):
        if not self.__instloop is None:
            self.__instloop.cleanup()

    def _resparse(self, size=None):
        return self.__instloop.resparse(size)

    def _stage_final_image(self):
        """Stage the final system image in _outdir.
           write meta data
        """
        self._resparse()

        msger.debug("moving disks to stage location")
        for name in self.__disks.keys():
            src = "%s/%s-%s.raw" % (self.__imgdir, self.name, name)
            self._img_name = "%s-%s.%s" % (self.name, name, self.__disk_format)
            dst = "%s/%s" % (self._outdir, self._img_name)
            msger.debug("moving %s to %s" % (src, dst))
            shutil.move(src, dst)
        self._write_image_xml()

    def _write_image_xml(self):
        imgarch = "i686"
        if self.target_arch and self.target_arch.startswith("arm"):
            imgarch = "arm"
        xml = "<image>\n"

        name_attributes = ""
        if self.appliance_version:
            name_attributes += " version='%s'" % self.appliance_version
        if self.appliance_release:
            name_attributes += " release='%s'" % self.appliance_release
        xml += "  <name%s>%s</name>\n" % (name_attributes, self.name)
        xml += "  <domain>\n"
        # XXX don't hardcode - determine based on the kernel we installed for
        # grub baremetal vs xen
        xml += "    <boot type='hvm'>\n"
        xml += "      <guest>\n"
        xml += "        <arch>%s</arch>\n" % imgarch
        xml += "      </guest>\n"
        xml += "      <os>\n"
        xml += "        <loader dev='hd'/>\n"
        xml += "      </os>\n"

        i = 0
        for name in self.__disks.keys():
            xml += "      <drive disk='%s-%s.%s' target='hd%s'/>\n" \
                   % (self.name,name, self.__disk_format,chr(ord('a')+i))
            i = i + 1

        xml += "    </boot>\n"
        xml += "    <devices>\n"
        xml += "      <vcpu>%s</vcpu>\n" % self.vcpu
        xml += "      <memory>%d</memory>\n" % (self.vmem * 1024)
        for network in self.ks.handler.network.network:
            xml += "      <interface/>\n"
        xml += "      <graphics/>\n"
        xml += "    </devices>\n"
        xml += "  </domain>\n"
        xml += "  <storage>\n"

        if self.checksum is True:
            for name in self.__disks.keys():
                diskpath = "%s/%s-%s.%s" \
                           % (self._outdir,self.name,name, self.__disk_format)
                disk_size = os.path.getsize(diskpath)
                meter_ct = 0
                meter = progress.TextMeter()
                meter.start(size=disk_size,
                            text="Generating disk signature for %s-%s.%s" \
                                 % (self.name,
                                    name,
                                    self.__disk_format))
                xml += "    <disk file='%s-%s.%s' use='system' format='%s'>\n" \
                       % (self.name,
                          name,
                          self.__disk_format,
                          self.__disk_format)

                try:
                    import hashlib
                    m1 = hashlib.sha1()
                    m2 = hashlib.sha256()
                except:
                    import sha
                    m1 = sha.new()
                    m2 = None
                f = open(diskpath, "r")
                while 1:
                    chunk = f.read(65536)
                    if not chunk:
                        break
                    m1.update(chunk)
                    if m2:
                        m2.update(chunk)
                    meter.update(meter_ct)
                    meter_ct = meter_ct + 65536

                sha1checksum = m1.hexdigest()
                xml +=  "      <checksum type='sha1'>%s</checksum>\n" \
                        % sha1checksum

                if m2:
                    sha256checksum = m2.hexdigest()
                    xml += "      <checksum type='sha256'>%s</checksum>\n" \
                           % sha256checksum

                xml += "    </disk>\n"
        else:
            for name in self.__disks.keys():
                xml += "    <disk file='%s-%s.%s' use='system' format='%s'/>\n"\
                       %(self.name,
                         name,
                         self.__disk_format,
                         self.__disk_format)

        xml += "  </storage>\n"
        xml += "</image>\n"

        msger.debug("writing image XML to %s/%s.xml" %
                    (self._outdir, self.name))
        cfg = open("%s/%s.xml" % (self._outdir, self.name), "w")
        cfg.write(xml)
        cfg.close()
Exemple #11
0
class DirectImageCreator(BaseImageCreator):
    """
    Installs a system into a file containing a partitioned disk image.

    DirectImageCreator is an advanced ImageCreator subclass; an image
    file is formatted with a partition table, each partition created
    from a rootfs or other OpenEmbedded build artifact and dd'ed into
    the virtual disk. The disk image can subsequently be dd'ed onto
    media and used on actual hardware.
    """

    def __init__(self, oe_builddir, image_output_dir, rootfs_dir, bootimg_dir,
                 kernel_dir, native_sysroot, hdddir, staging_data_dir,
                 creatoropts=None, pkgmgr=None, compress_image=None,
                 generate_bmap=None, fstab_entry="uuid"):
        """
        Initialize a DirectImageCreator instance.

        This method takes the same arguments as ImageCreator.__init__()
        """
        BaseImageCreator.__init__(self, creatoropts, pkgmgr)

        self.__instimage = None
        self.__imgdir = None
        self.__disks = {}
        self.__disk_format = "direct"
        self._disk_names = []
        self._ptable_format = self.ks.handler.bootloader.ptable
        self.use_uuid = fstab_entry == "uuid"
        self.compress_image = compress_image
        self.bmap_needed = generate_bmap

        self.oe_builddir = oe_builddir
        if image_output_dir:
            self.tmpdir = image_output_dir
            self.cachedir = "%s/cache" % image_output_dir
        self.rootfs_dir = rootfs_dir
        self.bootimg_dir = bootimg_dir
        self.kernel_dir = kernel_dir
        self.native_sysroot = native_sysroot
        self.hdddir = hdddir
        self.staging_data_dir = staging_data_dir

    def __write_fstab(self, image_rootfs):
        """overriden to generate fstab (temporarily) in rootfs. This
        is called from mount_instroot, make sure it doesn't get called
        from BaseImage.mount()"""
        if image_rootfs is None:
            return None

        fstab = image_rootfs + "/etc/fstab"
        if not os.path.isfile(fstab):
            return None

        parts = self._get_parts()

        self._save_fstab(fstab)
        fstab_lines = self._get_fstab(fstab, parts)
        self._update_fstab(fstab_lines, parts)
        self._write_fstab(fstab, fstab_lines)

        return fstab

    def _update_fstab(self, fstab_lines, parts):
        """Assume partition order same as in wks"""
        for num, p in enumerate(parts, 1):
            if not p.mountpoint or p.mountpoint == "/" or p.mountpoint == "/boot":
                continue
            if self._ptable_format == 'msdos' and num > 3:
                device_name = "/dev/" + p.disk + str(num + 1)
            else:
                device_name = "/dev/" + p.disk + str(num)

            opts = "defaults"
            if p.fsopts:
                opts = p.fsopts

            fstab_entry = device_name + "\t" + \
                          p.mountpoint + "\t" + \
                          p.fstype + "\t" + \
                          opts + "\t0\t0\n"
            fstab_lines.append(fstab_entry)

    def _write_fstab(self, fstab, fstab_lines):
        fstab = open(fstab, "w")
        for line in fstab_lines:
            fstab.write(line)
        fstab.close()

    def _save_fstab(self, fstab):
        """Save the current fstab in rootfs"""
        shutil.copyfile(fstab, fstab + ".orig")

    def _restore_fstab(self, fstab):
        """Restore the saved fstab in rootfs"""
        if fstab is None:
            return
        shutil.move(fstab + ".orig", fstab)

    def _get_fstab(self, fstab, parts):
        """Return the desired contents of /etc/fstab."""
        f = open(fstab, "r")
        fstab_contents = f.readlines()
        f.close()

        return fstab_contents

    def set_bootimg_dir(self, bootimg_dir):
        """
        Accessor for bootimg_dir, the actual location used for the source
        of the bootimg.  Should be set by source plugins (only if they
        change the default bootimg source) so the correct info gets
        displayed for print_outimage_info().
        """
        self.bootimg_dir = bootimg_dir

    def _get_parts(self):
        if not self.ks:
            raise CreatorError("Failed to get partition info, "
                               "please check your kickstart setting.")

        # Set a default partition if no partition is given out
        if not self.ks.handler.partition.partitions:
            partstr = "part / --size 1900 --ondisk sda --fstype=ext3"
            args = partstr.split()
            pd = self.ks.handler.partition.parse(args[1:])
            if pd not in self.ks.handler.partition.partitions:
                self.ks.handler.partition.partitions.append(pd)

        # partitions list from kickstart file
        return kickstart.get_partitions(self.ks)

    def get_disk_names(self):
        """ Returns a list of physical target disk names (e.g., 'sdb') which
        will be created. """

        if self._disk_names:
            return self._disk_names

        #get partition info from ks handler
        parts = self._get_parts()

        for i in range(len(parts)):
            if parts[i].disk:
                disk_name = parts[i].disk
            else:
                raise CreatorError("Failed to create disks, no --ondisk "
                                   "specified in partition line of ks file")

            if parts[i].mountpoint and not parts[i].fstype:
                raise CreatorError("Failed to create disks, no --fstype "
                                    "specified for partition with mountpoint "
                                    "'%s' in the ks file")

            self._disk_names.append(disk_name)

        return self._disk_names

    def _full_name(self, name, extention):
        """ Construct full file name for a file we generate. """
        return "%s-%s.%s" % (self.name, name, extention)

    def _full_path(self, path, name, extention):
        """ Construct full file path to a file we generate. """
        return os.path.join(path, self._full_name(name, extention))

    def get_default_source_plugin(self):
        """
        The default source plugin i.e. the plugin that's consulted for
        overall image generation tasks outside of any particular
        partition.  For convenience, we just hang it off the
        bootloader handler since it's the one non-partition object in
        any setup.  By default the default plugin is set to the same
        plugin as the /boot partition; since we hang it off the
        bootloader object, the default can be explicitly set using the
        --source bootloader param.
        """
        return self.ks.handler.bootloader.source

    #
    # Actual implemention
    #
    def _mount_instroot(self, base_on = None):
        """
        For 'wic', we already have our build artifacts and don't want
        to loop mount anything to install into, we just create
        filesystems from the artifacts directly and combine them into
        a partitioned image.

        We still want to reuse as much of the basic mic machinery
        though; despite the fact that we don't actually do loop or any
        other kind of mounting we still want to do many of the same
        things to prepare images, so we basically just adapt to the
        basic framework and reinterpret what 'mounting' means in our
        context.

        _instroot would normally be something like
        /var/tmp/wic/build/imgcreate-s_9AKQ/install_root, for
        installing packages, etc.  We don't currently need to do that,
        so we simplify life by just using /var/tmp/wic/build as our
        workdir.
        """
        parts = self._get_parts()

        self.__instimage = PartitionedMount(self._instroot)

        for p in parts:
            # as a convenience, set source to the boot partition source
            # instead of forcing it to be set via bootloader --source
            if not self.ks.handler.bootloader.source and p.mountpoint == "/boot":
                self.ks.handler.bootloader.source = p.source

        for p in parts:
            # need to create the filesystems in order to get their
            # sizes before we can add them and do the layout.
            # PartitionedMount.mount() actually calls __format_disks()
            # to create the disk images and carve out the partitions,
            # then self.install() calls PartitionedMount.install()
            # which calls __install_partitition() for each partition
            # to dd the fs into the partitions.  It would be nice to
            # be able to use e.g. ExtDiskMount etc to create the
            # filesystems, since that's where existing e.g. mkfs code
            # is, but those are only created after __format_disks()
            # which needs the partition sizes so needs them created
            # before its called.  Well, the existing setup is geared
            # to installing packages into mounted filesystems - maybe
            # when/if we need to actually do package selection we
            # should modify things to use those objects, but for now
            # we can avoid that.

            fstab = self.__write_fstab(self.rootfs_dir.get("ROOTFS_DIR"))

            p.prepare(self, self.workdir, self.oe_builddir, self.rootfs_dir,
                      self.bootimg_dir, self.kernel_dir, self.native_sysroot)

            self._restore_fstab(fstab)

            self.__instimage.add_partition(int(p.size),
                                           p.disk,
                                           p.mountpoint,
                                           p.source_file,
                                           p.fstype,
                                           p.label,
                                           fsopts = p.fsopts,
                                           boot = p.active,
                                           align = p.align,
                                           part_type = p.part_type)

        self.__instimage.layout_partitions(self._ptable_format)

        self.__imgdir = self.workdir
        for disk_name, disk in self.__instimage.disks.items():
            full_path = self._full_path(self.__imgdir, disk_name, "direct")
            msger.debug("Adding disk %s as %s with size %s bytes" \
                        % (disk_name, full_path, disk['min_size']))
            disk_obj = fs_related.DiskImage(full_path, disk['min_size'])
            self.__disks[disk_name] = disk_obj
            self.__instimage.add_disk(disk_name, disk_obj)

        self.__instimage.mount()

    def install(self, repo_urls=None):
        """
        Install fs images into partitions
        """
        for disk_name, disk in self.__instimage.disks.items():
            full_path = self._full_path(self.__imgdir, disk_name, "direct")
            msger.debug("Installing disk %s as %s with size %s bytes" \
                        % (disk_name, full_path, disk['min_size']))
            self.__instimage.install(full_path)

    def configure(self, repodata = None):
        """
        Configure the system image according to kickstart.

        For now, it just prepares the image to be bootable by e.g.
        creating and installing a bootloader configuration.
        """
        source_plugin = self.get_default_source_plugin()
        if source_plugin:
            self._source_methods = pluginmgr.get_source_plugin_methods(source_plugin, disk_methods)
            for disk_name, disk in self.__instimage.disks.items():
                self._source_methods["do_install_disk"](disk, disk_name, self,
                                                        self.workdir,
                                                        self.oe_builddir,
                                                        self.bootimg_dir,
                                                        self.kernel_dir,
                                                        self.native_sysroot)

    def print_outimage_info(self):
        """
        Print the image(s) and artifacts used, for the user.
        """
        msg = "The new image(s) can be found here:\n"

        parts = self._get_parts()

        for disk_name, disk in self.__instimage.disks.items():
            full_path = self._full_path(self.__imgdir, disk_name, "direct")
            msg += '  %s\n\n' % full_path

        msg += 'The following build artifacts were used to create the image(s):\n'
        for p in parts:
            if p.get_rootfs() is None:
                continue
            if p.mountpoint == '/':
                str = ':'
            else:
                str = '["%s"]:' % p.label
            msg += '  ROOTFS_DIR%s%s\n' % (str.ljust(20), p.get_rootfs())

        msg += '  BOOTIMG_DIR:                  %s\n' % self.bootimg_dir
        msg += '  KERNEL_DIR:                   %s\n' % self.kernel_dir
        msg += '  NATIVE_SYSROOT:               %s\n' % self.native_sysroot

        msger.info(msg)

    def _get_boot_config(self):
        """
        Return the rootdev/root_part_uuid (if specified by
        --part-type)

        Assume partition order same as in wks
        """
        rootdev = None
        root_part_uuid = None
        parts = self._get_parts()
        for num, p in enumerate(parts, 1):
            if p.mountpoint == "/":
                part = ''
                if p.disk.startswith('mmcblk'):
                    part = 'p'

                if self._ptable_format == 'msdos' and num > 3:
                    rootdev = "/dev/%s%s%-d" % (p.disk, part, num + 1)
                else:
                    rootdev = "/dev/%s%s%-d" % (p.disk, part, num)
                root_part_uuid = p.part_type

        return (rootdev, root_part_uuid)

    def _unmount_instroot(self):
        if not self.__instimage is None:
            try:
                self.__instimage.cleanup()
            except MountError, err:
                msger.warning("%s" % err)
Exemple #12
0
    def _mount_instroot(self, base_on = None):
        """
        For 'wic', we already have our build artifacts and don't want
        to loop mount anything to install into, we just create
        filesystems from the artifacts directly and combine them into
        a partitioned image.

        We still want to reuse as much of the basic mic machinery
        though; despite the fact that we don't actually do loop or any
        other kind of mounting we still want to do many of the same
        things to prepare images, so we basically just adapt to the
        basic framework and reinterpret what 'mounting' means in our
        context.

        _instroot would normally be something like
        /var/tmp/wic/build/imgcreate-s_9AKQ/install_root, for
        installing packages, etc.  We don't currently need to do that,
        so we simplify life by just using /var/tmp/wic/build as our
        workdir.
        """
        parts = self._get_parts()

        self.__instimage = PartitionedMount(self._instroot)

        for p in parts:
            # as a convenience, set source to the boot partition source
            # instead of forcing it to be set via bootloader --source
            if not self.ks.handler.bootloader.source and p.mountpoint == "/boot":
                self.ks.handler.bootloader.source = p.source

        for p in parts:
            # need to create the filesystems in order to get their
            # sizes before we can add them and do the layout.
            # PartitionedMount.mount() actually calls __format_disks()
            # to create the disk images and carve out the partitions,
            # then self.install() calls PartitionedMount.install()
            # which calls __install_partitition() for each partition
            # to dd the fs into the partitions.  It would be nice to
            # be able to use e.g. ExtDiskMount etc to create the
            # filesystems, since that's where existing e.g. mkfs code
            # is, but those are only created after __format_disks()
            # which needs the partition sizes so needs them created
            # before its called.  Well, the existing setup is geared
            # to installing packages into mounted filesystems - maybe
            # when/if we need to actually do package selection we
            # should modify things to use those objects, but for now
            # we can avoid that.

            fstab = self.__write_fstab(self.rootfs_dir.get("ROOTFS_DIR"))

            p.prepare(self, self.workdir, self.oe_builddir, self.rootfs_dir,
                      self.bootimg_dir, self.kernel_dir, self.native_sysroot)

            self._restore_fstab(fstab)

            self.__instimage.add_partition(int(p.size),
                                           p.disk,
                                           p.mountpoint,
                                           p.source_file,
                                           p.fstype,
                                           p.label,
                                           fsopts = p.fsopts,
                                           boot = p.active,
                                           align = p.align,
                                           part_type = p.part_type)

        self.__instimage.layout_partitions(self._ptable_format)

        self.__imgdir = self.workdir
        for disk_name, disk in self.__instimage.disks.items():
            full_path = self._full_path(self.__imgdir, disk_name, "direct")
            msger.debug("Adding disk %s as %s with size %s bytes" \
                        % (disk_name, full_path, disk['min_size']))
            disk_obj = fs_related.DiskImage(full_path, disk['min_size'])
            self.__disks[disk_name] = disk_obj
            self.__instimage.add_disk(disk_name, disk_obj)

        self.__instimage.mount()
Exemple #13
0
class RawImageCreator(BaseImageCreator):
    """Installs a system into a file containing a partitioned disk image.

    ApplianceImageCreator is an advanced ImageCreator subclass; a sparse file
    is formatted with a partition table, each partition loopback mounted
    and the system installed into an virtual disk. The disk image can
    subsequently be booted in a virtual machine or accessed with kpartx
    """

    def __init__(self, creatoropts=None, pkgmgr=None, compress_image=None, generate_bmap=None, fstab_entry="uuid"):
        """Initialize a ApplianceImageCreator instance.

            This method takes the same arguments as ImageCreator.__init__()
        """
        BaseImageCreator.__init__(self, creatoropts, pkgmgr)

        self.__instloop = None
        self.__imgdir = None
        self.__disks = {}
        self.__disk_format = "raw"
        self._disk_names = []
        self._ptable_format = self.ks.handler.bootloader.ptable
        self.vmem = 512
        self.vcpu = 1
        self.checksum = False
        self.use_uuid = fstab_entry == "uuid"
        self.appliance_version = None
        self.appliance_release = None
        self.compress_image = compress_image
        self.bmap_needed = generate_bmap
        #self.getsource = False
        #self.listpkg = False

        self._dep_checks.extend(["sync", "kpartx", "parted", "extlinux"])

    def configure(self, repodata = None):
        import subprocess
        def chroot():
            os.chroot(self._instroot)
            os.chdir("/")

        if os.path.exists(self._instroot + "/usr/bin/Xorg"):
            subprocess.call(["/bin/chmod", "u+s", "/usr/bin/Xorg"],
                            preexec_fn = chroot)

        BaseImageCreator.configure(self, repodata)

    def _get_fstab(self):
        s = ""
        for mp in self.__instloop.mountOrder:
            p = None
            for p1 in self.__instloop.partitions:
                if p1['mountpoint'] == mp:
                    p = p1
                    break

            if self.use_uuid and p['uuid']:
                device = "UUID=%s" % p['uuid']
            else:
                device = "/dev/%s%-d" % (p['disk_name'], p['num'])

            s += "%(device)s  %(mountpoint)s  %(fstype)s  %(fsopts)s 0 0\n" % {
               'device': device,
               'mountpoint': p['mountpoint'],
               'fstype': p['fstype'],
               'fsopts': "defaults,noatime" if not p['fsopts'] else p['fsopts']}

            if p['mountpoint'] == "/":
                for subvol in self.__instloop.subvolumes:
                    if subvol['mountpoint'] == "/":
                        continue
                    s += "%(device)s  %(mountpoint)s  %(fstype)s  %(fsopts)s 0 0\n" % {
                         'device': "/dev/%s%-d" % (p['disk_name'], p['num']),
                         'mountpoint': subvol['mountpoint'],
                         'fstype': p['fstype'],
                         'fsopts': "defaults,noatime" if not subvol['fsopts'] else subvol['fsopts']}

        s += "devpts     /dev/pts  devpts  gid=5,mode=620   0 0\n"
        s += "tmpfs      /dev/shm  tmpfs   defaults         0 0\n"
        s += "proc       /proc     proc    defaults         0 0\n"
        s += "sysfs      /sys      sysfs   defaults         0 0\n"
        return s

    def _create_mkinitrd_config(self):
        """write to tell which modules to be included in initrd"""

        mkinitrd = ""
        mkinitrd += "PROBE=\"no\"\n"
        mkinitrd += "MODULES+=\"ext3 ata_piix sd_mod libata scsi_mod\"\n"
        mkinitrd += "rootfs=\"ext3\"\n"
        mkinitrd += "rootopts=\"defaults\"\n"

        msger.debug("Writing mkinitrd config %s/etc/sysconfig/mkinitrd" \
                    % self._instroot)
        os.makedirs(self._instroot + "/etc/sysconfig/",mode=644)
        cfg = open(self._instroot + "/etc/sysconfig/mkinitrd", "w")
        cfg.write(mkinitrd)
        cfg.close()

    def _get_parts(self):
        if not self.ks:
            raise CreatorError("Failed to get partition info, "
                               "please check your kickstart setting.")

        # Set a default partition if no partition is given out
        if not self.ks.handler.partition.partitions:
            partstr = "part / --size 1900 --ondisk sda --fstype=ext3"
            args = partstr.split()
            pd = self.ks.handler.partition.parse(args[1:])
            if pd not in self.ks.handler.partition.partitions:
                self.ks.handler.partition.partitions.append(pd)

        # partitions list from kickstart file
        return kickstart.get_partitions(self.ks)

    def get_disk_names(self):
        """ Returns a list of physical target disk names (e.g., 'sdb') which
        will be created. """

        if self._disk_names:
            return self._disk_names

        #get partition info from ks handler
        parts = self._get_parts()

        for i in range(len(parts)):
            if parts[i].disk:
                disk_name = parts[i].disk
            else:
                raise CreatorError("Failed to create disks, no --ondisk "
                                   "specified in partition line of ks file")

            if parts[i].mountpoint and not parts[i].fstype:
                raise CreatorError("Failed to create disks, no --fstype "
                                    "specified for partition with mountpoint "
                                    "'%s' in the ks file")

            self._disk_names.append(disk_name)

        return self._disk_names

    def _full_name(self, name, extention):
        """ Construct full file name for a file we generate. """
        return "%s-%s.%s" % (self.name, name, extention)

    def _full_path(self, path, name, extention):
        """ Construct full file path to a file we generate. """
        return os.path.join(path, self._full_name(name, extention))

    #
    # Actual implemention
    #
    def _mount_instroot(self, base_on = None):
        parts = self._get_parts()
        self.__instloop = PartitionedMount(self._instroot)

        for p in parts:
            self.__instloop.add_partition(int(p.size),
                                          p.disk,
                                          p.mountpoint,
                                          p.fstype,
                                          p.label,
                                          fsopts = p.fsopts,
                                          boot = p.active,
                                          align = p.align,
                                          part_type = p.part_type)

        self.__instloop.layout_partitions(self._ptable_format)

        # Create the disks
        self.__imgdir = self._mkdtemp()
        for disk_name, disk in self.__instloop.disks.items():
            full_path = self._full_path(self.__imgdir, disk_name, "raw")
            msger.debug("Adding disk %s as %s with size %s bytes" \
                        % (disk_name, full_path, disk['min_size']))

            disk_obj = fs_related.SparseLoopbackDisk(full_path,
                                                     disk['min_size'])
            self.__disks[disk_name] = disk_obj
            self.__instloop.add_disk(disk_name, disk_obj)

        self.__instloop.mount()
        self._create_mkinitrd_config()

    def _get_required_packages(self):
        required_packages = BaseImageCreator._get_required_packages(self)
        if not self.target_arch or not self.target_arch.startswith("arm"):
            required_packages += ["syslinux", "syslinux-extlinux"]
        return required_packages

    def _get_excluded_packages(self):
        return BaseImageCreator._get_excluded_packages(self)

    def _get_syslinux_boot_config(self):
        rootdev = None
        root_part_uuid = None
        for p in self.__instloop.partitions:
            if p['mountpoint'] == "/":
                rootdev = "/dev/%s%-d" % (p['disk_name'], p['num'])
                root_part_uuid = p['partuuid']

        return (rootdev, root_part_uuid)

    def _create_syslinux_config(self):

        splash = os.path.join(self._instroot, "boot/extlinux")
        if os.path.exists(splash):
            splashline = "menu background splash.jpg"
        else:
            splashline = ""

        (rootdev, root_part_uuid) = self._get_syslinux_boot_config()
        options = self.ks.handler.bootloader.appendLine

        #XXX don't hardcode default kernel - see livecd code
        syslinux_conf = ""
        syslinux_conf += "prompt 0\n"
        syslinux_conf += "timeout 1\n"
        syslinux_conf += "\n"
        syslinux_conf += "default vesamenu.c32\n"
        syslinux_conf += "menu autoboot Starting %s...\n" % self.distro_name
        syslinux_conf += "menu hidden\n"
        syslinux_conf += "\n"
        syslinux_conf += "%s\n" % splashline
        syslinux_conf += "menu title Welcome to %s!\n" % self.distro_name
        syslinux_conf += "menu color border 0 #ffffffff #00000000\n"
        syslinux_conf += "menu color sel 7 #ffffffff #ff000000\n"
        syslinux_conf += "menu color title 0 #ffffffff #00000000\n"
        syslinux_conf += "menu color tabmsg 0 #ffffffff #00000000\n"
        syslinux_conf += "menu color unsel 0 #ffffffff #00000000\n"
        syslinux_conf += "menu color hotsel 0 #ff000000 #ffffffff\n"
        syslinux_conf += "menu color hotkey 7 #ffffffff #ff000000\n"
        syslinux_conf += "menu color timeout_msg 0 #ffffffff #00000000\n"
        syslinux_conf += "menu color timeout 0 #ffffffff #00000000\n"
        syslinux_conf += "menu color cmdline 0 #ffffffff #00000000\n"

        versions = []
        kernels = self._get_kernel_versions()
        symkern = "%s/boot/vmlinuz" % self._instroot

        if os.path.lexists(symkern):
            v = os.path.realpath(symkern).replace('%s-' % symkern, "")
            syslinux_conf += "label %s\n" % self.distro_name.lower()
            syslinux_conf += "\tmenu label %s (%s)\n" % (self.distro_name, v)
            syslinux_conf += "\tlinux ../vmlinuz\n"
            if self._ptable_format == 'msdos':
                rootstr = rootdev
            else:
                if not root_part_uuid:
                    raise MountError("Cannot find the root GPT partition UUID")
                rootstr = "PARTUUID=%s" % root_part_uuid
            syslinux_conf += "\tappend ro root=%s %s\n" % (rootstr, options)
            syslinux_conf += "\tmenu default\n"
        else:
            for kernel in kernels:
                for version in kernels[kernel]:
                    versions.append(version)

            footlabel = 0
            for v in versions:
                syslinux_conf += "label %s%d\n" \
                                 % (self.distro_name.lower(), footlabel)
                syslinux_conf += "\tmenu label %s (%s)\n" % (self.distro_name, v)
                syslinux_conf += "\tlinux ../vmlinuz-%s\n" % v
                syslinux_conf += "\tappend ro root=%s %s\n" \
                                 % (rootdev, options)
                if footlabel == 0:
                    syslinux_conf += "\tmenu default\n"
                footlabel += 1;

        msger.debug("Writing syslinux config %s/boot/extlinux/extlinux.conf" \
                    % self._instroot)
        cfg = open(self._instroot + "/boot/extlinux/extlinux.conf", "w")
        cfg.write(syslinux_conf)
        cfg.close()

    def _install_syslinux(self):
        for name in self.__disks.keys():
            loopdev = self.__disks[name].device

            # Set MBR
            mbrfile = "%s/usr/share/syslinux/" % self._instroot
            if self._ptable_format == 'gpt':
                mbrfile += "gptmbr.bin"
            else:
                mbrfile += "mbr.bin"

            msger.debug("Installing syslinux bootloader '%s' to %s" % \
                        (mbrfile, loopdev))

            mbrsize = os.stat(mbrfile)[stat.ST_SIZE]
            rc = runner.show(['dd', 'if=%s' % mbrfile, 'of=' + loopdev])
            if rc != 0:
                raise MountError("Unable to set MBR to %s" % loopdev)


            # Ensure all data is flushed to disk before doing syslinux install
            runner.quiet('sync')

            fullpathsyslinux = fs_related.find_binary_path("extlinux")
            rc = runner.show([fullpathsyslinux,
                              "-i",
                              "%s/boot/extlinux" % self._instroot])
            if rc != 0:
                raise MountError("Unable to install syslinux bootloader to %s" \
                                 % loopdev)

    def _create_bootconfig(self):
        #If syslinux is available do the required configurations.
        if os.path.exists("%s/usr/share/syslinux/" % (self._instroot)) \
           and os.path.exists("%s/boot/extlinux/" % (self._instroot)):
            self._create_syslinux_config()
            self._install_syslinux()

    def _unmount_instroot(self):
        if not self.__instloop is None:
            try:
                self.__instloop.cleanup()
            except MountError, err:
                msger.warning("%s" % err)
Exemple #14
0
class RawImageCreator(BaseImageCreator):
    """Installs a system into a file containing a partitioned disk image.

    ApplianceImageCreator is an advanced ImageCreator subclass; a sparse file
    is formatted with a partition table, each partition loopback mounted
    and the system installed into an virtual disk. The disk image can
    subsequently be booted in a virtual machine or accessed with kpartx
    """
    img_format = 'raw'

    def __init__(self, creatoropts=None, pkgmgr=None, compress_image=None, generate_bmap=None, fstab_entry="uuid"):
        """Initialize a ApplianceImageCreator instance.

            This method takes the same arguments as ImageCreator.__init__()
        """
        BaseImageCreator.__init__(self, creatoropts, pkgmgr)

        self.__instloop = None
        self.__imgdir = None
        self.__disks = {}
        self.__disk_format = "raw"
        self._disk_names = []
        self._ptable_format = self.ks.handler.bootloader.ptable
        self.vmem = 512
        self.vcpu = 1
        self.checksum = False
        self.use_uuid = fstab_entry == "uuid"
        self.appliance_version = None
        self.appliance_release = None
        self.compress_image = compress_image
        self.bmap_needed = generate_bmap
        self._need_extlinux = not kickstart.use_installerfw(self.ks, "bootloader")
        #self.getsource = False
        #self.listpkg = False

        self._dep_checks.extend(["sync", "kpartx", "parted"])
        if self._need_extlinux:
            self._dep_checks.extend(["extlinux"])

    def configure(self, repodata = None):
        import subprocess
        def chroot():
            os.chroot(self._instroot)
            os.chdir("/")

        if os.path.exists(self._instroot + "/usr/bin/Xorg"):
            subprocess.call(["/bin/chmod", "u+s", "/usr/bin/Xorg"],
                            preexec_fn = chroot)

        BaseImageCreator.configure(self, repodata)

    def _get_fstab(self):
        s = ""
        for mp in self.__instloop.mount_order:
            p = None
            for p1 in self.__instloop.partitions:
                if p1['mountpoint'] == mp:
                    p = p1
                    break

            if self.use_uuid and p['uuid']:
                device = "UUID=%s" % p['uuid']
            else:
                device = "/dev/%s%-d" % (p['disk_name'], p['num'])

            s += "%(device)s  %(mountpoint)s  %(fstype)s  %(fsopts)s 0 0\n" % {
               'device': device,
               'mountpoint': p['mountpoint'],
               'fstype': p['fstype'],
               'fsopts': "defaults,noatime" if not p['fsopts'] else p['fsopts']}

            if p['mountpoint'] == "/":
                for subvol in self.__instloop.subvolumes:
                    if subvol['mountpoint'] == "/":
                        continue
                    s += "%(device)s  %(mountpoint)s  %(fstype)s  %(fsopts)s 0 0\n" % {
                         'device': "/dev/%s%-d" % (p['disk_name'], p['num']),
                         'mountpoint': subvol['mountpoint'],
                         'fstype': p['fstype'],
                         'fsopts': "defaults,noatime" if not subvol['fsopts'] else subvol['fsopts']}

        s += "devpts     /dev/pts  devpts  gid=5,mode=620   0 0\n"
        s += "tmpfs      /dev/shm  tmpfs   defaults         0 0\n"
        s += "proc       /proc     proc    defaults         0 0\n"
        s += "sysfs      /sys      sysfs   defaults         0 0\n"
        return s

    def _create_mkinitrd_config(self):
        """write to tell which modules to be included in initrd"""

        mkinitrd = ""
        mkinitrd += "PROBE=\"no\"\n"
        mkinitrd += "MODULES+=\"ext3 ata_piix sd_mod libata scsi_mod\"\n"
        mkinitrd += "rootfs=\"ext3\"\n"
        mkinitrd += "rootopts=\"defaults\"\n"

        msger.debug("Writing mkinitrd config %s/etc/sysconfig/mkinitrd" \
                    % self._instroot)
        os.makedirs(self._instroot + "/etc/sysconfig/",mode=644)
        cfg = open(self._instroot + "/etc/sysconfig/mkinitrd", "w")
        cfg.write(mkinitrd)
        cfg.close()

    def _get_parts(self):
        if not self.ks:
            raise CreatorError("Failed to get partition info, "
                               "please check your kickstart setting.")

        # Set a default partition if no partition is given out
        if not self.ks.handler.partition.partitions:
            partstr = "part / --size 1900 --ondisk sda --fstype=ext3"
            args = partstr.split()
            pd = self.ks.handler.partition.parse(args[1:])
            if pd not in self.ks.handler.partition.partitions:
                self.ks.handler.partition.partitions.append(pd)

        # partitions list from kickstart file
        return kickstart.get_partitions(self.ks)

    def get_disk_names(self):
        """ Returns a list of physical target disk names (e.g., 'sdb') which
        will be created. """

        if self._disk_names:
            return self._disk_names

        #get partition info from ks handler
        parts = self._get_parts()

        for i in range(len(parts)):
            if parts[i].disk:
                disk_name = parts[i].disk
            else:
                raise CreatorError("Failed to create disks, no --ondisk "
                                   "specified in partition line of ks file")

            if parts[i].mountpoint and not parts[i].fstype:
                raise CreatorError("Failed to create disks, no --fstype "
                                    "specified for partition with mountpoint "
                                    "'%s' in the ks file")

            self._disk_names.append(disk_name)

        return self._disk_names

    def _full_name(self, name, extention):
        """ Construct full file name for a file we generate. """
        return "%s-%s.%s" % (self.name, name, extention)

    def _full_path(self, path, name, extention):
        """ Construct full file path to a file we generate. """
        return os.path.join(path, self._full_name(name, extention))

    #
    # Actual implemention
    #
    def _mount_instroot(self, base_on = None):
        parts = self._get_parts()
        self.__instloop = PartitionedMount(self._instroot)

        for p in parts:
            self.__instloop.add_partition(int(p.size),
                                          p.disk,
                                          p.mountpoint,
                                          p.fstype,
                                          p.label,
                                          fsopts = p.fsopts,
                                          boot = p.active,
                                          align = p.align,
                                          part_type = p.part_type)

        self.__instloop.layout_partitions(self._ptable_format)

        # Create the disks
        self.__imgdir = self._mkdtemp()
        for disk_name, disk in self.__instloop.disks.items():
            full_path = self._full_path(self.__imgdir, disk_name, "raw")
            msger.debug("Adding disk %s as %s with size %s bytes" \
                        % (disk_name, full_path, disk['min_size']))

            disk_obj = fs_related.SparseLoopbackDisk(full_path,
                                                     disk['min_size'])
            self.__disks[disk_name] = disk_obj
            self.__instloop.add_disk(disk_name, disk_obj)

        self.__instloop.mount()
        self._create_mkinitrd_config()

    def mount(self, base_on = None, cachedir = None):
        """
        This method calls the base class' 'mount()' method and then creates
        block device nodes corresponding to the image's partitions in the image
        itself. Namely, the image has /dev/loopX device corresponding to the
        entire image, and per-partition /dev/mapper/* devices.

        We copy these files to image's "/dev" directory in order to enable
        scripts which run in the image chroot environment to access own raw
        partitions. For example, this can be used to install the bootloader to
        the MBR (say, from an installer framework plugin).
        """

        def copy_devnode(src, dest):
            """A helper function for copying device nodes."""

            if not src:
                return

            stat_obj = os.stat(src)
            assert stat.S_ISBLK(stat_obj.st_mode)

            os.mknod(dest, stat_obj.st_mode,
                     os.makedev(os.major(stat_obj.st_rdev),
                                os.minor(stat_obj.st_rdev)))
            # os.mknod uses process umask may create a nod with different
            # permissions, so we use os.chmod to make sure permissions are
            # correct.
            os.chmod(dest, stat_obj.st_mode)

        BaseImageCreator.mount(self, base_on, cachedir)

        # Copy the disk loop devices
        for name in self.__disks.keys():
            loopdev = self.__disks[name].device
            copy_devnode(loopdev, self._instroot + loopdev)

        # Copy per-partition dm nodes
        os.mkdir(self._instroot + "/dev/mapper", os.stat("/dev/mapper").st_mode)
        for p in self.__instloop.partitions:
            copy_devnode(p['mapper_device'],
                         self._instroot + p['mapper_device'])
            copy_devnode(p['mpath_device'],
                         self._instroot + p['mpath_device'])

    def unmount(self):
        """
        Remove loop/dm device nodes which we created in 'mount()' and call the
        base class' 'unmount()' method.
        """

        for p in self.__instloop.partitions:
            if p['mapper_device']:
                path = self._instroot + p['mapper_device']
                if os.path.exists(path):
                    os.unlink(path)
            if p['mpath_device']:
                path = self._instroot + p['mpath_device']
                if os.path.exists(path):
                    os.unlink(path)

        path = self._instroot + "/dev/mapper"
        if os.path.exists(path):
            shutil.rmtree(path, ignore_errors=True)

        for name in self.__disks.keys():
            if self.__disks[name].device:
                path = self._instroot + self.__disks[name].device
                if os.path.exists(path):
                    os.unlink(path)

        BaseImageCreator.unmount(self)

    def _get_required_packages(self):
        required_packages = BaseImageCreator._get_required_packages(self)
        if self._need_extlinux:
            if not self.target_arch or not self.target_arch.startswith("arm"):
                required_packages += ["syslinux", "syslinux-extlinux"]
        return required_packages

    def _get_excluded_packages(self):
        return BaseImageCreator._get_excluded_packages(self)

    def _get_syslinux_boot_config(self):
        rootdev = None
        root_part_uuid = None
        for p in self.__instloop.partitions:
            if p['mountpoint'] == "/":
                rootdev = "/dev/%s%-d" % (p['disk_name'], p['num'])
                root_part_uuid = p['partuuid']

        return (rootdev, root_part_uuid)

    def _create_syslinux_config(self):

        splash = os.path.join(self._instroot, "boot/extlinux")
        if os.path.exists(splash):
            splashline = "menu background splash.jpg"
        else:
            splashline = ""

        (rootdev, root_part_uuid) = self._get_syslinux_boot_config()
        options = self.ks.handler.bootloader.appendLine

        #XXX don't hardcode default kernel - see livecd code
        syslinux_conf = ""
        syslinux_conf += "prompt 0\n"
        syslinux_conf += "timeout 1\n"
        syslinux_conf += "\n"
        syslinux_conf += "default vesamenu.c32\n"
        syslinux_conf += "menu autoboot Starting %s...\n" % self.distro_name
        syslinux_conf += "menu hidden\n"
        syslinux_conf += "\n"
        syslinux_conf += "%s\n" % splashline
        syslinux_conf += "menu title Welcome to %s!\n" % self.distro_name
        syslinux_conf += "menu color border 0 #ffffffff #00000000\n"
        syslinux_conf += "menu color sel 7 #ffffffff #ff000000\n"
        syslinux_conf += "menu color title 0 #ffffffff #00000000\n"
        syslinux_conf += "menu color tabmsg 0 #ffffffff #00000000\n"
        syslinux_conf += "menu color unsel 0 #ffffffff #00000000\n"
        syslinux_conf += "menu color hotsel 0 #ff000000 #ffffffff\n"
        syslinux_conf += "menu color hotkey 7 #ffffffff #ff000000\n"
        syslinux_conf += "menu color timeout_msg 0 #ffffffff #00000000\n"
        syslinux_conf += "menu color timeout 0 #ffffffff #00000000\n"
        syslinux_conf += "menu color cmdline 0 #ffffffff #00000000\n"

        versions = []
        kernels = self._get_kernel_versions()
        symkern = "%s/boot/vmlinuz" % self._instroot

        if os.path.lexists(symkern):
            v = os.path.realpath(symkern).replace('%s-' % symkern, "")
            syslinux_conf += "label %s\n" % self.distro_name.lower()
            syslinux_conf += "\tmenu label %s (%s)\n" % (self.distro_name, v)
            syslinux_conf += "\tlinux ../vmlinuz\n"
            if self._ptable_format == 'msdos':
                rootstr = rootdev
            else:
                if not root_part_uuid:
                    raise MountError("Cannot find the root GPT partition UUID")
                rootstr = "PARTUUID=%s" % root_part_uuid
            syslinux_conf += "\tappend ro root=%s %s\n" % (rootstr, options)
            syslinux_conf += "\tmenu default\n"
        else:
            for kernel in kernels:
                for version in kernels[kernel]:
                    versions.append(version)

            footlabel = 0
            for v in versions:
                syslinux_conf += "label %s%d\n" \
                                 % (self.distro_name.lower(), footlabel)
                syslinux_conf += "\tmenu label %s (%s)\n" % (self.distro_name, v)
                syslinux_conf += "\tlinux ../vmlinuz-%s\n" % v
                syslinux_conf += "\tappend ro root=%s %s\n" \
                                 % (rootdev, options)
                if footlabel == 0:
                    syslinux_conf += "\tmenu default\n"
                footlabel += 1;

        msger.debug("Writing syslinux config %s/boot/extlinux/extlinux.conf" \
                    % self._instroot)
        cfg = open(self._instroot + "/boot/extlinux/extlinux.conf", "w")
        cfg.write(syslinux_conf)
        cfg.close()

    def _install_syslinux(self):
        for name in self.__disks.keys():
            loopdev = self.__disks[name].device

            # Set MBR
            mbrfile = "%s/usr/share/syslinux/" % self._instroot
            if self._ptable_format == 'gpt':
                mbrfile += "gptmbr.bin"
            else:
                mbrfile += "mbr.bin"

            msger.debug("Installing syslinux bootloader '%s' to %s" % \
                        (mbrfile, loopdev))

            rc = runner.show(['dd', 'if=%s' % mbrfile, 'of=' + loopdev])
            if rc != 0:
                raise MountError("Unable to set MBR to %s" % loopdev)


            # Ensure all data is flushed to disk before doing syslinux install
            runner.quiet('sync')

            fullpathsyslinux = fs_related.find_binary_path("extlinux")
            rc = runner.show([fullpathsyslinux,
                              "-i",
                              "%s/boot/extlinux" % self._instroot])
            if rc != 0:
                raise MountError("Unable to install syslinux bootloader to %s" \
                                 % loopdev)

    def _create_bootconfig(self):
        #If syslinux is available do the required configurations.
        if self._need_extlinux \
           and os.path.exists("%s/usr/share/syslinux/" % (self._instroot)) \
           and os.path.exists("%s/boot/extlinux/" % (self._instroot)):
            self._create_syslinux_config()
            self._install_syslinux()

    def _unmount_instroot(self):
        if not self.__instloop is None:
            try:
                self.__instloop.cleanup()
            except MountError, err:
                msger.warning("%s" % err)
Exemple #15
0
    def do_chroot(cls, target):
        img = target
        imgsize = misc.get_file_size(img) * 1024L * 1024L
        partedcmd = fs_related.find_binary_path("parted")
        disk = fs_related.SparseLoopbackDisk(img, imgsize)
        imgmnt = misc.mkdtemp()
        imgloop = PartitionedMount({'/dev/sdb': disk}, imgmnt, skipformat=True)
        img_fstype = "ext3"

        # Check the partitions from raw disk.
        root_mounted = False
        partition_mounts = 0
        for line in runner.outs([partedcmd, "-s", img, "unit", "B",
                                 "print"]).splitlines():
            line = line.strip()

            # Lines that start with number are the partitions,
            # because parted can be translated we can't refer to any text lines.
            if not line or not line[0].isdigit():
                continue

            # Some vars have extra , as list seperator.
            line = line.replace(",", "")

            # Example of parted output lines that are handled:
            # Number  Start        End          Size         Type     File system     Flags
            #  1      512B         3400000511B  3400000000B  primary
            #  2      3400531968B  3656384511B  255852544B   primary  linux-swap(v1)
            #  3      3656384512B  3720347647B  63963136B    primary  fat16           boot, lba

            partition_info = re.split("\s+", line)

            size = partition_info[3].split("B")[0]

            if len(partition_info) < 6 or partition_info[5] in ["boot"]:
                # No filesystem can be found from partition line. Assuming
                # btrfs, because that is the only MeeGo fs that parted does
                # not recognize properly.
                # TODO: Can we make better assumption?
                fstype = "btrfs"
            elif partition_info[5] in ["ext2", "ext3", "ext4", "btrfs"]:
                fstype = partition_info[5]
            elif partition_info[5] in ["fat16", "fat32"]:
                fstype = "vfat"
            elif "swap" in partition_info[5]:
                fstype = "swap"
            else:
                raise errors.CreatorError(
                    "Could not recognize partition fs type '%s'." %
                    partition_info[5])

            if not root_mounted and fstype in [
                    "ext2", "ext3", "ext4", "btrfs"
            ]:
                # TODO: Check that this is actually the valid root partition from /etc/fstab
                mountpoint = "/"
                root_mounted = True
            elif fstype == "swap":
                mountpoint = "swap"
            else:
                # TODO: Assing better mount points for the rest of the partitions.
                partition_mounts += 1
                mountpoint = "/media/partition_%d" % partition_mounts

            if "boot" in partition_info:
                boot = True
            else:
                boot = False

            msger.verbose(
                "Size: %s Bytes, fstype: %s, mountpoint: %s, boot: %s" %
                (size, fstype, mountpoint, boot))
            # TODO: add_partition should take bytes as size parameter.
            imgloop.add_partition((int)(size) / 1024 / 1024,
                                  "/dev/sdb",
                                  mountpoint,
                                  fstype=fstype,
                                  boot=boot)

        try:
            imgloop.mount()

        except errors.MountError:
            imgloop.cleanup()
            raise

        try:
            chroot.chroot(imgmnt, None, "/bin/env HOME=/root /bin/bash")
        except:
            raise errors.CreatorError("Failed to chroot to %s." % img)
        finally:
            chroot.cleanup_after_chroot("img", imgloop, None, imgmnt)
Exemple #16
0
class DirectImageCreator(BaseImageCreator):
    """
    Installs a system into a file containing a partitioned disk image.

    DirectImageCreator is an advanced ImageCreator subclass; an image
    file is formatted with a partition table, each partition created
    from a rootfs or other OpenEmbedded build artifact and dd'ed into
    the virtual disk. The disk image can subsequently be dd'ed onto
    media and used on actual hardware.
    """
    def __init__(self,
                 oe_builddir,
                 image_output_dir,
                 rootfs_dir,
                 bootimg_dir,
                 kernel_dir,
                 native_sysroot,
                 hdddir,
                 staging_data_dir,
                 creatoropts=None,
                 pkgmgr=None,
                 compress_image=None,
                 generate_bmap=None,
                 fstab_entry="uuid"):
        """
        Initialize a DirectImageCreator instance.

        This method takes the same arguments as ImageCreator.__init__()
        """
        BaseImageCreator.__init__(self, creatoropts, pkgmgr)

        self.__instimage = None
        self.__imgdir = None
        self.__disks = {}
        self.__disk_format = "direct"
        self._disk_names = []
        self._ptable_format = self.ks.handler.bootloader.ptable
        self.use_uuid = fstab_entry == "uuid"
        self.compress_image = compress_image
        self.bmap_needed = generate_bmap

        self.oe_builddir = oe_builddir
        if image_output_dir:
            self.tmpdir = image_output_dir
            self.cachedir = "%s/cache" % image_output_dir
        self.rootfs_dir = rootfs_dir
        self.bootimg_dir = bootimg_dir
        self.kernel_dir = kernel_dir
        self.native_sysroot = native_sysroot
        self.hdddir = hdddir
        self.staging_data_dir = staging_data_dir

    def __write_fstab(self, image_rootfs):
        """overriden to generate fstab (temporarily) in rootfs. This
        is called from mount_instroot, make sure it doesn't get called
        from BaseImage.mount()"""
        if image_rootfs is None:
            return None

        fstab = image_rootfs + "/etc/fstab"
        if not os.path.isfile(fstab):
            return None

        parts = self._get_parts()

        self._save_fstab(fstab)
        fstab_lines = self._get_fstab(fstab, parts)
        self._update_fstab(fstab_lines, parts)
        self._write_fstab(fstab, fstab_lines)

        return fstab

    def _update_fstab(self, fstab_lines, parts):
        """Assume partition order same as in wks"""
        for num, p in enumerate(parts, 1):
            if not p.mountpoint or p.mountpoint == "/" or p.mountpoint == "/boot":
                continue
            if self._ptable_format == 'msdos' and num > 3:
                device_name = "/dev/" + p.disk + str(num + 1)
            else:
                device_name = "/dev/" + p.disk + str(num)

            opts = "defaults"
            if p.fsopts:
                opts = p.fsopts

            fstab_entry = device_name + "\t" + \
                          p.mountpoint + "\t" + \
                          p.fstype + "\t" + \
                          opts + "\t0\t0\n"
            fstab_lines.append(fstab_entry)

    def _write_fstab(self, fstab, fstab_lines):
        fstab = open(fstab, "w")
        for line in fstab_lines:
            fstab.write(line)
        fstab.close()

    def _save_fstab(self, fstab):
        """Save the current fstab in rootfs"""
        shutil.copyfile(fstab, fstab + ".orig")

    def _restore_fstab(self, fstab):
        """Restore the saved fstab in rootfs"""
        if fstab is None:
            return
        shutil.move(fstab + ".orig", fstab)

    def _get_fstab(self, fstab, parts):
        """Return the desired contents of /etc/fstab."""
        f = open(fstab, "r")
        fstab_contents = f.readlines()
        f.close()

        return fstab_contents

    def set_bootimg_dir(self, bootimg_dir):
        """
        Accessor for bootimg_dir, the actual location used for the source
        of the bootimg.  Should be set by source plugins (only if they
        change the default bootimg source) so the correct info gets
        displayed for print_outimage_info().
        """
        self.bootimg_dir = bootimg_dir

    def _get_parts(self):
        if not self.ks:
            raise CreatorError("Failed to get partition info, "
                               "please check your kickstart setting.")

        # Set a default partition if no partition is given out
        if not self.ks.handler.partition.partitions:
            partstr = "part / --size 1900 --ondisk sda --fstype=ext3"
            args = partstr.split()
            pd = self.ks.handler.partition.parse(args[1:])
            if pd not in self.ks.handler.partition.partitions:
                self.ks.handler.partition.partitions.append(pd)

        # partitions list from kickstart file
        return kickstart.get_partitions(self.ks)

    def get_disk_names(self):
        """ Returns a list of physical target disk names (e.g., 'sdb') which
        will be created. """

        if self._disk_names:
            return self._disk_names

        #get partition info from ks handler
        parts = self._get_parts()

        for i in range(len(parts)):
            if parts[i].disk:
                disk_name = parts[i].disk
            else:
                raise CreatorError("Failed to create disks, no --ondisk "
                                   "specified in partition line of ks file")

            if parts[i].mountpoint and not parts[i].fstype:
                raise CreatorError("Failed to create disks, no --fstype "
                                   "specified for partition with mountpoint "
                                   "'%s' in the ks file")

            self._disk_names.append(disk_name)

        return self._disk_names

    def _full_name(self, name, extention):
        """ Construct full file name for a file we generate. """
        return "%s-%s.%s" % (self.name, name, extention)

    def _full_path(self, path, name, extention):
        """ Construct full file path to a file we generate. """
        return os.path.join(path, self._full_name(name, extention))

    def get_default_source_plugin(self):
        """
        The default source plugin i.e. the plugin that's consulted for
        overall image generation tasks outside of any particular
        partition.  For convenience, we just hang it off the
        bootloader handler since it's the one non-partition object in
        any setup.  By default the default plugin is set to the same
        plugin as the /boot partition; since we hang it off the
        bootloader object, the default can be explicitly set using the
        --source bootloader param.
        """
        return self.ks.handler.bootloader.source

    #
    # Actual implemention
    #
    def _mount_instroot(self, base_on=None):
        """
        For 'wic', we already have our build artifacts and don't want
        to loop mount anything to install into, we just create
        filesystems from the artifacts directly and combine them into
        a partitioned image.

        We still want to reuse as much of the basic mic machinery
        though; despite the fact that we don't actually do loop or any
        other kind of mounting we still want to do many of the same
        things to prepare images, so we basically just adapt to the
        basic framework and reinterpret what 'mounting' means in our
        context.

        _instroot would normally be something like
        /var/tmp/wic/build/imgcreate-s_9AKQ/install_root, for
        installing packages, etc.  We don't currently need to do that,
        so we simplify life by just using /var/tmp/wic/build as our
        workdir.
        """
        parts = self._get_parts()

        self.__instimage = PartitionedMount(self._instroot)

        for p in parts:
            # as a convenience, set source to the boot partition source
            # instead of forcing it to be set via bootloader --source
            if not self.ks.handler.bootloader.source and p.mountpoint == "/boot":
                self.ks.handler.bootloader.source = p.source

        for p in parts:
            # need to create the filesystems in order to get their
            # sizes before we can add them and do the layout.
            # PartitionedMount.mount() actually calls __format_disks()
            # to create the disk images and carve out the partitions,
            # then self.install() calls PartitionedMount.install()
            # which calls __install_partitition() for each partition
            # to dd the fs into the partitions.  It would be nice to
            # be able to use e.g. ExtDiskMount etc to create the
            # filesystems, since that's where existing e.g. mkfs code
            # is, but those are only created after __format_disks()
            # which needs the partition sizes so needs them created
            # before its called.  Well, the existing setup is geared
            # to installing packages into mounted filesystems - maybe
            # when/if we need to actually do package selection we
            # should modify things to use those objects, but for now
            # we can avoid that.

            fstab = self.__write_fstab(self.rootfs_dir.get("ROOTFS_DIR"))

            p.prepare(self, self.workdir, self.oe_builddir, self.rootfs_dir,
                      self.bootimg_dir, self.kernel_dir, self.native_sysroot)

            self._restore_fstab(fstab)

            self.__instimage.add_partition(int(p.size),
                                           p.disk,
                                           p.mountpoint,
                                           p.source_file,
                                           p.fstype,
                                           p.label,
                                           fsopts=p.fsopts,
                                           boot=p.active,
                                           align=p.align,
                                           part_type=p.part_type)

        self.__instimage.layout_partitions(self._ptable_format)

        self.__imgdir = self.workdir
        for disk_name, disk in self.__instimage.disks.items():
            full_path = self._full_path(self.__imgdir, disk_name, "direct")
            msger.debug("Adding disk %s as %s with size %s bytes" \
                        % (disk_name, full_path, disk['min_size']))
            disk_obj = fs_related.DiskImage(full_path, disk['min_size'])
            self.__disks[disk_name] = disk_obj
            self.__instimage.add_disk(disk_name, disk_obj)

        self.__instimage.mount()

    def install(self, repo_urls=None):
        """
        Install fs images into partitions
        """
        for disk_name, disk in self.__instimage.disks.items():
            full_path = self._full_path(self.__imgdir, disk_name, "direct")
            msger.debug("Installing disk %s as %s with size %s bytes" \
                        % (disk_name, full_path, disk['min_size']))
            self.__instimage.install(full_path)

    def configure(self, repodata=None):
        """
        Configure the system image according to kickstart.

        For now, it just prepares the image to be bootable by e.g.
        creating and installing a bootloader configuration.
        """
        source_plugin = self.get_default_source_plugin()
        if source_plugin:
            self._source_methods = pluginmgr.get_source_plugin_methods(
                source_plugin, disk_methods)
            for disk_name, disk in self.__instimage.disks.items():
                self._source_methods["do_install_disk"](
                    disk, disk_name, self, self.workdir, self.oe_builddir,
                    self.bootimg_dir, self.kernel_dir, self.native_sysroot)

    def print_outimage_info(self):
        """
        Print the image(s) and artifacts used, for the user.
        """
        msg = "The new image(s) can be found here:\n"

        parts = self._get_parts()

        for disk_name, disk in self.__instimage.disks.items():
            full_path = self._full_path(self.__imgdir, disk_name, "direct")
            msg += '  %s\n\n' % full_path

        msg += 'The following build artifacts were used to create the image(s):\n'
        for p in parts:
            if p.get_rootfs() is None:
                continue
            if p.mountpoint == '/':
                str = ':'
            else:
                str = '["%s"]:' % p.label
            msg += '  ROOTFS_DIR%s%s\n' % (str.ljust(20), p.get_rootfs())

        msg += '  BOOTIMG_DIR:                  %s\n' % self.bootimg_dir
        msg += '  KERNEL_DIR:                   %s\n' % self.kernel_dir
        msg += '  NATIVE_SYSROOT:               %s\n' % self.native_sysroot

        msger.info(msg)

    def _get_boot_config(self):
        """
        Return the rootdev/root_part_uuid (if specified by
        --part-type)

        Assume partition order same as in wks
        """
        rootdev = None
        root_part_uuid = None
        parts = self._get_parts()
        for num, p in enumerate(parts, 1):
            if p.mountpoint == "/":
                part = ''
                if p.disk.startswith('mmcblk'):
                    part = 'p'

                if self._ptable_format == 'msdos' and num > 3:
                    rootdev = "/dev/%s%s%-d" % (p.disk, part, num + 1)
                else:
                    rootdev = "/dev/%s%s%-d" % (p.disk, part, num)
                root_part_uuid = p.part_type

        return (rootdev, root_part_uuid)

    def _unmount_instroot(self):
        if not self.__instimage is None:
            try:
                self.__instimage.cleanup()
            except MountError, err:
                msger.warning("%s" % err)
Exemple #17
0
    def _mount_instroot(self, base_on=None):
        """
        For 'wic', we already have our build artifacts and don't want
        to loop mount anything to install into, we just create
        filesystems from the artifacts directly and combine them into
        a partitioned image.

        We still want to reuse as much of the basic mic machinery
        though; despite the fact that we don't actually do loop or any
        other kind of mounting we still want to do many of the same
        things to prepare images, so we basically just adapt to the
        basic framework and reinterpret what 'mounting' means in our
        context.

        _instroot would normally be something like
        /var/tmp/wic/build/imgcreate-s_9AKQ/install_root, for
        installing packages, etc.  We don't currently need to do that,
        so we simplify life by just using /var/tmp/wic/build as our
        workdir.
        """
        parts = self._get_parts()

        self.__instimage = PartitionedMount(self._instroot)

        for p in parts:
            # as a convenience, set source to the boot partition source
            # instead of forcing it to be set via bootloader --source
            if not self.ks.handler.bootloader.source and p.mountpoint == "/boot":
                self.ks.handler.bootloader.source = p.source

        for p in parts:
            # need to create the filesystems in order to get their
            # sizes before we can add them and do the layout.
            # PartitionedMount.mount() actually calls __format_disks()
            # to create the disk images and carve out the partitions,
            # then self.install() calls PartitionedMount.install()
            # which calls __install_partitition() for each partition
            # to dd the fs into the partitions.  It would be nice to
            # be able to use e.g. ExtDiskMount etc to create the
            # filesystems, since that's where existing e.g. mkfs code
            # is, but those are only created after __format_disks()
            # which needs the partition sizes so needs them created
            # before its called.  Well, the existing setup is geared
            # to installing packages into mounted filesystems - maybe
            # when/if we need to actually do package selection we
            # should modify things to use those objects, but for now
            # we can avoid that.

            fstab = self.__write_fstab(self.rootfs_dir.get("ROOTFS_DIR"))

            p.prepare(self, self.workdir, self.oe_builddir, self.rootfs_dir,
                      self.bootimg_dir, self.kernel_dir, self.native_sysroot)

            self._restore_fstab(fstab)

            self.__instimage.add_partition(int(p.size),
                                           p.disk,
                                           p.mountpoint,
                                           p.source_file,
                                           p.fstype,
                                           p.label,
                                           fsopts=p.fsopts,
                                           boot=p.active,
                                           align=p.align,
                                           part_type=p.part_type)

        self.__instimage.layout_partitions(self._ptable_format)

        self.__imgdir = self.workdir
        for disk_name, disk in self.__instimage.disks.items():
            full_path = self._full_path(self.__imgdir, disk_name, "direct")
            msger.debug("Adding disk %s as %s with size %s bytes" \
                        % (disk_name, full_path, disk['min_size']))
            disk_obj = fs_related.DiskImage(full_path, disk['min_size'])
            self.__disks[disk_name] = disk_obj
            self.__instimage.add_disk(disk_name, disk_obj)

        self.__instimage.mount()
Exemple #18
0
Fichier : raw.py Projet : lbt/mic
class RawImageCreator(BaseImageCreator):
    """Installs a system into a file containing a partitioned disk image.

    ApplianceImageCreator is an advanced ImageCreator subclass; a sparse file
    is formatted with a partition table, each partition loopback mounted
    and the system installed into an virtual disk. The disk image can
    subsequently be booted in a virtual machine or accessed with kpartx
    """

    def __init__(self, creatoropts=None, pkgmgr=None, compress_image=None):
        """Initialize a ApplianceImageCreator instance.

            This method takes the same arguments as ImageCreator.__init__()
        """
        BaseImageCreator.__init__(self, creatoropts, pkgmgr)

        self.__instloop = None
        self.__imgdir = None
        self.__disks = {}
        self.__disk_format = "raw"
        self._diskinfo = []
        self.vmem = 512
        self.vcpu = 1
        self.checksum = False
        self.appliance_version = None
        self.appliance_release = None
        self.compress_image = compress_image
        #self.getsource = False
        #self.listpkg = False

        self._dep_checks.extend(["sync", "kpartx", "parted", "extlinux"])

    def configure(self, repodata = None):
        import subprocess
        def chroot():
            os.chroot(self._instroot)
            os.chdir("/")

        if os.path.exists(self._instroot + "/usr/bin/Xorg"):
            subprocess.call(["/bin/chmod", "u+s", "/usr/bin/Xorg"],
                            preexec_fn = chroot)

        BaseImageCreator.configure(self, repodata)

    def _get_fstab(self):
        s = ""
        for mp in self.__instloop.mountOrder:
            p = None
            for p1 in self.__instloop.partitions:
                if p1['mountpoint'] == mp:
                    p = p1
                    break

            s += "%(device)s  %(mountpoint)s  %(fstype)s  %(fsopts)s 0 0\n" % {
               'device': "/dev/%s%-d" % (p['disk'], p['num']),
               'mountpoint': p['mountpoint'],
               'fstype': p['fstype'],
               'fsopts': "defaults,noatime" if not p['fsopts'] else p['fsopts']}

            if p['mountpoint'] == "/":
                for subvol in self.__instloop.subvolumes:
                    if subvol['mountpoint'] == "/":
                        continue
                    s += "%(device)s  %(mountpoint)s  %(fstype)s  %(fsopts)s 0 0\n" % {
                         'device': "/dev/%s%-d" % (p['disk'], p['num']),
                         'mountpoint': subvol['mountpoint'],
                         'fstype': p['fstype'],
                         'fsopts': "defaults,noatime" if not subvol['fsopts'] else subvol['fsopts']}

        s += "devpts     /dev/pts  devpts  gid=5,mode=620   0 0\n"
        s += "tmpfs      /dev/shm  tmpfs   defaults         0 0\n"
        s += "proc       /proc     proc    defaults         0 0\n"
        s += "sysfs      /sys      sysfs   defaults         0 0\n"
        return s

    def _create_mkinitrd_config(self):
        #write  to tell which modules to be included in initrd

        mkinitrd = ""
        mkinitrd += "PROBE=\"no\"\n"
        mkinitrd += "MODULES+=\"ext3 ata_piix sd_mod libata scsi_mod\"\n"
        mkinitrd += "rootfs=\"ext3\"\n"
        mkinitrd += "rootopts=\"defaults\"\n"

        msger.debug("Writing mkinitrd config %s/etc/sysconfig/mkinitrd" \
                    % self._instroot)
        os.makedirs(self._instroot + "/etc/sysconfig/",mode=644)
        cfg = open(self._instroot + "/etc/sysconfig/mkinitrd", "w")
        cfg.write(mkinitrd)
        cfg.close()

    def _get_parts(self):
        if not self.ks:
            raise CreatorError("Failed to get partition info, "
                               "please check your kickstart setting.")

        # Set a default partition if no partition is given out
        if not self.ks.handler.partition.partitions:
            partstr = "part / --size 1900 --ondisk sda --fstype=ext3"
            args = partstr.split()
            pd = self.ks.handler.partition.parse(args[1:])
            if pd not in self.ks.handler.partition.partitions:
                self.ks.handler.partition.partitions.append(pd)

        # partitions list from kickstart file
        return kickstart.get_partitions(self.ks)

    def get_diskinfo(self):

        if self._diskinfo:
            return self._diskinfo

        #get partition info from ks handler
        parts = self._get_parts()

        for i in range(len(parts)):
            if parts[i].disk:
                disk = parts[i].disk
            else:
                raise CreatorError("Failed to create disks, no --ondisk "
                                   "specified in partition line of ks file")

            if not parts[i].fstype:
                 raise CreatorError("Failed to create disks, no --fstype "
                                    "specified in partition line of ks file")

            size =   parts[i].size * 1024L * 1024L

            # If we have alignment set for partition we need to enlarge the
            # drive, so that the alignment changes fits there as well
            if parts[i].align:
                size += parts[i].align * 1024L

            found = False
            for j in range(len(self._diskinfo)):
                if self._diskinfo[j]['name'] == disk:
                    self._diskinfo[j]['size'] = self._diskinfo[j]['size'] + size
                    found = True
                    break
                else:
                    found = False

            if not found:
                self._diskinfo.append({ 'name': disk, 'size': size })

        return self._diskinfo

    #
    # Actual implemention
    #
    def _mount_instroot(self, base_on = None):
        self.__imgdir = self._mkdtemp()

        parts = self._get_parts()

        #create disk
        for item in self.get_diskinfo():
            msger.debug("Adding disk %s as %s/%s-%s.raw with size %s bytes" %
                        (item['name'], self.__imgdir, self.name, item['name'],
                         item['size']))

            disk = fs_related.SparseLoopbackDisk("%s/%s-%s.raw" % (
                                                                self.__imgdir,
                                                                self.name,
                                                                item['name']),
                                                 item['size'])
            self.__disks[item['name']] = disk

        self.__instloop = PartitionedMount(self.__disks, self._instroot)

        for p in parts:
            self.__instloop.add_partition(int(p.size),
                                          p.disk,
                                          p.mountpoint,
                                          p.fstype,
                                          fsopts = p.fsopts,
                                          boot = p.active,
                                          align = p.align)

        self.__instloop.mount()
        self._create_mkinitrd_config()

    def _get_required_packages(self):
        required_packages = BaseImageCreator._get_required_packages(self)
        if not self.target_arch or not self.target_arch.startswith("arm"):
            required_packages += ["syslinux", "syslinux-extlinux"]
        return required_packages

    def _get_excluded_packages(self):
        return BaseImageCreator._get_excluded_packages(self)

    def _get_syslinux_boot_config(self):
        bootdevnum = None
        rootdevnum = None
        rootdev = None
        for p in self.__instloop.partitions:
            if p['mountpoint'] == "/boot":
                bootdevnum = p['num'] - 1
            elif p['mountpoint'] == "/" and bootdevnum is None:
                bootdevnum = p['num'] - 1

            if p['mountpoint'] == "/":
                rootdevnum = p['num'] - 1
                rootdev = "/dev/%s%-d" % (p['disk'], p['num'])

        prefix = ""
        if bootdevnum == rootdevnum:
            prefix = "/boot"

        return (bootdevnum, rootdevnum, rootdev, prefix)

    def _create_syslinux_config(self):
        #Copy splash
        splash = "%s/usr/lib/anaconda-runtime/syslinux-vesa-splash.jpg" \
                 % self._instroot

        if os.path.exists(splash):
            shutil.copy(splash, "%s%s/splash.jpg" \
                                % (self._instroot, "/boot/extlinux"))
            splashline = "menu background splash.jpg"
        else:
            splashline = ""

        (bootdevnum, rootdevnum, rootdev, prefix) = \
                                            self._get_syslinux_boot_config()
        options = self.ks.handler.bootloader.appendLine

        #XXX don't hardcode default kernel - see livecd code
        syslinux_conf = ""
        syslinux_conf += "prompt 0\n"
        syslinux_conf += "timeout 1\n"
        syslinux_conf += "\n"
        syslinux_conf += "default vesamenu.c32\n"
        syslinux_conf += "menu autoboot Starting %s...\n" % self.distro_name
        syslinux_conf += "menu hidden\n"
        syslinux_conf += "\n"
        syslinux_conf += "%s\n" % splashline
        syslinux_conf += "menu title Welcome to %s!\n" % self.distro_name
        syslinux_conf += "menu color border 0 #ffffffff #00000000\n"
        syslinux_conf += "menu color sel 7 #ffffffff #ff000000\n"
        syslinux_conf += "menu color title 0 #ffffffff #00000000\n"
        syslinux_conf += "menu color tabmsg 0 #ffffffff #00000000\n"
        syslinux_conf += "menu color unsel 0 #ffffffff #00000000\n"
        syslinux_conf += "menu color hotsel 0 #ff000000 #ffffffff\n"
        syslinux_conf += "menu color hotkey 7 #ffffffff #ff000000\n"
        syslinux_conf += "menu color timeout_msg 0 #ffffffff #00000000\n"
        syslinux_conf += "menu color timeout 0 #ffffffff #00000000\n"
        syslinux_conf += "menu color cmdline 0 #ffffffff #00000000\n"

        versions = []
        kernels = self._get_kernel_versions()
        for kernel in kernels:
            for version in kernels[kernel]:
                versions.append(version)

        footlabel = 0
        for v in versions:
            shutil.copy("%s/boot/vmlinuz-%s" %(self._instroot, v),
                        "%s%s/vmlinuz-%s" % (self._instroot,
                                             "/boot/extlinux/", v))
            syslinux_conf += "label %s%d\n" \
                             % (self.distro_name.lower(), footlabel)
            syslinux_conf += "\tmenu label %s (%s)\n" % (self.distro_name, v)
            syslinux_conf += "\tkernel vmlinuz-%s\n" % v
            syslinux_conf += "\tappend ro root=%s %s\n" \
                             % (rootdev, options)
            if footlabel == 0:
               syslinux_conf += "\tmenu default\n"
            footlabel += 1;

        msger.debug("Writing syslinux config %s/boot/extlinux/extlinux.conf" \
                    % self._instroot)
        cfg = open(self._instroot + "/boot/extlinux/extlinux.conf", "w")
        cfg.write(syslinux_conf)
        cfg.close()

    def _install_syslinux(self):
        i = 0
        for name in self.__disks.keys():
            loopdev = self.__disks[name].device
            i =i+1

        msger.debug("Installing syslinux bootloader to %s" % loopdev)

        (bootdevnum, rootdevnum, rootdev, prefix) = \
                                    self._get_syslinux_boot_config()


        #Set MBR
        mbrsize = os.stat("%s/usr/share/syslinux/mbr.bin" \
                          % self._instroot)[stat.ST_SIZE]
        rc = runner.show(['dd',
                          'if=%s/usr/share/syslinux/mbr.bin' % self._instroot,
                          'of=' + loopdev])
        if rc != 0:
            raise MountError("Unable to set MBR to %s" % loopdev)

        #Set Bootable flag
        parted = fs_related.find_binary_path("parted")
        rc = runner.quiet([parted,
                           "-s",
                           loopdev,
                           "set",
                           "%d" % (bootdevnum + 1),
                           "boot",
                           "on"])
        #XXX disabled return code check because parted always fails to
        #reload part table with loop devices. Annoying because we can't
        #distinguish this failure from real partition failures :-(
        if rc != 0 and 1 == 0:
            raise MountError("Unable to set bootable flag to %sp%d" \
                             % (loopdev, (bootdevnum + 1)))

        #Ensure all data is flushed to disk before doing syslinux install
        runner.quiet('sync')

        fullpathsyslinux = fs_related.find_binary_path("extlinux")
        rc = runner.show([fullpathsyslinux,
                          "-i",
                          "%s/boot/extlinux" % self._instroot])
        if rc != 0:
            raise MountError("Unable to install syslinux bootloader to %sp%d" \
                             % (loopdev, (bootdevnum + 1)))

    def _create_bootconfig(self):
        #If syslinux is available do the required configurations.
        if os.path.exists("%s/usr/share/syslinux/" % (self._instroot)) \
           and os.path.exists("%s/boot/extlinux/" % (self._instroot)):
            self._create_syslinux_config()
            self._install_syslinux()

    def _unmount_instroot(self):
        if not self.__instloop is None:
            self.__instloop.cleanup()

    def _resparse(self, size = None):
        return self.__instloop.resparse(size)

    def _stage_final_image(self):
        """Stage the final system image in _outdir.
           write meta data
        """
        self._resparse()

        if self.compress_image:
            for imgfile in os.listdir(self.__imgdir):
                if imgfile.endswith('.raw') or imgfile.endswith('bin'):
                    imgpath = os.path.join(self.__imgdir, imgfile)
                    misc.compressing(imgpath, self.compress_image)

        if self.pack_to:
            dst = os.path.join(self._outdir, self.pack_to)
            msger.info("Pack all raw images to %s" % dst)
            misc.packing(dst, self.__imgdir)
        else:
            msger.debug("moving disks to stage location")
	    for imgfile in os.listdir(self.__imgdir):
                src = os.path.join(self.__imgdir, imgfile)
                dst = os.path.join(self._outdir, imgfile)
                msger.debug("moving %s to %s" % (src,dst))
                shutil.move(src,dst)
        self._write_image_xml()

    def _write_image_xml(self):
        imgarch = "i686"
        if self.target_arch and self.target_arch.startswith("arm"):
            imgarch = "arm"
        xml = "<image>\n"

        name_attributes = ""
        if self.appliance_version:
            name_attributes += " version='%s'" % self.appliance_version
        if self.appliance_release:
            name_attributes += " release='%s'" % self.appliance_release
        xml += "  <name%s>%s</name>\n" % (name_attributes, self.name)
        xml += "  <domain>\n"
        # XXX don't hardcode - determine based on the kernel we installed for
        # grub baremetal vs xen
        xml += "    <boot type='hvm'>\n"
        xml += "      <guest>\n"
        xml += "        <arch>%s</arch>\n" % imgarch
        xml += "      </guest>\n"
        xml += "      <os>\n"
        xml += "        <loader dev='hd'/>\n"
        xml += "      </os>\n"

        i = 0
        for name in self.__disks.keys():
            xml += "      <drive disk='%s-%s.%s' target='hd%s'/>\n" \
                   % (self.name,name, self.__disk_format,chr(ord('a')+i))
            i = i + 1

        xml += "    </boot>\n"
        xml += "    <devices>\n"
        xml += "      <vcpu>%s</vcpu>\n" % self.vcpu
        xml += "      <memory>%d</memory>\n" %(self.vmem * 1024)
        for network in self.ks.handler.network.network:
            xml += "      <interface/>\n"
        xml += "      <graphics/>\n"
        xml += "    </devices>\n"
        xml += "  </domain>\n"
        xml += "  <storage>\n"

        if self.checksum is True:
            for name in self.__disks.keys():
                diskpath = "%s/%s-%s.%s" \
                           % (self._outdir,self.name,name, self.__disk_format)
                disk_size = os.path.getsize(diskpath)
                meter_ct = 0
                meter = progress.TextMeter()
                meter.start(size=disk_size,
                            text="Generating disk signature for %s-%s.%s" \
                                 % (self.name,
                                    name,
                                    self.__disk_format))
                xml += "    <disk file='%s-%s.%s' use='system' format='%s'>\n" \
                       % (self.name,
                          name,
                          self.__disk_format,
                          self.__disk_format)

                try:
                    import hashlib
                    m1 = hashlib.sha1()
                    m2 = hashlib.sha256()
                except:
                    import sha
                    m1 = sha.new()
                    m2 = None
                f = open(diskpath,"r")
                while 1:
                    chunk = f.read(65536)
                    if not chunk:
                        break
                    m1.update(chunk)
                    if m2:
                       m2.update(chunk)
                    meter.update(meter_ct)
                    meter_ct = meter_ct + 65536

                sha1checksum = m1.hexdigest()
                xml +=  "      <checksum type='sha1'>%s</checksum>\n" \
                        % sha1checksum

                if m2:
                    sha256checksum = m2.hexdigest()
                    xml += "      <checksum type='sha256'>%s</checksum>\n" \
                           % sha256checksum

                xml += "    </disk>\n"
        else:
            for name in self.__disks.keys():
                xml += "    <disk file='%s-%s.%s' use='system' format='%s'/>\n"\
                       %(self.name,
                         name,
                         self.__disk_format,
                         self.__disk_format)

        xml += "  </storage>\n"
        xml += "</image>\n"

        msger.debug("writing image XML to %s/%s.xml" %(self._outdir, self.name))
        cfg = open("%s/%s.xml" % (self._outdir, self.name), "w")
        cfg.write(xml)
        cfg.close()
Exemple #19
0
    def _create_usbimg(self, isodir):
        overlaysizemb = 64 #default
        #skipcompress = self.skip_compression?
        fstype = "vfat"
        homesizemb=0
        swapsizemb=0
        homefile="home.img"
        plussize=128
        kernelargs=None

        if fstype == 'vfat':
            if overlaysizemb > 2047:
                raise CreatorError("Can't have an overlay of 2048MB or "
                                   "greater on VFAT")

            if homesizemb > 2047:
                raise CreatorError("Can't have an home overlay of 2048MB or "
                                   "greater on VFAT")

            if swapsizemb > 2047:
                raise CreatorError("Can't have an swap overlay of 2048MB or "
                                   "greater on VFAT")

        livesize = misc.get_file_size(isodir + "/LiveOS")

        usbimgsize = (overlaysizemb + \
                      homesizemb + \
                      swapsizemb + \
                      livesize + \
                      plussize) * 1024 * 1024

        disk = fs_related.SparseLoopbackDisk("%s/%s.usbimg" \
                                                 % (self._outdir, self.name),
                                             usbimgsize)
        usbmnt = self._mkdtemp("usb-mnt")
        usbloop = PartitionedMount({'/dev/sdb':disk}, usbmnt)

        usbloop.add_partition(usbimgsize/1024/1024,
                              "/dev/sdb",
                              "/",
                              fstype,
                              boot=True)

        usbloop.mount()

        try:
            fs_related.makedirs(usbmnt + "/LiveOS")

            if os.path.exists(isodir + "/LiveOS/squashfs.img"):
                shutil.copyfile(isodir + "/LiveOS/squashfs.img",
                                usbmnt + "/LiveOS/squashfs.img")
            else:
                fs_related.mksquashfs(os.path.dirname(self._image),
                                      usbmnt + "/LiveOS/squashfs.img")

            if os.path.exists(isodir + "/LiveOS/osmin.img"):
                shutil.copyfile(isodir + "/LiveOS/osmin.img",
                                usbmnt + "/LiveOS/osmin.img")

            uuid = usbloop.partitions[0]['mount'].uuid
            label = usbloop.partitions[0]['mount'].fslabel
            usblabel = "UUID=%s" % (uuid)
            overlaysuffix = "-%s-%s" % (label, uuid)

            args = ['cp', "-Rf", isodir + "/isolinux", usbmnt + "/syslinux"]
            rc = runner.show(args)
            if rc:
                raise CreatorError("Can't copy isolinux directory %s" \
                                   % (isodir + "/isolinux/*"))

            if os.path.isfile("/usr/share/syslinux/isolinux.bin"):
                syslinux_path = "/usr/share/syslinux"
            elif  os.path.isfile("/usr/lib/syslinux/isolinux.bin"):
                syslinux_path = "/usr/lib/syslinux"
            else:
                raise CreatorError("syslinux not installed : "
                                   "cannot find syslinux installation path")

            for f in ("isolinux.bin", "vesamenu.c32"):
                path = os.path.join(syslinux_path, f)
                if os.path.isfile(path):
                    args = ['cp', path, usbmnt + "/syslinux/"]
                    rc = runner.show(args)
                    if rc:
                        raise CreatorError("Can't copy syslinux file " + path)
                else:
                    raise CreatorError("syslinux not installed: "
                                       "syslinux file %s not found" % path)

            fd = open(isodir + "/isolinux/isolinux.cfg", "r")
            text = fd.read()
            fd.close()
            pattern = re.compile('CDLABEL=[^ ]*')
            text = pattern.sub(usblabel, text)
            pattern = re.compile('rootfstype=[^ ]*')
            text = pattern.sub("rootfstype=" + fstype, text)
            if kernelargs:
                text = text.replace("liveimg", "liveimg " + kernelargs)

            if overlaysizemb > 0:
                msger.info("Initializing persistent overlay file")
                overfile = "overlay" + overlaysuffix
                if fstype == "vfat":
                    args = ['dd',
                            "if=/dev/zero",
                            "of=" + usbmnt + "/LiveOS/" + overfile,
                            "count=%d" % overlaysizemb,
                            "bs=1M"]
                else:
                    args = ['dd',
                            "if=/dev/null",
                            "of=" + usbmnt + "/LiveOS/" + overfile,
                            "count=1",
                            "bs=1M",
                            "seek=%d" % overlaysizemb]
                rc = runner.show(args)
                if rc:
                    raise CreatorError("Can't create overlay file")
                text = text.replace("liveimg", "liveimg overlay=" + usblabel)
                text = text.replace(" ro ", " rw ")

            if swapsizemb > 0:
                msger.info("Initializing swap file")
                swapfile = usbmnt + "/LiveOS/" + "swap.img"
                args = ['dd',
                        "if=/dev/zero",
                        "of=" + swapfile,
                        "count=%d" % swapsizemb,
                        "bs=1M"]
                rc = runner.show(args)
                if rc:
                    raise CreatorError("Can't create swap file")
                args = ["mkswap", "-f", swapfile]
                rc = runner.show(args)
                if rc:
                    raise CreatorError("Can't mkswap on swap file")

            if homesizemb > 0:
                msger.info("Initializing persistent /home")
                homefile = usbmnt + "/LiveOS/" + homefile
                if fstype == "vfat":
                    args = ['dd',
                            "if=/dev/zero",
                            "of=" + homefile,
                            "count=%d" % homesizemb,
                            "bs=1M"]
                else:
                    args = ['dd',
                            "if=/dev/null",
                            "of=" + homefile,
                            "count=1",
                            "bs=1M",
                            "seek=%d" % homesizemb]
                rc = runner.show(args)
                if rc:
                    raise CreatorError("Can't create home file")

                mkfscmd = fs_related.find_binary_path("/sbin/mkfs." + fstype)
                if fstype == "ext2" or fstype == "ext3":
                    args = [mkfscmd, "-F", "-j", homefile]
                else:
                    args = [mkfscmd, homefile]
                rc = runner.show(args)
                if rc:
                    raise CreatorError("Can't mke2fs home file")
                if fstype == "ext2" or fstype == "ext3":
                    tune2fs = fs_related.find_binary_path("tune2fs")
                    args = [tune2fs,
                            "-c0",
                            "-i0",
                            "-ouser_xattr,acl",
                            homefile]
                    rc = runner.show(args)
                    if rc:
                         raise CreatorError("Can't tune2fs home file")

            if fstype == "vfat" or fstype == "msdos":
                syslinuxcmd = fs_related.find_binary_path("syslinux")
                syslinuxcfg = usbmnt + "/syslinux/syslinux.cfg"
                args = [syslinuxcmd,
                        "-d",
                        "syslinux",
                        usbloop.partitions[0]["device"]]

            elif fstype == "ext2" or fstype == "ext3":
                extlinuxcmd = fs_related.find_binary_path("extlinux")
                syslinuxcfg = usbmnt + "/syslinux/extlinux.conf"
                args = [extlinuxcmd,
                        "-i",
                        usbmnt + "/syslinux"]

            else:
                raise CreatorError("Invalid file system type: %s" % (fstype))

            os.unlink(usbmnt + "/syslinux/isolinux.cfg")
            fd = open(syslinuxcfg, "w")
            fd.write(text)
            fd.close()
            rc = runner.show(args)
            if rc:
                raise CreatorError("Can't install boot loader.")

        finally:
            usbloop.unmount()
            usbloop.cleanup()

        # Need to do this after image is unmounted and device mapper is closed
        msger.info("set MBR")
        mbrfile = "/usr/lib/syslinux/mbr.bin"
        if not os.path.exists(mbrfile):
            mbrfile = "/usr/share/syslinux/mbr.bin"
            if not os.path.exists(mbrfile):
                raise CreatorError("mbr.bin file didn't exist.")
        mbrsize = os.path.getsize(mbrfile)
        outimg = "%s/%s.usbimg" % (self._outdir, self.name)

        args = ['dd',
                "if=" + mbrfile,
                "of=" + outimg,
                "seek=0",
                "conv=notrunc",
                "bs=1",
                "count=%d" % (mbrsize)]
        rc = runner.show(args)
        if rc:
            raise CreatorError("Can't set MBR.")
Exemple #20
0
    def _mount_instroot(self, base_on=None):
        self.__imgdir = self._mkdtemp()

        #Set a default partition if no partition is given out
        if not self.ks.handler.partition.partitions:
            partstr = "part / --size 1900 --ondisk sda --fstype=ext3"
            args = partstr.split()
            pd = self.ks.handler.partition.parse(args[1:])
            if pd not in self.ks.handler.partition.partitions:
                self.ks.handler.partition.partitions.append(pd)

        #list of partitions from kickstart file
        parts = kickstart.get_partitions(self.ks)

        #list of disks where a disk is an dict with name: and size
        disks = []

        for i in range(len(parts)):
            if parts[i].disk:
                disk = parts[i].disk
            else:
                raise CreatorError(
                    "Failed to create disks, no --ondisk specified in partition line of ks file"
                )

            if not parts[i].fstype:
                raise CreatorError(
                    "Failed to create disks, no --fstype specified in partition line of ks file"
                )

            size = parts[i].size * 1024L * 1024L

            found = False
            for j in range(len(disks)):
                if disks[j]['name'] == disk:
                    disks[j]['size'] = disks[j]['size'] + size
                    found = True
                    break
                else:
                    found = False
            if not found:
                disks.append({'name': disk, 'size': size})

        #create disk
        for item in disks:
            msger.debug("Adding disk %s as %s/%s-%s.raw" %
                        (item['name'], self.__imgdir, self.name, item['name']))
            disk = fs_related.SparseLoopbackDisk(
                "%s/%s-%s.raw" % (self.__imgdir, self.name, item['name']),
                item['size'])
            self.__disks[item['name']] = disk

        self.__instloop = PartitionedMount(self.__disks, self._instroot)

        for p in parts:
            self.__instloop.add_partition(int(p.size),
                                          p.disk,
                                          p.mountpoint,
                                          p.fstype,
                                          fsopts=p.fsopts,
                                          boot=p.active)

        self.__instloop.mount()
        self._create_mkinitrd_config()
Exemple #21
0
    def _create_usbimg(self, isodir):
        overlaysizemb = 64 #default
        #skipcompress = self.skip_compression?
        fstype = "vfat"
        homesizemb=0
        swapsizemb=0
        homefile="home.img"
        plussize=128
        kernelargs=None

        if fstype == 'vfat':
            if overlaysizemb > 2047:
                raise CreatorError("Can't have an overlay of 2048MB or "
                                   "greater on VFAT")

            if homesizemb > 2047:
                raise CreatorError("Can't have an home overlay of 2048MB or "
                                   "greater on VFAT")

            if swapsizemb > 2047:
                raise CreatorError("Can't have an swap overlay of 2048MB or "
                                   "greater on VFAT")

        livesize = misc.get_file_size(isodir + "/LiveOS")

        usbimgsize = (overlaysizemb + \
                      homesizemb + \
                      swapsizemb + \
                      livesize + \
                      plussize) * 1024L * 1024L

        disk = fs_related.SparseLoopbackDisk("%s/%s.usbimg" \
                                                 % (self._outdir, self.name),
                                             usbimgsize)
        usbmnt = self._mkdtemp("usb-mnt")
        usbloop = PartitionedMount(usbmnt)
        usbloop.add_disk('/dev/sdb', disk)

        usbloop.add_partition(usbimgsize/1024/1024,
                              "/dev/sdb",
                              "/",
                              fstype,
                              boot=True)

        usbloop.mount()

        try:
            fs_related.makedirs(usbmnt + "/LiveOS")

            if os.path.exists(isodir + "/LiveOS/squashfs.img"):
                shutil.copyfile(isodir + "/LiveOS/squashfs.img",
                                usbmnt + "/LiveOS/squashfs.img")
            else:
                fs_related.mksquashfs(os.path.dirname(self._image),
                                      usbmnt + "/LiveOS/squashfs.img")

            if os.path.exists(isodir + "/LiveOS/osmin.img"):
                shutil.copyfile(isodir + "/LiveOS/osmin.img",
                                usbmnt + "/LiveOS/osmin.img")

            if fstype == "vfat" or fstype == "msdos":
                uuid = usbloop.partitions[0]['mount'].uuid
                label = usbloop.partitions[0]['mount'].fslabel
                usblabel = "UUID=%s-%s" % (uuid[0:4], uuid[4:8])
                overlaysuffix = "-%s-%s-%s" % (label, uuid[0:4], uuid[4:8])
            else:
                diskmount = usbloop.partitions[0]['mount']
                usblabel = "UUID=%s" % diskmount.uuid
                overlaysuffix = "-%s-%s" % (diskmount.fslabel, diskmount.uuid)

            args = ['cp', "-Rf", isodir + "/isolinux", usbmnt + "/syslinux"]
            rc = runner.show(args)
            if rc:
                raise CreatorError("Can't copy isolinux directory %s" \
                                   % (isodir + "/isolinux/*"))

            if os.path.isfile("/usr/share/syslinux/isolinux.bin"):
                syslinux_path = "/usr/share/syslinux"
            elif  os.path.isfile("/usr/lib/syslinux/isolinux.bin"):
                syslinux_path = "/usr/lib/syslinux"
            else:
                raise CreatorError("syslinux not installed : "
                                   "cannot find syslinux installation path")

            for f in ("isolinux.bin", "vesamenu.c32"):
                path = os.path.join(syslinux_path, f)
                if os.path.isfile(path):
                    args = ['cp', path, usbmnt + "/syslinux/"]
                    rc = runner.show(args)
                    if rc:
                        raise CreatorError("Can't copy syslinux file " + path)
                else:
                    raise CreatorError("syslinux not installed: "
                                       "syslinux file %s not found" % path)

            fd = open(isodir + "/isolinux/isolinux.cfg", "r")
            text = fd.read()
            fd.close()
            pattern = re.compile('CDLABEL=[^ ]*')
            text = pattern.sub(usblabel, text)
            pattern = re.compile('rootfstype=[^ ]*')
            text = pattern.sub("rootfstype=" + fstype, text)
            if kernelargs:
                text = text.replace("rd.live.image", "rd.live.image " + kernelargs)

            if overlaysizemb > 0:
                msger.info("Initializing persistent overlay file")
                overfile = "overlay" + overlaysuffix
                if fstype == "vfat":
                    args = ['dd',
                            "if=/dev/zero",
                            "of=" + usbmnt + "/LiveOS/" + overfile,
                            "count=%d" % overlaysizemb,
                            "bs=1M"]
                else:
                    args = ['dd',
                            "if=/dev/null",
                            "of=" + usbmnt + "/LiveOS/" + overfile,
                            "count=1",
                            "bs=1M",
                            "seek=%d" % overlaysizemb]
                rc = runner.show(args)
                if rc:
                    raise CreatorError("Can't create overlay file")
                text = text.replace("rd.live.image", "rd.live.image rd.live.overlay=" + usblabel)
                text = text.replace(" ro ", " rw ")

            if swapsizemb > 0:
                msger.info("Initializing swap file")
                swapfile = usbmnt + "/LiveOS/" + "swap.img"
                args = ['dd',
                        "if=/dev/zero",
                        "of=" + swapfile,
                        "count=%d" % swapsizemb,
                        "bs=1M"]
                rc = runner.show(args)
                if rc:
                    raise CreatorError("Can't create swap file")
                args = ["mkswap", "-f", swapfile]
                rc = runner.show(args)
                if rc:
                    raise CreatorError("Can't mkswap on swap file")

            if homesizemb > 0:
                msger.info("Initializing persistent /home")
                homefile = usbmnt + "/LiveOS/" + homefile
                if fstype == "vfat":
                    args = ['dd',
                            "if=/dev/zero",
                            "of=" + homefile,
                            "count=%d" % homesizemb,
                            "bs=1M"]
                else:
                    args = ['dd',
                            "if=/dev/null",
                            "of=" + homefile,
                            "count=1",
                            "bs=1M",
                            "seek=%d" % homesizemb]
                rc = runner.show(args)
                if rc:
                    raise CreatorError("Can't create home file")

                mkfscmd = fs_related.find_binary_path("/sbin/mkfs." + fstype)
                if fstype == "ext2" or fstype == "ext3":
                    args = [mkfscmd, "-F", "-j", homefile]
                else:
                    args = [mkfscmd, homefile]
                rc = runner.show(args)
                if rc:
                    raise CreatorError("Can't mke2fs home file")
                if fstype == "ext2" or fstype == "ext3":
                    tune2fs = fs_related.find_binary_path("tune2fs")
                    args = [tune2fs,
                            "-c0",
                            "-i0",
                            "-ouser_xattr,acl",
                            homefile]
                    rc = runner.show(args)
                    if rc:
                        raise CreatorError("Can't tune2fs home file")

            if fstype == "vfat" or fstype == "msdos":
                syslinuxcmd = fs_related.find_binary_path("syslinux")
                syslinuxcfg = usbmnt + "/syslinux/syslinux.cfg"
                args = [syslinuxcmd,
                        "-d",
                        "syslinux",
                        usbloop.partitions[0]["device"]]

            elif fstype == "ext2" or fstype == "ext3":
                extlinuxcmd = fs_related.find_binary_path("extlinux")
                syslinuxcfg = usbmnt + "/syslinux/extlinux.conf"
                args = [extlinuxcmd,
                        "-i",
                        usbmnt + "/syslinux"]

            else:
                raise CreatorError("Invalid file system type: %s" % (fstype))

            os.unlink(usbmnt + "/syslinux/isolinux.cfg")
            fd = open(syslinuxcfg, "w")
            fd.write(text)
            fd.close()
            rc = runner.show(args)
            if rc:
                raise CreatorError("Can't install boot loader.")

        finally:
            usbloop.unmount()
            usbloop.cleanup()

        # Need to do this after image is unmounted and device mapper is closed
        msger.info("set MBR")
        mbrfile = "/usr/lib/syslinux/mbr.bin"
        if not os.path.exists(mbrfile):
            mbrfile = "/usr/share/syslinux/mbr.bin"
            if not os.path.exists(mbrfile):
                raise CreatorError("mbr.bin file didn't exist.")
        mbrsize = os.path.getsize(mbrfile)
        outimg = "%s/%s.usbimg" % (self._outdir, self.name)

        args = ['dd',
                "if=" + mbrfile,
                "of=" + outimg,
                "seek=0",
                "conv=notrunc",
                "bs=1",
                "count=%d" % (mbrsize)]
        rc = runner.show(args)
        if rc:
            raise CreatorError("Can't set MBR.")
class DirectImageCreator(BaseImageCreator):
    """
    Installs a system into a file containing a partitioned disk image.

    DirectImageCreator is an advanced ImageCreator subclass; an image
    file is formatted with a partition table, each partition created
    from a rootfs or other OpenEmbedded build artifact and dd'ed into
    the virtual disk. The disk image can subsequently be dd'ed onto
    media and used on actual hardware.
    """
    def __init__(self,
                 oe_builddir,
                 image_output_dir,
                 rootfs_dir,
                 bootimg_dir,
                 kernel_dir,
                 native_sysroot,
                 hdddir,
                 staging_data_dir,
                 creatoropts=None,
                 pkgmgr=None,
                 compress_image=None,
                 generate_bmap=None,
                 fstab_entry="uuid"):
        """
        Initialize a DirectImageCreator instance.

        This method takes the same arguments as ImageCreator.__init__()
        """
        BaseImageCreator.__init__(self, creatoropts, pkgmgr)

        self.__instimage = None
        self.__imgdir = None
        self.__disks = {}
        self.__disk_format = "direct"
        self._disk_names = []
        self._ptable_format = self.ks.handler.bootloader.ptable
        self.use_uuid = fstab_entry == "uuid"
        self.compress_image = compress_image
        self.bmap_needed = generate_bmap

        self.oe_builddir = oe_builddir
        if image_output_dir:
            self.tmpdir = image_output_dir
            self.cachedir = "%s/cache" % image_output_dir
        self.rootfs_dir = rootfs_dir
        self.bootimg_dir = bootimg_dir
        self.kernel_dir = kernel_dir
        self.native_sysroot = native_sysroot
        self.hdddir = hdddir
        self.staging_data_dir = staging_data_dir
        self.boot_type = ""

    def __write_fstab(self):
        """overriden to generate fstab (temporarily) in rootfs. This
        is called from mount_instroot, make sure it doesn't get called
        from BaseImage.mount()"""

        image_rootfs = self.rootfs_dir

        parts = self._get_parts()

        fstab = image_rootfs + "/etc/fstab"

        self._save_fstab(fstab)
        fstab_lines = self._get_fstab(fstab, parts)
        self._update_fstab(fstab_lines, parts)
        self._write_fstab(fstab, fstab_lines)

        return fstab

    def _update_fstab(self, fstab_lines, parts):
        """Assume partition order same as in wks"""
        for num, p in enumerate(parts, 1):
            if p.mountpoint == "/" or p.mountpoint == "/boot":
                continue
            if self._ptable_format == 'msdos' and num > 3:
                device_name = "/dev/" + p.disk + str(num + 1)
            else:
                device_name = "/dev/" + p.disk + str(num)
            fstab_entry = device_name + "\t" + p.mountpoint + "\t" + p.fstype + "\tdefaults\t0\t0\n"
            fstab_lines.append(fstab_entry)

    def _write_fstab(self, fstab, fstab_lines):
        fstab = open(fstab, "w")
        for line in fstab_lines:
            fstab.write(line)
        fstab.close()

    def _save_fstab(self, fstab):
        """Save the current fstab in rootfs"""
        shutil.copyfile(fstab, fstab + ".orig")

    def _restore_fstab(self, fstab):
        """Restore the saved fstab in rootfs"""
        shutil.move(fstab + ".orig", fstab)

    def _get_fstab(self, fstab, parts):
        """Return the desired contents of /etc/fstab."""
        f = open(fstab, "r")
        fstab_contents = f.readlines()
        f.close()

        return fstab_contents

    def _get_parts(self):
        if not self.ks:
            raise CreatorError("Failed to get partition info, "
                               "please check your kickstart setting.")

        # Set a default partition if no partition is given out
        if not self.ks.handler.partition.partitions:
            partstr = "part / --size 1900 --ondisk sda --fstype=ext3"
            args = partstr.split()
            pd = self.ks.handler.partition.parse(args[1:])
            if pd not in self.ks.handler.partition.partitions:
                self.ks.handler.partition.partitions.append(pd)

        # partitions list from kickstart file
        return kickstart.get_partitions(self.ks)

    def get_disk_names(self):
        """ Returns a list of physical target disk names (e.g., 'sdb') which
        will be created. """

        if self._disk_names:
            return self._disk_names

        #get partition info from ks handler
        parts = self._get_parts()

        for i in range(len(parts)):
            if parts[i].disk:
                disk_name = parts[i].disk
            else:
                raise CreatorError("Failed to create disks, no --ondisk "
                                   "specified in partition line of ks file")

            if parts[i].mountpoint and not parts[i].fstype:
                raise CreatorError("Failed to create disks, no --fstype "
                                   "specified for partition with mountpoint "
                                   "'%s' in the ks file")

            self._disk_names.append(disk_name)

        return self._disk_names

    def _full_name(self, name, extention):
        """ Construct full file name for a file we generate. """
        return "%s-%s.%s" % (self.name, name, extention)

    def _full_path(self, path, name, extention):
        """ Construct full file path to a file we generate. """
        return os.path.join(path, self._full_name(name, extention))

    def get_boot_type(self):
        """ Determine the boot type from fstype and mountpoint. """
        parts = self._get_parts()

        boot_type = ""

        for p in parts:
            if p.mountpoint == "/boot":
                if p.fstype == "msdos":
                    boot_type = "pcbios"
                else:
                    boot_type = p.fstype
        return boot_type

    #
    # Actual implemention
    #
    def _mount_instroot(self, base_on=None):
        """
        For 'wic', we already have our build artifacts and don't want
        to loop mount anything to install into, we just create
        filesystems from the artifacts directly and combine them into
        a partitioned image.

        We still want to reuse as much of the basic mic machinery
        though; despite the fact that we don't actually do loop or any
        other kind of mounting we still want to do many of the same
        things to prepare images, so we basically just adapt to the
        basic framework and reinterpret what 'mounting' means in our
        context.

        _instroot would normally be something like
        /var/tmp/wic/build/imgcreate-s_9AKQ/install_root, for
        installing packages, etc.  We don't currently need to do that,
        so we simplify life by just using /var/tmp/wic/build as our
        workdir.
        """
        parts = self._get_parts()

        self.__instimage = PartitionedMount(self._instroot)

        fstab = self.__write_fstab()

        self.boot_type = self.get_boot_type()

        if not self.bootimg_dir:
            if self.boot_type == "pcbios":
                self.bootimg_dir = self.staging_data_dir
            elif self.boot_type == "efi":
                self.bootimg_dir = self.hdddir

        if self.boot_type == "pcbios":
            self._create_syslinux_config()
        elif self.boot_type == "efi":
            self._create_grubefi_config()
        else:
            raise CreatorError(
                "Failed to detect boot type (no /boot partition?), "
                "please check your kickstart setting.")

        for p in parts:
            if p.fstype == "efi":
                p.fstype = "msdos"
            # need to create the filesystems in order to get their
            # sizes before we can add them and do the layout.
            # PartitionedMount.mount() actually calls __format_disks()
            # to create the disk images and carve out the partitions,
            # then self.install() calls PartitionedMount.install()
            # which calls __install_partitition() for each partition
            # to dd the fs into the partitions.  It would be nice to
            # be able to use e.g. ExtDiskMount etc to create the
            # filesystems, since that's where existing e.g. mkfs code
            # is, but those are only created after __format_disks()
            # which needs the partition sizes so needs them created
            # before its called.  Well, the existing setup is geared
            # to installing packages into mounted filesystems - maybe
            # when/if we need to actually do package selection we
            # should modify things to use those objects, but for now
            # we can avoid that.
            p.prepare(self.workdir, self.oe_builddir, self.boot_type,
                      self.rootfs_dir, self.bootimg_dir, self.kernel_dir,
                      self.native_sysroot)

            self.__instimage.add_partition(int(p.size),
                                           p.disk,
                                           p.mountpoint,
                                           p.source_file,
                                           p.fstype,
                                           p.label,
                                           fsopts=p.fsopts,
                                           boot=p.active,
                                           align=p.align,
                                           part_type=p.part_type)
        self._restore_fstab(fstab)
        self.__instimage.layout_partitions(self._ptable_format)

        self.__imgdir = self.workdir
        for disk_name, disk in self.__instimage.disks.items():
            full_path = self._full_path(self.__imgdir, disk_name, "direct")
            msger.debug("Adding disk %s as %s with size %s bytes" \
                        % (disk_name, full_path, disk['min_size']))
            disk_obj = fs_related.DiskImage(full_path, disk['min_size'])
            self.__disks[disk_name] = disk_obj
            self.__instimage.add_disk(disk_name, disk_obj)

        self.__instimage.mount()

    def install(self, repo_urls=None):
        """
        Install fs images into partitions
        """
        for disk_name, disk in self.__instimage.disks.items():
            full_path = self._full_path(self.__imgdir, disk_name, "direct")
            msger.debug("Installing disk %s as %s with size %s bytes" \
                        % (disk_name, full_path, disk['min_size']))
            self.__instimage.install(full_path)

    def configure(self, repodata=None):
        """
        Configure the system image according to kickstart.

        For now, it just prepares the image to be bootable by e.g.
        creating and installing a bootloader configuration.
        """
        if self.boot_type == "pcbios":
            self._install_syslinux()

    def print_outimage_info(self):
        """
        Print the image(s) and artifacts used, for the user.
        """
        msg = "The new image(s) can be found here:\n"

        for disk_name, disk in self.__instimage.disks.items():
            full_path = self._full_path(self.__imgdir, disk_name, "direct")
            msg += '  %s\n\n' % full_path

        msg += 'The following build artifacts were used to create the image(s):\n'
        msg += '  ROOTFS_DIR:      %s\n' % self.rootfs_dir
        msg += '  BOOTIMG_DIR:     %s\n' % self.bootimg_dir
        msg += '  KERNEL_DIR:      %s\n' % self.kernel_dir
        msg += '  NATIVE_SYSROOT:  %s\n' % self.native_sysroot

        msger.info(msg)

    def _get_boot_config(self):
        """
        Return the rootdev/root_part_uuid (if specified by
        --part-type)

        Assume partition order same as in wks
        """
        rootdev = None
        root_part_uuid = None
        parts = self._get_parts()
        for num, p in enumerate(parts, 1):
            if p.mountpoint == "/":
                if self._ptable_format == 'msdos' and num > 3:
                    rootdev = "/dev/%s%-d" % (p.disk, num + 1)
                else:
                    rootdev = "/dev/%s%-d" % (p.disk, num)
                root_part_uuid = p.part_type

        return (rootdev, root_part_uuid)

    def _create_syslinux_config(self):
        hdddir = "%s/hdd/boot" % self.workdir
        rm_cmd = "rm -rf " + self.workdir
        exec_cmd(rm_cmd)

        install_cmd = "install -d %s" % hdddir
        tmp = exec_cmd(install_cmd)

        splash = os.path.join(self.workdir, "/hdd/boot/splash.jpg")
        if os.path.exists(splash):
            splashline = "menu background splash.jpg"
        else:
            splashline = ""

        (rootdev, root_part_uuid) = self._get_boot_config()
        options = self.ks.handler.bootloader.appendLine

        syslinux_conf = ""
        syslinux_conf += "PROMPT 0\n"
        timeout = kickstart.get_timeout(self.ks)
        if not timeout:
            timeout = 0
        syslinux_conf += "TIMEOUT " + str(timeout) + "\n"
        syslinux_conf += "\n"
        syslinux_conf += "ALLOWOPTIONS 1\n"
        syslinux_conf += "SERIAL 0 115200\n"
        syslinux_conf += "\n"
        if splashline:
            syslinux_conf += "%s\n" % splashline
        syslinux_conf += "DEFAULT boot\n"
        syslinux_conf += "LABEL boot\n"

        kernel = "/vmlinuz"
        syslinux_conf += "KERNEL " + kernel + "\n"

        if self._ptable_format == 'msdos':
            rootstr = rootdev
        else:
            if not root_part_uuid:
                raise MountError("Cannot find the root GPT partition UUID")
            rootstr = "PARTUUID=%s" % root_part_uuid

        syslinux_conf += "APPEND label=boot root=%s %s\n" % (rootstr, options)

        msger.debug("Writing syslinux config %s/hdd/boot/syslinux.cfg" \
                    % self.workdir)
        cfg = open("%s/hdd/boot/syslinux.cfg" % self.workdir, "w")
        cfg.write(syslinux_conf)
        cfg.close()

    def _create_grubefi_config(self):
        hdddir = "%s/hdd/boot" % self.workdir
        rm_cmd = "rm -rf %s" % self.workdir
        exec_cmd(rm_cmd)

        install_cmd = "install -d %s/EFI/BOOT" % hdddir
        tmp = exec_cmd(install_cmd)

        splash = os.path.join(self.workdir, "/EFI/boot/splash.jpg")
        if os.path.exists(splash):
            splashline = "menu background splash.jpg"
        else:
            splashline = ""

        (rootdev, root_part_uuid) = self._get_boot_config()
        options = self.ks.handler.bootloader.appendLine

        grubefi_conf = ""
        grubefi_conf += "serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1\n"
        grubefi_conf += "default=boot\n"
        timeout = kickstart.get_timeout(self.ks)
        if not timeout:
            timeout = 0
        grubefi_conf += "timeout=%s\n" % timeout
        grubefi_conf += "menuentry 'boot'{\n"

        kernel = "/vmlinuz"

        if self._ptable_format == 'msdos':
            rootstr = rootdev
        else:
            if not root_part_uuid:
                raise MountError("Cannot find the root GPT partition UUID")
            rootstr = "PARTUUID=%s" % root_part_uuid

        grubefi_conf += "linux %s root=%s rootwait %s\n" \
            % (kernel, rootstr, options)
        grubefi_conf += "}\n"
        if splashline:
            syslinux_conf += "%s\n" % splashline

        msger.debug("Writing grubefi config %s/hdd/boot/EFI/BOOT/grub.cfg" \
                        % self.workdir)
        cfg = open("%s/hdd/boot/EFI/BOOT/grub.cfg" % self.workdir, "w")
        cfg.write(grubefi_conf)
        cfg.close()

    def _install_syslinux(self):
        mbrfile = "%s/syslinux/" % self.bootimg_dir
        if self._ptable_format == 'gpt':
            mbrfile += "gptmbr.bin"
        else:
            mbrfile += "mbr.bin"

        if not os.path.exists(mbrfile):
            msger.error(
                "Couldn't find %s.  If using the -e option, do you have the right MACHINE set in local.conf?  If not, is the bootimg_dir path correct?"
                % mbrfile)

        for disk_name, disk in self.__instimage.disks.items():
            full_path = self._full_path(self.__imgdir, disk_name, "direct")
            msger.debug("Installing MBR on disk %s as %s with size %s bytes" \
                            % (disk_name, full_path, disk['min_size']))

            rc = runner.show(
                ['dd',
                 'if=%s' % mbrfile,
                 'of=%s' % full_path, 'conv=notrunc'])
            if rc != 0:
                raise MountError("Unable to set MBR to %s" % full_path)

    def _unmount_instroot(self):
        if not self.__instimage is None:
            try:
                self.__instimage.cleanup()
            except MountError, err:
                msger.warning("%s" % err)
Exemple #23
0
    def do_chroot(cls, target, cmd=[]):
        img = target
        imgsize = misc.get_file_size(img) * 1024L * 1024L
        partedcmd = fs_related.find_binary_path("parted")
        disk = fs_related.SparseLoopbackDisk(img, imgsize)
        imgmnt = misc.mkdtemp()
        imgloop = PartitionedMount(imgmnt, skipformat = True)
        imgloop.add_disk('/dev/sdb', disk)
        img_fstype = "ext3"

        msger.info("Partition Table:")
        partnum = []
        for line in runner.outs([partedcmd, "-s", img, "print"]).splitlines():
            # no use strip to keep line output here
            if "Number" in line:
                msger.raw(line)
            if line.strip() and line.strip()[0].isdigit():
                partnum.append(line.strip()[0])
                msger.raw(line)

        rootpart = None
        if len(partnum) > 1:
            rootpart = msger.choice("please choose root partition", partnum)

        # Check the partitions from raw disk.
        # if choose root part, the mark it as mounted
        if rootpart:
            root_mounted = True
        else:
            root_mounted = False
        partition_mounts = 0
        for line in runner.outs([partedcmd,"-s",img,"unit","B","print"]).splitlines():
            line = line.strip()

            # Lines that start with number are the partitions,
            # because parted can be translated we can't refer to any text lines.
            if not line or not line[0].isdigit():
                continue

            # Some vars have extra , as list seperator.
            line = line.replace(",","")

            # Example of parted output lines that are handled:
            # Number  Start        End          Size         Type     File system     Flags
            #  1      512B         3400000511B  3400000000B  primary
            #  2      3400531968B  3656384511B  255852544B   primary  linux-swap(v1)
            #  3      3656384512B  3720347647B  63963136B    primary  fat16           boot, lba

            partition_info = re.split("\s+",line)

            size = partition_info[3].split("B")[0]

            if len(partition_info) < 6 or partition_info[5] in ["boot"]:
                # No filesystem can be found from partition line. Assuming
                # btrfs, because that is the only MeeGo fs that parted does
                # not recognize properly.
                # TODO: Can we make better assumption?
                fstype = "btrfs"
            elif partition_info[5] in ["ext2","ext3","ext4","btrfs"]:
                fstype = partition_info[5]
            elif partition_info[5] in ["fat16","fat32"]:
                fstype = "vfat"
            elif "swap" in partition_info[5]:
                fstype = "swap"
            else:
                raise errors.CreatorError("Could not recognize partition fs type '%s'." % partition_info[5])

            if rootpart and rootpart == line[0]:
                mountpoint = '/'
            elif not root_mounted and fstype in ["ext2","ext3","ext4","btrfs"]:
                # TODO: Check that this is actually the valid root partition from /etc/fstab
                mountpoint = "/"
                root_mounted = True
            elif fstype == "swap":
                mountpoint = "swap"
            else:
                # TODO: Assing better mount points for the rest of the partitions.
                partition_mounts += 1
                mountpoint = "/media/partition_%d" % partition_mounts

            if "boot" in partition_info:
                boot = True
            else:
                boot = False

            msger.verbose("Size: %s Bytes, fstype: %s, mountpoint: %s, boot: %s" % (size, fstype, mountpoint, boot))
            # TODO: add_partition should take bytes as size parameter.
            imgloop.add_partition((int)(size)/1024/1024, "/dev/sdb", mountpoint, fstype = fstype, boot = boot)

        try:
            imgloop.mount()

        except errors.MountError:
            imgloop.cleanup()
            raise

        try:
            if len(cmd) != 0:
                cmdline = ' '.join(cmd)
            else:
                cmdline = "/bin/bash"
            envcmd = fs_related.find_binary_inchroot("env", imgmnt)
            if envcmd:
                cmdline = "%s HOME=/root %s" % (envcmd, cmdline)
            chroot.chroot(imgmnt, None, cmdline)
        except:
            raise errors.CreatorError("Failed to chroot to %s." %img)
        finally:
            chroot.cleanup_after_chroot("img", imgloop, None, imgmnt)
class DirectImageCreator(BaseImageCreator):
    """
    Installs a system into a file containing a partitioned disk image.

    DirectImageCreator is an advanced ImageCreator subclass; an image
    file is formatted with a partition table, each partition created
    from a rootfs or other OpenEmbedded build artifact and dd'ed into
    the virtual disk. The disk image can subsequently be dd'ed onto
    media and used on actual hardware.
    """

    def __init__(self, oe_builddir, image_output_dir, rootfs_dir, bootimg_dir,
                 kernel_dir, native_sysroot, hdddir, staging_data_dir,
                 creatoropts=None, pkgmgr=None, compress_image=None,
                 generate_bmap=None, fstab_entry="uuid"):
        """
        Initialize a DirectImageCreator instance.

        This method takes the same arguments as ImageCreator.__init__()
        """
        BaseImageCreator.__init__(self, creatoropts, pkgmgr)

        self.__instimage = None
        self.__imgdir = None
        self.__disks = {}
        self.__disk_format = "direct"
        self._disk_names = []
        self._ptable_format = self.ks.handler.bootloader.ptable
        self.use_uuid = fstab_entry == "uuid"
        self.compress_image = compress_image
        self.bmap_needed = generate_bmap

        self.oe_builddir = oe_builddir
        if image_output_dir:
            self.tmpdir = image_output_dir
            self.cachedir = "%s/cache" % image_output_dir
        self.rootfs_dir = rootfs_dir
        self.bootimg_dir = bootimg_dir
        self.kernel_dir = kernel_dir
        self.native_sysroot = native_sysroot
        self.hdddir = hdddir
        self.staging_data_dir = staging_data_dir
        self.boot_type = ""

    def __write_fstab(self):
        """overriden to generate fstab (temporarily) in rootfs. This
        is called from mount_instroot, make sure it doesn't get called
        from BaseImage.mount()"""

        image_rootfs = self.rootfs_dir

        parts = self._get_parts()

        fstab = image_rootfs + "/etc/fstab"

        self._save_fstab(fstab)
        fstab_lines = self._get_fstab(fstab, parts)
        self._update_fstab(fstab_lines, parts)
        self._write_fstab(fstab, fstab_lines)

        return fstab

    def _update_fstab(self, fstab_lines, parts):
        """Assume partition order same as in wks"""
        for num, p in enumerate(parts, 1):
            if p.mountpoint == "/" or p.mountpoint == "/boot":
                continue
            if self._ptable_format == 'msdos' and num > 3:
                device_name = "/dev/" + p.disk + str(num + 1)
            else:
                device_name = "/dev/" + p.disk + str(num)
            fstab_entry = device_name + "\t" + p.mountpoint + "\t" + p.fstype + "\tdefaults\t0\t0\n"
            fstab_lines.append(fstab_entry)

    def _write_fstab(self, fstab, fstab_lines):
        fstab = open(fstab, "w")
        for line in fstab_lines:
            fstab.write(line)
        fstab.close()

    def _save_fstab(self, fstab):
        """Save the current fstab in rootfs"""
        shutil.copyfile(fstab, fstab + ".orig")

    def _restore_fstab(self, fstab):
        """Restore the saved fstab in rootfs"""
        shutil.move(fstab + ".orig", fstab)

    def _get_fstab(self, fstab, parts):
        """Return the desired contents of /etc/fstab."""
        f = open(fstab, "r")
        fstab_contents = f.readlines()
        f.close()

        return fstab_contents

    def _get_parts(self):
        if not self.ks:
            raise CreatorError("Failed to get partition info, "
                               "please check your kickstart setting.")

        # Set a default partition if no partition is given out
        if not self.ks.handler.partition.partitions:
            partstr = "part / --size 1900 --ondisk sda --fstype=ext3"
            args = partstr.split()
            pd = self.ks.handler.partition.parse(args[1:])
            if pd not in self.ks.handler.partition.partitions:
                self.ks.handler.partition.partitions.append(pd)

        # partitions list from kickstart file
        return kickstart.get_partitions(self.ks)

    def get_disk_names(self):
        """ Returns a list of physical target disk names (e.g., 'sdb') which
        will be created. """

        if self._disk_names:
            return self._disk_names

        #get partition info from ks handler
        parts = self._get_parts()

        for i in range(len(parts)):
            if parts[i].disk:
                disk_name = parts[i].disk
            else:
                raise CreatorError("Failed to create disks, no --ondisk "
                                   "specified in partition line of ks file")

            if parts[i].mountpoint and not parts[i].fstype:
                raise CreatorError("Failed to create disks, no --fstype "
                                    "specified for partition with mountpoint "
                                    "'%s' in the ks file")

            self._disk_names.append(disk_name)

        return self._disk_names

    def _full_name(self, name, extention):
        """ Construct full file name for a file we generate. """
        return "%s-%s.%s" % (self.name, name, extention)

    def _full_path(self, path, name, extention):
        """ Construct full file path to a file we generate. """
        return os.path.join(path, self._full_name(name, extention))

    def get_boot_type(self):
        """ Determine the boot type from fstype and mountpoint. """
        parts = self._get_parts()

        boot_type = ""

        for p in parts:
            if p.mountpoint == "/boot":
                if p.fstype == "msdos":
                    boot_type = "pcbios"
                else:
                    boot_type = p.fstype
        return boot_type

    #
    # Actual implemention
    #
    def _mount_instroot(self, base_on = None):
        """
        For 'wic', we already have our build artifacts and don't want
        to loop mount anything to install into, we just create
        filesystems from the artifacts directly and combine them into
        a partitioned image.

        We still want to reuse as much of the basic mic machinery
        though; despite the fact that we don't actually do loop or any
        other kind of mounting we still want to do many of the same
        things to prepare images, so we basically just adapt to the
        basic framework and reinterpret what 'mounting' means in our
        context.

        _instroot would normally be something like
        /var/tmp/wic/build/imgcreate-s_9AKQ/install_root, for
        installing packages, etc.  We don't currently need to do that,
        so we simplify life by just using /var/tmp/wic/build as our
        workdir.
        """
        parts = self._get_parts()

        self.__instimage = PartitionedMount(self._instroot)

        fstab = self.__write_fstab()

        self.boot_type = self.get_boot_type()

        if not self.bootimg_dir:
            if self.boot_type == "pcbios":
                self.bootimg_dir = self.staging_data_dir
            elif self.boot_type == "efi":
                self.bootimg_dir = self.hdddir

        if self.boot_type == "pcbios":
            self._create_syslinux_config()
        elif self.boot_type == "efi":
            self._create_grubefi_config()
        else:
            raise CreatorError("Failed to detect boot type (no /boot partition?), "
                               "please check your kickstart setting.")

        for p in parts:
            if p.fstype == "efi":
                p.fstype = "msdos"
            # need to create the filesystems in order to get their
            # sizes before we can add them and do the layout.
            # PartitionedMount.mount() actually calls __format_disks()
            # to create the disk images and carve out the partitions,
            # then self.install() calls PartitionedMount.install()
            # which calls __install_partitition() for each partition
            # to dd the fs into the partitions.  It would be nice to
            # be able to use e.g. ExtDiskMount etc to create the
            # filesystems, since that's where existing e.g. mkfs code
            # is, but those are only created after __format_disks()
            # which needs the partition sizes so needs them created
            # before its called.  Well, the existing setup is geared
            # to installing packages into mounted filesystems - maybe
            # when/if we need to actually do package selection we
            # should modify things to use those objects, but for now
            # we can avoid that.
            p.prepare(self.workdir, self.oe_builddir, self.boot_type,
                      self.rootfs_dir, self.bootimg_dir, self.kernel_dir,
                      self.native_sysroot)

            self.__instimage.add_partition(int(p.size),
                                           p.disk,
                                           p.mountpoint,
                                           p.source_file,
                                           p.fstype,
                                           p.label,
                                           fsopts = p.fsopts,
                                           boot = p.active,
                                           align = p.align,
                                           part_type = p.part_type)
        self._restore_fstab(fstab)
        self.__instimage.layout_partitions(self._ptable_format)

        self.__imgdir = self.workdir
        for disk_name, disk in self.__instimage.disks.items():
            full_path = self._full_path(self.__imgdir, disk_name, "direct")
            msger.debug("Adding disk %s as %s with size %s bytes" \
                        % (disk_name, full_path, disk['min_size']))
            disk_obj = fs_related.DiskImage(full_path, disk['min_size'])
            self.__disks[disk_name] = disk_obj
            self.__instimage.add_disk(disk_name, disk_obj)

        self.__instimage.mount()

    def install(self, repo_urls=None):
        """
        Install fs images into partitions
        """
        for disk_name, disk in self.__instimage.disks.items():
            full_path = self._full_path(self.__imgdir, disk_name, "direct")
            msger.debug("Installing disk %s as %s with size %s bytes" \
                        % (disk_name, full_path, disk['min_size']))
            self.__instimage.install(full_path)

    def configure(self, repodata = None):
        """
        Configure the system image according to kickstart.

        For now, it just prepares the image to be bootable by e.g.
        creating and installing a bootloader configuration.
        """
        if self.boot_type == "pcbios":
            self._install_syslinux()

    def print_outimage_info(self):
        """
        Print the image(s) and artifacts used, for the user.
        """
        msg = "The new image(s) can be found here:\n"

        for disk_name, disk in self.__instimage.disks.items():
            full_path = self._full_path(self.__imgdir, disk_name, "direct")
            msg += '  %s\n\n' % full_path

        msg += 'The following build artifacts were used to create the image(s):\n'
        msg += '  ROOTFS_DIR:      %s\n' % self.rootfs_dir
        msg += '  BOOTIMG_DIR:     %s\n' % self.bootimg_dir
        msg += '  KERNEL_DIR:      %s\n' % self.kernel_dir
        msg += '  NATIVE_SYSROOT:  %s\n' % self.native_sysroot

        msger.info(msg)

    def _get_boot_config(self):
        """
        Return the rootdev/root_part_uuid (if specified by
        --part-type)

        Assume partition order same as in wks
        """
        rootdev = None
        root_part_uuid = None
        parts = self._get_parts()
        for num, p in enumerate(parts, 1):
            if p.mountpoint == "/":
                if self._ptable_format == 'msdos' and num > 3:
                    rootdev = "/dev/%s%-d" % (p.disk, num + 1)
                else:
                    rootdev = "/dev/%s%-d" % (p.disk, num)
                root_part_uuid = p.part_type

        return (rootdev, root_part_uuid)

    def _create_syslinux_config(self):
        hdddir = "%s/hdd/boot" % self.workdir
        rm_cmd = "rm -rf " + self.workdir
        exec_cmd(rm_cmd)

        install_cmd = "install -d %s" % hdddir
        tmp = exec_cmd(install_cmd)

        splash = os.path.join(self.workdir, "/hdd/boot/splash.jpg")
        if os.path.exists(splash):
            splashline = "menu background splash.jpg"
        else:
            splashline = ""

        (rootdev, root_part_uuid) = self._get_boot_config()
        options = self.ks.handler.bootloader.appendLine

        syslinux_conf = ""
        syslinux_conf += "PROMPT 0\n"
        timeout = kickstart.get_timeout(self.ks)
        if not timeout:
            timeout = 0
        syslinux_conf += "TIMEOUT " + str(timeout) + "\n"
        syslinux_conf += "\n"
        syslinux_conf += "ALLOWOPTIONS 1\n"
        syslinux_conf += "SERIAL 0 115200\n"
        syslinux_conf += "\n"
        if splashline:
            syslinux_conf += "%s\n" % splashline
        syslinux_conf += "DEFAULT boot\n"
        syslinux_conf += "LABEL boot\n"

        kernel = "/vmlinuz"
        syslinux_conf += "KERNEL " + kernel + "\n"

        if self._ptable_format == 'msdos':
            rootstr = rootdev
        else:
            if not root_part_uuid:
                raise MountError("Cannot find the root GPT partition UUID")
            rootstr = "PARTUUID=%s" % root_part_uuid

        syslinux_conf += "APPEND label=boot root=%s %s\n" % (rootstr, options)

        msger.debug("Writing syslinux config %s/hdd/boot/syslinux.cfg" \
                    % self.workdir)
        cfg = open("%s/hdd/boot/syslinux.cfg" % self.workdir, "w")
        cfg.write(syslinux_conf)
        cfg.close()

    def _create_grubefi_config(self):
        hdddir = "%s/hdd/boot" % self.workdir
        rm_cmd = "rm -rf %s" % self.workdir
        exec_cmd(rm_cmd)

        install_cmd = "install -d %s/EFI/BOOT" % hdddir
        tmp = exec_cmd(install_cmd)

        splash = os.path.join(self.workdir, "/EFI/boot/splash.jpg")
        if os.path.exists(splash):
            splashline = "menu background splash.jpg"
        else:
            splashline = ""

        (rootdev, root_part_uuid) = self._get_boot_config()
        options = self.ks.handler.bootloader.appendLine

        grubefi_conf = ""
        grubefi_conf += "serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1\n"
        grubefi_conf += "default=boot\n"
        timeout = kickstart.get_timeout(self.ks)
        if not timeout:
            timeout = 0
        grubefi_conf += "timeout=%s\n" % timeout
        grubefi_conf += "menuentry 'boot'{\n"

        kernel = "/vmlinuz"

        if self._ptable_format == 'msdos':
            rootstr = rootdev
        else:
            if not root_part_uuid:
                raise MountError("Cannot find the root GPT partition UUID")
            rootstr = "PARTUUID=%s" % root_part_uuid

        grubefi_conf += "linux %s root=%s rootwait %s\n" \
            % (kernel, rootstr, options)
        grubefi_conf += "}\n"
        if splashline:
            syslinux_conf += "%s\n" % splashline

        msger.debug("Writing grubefi config %s/hdd/boot/EFI/BOOT/grub.cfg" \
                        % self.workdir)
        cfg = open("%s/hdd/boot/EFI/BOOT/grub.cfg" % self.workdir, "w")
        cfg.write(grubefi_conf)
        cfg.close()

    def _install_syslinux(self):
        mbrfile = "%s/syslinux/" % self.bootimg_dir
        if self._ptable_format == 'gpt':
            mbrfile += "gptmbr.bin"
        else:
            mbrfile += "mbr.bin"

        if not os.path.exists(mbrfile):
            msger.error("Couldn't find %s.  If using the -e option, do you have the right MACHINE set in local.conf?  If not, is the bootimg_dir path correct?" % mbrfile)

        for disk_name, disk in self.__instimage.disks.items():
            full_path = self._full_path(self.__imgdir, disk_name, "direct")
            msger.debug("Installing MBR on disk %s as %s with size %s bytes" \
                            % (disk_name, full_path, disk['min_size']))

            rc = runner.show(['dd', 'if=%s' % mbrfile,
                              'of=%s' % full_path, 'conv=notrunc'])
            if rc != 0:
                raise MountError("Unable to set MBR to %s" % full_path)

    def _unmount_instroot(self):
        if not self.__instimage is None:
            try:
                self.__instimage.cleanup()
            except MountError, err:
                msger.warning("%s" % err)