openstack-nova-虚机挂载云盘过程以及源码分析

本文基于openstack Stein 版本

nova 侧虚机需要挂载云盘,包括创建时挂载系统盘以及普通数据盘

代码在 nova\compute]manager.py, nova 获取volume信息,并发起attach请求,最终调用cinder api发起了attach请求。

1
2
3
4
5
6
nova.compute.manager.ComputeManager._attach_volume:
try:
bdm.attach(context, instance, self.volume_api, self.driver,
do_driver_attach=True)
......................................

1
2
3
4
5
6
nova.virt.block_device.DriverVolumeBlockDevice.attach
def attach(self, context, instance, volume_api, virt_driver,
do_driver_attach=False, **kwargs):
...................................
self._do_attach(context, instance, volume, volume_api,
virt_driver, do_driver_attach)
1
2
3
4
5
6
nova.virt.block_device.DriverVolumeBlockDevice.attach_volume
def _do_attach(self, context, instance, volume, volume_api, virt_driver,
do_driver_attach):
...................
self._legacy_volume_attach(context, volume, connector, instance,
..........................

这里没有attachment id调用了_legacy_volume_attach

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
nova.virt.block_device.DriverVolumeBlockDevice._legacy_volume_attach
def _legacy_volume_attach(self, context, volume, connector, instance,
volume_api, virt_driver,
do_driver_attach=False):
volume_id = volume['id']

connection_info = volume_api.initialize_connection(context,
volume_id,
connector) #调用cinder client初始化connection连接信息
.....................................................................
try:
virt_driver.attach_volume(
context, connection_info, instance,
self['mount_device'], disk_bus=self['disk_bus'],
device_type=self['device_type'], encryption=encryption) #调用libvirt 连接volume云盘
except Exception:
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']},
instance=instance)
volume_api.terminate_connection(context, volume_id,
connector)
self['connection_info'] = connection_info
if self.volume_size is None:
self.volume_size = volume.get('size')

mode = 'rw'
if 'data' in connection_info:
mode = connection_info['data'].get('access_mode', 'rw')
if volume['attach_status'] == "detached":
# NOTE(mriedem): save our current state so connection_info is in
# the database before the volume status goes to 'in-use' because
# after that we can detach and connection_info is required for
# detach.
self.save()
try:
volume_api.attach(context, volume_id, instance.uuid,
self['mount_device'], mode=mode) #挂载云盘
...................................
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
nova.libvirt.driver.ComputeDriver.attach_volume
def attach_volume(self, context, connection_info, instance, mountpoint,
disk_bus=None, device_type=None, encryption=None):
guest = self._host.get_guest(instance)

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)

self._connect_volume(context, connection_info, instance,
encryption=encryption)

上面从nova收到请求,到调用cinder client 挂载云盘,再到libvirt 连接volume,从而虚机可以识别到磁盘,至此完成!