FAQ Search Today's Posts Mark Forums Read
» Video Reviews

» Linux Archive

Linux-archive is a website aiming to archive linux email lists and to make them easily accessible for linux users/developers.


» Sponsor

» Partners

» Sponsor

Go Back   Linux Archive > Debian > Debian Development

 
 
LinkBack Thread Tools
 
Old 04-01-2011, 07:57 PM
David Lehman
 
Default Update platform.py for new bootloader module.

Remove the vast majority of bootloader-related code and make the
bootloader an attribute of the platform.

Separate X86 from EFI.

Make bootDevice always represent bootloader stage2 device and create
bootLoaderDevice to represent bootloader stage1 device. Make both of
them into properties.

Remove ia64 and alpha platform classes.
---
pyanaconda/platform.py | 521 +++++++++++++-----------------------------------
1 files changed, 134 insertions(+), 387 deletions(-)

diff --git a/pyanaconda/platform.py b/pyanaconda/platform.py
index 3942887..b1fee83 100644
--- a/pyanaconda/platform.py
+++ b/pyanaconda/platform.py
@@ -1,7 +1,7 @@
#
# platform.py: Architecture-specific information
#
-# Copyright (C) 2009
+# Copyright (C) 2009-2011
# Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
@@ -20,12 +20,12 @@
# Authors: Chris Lumens <clumens@redhat.com>
#

+from pyanaconda import bootloader
+
import iutil
-import parted

import gettext
_ = lambda x: gettext.ldgettext("anaconda", x)
-N_ = lambda x: x

class Platform(object):
"""Platform
@@ -34,15 +34,9 @@ class Platform(object):
during installation. The intent is to eventually encapsulate all the
architecture quirks in one place to avoid lots of platform checks
throughout anaconda."""
- _bootFSTypes = ["ext3"]
- _diskLabelType = "msdos"
- _isEfi = iutil.isEfi()
_minimumSector = 0
_packages = []
- _supportsLvmBoot = False
- _supportsMdRaidBoot = False
- _minBootPartSize = 50
- _maxBootPartSize = 0
+ _bootloaderClass = bootloader.BootLoader

def __init__(self, anaconda):
"""Creates a new Platform object. This is basically an abstract class.
@@ -50,106 +44,117 @@ class Platform(object):
returned by getPlatform below. Not all subclasses need to provide
all the methods in this class."""
self.anaconda = anaconda
+ self.bootloader = self._bootloaderClass(storage=getattr(anaconda,
+ "storage",
+ None))

- def _mntDict(self):
- """Return a dictionary mapping mount points to devices."""
- ret = {}
- for device in [d for d in self.anaconda.storage.devices if d.format.mountable]:
- ret[device.format.mountpoint] = device
-
- return ret
-
+ @property
def bootDevice(self):
- """Return the device where /boot is mounted."""
- if self.__class__ is Platform:
- raise NotImplementedError("bootDevice not implemented for this platform")
+ """The device that includes the /boot filesystem."""
+ return self.bootloader.stage2_device

- mntDict = self._mntDict()
- return mntDict.get("/boot", mntDict.get("/"))
+ @property
+ def bootLoaderDevice(self):
+ """The device the bootloader will be installed into."""
+ return self.bootloader.stage1_device
+
+ @property
+ def bootFSTypes(self):
+ """A list of all valid filesystem types for the boot partition."""
+ return self.bootloader.linux_boot_device_format_types

@property
def defaultBootFSType(self):
- """Return the default filesystem type for the boot partition."""
- return self._bootFSTypes[0]
+ """The default filesystem type for the boot partition."""
+ return self.bootFSTypes[0]

@property
- def bootFSTypes(self):
- """Return a list of all valid filesystem types for the boot partition."""
- return self._bootFSTypes
-
- def bootloaderChoices(self, bl):
- """Return the default list of places to install the bootloader.
- This is returned as a dictionary of locations to (device, identifier)
- tuples. If there is no boot device, an empty dictionary is
- returned."""
- if self.__class__ is Platform:
- raise NotImplementedError("bootloaderChoices not implemented for this platform")
-
- bootDev = self.bootDevice()
- ret = {}
-
- if not bootDev:
- return ret
-
- if bootDev.type == "mdarray":
- ret["boot"] = (bootDev.name, N_("RAID Device"))
- ret["mbr"] = (bl.drivelist[0], N_("Master Boot Record (MBR)"))
- else:
- ret["boot"] = (bootDev.name, N_("First sector of boot partition"))
- ret["mbr"] = (bl.drivelist[0], N_("Master Boot Record (MBR)"))
+ def diskLabelTypes(self):
+ """A list of valid disklabel types for this architecture."""
+ return self.bootloader.target_device_disklabel_types

- return ret
+ @property
+ def defaultDiskLabelType(self):
+ """The default disklabel type for this architecture."""
+ return self.diskLabelTypes[0]
+
+ def diskLabelType(self, device_type):
+ """The default disklabel type for the specified device type."""
+ return self.defaultDiskLabelType
+
+ def checkDiskLabel(self, req):
+ """Check the disk containing req for the correct disklabel type.
+
+ Return a list of error strings if incorrect disklabels are found."""
+ errors = []
+ if not self.bootloader.target_device_disklabel_types:
+ return errors

- def checkBootRequest(self, req):
+ for disk in req.disks:
+ labelType = disk.format.labelType
+ labelTypes = self.bootloader.target_device_disklabel_types
+ if labelType not in labelTypes:
+ errors.append(_("%s must have a %s disk label.")
+ % (disk.name,
+ " or ".join([t.upper() for t in labelTypes])))
+ return errors
+
+ def checkBootRequest(self):
"""Perform an architecture-specific check on the boot device. Not all
platforms may need to do any checks. Returns a list of errors if
there is a problem, or [] otherwise."""
errors = []

+ req = self.bootDevice
if not req:
return [_("You have not created a bootable partition.")]

- # most arches can't have boot on RAID
- if req.type == "mdarray":
- if not self.supportsMdRaidBoot:
- errors.append(_("Bootable partitions cannot be on a RAID device."))
- elif req.type == "mdarray" and req.level != 1:
- errors.append(_("Bootable partitions can only be on RAID1 devices."))
- else:
- for p in req.parents:
- if p.type != "partition":
- errors.append(_("Bootable RAID1 set members must be partitions."))
- break
-
- # most arches can't have boot on a logical volume
- if req.type == "lvmlv" and not self.supportsLvmBoot:
- errors.append(_("Bootable partitions cannot be on a logical volume."))
+ # TODO: reimplement BootLoader._device_is_bootable(req, linux=True)
+ # such that it returns a list of error strings instead of
+ # True/False
+
+ if req.type not in self.bootloader.boot_device_types:
+ errors.append(_("The /boot filesystem cannot be on devices of "
+ "type %s") % req.type)
+ elif req.type == "mdarray":
+ raid_levels = self.bootloader.boot_device_raid_levels
+ if req.level not in raid_levels:
+ levels = ",".join(["RAID%d" % l for l in raid_levels])
+ errors.append(_("RAID sets containing the /boot filesystem "
+ "must have one of the following raid levels: "
+ "%s.") % levels)
+
+ for p in req.parents:
+ if p.type != "partition":
+ errors.append(_("RAID sets containing the /boot "
+ "filesystem may only have partitions "
+ "as member devices."))
+ break

# Make sure /boot is on a supported FS type. This prevents crazy
# things like boot on vfat.
if not req.format.bootable or
- (getattr(req.format, "mountpoint", None) == "/boot" and
- req.format.type not in self.bootFSTypes):
- errors.append(_("Bootable partitions cannot be on an %s filesystem.") % req.format.type)
+ req.format.type not in self.bootFSTypes:
+ errors.append(_("The /boot filesystem cannot be of type %s.") % req.format.type)

if req.type == "luks/dm-crypt":
# Handle encrypted boot on a partition.
- errors.append(_("Bootable partitions cannot be on an encrypted block device"))
+ errors.append(_("The /boot filesystem cannot be on an encrypted block device"))
else:
# Handle encrypted boot on more complicated devices.
for dev in filter(lambda d: d.type == "luks/dm-crypt", self.anaconda.storage.devices):
if req in self.anaconda.storage.deviceDeps(dev):
- errors.append(_("Bootable partitions cannot be on an encrypted block device"))
+ errors.append(_("The /boot filesystem cannot be on an encrypted block device"))

+ errors.extend(self.checkDiskLabel(req))
return errors

- def diskLabelType(self, deviceType):
- """Return the disk label type as a string."""
- return self._diskLabelType
+ def checkBootLoaderRequest(self):
+ """ Perform architecture-specific checks on the bootloader device.

- @property
- def isEfi(self):
- return self._isEfi
+ Returns a list of error strings.
+ """
+ return self.checkDiskLabel(self.bootLoaderDevice)

@property
def minimumSector(self, disk):
@@ -158,7 +163,7 @@ class Platform(object):

@property
def packages (self):
- return self._packages
+ return self._packages + self.bootloader.packages

def setDefaultPartitioning(self):
"""Return the default platform-specific partitioning information."""
@@ -166,102 +171,32 @@ class Platform(object):
return [PartSpec(mountpoint="/boot", fstype=self.defaultBootFSType, size=500,
weight=self.weight(mountpoint="/boot"))]

- @property
- def supportsLvmBoot(self):
- """Does the platform support /boot on LVM logical volume?"""
- return self._supportsLvmBoot
-
- @property
- def supportsMdRaidBoot(self):
- """Does the platform support /boot on MD RAID?"""
- return self._supportsMdRaidBoot
-
- @property
- def minBootPartSize(self):
- return self._minBootPartSize
-
- @property
- def maxBootPartSize(self):
- return self._maxBootPartSize
-
- def validBootPartSize(self, size):
- """ Is the given size (in MB) acceptable for a boot device? """
+ def validBootLoaderPartSize(self, size):
+ """ Is the given size (in MB) acceptable for a bootloader device? """
if not isinstance(size, int) and not isinstance(size, float):
return False

- return ((not self.minBootPartSize or size >= self.minBootPartSize)
+ return ((self.bootloader.target_device_min_size is None or
+ size >= self.bootloader.target_device_min_size)
and
- (not self.maxBootPartSize or size <= self.maxBootPartSize))
+ (self.bootloader.target_device_max_size is None or
+ size <= self.bootloader.target_device_max_size))

def weight(self, fstype=None, mountpoint=None):
""" Given an fstype (as a string) or a mountpoint, return an integer
for the base sorting weight. This is used to modify the sort
algorithm for partition requests, mainly to make sure bootable
partitions and /boot are placed where they need to be."""
- return 0
-
-class EFI(Platform):
- _bootFSTypes = ["ext4", "ext3", "ext2"]
- _diskLabelType = "gpt"
- _minBootPartSize = 50
- _maxBootPartSize = 256
-
- def bootDevice(self):
- bootDev = None
-
- for part in self.anaconda.storage.partitions:
- if part.format.type == "efi" and self.validBootPartSize(part.size):
- bootDev = part
- # if we're only picking one, it might as well be the first
- break
-
- return bootDev
-
- def bootloaderChoices(self, bl):
- bootDev = self.bootDevice()
- ret = {}
-
- if not bootDev:
- return ret
-
- ret["boot"] = (bootDev.name, N_("EFI System Partition"))
- return ret
-
- def checkBootRequest(self, req):
- """ Perform architecture-specific checks on the boot device.
-
- Returns a list of error strings.
-
- NOTE: X86 does not have a separate checkBootRequest method,
- so this one must work for x86 as well as EFI.
- """
- if not req:
- return [_("You have not created a /boot/efi partition.")]
-
- errors = Platform.checkBootRequest(self, req)
-
- if req.format.mountpoint == "/boot/efi":
- if req.format.type != "efi":
- errors.append(_("/boot/efi is not EFI."))
+ if fstype in self.bootFSTypes and mountpoint == "/boot":
+ return 2000
+ else:
+ return 0

- # Don't try to check the disklabel on lv's etc, using lv for /boot
- # is already checked in the generic Platform.checkBootRequest()
- partitions = []
- if req.type == "partition":
- partitions = [ req ]
- elif req.type == "mdarray":
- partitions = filter(lambda d: d.type == "partition", req.parents)
-
- # Check that we've got a correct disk label.
- for p in partitions:
- partedDisk = p.disk.format.partedDisk
- labelType = self.diskLabelType(partedDisk.device.type)
- # Allow using gpt with x86, but not msdos with EFI
- if partedDisk.type != labelType and partedDisk.type != "gpt":
- errors.append(_("%s must have a %s disk label.")
- % (p.disk.name, labelType.upper()))
+class X86(Platform):
+ _bootloaderClass = bootloader.GRUB

- return errors
+class EFI(Platform):
+ _bootloaderClass = bootloader.EFIGRUB

def setDefaultPartitioning(self):
from storage.partspec import PartSpec
@@ -271,110 +206,37 @@ class EFI(Platform):
return ret

def weight(self, fstype=None, mountpoint=None):
- if fstype and fstype == "efi" or mountpoint and mountpoint == "/boot/efi":
+ score = Platform.weight(self, fstype=fstype, mountpoint=mountpoint)
+ if score:
+ return score
+ elif fstype == "efi" or mountpoint == "/boot/efi":
return 5000
- elif mountpoint and mountpoint == "/boot":
- return 2000
else:
return 0

-class Alpha(Platform):
- _diskLabelType = "bsd"
-
- def checkBootRequest(self, req):
- errors = Platform.checkBootRequest(self, req)
-
- if not req or req.type != "partition" or not req.disk:
- return errors
-
- disk = req.disk.format.partedDisk
-
- # Check that we're a BSD disk label
- if not disk.type == self._diskLabelType:
- errors.append(_("%s must have a bsd disk label.") % req.disk.name)
-
- # The first free space should start at the beginning of the drive and
- # span for a megabyte or more.
- free = disk.getFirstPartition()
- while free:
- if free.type & parted.PARTITION_FREESPACE:
- break
-
- free = free.nextPartition()
-
- if not free or free.geoemtry.start != 1L or free.getSize(unit="MB") < 1:
- errors.append(_("The disk %s requires at least 1MB of free space at the beginning.") % req.disk.name)
-
- return errors
-
-class IA64(EFI):
- _packages = ["elilo"]
-
- def __init__(self, anaconda):
- EFI.__init__(self, anaconda)
-
class PPC(Platform):
- _bootFSTypes = ["ext4", "ext3", "ext2"]
- _packages = ["yaboot"]
_ppcMachine = iutil.getPPCMachine()
- _supportsMdRaidBoot = True
+ _bootloaderClass = bootloader.Yaboot

@property
def ppcMachine(self):
return self._ppcMachine

class IPSeriesPPC(PPC):
- _minBootPartSize = 4
- _maxBootPartSize = 10
-
- def bootDevice(self):
- bootDev = None
-
- # We want the first PReP partition.
- for device in self.anaconda.storage.partitions:
- if device.format.type == "prepboot":
- bootDev = device
- break
-
- return bootDev
-
- def bootloaderChoices(self, bl):
- ret = {}
+ _bootloaderClass = bootloader.IPSeriesYaboot

- bootDev = self.bootDevice()
- if not bootDev:
- return ret
-
- if bootDev.type == "mdarray":
- ret["boot"] = (bootDev.name, N_("RAID Device"))
- ret["mbr"] = (bl.drivelist[0], N_("Master Boot Record (MBR)"))
- else:
- ret["boot"] = (bootDev.name, N_("PPC PReP Boot"))
-
- return ret
-
- def checkBootRequest(self, req):
- errors = PPC.checkBootRequest(self, req)
+ def checkBootLoaderRequest(self):
+ req = self.bootLoaderDevice
+ errors = PPC.checkBootLoaderRequest(self)

bootPart = getattr(req, "partedPartition", None)
if not bootPart:
return errors

- # All of the above just checks the PPC PReP boot partitions. We still
- # need to make sure that whatever /boot is on also meets these criteria.
- if req == self.bootDevice():
- # However, this check only applies to prepboot.
- if bootPart.geometry.end * bootPart.geometry.device.sectorSize / (1024.0 * 1024) > 4096:
- errors.append(_("The boot partition must be within the first 4MB of the disk."))
+ if bootPart.geometry.end * bootPart.geometry.device.sectorSize / (1024.0 * 1024) > 10:
+ errors.append(_("The boot partition must be within the first 10MB of the disk."))

- try:
- req = self.anaconda.storage.mountpoints["/boot"]
- except KeyError:
- req = self.anaconda.storage.rootDevice
-
- return errors + self.checkBootRequest(req)
- else:
- return errors
+ return errors

def setDefaultPartitioning(self):
from storage.partspec import PartSpec
@@ -384,70 +246,25 @@ class IPSeriesPPC(PPC):
return ret

def weight(self, fstype=None, mountpoint=None):
- if fstype and fstype == "prepboot":
+ score = Platform.weight(self, fstype=fstype, mountpoint=mountpoint)
+ if score:
+ return score
+ elif fstype == "prepboot":
return 5000
- elif mountpoint and mountpoint == "/boot":
- return 2000
else:
return 0

class NewWorldPPC(PPC):
- _diskLabelType = "mac"
- _minBootPartSize = (800.00 / 1024.00)
- _maxBootPartSize = 1
-
- def bootDevice(self):
- bootDev = None
-
- for part in self.anaconda.storage.partitions:
- if part.format.type == "appleboot" and self.validBootPartSize(part.size):
- bootDev = part
- # if we're only picking one, it might as well be the first
- break
-
- return bootDev
-
- def bootloaderChoices(self, bl):
- ret = {}
-
- bootDev = self.bootDevice()
- if not bootDev:
- return ret
-
- if bootDev.type == "mdarray":
- ret["boot"] = (bootDev.name, N_("RAID Device"))
- ret["mbr"] = (bl.drivelist[0], N_("Master Boot Record (MBR)"))
- else:
- ret["boot"] = (bootDev.name, N_("Apple Bootstrap"))
- for (n, device) in enumerate(self.anaconda.storage.partitions):
- if device.format.type == "appleboot" and device.path != bootDev.path:
- ret["boot%d" % n] = (device.path, N_("Apple Bootstrap"))
+ _bootloaderClass = bootloader.MacYaboot

- return ret
-
- def checkBootRequest(self, req):
- errors = PPC.checkBootRequest(self, req)
+ def checkBootLoaderRequest(self):
+ req = self.bootLoaderDevice
+ errors = PPC.checkBootLoaderRequest(self)

if not req or req.type != "partition" or not req.disk:
return errors

- disk = req.disk.format.partedDisk
-
- # Check that we're a Mac disk label
- if not disk.type == self._diskLabelType:
- errors.append(_("%s must have a mac disk label.") % req.disk.name)
-
- # All of the above just checks the appleboot partitions. We still
- # need to make sure that whatever /boot is on also meets these criteria.
- if req == self.bootDevice():
- try:
- req = self.anaconda.storage.mountpoints["/boot"]
- except KeyError:
- req = self.anaconda.storage.rootDevice
-
- return errors + self.checkBootRequest(req)
- else:
- return errors
+ return errors

def setDefaultPartitioning(self):
from storage.partspec import PartSpec
@@ -457,34 +274,24 @@ class NewWorldPPC(PPC):
return ret

def weight(self, fstype=None, mountpoint=None):
- if fstype and fstype == "appleboot":
+ score = Platform.weight(self, fstype=fstype, mountpoint=mountpoint)
+ if score:
+ return score
+ elif fstype == "appleboot":
return 5000
- elif mountpoint and mountpoint == "/boot":
- return 2000
else:
return 0

class PS3(PPC):
- _diskLabelType = "msdos"
-
- def __init__(self, anaconda):
- PPC.__init__(self, anaconda)
+ pass

class S390(Platform):
- _bootFSTypes = ["ext4", "ext3", "ext2"]
+ _bootloaderClass = bootloader.ZIPL
_packages = ["s390utils"]
- _supportsLvmBoot = True

def __init__(self, anaconda):
Platform.__init__(self, anaconda)

- def diskLabelType(self, deviceType):
- """Return the disk label type as a string."""
- if deviceType == parted.DEVICE_DASD:
- return "dasd"
- else:
- return Platform.diskLabelType(self, deviceType)
-
def setDefaultPartitioning(self):
"""Return the default platform-specific partitioning information."""
from storage.partspec import PartSpec
@@ -492,15 +299,15 @@ class S390(Platform):
weight=self.weight(mountpoint="/boot"), asVol=True,
singlePV=True)]

- def weight(self, fstype=None, mountpoint=None):
- if mountpoint and mountpoint == "/boot":
- return 5000
- else:
- return 0
+ def diskLabelType(self, device_type):
+ """The default disklabel type for the specified device type."""
+ if device_type == "dasd":
+ return "dasd"
+
+ return self.defaultDiskLabelType

class Sparc(Platform):
- _diskLabelType = "sun"
- _packages = ["silo"]
+ _bootloaderClass = bootloader.SILO

@property
def minimumSector(self, disk):
@@ -509,73 +316,11 @@ class Sparc(Platform):
start /= long(1024 / disk.device.sectorSize)
return start+1

-class X86(EFI):
- _bootFSTypes = ["ext4", "ext3", "ext2"]
- _packages = ["grub"]
- _supportsMdRaidBoot = True
-
- def __init__(self, anaconda):
- EFI.__init__(self, anaconda)
-
- if self.isEfi:
- self._diskLabelType = "gpt"
- else:
- self._diskLabelType = "msdos"
-
- def bootDevice(self):
- if self.isEfi:
- return EFI.bootDevice(self)
- else:
- return Platform.bootDevice(self)
-
- def bootloaderChoices(self, bl):
- if self.isEfi:
- return EFI.bootloaderChoices(self, bl)
-
- bootDev = self.bootDevice()
- ret = {}
-
- if not bootDev:
- return {}
-
- if bootDev.type == "mdarray":
- ret["boot"] = (bootDev.name, N_("RAID Device"))
- ret["mbr"] = (bl.drivelist[0], N_("Master Boot Record (MBR)"))
- else:
- ret["boot"] = (bootDev.name, N_("First sector of boot partition"))
- ret["mbr"] = (bl.drivelist[0], N_("Master Boot Record (MBR)"))
-
- return ret
-
- @property
- def maxBootPartSize(self):
- if self.isEfi:
- return EFI._maxBootPartSize
- else:
- return Platform._maxBootPartSize
-
- @property
- def minBootPartSize(self):
- if self.isEfi:
- return EFI._minBootPartSize
- else:
- return Platform._minBootPartSize
-
- def setDefaultPartitioning(self):
- if self.isEfi:
- return EFI.setDefaultPartitioning(self)
- else:
- return Platform.setDefaultPartitioning(self)
-
def getPlatform(anaconda):
"""Check the architecture of the system and return an instance of a
Platform subclass to match. If the architecture could not be determined,
raise an exception."""
- if iutil.isAlpha():
- return Alpha(anaconda)
- elif iutil.isIA64():
- return IA64(anaconda)
- elif iutil.isPPC():
+ if iutil.isPPC():
ppcMachine = iutil.getPPCMachine()

if (ppcMachine == "PMac" and iutil.getPPCMacGen() == "NewWorld"):
@@ -590,6 +335,8 @@ def getPlatform(anaconda):
return S390(anaconda)
elif iutil.isSparc():
return Sparc(anaconda)
+ elif iutil.isEfi():
+ return EFI(anaconda)
elif iutil.isX86():
return X86(anaconda)
else:
--
1.7.3.4

_______________________________________________
Anaconda-devel-list mailing list
Anaconda-devel-list@redhat.com
https://www.redhat.com/mailman/listinfo/anaconda-devel-list
 

Thread Tools




All times are GMT. The time now is 01:27 PM.

VBulletin, Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
Content Relevant URLs by vBSEO ©2007, Crawlability, Inc.
Copyright 2007 - 2008, www.linux-archive.org