cinder侧卸载卷流程分析
cinder侧卸载卷分析,存储类型以lvm+iscsi的方式为分析基础
在虚机卸载卷的过程中,主要涉及如下三个函数
1)cinder.volume.api.begin_detaching 把volume的状态改为detaching,阻止其它节点执行挂载操作
2)cinder.volume.api.terminate_connection 进行target,lun等信息的清理
3)cinder.volume.api.detach 更新cinder数据库,设置卷的状态为available
1、nova侧调用cinderclient的begin_detaching方法,
nova/compute/api.py:API
def _check_and_begin_detach(self, context, volume, instance):
self.volume_api.check_detach(context, volume, instance=instance)
self.volume_api.begin_detaching(context, volume['id'])
1)cinderclient端接受到nova发送的begin_detaching操作的http请求,其入口处理函数为
cinder/api/contrib/volume_actions.py:VolumeActionsController
def _begin_detaching(self, req, id, body):
"""Update volume status to 'detaching'."""
context = req.environ['cinder.context']
# Not found exception will be handled at the wsgi level
volume = self.volume_api.get(context, id) self.volume_api.begin_detaching(context, volume)
return webob.Response(status_int=http_client.ACCEPTED)
该函数的主要作用是通过volume 的uuid,获取volume实例信息,并调用volume目录下的api模块
2)进一步调用cinder volume的api模块的begin_detaching函数,进行数据库的操作,更新卷的状态为detaching,防止其他api对这个卷操作
@wrap_check_policy
def begin_detaching(self, context, volume):
# If we are in the middle of a volume migration, we don't want the
# user to see that the volume is 'detaching'. Having
# 'migration_status' set will have the same effect internally.
expected = {'status': 'in-use',
'attach_status': fields.VolumeAttachStatus.ATTACHED,
'migration_status': self.AVAILABLE_MIGRATION_STATUS} result = volume.conditional_update({'status': 'detaching'}, expected) if not (result or self._is_volume_migrating(volume)):
msg = _("Unable to detach volume. Volume status must be 'in-use' "
"and attach_status must be 'attached' to detach.")
LOG.error(msg)
raise exception.InvalidVolume(reason=msg) LOG.info(_LI("Begin detaching volume completed successfully."),
resource=volume)
2、nova侧向cinder发送terminate_connection请求,请求删除卷的连接信息
def _detach_volume(self, context, volume_id, instance, destroy_bdm=True,attachment_id=None):
......
self.volume_api.terminate_connection(context, volume_id, connector)
......
self.volume_api.detach(context.elevated(), volume_id, instance.uuid,attachment_id)
1)cinderclient接受nova发送过来的os-terminate_connection请求
@wsgi.action('os-terminate_connection')
def _terminate_connection(self, req, id, body):
"""Terminate volume attachment."""
context = req.environ['cinder.context']
# Not found exception will be handled at the wsgi level
volume = self.volume_api.get(context, id)
try:
connector = body['os-terminate_connection']['connector']
except KeyError:
raise webob.exc.HTTPBadRequest(
explanation=_("Must specify 'connector'"))
try:
self.volume_api.terminate_connection(context, volume, connector)
except exception.VolumeBackendAPIException:
msg = _("Unable to terminate volume connection from backend.")
raise webob.exc.HTTPInternalServerError(explanation=msg)
return webob.Response(status_int=http_client.ACCEPTED)
2)进一步调用volume目录下api模块的 terminate_connection 函数,对该请求进行处理
cinder/volume/api.py:API类
@wrap_check_policy
def terminate_connection(self, context, volume, connector, force=False):
step : self.volume_rpcapi.terminate_connection(context,volume,connector,force)
step :self.unreserve_volume(context, volume)
step 1:cinder api进一步发送RPC请求给volume所在的cinder-volume服务节点,最终在cinder-volume节点,
由cinder/volume/manager.py:VolumeManager的terminate_connection处理,该函数的处理,主要包括如下内容
def terminate_connection(self, context, volume_id, connector, force=False):
utils.require_driver_initialized(self.driver)----获取对应的驱动信息
volume_ref = self.db.volume_get(context, volume_id)-----从数据库中获取卷的信息
try:
step 1.1 self.driver.terminate_connection(volume_ref, connector, force=force)-----调用对应的驱动的terminate_connection函数
step 1.1 :
使用lvm+lio的方式,代码跳转过程如下:drivers/lvm.py -> targets/lio.py,从target 的acl中删除initiator,从而有效的在 target侧关闭iscis session连接
def terminate_connection(self, volume, connector, **kwargs):
volume_iqn = volume['provider_location'].split(' ')[]
# Delete initiator iqns from target ACL
try:
self._execute('cinder-rtstool', 'delete-initiator',
volume_iqn,
connector['initiator'],
run_as_root=True)
except putils.ProcessExecutionError:
LOG.exception(
_LE("Failed to delete initiator iqn %s from target."),
connector['initiator'])
raise exception.ISCSITargetDetachFailed(volume_id=volume['id']) # We make changes persistent
self._persist_configuration(volume['id'])
3、nova给cinderclient发送os-detach命令,更改cinder数据库
1)cinder侧接受nova更新cinder数据库的入口函数
cinder/api/contrib/volume_actions.py
@wsgi.action('os-detach')
def _detach(self, req, id, body):
volume = self.volume_api.get(context, id)
attachment_id = None
if body['os-detach']:
attachment_id = body['os-detach'].get('attachment_id', None)
try:
self.volume_api.detach(context, volume, attachment_id)
2)最后cinder-api通过RPC请求到cinder-volume节点,调用remove_export,移除target信息,更新数据库,把volume状态改为available,attach_status状态为detached
cinder\volume\api.py
@wrap_check_policy
def detach(self, context, volume, attachment_id):
if volume['status'] == 'maintenance':
LOG.info(_LI('Unable to detach volume, '
'because it is in maintenance.'), resource=volume)
msg = _("The volume cannot be detached in maintenance mode.")
raise exception.InvalidVolume(reason=msg)
detach_results = self.volume_rpcapi.detach_volume(context, volume,
attachment_id)
LOG.info(_LI("Detach volume completed successfully."),
resource=volume)
return detach_results
最终调用cinder-volume服务的manage.py文件中的detach_volume接口
@coordination.synchronized('{volume_id}-{f_name}')
def detach_volume(self, context, volume_id, attachment_id=None,
volume=None):
"""Updates db to show volume is detached."""
# TODO(vish): refactor this into a more general "unreserve"
# FIXME(lixiaoy1): Remove this in v4. of RPC API.
if volume is None:
# For older clients, mimic the old behavior and look up the volume
# by its volume_id.
volume = objects.Volume.get_by_id(context, volume_id) if attachment_id:
try:
attachment = objects.VolumeAttachment.get_by_id(context,
attachment_id)
except exception.VolumeAttachmentNotFound:
LOG.info(_LI("Volume detach called, but volume not attached."),
resource=volume)
# We need to make sure the volume status is set to the correct
# status. It could be in detaching status now, and we don't
# want to leave it there.
volume.finish_detach(attachment_id)
return
else:
# We can try and degrade gracefully here by trying to detach
# a volume without the attachment_id here if the volume only has
# one attachment. This is for backwards compatibility.
attachments = volume.volume_attachment
if len(attachments) > :
# There are more than attachments for this volume
# we have to have an attachment id.
msg = _("Detach volume failed: More than one attachment, "
"but no attachment_id provided.")
LOG.error(msg, resource=volume)
raise exception.InvalidVolume(reason=msg)
elif len(attachments) == :
attachment = attachments[]
else:
# there aren't any attachments for this volume.
# so set the status to available and move on.
LOG.info(_LI("Volume detach called, but volume not attached."),
resource=volume)
volume.status = 'available'
volume.attach_status = fields.VolumeAttachStatus.DETACHED
volume.save()
return self._notify_about_volume_usage(context, volume, "detach.start")
try:
# NOTE(flaper87): Verify the driver is enabled
# before going forward. The exception will be caught
# and the volume status updated.
utils.require_driver_initialized(self.driver) LOG.info(_LI('Detaching volume %(volume_id)s from instance '
'%(instance)s.'),
{'volume_id': volume_id,
'instance': attachment.get('instance_uuid')},
resource=volume)
self.driver.detach_volume(context, volume, attachment)
except Exception as ex:
with excutils.save_and_reraise_exception():
self.db.volume_attachment_update(
context, attachment.get('id'), {
'attach_status':
fields.VolumeAttachStatus.ERROR_DETACHING}) self.db.volume_metadata_update(context,
volume_id,
{'error': six.text_type(ex)},
False) # NOTE(jdg): We used to do an ensure export here to
# catch upgrades while volumes were attached (E->F)
# this was necessary to convert in-use volumes from
# int ID's to UUID's. Don't need this any longer # We're going to remove the export here
# (delete the iscsi target)
try:
utils.require_driver_initialized(self.driver)
self.driver.remove_export(context.elevated(), volume)
except exception.DriverNotInitialized:
with excutils.save_and_reraise_exception():
LOG.exception(_LE("Detach volume failed, due to "
"uninitialized driver."),
resource=volume)
except Exception as ex:
LOG.exception(_LE("Detach volume failed, due to "
"remove-export failure."),
resource=volume)
raise exception.RemoveExportException(volume=volume_id,
reason=six.text_type(ex)) volume.finish_detach(attachment.id)
self._notify_about_volume_usage(context, volume, "detach.end")
LOG.info(_LI("Detach volume completed successfully."), resource=volume)
cinder侧卸载卷流程分析的更多相关文章
- cinder侧挂载卷流程分析
cinder侧挂载卷流程分析,存储类型以lvm+iscsi的方式为分析基础cinder侧主要调用了三个接口1)reserve_volume: 把volume的状态改为attaching,阻止其它节点执 ...
- Cinder Volume 服务启动流程分析和周期性任务分析
1.cinder-volume服务的程序入口 #!/usr/bin/python2 # PBR Generated from u'console_scripts' import sys from ci ...
- cinder创建volume的流程-简单梳理
1. cinder-api接收到创建的请求,入口:cinder.api.v2.volumes.VolumeController#create,该方法主要负责一些参数的重新封装和校验,然后调用cinde ...
- Android之 MTP框架和流程分析
概要 本文的目的是介绍Android系统中MTP的一些相关知识.主要的内容包括:第1部分 MTP简介 对Mtp协议进行简单的介绍.第2部分 MTP框架 介绍 ...
- Android5 Zygote 与 SystemServer 启动流程分析
Android5 Zygote 与 SystemServer 启动流程分析 Android5 Zygote 与 SystemServer 启动流程分析 前言 zygote 进程 解析 zygoterc ...
- VLC架构及流程分析
0x00 前置信息 VLC是一个非常庞大的工程,我从它的架构及流程入手进行分析,涉及到一些很细的概念先搁置一边,日后详细分析. 0x01 源码结构(Android Java相关的暂未分析) # bui ...
- nova start 虚机的代码流程分析
nova start 虚机的代码流程分析,以ocata版本为分析基础1.nova api服务接受用户下发的 nova start启动虚机请求其对应的http restfull api接口为post / ...
- 8、Struts2 运行流程分析
1.流程分析: 请求发送给 StrutsPrepareAndExecuteFilter StrutsPrepareAndExecuteFilter 询问 ActionMapper: 该请求是否是一个 ...
- freeswitch呼叫流程分析
今天翻文档时发现之前整理的关于freeswitch呼叫相关的内容,写成博文分享出来也方便我以后查阅. 整体结构图 FreeswitchCore 模块加载过程 freeswitch主程序初始化时会从mo ...
随机推荐
- sublime text3 自动编译php 适合用于简单的php文件执行
1.将php路径放入环境变量中 2. 点击 sublime_text的“工具”->"编译系统"->"编译新系统" { "cmd" ...
- linux lcd设备驱动剖析四
在"linux lcd设备驱动剖析二"文章中,我们详细分析了s3c24xxfb_probe函数. 文章链接:http://blog.csdn.net/lwj103862095/ar ...
- Py修行路 python基础 (二十五)线程与进程
操作系统是用户和硬件沟通的桥梁 操作系统,位于底层硬件与应用软件之间的一层 工作方式:向下管理硬件,向上提供接口 操作系统进行切换操作: 把CPU的使用权切换给不同的进程. 1.出现IO操作 2.固定 ...
- 程序实现DataGrid过滤设置
给gdv_pro.ActiveFilterString赋值就能直接控制DataGrid过滤 gdv_pro.ActiveFilterString语法: 最简单方式:gdv_pro.ActiveFilt ...
- linux 下安装mysql-5.7.16
1.解压tar -xvf mysql的包 tar -xvf mysql-5.7.16-1.el6.x86_64.rpm-bundle.tar(mysql 官网中即可找到) 2.查看是否需要卸载安装时候 ...
- requirejs——define——普通模块
一.普通模块可能包含的内容: 一个模块对应着一个js文件,由于模块可能包含着以下三种内容:模块名.依赖模块.返回给其他模块使用的参数:因此js文件根据包含内容的不同而写法不同. 一.传统的js脚本文件 ...
- window 下编译cef 内核 加入mp3/mp4 支持
下载 depot_tools 解压,加入到环境变量 进入cmd(管理员)运行 gclient 获取 python和git,svn,设置python环境变量 创建新文件夹 mkdir chromium ...
- Spring整合web项目原理
- TensorFlow模型保存和提取方法
一.TensorFlow模型保存和提取方法 1. TensorFlow通过tf.train.Saver类实现神经网络模型的保存和提取.tf.train.Saver对象saver的save方法将Tens ...
- 在zookeeper集群的基础上,搭建solrCloud
1 将在window中部署的单机版solr上传到node-01中 cd /export/software/ rz 选择资料中的solr.zip进行上传(此zip就是 solr的简单部署:在tomca ...