def get_next_device_name(instance, device_name_list, root_device_name=None, device=None): """Validates (or generates) a device name for instance. If device is not set, it will generate a unique device appropriate for the instance. It uses the root_device_name (if provided) and the list of used devices to find valid device names. If the device name is valid but applicable to a different backend (for example /dev/vdc is specified but the backend uses /dev/xvdc), the device name will be converted to the appropriate format. """ req_prefix = None req_letter = None if device: try: req_prefix, req_letter = block_device.match_device(device) except (TypeError, AttributeError, ValueError): raise exception.InvalidDevicePath(path=device) if not root_device_name: root_device_name = block_device.DEFAULT_ROOT_DEV_NAME try: prefix = block_device.match_device( block_device.prepend_dev(root_device_name))[0] except (TypeError, AttributeError, ValueError): raise exception.InvalidDevicePath(path=root_device_name) # NOTE(vish): remove this when xenapi is setting default_root_device if driver.is_xenapi(): prefix = '/dev/xvd' if req_prefix != prefix: LOG.debug("Using %(prefix)s instead of %(req_prefix)s", {'prefix': prefix, 'req_prefix': req_prefix}) used_letters = set() for device_path in device_name_list: letter = block_device.get_device_letter(device_path) used_letters.add(letter) # NOTE(vish): remove this when xenapi is properly setting # default_ephemeral_device and default_swap_device if driver.is_xenapi(): flavor = instance.get_flavor() if flavor.ephemeral_gb: used_letters.add('b') if flavor.swap: used_letters.add('c') if not req_letter: req_letter = _get_unused_letter(used_letters) if req_letter in used_letters: raise exception.DevicePathInUse(path=device) return prefix + req_letter
def remove_block_dev(devpath, scan_timeout=10): """Remove a block device from the management partition. This method causes the operating system of the management partition to delete the device special files associated with the specified block device. :param devpath: Any path to the block special file associated with the device to be removed. :param scan_timeout: The maximum number of seconds after scanning to wait for the specified device to disappear. :raise InvalidDevicePath: If the specified device or its 'delete' special file cannot be found. :raise DeviceDeletionException: If the deletion was attempted, but the device special file is still present afterward. """ # Resolve symlinks, if any, to get to the /dev/sdX path devpath = os.path.realpath(devpath) try: os.stat(devpath) except OSError: raise exception.InvalidDevicePath(path=devpath) devname = devpath.rsplit('/', 1)[-1] delpath = '/sys/block/%s/device/delete' % devname try: os.stat(delpath) except OSError: raise exception.InvalidDevicePath(path=delpath) LOG.debug( "Deleting block device %(devpath)s from the management " "partition via special file %(delpath)s.", { 'devpath': devpath, 'delpath': delpath }) # Writing '1' to this sysfs file deletes the block device and rescans. priv_path.writefile(delpath, 'a', '1') # The bus scan is asynchronous. Need to poll, waiting for the device to # disappear. Stop when stat raises OSError (dev file not found) - which is # success - or after the specified timeout (which is failure). Sleep 1/4 # second between polls. @retrying.retry(retry_on_result=lambda result: result, wait_fixed=250, stop_max_delay=scan_timeout * 1000) def _poll_for_del(statpath): try: os.stat(statpath) return True except OSError: # Device special file is absent, as expected return False try: _poll_for_del(devpath) except retrying.RetryError as re: # stat just kept returning (dev file continued to exist). raise npvmex.DeviceDeletionException( devpath=devpath, polls=re.last_attempt.attempt_number, timeout=scan_timeout)
def get_device_name_for_instance(context, instance, bdms, device): """Validates (or generates) a device name for instance. If device is not set, it will generate a unique device appropriate for the instance. It uses the block device mapping table to find valid device names. If the device name is valid but applicable to a different backend (for example /dev/vdc is specified but the backend uses /dev/xvdc), the device name will be converted to the appropriate format. """ req_prefix = None req_letter = None if device: try: req_prefix, req_letter = block_device.match_device(device) except (TypeError, AttributeError, ValueError): raise exception.InvalidDevicePath(path=device) mappings = block_device.instance_block_mapping(instance, bdms) try: prefix = block_device.match_device(mappings['root'])[0] except (TypeError, AttributeError, ValueError): raise exception.InvalidDevicePath(path=mappings['root']) # NOTE(vish): remove this when xenapi is setting default_root_device if driver.compute_driver_matches('xenapi.XenAPIDriver'): prefix = '/dev/xvd' if req_prefix != prefix: LOG.debug(_("Using %(prefix)s instead of %(req_prefix)s") % locals()) used_letters = set() for device_path in mappings.itervalues(): letter = block_device.strip_prefix(device_path) # NOTE(vish): delete numbers in case we have something like # /dev/sda1 letter = re.sub("\d+", "", letter) used_letters.add(letter) # NOTE(vish): remove this when xenapi is properly setting # default_ephemeral_device and default_swap_device if driver.compute_driver_matches('xenapi.XenAPIDriver'): instance_type = instance_types.extract_instance_type(instance) if instance_type['ephemeral_gb']: used_letters.add('b') if instance_type['swap']: used_letters.add('c') if not req_letter: req_letter = _get_unused_letter(used_letters) if req_letter in used_letters: raise exception.DevicePathInUse(path=device) device_name = prefix + req_letter return device_name
def __init__(self, instance=None, disk_name=None, path=None, **kwargs): super(Rbd, self).__init__("block", "rbd", is_block_dev=False) if path: try: self.rbd_name = path.split('/')[1] except IndexError: raise exception.InvalidDevicePath(path=path) else: self.rbd_name = '%s_%s' % (instance.uuid, disk_name) if not CONF.libvirt.images_rbd_pool: raise RuntimeError(_('You should specify' ' images_rbd_pool' ' flag to use rbd images.')) self.pool = CONF.libvirt.images_rbd_pool self.discard_mode = get_hw_disk_discard( CONF.libvirt.hw_disk_discard) self.rbd_user = CONF.libvirt.rbd_user self.ceph_conf = CONF.libvirt.images_rbd_ceph_conf self.driver = rbd_utils.RBDDriver( pool=self.pool, ceph_conf=self.ceph_conf, rbd_user=self.rbd_user) self.path = 'rbd:%s/%s' % (self.pool, self.rbd_name) if self.rbd_user: self.path += ':id=' + self.rbd_user if self.ceph_conf: self.path += ':conf=' + self.ceph_conf
def __init__(self, instance=None, disk_name=None, path=None, **kwargs): super(Rbd, self).__init__("block", "rbd", is_block_dev=True) if path: try: self.rbd_name = path.split('/')[1] except IndexError: raise exception.InvalidDevicePath(path=path) else: self.rbd_name = '%s_%s' % (instance['uuid'], disk_name) if not CONF.libvirt.images_rbd_pool: raise RuntimeError( _('You should specify' ' images_rbd_pool' ' flag to use rbd images.')) self.pool = CONF.libvirt.images_rbd_pool self.ceph_conf = ascii_str(CONF.libvirt.images_rbd_ceph_conf) self.rbd_user = ascii_str(CONF.libvirt.rbd_user) self.rbd = kwargs.get('rbd', rbd) self.rados = kwargs.get('rados', rados) self.path = 'rbd:%s/%s' % (self.pool, self.rbd_name) if self.rbd_user: self.path += ':id=' + self.rbd_user if self.ceph_conf: self.path += ':conf=' + self.ceph_conf
def _check_device_paths(self, device_paths): if len(device_paths) > 1: err_msg = _("Multiple disk paths were found: %s. This can " "occur if multipath is used and MPIO is not " "properly configured, thus not claiming the device " "paths. This issue must be addressed urgently as " "it can lead to data corruption.") raise exception.InvalidDevicePath(err_msg % device_paths) elif not device_paths: err_msg = _("Could not find the physical disk " "path for the requested volume.") raise exception.DiskNotFound(err_msg)
def get_device_name_for_instance(context, instance, device): """Validates (or generates) a device name for instance. If device is not set, it will generate a unique device appropriate for the instance. It uses the block device mapping table to find valid device names. If the device name is valid but applicable to a different backend (for example /dev/vdc is specified but the backend uses /dev/xvdc), the device name will be converted to the appropriate format. """ req_prefix = None req_letters = None if device: try: req_prefix, req_letters = block_device.match_device(device) except (TypeError, AttributeError, ValueError): raise exception.InvalidDevicePath(path=device) bdms = db.block_device_mapping_get_all_by_instance(context, instance['uuid']) mappings = block_device.instance_block_mapping(instance, bdms) try: prefix = block_device.match_device(mappings['root'])[0] except (TypeError, AttributeError, ValueError): raise exception.InvalidDevicePath(path=mappings['root']) if req_prefix != prefix: LOG.debug(_("Using %(prefix)s instead of %(req_prefix)s") % locals()) letters_list = [] for _name, device in mappings.iteritems(): letter = block_device.strip_prefix(device) # NOTE(vish): delete numbers in case we have something like # /dev/sda1 letter = re.sub("\d+", "", letter) letters_list.append(letter) used_letters = set(letters_list) if not req_letters: req_letters = _get_unused_letters(used_letters) if req_letters in used_letters: raise exception.DevicePathInUse(path=device) return prefix + req_letters
def attach_volume(self, context, instance, volume_id, device=None): """Attach an existing volume to an existing instance.""" if device and not block_device.match_device(device): raise exception.InvalidDevicePath(path=device) try: volume = self.volume_api.get(context, volume_id) self.volume_api.check_attach(context, volume, instance=instance) except Exception: with excutils.save_and_reraise_exception(): self.db.block_device_mapping_destroy_by_instance_and_device( context, instance['uuid'], device) return self._call_to_cells(context, instance, 'attach_volume', volume_id, device)
def attach_volume(self, context, instance, volume_id, device=None, disk_bus=None, device_type=None): """Attach an existing volume to an existing instance.""" if device and not block_device.match_device(device): raise exception.InvalidDevicePath(path=device) volume = self.volume_api.get(context, volume_id) self.volume_api.check_attach(context, volume, instance=instance) return self._call_to_cells(context, instance, 'attach_volume', volume_id, device, disk_bus, device_type)
def __init__(self, instance=None, disk_name=None, path=None, snapshot_name=None, **kwargs): super(Rbd, self).__init__("block", "rbd", is_block_dev=True) if path: try: self.rbd_name = path.split('/')[1] except IndexError: raise exception.InvalidDevicePath(path=path) else: self.rbd_name = '%s_%s' % (instance['name'], disk_name) self.snapshot_name = snapshot_name if not CONF.libvirt_images_rbd_pool: raise RuntimeError(_('You should specify' ' libvirt_images_rbd_pool' ' flag to use rbd images.')) self.pool = CONF.libvirt_images_rbd_pool self.ceph_conf = CONF.libvirt_images_rbd_ceph_conf self.rbd = kwargs.get('rbd', rbd)
def get_next_device_name(instance, device_name_list, root_device_name=None, device=None): """Validates (or generates) a device name for instance. If device is not set, it will generate a unique device appropriate for the instance. It uses the root_device_name (if provided) and the list of used devices to find valid device names. If the device name is valid but applicable to a different backend (for example /dev/vdc is specified but the backend uses /dev/xvdc), the device name will be converted to the appropriate format. """ req_prefix = None req_letter = None if device: try: req_prefix, req_letter = block_device.match_device(device) except (TypeError, AttributeError, ValueError): raise exception.InvalidDevicePath(path=device) if not root_device_name: root_device_name = block_device.DEFAULT_ROOT_DEV_NAME try: prefix = block_device.match_device(root_device_name)[0] except (TypeError, AttributeError, ValueError): raise exception.InvalidDevicePath(path=root_device_name) # NOTE(vish): remove this when xenapi is setting default_root_device if driver.compute_driver_matches('xenapi.XenAPIDriver'): prefix = '/dev/xvd' if req_prefix != prefix: LOG.debug(_("Using %(prefix)s instead of %(req_prefix)s"), { 'prefix': prefix, 'req_prefix': req_prefix }) used_letters = set() for device_path in device_name_list: letter = block_device.strip_prefix(device_path) # NOTE(vish): delete numbers in case we have something like # /dev/sda1 letter = re.sub("\d+", "", letter) used_letters.add(letter) # NOTE(vish): remove this when xenapi is properly setting # default_ephemeral_device and default_swap_device if driver.compute_driver_matches('xenapi.XenAPIDriver'): flavor = flavors.extract_flavor(instance) if flavor['ephemeral_gb']: used_letters.add('b') if flavor['swap']: used_letters.add('c') if not req_letter: req_letter = _get_unused_letter(used_letters) if req_letter in used_letters: raise exception.DevicePathInUse(path=device) return prefix + req_letter
def fake_attach_volume_invalid_device_path(self, context, instance, volume_id, device, disk_bus, device_type): raise exception.InvalidDevicePath(path=device)