[master 1/2] Put DeviceTree methods into a sensible order.
dwlehman
installerbot-noreply at redhat.com
Thu Nov 5 14:40:50 UTC 2015
From: David Lehman <dlehman at redhat.com>
---
blivet/devicetree.py | 915 ++++++++++++++++++++++++++-------------------------
1 file changed, 474 insertions(+), 441 deletions(-)
diff --git a/blivet/devicetree.py b/blivet/devicetree.py
index 00267a8..7613c98 100644
--- a/blivet/devicetree.py
+++ b/blivet/devicetree.py
@@ -112,68 +112,44 @@ def reset(self, conf=None, passphrase=None, luks_dict=None,
iscsi=iscsi,
dasd=dasd)
- @property
- def actions(self):
- return self._actions
-
- def set_disk_images(self, images):
- """ Set the disk images and reflect them in exclusive_disks.
-
- :param images: dict with image name keys and filename values
- :type images: dict
-
- .. note::
-
- Disk images are automatically exclusive. That means that, in the
- presence of disk images, any local storage not associated with
- the disk images is ignored.
- """
- self._populator.set_disk_images(images)
-
- @property
- def exclusive_disks(self):
- return self._populator.exclusive_disks
-
- @property
- def ignored_disks(self):
- return self._populator.ignored_disks
-
- @property
- def dasd(self):
- return self._populator.dasd
-
- @dasd.setter
- def dasd(self, dasd):
- self._populator.dasd = dasd
+ def __str__(self):
+ done = []
- @property
- def protected_dev_names(self):
- return self._populator.protected_dev_names
+ def show_subtree(root, depth):
+ abbreviate_subtree = root in done
+ s = "%s%s\n" % (" " * depth, root)
+ done.append(root)
+ if abbreviate_subtree:
+ s += "%s...\n" % (" " * (depth + 1),)
+ else:
+ for child in self.get_children(root):
+ s += show_subtree(child, depth + 1)
+ return s
- @property
- def disk_images(self):
- return self._populator.disk_images
+ roots = [d for d in self._devices if not d.parents]
+ tree = ""
+ for root in roots:
+ tree += show_subtree(root, 0)
+ return tree
+ #
+ # Device list
+ #
@property
- def pv_info(self):
- if self._pvs_cache is None:
- pvs = blockdev.lvm.pvs()
- self._pvs_cache = dict((pv.pv_name, pv) for pv in pvs) # pylint: disable=attribute-defined-outside-init
-
- return self._pvs_cache
+ def devices(self):
+ """ List of devices currently in the tree """
+ devices = []
+ for device in self._devices:
+ if not getattr(device, "complete", True):
+ continue
- @property
- def lv_info(self):
- if self._lvs_cache is None:
- lvs = blockdev.lvm.lvs()
- self._lvs_cache = dict(("%s-%s" % (lv.vg_name, lv.lv_name), lv) for lv in lvs) # pylint: disable=attribute-defined-outside-init
+ if device.uuid and device.uuid in [d.uuid for d in devices] and \
+ not isinstance(device, NoDevice):
+ raise DeviceTreeError("duplicate uuids in device tree")
- return self._lvs_cache
+ devices.append(device)
- def drop_lvm_cache(self):
- """ Drop cached lvm information. """
- self._pvs_cache = None # pylint: disable=attribute-defined-outside-init
- self._lvs_cache = None # pylint: disable=attribute-defined-outside-init
+ return devices
def _add_device(self, newdev, new=True):
""" Add a device to the tree.
@@ -297,6 +273,13 @@ def recursive_remove(self, device, actions=True):
else:
self._remove_device(device)
+ #
+ # Actions
+ #
+ @property
+ def actions(self):
+ return self._actions
+
def register_action(self, action):
""" Register an action to be performed at a later time.
@@ -377,11 +360,103 @@ def find_actions(self, device=None, action_type=None, object_type=None,
path=path,
devid=devid)
+ def prune_actions(self):
+ return self._actions.prune()
+
+ def sort_actions(self):
+ return self._actions.sort()
+
def process_actions(self, callbacks=None, dry_run=False):
self.actions.process(devices=self.devices,
dry_run=dry_run,
callbacks=callbacks)
+ #
+ # Device detection
+ #
+ def populate(self, cleanup_only=False):
+ """ Locate all storage devices.
+
+ Everything should already be active. We just go through and gather
+ details as needed and set up the relations between various devices.
+
+ Devices excluded via disk filtering (or because of disk images) are
+ scanned just the rest, but then they are hidden at the end of this
+ process.
+ """
+ udev.settle()
+ self.drop_lvm_cache()
+ try:
+ self._populator.populate(cleanup_only=cleanup_only)
+ except Exception:
+ raise
+ finally:
+ self._hide_ignored_disks()
+
+ if flags.installer_mode:
+ self.teardown_all()
+
+ def update_device_format(self, device):
+ return self._populator.update_device_format(device)
+
+ def handle_nodev_filesystems(self):
+ for line in open("/proc/mounts").readlines():
+ try:
+ (_devspec, mountpoint, fstype, _options, _rest) = line.split(None, 4)
+ except ValueError:
+ log.error("failed to parse /proc/mounts line: %s", line)
+ continue
+ if fstype in formats.fslib.nodev_filesystems:
+ if not flags.include_nodev:
+ continue
+
+ log.info("found nodev %s filesystem mounted at %s",
+ fstype, mountpoint)
+ # nodev filesystems require some special handling.
+ # For now, a lot of this is based on the idea that it's a losing
+ # battle to require the presence of an FS class for every type
+ # of nodev filesystem. Based on that idea, we just instantiate
+ # NoDevFS directly and then hack in the fstype as the device
+ # attribute.
+ fmt = formats.get_format("nodev")
+ fmt.device = fstype
+
+ # NoDevice also needs some special works since they don't have
+ # per-instance names in the kernel.
+ device = NoDevice(fmt=fmt)
+ n = len([d for d in self.devices if d.format.type == fstype])
+ device._name += ".%d" % n
+ self._add_device(device)
+
+ #
+ # Device control
+ #
+ def teardown_all(self):
+ """ Run teardown methods on all devices. """
+ for device in self.leaves:
+ if device.protected:
+ continue
+
+ try:
+ device.teardown(recursive=True)
+ except (StorageError, blockdev.BlockDevError) as e:
+ log.info("teardown of %s failed: %s", device.name, e)
+
+ def setup_all(self):
+ """ Run setup methods on all devices. """
+ for device in self.leaves:
+ try:
+ device.setup()
+ except DeviceError as e:
+ log.error("setup of %s failed: %s", device.name, e)
+
+ #
+ # Device search by relation
+ #
+ def get_children(self, device):
+ """ Return a list of a device's children. """
+ return [c for c in self._devices if device in c.parents]
+
def get_dependent_devices(self, dep, hidden=False):
""" Return a list of devices that depend on dep.
@@ -426,277 +501,64 @@ def get_related_disks(self, disk):
return set(d for dep in self.get_dependent_devices(disk, hidden=True)
for d in dep.disks)
- def hide(self, device):
- """ Hide the specified device.
+ #
+ # Device search by property
+ #
+ def _filter_devices(self, incomplete=False, hidden=False):
+ """ Return list of devices modified according to parameters.
- :param device: the device to hide
- :type device: :class:`~.devices.StorageDevice`
+ :param bool incomplete: include incomplete devices in result
+ :param bool hidden: include hidden devices in result
- Hiding a device will cancel all actions that involve the device and
- will remove the device from the device list.
+ :returns: a generator of devices
+ :rtype: generator of :class:`~.devices.Device`
+ """
+ if hidden:
+ devices = (d for d in self._devices[:] + self._hidden[:])
+ else:
+ devices = (d for d in self._devices[:])
- If the device is not a leaf device, all devices that depend on it
- will be hidden leaves-first until the device is a leaf device.
+ if not incomplete:
+ devices = (d for d in devices if getattr(d, "complete", True))
+ return devices
- If a device exists, performs some special actions and places
- it on a list of hidden devices.
+ def get_device_by_sysfs_path(self, path, incomplete=False, hidden=False):
+ """ Return a list of devices with a matching sysfs path.
- Mixes recursion and side effects, most significantly in the code
- that removes all the actions. However, this code is a null op
- in every case except the first base case that is reached,
- where all actions are removed. This means that when a device
- is removed explicitly in this function by means of a direct call to
- _remove_devices it is guaranteed that all actions have already
- been canceled.
+ :param str path: the sysfs path to match
+ :param bool incomplete: include incomplete devices in search
+ :param bool hidden: include hidden devices in search
+ :returns: the first matching device found
+ :rtype: :class:`~.devices.Device`
+ """
+ log_method_call(self, path=path, incomplete=incomplete, hidden=hidden)
+ result = None
+ if path:
+ devices = self._filter_devices(incomplete=incomplete, hidden=hidden)
+ result = next((d for d in devices if d.sysfs_path == path), None)
+ log_method_return(self, result)
+ return result
- If a device does not exist then it must have been removed by the
- cancelation of all the actions, so it does not need to be removed
- explicitly.
+ def get_device_by_uuid(self, uuid, incomplete=False, hidden=False):
+ """ Return a list of devices with a matching UUID.
- Most devices are considered leaf devices if they have no children,
- however, some devices must satisfy more stringent requirements.
- _remove_device() will raise an exception if the device it is
- removing is not a leaf device. hide() guarantees that any
- device that it removes will have no children, but it does not
- guarantee that the more stringent requirements will be enforced.
- Therefore, _remove_device() is invoked with the force parameter
- set to True, to skip the isleaf check.
+ :param str uuid: the UUID to match
+ :param bool incomplete: include incomplete devices in search
+ :param bool hidden: include hidden devices in search
+ :returns: the first matching device found
+ :rtype: :class:`~.devices.Device`
"""
- if device in self._hidden:
- return
+ log_method_call(self, uuid=uuid, incomplete=incomplete, hidden=hidden)
+ result = None
+ if uuid:
+ devices = self._filter_devices(incomplete=incomplete, hidden=hidden)
+ result = next((d for d in devices if d.uuid == uuid or d.format.uuid == uuid), None)
+ log_method_return(self, result)
+ return result
- # cancel actions first thing so that we hide the correct set of devices
- if device.is_disk:
- # Cancel all actions on this disk and any disk related by way of an
- # aggregate/container device (eg: lvm volume group).
- disks = [device]
- related_actions = [a for a in self._actions
- if a.device.depends_on(device)]
- for related_device in (a.device for a in related_actions):
- disks.extend(related_device.disks)
-
- disks = set(disks)
- cancel = [a for a in self._actions
- if set(a.device.disks).intersection(disks)]
- for action in reversed(cancel):
- self.cancel_action(action)
-
- for d in self.get_children(device):
- self.hide(d)
-
- log.info("hiding device %s", device)
-
- if not device.exists:
- return
-
- self._remove_device(device, force=True, modparent=False)
-
- self._hidden.append(device)
- lvm.lvm_cc_addFilterRejectRegexp(device.name)
-
- if isinstance(device, DASDDevice):
- self.dasd.remove(device)
-
- if device.name not in self.names:
- self.names.append(device.name)
-
- def unhide(self, device):
- """ Restore a device's visibility.
-
- :param device: the device to restore/unhide
- :type device: :class:`~.devices.StorageDevice`
-
- .. note::
-
- Actions canceled while hiding the device are not rescheduled
- automatically.
-
- """
-
- # the hidden list should be in leaves-first order
- for hidden in reversed(self._hidden):
- if hidden == device or hidden.depends_on(device) and \
- not any(parent in self._hidden for parent in hidden.parents):
-
- log.info("unhiding device %s %s (id %d)", hidden.type,
- hidden.name,
- hidden.id)
- self._hidden.remove(hidden)
- self._devices.append(hidden)
- hidden.add_hook(new=False)
- lvm.lvm_cc_removeFilterRejectRegexp(hidden.name)
- if isinstance(device, DASDDevice):
- self.dasd.append(device)
-
- def setup_disk_images(self):
- """ Set up devices to represent the disk image files. """
- self._populator.setup_disk_images()
-
- def update_device_format(self, device):
- return self._populator.update_device_format(device)
-
- def prune_actions(self):
- return self._actions.prune()
-
- def sort_actions(self):
- return self._actions.sort()
-
- def populate(self, cleanup_only=False):
- """ Locate all storage devices.
-
- Everything should already be active. We just go through and gather
- details as needed and set up the relations between various devices.
-
- Devices excluded via disk filtering (or because of disk images) are
- scanned just the rest, but then they are hidden at the end of this
- process.
- """
- udev.settle()
- self.drop_lvm_cache()
- try:
- self._populator.populate(cleanup_only=cleanup_only)
- except Exception:
- raise
- finally:
- self._hide_ignored_disks()
-
- if flags.installer_mode:
- self.teardown_all()
-
- def _is_ignored_disk(self, disk):
- return ((self.ignored_disks and disk.name in self.ignored_disks) or
- (self.exclusive_disks and
- disk.name not in self.exclusive_disks))
-
- def _hide_ignored_disks(self):
- # hide any subtrees that begin with an ignored disk
- for disk in [d for d in self._devices if d.is_disk]:
- if self._is_ignored_disk(disk):
- ignored = True
- # If the filter allows all members of a fwraid or mpath, the
- # fwraid or mpath itself is implicitly allowed as well. I don't
- # like this very much but we have supported this usage in the
- # past, so I guess we will support it forever.
- if disk.parents and all(p.format.hidden for p in disk.parents):
- ignored = any(self._is_ignored_disk(d) for d in disk.parents)
-
- if ignored:
- self.hide(disk)
-
- def teardown_all(self):
- """ Run teardown methods on all devices. """
- for device in self.leaves:
- if device.protected:
- continue
-
- try:
- device.teardown(recursive=True)
- except (StorageError, blockdev.BlockDevError) as e:
- log.info("teardown of %s failed: %s", device.name, e)
-
- def teardown_disk_images(self):
- """ Tear down any disk image stacks. """
- self._populator.teardown_disk_images()
-
- def setup_all(self):
- """ Run setup methods on all devices. """
- for device in self.leaves:
- try:
- device.setup()
- except DeviceError as e:
- log.error("setup of %s failed: %s", device.name, e)
-
- def _filter_devices(self, incomplete=False, hidden=False):
- """ Return list of devices modified according to parameters.
-
- :param bool incomplete: include incomplete devices in result
- :param bool hidden: include hidden devices in result
-
- :returns: a generator of devices
- :rtype: generator of :class:`~.devices.Device`
- """
- if hidden:
- devices = (d for d in self._devices[:] + self._hidden[:])
- else:
- devices = (d for d in self._devices[:])
-
- if not incomplete:
- devices = (d for d in devices if getattr(d, "complete", True))
- return devices
-
- def make_dasd_list(self, dasds, disks):
- """ Create a list of DASDs recognized by the system
-
- :param list dasds: a list of DASD devices
- :param list disks: a list of disks on the system
- :returns: a list of DASD devices identified on the system
- :rtype: list of :class:
- """
- if not arch.is_s390():
- return
-
- log.info("Generating DASD list....")
- for dev in (disk for disk in disks if disk.type == "dasd"):
- if dev not in dasds:
- dasds.append(dev)
-
- return dasds
-
- def make_unformatted_dasd_list(self, dasds):
- """ Create a list of DASDs which are detected to require dasdfmt.
-
- :param list dasds: a list of DASD devices
- :returns: a list of DASDs which need dasdfmt in order to be used
- :rtype: list of :class:
- """
- if not arch.is_s390():
- return
-
- unformatted = []
-
- for dasd in dasds:
- if blockdev.s390.dasd_needs_format(dasd.busid):
- unformatted.append(dasd)
-
- return unformatted
-
- def get_device_by_sysfs_path(self, path, incomplete=False, hidden=False):
- """ Return a list of devices with a matching sysfs path.
-
- :param str path: the sysfs path to match
- :param bool incomplete: include incomplete devices in search
- :param bool hidden: include hidden devices in search
- :returns: the first matching device found
- :rtype: :class:`~.devices.Device`
- """
- log_method_call(self, path=path, incomplete=incomplete, hidden=hidden)
- result = None
- if path:
- devices = self._filter_devices(incomplete=incomplete, hidden=hidden)
- result = next((d for d in devices if d.sysfs_path == path), None)
- log_method_return(self, result)
- return result
-
- def get_device_by_uuid(self, uuid, incomplete=False, hidden=False):
- """ Return a list of devices with a matching UUID.
-
- :param str uuid: the UUID to match
- :param bool incomplete: include incomplete devices in search
- :param bool hidden: include hidden devices in search
- :returns: the first matching device found
- :rtype: :class:`~.devices.Device`
- """
- log_method_call(self, uuid=uuid, incomplete=incomplete, hidden=hidden)
- result = None
- if uuid:
- devices = self._filter_devices(incomplete=incomplete, hidden=hidden)
- result = next((d for d in devices if d.uuid == uuid or d.format.uuid == uuid), None)
- log_method_return(self, result)
- return result
-
- @util.deprecated('1.7', '')
- def get_devices_by_serial(self, serial, incomplete=False, hidden=False):
- """ Return a list of devices with a matching serial.
+ @util.deprecated('1.7', '')
+ def get_devices_by_serial(self, serial, incomplete=False, hidden=False):
+ """ Return a list of devices with a matching serial.
:param str serial: the serial to match
:param bool incomplete: include incomplete devices in search
@@ -826,86 +688,12 @@ def get_device_by_id(self, id_num, incomplete=False, hidden=False):
log_method_return(self, result)
return result
- @property
- def devices(self):
- """ List of devices currently in the tree """
- devices = []
- for device in self._devices:
- if not getattr(device, "complete", True):
- continue
-
- if device.uuid and device.uuid in [d.uuid for d in devices] and \
- not isinstance(device, NoDevice):
- raise DeviceTreeError("duplicate uuids in device tree")
-
- devices.append(device)
-
- return devices
-
- @property
- def filesystems(self):
- """ List of filesystems. """
- filesystems = []
- for dev in self.leaves:
- if dev.format and getattr(dev.format, 'mountpoint', None):
- filesystems.append(dev.format)
+ def resolve_device(self, devspec, blkid_tab=None, crypt_tab=None, options=None):
+ """ Return the device matching the provided device specification.
- return filesystems
-
- @property
- def uuids(self):
- """ Dict with uuid keys and :class:`~.devices.Device` values. """
- uuids = {}
- for dev in self._devices:
- try:
- uuid = dev.uuid
- except AttributeError:
- uuid = None
-
- if uuid:
- uuids[uuid] = dev
-
- try:
- uuid = dev.format.uuid
- except AttributeError:
- uuid = None
-
- if uuid:
- uuids[uuid] = dev
-
- return uuids
-
- @property
- def labels(self):
- """ Dict with label keys and Device values.
-
- FIXME: duplicate labels are a possibility
- """
- labels = {}
- for dev in self._devices:
- # don't include btrfs member devices
- if getattr(dev.format, "label", None) and \
- (dev.format.type != "btrfs" or isinstance(dev, BTRFSDevice)):
- labels[dev.format.label] = dev
-
- return labels
-
- @property
- def leaves(self):
- """ List of all devices upon which no other devices exist. """
- leaves = [d for d in self._devices if d.isleaf]
- return leaves
-
- def get_children(self, device):
- """ Return a list of a device's children. """
- return [c for c in self._devices if device in c.parents]
-
- def resolve_device(self, devspec, blkid_tab=None, crypt_tab=None, options=None):
- """ Return the device matching the provided device specification.
-
- The spec can be anything from a device name (eg: 'sda3') to a device
- node path (eg: '/dev/mapper/fedora-root' or '/dev/dm-2') to
- something like 'UUID=xyz-tuv-qrs' or 'LABEL=rootfs'.
+ The spec can be anything from a device name (eg: 'sda3') to a device
+ node path (eg: '/dev/mapper/fedora-root' or '/dev/dm-2') to
+ something like 'UUID=xyz-tuv-qrs' or 'LABEL=rootfs'.
:param devspec: a string describing a block device
:type devspec: str
@@ -1054,56 +842,301 @@ def resolve_device(self, devspec, blkid_tab=None, crypt_tab=None, options=None):
log.debug("failed to resolve '%s'", devspec)
return device
- def handle_nodev_filesystems(self):
- for line in open("/proc/mounts").readlines():
+ #
+ # DASD
+ #
+ def make_dasd_list(self, dasds, disks):
+ """ Create a list of DASDs recognized by the system
+
+ :param list dasds: a list of DASD devices
+ :param list disks: a list of disks on the system
+ :returns: a list of DASD devices identified on the system
+ :rtype: list of :class:
+ """
+ if not arch.is_s390():
+ return
+
+ log.info("Generating DASD list....")
+ for dev in (disk for disk in disks if disk.type == "dasd"):
+ if dev not in dasds:
+ dasds.append(dev)
+
+ return dasds
+
+ def make_unformatted_dasd_list(self, dasds):
+ """ Create a list of DASDs which are detected to require dasdfmt.
+
+ :param list dasds: a list of DASD devices
+ :returns: a list of DASDs which need dasdfmt in order to be used
+ :rtype: list of :class:
+ """
+ if not arch.is_s390():
+ return
+
+ unformatted = []
+
+ for dasd in dasds:
+ if blockdev.s390.dasd_needs_format(dasd.busid):
+ unformatted.append(dasd)
+
+ return unformatted
+
+ #
+ # Conveniences
+ #
+ @property
+ def leaves(self):
+ """ List of all devices upon which no other devices exist. """
+ leaves = [d for d in self._devices if d.isleaf]
+ return leaves
+
+ @property
+ def filesystems(self):
+ """ List of filesystems. """
+ filesystems = []
+ for dev in self.leaves:
+ if dev.format and getattr(dev.format, 'mountpoint', None):
+ filesystems.append(dev.format)
+
+ return filesystems
+
+ @property
+ def uuids(self):
+ """ Dict with uuid keys and :class:`~.devices.Device` values. """
+ uuids = {}
+ for dev in self._devices:
try:
- (_devspec, mountpoint, fstype, _options, _rest) = line.split(None, 4)
- except ValueError:
- log.error("failed to parse /proc/mounts line: %s", line)
- continue
- if fstype in formats.fslib.nodev_filesystems:
- if not flags.include_nodev:
- continue
+ uuid = dev.uuid
+ except AttributeError:
+ uuid = None
- log.info("found nodev %s filesystem mounted at %s",
- fstype, mountpoint)
- # nodev filesystems require some special handling.
- # For now, a lot of this is based on the idea that it's a losing
- # battle to require the presence of an FS class for every type
- # of nodev filesystem. Based on that idea, we just instantiate
- # NoDevFS directly and then hack in the fstype as the device
- # attribute.
- fmt = formats.get_format("nodev")
- fmt.device = fstype
+ if uuid:
+ uuids[uuid] = dev
- # NoDevice also needs some special works since they don't have
- # per-instance names in the kernel.
- device = NoDevice(fmt=fmt)
- n = len([d for d in self.devices if d.format.type == fstype])
- device._name += ".%d" % n
- self._add_device(device)
+ try:
+ uuid = dev.format.uuid
+ except AttributeError:
+ uuid = None
- def save_luks_passphrase(self, device):
- """ Save a device's LUKS passphrase in case of reset. """
+ if uuid:
+ uuids[uuid] = dev
- self._populator.save_luks_passphrase(device)
+ return uuids
- def __str__(self):
- done = []
+ @property
+ def labels(self):
+ """ Dict with label keys and Device values.
- def show_subtree(root, depth):
- abbreviate_subtree = root in done
- s = "%s%s\n" % (" " * depth, root)
- done.append(root)
- if abbreviate_subtree:
- s += "%s...\n" % (" " * (depth + 1),)
- else:
- for child in self.get_children(root):
- s += show_subtree(child, depth + 1)
- return s
+ FIXME: duplicate labels are a possibility
+ """
+ labels = {}
+ for dev in self._devices:
+ # don't include btrfs member devices
+ if getattr(dev.format, "label", None) and \
+ (dev.format.type != "btrfs" or isinstance(dev, BTRFSDevice)):
+ labels[dev.format.label] = dev
- roots = [d for d in self._devices if not d.parents]
- tree = ""
- for root in roots:
- tree += show_subtree(root, 0)
- return tree
+ return labels
+
+ #
+ # Disk filter
+ #
+ @property
+ def exclusive_disks(self):
+ return self._populator.exclusive_disks
+
+ @property
+ def ignored_disks(self):
+ return self._populator.ignored_disks
+
+ def hide(self, device):
+ """ Hide the specified device.
+
+ :param device: the device to hide
+ :type device: :class:`~.devices.StorageDevice`
+
+ Hiding a device will cancel all actions that involve the device and
+ will remove the device from the device list.
+
+ If the device is not a leaf device, all devices that depend on it
+ will be hidden leaves-first until the device is a leaf device.
+
+ If a device exists, performs some special actions and places
+ it on a list of hidden devices.
+
+ Mixes recursion and side effects, most significantly in the code
+ that removes all the actions. However, this code is a null op
+ in every case except the first base case that is reached,
+ where all actions are removed. This means that when a device
+ is removed explicitly in this function by means of a direct call to
+ _remove_devices it is guaranteed that all actions have already
+ been canceled.
+
+ If a device does not exist then it must have been removed by the
+ cancelation of all the actions, so it does not need to be removed
+ explicitly.
+
+ Most devices are considered leaf devices if they have no children,
+ however, some devices must satisfy more stringent requirements.
+ _remove_device() will raise an exception if the device it is
+ removing is not a leaf device. hide() guarantees that any
+ device that it removes will have no children, but it does not
+ guarantee that the more stringent requirements will be enforced.
+ Therefore, _remove_device() is invoked with the force parameter
+ set to True, to skip the isleaf check.
+ """
+ if device in self._hidden:
+ return
+
+ # cancel actions first thing so that we hide the correct set of devices
+ if device.is_disk:
+ # Cancel all actions on this disk and any disk related by way of an
+ # aggregate/container device (eg: lvm volume group).
+ disks = [device]
+ related_actions = [a for a in self._actions
+ if a.device.depends_on(device)]
+ for related_device in (a.device for a in related_actions):
+ disks.extend(related_device.disks)
+
+ disks = set(disks)
+ cancel = [a for a in self._actions
+ if set(a.device.disks).intersection(disks)]
+ for action in reversed(cancel):
+ self.cancel_action(action)
+
+ for d in self.get_children(device):
+ self.hide(d)
+
+ log.info("hiding device %s", device)
+
+ if not device.exists:
+ return
+
+ self._remove_device(device, force=True, modparent=False)
+
+ self._hidden.append(device)
+ lvm.lvm_cc_addFilterRejectRegexp(device.name)
+
+ if isinstance(device, DASDDevice):
+ self.dasd.remove(device)
+
+ if device.name not in self.names:
+ self.names.append(device.name)
+
+ def unhide(self, device):
+ """ Restore a device's visibility.
+
+ :param device: the device to restore/unhide
+ :type device: :class:`~.devices.StorageDevice`
+
+ .. note::
+
+ Actions canceled while hiding the device are not rescheduled
+ automatically.
+
+ """
+
+ # the hidden list should be in leaves-first order
+ for hidden in reversed(self._hidden):
+ if hidden == device or hidden.depends_on(device) and \
+ not any(parent in self._hidden for parent in hidden.parents):
+
+ log.info("unhiding device %s %s (id %d)", hidden.type,
+ hidden.name,
+ hidden.id)
+ self._hidden.remove(hidden)
+ self._devices.append(hidden)
+ hidden.add_hook(new=False)
+ lvm.lvm_cc_removeFilterRejectRegexp(hidden.name)
+ if isinstance(device, DASDDevice):
+ self.dasd.append(device)
+
+ def _is_ignored_disk(self, disk):
+ return ((self.ignored_disks and disk.name in self.ignored_disks) or
+ (self.exclusive_disks and
+ disk.name not in self.exclusive_disks))
+
+ def _hide_ignored_disks(self):
+ # hide any subtrees that begin with an ignored disk
+ for disk in [d for d in self._devices if d.is_disk]:
+ if self._is_ignored_disk(disk):
+ ignored = True
+ # If the filter allows all members of a fwraid or mpath, the
+ # fwraid or mpath itself is implicitly allowed as well. I don't
+ # like this very much but we have supported this usage in the
+ # past, so I guess we will support it forever.
+ if disk.parents and all(p.format.hidden for p in disk.parents):
+ ignored = any(self._is_ignored_disk(d) for d in disk.parents)
+
+ if ignored:
+ self.hide(disk)
+
+ #
+ # Disk images
+ #
+ def set_disk_images(self, images):
+ """ Set the disk images and reflect them in exclusive_disks.
+
+ :param images: dict with image name keys and filename values
+ :type images: dict
+
+ .. note::
+
+ Disk images are automatically exclusive. That means that, in the
+ presence of disk images, any local storage not associated with
+ the disk images is ignored.
+ """
+ self._populator.set_disk_images(images)
+
+ def setup_disk_images(self):
+ """ Set up devices to represent the disk image files. """
+ self._populator.setup_disk_images()
+
+ def teardown_disk_images(self):
+ """ Tear down any disk image stacks. """
+ self._populator.teardown_disk_images()
+
+ @property
+ def disk_images(self):
+ return self._populator.disk_images
+
+ #
+ # Miscellaneous (global) data
+ #
+ @property
+ def pv_info(self):
+ if self._pvs_cache is None:
+ pvs = blockdev.lvm.pvs()
+ self._pvs_cache = dict((pv.pv_name, pv) for pv in pvs) # pylint: disable=attribute-defined-outside-init
+
+ return self._pvs_cache
+
+ @property
+ def lv_info(self):
+ if self._lvs_cache is None:
+ lvs = blockdev.lvm.lvs()
+ self._lvs_cache = dict(("%s-%s" % (lv.vg_name, lv.lv_name), lv) for lv in lvs) # pylint: disable=attribute-defined-outside-init
+
+ return self._lvs_cache
+
+ def drop_lvm_cache(self):
+ """ Drop cached lvm information. """
+ self._pvs_cache = None # pylint: disable=attribute-defined-outside-init
+ self._lvs_cache = None # pylint: disable=attribute-defined-outside-init
+
+ @property
+ def dasd(self):
+ return self._populator.dasd
+
+ @dasd.setter
+ def dasd(self, dasd):
+ self._populator.dasd = dasd
+
+ @property
+ def protected_dev_names(self):
+ return self._populator.protected_dev_names
+
+ def save_luks_passphrase(self, device):
+ """ Save a device's LUKS passphrase in case of reset. """
+
+ self._populator.save_luks_passphrase(device)
--
To view this commit on github, visit https://github.com/rhinstaller/blivet/commit/3acd2238dcb82adee6d82078dababd8beb4adec8
More information about the anaconda-patches
mailing list