Example #1
0
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
Example #2
0
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
Example #4
0
    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
Example #6
0
 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)
Example #7
0
File: utils.py Project: linets/nova
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
Example #8
0
 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)
Example #9
0
    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)
Example #10
0
 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)
Example #11
0
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
Example #12
0
def fake_attach_volume_invalid_device_path(self, context, instance, volume_id,
                                           device, disk_bus, device_type):
    raise exception.InvalidDevicePath(path=device)