nova 挂载卷源码分析

本文以kilo版本的nova为例

nova挂载卷源码分析

nova/api/openstack/compute/contrib/volumes.py
在Nova Client进程中,由VolumeAttachmentController接受挂载请求

nova client
    ↓
POST /v2.1/servers/c2486c45-5a8f-4028-8cd1-51c0425f677a/os-volume_attachments
    ↓
nova.api.openstack.compute.volumes.VolumeAttachmentController.create
    self.compute_api.attach_volume
        self.compute_api 可用的有两个:
            1. nova.compute.cells_api.ComputeCellsAPI
            2. nova.compute.api.API
        根据 nova.conf 配置项决定使用哪一个,默认情况下是 nova.compute.api.API
nova.compute.api.API.attach_volume
    self._attach_volume
        ↓
nova.compute.api.API._attach_volume
    step1: volume_bdm = self.compute_rpcapi.reserve_block_device_name
    step2: volume = self.volume_api.get(context, volume_id)
    step3: self.volume_api.check_attach(context, volume, instance=instance)
    step4: self.volume_api.reserve_volume(context, volume_id)
    step5: self.compute_rpcapi.attach_volume(context, instance=instance,
                    volume_id=volume_id, mountpoint=device, bdm=volume_bdm)      

step1: 创建 BDM 数据库表数据

nova.compute.api.API._attach_volume
    volume_bdm = self.compute_rpcapi.reserve_block_device_name
        ↓
nova.compute.rpcapi.ComputeApi.reserve_block_device_name
    volume_bdm = cctxt.call(ctxt, 'reserve_block_device_name', **kw)
        ↓
nova.compute.manager.reserve_block_device_name
    bdm = objects.BlockDeviceMapping(...)
    bdm.create() 创建 BDM 数据库表数据  

step2: 调用 cinderclient 获取需要挂载的 volume 信息

nova.compute.api.API._attach_volume
    volume = self.volume_api.get(context, volume_id)
        ↓
nova.volume.API.get
    item = cinderclient(context).volumes.get(volume_id)
         

step3: 检查cinder status和可用域

nova.compute.api.API._attach_volume
    self.volume_api.check_attach(context, volume, instance=instance)
        ↓
nova.volume.API.check_attach
    if (volume['status'] not in ("available", 'in-use', 'attaching'))
    if instance_az != volume['availability_zone']

step4: 调用 cinderclient 更新 cinder DB -> 'status': 'attaching'(以防止其他操作进入)

nova.compute.api.API._attach_volume
    self.volume_api.reserve_volume(context, volume_id)
        ↓
nova.volume.API.reserve_volume
     cinderclient(context).volumes.reserve(volume_id)

step5: 挂载卷

nova.compute.api.API._attach_volume
    self.compute_rpcapi.attach_volume(context, instance=instance,
                    volume_id=volume_id, mountpoint=device, bdm=volume_bdm)  
        ↓
nova.compute.rpcapi.ComputeAPI.attach_volume
     cctxt = self.client.prepare(server=_compute_host(None, instance),
                version=version)
     cctxt.cast(ctxt, 'attach_volume', **kw)
        ↓
nova.compute.manager.ComputeManager.attach_volume
     step6: driver_bdm = driver_block_device.convert_volume(bdm) 
     step7: self._attach_volume(context, instance, driver_bdm)       

step6: 根据 source_type 获取 BDM 驱动 DriverVolumeBlockDevice

nova.compute.manager.ComputeManager.attach_volume
     driver_bdm = driver_block_device.convert_volume(bdm) 
        ↓
nova.virt.block_device.convert_volume
     source_volume = convert_volumes(volume_bdms)
     convert_volumes = functools.partial(_convert_block_devices,
                                   DriverVolumeBlockDevice)
                     

step7: BDM driver attach

nova.compute.manager.ComputeManager.attach_volume
     self._attach_volume(context, instance, driver_bdm)
        ↓
nova.compute.manager.ComputeManager._attach_volume  
     bdm.attach(context, instance, self.volume_api, self.driver,
                       do_check_attach=False, do_driver_attach=True)
        ↓           
nova.virt.block_device.DriverVolumeBlockDevice.attach
     volume_api.check_attach(context, volume, instance=instance) #检查cinder status和可用域
     step8:  connector = virt_driver.get_volume_connector(instance)
     step9:  connection_info = volume_api.initialize_connection(context,volume_id,connector)
     step10: virt_driver.attach_volume()  

step8: 获取 connector,为 initialize_connection 提供参数

nova.virt.block_device.DriverVolumeBlockDevice.attach
     connector = virt_driver.get_volume_connector(instance)
        ↓
nova.virt.libvirt.driver.LibvirtDriver.get_volume_connector
     self._initiator = libvirt_utils.get_iscsi_initiator()
     self._fc_wwnns = libvirt_utils.get_fc_wwnns()
     self._fc_wwpns = libvirt_utils.get_fc_wwpns()
     return connector

step9: 存储端进行挂载返回 connection_info

nova.virt.block_device.DriverVolumeBlockDevice.attach
     connection_info = volume_api.initialize_connection(context,volume_id,connector)
        ↓
nova.volume.cinder.API.initialize_connection
     return cinderclient(context).volumes.initialize_connection(volume_id,
                                                                   connector)

step10: 主机端根据 connection_info 挂载卷到目标主机(iSCSI 为例)

nova.virt.block_device.DriverVolumeBlockDevice.attach
     virt_driver.attach_volume() 
        ↓
nova.virt.libvirt.driver.LibvirtDriver.attach_volume
     self._connect_volume(connection_info, disk_info)
        ↓
nova.virt.libvirt.volume.iscsi.LibvirtISCSIVolumeDriver.connect_volume
     # 接下来分为多路径和单路径两种情况,开启多路径的配置见文章最后的参考
     if self.use_multipath:
        run_iscsiadm_update_discoverydb()
        out = self._run_iscsiadm_bare()
        self._connect_to_iscsi_portal(props)
        self._rescan_iscsi()
     else:
        self._connect_to_iscsi_portal(iscsi_properties)
        self._run_iscsiadm(iscsi_properties, ("--rescan",))
     host_device = self._get_host_device(iscsi_properties)
                

step10中涉及的命令有:

其中牵扯到的指令有:
a. 尝试连接
iscsiadm -m node -T target_iqn -p target_protal
b. 连接失败重新建立连接
iscsiadm -m node -T target_iqn -p target_protal -op new
iscsiadm -m node -T target_iqn -p target_protal —op update -n node.session.auth.authmethod -v auth_method
iscsiadm -m node -T target_iqn -p target_protal —op update -n node.session.auth.username -v auth_username
iscsiadm -m node -T target_iqn -p target_protal —op update -n node.session.auth.password -v auth_password
c. 检查session,登陆
iscsiadm -m session检查是否登录成功
iscsiadm –m node –T targetname –p ip —login 登陆建立session
d. 设置为随机器启动而启动
iscsiadm -m node -T target_iqn -p target_protal —op update -n node.startup -v automatic
iscsiadm -m node -T target_iqn -p target_protal –rescan

step11: 更新 cinder DB 数据

nova.virt.block_device.DriverVolumeBlockDevice.attach
     volume_api.attach(context, volume_id, instance.uuid,
                       self['mount_device'], mode=mode)
        ↓
nova.volume.API.attach()
     cinderclient(context).volumes.attach(volume_id, instance_uuid,
                                          mountpoint, mode=mode)

step10 提到的多路径:

普通的电脑主机都是一个硬盘挂接到一个总线上,这里是一对一的关系。而到了有光纤组成的SAN环境,或者由iSCSI组成的IPSAN环境,由于主机和存储通过了光纤交换机或者多块网卡及IP来连接,这样的话,就构成了多对多的关系。也就是说,主机到存储可以有多条路径可以选择。主机到存储之间的IO由多条路径可以选择。每个主机到所对应的存储可以经过几条不同的路径,如果是同时使用的话,I/O流量如何分配?其中一条路径坏掉了,如何处理?还有在操作系统的角度来看,每条路径,操作系统会认为是一个实际存在的物理盘,但实际上只是通向同一个物理盘的不同路径而已,这样是在使用的时候,就给用户带来了困惑。多路径软件就是为了解决上面的问题应运而生的。

多路径的主要功能就是和存储设备一起配合实现如下功能:

  1. 故障的切换和恢复
  2. IO流量的负载均衡
  3. 磁盘的虚拟化

参考

开启多路径
yikun's blog

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,087评论 18 139
  • 以下是本人通过阅读Grizzly版OpenStack源码,整理的简要的Nova模块源码结构,希望和大家相互交流。 ...
    Chenzongshu阅读 2,592评论 0 50
  • 一、基本数据类型 注释 单行注释:// 区域注释:/* */ 文档注释:/** */ 数值 对于byte类型而言...
    龙猫小爷阅读 4,213评论 0 16
  • Openstack Mitaka安装部署教程 一、实验环境: 系统:centos7.2-minimal 网络:管理...
    指间_流年阅读 2,063评论 0 0
  • Arch Linux是一个优秀的linux操作系统。其优点是滚动发行、软件包比较新,并且可以深度可定制。缺点是由于...
    乐百川阅读 9,896评论 6 39