创建虚拟机快照的实现在\nova\compute\manager.py 中的_snapshot_instance
def _snapshot_instance(self, context, image_id, instance,
expected_task_state):
def update_task_state(task_state,
expected_state=expected_task_state):
instance.task_state = task_state
instance.save(expected_task_state=expected_state)
self.driver.snapshot(context, instance, image_id,
update_task_state)
可见最终还是driver的snapshot方法完成虚拟机的快照,由于我们使用的是LibvirtDriver,因此
其实现在\nova\virt\libvirt\driver.py def snapshot(self, context, instance, image_id, update_task_state):
"""Create snapshot from a running VM instance.
This command only works with qemu 0.14+
"""
//先找到root disk,再调用root disk自己的direct_snapshot来实现snapshot
root_disk = self.image_backend.by_libvirt_path(instance, disk_path, image_type=source_type)
metadata['location'] = root_disk.direct_snapshot(
context, snapshot_name, image_format, image_id,
instance.image_ref)
这里的image_backend 实现在E:\nova\nova\virt\libvirt\imagebackend.py 中
class Backend(object):
def __init__(self, use_cow):
self.BACKEND = {
'raw': Flat,
'flat': Flat,
'qcow2': Qcow2,
'lvm': Lvm,
'rbd': Rbd,
'ploop': Ploop,
'default': Qcow2 if use_cow else Flat
}
def backend(self, image_type=None):
if not image_type:
image_type = CONF.libvirt.images_type
image = self.BACKEND.get(image_type)
if not image:
raise RuntimeError(_('Unknown image_type=%s') % image_type)
return image
def by_libvirt_path(self, instance, path, image_type=None):
"""Return an Image object for a disk with the given libvirt path.
:param instance: The instance which owns this disk.
:param path: The libvirt representation of the image's path.
:param image_type: (Optional) Image type.
Default is CONF.libvirt.images_type.
:return: An Image object for the given libvirt path.
:rtype: Image
"""
backend = self.backend(image_type)
return backend(instance=instance, path=path)
我们这里用的ceph最为后端存储因此这里对应BACKEND 中的rbd,
因此image_backend.by_libvirt_path 最终返回的是Rbd这个类,因此最终的调用rbd中的direct_snapshot来实现虚拟机快照
Rbd类的实现如下:
def direct_snapshot(self, context, snapshot_name, image_format,
image_id, base_image_id):
"""Creates an RBD snapshot directly.
"""
fsid = self.driver.get_fsid()
# NOTE(nic): Nova has zero comprehension of how Glance's image store
# is configured, but we can infer what storage pool Glance is using
# by looking at the parent image. If using authx, write access should
# be enabled on that pool for the Nova user
parent_pool = self._get_parent_pool(context, base_image_id, fsid)
# Snapshot the disk and clone it into Glance's storage pool. librbd
# requires that snapshots be set to "protected" in order to clone them
self.driver.create_snap(self.rbd_name, snapshot_name, protect=True)
location = {'url': 'rbd://%(fsid)s/%(pool)s/%(image)s/%(snap)s' %
dict(fsid=fsid,
pool=self.pool,
image=self.rbd_name,
snap=snapshot_name)}
try:
self.driver.clone(location, image_id, dest_pool=parent_pool)
# Flatten the image, which detaches it from the source snapshot
self.driver.flatten(image_id, pool=parent_pool)
finally:
# all done with the source snapshot, clean it up
self.cleanup_direct_snapshot(location)
# Glance makes a protected snapshot called 'snap' on uploaded
# images and hands it out, so we'll do that too. The name of
# the snapshot doesn't really matter, this just uses what the
# glance-store rbd backend sets (which is not configurable).
self.driver.create_snap(image_id, 'snap', pool=parent_pool,
protect=True)
return ('rbd://%(fsid)s/%(pool)s/%(image)s/snap' %
dict(fsid=fsid, pool=parent_pool, image=image_id))
Rbd类的self.driver 赋值如下:
self.driver = rbd_utils.RBDDriver(
pool=self.pool,
ceph_conf=self.ceph_conf,
rbd_user=self.rbd_user)
这里的RBDDriver的实现在E:\nova\nova\virt\libvirt\storage\rbd_utils.py中。
class RBDDriver(object):
def __init__(self, pool, ceph_conf, rbd_user):
self.pool = pool
# NOTE(angdraug): rados.Rados fails to connect if ceph_conf is None:
# https://github.com/ceph/ceph/pull/1787
self.ceph_conf = ceph_conf or ''
self.rbd_user = rbd_user or None
if rbd is None:
raise RuntimeError(_('rbd python libraries not found'))
def _connect_to_rados(self, pool=None):
client = rados.Rados(rados_id=self.rbd_user,
conffile=self.ceph_conf)
try:
client.connect()
pool_to_open = pool or self.pool
# NOTE(luogangyi): open_ioctx >= 10.1.0 could handle unicode
# arguments perfectly as part of Python 3 support.
# Therefore, when we turn to Python 3, it's safe to remove
# str() conversion.
ioctx = client.open_ioctx(str(pool_to_open))
return client, ioctx
except rados.Error:
# shutdown cannot raise an exception
client.shutdown()
raise
在RBDDriver 中通过_connect_to_rados 得到rados的client。因此在Rbd类中的self.driver 其实都是调用ceph 模块的接口进行和直接使用ceph 命令是一样的效果
nova调用rados来实现snapshot
最新推荐文章于 2024-07-18 16:13:13 发布