Esempio n. 1
0
def lookup_disk(serial):
    """
    Search for a disk by its serial number using /dev/disk/by-id/
    """
    # Get all volumes in /dev/disk/by-id/ containing the serial string. The
    # string specified can be either in the short or long serial format
    # hack, some serials have spaces, udev usually converts ' ' -> '_'
    serial_udev = serial.replace(' ', '_')
    LOG.info('Processing serial %s via udev to %s', serial, serial_udev)

    disks = list(
        filter(lambda x: serial_udev in x, os.listdir("/dev/disk/by-id/")))
    if not disks or len(disks) < 1:
        raise ValueError("no disk with serial '%s' found" % serial_udev)

    # Sort by length and take the shortest path name, as the longer path names
    # will be the partitions on the disk. Then use os.path.realpath to
    # determine the path to the block device in /dev/
    disks.sort(key=lambda x: len(x))
    LOG.debug('lookup_disks found: %s', disks)
    path = os.path.realpath("/dev/disk/by-id/%s" % disks[0])
    # /dev/dm-X
    if multipath.is_mpath_device(path):
        info = udevadm_info(path)
        path = os.path.join('/dev/mapper', info['DM_NAME'])
    # /dev/sdX
    elif multipath.is_mpath_member(path):
        mp_name = multipath.find_mpath_id_by_path(path)
        path = os.path.join('/dev/mapper', mp_name)

    if not os.path.exists(path):
        raise ValueError("path '%s' to block device for disk with serial '%s' \
            does not exist" % (path, serial_udev))
    LOG.debug('block.lookup_disk() returning path %s', path)
    return path
Esempio n. 2
0
def _device_is_multipathed(devpath):
    devpath = os.path.realpath(devpath)
    info = udevadm_info(devpath)
    if multipath.is_mpath_device(devpath, info=info):
        return True
    if multipath.is_mpath_partition(devpath, info=info):
        return True

    if devpath.startswith('/dev/dm-'):
        # check members of composed devices (LVM, dm-crypt)
        if 'DM_LV_NAME' in info:
            volgroup = info.get('DM_VG_NAME')
            if volgroup:
                if any((multipath.is_mpath_member(pv)
                        for pv in lvm.get_pvols_in_volgroup(volgroup))):
                    return True

    elif devpath.startswith('/dev/md'):
        if any((multipath.is_mpath_member(md)
                for md in md_get_devices_list(devpath) +
                md_get_spares_list(devpath))):
            return True

    result = multipath.is_mpath_member(devpath)
    return result
Esempio n. 3
0
 def test_is_mpath_device_false(self):
     """is_mpath_device returns false when DM_UUID doesnt start w/ mpath-"""
     self.m_udev.udevadm_info.return_value = {'DM_UUID': 'lvm-vg-foo-lv1'}
     self.assertFalse(multipath.is_mpath_device(self.random_string()))
Esempio n. 4
0
 def test_is_mpath_device_true(self):
     """is_mpath_device returns true if dev DM_UUID starts with mpath-"""
     self.m_udev.udevadm_info.return_value = {'DM_UUID': 'mpath-mpatha-foo'}
     self.assertTrue(multipath.is_mpath_device(self.random_string()))
Esempio n. 5
0
def wipe_superblock(device):
    """
    Wrapper for block.wipe_volume compatible with shutdown function interface
    """
    blockdev = block.sysfs_to_devpath(device)
    # when operating on a disk that used to have a dos part table with an
    # extended partition, attempting to wipe the extended partition will fail
    try:
        if not block.is_online(blockdev):
            LOG.debug("Device is not online (size=0), so skipping:"
                      " '%s'", blockdev)
            return

        if block.is_extended_partition(blockdev):
            LOG.info(
                "extended partitions do not need wiping, so skipping:"
                " '%s'", blockdev)
            return
    except OSError as e:
        if util.is_file_not_found_exc(e):
            LOG.debug('Device to wipe disappeared: %s', e)
            LOG.debug('/proc/partitions says: %s',
                      util.load_file('/proc/partitions'))

            (parent, partnum) = block.get_blockdev_for_partition(blockdev)
            out, _e = util.subp(['sfdisk', '-d', parent],
                                capture=True,
                                combine_capture=True)
            LOG.debug('Disk partition info:\n%s', out)
            return
        else:
            raise e

    # gather any partitions
    partitions = block.get_sysfs_partitions(device)

    # release zfs member by exporting the pool
    if zfs.zfs_supported() and block.is_zfs_member(blockdev):
        poolname = zfs.device_to_poolname(blockdev)
        # only export pools that have been imported
        if poolname in zfs.zpool_list():
            try:
                zfs.zpool_export(poolname)
            except util.ProcessExecutionError as e:
                LOG.warning('Failed to export zpool "%s": %s', poolname, e)

    if is_swap_device(blockdev):
        shutdown_swap(blockdev)

    # some volumes will be claimed by the bcache layer but do not surface
    # an actual /dev/bcacheN device which owns the parts (backing, cache)
    # The result is that some volumes cannot be wiped while bcache claims
    # the device.  Resolve this by stopping bcache layer on those volumes
    # if present.
    for bcache_path in ['bcache', 'bcache/set']:
        stop_path = os.path.join(device, bcache_path)
        if os.path.exists(stop_path):
            LOG.debug('Attempting to release bcache layer from device: %s:%s',
                      device, stop_path)
            if stop_path.endswith('set'):
                rp = os.path.realpath(stop_path)
                bcache.stop_cacheset(rp)
            else:
                bcache._stop_device(stop_path)

    _wipe_superblock(blockdev)

    # if we had partitions, make sure they've been removed
    if partitions:
        LOG.debug('%s had partitions, issuing partition reread', device)
        retries = [.5, .5, 1, 2, 5, 7]
        for attempt, wait in enumerate(retries):
            try:
                # only rereadpt on wiped device
                block.rescan_block_devices(devices=[blockdev])
                # may raise IOError, OSError due to wiped partition table
                curparts = block.get_sysfs_partitions(device)
                if len(curparts) == 0:
                    return
            except (IOError, OSError):
                if attempt + 1 >= len(retries):
                    raise

            LOG.debug(
                "%s partitions still present, rereading pt"
                " (%s/%s).  sleeping %ss before retry", device, attempt + 1,
                len(retries), wait)
            time.sleep(wait)

    # multipath partitions are separate block devices (disks)
    if multipath.is_mpath_partition(blockdev):
        multipath.remove_partition(blockdev)
    # multipath devices must be hidden to utilize a single member (path)
    elif multipath.is_mpath_device(blockdev):
        mp_id = multipath.find_mpath_id(blockdev)
        if mp_id:
            multipath.remove_map(mp_id)
        else:
            raise RuntimeError('Failed to find multipath id for %s' % blockdev)
Esempio n. 6
0
 def is_mpath_device(self, blockdev):
     return multipath.is_mpath_device(blockdev.get('DEVNAME', ''), blockdev)
 def test_is_mpath_device_false(self):
     self.m_udev.udevadm_info.return_value = {'DM_UUID': 'lvm-vg-foo-lv1'}
     self.assertFalse(multipath.is_mpath_device(self.random_string()))
 def test_is_mpath_device_true(self):
     self.m_udev.udevadm_info.return_value = {'DM_UUID': 'mpath-mpatha-foo'}
     self.assertTrue(multipath.is_mpath_device(self.random_string()))