def gen_holders_tree(device): """ generate a tree representing the current storage hirearchy above 'device' """ device = block.sys_block_path(device) dev_name = block.path_to_kname(device) # the holders for a device should consist of the devices in the holders/ # dir in sysfs and any partitions on the device. this ensures that a # storage tree starting from a disk will include all devices holding the # disk's partitions holder_paths = ([block.sys_block_path(h) for h in get_holders(device)] + block.get_sysfs_partitions(device)) # the DEV_TYPE registry contains a function under the key 'ident' for each # device type entry that returns true if the device passed to it is of the # correct type. there should never be a situation in which multiple # identify functions return true. therefore, it will always work to take # the device type with the first identify function that returns true as the # device type for the current device. in the event that no identify # functions return true, the device will be treated as a disk # (DEFAULT_DEV_TYPE). the identify function for disk never returns true. # the next() builtin in python will not raise a StopIteration exception if # there is a default value defined dev_type = next((k for k, v in DEV_TYPES.items() if v['ident'](device)), DEFAULT_DEV_TYPE) return { 'device': device, 'dev_type': dev_type, 'name': dev_name, 'holders': [gen_holders_tree(h) for h in holder_paths], }
def test_cciss_sysfs_path(self, m_os_path_exists, m_get_blk): m_os_path_exists.return_value = True m_get_blk.return_value = ('cciss!c0d0', None) self.assertEqual('/sys/class/block/cciss!c0d0', block.sys_block_path('/dev/cciss/c0d0')) m_get_blk.return_value = ('cciss!c0d0', 1) self.assertEqual('/sys/class/block/cciss!c0d0/cciss!c0d0p1', block.sys_block_path('/dev/cciss/c0d0p1'))
def md_sysfs_attr_path(md_devname, attrname): """ Return the path to a md device attribute under the 'md' dir """ # build /sys/class/block/<md_short>/md sysmd = sys_block_path(md_devname, "md") # append attrname return os.path.join(sysmd, attrname)
def shutdown_lvm(device): """ Shutdown specified lvm device. """ device = block.sys_block_path(device) # lvm devices have a dm directory that containes a file 'name' containing # '{volume group}-{logical volume}'. The volume can be freed using lvremove name_file = os.path.join(device, 'dm', 'name') lvm_name = util.load_file(name_file).strip() (vg_name, lv_name) = lvm.split_lvm_name(lvm_name) vg_lv_name = "%s/%s" % (vg_name, lv_name) devname = "/dev/" + vg_lv_name # wipe contents of the logical volume first LOG.info('Wiping lvm logical volume: %s', devname) block.quick_zero(devname, partitions=False) # remove the logical volume LOG.debug('using "lvremove" on %s', vg_lv_name) util.subp(['lvremove', '--force', '--force', vg_lv_name]) # if that was the last lvol in the volgroup, get rid of volgroup if len(lvm.get_lvols_in_volgroup(vg_name)) == 0: pvols = lvm.get_pvols_in_volgroup(vg_name) util.subp(['vgremove', '--force', '--force', vg_name], rcs=[0, 5]) # wipe the underlying physical volumes for pv in pvols: LOG.info('Wiping lvm physical volume: %s', pv) block.quick_zero(pv, partitions=False) # refresh lvmetad lvm.lvm_scan()
def md_get_devices_list(devpath): sysfs_md = sys_block_path(devpath, "md") devices = [ dev_path(dev[4:]) for dev in os.listdir(sysfs_md) if (dev.startswith('dev-') and util.load_file( os.path.join(sysfs_md, dev, 'state')).strip() != 'spare') ] return devices
def get_holders(device): """ Look up any block device holders, return list of knames """ # block.sys_block_path works when given a /sys or /dev path sysfs_path = block.sys_block_path(device) # get holders holders = os.listdir(os.path.join(sysfs_path, 'holders')) LOG.debug("devname '%s' had holders: %s", device, holders) return holders
def assert_clear(base_paths): """ Check if all paths in base_paths are clear to use """ valid = ('disk', 'partition') if not isinstance(base_paths, (list, tuple)): base_paths = [base_paths] base_paths = [block.sys_block_path(path) for path in base_paths] for holders_tree in [gen_holders_tree(p) for p in base_paths]: if any(holder_type not in valid and path not in base_paths for (holder_type, path) in get_holder_types(holders_tree)): raise OSError('Storage not clear, remaining:\n{}'.format( format_holders_tree(holders_tree)))
def identify_partition(device): """ determine if specified device is a partition """ blockdev = block.sys_block_path(device) path = os.path.join(blockdev, 'partition') if os.path.exists(path): return True if multipath.is_mpath_partition(blockdev): return True return False
def get_bcache_sys_path(device, strict=True): """ Get the /sys/class/block/<device>/bcache path """ sysfs_path = block.sys_block_path(device, strict=strict) path = os.path.join(sysfs_path, 'bcache') if strict and not os.path.exists(path): err = OSError("device '{}' did not have existing syspath '{}'".format( device, path)) err.errno = errno.ENOENT raise err return path
def get_bcache_using_dev(device, strict=True): """ Get the /sys/fs/bcache/ path of the bcache cache device bound to specified device """ # FIXME: when block.bcache is written this should be moved there sysfs_path = block.sys_block_path(device) path = os.path.realpath(os.path.join(sysfs_path, 'bcache', 'cache')) if strict and not os.path.exists(path): err = OSError("device '{}' did not have existing syspath '{}'".format( device, path)) err.errno = errno.ENOENT raise err return path
def test_not_strict_does_not_care(self, m_os_path_exists, m_get_blk): m_os_path_exists.return_value = False m_get_blk.return_value = ('foodev', None) self.assertEqual('/sys/class/block/foodev/md/b', block.sys_block_path("foodev", "/md/b", strict=False))
def test_invalid_devname_raises(self, m_os_path_exists, m_get_blk): m_os_path_exists.return_value = False with self.assertRaises(ValueError): block.sys_block_path("foodevice")
def test_add_works_leading_slash(self, m_os_path_exists, m_get_blk): m_os_path_exists.return_value = True m_get_blk.return_value = ('foodev', None) self.assertEqual('/sys/class/block/foodev/md/b', block.sys_block_path("/dev/foodev", "/md/b"))
def test_existing_devpath_allowed(self, m_os_path_exists, m_get_blk): m_os_path_exists.return_value = True m_get_blk.return_value = ('foodev', None) self.assertEqual('/sys/class/block/foodev', block.sys_block_path("/dev/foodev"))
def test_existing_valid_devname(self, m_os_path_exists, m_get_blk): m_os_path_exists.return_value = True m_get_blk.return_value = ('foodevice', None) self.assertEqual('/sys/class/block/foodevice', block.sys_block_path("foodevice"))
def test_cciss_sysfs_path(self, m_os_path_exists): m_os_path_exists.return_value = True self.assertEqual('/sys/class/block/cciss!c0d0', block.sys_block_path('/dev/cciss/c0d0'))
def test_add_works(self, m_os_path_exists): m_os_path_exists.return_value = True self.assertEqual('/sys/class/block/foodev/md/b', block.sys_block_path("/dev/foodev", "md/b"))
def identify_partition(device): """ determine if specified device is a partition """ path = os.path.join(block.sys_block_path(device), 'partition') return os.path.exists(path)