--- pyanaconda/rescue.py | 5 +- pyanaconda/storage/__init__.py | 363 +++++++++--------------------------- pyanaconda/storage/errors.py | 6 + pyanaconda/storage/partitioning.py | 226 +++++++++-------------- pyanaconda/upgrade.py | 2 +- 5 files changed, 185 insertions(+), 417 deletions(-) diff --git a/pyanaconda/rescue.py b/pyanaconda/rescue.py index 6fab62d..0698357 100644 --- a/pyanaconda/rescue.py +++ b/pyanaconda/rescue.py @@ -339,8 +339,9 @@ def doRescue(anaconda): if root: try: - rc = mountExistingSystem(anaconda, root, - allowDirty = 1, warnDirty = 1, + # TODO: add a callback to warn about dirty filesystems + rc = mountExistingSystem(anaconda.storage.fsset, root, + allowDirty = 1, readOnly = readOnly) if not flags.imageInstall: diff --git a/pyanaconda/storage/__init__.py b/pyanaconda/storage/__init__.py index ae6e26f..e4f0b17 100644 --- a/pyanaconda/storage/__init__.py +++ b/pyanaconda/storage/__init__.py @@ -304,25 +304,18 @@ class StorageDiscoveryConfig(object): class Storage(object): - def __init__(self, anaconda=None, intf=None, platform=None): + def __init__(self, data=None, platform=None): """ Create a Storage instance. Keyword Arguments: - anaconda - an Anaconda instance - intf - an InstallInterface instance + data - a pykickstart Handler instance platform - a Platform instance - All arguments are optional. An Anaconda instance will contain - an InstallInterface and a Platform instance, so it makes sense - to pass in either an Anaconda instance or as many of the other - two as is desired. Explicitly passed intf or platform will take - precedence over those in the Anaconda instance. - """ - self.anaconda = anaconda - self._intf = intf - self._platform = platform + self.data = data + self.platform = platform + self._bootloader = None self.config = StorageDiscoveryConfig() @@ -365,8 +358,8 @@ class Storage(object): self.doEncryptionPassphraseRetrofits() # now set the boot partition's flag - if self.anaconda: - if self.anaconda.bootloader.stage2_bootable: + if self.bootloader: + if self.bootloader.stage2_bootable: boot = self.bootDevice else: boot = self.bootLoaderDevice @@ -437,7 +430,7 @@ class Storage(object): self.config.exclusiveDisks, self.config.zeroMbr) clearPartType = self.config.clearPartType # save this before overriding it - if getattr(self.anaconda, "upgrade", False): + if self.data and self.data.upgrade.upgrade: self.config.clearPartType = CLEARPART_TYPE_NONE self.devicetree.reset(conf=self.config, @@ -449,16 +442,12 @@ class Storage(object): self.config.clearPartType = clearPartType # set it back self.fsset = FSSet(self.devicetree) self.eddDict = get_edd_dict(self.partitioned) - if hasattr(self.anaconda, "rootParts") and \ - hasattr(self.anaconda, "upgradeRoot"): - self.anaconda.rootParts = None - self.anaconda.upgradeRoot = None - if self.anaconda: + if self.bootloader: # clear out bootloader attributes that refer to devices that are # no longer in the tree - self.anaconda.bootloader.clear_drive_list() - self.anaconda.bootloader.stage1_drive = None - self.anaconda.bootloader.stage1_device = None + self.bootloader.clear_drive_list() + self.bootloader.stage1_drive = None + self.bootloader.stage1_device = None self.dumpState("initial") @@ -657,24 +646,7 @@ class Storage(object): @property def liveImage(self): """ The OS image used by live installs. """ - _image = None - if flags.livecdInstall and hasattr(self.anaconda, "methodstr"): - _image = self.devicetree.getDeviceByPath(self.anaconda.methodstr[9:]) - return _image - - @property - def intf(self): - _intf = self._intf - if not _intf: - _intf = getattr(self.anaconda, "intf", None) - return _intf - - @property - def platform(self): - _platform = self._platform - if not _platform: - _platform = getattr(self.anaconda, "platform", None) - return _platform + raise NotImplementedError() def exceptionDisks(self): """ Return a list of removable devices to save exceptions to. @@ -839,8 +811,8 @@ class Storage(object): name = kwargs.pop("name") else: hostname = "" - if hasattr(self.anaconda, "network"): - hostname = self.anaconda.network.hostname + if self.data: + hostname = self.data.network.hostname name = self.createSuggestedVGName(hostname=hostname) if name in [d.name for d in self.devices]: @@ -1056,7 +1028,6 @@ class Storage(object): try: boot = self.bootDevice except (DeviceError, AttributeError): - # AttributeError means we have no anaconda or platform. it's ok. boot = None if not root: @@ -1069,19 +1040,7 @@ class Storage(object): "megabytes which is usually too small to " "install %s.") % (productName,)) - if (root and - hasattr(self.anaconda, "backend") and - root.size < self.anaconda.backend.getMinimumSizeMB("/")): - if flags.livecdInstall: - live = " Live" - else: - live = "" - errors.append(_("Your / partition is less than %(min)s " - "MB which is lower than recommended " - "for a normal %(productName)s%(live)s install.") - % {'min': self.anaconda.backend.getMinimumSizeMB("/"), - 'productName': productName, - 'live': live}) + # FIXME: put a check here for enough space on the filesystems. maybe? # livecds have to have the rootfs type match up if (root and @@ -1142,23 +1101,23 @@ class Storage(object): warnings.append(_("Installing on a FireWire device. This may " "or may not produce a working system.")) - if self.anaconda and self.anaconda.dispatch.step_enabled('instbootloader'): - stage1 = self.anaconda.bootloader.stage1_device + if self.data and self.data.bootloader.location is not None: + stage1 = self.bootloader.stage1_device if not stage1: errors.append(_("you have not created a bootloader stage1 " "target device")) else: - self.anaconda.bootloader.is_valid_stage1_device(stage1) - errors.extend(self.anaconda.bootloader.errors) - warnings.extend(self.anaconda.bootloader.warnings) + self.bootloader.is_valid_stage1_device(stage1) + errors.extend(self.bootloader.errors) + warnings.extend(self.bootloader.warnings) - stage2 = self.anaconda.bootloader.stage2_device + stage2 = self.bootloader.stage2_device if not stage2: errors.append(_("You have not created a bootable partition.")) else: - self.anaconda.bootloader.is_valid_stage2_device(stage2) - errors.extend(self.anaconda.bootloader.errors) - warnings.extend(self.anaconda.bootloader.warnings) + self.bootloader.is_valid_stage2_device(stage2) + errors.extend(self.bootloader.errors) + warnings.extend(self.bootloader.warnings) if not swaps: from pyanaconda.storage.size import Size @@ -1203,14 +1162,8 @@ class Storage(object): def checkNoDisks(self): """Check that there are valid disk devices.""" - if not self.disks and self.intf: - self.intf.messageWindow(_("No Drives Found"), - _("An error has occurred - no valid devices were " - "found on which to create new file systems. " - "Please check your hardware for the cause " - "of this problem.")) - return True - return False + if not self.disks: + raise NoDisksError() def dumpState(self, suffix): """ Dump the current device list to the storage shelf. """ @@ -1290,21 +1243,19 @@ class Storage(object): f.write("\n") def turnOnSwap(self, upgrading=None): - self.fsset.turnOnSwap(intf=self.intf, - rootPath=ROOT_PATH, + self.fsset.turnOnSwap(rootPath=ROOT_PATH, upgrading=upgrading) def mountFilesystems(self, raiseErrors=None, readOnly=None, skipRoot=False): - self.fsset.mountFilesystems(intf=self.intf, - rootPath=ROOT_PATH, + self.fsset.mountFilesystems(rootPath=ROOT_PATH, raiseErrors=raiseErrors, readOnly=readOnly, skipRoot=skipRoot) def umountFilesystems(self, ignoreErrors=True, swapoff=True): self.fsset.umountFilesystems(ignoreErrors=ignoreErrors, swapoff=swapoff) - def parseFSTab(self, anaconda=None, chroot=None): - self.fsset.parseFSTab(anaconda=anaconda, chroot=chroot) + def parseFSTab(self, chroot=None): + self.fsset.parseFSTab(chroot=chroot) def mkDevRoot(self): self.fsset.mkDevRoot() @@ -1313,32 +1264,39 @@ class Storage(object): self.fsset.createSwapFile(device, size) @property - def bootDevice(self): - dev = None - if self.anaconda: - dev = self.anaconda.bootloader.stage2_device - return dev + def bootloader(self): + if self._bootloader is None and self.platform is not None: + self._bootloader = self.platform.bootloaderClass(self.platform) + return self._bootloader + + @property + def bootDisk(self): + disk = None + if self.data: + spec = self.data.bootloader.bootDrive + disk = self.devicetree.resolveDevice(spec) + return disk @property - def bootLoaderDevice(self): + def bootDevice(self): dev = None - if self.anaconda: - dev = self.anaconda.bootloader.stage1_device + if self.fsset: + dev = self.mountpoints.get("/boot", self.rootDevice) return dev @property def bootFSTypes(self): """A list of all valid filesystem types for the boot partition.""" fstypes = [] - if self.anaconda: - fstypes = self.anaconda.bootloader.stage2_format_types + if self.bootloader: + fstypes = self.bootloader.stage2_format_types return fstypes @property def defaultBootFSType(self): """The default filesystem type for the boot partition.""" fstype = None - if self.anaconda: + if self.bootloader: fstype = self.bootFSTypes[0] return fstype @@ -1516,13 +1474,15 @@ def findExistingRootDevices(anaconda, upgradeany=False): return (rootDevs, notUpgradable) -def mountExistingSystem(anaconda, rootEnt, - allowDirty=None, warnDirty=None, +def mountExistingSystem(fsset, rootEnt, + allowDirty=None, dirtyCB=None, readOnly=None): """ Mount filesystems specified in rootDevice's /etc/fstab file. """ rootDevice = rootEnt[0] rootPath = ROOT_PATH - fsset = anaconda.storage.fsset + if dirtyCB is None: + dirtyCB = lambda l: False + if readOnly: readOnly = "ro" else: @@ -1539,7 +1499,7 @@ def mountExistingSystem(anaconda, rootEnt, mountpoint="/", options=readOnly) - fsset.parseFSTab(anaconda=anaconda) + fsset.parseFSTab() # check for dirty filesystems dirtyDevs = [] @@ -1558,28 +1518,10 @@ def mountExistingSystem(anaconda, rootEnt, device.format.type)) dirtyDevs.append(device.path) - messageWindow = anaconda.intf.messageWindow - if not allowDirty and dirtyDevs: - messageWindow(_("Dirty File Systems"), - _("The following file systems for your Linux system " - "were not unmounted cleanly. Please boot your " - "Linux installation, let the file systems be " - "checked and shut down cleanly to upgrade.\n" - "%s") % "\n".join(dirtyDevs)) - anaconda.storage.devicetree.teardownAll() - sys.exit(0) - elif warnDirty and dirtyDevs: - rc = messageWindow(_("Dirty File Systems"), - _("The following file systems for your Linux " - "system were not unmounted cleanly. Would " - "you like to mount them anyway?\n" - "%s") % "\n".join(dirtyDevs), - type = "yesno") - if rc == 0: - return -1 + if dirtyDevs and (not allowDirty or dirtyCB(dirtyDevs)): + raise DirtyFSError("\n".join(dirtyDevs)) - fsset.mountFilesystems(intf=anaconda.intf, rootPath=ROOT_PATH, - readOnly=readOnly, skipRoot=True) + fsset.mountFilesystems(rootPath=ROOT_PATH, readOnly=readOnly, skipRoot=True) class BlkidTab(object): @@ -1908,7 +1850,7 @@ class FSSet(object): return device - def parseFSTab(self, anaconda=None, chroot=None): + def parseFSTab(self, chroot=None): """ parse /etc/fstab preconditions: @@ -1977,16 +1919,6 @@ class FSSet(object): # just write the line back out as-is after upgrade self.preserveLines.append(line) continue - except FSTabTypeMismatchError as e: - if anaconda and hasattr(anaconda.intf, "messageWindow"): - err = _("There is an entry in your /etc/fstab file " - "that contains an invalid or incorrect " - "filesystem type:\n\n ") - err += str(e) - anaconda.intf.messageWindow(_("Error"), err) - sys.exit(0) - - raise Exception("fstab entry %s is malformed: %s" % (devspec, e)) if not device: continue @@ -1998,25 +1930,14 @@ class FSSet(object): # just write duplicates back out post-install self.preserveLines.append(line) - def turnOnSwap(self, intf=None, rootPath="", upgrading=None): - def swapErrorDialog(msg, device): - if not intf: - # can't show a dialog? ignore this busted device. - ret = 0 - else: - buttons = [_("Skip"), _("Format"), _("_Exit")] - ret = intf.messageWindow(_("Error"), msg, type="custom", - custom_buttons=buttons, - custom_icon="warning") + def turnOnSwap(self, rootPath="", upgrading=None, errorcb=None): + """ Activate the system's swap space. - if ret == 0: - self.devicetree._removeDevice(device) - return False - elif ret == 1: - device.format.create(force=True) - return True - else: - sys.exit(0) + errorcb should accept an Exception instance and a Device instance + return True if the exception should be fatal, which is the default. + """ + if errorcb is None: + errorcb = lambda e,d: True for device in self.swapDevices: if isinstance(device, FileDevice): @@ -2036,69 +1957,23 @@ class FSSet(object): try: device.setup() device.format.setup() - except OldSwapError: - msg = _("The swap device:\n\n %s\n\n" - "is an old-style Linux swap partition. If " - "you want to use this device for swap space, " - "you must reformat as a new-style Linux swap " - "partition.") \ - % device.path - - if swapErrorDialog(msg, device): - continue - except SuspendError: - if upgrading: - msg = _("The swap device:\n\n %s\n\n" - "in your /etc/fstab file is currently in " - "use as a software suspend device, " - "which means your system is hibernating. " - "To perform an upgrade, please shut down " - "your system rather than hibernating it.") \ - % device.path - else: - msg = _("The swap device:\n\n %s\n\n" - "in your /etc/fstab file is currently in " - "use as a software suspend device, " - "which means your system is hibernating. " - "If you are performing a new install, " - "make sure the installer is set " - "to format all swap devices.") \ - % device.path - - if swapErrorDialog(msg, device): - continue - except UnknownSwapError: - msg = _("The swap device:\n\n %s\n\n" - "does not contain a supported swap volume. In " - "order to continue installation, you will need " - "to format the device or skip it.") \ - % device.path - - if swapErrorDialog(msg, device): - continue - except DeviceError as (msg, name): - if intf: - if upgrading: - err = _("Error enabling swap device %(name)s: " - "%(msg)s\n\n" - "The /etc/fstab on your upgrade partition " - "does not reference a valid swap " - "device.\n\nPress OK to exit the " - "installer") % {'name': name, 'msg': msg} - else: - err = _("Error enabling swap device %(name)s: " - "%(msg)s\n\n" - "This most likely means this swap " - "device has not been initialized.\n\n" - "Press OK to exit the installer.") % \ - {'name': name, 'msg': msg} - intf.messageWindow(_("Error"), err) - sys.exit(0) - - break + except StorageError as e: + if errorcb(e, device): + raise + else: + break - def mountFilesystems(self, intf=None, rootPath="", readOnly=None, + def mountFilesystems(self, rootPath="", readOnly=None, errorcb=None, skipRoot=False, raiseErrors=None): + """ Mount the system's filesystems. + + errorcb should accept an Exception instance and a Device instance + and return True if the exception should be fatal, which is the + default. + """ + if errorcb is None: + errorcb = lambda e,d: True + devices = self.mountpoints.values() + self.swapDevices devices.extend([self.dev, self.devshm, self.devpts, self.sysfs, self.proc, self.selinux, self.usb]) @@ -2135,8 +2010,10 @@ class FSSet(object): try: device.setup() except Exception as msg: - # FIXME: need an error popup - continue + if errorcb(e, device): + raise + else: + continue if readOnly: options = "%s,%s" % (options, readOnly) @@ -2144,73 +2021,11 @@ class FSSet(object): try: device.format.setup(options=options, chroot=rootPath) - except OSError as e: - log.error("OSError: (%d) %s" % (e.errno, e.strerror)) - - if intf: - if e.errno == errno.EEXIST: - intf.messageWindow(_("Invalid mount point"), - _("An error occurred when trying " - "to create %s. Some element of " - "this path is not a directory. " - "This is a fatal error and the " - "install cannot continue.\n\n" - "Press <Enter> to exit the " - "installer.") - % (device.format.mountpoint,)) - else: - na = {'mountpoint': device.format.mountpoint, - 'msg': e.strerror} - intf.messageWindow(_("Invalid mount point"), - _("An error occurred when trying " - "to create %(mountpoint)s: " - "%(msg)s. This is " - "a fatal error and the install " - "cannot continue.\n\n" - "Press <Enter> to exit the " - "installer.") % na) - sys.exit(0) - except SystemError as (num, msg): - log.error("SystemError: (%d) %s" % (num, msg) ) - - if raiseErrors: + except Exception as e: + log.error("error mounting %s on %s: %s" + % (device.path, device.format.mountpoint, e)) + if errorcb(e, device): raise - if intf and not device.format.linuxNative: - na = {'path': device.path, - 'mountpoint': device.format.mountpoint} - ret = intf.messageWindow(_("Unable to mount filesystem"), - _("An error occurred mounting " - "device %(path)s as " - "%(mountpoint)s. You may " - "continue installation, but " - "there may be problems.") % na, - type="custom", - custom_icon="warning", - custom_buttons=[_("_Exit installer"), - _("_Continue")]) - - if ret == 0: - sys.exit(0) - else: - continue - - sys.exit(0) - except FSError as msg: - log.error("FSError: %s" % msg) - - if intf: - na = {'path': device.path, - 'mountpoint': device.format.mountpoint, - 'msg': msg} - intf.messageWindow(_("Unable to mount filesystem"), - _("An error occurred mounting " - "device %(path)s as %(mountpoint)s: " - "%(msg)s. This is " - "a fatal error and the install " - "cannot continue.\n\n" - "Press <Enter> to exit the " - "installer.") % na) - sys.exit(0) self.active = True diff --git a/pyanaconda/storage/errors.py b/pyanaconda/storage/errors.py index 2217873..6b7e5fc 100644 --- a/pyanaconda/storage/errors.py +++ b/pyanaconda/storage/errors.py @@ -25,6 +25,9 @@ class StorageError(Exception): self.hardware_fault = kwargs.pop("hardware_fault", False) super(StorageError, self).__init__(*args, **kwargs) +class NoDisksError(StorageError): + pass + # Device class DeviceError(StorageError): pass @@ -78,6 +81,9 @@ class FSResizeError(FSError): class FSMigrateError(FSError): pass +class DirtyFSError(FSError): + pass + class LUKSError(DeviceFormatError): pass diff --git a/pyanaconda/storage/partitioning.py b/pyanaconda/storage/partitioning.py index 7dba783..cbcb43a 100644 --- a/pyanaconda/storage/partitioning.py +++ b/pyanaconda/storage/partitioning.py @@ -104,6 +104,17 @@ def _schedulePartitions(storage, disks): if len(all_free) > 1: free += all_free[1].getSize() + # The boot disk must be set at this point. See if any platform-specific + # stage1 device we might allocate already exists on the boot disk. + stage1_device = None + for device in storage.devices: + if storage.bootloader.stage1_drive not in device.disks: + continue + + if storage.bootloader._is_valid_stage1_device(device): + stage1_device = device + break + # # First pass is for partitions only. We'll do LVs later. # @@ -120,27 +131,17 @@ def _schedulePartitions(storage, disks): else: request.fstype = storage.defaultFSType - elif request.fstype == "prepboot" and storage.bootLoaderDevice: - # there should never be a need for more than one of these - # partitions, so skip them. - log.info("skipping unneeded stage1 prepboot request") - log.debug(request) - log.debug(storage.bootLoaderDevice) - continue - elif request.fstype == "efi" and storage.bootLoaderDevice: - # there should never be a need for more than one of these - # partitions, so skip them. - log.info("skipping unneeded stage1 efi request") - log.debug(request) - # Set the mountpoint for the existing EFI boot partition - storage.bootLoaderDevice.format.mountpoint = "/boot/efi" - log.debug(storage.bootLoaderDevice) - continue - elif request.fstype == "biosboot" and storage.bootLoaderDevice: - log.info("skipping unneeded stage1 biosboot request") - log.debug(request) - log.debug(storage.bootLoaderDevice) - continue + elif request.fstype in ("prepboot", "efi", "biosboot") and stage1_device: + # there should never be a need for more than one of these + # partitions, so skip them. + log.info("skipping unneeded stage1 %s request" % request.fstype) + log.debug(request) + + if request.fstype == "efi": + # Set the mountpoint for the existing EFI boot partition + stage1_device.format.mountpoint = "/boot/efi" + + log.debug(stage1_device) # This is a little unfortunate but let the backend dictate the rootfstype # so that things like live installs can do the right thing @@ -244,121 +245,75 @@ def scheduleShrinkActions(storage): if device.targetSize != size: device.format.targetSize = device.targetSize -def doAutoPartition(anaconda): - log.debug("doAutoPartition(%s)" % anaconda) - log.debug("doAutoPart: %s" % anaconda.storage.doAutoPart) - log.debug("encryptedAutoPart: %s" % anaconda.storage.encryptedAutoPart) - log.debug("lvmAutoPart: %s" % anaconda.storage.lvmAutoPart) - log.debug("clearPartType: %s" % anaconda.storage.config.clearPartType) - log.debug("clearPartDisks: %s" % anaconda.storage.config.clearPartDisks) - log.debug("autoPartitionRequests:\n%s" % "".join([str(p) for p in anaconda.storage.autoPartitionRequests])) - log.debug("storage.disks: %s" % [d.name for d in anaconda.storage.disks]) - log.debug("storage.partitioned: %s" % [d.name for d in anaconda.storage.partitioned]) - log.debug("all names: %s" % [d.name for d in anaconda.storage.devices]) - if anaconda.dir == DISPATCH_BACK: - return +def doAutoPartition(storage, data, errorcb=None, warningcb=None): + log.debug("doAutoPart: %s" % storage.doAutoPart) + log.debug("encryptedAutoPart: %s" % storage.encryptedAutoPart) + log.debug("lvmAutoPart: %s" % storage.lvmAutoPart) + log.debug("clearPartType: %s" % storage.config.clearPartType) + log.debug("clearPartDisks: %s" % storage.config.clearPartDisks) + log.debug("autoPartitionRequests:\n%s" % "".join([str(p) for p in storage.autoPartitionRequests])) + log.debug("storage.disks: %s" % [d.name for d in storage.disks]) + log.debug("storage.partitioned: %s" % [d.name for d in storage.partitioned]) + log.debug("all names: %s" % [d.name for d in storage.devices]) + log.debug("boot disk: %s" % getattr(storage.bootDisk, "name", None)) disks = [] devs = [] - if anaconda.storage.doAutoPart: - scheduleShrinkActions(anaconda.storage) - clearPartitions(anaconda.storage, bootloader=anaconda.bootloader) + if errorcb is None: + errorcb = lambda e: True + if warningcb is None: + warningcb = lambda e: True + + if storage.doAutoPart: + scheduleShrinkActions(storage) + clearPartitions(storage) # update the bootloader's drive list to add disks which have their # whole disk format replaced by a disklabel. Make sure to keep any # previous boot order selection from clearpart_gui or kickstart anaconda.bootloader.clear_drive_list() - disks = _getCandidateDisks(anaconda.storage) - devs = _schedulePVs(anaconda.storage, disks) + disks = _getCandidateDisks(storage) + devs = _schedulePVs(storage, disks) log.debug("candidate disks: %s" % disks) log.debug("devs: %s" % devs) if disks == []: - if anaconda.ksdata: - msg = _("Could not find enough free space for automatic " - "partitioning. Press 'OK' to exit the installer.") - else: - msg = _("Could not find enough free space for automatic " - "partitioning, please use another partitioning method.") - - anaconda.intf.messageWindow(_("Error Partitioning"), msg, - custom_icon='error') - - if anaconda.ksdata: - sys.exit(0) + raise PartitioningError("not enough free space") - anaconda.storage.reset() - return DISPATCH_BACK - - _schedulePartitions(anaconda.storage, disks) + _schedulePartitions(storage, disks) # run the autopart function to allocate and grow partitions try: - doPartitioning(anaconda.storage, bootloader=anaconda.bootloader) + doPartitioning(storage) - if anaconda.storage.doAutoPart: - _scheduleLVs(anaconda.storage, devs) + if storage.doAutoPart: + _scheduleLVs(storage, devs) # grow LVs - growLVM(anaconda.storage) - except PartitioningWarning as msg: - if not anaconda.ksdata: - anaconda.intf.messageWindow(_("Warnings During Automatic " - "Partitioning"), - _("Following warnings occurred during automatic " - "partitioning:\n\n%s") % (msg,), - custom_icon='warning') - else: - log.warning(msg) - except PartitioningError as msg: - # restore drives to original state - anaconda.storage.reset() - - extra = "" - if anaconda.ksdata: - extra = _("\n\nPress 'OK' to exit the installer.") - else: - anaconda.dispatch.request_steps_gently("partition") - anaconda.intf.messageWindow(_("Error Partitioning"), - _("Could not allocate requested partitions: \n\n" - "%(msg)s.%(extra)s") % {'msg': msg, 'extra': extra}, - custom_icon='error') - - if anaconda.ksdata: - sys.exit(0) - else: - return DISPATCH_BACK + growLVM(storage) + except PartitioningWarning as e: + log.warning(str(e)) + warningcb(e) + except PartitioningError as e: + log.error(str(e)) + errorcb(e) + storage.reset() + raise + + storage.setUpBootLoader() # now do a full check of the requests - (errors, warnings) = anaconda.storage.sanityCheck() - if warnings: - for warning in warnings: - log.warning(warning) + (errors, warnings) = storage.sanityCheck() + for error in errors: + log.error(error) + for warning in warnings: + log.warning(warning) if errors: - errortxt = "\n".join(errors) - if anaconda.ksdata: - extra = _("\n\nPress 'OK' to exit the installer.") - else: - extra = _("\n\nPress 'OK' to choose a different partitioning option.") - - anaconda.intf.messageWindow(_("Automatic Partitioning Errors"), - _("The following errors occurred with your " - "partitioning:\n\n%(errortxt)s\n\n" - "This can happen if there is not enough " - "space on your hard drive(s) for the " - "installation. %(extra)s") - % {'errortxt': errortxt, 'extra': extra}, - custom_icon='error') - # - # XXX if in kickstart we reboot - # - if anaconda.ksdata: - anaconda.intf.messageWindow(_("Unrecoverable Error"), - _("The system will now reboot.")) - sys.exit(0) - anaconda.storage.reset() - return DISPATCH_BACK + exn = PartitioningError("\n".join(errors)) + errorcb(exn) + storage.reset() + raise exn def shouldClear(device, clearPartType, clearPartDisks=None): if clearPartType not in [CLEARPART_TYPE_LINUX, CLEARPART_TYPE_ALL]: @@ -409,7 +364,7 @@ def shouldClear(device, clearPartType, clearPartDisks=None): return True -def clearPartitions(storage, bootloader=None): +def clearPartitions(storage): """ Clear partitions and dependent devices from disks. Arguments: @@ -418,7 +373,7 @@ def clearPartitions(storage, bootloader=None): Keyword arguments: - bootloader -- a BootLoader instance + None NOTES: @@ -486,11 +441,12 @@ def clearPartitions(storage, bootloader=None): # make sure that the the boot device has the correct disklabel type if # we're going to completely clear it. + boot_disk = storage.bootDisk for disk in storage.partitioned: - if not bootloader or not bootloader.stage1_drive: + if not boot_disk: break - if disk != bootloader.stage1_drive: + if disk != boot_disk: continue if storage.config.clearPartType != CLEARPART_TYPE_ALL or \ @@ -926,7 +882,7 @@ def updateExtendedPartitions(storage, disks): # moment to simplify things storage.devicetree._addDevice(device) -def doPartitioning(storage, bootloader=None): +def doPartitioning(storage): """ Allocate and grow partitions. When this function returns without error, all PartitionDevice @@ -941,7 +897,7 @@ def doPartitioning(storage, bootloader=None): Keyword/Optional Arguments: - bootloader - BootLoader instance + None """ if not hasattr(storage.platform, "diskLabelTypes"): @@ -973,14 +929,6 @@ def doPartitioning(storage, bootloader=None): # start over with flexible-size requests part.req_size = part.req_base_size - try: - storage.bootDevice.req_bootable = True - except AttributeError: - # there's no stage2 device. hopefully it's temporary. - pass - - removeNewPartitions(disks, partitions) - if storage.platform.weight(fstype="biosboot") > 0: # add a request for a bios boot partition on every disk that contains a # gpt disklabel if we're on a bios platform. @@ -1017,10 +965,16 @@ def doPartitioning(storage, bootloader=None): storage.createDevice(part) partitions.append(part) + try: + storage.bootDevice.req_bootable = True + except AttributeError: + # there's no stage2 device. hopefully it's temporary. + pass + + removeNewPartitions(disks, partitions) free = getFreeRegions(disks) try: - allocatePartitions(storage, disks, partitions, free, - bootloader=bootloader) + allocatePartitions(storage, disks, partitions, free) growPartitions(disks, partitions, free) finally: # The number and thus the name of partitions may have changed now, @@ -1034,11 +988,7 @@ def doPartitioning(storage, bootloader=None): updateExtendedPartitions(storage, disks) - # make sure the stage1_device gets updated - if storage.anaconda: - storage.anaconda.bootloader.stage1_device = None - -def allocatePartitions(storage, disks, partitions, freespace, bootloader=None): +def allocatePartitions(storage, disks, partitions, freespace): """ Allocate partitions based on requested features. Non-existing partitions are sorted according to their requested @@ -1088,14 +1038,10 @@ def allocatePartitions(storage, disks, partitions, freespace, bootloader=None): # sort the disks, making sure the boot disk is first req_disks.sort(key=lambda d: d.name, cmp=storage.compareDisks) - boot_index = None for disk in req_disks: - if bootloader and disk == bootloader.stage1_drive: + if storage.bootDisk and disk == storage.bootDisk: boot_index = req_disks.index(disk) - - if boot_index is not None and len(req_disks) > 1: - boot_disk = req_disks.pop(boot_index) - req_disks.insert(0, boot_disk) + req_disks.insert(0, req_disks.pop(boot_index)) boot = _part.req_base_weight > 1000 diff --git a/pyanaconda/upgrade.py b/pyanaconda/upgrade.py index 5d9fe4f..d5dd7a4 100644 --- a/pyanaconda/upgrade.py +++ b/pyanaconda/upgrade.py @@ -168,7 +168,7 @@ def upgradeMountFilesystems(anaconda): # mount everything and turn on swap try: - mountExistingSystem(anaconda, anaconda.upgradeRoot[0], allowDirty = 0) + mountExistingSystem(anaconda.storage.fsset, anaconda.upgradeRoot[0], allowDirty = 0) except ValueError as e: log.error("Error mounting filesystem: %s" % e) anaconda.intf.messageWindow(_("Mount failed"), -- 1.7.8.4 _______________________________________________ Anaconda-devel-list mailing list Anaconda-devel-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/anaconda-devel-list