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方法,

  1. nova/compute/api.py:API
  2. def _check_and_begin_detach(self, context, volume, instance):
  3. self.volume_api.check_detach(context, volume, instance=instance)
  4. self.volume_api.begin_detaching(context, volume['id'])

1)cinderclient端接受到nova发送的begin_detaching操作的http请求,其入口处理函数为

  1. cinder/api/contrib/volume_actions.py:VolumeActionsController
  2. def _begin_detaching(self, req, id, body):
  3. """Update volume status to 'detaching'."""
  4. context = req.environ['cinder.context']
  5. # Not found exception will be handled at the wsgi level
  6. volume = self.volume_api.get(context, id)
  7.  
  8. self.volume_api.begin_detaching(context, volume)
  9. return webob.Response(status_int=http_client.ACCEPTED)
  10. 该函数的主要作用是通过volume uuid,获取volume实例信息,并调用volume目录下的api模块

2)进一步调用cinder volume的api模块的begin_detaching函数,进行数据库的操作,更新卷的状态为detaching,防止其他api对这个卷操作

  1. @wrap_check_policy
  2. def begin_detaching(self, context, volume):
  3. # If we are in the middle of a volume migration, we don't want the
  4. # user to see that the volume is 'detaching'. Having
  5. # 'migration_status' set will have the same effect internally.
  6. expected = {'status': 'in-use',
  7. 'attach_status': fields.VolumeAttachStatus.ATTACHED,
  8. 'migration_status': self.AVAILABLE_MIGRATION_STATUS}
  9.  
  10. result = volume.conditional_update({'status': 'detaching'}, expected)
  11.  
  12. if not (result or self._is_volume_migrating(volume)):
  13. msg = _("Unable to detach volume. Volume status must be 'in-use' "
  14. "and attach_status must be 'attached' to detach.")
  15. LOG.error(msg)
  16. raise exception.InvalidVolume(reason=msg)
  17.  
  18. LOG.info(_LI("Begin detaching volume completed successfully."),
  19. resource=volume)

2、nova侧向cinder发送terminate_connection请求,请求删除卷的连接信息

  1. def _detach_volume(self, context, volume_id, instance, destroy_bdm=True,attachment_id=None):
  2. ......
  3. self.volume_api.terminate_connection(context, volume_id, connector)
  4. ......
  5. self.volume_api.detach(context.elevated(), volume_id, instance.uuid,attachment_id)

1)cinderclient接受nova发送过来的os-terminate_connection请求

  1. @wsgi.action('os-terminate_connection')
  2. def _terminate_connection(self, req, id, body):
  3. """Terminate volume attachment."""
  4. context = req.environ['cinder.context']
  5. # Not found exception will be handled at the wsgi level
  6. volume = self.volume_api.get(context, id)
  7. try:
  8. connector = body['os-terminate_connection']['connector']
  9. except KeyError:
  10. raise webob.exc.HTTPBadRequest(
  11. explanation=_("Must specify 'connector'"))
  12. try:
  13. self.volume_api.terminate_connection(context, volume, connector)
  14. except exception.VolumeBackendAPIException:
  15. msg = _("Unable to terminate volume connection from backend.")
  16. raise webob.exc.HTTPInternalServerError(explanation=msg)
  17. return webob.Response(status_int=http_client.ACCEPTED)

2)进一步调用volume目录下api模块的 terminate_connection 函数,对该请求进行处理

  1. cinder/volume/api.py:API
  2. @wrap_check_policy
  3. def terminate_connection(self, context, volume, connector, force=False):
  4. step : self.volume_rpcapi.terminate_connection(context,volume,connector,force)
  5. step :self.unreserve_volume(context, volume)

step 1:cinder api进一步发送RPC请求给volume所在的cinder-volume服务节点,最终在cinder-volume节点,
由cinder/volume/manager.py:VolumeManager的terminate_connection处理,该函数的处理,主要包括如下内容

  1. def terminate_connection(self, context, volume_id, connector, force=False):
  2. utils.require_driver_initialized(self.driver)----获取对应的驱动信息
  3. volume_ref = self.db.volume_get(context, volume_id)-----从数据库中获取卷的信息
  4. try:
  5. 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连接

  1. def terminate_connection(self, volume, connector, **kwargs):
  2. volume_iqn = volume['provider_location'].split(' ')[]
  3. # Delete initiator iqns from target ACL
  4. try:
  5. self._execute('cinder-rtstool', 'delete-initiator',
  6. volume_iqn,
  7. connector['initiator'],
  8. run_as_root=True)
  9. except putils.ProcessExecutionError:
  10. LOG.exception(
  11. _LE("Failed to delete initiator iqn %s from target."),
  12. connector['initiator'])
  13. raise exception.ISCSITargetDetachFailed(volume_id=volume['id'])
  14.  
  15. # We make changes persistent
  16. self._persist_configuration(volume['id'])

3、nova给cinderclient发送os-detach命令,更改cinder数据库

1)cinder侧接受nova更新cinder数据库的入口函数

  1. cinder/api/contrib/volume_actions.py
  2. @wsgi.action('os-detach')
  3. def _detach(self, req, id, body):
  4. volume = self.volume_api.get(context, id)
  5. attachment_id = None
  6. if body['os-detach']:
  7. attachment_id = body['os-detach'].get('attachment_id', None)
  8. try:
  9. self.volume_api.detach(context, volume, attachment_id)

2)最后cinder-api通过RPC请求到cinder-volume节点,调用remove_export,移除target信息,更新数据库,把volume状态改为available,attach_status状态为detached

  1. cinder\volume\api.py
  2. @wrap_check_policy
  3. def detach(self, context, volume, attachment_id):
  4. if volume['status'] == 'maintenance':
  5. LOG.info(_LI('Unable to detach volume, '
  6. 'because it is in maintenance.'), resource=volume)
  7. msg = _("The volume cannot be detached in maintenance mode.")
  8. raise exception.InvalidVolume(reason=msg)
  9. detach_results = self.volume_rpcapi.detach_volume(context, volume,
  10. attachment_id)
  11. LOG.info(_LI("Detach volume completed successfully."),
  12. resource=volume)
  13. return detach_results

最终调用cinder-volume服务的manage.py文件中的detach_volume接口

  1. @coordination.synchronized('{volume_id}-{f_name}')
  2. def detach_volume(self, context, volume_id, attachment_id=None,
  3. volume=None):
  4. """Updates db to show volume is detached."""
  5. # TODO(vish): refactor this into a more general "unreserve"
  6. # FIXME(lixiaoy1): Remove this in v4. of RPC API.
  7. if volume is None:
  8. # For older clients, mimic the old behavior and look up the volume
  9. # by its volume_id.
  10. volume = objects.Volume.get_by_id(context, volume_id)
  11.  
  12. if attachment_id:
  13. try:
  14. attachment = objects.VolumeAttachment.get_by_id(context,
  15. attachment_id)
  16. except exception.VolumeAttachmentNotFound:
  17. LOG.info(_LI("Volume detach called, but volume not attached."),
  18. resource=volume)
  19. # We need to make sure the volume status is set to the correct
  20. # status. It could be in detaching status now, and we don't
  21. # want to leave it there.
  22. volume.finish_detach(attachment_id)
  23. return
  24. else:
  25. # We can try and degrade gracefully here by trying to detach
  26. # a volume without the attachment_id here if the volume only has
  27. # one attachment. This is for backwards compatibility.
  28. attachments = volume.volume_attachment
  29. if len(attachments) > :
  30. # There are more than attachments for this volume
  31. # we have to have an attachment id.
  32. msg = _("Detach volume failed: More than one attachment, "
  33. "but no attachment_id provided.")
  34. LOG.error(msg, resource=volume)
  35. raise exception.InvalidVolume(reason=msg)
  36. elif len(attachments) == :
  37. attachment = attachments[]
  38. else:
  39. # there aren't any attachments for this volume.
  40. # so set the status to available and move on.
  41. LOG.info(_LI("Volume detach called, but volume not attached."),
  42. resource=volume)
  43. volume.status = 'available'
  44. volume.attach_status = fields.VolumeAttachStatus.DETACHED
  45. volume.save()
  46. return
  47.  
  48. self._notify_about_volume_usage(context, volume, "detach.start")
  49. try:
  50. # NOTE(flaper87): Verify the driver is enabled
  51. # before going forward. The exception will be caught
  52. # and the volume status updated.
  53. utils.require_driver_initialized(self.driver)
  54.  
  55. LOG.info(_LI('Detaching volume %(volume_id)s from instance '
  56. '%(instance)s.'),
  57. {'volume_id': volume_id,
  58. 'instance': attachment.get('instance_uuid')},
  59. resource=volume)
  60. self.driver.detach_volume(context, volume, attachment)
  61. except Exception as ex:
  62. with excutils.save_and_reraise_exception():
  63. self.db.volume_attachment_update(
  64. context, attachment.get('id'), {
  65. 'attach_status':
  66. fields.VolumeAttachStatus.ERROR_DETACHING})
  67.  
  68. self.db.volume_metadata_update(context,
  69. volume_id,
  70. {'error': six.text_type(ex)},
  71. False)
  72.  
  73. # NOTE(jdg): We used to do an ensure export here to
  74. # catch upgrades while volumes were attached (E->F)
  75. # this was necessary to convert in-use volumes from
  76. # int ID's to UUID's. Don't need this any longer
  77.  
  78. # We're going to remove the export here
  79. # (delete the iscsi target)
  80. try:
  81. utils.require_driver_initialized(self.driver)
  82. self.driver.remove_export(context.elevated(), volume)
  83. except exception.DriverNotInitialized:
  84. with excutils.save_and_reraise_exception():
  85. LOG.exception(_LE("Detach volume failed, due to "
  86. "uninitialized driver."),
  87. resource=volume)
  88. except Exception as ex:
  89. LOG.exception(_LE("Detach volume failed, due to "
  90. "remove-export failure."),
  91. resource=volume)
  92. raise exception.RemoveExportException(volume=volume_id,
  93. reason=six.text_type(ex))
  94.  
  95. volume.finish_detach(attachment.id)
  96. self._notify_about_volume_usage(context, volume, "detach.end")
  97. 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. Git 学习小问题记录

    最近一直使用Git在管理代码,但是的确不规范,今天开始恶补Git常用命令.实际今天的任务是需要从master牵出一条branch.心想着这个简单只补一下创建分支以及merge的这边的命令就可以了,于是 ...

  2. 融云rongCloud聊天室的使用

    融云提供了两种途径的接口, 一个是app端,一个是服务器端的. app端 1.连接融云,监听消息 rong = api.require('rongCloud2'); rong.init(functio ...

  3. mongdb与mysql的联系和区别

    与关系型数据库相比,MongoDB的优点:①弱一致性(最终一致),更能保证用户的访问速度举例来说,在传统的关系型数据库中,一个COUNT类型的操作会锁定数据集,这样可以保证得到“当前”情况下的精确值. ...

  4. python学习(二) 列表和元组

    第2章  列表和元组 2.1 序列概论 python有六种内建的序列,本章讨论最常用的两种类型:列表和元组.其他的内建序列有字符串.Unicode字符串.buffer对象和xragne对象. 列表和元 ...

  5. VC++使用TCHAR

    #ifdef _UNICODE #define tcout wcout #define tcin wcin #else #define tcout cout #define tcin cin #end ...

  6. 使用 Ansible 管理 MySQL 复制

    Ansible 是一个新兴的 IT 自动化工具.本文将介绍如何通过 Ansible 配置及管理 MySQL 主.从复制环境,实现部署过程自动化,体验 Ansible 简单快速带来的快感. 简介: An ...

  7. HTTP及XMLHTTP状态代码一览

    (一) HTTP 1.1支持的状态代码 100 Continue 初始的请求已经接受,客户应当继续发送请求的其余部分 101 Switching Protocols 服务器将遵从客户的请求转换到另外一 ...

  8. requirejs——define——普通模块

    一.普通模块可能包含的内容: 一个模块对应着一个js文件,由于模块可能包含着以下三种内容:模块名.依赖模块.返回给其他模块使用的参数:因此js文件根据包含内容的不同而写法不同. 一.传统的js脚本文件 ...

  9. javascipt——原型

    1.原型存在的意义 JS不是面向对象的语言,没有类的概念,但是提供了构造器函数,其也可以创建一个对象.构造器函数如下: function people(name, age, sex) { this.n ...

  10. Oracle11g-BBED安装

    oracle 11g中缺bbed包 下载地址: https://pan.baidu.com/s/19DVvIajarDjnynILNwQDWQ 密码:tmqt 1.BBED的安装 1.上传(sbbdp ...