Source

vinstall / vinstall / backend / installmedia.py

#-*- coding: utf-8 -*-

"""install media returns a list of install media

"""


import media
from utils import mount, mountiso, umount

import os
import ConfigParser
from itertools import chain
from vinstall.core import log
import platform

__author__ = "Uel Archuletta, Rodrigo Bistolfi"

LOG = log.get_logger("install_media_scanner")

class InstallMedia(object):
    """Represents a source media containing the installer

    """
    @classmethod
    def all(cls):
        """Find install media in devices and partitions

        """
        finders = [ CdRomInstallMediaFinder(), PartitionInstallMediaFinder(), DiskInstallMediaFinder() ]
        return chain(*[i.find() for i in finders])

    def __init__(self, device, path, config):
        """Expose install media base dir and the config object

        """
        self.device = device
        self.path = path
        self.config = config

    def __str__(self):
        if self.is_iso():
            format = "%s %s - ISO on %s"
            path = self.path.rsplit("/", 1)[0] or "/"
        else:
            format = "%s %s on %s"
            path = self.path
        return format % (self.get("general", "distro"),
                self.get("general", "version"), path)

    def __getattr__(self, name):
        """Delegate in config object

        """
        return getattr(self.config, name)

    def is_iso(self):
        """Answer if the installer source is in an iso file

        """
        return self.path.endswith("iso")


class InstallMediaFinder(object):
    "Interface for media finder objects"

    def find(self):
        "Find install media. Return an iterable containing InstallMedia objects"


class CdRomInstallMediaFinder(InstallMediaFinder):
    "Find install media in cdrom devices"

    def __init__(self):
        self.devices = ( cd for cd in media.CDRom.all())
        self.mountpoint = "/tmp/DEVMNT"
        create_mountpoint(self.mountpoint)

    def find(self):
        "Find install media in cdrom devices"
        for cdrom in self.devices:
            LOG.debug("Scanning %s for install media"% cdrom.path())
            needs_umount = False
            mountloc = None
            if cdrom.is_mounted():
                mountloc = cdrom.mountpoint
                needs_umount = False
            else:
                mountloc = cdrom.mount(self.mountpoint)
                needs_umount = True
            
            if mountloc is None:
                LOG.warning("Unable to mount %s to scan for install media."% cdrom.path())

            if is_install_media(mountloc):
                config = parse_config(mountloc)
                LOG.debug("Found install media in %s"% cdrom.path())
                yield InstallMedia(cdrom, cdrom.device_path, config)

            if needs_umount:
                cdrom.umount()


class PartitionInstallMediaFinder(InstallMediaFinder):
    "Find install media in existing partitions"

    def __init__(self):
        self.partitions = media.Partition.all()

    def find(self):
        for partition in self.partitions:
            needs_umount = False
            if not partition.is_mounted():
                partition.mount(partition.mountpoint)
                needs_umount = True
            if is_install_media(partition.mountpoint):
                config = parse_config(partition.mountpoint)
                yield InstallMedia(partition, partition.mountpoint, config)
            else:
                isofinder = ISOInstallMediaFinder(partition)
                for im in isofinder.find():
                    yield im
            if needs_umount:
                partition.umount()

class DiskInstallMediaFinder(InstallMediaFinder):
    "Find install media in existing disks"

    def __init__(self):
        self.partitions = media.Disk.all()

    def find(self):
        for partition in self.partitions:
            needs_umount = False
            try:
                if not partition.is_mounted():
                    partition.mount(partition.mountpoint)
                    needs_umount = True
                if is_install_media(partition.mountpoint):
                    config = parse_config(partition.mountpoint)
                    if isinstance(partition, media.Disk):
                        yield InstallMedia(partition, partition.path(), config)
                    else:
                        yield InstallMedia(partition, partition.mountpoint, config)
                else:
                    isofinder = ISOInstallMediaFinder(partition)
                    for im in isofinder.find():
                        yield im
                if needs_umount:
                    partition.umount()
            except:
                LOG.debug("Could not check %s for install media"% partition.path())
                return


class ISOInstallMediaFinder(InstallMediaFinder):
    "Find install media in ISO files"

    def __init__(self, partition):
        self.partition = partition
        self.root_dir = partition.mountpoint
        self.mountpoint = "/tmp/ISOMNT"
        create_mountpoint(self.mountpoint)

    def find(self):
        for f in os.listdir(self.root_dir):
            if os.path.isfile(os.path.join(self.root_dir, f)) and f.endswith(".iso"):
                isopath = os.path.join(self.root_dir, f)
                mountiso(isopath, self.mountpoint)
                if is_install_media(self.mountpoint):
                    config = parse_config(self.mountpoint)
                    yield InstallMedia(self.partition, isopath, config)
                umount(self.mountpoint)


def parse_config(mnt):
    """ Reads VINSTALL.INI

    """
    conf = "veclinux/VINSTALL.INI"
    config = ConfigParser.RawConfigParser()
    config.optionxform = str
    config.read(os.path.join(mnt,conf))
    return config


def make_mountpoint(device):
    """Create mountpoint for device

    """
    mountpoint = device.replace("/dev", "/mnt")
    if not os.path.exists(mountpoint):
        os.mkdir(mountpoint)


def is_install_media(mnt):
    """ Checks for VINSTALL.INI the install config file added in 6.0

    """
    myplatform = platform.machine()
    config = "veclinux/VINSTALL.INI"
    if myplatform.lower() not in ("x86_64"):
	if os.path.exists(os.path.join(mnt, config)):
	    with open(os.path.join(mnt, config)) as data:
		for line in data:
		    if line.lower().startswith("distro"):
			if "vector" in line.lower():
			    return True
		return False
    else:
	return os.path.exists(os.path.join(mnt, config))


def create_mountpoint(location):
    "Create mountpoint if it doesnt exist"
    try:
        os.mkdir(location)
    except OSError as e:
        if e.errno == 17:
            pass
        else:
            raise e