Nova 代码分析之Attach volume 01

# 先看下挂载卷的入口代码:

  nova\api\openstack\compute\contrib\volumes.py  class VolumeAttachmentController(wsgi.Controller):

@wsgi.serializers(xml=VolumeAttachmentTemplate)
def create(self, req, server_id, body):
    """Attach a volume to an instance."""
    context = req.environ['nova.context']
    authorize(context)
    authorize_attach(context, action='create')

    if not self.is_valid_body(body, 'volumeAttachment'):
        msg = _("volumeAttachment not specified")
        raise exc.HTTPBadRequest(explanation=msg)
    try:
        volume_id = body['volumeAttachment']['volumeId']
    except KeyError:
        msg = _("volumeId must be specified.")
        raise exc.HTTPBadRequest(explanation=msg)
    device = body['volumeAttachment'].get('device')

    self._validate_volume_id(volume_id)

    LOG.audit(_("Attach volume %(volume_id)s to instance %(server_id)s "
                "at %(device)s"),
              {'volume_id': volume_id,
               'device': device,
               'server_id': server_id},
              context=context)

    try:
        instance = self.compute_api.get(context, server_id,
                                        want_objects=True)
        device = self.compute_api.attach_volume(context, instance,
                                                volume_id, device)
    except exception.NotFound as e:
        raise exc.HTTPNotFound(explanation=e.format_message())
    except exception.InstanceIsLocked as e:
        raise exc.HTTPConflict(explanation=e.format_message())
    except exception.InstanceInvalidState as state_error:
        common.raise_http_conflict_for_instance_invalid_state(state_error,
                'attach_volume')

    # The attach is async
    attachment = {}
    attachment['id'] = volume_id
    attachment['serverId'] = server_id
    attachment['volumeId'] = volume_id
    attachment['device'] = device

    # NOTE(justinsb): And now, we have a problem...
    # The attach is async, so there's a window in which we don't see
    # the attachment (until the attachment completes).  We could also
    # get problems with concurrent requests.  I think we need an
    # attachment state, and to write to the DB here, but that's a bigger
    # change.
    # For now, we'll probably have to rely on libraries being smart

    # TODO(justinsb): How do I return "accepted" here?
    return {'volumeAttachment': attachment}

# 设置好一个断点,dashboard上执行挂载操作来触发pdb调试。首先会进入到入口函数中:

[root@controller ~]#  /usr/bin/python /usr/bin/nova-api
> /usr/lib/python2.7/site-packages/nova/api/openstack/compute/contrib/volumes.py(392)create()
-> context = req.environ['nova.context']
(Pdb) l
387  	
388  	    @wsgi.serializers(xml=VolumeAttachmentTemplate)
389  	    def create(self, req, server_id, body):
390  	        """Attach a volume to an instance."""
391  	        import pdb; pdb.set_trace()
392  	        context = req.environ['nova.context']
393  	        authorize(context)
394  	        authorize_attach(context, action='create')
395  	
396  	        if not self.is_valid_body(body, 'volumeAttachment'):
397  	            msg = _("volumeAttachment not specified")
(Pdb) pp body
{u'volumeAttachment': {u'device': u'',
                       u'volumeId': u'c6129426-c4ae-45fe-9052-b9248eacad73'}}
(Pdb) pp req
<Request at 0x84674d0 POST http://controller:8774/v2/0ea8ceb2f23a4814976b878fe61b1b55/servers/4cfde5a8-58eb-42e7-ace6-1e2de41b5c3a/os-volume_attachments>
(Pdb) pp server_id
u'4cfde5a8-58eb-42e7-ace6-1e2de41b5c3a'

# 在做一些参数验证后,调用compute api中的attach_volume方法:

415  	        try:
416  	            instance = self.compute_api.get(context, server_id,
417  	                                            want_objects=True)
418  	            device = self.compute_api.attach_volume(context, instance,
419  	                                                    volume_id, device)
420  	        except exception.NotFound as e:
421  	            raise exc.HTTPNotFound(explanation=e.format_message())
422  	        except exception.InstanceIsLocked as e:
423  	            raise exc.HTTPConflict(explanation=e.format_message())
(Pdb) pp self.compute_api
<nova.compute.api.API object at 0x511d0d0>

# 代码如下:

  \nova\compute\api.py class API(base.Base):

def _attach_volume(self, context, instance, volume_id, device,
                   disk_bus, device_type):
    """Attach an existing volume to an existing instance.

    This method is separated to make it possible for cells version
    to override it.
    """
    # NOTE(vish): This is done on the compute host because we want
    #             to avoid a race where two devices are requested at
    #             the same time. When db access is removed from
    #             compute, the bdm will be created here and we will
    #             have to make sure that they are assigned atomically.
    volume_bdm = self.compute_rpcapi.reserve_block_device_name(
        context, instance, device, volume_id, disk_bus=disk_bus,
        device_type=device_type)
    try:
        volume = self.volume_api.get(context, volume_id)
        self.volume_api.check_attach(context, volume, instance=instance)
        self.volume_api.reserve_volume(context, volume_id)
        self.compute_rpcapi.attach_volume(context, instance=instance,
                volume_id=volume_id, mountpoint=device, bdm=volume_bdm)
    except Exception:
        with excutils.save_and_reraise_exception():
            volume_bdm.destroy(context)

    return volume_bdm.device_name

@wrap_check_policy
@check_instance_lock
@check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.PAUSED,
                                vm_states.STOPPED, vm_states.RESIZED,
                                vm_states.SOFT_DELETED])
def attach_volume(self, context, instance, volume_id, device=None,
                   disk_bus=None, device_type=None, is_ext_volume=False):
    """Attach an existing volume to an existing instance."""
    # NOTE(vish): Fail fast if the device is not going to pass. This
    #             will need to be removed along with the test if we
    #             change the logic in the manager for what constitutes
    #             a valid device.
    if device and not block_device.match_device(device):
        raise exception.InvalidDevicePath(path=device)
    if is_ext_volume:
        return self.ext_volume_api.attach_volume(context, instance,
                                                 volume_id, device,
                                                 disk_bus, device_type)
    return self._attach_volume(context, instance, volume_id, device,
                               disk_bus, device_type)

# 进而,会调用rpc api来向指定的nova-compue节点发送message。

> /usr/lib/python2.7/site-packages/nova/compute/api.py(3156)_attach_volume()
-> volume_id=volume_id, mountpoint=device, bdm=volume_bdm)
(Pdb) l
3151 	        try:
3152 	            volume = self.volume_api.get(context, volume_id)
3153 	            self.volume_api.check_attach(context, volume, instance=instance)
3154 	            self.volume_api.reserve_volume(context, volume_id)
3155 	            self.compute_rpcapi.attach_volume(context, instance=instance,
3156 	                    volume_id=volume_id, mountpoint=device, bdm=volume_bdm)
3157 	        except Exception:
3158 	            with excutils.save_and_reraise_exception():
3159 	                volume_bdm.destroy(context)
3160 	
3161 	        return volume_bdm.device_name
(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=4,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-15T09:42:58Z,user_data=None,user_id='8a3073f7423d46bea51a3ab1398da61c',uuid=4cfde5a8-58eb-42e7-ace6-1e2de41b5c3a,vcpus=1,vm_mode=None,vm_state='stopped')
(Pdb) pp bdm
*** NameError: NameError("name 'bdm' is not defined",)
(Pdb) pp volume_bdm
BlockDeviceMapping(boot_index=None,connection_info=None,created_at=2015-07-16T02:48:36Z,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=39,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)
> /usr/lib/python2.7/site-packages/nova/compute/rpcapi.py(408)attach_volume()
-> def attach_volume(self, ctxt, instance, volume_id, mountpoint, bdm=None):
(Pdb) l
403  	                version=version)
404  	        return cctxt.call(ctxt, 'attach_interface',
405  	                          instance=instance, network_id=network_id,
406  	                          port_id=port_id, requested_ip=requested_ip)
407  	
408  	    def attach_volume(self, ctxt, instance, volume_id, mountpoint, bdm=None):
409  	        # NOTE(ndipanov): Remove volume_id and mountpoint on the next major
410  	        # version bump - they are not needed when using bdm objects.
411  	        version = '3.16'
412  	        kw = {'instance': instance, 'volume_id': volume_id,
413  	              'mountpoint': mountpoint, 'bdm': bdm}
(Pdb) l
414  	        cctxt = self.client.prepare(server=_compute_host(None, instance),
415  	                version=version)
416  	        cctxt.cast(ctxt, 'attach_volume', **kw)

# 下一篇分析nova-compute节点接收到attach_volume message后执行的流程。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值