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 ...
随机推荐
- Git 学习小问题记录
最近一直使用Git在管理代码,但是的确不规范,今天开始恶补Git常用命令.实际今天的任务是需要从master牵出一条branch.心想着这个简单只补一下创建分支以及merge的这边的命令就可以了,于是 ...
- 融云rongCloud聊天室的使用
融云提供了两种途径的接口, 一个是app端,一个是服务器端的. app端 1.连接融云,监听消息 rong = api.require('rongCloud2'); rong.init(functio ...
- mongdb与mysql的联系和区别
与关系型数据库相比,MongoDB的优点:①弱一致性(最终一致),更能保证用户的访问速度举例来说,在传统的关系型数据库中,一个COUNT类型的操作会锁定数据集,这样可以保证得到“当前”情况下的精确值. ...
- python学习(二) 列表和元组
第2章 列表和元组 2.1 序列概论 python有六种内建的序列,本章讨论最常用的两种类型:列表和元组.其他的内建序列有字符串.Unicode字符串.buffer对象和xragne对象. 列表和元 ...
- VC++使用TCHAR
#ifdef _UNICODE #define tcout wcout #define tcin wcin #else #define tcout cout #define tcin cin #end ...
- 使用 Ansible 管理 MySQL 复制
Ansible 是一个新兴的 IT 自动化工具.本文将介绍如何通过 Ansible 配置及管理 MySQL 主.从复制环境,实现部署过程自动化,体验 Ansible 简单快速带来的快感. 简介: An ...
- HTTP及XMLHTTP状态代码一览
(一) HTTP 1.1支持的状态代码 100 Continue 初始的请求已经接受,客户应当继续发送请求的其余部分 101 Switching Protocols 服务器将遵从客户的请求转换到另外一 ...
- requirejs——define——普通模块
一.普通模块可能包含的内容: 一个模块对应着一个js文件,由于模块可能包含着以下三种内容:模块名.依赖模块.返回给其他模块使用的参数:因此js文件根据包含内容的不同而写法不同. 一.传统的js脚本文件 ...
- javascipt——原型
1.原型存在的意义 JS不是面向对象的语言,没有类的概念,但是提供了构造器函数,其也可以创建一个对象.构造器函数如下: function people(name, age, sex) { this.n ...
- Oracle11g-BBED安装
oracle 11g中缺bbed包 下载地址: https://pan.baidu.com/s/19DVvIajarDjnynILNwQDWQ 密码:tmqt 1.BBED的安装 1.上传(sbbdp ...