OpenStack快照分析:(三)从磁盘启动云主机离线(在线)快照分析 (3)

@check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.STOPPED, vm_states.SUSPENDED])
def snapshot_volume_backed(self, context, instance, name, extra_properties=None):
   
"""Snapshot the given volume-backed instance.从实例的system_metadata生成镜像属性(排除不可继承属性),如下:
      
# {
       #     u'min_disk': u'20',
       #     'is_public': False,
       #     'min_ram': u'0',
       #     'properties': {
       #         'base_image_ref': u''
       #      },
       #     'name': u'snapshot1'
       # }


    :param instance: nova.objects.instance.Instance object
    :param name: name of the backup or snapshot
    :param extra_properties: dict of extra image properties to include

    :returns: the new image metadata
    """
    #
获取实例的metadata属性
   
image_meta = self._initialize_instance_snapshot_metadata(instance, name, extra_properties)
   
image_meta['size'] = 0
   
# 清除镜像metadata属性中的container_formatdisk_forma属性
   
for attr in ('container_format', 'disk_format'):
        image_meta.pop(attr
, None)
    properties = image_meta[
'properties']
   
# clean properties before filling,清除properties属性里面的'block_device_mapping', 'bdm_v2', 'root_device_name'相关属性值
   
for key in ('block_device_mapping', 'bdm_v2', 'root_device_name'):
        properties.pop(key
, None)
   
# 将实例中的‘root_device_name’属性更新到properties属性里,image_meta的最终内容如:
    # {
    #     'name': u'snapshot1',
    #     u'min_ram': u'0',
    #     u'min_disk': u'20',
    #     'is_public': False,
    #     'properties': {
    #         u'base_image_ref': u'',
    #         'root_device_name': u'/dev/vda'
    #     },
    #     'size': 0
    # }

   
if instance.root_device_name:
        properties[
'root_device_name'] = instance.root_device_name

   
# 从数据库中获取该云主机所关联的所有块设备,结果会返回一个BlockDeviceMappingList对象
    bdms = objects.BlockDeviceMappingList.get_by_instance_uuid(context
, instance.uuid)
   
# 接下来开始做快照的操作,注意,云主机挂在了多少个卷设备,就要做多少次快照
    mapping = [] 
# list of BDM dicts that can go into the image properties
    # Do some up-front filtering of the list of BDMs from
    # which we are going to create snapshots.
   
volume_bdms = []
   
for bdm in bdms:
       
if bdm.no_device:
           
# 映射关系中没有块设备,则忽略此条映射
           
continue
        if
bdm.is_volume:
           
# These will be handled below.此映射包含块设备,加入到volume_bdms,准备做快照
           
volume_bdms.append(bdm)
       
else:
            mapping.append(bdm.get_image_mapping())

   
# Check limits in Cinder before creating snapshots to avoid going over
    # quota in the middle of a list of volumes. This is a best-effort check
    # but concurrently running snapshot requests from the same project
    # could still fail to create volume snapshots if they go over limit.
   
# 在创建快照之前,需要首先在Cinder中检查配额限制,以避免超过配额限制
   
if volume_bdms:
        limits =
self.volume_api.get_absolute_limits(context)
        total_snapshots_used = limits[
'totalSnapshotsUsed']
        max_snapshots = limits[
'maxTotalSnapshots']
        
# -1 means there is unlimited quota for snapshots
       
if (max_snapshots > -1 and
               
len(volume_bdms) + total_snapshots_used > max_snapshots):
            LOG.debug(
'Unable to create volume snapshots for instance. Currently has %s snapshots, requesting %s new snapshots, with a limit of %s.',
                     
total_snapshots_used, len(volume_bdms),
                     
max_snapshots, instance=instance)
           
raise exception.OverQuota(overs='snapshots')

    quiesced =
False
   
# 判断虚拟机的状态,如果虚拟机处于active,则通过rpc通知虚拟机进入静默状态(异常处理省略)
   
if instance.vm_state == vm_states.ACTIVE:
        LOG.info(
"Attempting to quiesce instance before volume snapshot.", instance=instance)
       
self.compute_rpcapi.quiesce_instance(context, instance)
        quiesced =
True

   
# 定义一个获取云主机上的及具体卷信息的方法,返回云主机的卷映射
    @
wrap_instance_event(prefix='api')
   
def snapshot_instance(self, context, instance, bdms):
       
for bdm in volume_bdms:
            
# create snapshot based on volume_id
           
#根据卷的volume_id从数据库获取卷的详细信息
            
volume = self.volume_api.get(context, bdm.volume_id)
           
# 组装出一个貌似是desc的消息,比如快照名称是snapshot1,则这里就是snapshot for snapshot1
            
name = _('snapshot for %s') % image_meta['name']
            LOG.debug(
'Creating snapshot from volume %s.', volume['id'], instance=instance)
           
# 调用cinderapi create_snapshot_force创建新的卷
           
# “create_snapshot_force”中实际上是通过cinderclient来调用volume_snapshots.create
            #
来发起创建卷的请求,具体是由cinder-volume来完成卷的快照,返回的内容为卷快照的信息,
            #
格式如:
            #{

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpxggp.html