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侧卸载卷流程分析的更多相关文章

  1. cinder侧挂载卷流程分析

    cinder侧挂载卷流程分析,存储类型以lvm+iscsi的方式为分析基础cinder侧主要调用了三个接口1)reserve_volume: 把volume的状态改为attaching,阻止其它节点执 ...

  2. Cinder Volume 服务启动流程分析和周期性任务分析

    1.cinder-volume服务的程序入口 #!/usr/bin/python2 # PBR Generated from u'console_scripts' import sys from ci ...

  3. cinder创建volume的流程-简单梳理

    1. cinder-api接收到创建的请求,入口:cinder.api.v2.volumes.VolumeController#create,该方法主要负责一些参数的重新封装和校验,然后调用cinde ...

  4. Android之 MTP框架和流程分析

    概要 本文的目的是介绍Android系统中MTP的一些相关知识.主要的内容包括:第1部分 MTP简介            对Mtp协议进行简单的介绍.第2部分 MTP框架            介绍 ...

  5. Android5 Zygote 与 SystemServer 启动流程分析

    Android5 Zygote 与 SystemServer 启动流程分析 Android5 Zygote 与 SystemServer 启动流程分析 前言 zygote 进程 解析 zygoterc ...

  6. VLC架构及流程分析

    0x00 前置信息 VLC是一个非常庞大的工程,我从它的架构及流程入手进行分析,涉及到一些很细的概念先搁置一边,日后详细分析. 0x01 源码结构(Android Java相关的暂未分析) # bui ...

  7. nova start 虚机的代码流程分析

    nova start 虚机的代码流程分析,以ocata版本为分析基础1.nova api服务接受用户下发的 nova start启动虚机请求其对应的http restfull api接口为post / ...

  8. 8、Struts2 运行流程分析

    1.流程分析: 请求发送给 StrutsPrepareAndExecuteFilter StrutsPrepareAndExecuteFilter 询问 ActionMapper: 该请求是否是一个 ...

  9. freeswitch呼叫流程分析

    今天翻文档时发现之前整理的关于freeswitch呼叫相关的内容,写成博文分享出来也方便我以后查阅. 整体结构图 FreeswitchCore 模块加载过程 freeswitch主程序初始化时会从mo ...

随机推荐

  1. TCP与UDP比较 以及并发编程基础知识

    一.tcp比udp真正可靠地原因 1.为什么tcp比udp传输可靠地原因: 我们知道在传输数据的时候,数据是先存在操作系统的缓存中,然后发送给客户端,在客户端也是要经过客户端的操作系统的,因为这个过程 ...

  2. Centos7 第三方仓库 yum 方式安装 PHP7.2

    1.卸载原先安装的PHP yum remove php rpm -qa|grep php #列出所有的php相关的rpm包 rpm -e xxx #xxx指的是上一个命令列出的rpm包的包名,复制即可 ...

  3. classmethod VS staticmethod

  4. 委托小结及Func用法

    首先,委托是一种类型,由关键字delegate声明.确切的说,委托是一种可用于封装命名或者匿名方法的引用类型.  它类似于 C++ 中的函数指针,而且是类型安全和可靠的.       委托类型的声明与 ...

  5. 系统环境变量PATH被删除后从注册表恢复

    转自:https://wenku.baidu.com/view/75d0b6ec19e8b8f67c1cb958.html 首先需要了解path这个环境变量有什么用: 当你打开命令提示窗口时,即win ...

  6. mysql 存储过程动态执行sql语句

    之前经常在程序中拼接sql语句,其实我们也可以在存储过程中拼接sql 语句,动态的执行~~ 代码如下: DROP PROCEDURE IF EXISTS SearchByDoctor;CREATE P ...

  7. 一次 Mysql 字符集的报错,最后让我万马奔腾!!!

    wuba---深圳---龙岗周边----3000元--------- wuba---深圳---龙岗周边----5000元--------- wuba---深圳---龙岗周边----8000元----- ...

  8. AngularJS学习(一)

    参考文章:http://blog.csdn.net/dc_726/article/details/17010325 1.HelloWorld篇 1.1 环境 下载:angular-1.2.5min.j ...

  9. 【bzoj1083】[SCOI2005]繁忙的都市

    1083: [SCOI2005]繁忙的都市 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2424  Solved: 1591[Submit][Sta ...

  10. windows7 Sql server 2012 尝试读取或写入受保护的内存。这通常指示其他内存已损坏的修复

    项目中,使用了sql server2012数据库,服务端是2012,客户端如果是2008的话,就会报错: 索引错误. 没办法,就安装了sql server2012客户端.但是还是报错,无法连上数据库服 ...