openstack基于卷快照恢复卷

基于P版本,对卷基于快照进行恢复的源码分析

1、特性描述

在pike版本中,openstack官网增加了一个新特性,Cinder volume revert to snapshot,该特性支持将卷恢复到最近的快照。还原过程将覆盖卷的当前状态和数据。如果在快照之后对卷进行了扩展,那么请求将被拒绝。该特性的目的是让用户能够更方便地恢复实例和卷,并减少停机时间。

目前只提供api调用,cli无此命令

2、api接口参数样例

POST /v3/{project_id}/volumes/{volume_id}/action

Request

Name In Type Description
project_id path string The UUID of the project in a multi-tenancy cloud.
volume_id path string The UUID of the volume.
revert body object The revert action.
snapshot_id body string The UUID of the snapshot. The API reverts the volume with this snapshot.

恢复一个卷到它自己最新的快照,这个接口仅仅支持恢复卸载的卷,并且卷的状态是有效的

{
"revert": {
"snapshot_id": "5aa119a8-d25b-45a7-8d1b-88e127885635"
}
}

3、源码跟踪

cinder-api服务侧的处理\

api接口,对http请求的处理 

cinder/api/v3/volumes.py
@wsgi.response(http_client.ACCEPTED)
@wsgi.Controller.api_version('3.40')
@wsgi.action('revert')
def revert(self, req, id, body):
"""revert a volume to a snapshot""" context = req.environ['cinder.context']
self.assert_valid_body(body, 'revert')
snapshot_id = body['revert'].get('snapshot_id')-----------获取用户传入的快照uuid
volume = self.volume_api.get_volume(context, id)-----------通过卷的id,获取卷对象
try:
l_snap = volume.get_latest_snapshot()------读取数据库获取卷最新的快照UUID
except exception.VolumeSnapshotNotFound:
msg = _("Volume %s doesn't have any snapshots.")
raise exc.HTTPBadRequest(explanation=msg % volume.id)
# Ensure volume and snapshot match.
if snapshot_id is None or snapshot_id != l_snap.id:-------判断用户是否输入快照及输入的快照是否为最新的快照
msg = _("Specified snapshot %(s_id)s is None or not "
"the latest one of volume %(v_id)s.")
raise exc.HTTPBadRequest(explanation=msg % {'s_id': snapshot_id,
'v_id': volume.id})
try:
msg = 'Reverting volume %(v_id)s to snapshot %(s_id)s.'
LOG.info(msg, {'v_id': volume.id,
's_id': l_snap.id})
self.volume_api.revert_to_snapshot(context, volume, l_snap)------s1 调用恢复卷快照的接口
except (exception.InvalidVolume, exception.InvalidSnapshot) as e:
raise exc.HTTPConflict(explanation=six.text_type(e))
except exception.VolumeSizeExceedsAvailableQuota as e:
raise exc.HTTPForbidden(explanation=six.text_type(e))  

cinder volume模块对请求的处理

cinder/volume/api.py
@wrap_check_policy
def revert_to_snapshot(self, context, volume, snapshot):
"""revert a volume to a snapshot""" v_res = volume.update_single_status_where(-----------------更新卷的状态由 available 变为 reverting,
'reverting', 'available')
if not v_res:
msg = _("Can't revert volume %s to its latest snapshot. "
"Volume's status must be 'available'.") % volume.id
raise exception.InvalidVolume(reason=msg)
s_res = snapshot.update_single_status_where(------------更新快照的状态由available 变为 restoring
fields.SnapshotStatus.RESTORING,
fields.SnapshotStatus.AVAILABLE)
if not s_res:
msg = _("Can't revert volume %s to its latest snapshot. "
"Snapshot's status must be 'available'.") % snapshot.id
raise exception.InvalidSnapshot(reason=msg) self.volume_rpcapi.revert_to_snapshot(context, volume, snapshot)--------s2调用cinder volume的rpc接口

 调用rpc接口

cinder/volume/rpcapi.py
@rpc.assert_min_rpc_version('3.15')
def revert_to_snapshot(self, ctxt, volume, snapshot):
version = self._compat_ver('3.15')
cctxt = self._get_cctxt(volume.host, version)
cctxt.cast(ctxt, 'revert_to_snapshot', volume=volume,snapshot=snapshot) 

 cinder-voume侧接受到rpc请求,对rpc信息进行处理

cinder/volume/manager.py
def revert_to_snapshot(self, context, volume, snapshot):
"""Revert a volume to a snapshot. The process of reverting to snapshot consists of several steps:
1. create a snapshot for backup (in case of data loss) 为了防止数据丢失创建一个快照的备份
2.1. use driver's specific logic to revert volume 调用驱动的revert_to_snapshot接口来恢复卷
2.2. try the generic way to revert volume if driver's method is missing 如果驱动的revert_to_snapshot 方法没有,那么就使用一般的方式去恢复卷
3. delete the backup snapshot 删除快照的备份
"""
backup_snapshot = None
try:
LOG.info("Start to perform revert to snapshot process.")
# Create a snapshot which can be used to restore the volume
# data by hand if revert process failed.
backup_snapshot = self._create_backup_snapshot(context, volume)---------创建卷的快照的备份
self._revert_to_snapshot(context, volume, snapshot)--------------s1 执行快照的恢复
except
...........
v_res = volume.update_single_status_where('available', 'reverting')-----------把卷的状态由reverting更新为available
if not v_res:
msg_args = {"id": volume.id,
"status": 'available'}
msg = _("Revert finished, but failed to reset "----------底层恢复完了,但是状态的状态没有设置成功,需要手动设置
"volume %(id)s status to %(status)s, "
"please manually reset it.") % msg_args
raise exception.BadResetResourceStatus(message=msg) s_res = snapshot.update_single_status_where(---------------把快照的状态由reverting更新为available
fields.SnapshotStatus.AVAILABLE,
fields.SnapshotStatus.RESTORING)
if not s_res:
msg_args = {"id": snapshot.id,
"status":
fields.SnapshotStatus.AVAILABLE}
msg = _("Revert finished, but failed to reset "-----------底层恢复完成,但是快照的状态没有设置成功,需要手动设置
"snapshot %(id)s status to %(status)s, "
"please manually reset it.") % msg_args
raise exception.BadResetResourceStatus(message=msg)
if backup_snapshot:
self.delete_snapshot(context,----------------------删除备份的快照
backup_snapshot, handle_quota=False)
msg = ('Volume %(v_id)s reverted to snapshot %(snap_id)s '
'successfully.')
msg_args = {'v_id': volume.id, 'snap_id': snapshot.id}
LOG.info(msg, msg_args) cinder/volume/manager.py
def _revert_to_snapshot(self, context, volume, snapshot):
"""Use driver or generic method to rollback volume.""" self._notify_about_volume_usage(context, volume, "revert.start")
self._notify_about_snapshot_usage(context, snapshot, "revert.start")
try:
self.driver.revert_to_snapshot(context, volume, snapshot)------调用相关驱动去恢复快照
except (NotImplementedError, AttributeError):
LOG.info("Driver's 'revert_to_snapshot' is not found. "
"Try to use copy-snapshot-to-volume method.")
self._revert_to_snapshot_generic(context, volume, snapshot)----------没有实现revert_to_snapshot功能,那么走一般路径ceph调用的就是这个
self._notify_about_volume_usage(context, volume, "revert.end")
self._notify_about_snapshot_usage(context, snapshot, "revert.end")  

基于lvm的驱动

cinder/volume/drivers/lvm.py
def revert_to_snapshot(self, context, volume, snapshot):
"""Revert a volume to a snapshot"""
# NOTE(tommylikehu): We still can revert the volume because Cinder
# will try the alternative approach if 'NotImplementedError'
# is raised here.
if self.configuration.lvm_type == 'thin':--------如果lvm配置成thin,那么不支持快照恢复
msg = _("Revert volume to snapshot not implemented for thin LVM.")
raise NotImplementedError(msg)
else:
self.vg.revert(self._escape_snapshot(snapshot.name))-----执行的是lvconvert --merge命令,合并快照到原始卷中,此时这个快照会被销毁
self.vg.deactivate_lv(volume.name)------执行的是lvchange -a n命令,表示更改lv卷的状态为无效,lvchange表示更改lv的活动状态,y表示lv活动或有效,n表示lv不活动或无效
self.vg.activate_lv(volume.name)--------执行的是lvchange -a y --yes,表示更改lv卷的状态为有效状态,--yes表示不提示确认互动,直接认为是,
# Recreate the snapshot that was destroyed by the revert
self.create_snapshot(snapshot)-----------创建快照  

由于ceph目前没有实现revert_to_snapshot方法,因此调用_revert_to_snapshot_generic接口

cinder/volume/manager.py
def _revert_to_snapshot_generic(self, ctxt, volume, snapshot):
"""Generic way to revert volume to a snapshot.
the framework will use the generic way to implement the revert
to snapshot feature:
1. create a temporary volume from snapshot-----从快照创建一个临时的卷
2. mount two volumes to host--------------挂载两个卷到主机上
3. copy data from temporary volume to original volume--------从临时卷拷贝数据到原始卷中
4. detach and destroy temporary volume----------卸载并销毁临时卷
"""
temp_vol = None try:
v_options = {'display_name': '[revert] temporary volume created '
'from snapshot %s' % snapshot.id}
ctxt = context.get_internal_tenant_context() or ctxt
temp_vol = self.driver._create_temp_volume_from_snapshot(--------通过快照创建临时卷
ctxt, volume, snapshot, volume_options=v_options)
self._copy_volume_data(ctxt, temp_vol, volume)-------从临时卷拷贝数据到原始卷,这个过程会分三个小步骤:挂载原始卷和临时卷;从临时卷拷贝数据到原始卷;<br>卸载临时卷和原始卷
self.driver.delete_volume(temp_vol)-----删除临时卷
temp_vol.destroy()
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(
"Failed to use snapshot %(snapshot)s to create "
"a temporary volume and copy data to volume "
" %(volume)s.",
{'snapshot': snapshot.id,
'volume': volume.id})
if temp_vol and temp_vol.status == 'available':
self.driver.delete_volume(temp_vol)

本文来自:https://www.cnblogs.com/potato-chip/p/11535166.html

openstack基于卷快照恢复卷的更多相关文章

  1. MySQL基于LVM快照的备份恢复(临时)

    目录1.数据库全备份2.准备LVM卷3.数据恢复到LVM卷4.基于LVM快照备份数据5.数据灾难恢复6.总结 写在前面:测试环境中已安装有mysql 5.5.36数据库,但数据目录没有存放在LVM卷, ...

  2. MySQL的备份和恢复-基于LVM快照的备份(lvm-snapshot)

    MySQL的备份和恢复-基于LVM快照的备份(lvm-snapshot) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.什么是快照卷 如上图所示,原卷和快照卷可以不一样大,因为 ...

  3. GNU/Linux下LVM配置管理以及快照卷、物理卷、卷组、逻辑卷的创建和删除

    LVM是Linux环境中对磁盘分区进行管理的一种机制,是建立在硬盘和分区之上.文件系统之下的一个逻辑层,可提高磁盘分区管理的灵活性.最大的优点是在不损伤数据的前提下调整存储空间的大小. 本篇主要讲述L ...

  4. mysql数据库基于LVM快照的备份

    lvm-snapshot: 基于LVM快照的备份 1.事务日志跟数据文件必须在同一个卷上          2.创建快照卷之前,要请求mysql的全局锁,在快照创建完成之后释放锁          3 ...

  5. mysql 基于lvm快照的备份

    1.查看磁盘数 ls /dev/ | grep sd 2.快照备份 pvcreate /dev/sdb #制作成物理卷vgcreate testvg /dev/sdblvcreate -L200M - ...

  6. Record:逻辑分区下新建简单卷后其他卷被删除

    上图是恢复后的磁盘情况,恢复前的情况没有截图. 事情是这样:扩展分区中原本有4个逻辑分区.想将其中一个分区(MySpace,第一个分区)压缩出部分空间新建一个分区.经过 压缩卷->新建简单卷 后 ...

  7. 聊聊Docker数据卷和数据卷容器

    当程序在容器运行的时候,特别是需要与其他容器中的程序或容器外部程序进行沟通交流,这时需要进行数据交换,作为常用的两种沟通数据的方式,网络通信与文件读写是需要提供给程序的支持, [数据卷] 文件是数据持 ...

  8. Docker数据卷和数据卷容器

    是什么 数据卷设计的目的,在于数据的永久化,他完全独立于容器的生存周期,因此,Docker不会在容器删除时删除其挂载的数据卷,也不会存在类似的垃圾收集机制对容器引用的数据卷进行处理.类似我们Redis ...

  9. Windows Server 2012 磁盘管理之 简单卷、跨区卷、带区卷、镜像卷和RAID-5卷

    今天给客户配置故障转移群集,在Windows Server 2012 R2的系统上,通过iSCSI连接上DELL的SAN存储后,在磁盘管理里面发现可以新建 简单卷.跨区卷.带区卷.镜像卷.RAID-5 ...

随机推荐

  1. vim学习(一)

    vim是linux和mac中常用到的编辑器. 其分为4种模式: normal模式:普通模式,浏览作用 insert模式: i(insert)     在当前光标处进行插入 a(append) 在当前光 ...

  2. 前端基础(七):Toastr(弹出框)

    Toastr 简介 jquery toastr 一款轻量级的通知提示框插件. 网页开发中经常会用到提示框,自带的alert样式无法调整,用户体验差. 所以一般通过自定义提示框来实现弹窗提示信息,而jq ...

  3. sudo身份切换

    sudo更改身份: 我们知道,使用 su 命令可以让普通用户切换到 root 身份去执行某些特权命令,但存在一些问题,比如说:仅仅为了一个特权操作就直接赋予普通用户控制系统的完整权限: 当多人使用同一 ...

  4. Form组件 cookie和session

    django form组件 1.渲染标签 2.校验数据 3.展示信息 第一步需要一个form类 from django import forms class MyForm(forms.Form): n ...

  5. rpm的specs学习

    参考 制作rpm包:    https://wangbin.io/blog/it/yum-rpm-make.html linux rpm安装mysql: https://www.jianshu.com ...

  6. YOLO---Darknet下的学习笔记 V190319

    YOLO---Darknet下的学习笔记 @WP 20190319 很久没有用YOlO算法了,今天又拿过来玩玩.折腾半天,才好运行通的,随手记一下: 一是,终端下的使用.二是,python接口的使用. ...

  7. LoadRunner(7)

    一.参数化策略 1.Select next row(How? 如何取?)取值方式 选择下一行 1)Sequential:顺序的 每个VU都从第一行开始,顺序依次向下取值: 数据取完可以从头循环重复使用 ...

  8. mysql5.7安装中的问题(服务无法启动。服务没有报告任何错误。排查方法)

    1.拒绝访问的问题 权限不够,必须以管理员身份启动命令行 2.MySQL 服务无法启动.服务没有报告任何错误. 进入到你的mysql安装目录,C:\Program Files\MySQL\MySQL ...

  9. C3的坑之inline-block

    最近开始复习css一直在踩坑,今天分享一个inline-block 关于inline-block可能很多人都不熟悉,布局这方面很多人用的都是flex或者浮动,flex很强大毋庸置疑的可是关于兼容性就不 ...

  10. barcode模块: plus.barcode.scan 进行扫描图片出现无法识别二维码,打印的错误信息是code:8,message:''

    原因之一:图片的像素太大了,无法识别. 解决方法: 压缩一下图片. 这里的 data 我放了一个  像素为 4040 × 4040 的 图片. 进行识别的时候会报, (无法识别的图片,都是返回这些值) ...