Nova 代码分析之Attach volume 02

# 通过RPC发送到指定的nova-compute节点后,进入到nova\compute\manager.py中:

@object_compat
@wrap_exception()
@reverts_task_state
@wrap_instance_fault
def attach_volume(self, context, volume_id, mountpoint,
                  instance, bdm=None):
    """Attach a volume to an instance."""
    if not bdm:
        bdm = objects.BlockDeviceMapping.get_by_volume_id(
                context, volume_id)
    driver_bdm = driver_block_device.DriverVolumeBlockDevice(bdm)

    @utils.synchronized(instance.uuid)
    def do_attach_volume(context, instance, driver_bdm):
        try:
            return self._attach_volume(context, instance, driver_bdm)
        except Exception:
            with excutils.save_and_reraise_exception():
                bdm.destroy(context)

    do_attach_volume(context, instance, driver_bdm)

def _attach_volume(self, context, instance, bdm):
    context = context.elevated()
    LOG.audit(_('Attaching volume %(volume_id)s to %(mountpoint)s'),
              {'volume_id': bdm.volume_id,
              'mountpoint': bdm['mount_device']},
              context=context, instance=instance)
    try:
        bdm.attach(context, instance, self.volume_api, self.driver,
                   do_check_attach=False, do_driver_attach=True)
    except Exception:  # pylint: disable=W0702
        with excutils.save_and_reraise_exception():
            LOG.exception(_LE("Failed to attach %(volume_id)s "
                              "at %(mountpoint)s"),
                          {'volume_id': bdm.volume_id,
                           'mountpoint': bdm['mount_device']},
                          context=context, instance=instance)
            self.volume_api.unreserve_volume(context, bdm.volume_id)

    info = {'volume_id': bdm.volume_id}
    self._notify_about_instance_usage(
        context, instance, "volume.attach", extra_usage_info=info)

# pdb调试结果

> /usr/lib/python2.7/site-packages/nova/compute/manager.py(4855)attach_volume()
-> if not bdm:
(Pdb) l
4850 	    @wrap_instance_fault
4851 	    def attach_volume(self, context, volume_id, mountpoint,
4852 	                      instance, bdm=None):
4853 	        """Attach a volume to an instance."""
4854 	        import pdb; pdb.set_trace()
4855 	        if not bdm:
4856 	            bdm = objects.BlockDeviceMapping.get_by_volume_id(
4857 	                    context, volume_id)
4858 	        driver_bdm = driver_block_device.DriverVolumeBlockDevice(bdm)
4859 	
4860 	        @utils.synchronized(instance.uuid)
(Pdb) pp volume_id
u'c6129426-c4ae-45fe-9052-b9248eacad73'
(Pdb) pp mountpoint
u''
(Pdb) pp instance
Instance(access_ip_v4=None,access_ip_v6=None,architecture=None,auto_disk_config=True,availability_zone='nova',cell_name=None,cleaned=False,config_drive='',cpu_pinning=<?>,created_at=2015-07-15T08:49:29Z,default_ephemeral_device=None,default_swap_device=None,deleted=False,deleted_at=None,disable_terminate=False,display_description='instance01',display_name='instance01',ephemeral_gb=0,ephemeral_key_uuid=None,fault=<?>,host='compute1',hostname='instance01',id=33,image_ref='',info_cache=InstanceInfoCache,instance_type_id=2,kernel_id='',key_data=None,key_name=None,launch_index=0,launched_at=2015-07-15T08:49:36Z,launched_on='compute1',locked=False,locked_by=None,memory_mb=512,metadata={},node='compute1',numa_topology=<?>,os_type=None,pci_devices=<?>,power_state=1,progress=0,project_id='0ea8ceb2f23a4814976b878fe61b1b55',ramdisk_id='',reservation_id='r-jajb10ay',root_device_name='/dev/vda',root_gb=1,scheduled_at=None,security_groups=SecurityGroupList,shutdown_terminate=False,system_metadata={image_base_image_ref='',image_min_disk='1',instance_type_ephemeral_gb='0',instance_type_flavorid='1',instance_type_id='2',instance_type_memory_mb='512',instance_type_name='m1.tiny',instance_type_root_gb='1',instance_type_rxtx_factor='1.0',instance_type_swap='0',instance_type_vcpu_weight=None,instance_type_vcpus='1'},task_state=None,terminated_at=None,updated_at=2015-07-16T03:17:59Z,user_data=None,user_id='8a3073f7423d46bea51a3ab1398da61c',uuid=4cfde5a8-58eb-42e7-ace6-1e2de41b5c3a,vcpus=1,vm_mode=None,vm_state='active')
(Pdb) pp bdm
BlockDeviceMapping(boot_index=None,connection_info=None,created_at=2015-07-16T03:24:46Z,delete_on_termination=False,deleted=False,deleted_at=None,destination_type='volume',device_name='/dev/vdb',device_type=None,disk_bus=None,guest_format=None,id=41,image_id=None,instance=<?>,instance_uuid=4cfde5a8-58eb-42e7-ace6-1e2de41b5c3a,no_device=False,snapshot_id=None,source_type='volume',updated_at=None,volume_id='c6129426-c4ae-45fe-9052-b9248eacad73',volume_size=None)
4870 	    def _attach_volume(self, context, instance, bdm):
4871 	        context = context.elevated()
4872 	        LOG.audit(_('Attaching volume %(volume_id)s to %(mountpoint)s'),
4873 	                  {'volume_id': bdm.volume_id,
4874 	                  'mountpoint': bdm['mount_device']},
4875 	                  context=context, instance=instance)
(Pdb) l
4876 	        try:
4877 	            bdm.attach(context, instance, self.volume_api, self.driver,
4878 	                       do_check_attach=False, do_driver_attach=True)
4879 	        except Exception:  # pylint: disable=W0702
4880 	            with excutils.save_and_reraise_exception():
4881 	                LOG.exception(_LE("Failed to attach %(volume_id)s "
4882 	                                  "at %(mountpoint)s"),
4883 	                              {'volume_id': bdm.volume_id,
4884 	                               'mountpoint': bdm['mount_device']},
4885 	                              context=context, instance=instance)
4886 	                self.volume_api.unreserve_volume(context, bdm.volume_id)
(Pdb) l
4887 	
4888 	        info = {'volume_id': bdm.volume_id}
4889 	        self._notify_about_instance_usage(
4890 	            context, instance, "volume.attach", extra_usage_info=info)
4891 	
4892 	    def _detach_volume(self, context, instance, bdm):
4893 	        """Do the actual driver detach using block device mapping."""
4894 	        mp = bdm.device_name
4895 	        volume_id = bdm.volume_id
4896 	
4897 	        LOG.audit(_('Detach volume %(volume_id)s from mountpoint %(mp)s'),
(Pdb) pp bdm
{'boot_index': None,
 'connection_info': None,
 'delete_on_termination': False,
 'device_type': None,
 'disk_bus': None,
 'guest_format': None,
 'mount_device': u'/dev/vdb'}
(Pdb) pp type(bdm)
<class 'nova.virt.block_device.DriverVolumeBlockDevice'>

# 进而调用\nova\virt\block_device.py class DriverVolumeBlockDevice(DriverBlockDevice):

@update_db
def attach(self, context, instance, volume_api, virt_driver,
           do_check_attach=True, do_driver_attach=False):
    volume = volume_api.get(context, self.volume_id)
    if do_check_attach:
        volume_api.check_attach(context, volume, instance=instance)

    volume_id = volume['id']
    context = context.elevated()

    connector = virt_driver.get_volume_connector(instance)
    connection_info = volume_api.initialize_connection(context,
                                                       volume_id,
                                                       connector)
    if 'serial' not in connection_info:
        connection_info['serial'] = self.volume_id
    self._preserve_multipath_id(connection_info)

    # If do_driver_attach is False, we will attach a volume to an instance
    # at boot time. So actual attach is done by instance creation code.
    if do_driver_attach:
        encryption = encryptors.get_encryption_metadata(
            context, volume_api, volume_id, connection_info)

        try:
            virt_driver.attach_volume(
                    context, connection_info, instance,
                    self['mount_device'], disk_bus=self['disk_bus'],
                    device_type=self['device_type'], encryption=encryption)
        except Exception:  # pylint: disable=W0702
            with excutils.save_and_reraise_exception():
                LOG.exception(_("Driver failed to attach volume "
                                "%(volume_id)s at %(mountpoint)s"),
                              {'volume_id': volume_id,
                               'mountpoint': self['mount_device']},
                              context=context, instance=instance)
                volume_api.terminate_connection(context, volume_id,
                                                connector)
    self['connection_info'] = connection_info

    mode = 'rw'
    if 'data' in connection_info:
        mode = connection_info['data'].get('access_mode', 'rw')
    if volume['attach_status'] == "detached":
        volume_api.attach(context, volume_id, instance['uuid'],
                          self['mount_device'], mode=mode)

# pdb调试结果

331  	    @update_db
332  	    def attach(self, context, instance, volume_api, virt_driver,
333  	               do_check_attach=True, do_driver_attach=False):
334             volume = volume_api.get(context, self.volume_id)
335  	        if do_check_attach:
336  	            volume_api.check_attach(context, volume, instance=instance)
337  	
338  	        volume_id = volume['id']
339  	        context = context.elevated()
(Pdb) pp volume_api
<nova.volume.cinder.API object at 0x444c990>
(Pdb) pp virt_driver
<nova.virt.libvirt.driver.LibvirtDriver object at 0x449d8d0>
(Pdb) pp do_check_attach
False
(Pdb) pp do_driver_attach
True

# pdb打印出connector和connection_info的值:

> /usr/lib/python2.7/site-packages/nova/virt/block_device.py(345)attach()
-> if 'serial' not in connection_info:
(Pdb) l
340  	
341  	        connector = virt_driver.get_volume_connector(instance)
342  	        connection_info = volume_api.initialize_connection(context,
343  	                                                           volume_id,
344  	                                                           connector)
345  ->	        if 'serial' not in connection_info:
346  	            connection_info['serial'] = self.volume_id
347  	        self._preserve_multipath_id(connection_info)
348  	
349  	        # If do_driver_attach is False, we will attach a volume to an instance
350  	        # at boot time. So actual attach is done by instance creation code.
(Pdb) pp connector
{'host': 'compute1',
 'initiator': 'iqn.1994-05.com.redhat:ac5f49ab23a1',
 'ip': '192.168.56.106'}
(Pdb) pp connection_info
{u'data': {u'access_mode': u'rw',
           u'auth_enabled': True,
           u'auth_username': u'cinder',
           u'hosts': [u'192.168.56.102'],
           u'name': u'volumes/volume-c6129426-c4ae-45fe-9052-b9248eacad73',
           u'ports': [u'6789'],
           u'qos_specs': None,
           u'secret_type': u'ceph',
           u'secret_uuid': u'691a9b3f-b839-4233-b050-7d061fecea5a'},
 u'driver_volume_type': u'rbd'}

# 可以看出使用的是ceph卷,进而会去调用如下方法:

  /usr/lib/python2.7/sitepackages/nova/virt/libvirt/driver.py(1540)attach_volume()

def attach_volume(self, context, connection_info, instance, mountpoint,
                  disk_bus=None, device_type=None, encryption=None,
                  update_device=False):
    instance_name = instance['name']
    virt_dom = self._lookup_by_name(instance_name)
    disk_dev = mountpoint.rpartition("/")[2]
    bdm = {
        'device_name': disk_dev,
        'disk_bus': disk_bus,
        'device_type': device_type}

    # Note(cfb): If the volume has a custom block size, check that
    #            that we are using QEMU/KVM and libvirt >= 0.10.2. The
    #            presence of a block size is considered mandatory by
    #            cinder so we fail if we can't honor the request.
    data = {}
    if ('data' in connection_info):
        data = connection_info['data']
    if ('logical_block_size' in data or 'physical_block_size' in data):
        if ((CONF.libvirt.virt_type != "kvm" and
             CONF.libvirt.virt_type != "qemu")):
            msg = _("Volume sets block size, but the current "
                    "libvirt hypervisor '%s' does not support custom "
                    "block size") % CONF.libvirt.virt_type
            raise exception.InvalidHypervisorType(msg)

        if not self._has_min_version(MIN_LIBVIRT_BLOCKIO_VERSION):
            ver = ".".join([str(x) for x in MIN_LIBVIRT_BLOCKIO_VERSION])
            msg = _("Volume sets block size, but libvirt '%s' or later is "
                    "required.") % ver
            raise exception.Invalid(msg)

    disk_info = blockinfo.get_info_from_bdm(CONF.libvirt.virt_type, bdm)
    conf = self._connect_volume(connection_info, disk_info)
    self._set_cache_mode(conf)

    try:
        # NOTE(vish): We can always affect config because our
        #             domains are persistent, but we should only
        #             affect live if the domain is running.
        flags = libvirt.VIR_DOMAIN_AFFECT_CONFIG
        state = LIBVIRT_POWER_STATE[virt_dom.info()[0]]
        if not update_device and \
                state in (power_state.RUNNING, power_state.PAUSED):
            flags |= libvirt.VIR_DOMAIN_AFFECT_LIVE

        # cache device_path in connection_info -- required by encryptors
        if 'data' in connection_info:
            connection_info['data']['device_path'] = conf.source_path

        if encryption:
            encryptor = self._get_volume_encryptor(connection_info,
                                                   encryption)
            encryptor.attach_volume(context, **encryption)

        if update_device:
            virt_dom.updateDeviceFlags(conf.to_xml(), flags)
        else:
            virt_dom.attachDeviceFlags(conf.to_xml(), flags)
    except Exception as ex:
        LOG.exception(_('Failed to attach volume at mountpoint: %s'),
                      mountpoint, instance=instance)
        if isinstance(ex, libvirt.libvirtError):
            errcode = ex.get_error_code()
            if errcode == libvirt.VIR_ERR_OPERATION_FAILED:
                self._disconnect_volume(connection_info, disk_dev)
                raise exception.DeviceIsBusy(device=disk_dev)

        with excutils.save_and_reraise_exception():
            self._disconnect_volume(connection_info, disk_dev)

# 至此,nova中挂载磁盘操作结束,接着会去调用cinder中更新卷的元数据操作,即更新cinder数据库中volume表的挂载信息。

转载于:https://my.oschina.net/moyasu/blog/479211

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值