Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Don't crash in populate when blockdev plugins are missing. #686

Open
wants to merge 2 commits into
base: 3.1-devel
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions blivet/dependencies.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@

import abc
import gi
import six

gi.require_version("BlockDev", "2.0")
from gi.repository import BlockDev as blockdev

from .util import DependencyGuard


@six.add_metaclass(abc.ABCMeta)
class BlockDevDependencyGuard(DependencyGuard):
_tech = abc.abstractproperty(doc="BlockDev tech list")
_mode = abc.abstractproperty(doc="BlockDev tech mode")
_is_tech_avail = abc.abstractproperty(doc="BlockDev tech check method")

def _check_avail(self):
try:
return all(self.__class__._is_tech_avail(tech, self.__class__._mode) for tech in self.__class__._tech)
except blockdev.BlockDevNotImplementedError: # pylint: disable=catching-non-exception
return False


class DMDependencyGuard(BlockDevDependencyGuard):
error_msg = "libblockdev device-mapper functionality not available"
_tech = [blockdev.DMTech.MAP]
_mode = blockdev.DMTechMode.QUERY
_is_tech_avail = blockdev.dm.is_tech_avail

blockdev_dm_required = DMDependencyGuard()


class DMRaidDependencyGuard(DMDependencyGuard):
error_msg = "libblockdev dmraid functionality not available"
_tech = [blockdev.DMTech.RAID]

blockdev_dmraid_required = DMRaidDependencyGuard()


class LoopDependencyGuard(BlockDevDependencyGuard):
error_msg = "libblockdev loop functionality not available"
_tech = [blockdev.LoopTech.LOOP_TECH_LOOP]
_mode = blockdev.LoopTechMode.QUERY
_is_tech_avail = blockdev.loop.is_tech_avail

blockdev_loop_required = LoopDependencyGuard()


class LUKSDependencyGuard(BlockDevDependencyGuard):
error_msg = "libblockdev LUKS functionality not available"
_tech = [blockdev.CryptoTech.LUKS]
_mode = blockdev.CryptoTechMode.QUERY
_is_tech_avail = blockdev.crypto.is_tech_avail

blockdev_luks_required = LUKSDependencyGuard()


class LVMDependencyGuard(BlockDevDependencyGuard):
error_msg = "libblockdev LVM functionality not available"
_tech = [blockdev.LVMTech.BASIC,
blockdev.LVMTech.BASIC_SNAP,
blockdev.LVMTech.THIN,
blockdev.LVMTech.CACHE,
blockdev.LVMTech.CALCS,
blockdev.LVMTech.THIN_CALCS,
blockdev.LVMTech.CACHE_CALCS,
blockdev.LVMTech.GLOB_CONF]
_mode = blockdev.LVMTechMode.QUERY
_is_tech_avail = blockdev.lvm.is_tech_avail

blockdev_lvm_required = LVMDependencyGuard()


class MDDependencyGuard(BlockDevDependencyGuard):
error_msg = "libblockdev MD RAID functionality not available"
_tech = [blockdev.MDTech.MD_TECH_MDRAID]
_mode = blockdev.MDTechMode.QUERY
_is_tech_avail = blockdev.md.is_tech_avail

blockdev_md_required = MDDependencyGuard()


class MultipathDependencyGuard(BlockDevDependencyGuard):
error_msg = "libblockdev multipath functionality not available"
_tech = [blockdev.MpathTech.BASE,
blockdev.MpathTech.FRIENDLY_NAMES]
_mode = blockdev.MpathTechMode.QUERY
_is_tech_avail = blockdev.mpath.is_tech_avail

blockdev_mpath_required = MultipathDependencyGuard()
2 changes: 2 additions & 0 deletions blivet/populator/helpers/disk.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

from ... import udev
from ... import util
from ... import dependencies
from ...devices import DASDDevice, DiskDevice, FcoeDiskDevice, iScsiDiskDevice
from ...devices import MDBiosRaidArrayDevice, ZFCPDiskDevice, NVDIMMNamespaceDevice
from ...devices import device_path_to_name
Expand Down Expand Up @@ -136,6 +137,7 @@ class MDBiosRaidDevicePopulator(DiskDevicePopulator):
_device_class = MDBiosRaidArrayDevice

@classmethod
@dependencies.blockdev_md_required()
def match(cls, data):
return (super(MDBiosRaidDevicePopulator, MDBiosRaidDevicePopulator).match(data) and
udev.device_get_md_container(data))
Expand Down
4 changes: 3 additions & 1 deletion blivet/populator/helpers/disklabel.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import os
import six

from ... import dependencies
from ... import formats
from ... import udev
from ...errors import InvalidDiskLabelError
Expand All @@ -44,7 +45,8 @@ def match(cls, data, device):
return (bool(udev.device_get_disklabel_type(data)) and
not udev.device_is_biosraid_member(data) and
udev.device_get_format(data) != "iso9660" and
not (device.is_disk and mpath_members.is_mpath_member(device.path)))
not (device.is_disk and dependencies.blockdev_mpath_required.check_avail() and
mpath_members.is_mpath_member(device.path)))

def _get_kwargs(self):
kwargs = super(DiskLabelFormatPopulator, self)._get_kwargs()
Expand Down
2 changes: 2 additions & 0 deletions blivet/populator/helpers/dm.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#

from ... import udev
from ... import dependencies
from ...devices import DMDevice
from ...devicelibs import lvm
from ...storage_log import log_method_call
Expand All @@ -34,6 +35,7 @@ class DMDevicePopulator(DevicePopulator):
priority = 50

@classmethod
@dependencies.blockdev_dm_required()
def match(cls, data):
return (udev.device_is_dm(data) and
not udev.device_is_dm_partition(data) and
Expand Down
6 changes: 6 additions & 0 deletions blivet/populator/helpers/dmraid.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

from gi.repository import BlockDev as blockdev

from ... import dependencies
from ... import udev
from ...devices import DMRaidArrayDevice
from ...flags import flags
Expand All @@ -39,6 +40,11 @@ class DMRaidFormatPopulator(FormatPopulator):
priority = 100
_type_specifier = "dmraidmember"

@classmethod
@dependencies.blockdev_dmraid_required()
def match(cls, data, device):
return super(cls, cls).match(data, device)

def run(self):
super(DMRaidFormatPopulator, self).run()

Expand Down
2 changes: 2 additions & 0 deletions blivet/populator/helpers/loop.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
gi.require_version("BlockDev", "2.0")
from gi.repository import BlockDev as blockdev

from ... import dependencies
from ... import udev
from ...devices import FileDevice, LoopDevice
from ...storage_log import log_method_call
Expand All @@ -32,6 +33,7 @@

class LoopDevicePopulator(DevicePopulator):
@classmethod
@dependencies.blockdev_loop_required()
def match(cls, data):
return udev.device_is_loop(data)

Expand Down
6 changes: 5 additions & 1 deletion blivet/populator/helpers/luks.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
class LUKSDevicePopulator(DevicePopulator):
@classmethod
def match(cls, data):
return udev.device_is_dm_luks(data)
return not LUKSDevice.unavailable_type_dependencies() and udev.device_is_dm_luks(data)

def run(self):
parents = self._devicetree._add_slave_devices(self.data)
Expand All @@ -56,6 +56,10 @@ class LUKSFormatPopulator(FormatPopulator):
priority = 100
_type_specifier = "luks"

@classmethod
def match(cls, data, device):
return not LUKSDevice.unavailable_type_dependencies() and super(cls, cls).match(data, device)

def _get_kwargs(self):
kwargs = super(LUKSFormatPopulator, self)._get_kwargs()
kwargs["name"] = "luks-%s" % udev.device_get_uuid(self.data)
Expand Down
7 changes: 7 additions & 0 deletions blivet/populator/helpers/lvm.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

from ...callbacks import callbacks
from ... import udev
from ... import dependencies
from ...devicelibs import lvm
from ...devices.lvm import LVMVolumeGroupDevice, LVMLogicalVolumeDevice, LVMInternalLVtype
from ...errors import DeviceTreeError, DuplicateVGError
Expand All @@ -44,6 +45,7 @@

class LVMDevicePopulator(DevicePopulator):
@classmethod
@dependencies.blockdev_lvm_required()
def match(cls, data):
return udev.device_is_dm_lvm(data)

Expand Down Expand Up @@ -84,6 +86,11 @@ class LVMFormatPopulator(FormatPopulator):
priority = 100
_type_specifier = "lvmpv"

@classmethod
@dependencies.blockdev_lvm_required()
def match(cls, data, device):
return super(cls, cls).match(data, device)

def _get_kwargs(self):
kwargs = super(LVMFormatPopulator, self)._get_kwargs()

Expand Down
7 changes: 7 additions & 0 deletions blivet/populator/helpers/mdraid.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import re

from ... import udev
from ...import dependencies
from ...devicelibs import raid
from ...devices import MDRaidArrayDevice, MDContainerDevice
from ...devices import device_path_to_name
Expand All @@ -43,6 +44,7 @@

class MDDevicePopulator(DevicePopulator):
@classmethod
@dependencies.blockdev_md_required()
def match(cls, data):
return (udev.device_is_md(data) and
not udev.device_get_md_container(data))
Expand Down Expand Up @@ -96,6 +98,11 @@ class MDFormatPopulator(FormatPopulator):
priority = 100
_type_specifier = "mdmember"

@classmethod
@dependencies.blockdev_md_required()
def match(cls, data, device):
return super(cls, cls).match(data, device)

def _get_kwargs(self):
kwargs = super(MDFormatPopulator, self)._get_kwargs()
try:
Expand Down
3 changes: 2 additions & 1 deletion blivet/populator/helpers/multipath.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@
class MultipathDevicePopulator(DevicePopulator):
@classmethod
def match(cls, data):
return (udev.device_is_dm_mpath(data) and
return (not MultipathDevice.unavailable_type_dependencies() and
udev.device_is_dm_mpath(data) and
not udev.device_is_dm_partition(data))

def run(self):
Expand Down
4 changes: 2 additions & 2 deletions blivet/populator/helpers/partition.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

from ... import udev
from ...devicelibs import lvm
from ...devices import PartitionDevice
from ...devices import PartitionDevice, MDRaidArrayDevice
from ...errors import DeviceError
from ...formats import get_format
from ...storage_log import log_method_call
Expand All @@ -51,7 +51,7 @@ def run(self):
log_method_call(self, name=name)
sysfs_path = udev.device_get_sysfs_path(self.data)

if name.startswith("md"):
if name.startswith("md") and not MDRaidArrayDevice.unavailable_type_dependencies():
name = blockdev.md.name_from_node(name)
device = self._devicetree.get_device_by_name(name)
if device:
Expand Down
9 changes: 7 additions & 2 deletions blivet/populator/populator.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,8 @@ def _handle_degraded_md(self, info, device):
# If the md name is None, then some udev info is missing. Likely,
# this is because the array is degraded, and mdadm has deactivated
# it. Try to activate it and re-get the udev info.
if flags.allow_imperfect_devices and udev.device_get_md_name(info) is None:
if flags.allow_imperfect_devices and udev.device_get_md_name(info) is None and \
MDRaidArrayDevice.unavailable_type_dependencies():
devname = udev.device_get_devname(info)
if devname:
try:
Expand Down Expand Up @@ -333,6 +334,10 @@ def set_disk_images(self, images):

def setup_disk_images(self):
""" Set up devices to represent the disk image files. """
if LoopDevice.unavailable_type_dependencies():
log.error("Cannot set up disk images without libblockdev loop plugin.")
return

for (name, path) in self.disk_images.items():
log.info("setting up disk image file '%s' as '%s'", path, name)
dmdev = self.get_device_by_name(name)
Expand Down Expand Up @@ -427,7 +432,7 @@ def _populate(self):
self.drop_lvm_cache()
mpath_members.drop_cache()

if flags.auto_dev_updates and not flags.image_install:
if flags.auto_dev_updates and not flags.image_install and MultipathDevice.unavailable_type_dependencies():
blockdev.mpath.set_friendly_names(flags.multipath_friendly_names)

self.setup_disk_images()
Expand Down
3 changes: 3 additions & 0 deletions blivet/udev.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import logging
import pyudev

from . import dependencies
from . import util
from .size import Size
from .flags import flags
Expand Down Expand Up @@ -582,13 +583,15 @@ def device_get_lv_type(info):
return info['LVM2_SEGTYPE']


@dependencies.blockdev_dm_required()
def device_dm_subsystem_match(info, subsystem):
""" Return True if the device matches a given device-mapper subsystem. """
name = info.get("DM_NAME")
if name is None:
return False

_subsystem = blockdev.dm.get_subsystem_from_name(name)

if not _subsystem:
return False

Expand Down