一、cinder-api服务的入口函数

D:\code-program\cinder-ocata_cinder\cinder\api\contrib\admin_actions.py
from cinder import volume
self.volume_api = volume.API()
class VolumeAdminController(AdminController):
"""AdminController for Volumes."""
@wsgi.Controller.api_version('3.28')
@wsgi.action('os-migrate_volume_progress')
def _get_migrate_volume_progress(self, req, id, body):
"""Get the migration progress of a volume."""
context = req.environ['cinder.context']
self.authorize(context, 'get_migrate_volume_progress')daim
volume = self._get(context, id)-----根据卷的uuid获取卷的信息
return self.volume_api.get_migrate_volume_progress(context, volume)---调用volume.api里面的接口 D:\code-program\cinder-ocata_cinder\cinder\volume\api.py
from cinder.volume import rpcapi as volume_rpcapi
self.volume_rpcapi = volume_rpcapi.VolumeAPI()
class API(base.Base):
"""API for interacting with the volume manager."""
AVAILABLE_MIGRATION_STATUS = (None, 'deleting', 'error', 'success')
#返回一个特定卷的迁移进度,入参为将被迁移或者正在被迁移的源卷信息,
#返回值包括卷uuid,迁移的状态、及迁移的进度
#如果卷的迁移状态migration_status为migrating,则获取卷的实际迁移进度
#如果卷的迁移状态migration_status为starting,则返回卷的迁移进度为0%,在源卷所在的存储节点cinder-volume服务没有接受到发送的
#卷迁移rpc.cast请求以前,此时调用获取卷的迁移进度,会一直是0%的状态
#如果卷的迁移进度migration_status为success',completing',则返回卷的迁移进度为100%,在卷成功迁移完成之后,获取卷的迁移进度,
#那么它是100%
#对于获取到的卷的迁移进度为NA,这个值,那么一种可能情况是,卷的迁移消息还没被cinder.volume接口migrate_volume及时的处理,就调用
#获取卷的迁移进度api接口
@wrap_check_policy
def get_migrate_volume_progress(self, context, volume):
"""Return the migration progress for a specific volume. :param context: the context of the caller
:param volume: the source volume to be migrated or being migrated
:return the volume migration progress including volume id, migration
status and migration progress
"""
volume_progress = {'volume_id': volume['id'],
'migration_status': volume['migration_status'],
'migration_progress': 'NA'}---初始值为NA
if volume['migration_status'] == 'migrating':
progress = self.volume_rpcapi.get_migrate_volume_progress(------对步骤1的详解
context, volume)
volume_progress['migration_progress'] = progress + "%"
elif volume['migration_status'] == 'starting':
volume_progress['migration_progress'] = '0%'
elif volume['migration_status'] in ('success', 'completing'):
volume_progress['migration_progress'] = '100%'
LOG.info(_LI('Volume %(vol_id)s has been migrated %(mig_progress)s.'),
{'vol_id': volume['id'],
'mig_progress': volume_progress['migration_progress']})
return {'volume': volume_progress} 对步骤1的详解
给源卷所在的cinder-volume服务的存储节点,发送一个rpc.call请求,来获取迁移的进度
D:\code-program\cinder-ocata_cinder\cinder\volume\rpcapi.py
class VolumeAPI(rpc.RPCAPI):
"""Client side of the volume rpc API.
@rpc.assert_min_rpc_version('3.11')
def get_migrate_volume_progress(self, ctxt, volume):
version = self._compat_ver('3.11')
cctxt = self._get_cctxt(volume['host'], version=version)
return cctxt.call(ctxt, 'get_migrate_volume_progress',
volume=volume)

二、源卷所在的cinder-volume服务存储节点,接受rpc.call请求,并处理,虽然配置了cinder-volume对应的驱动,volume_driver = cinder.volume.drivers.lvm.LVMVolumeDriver

但是最终调用的是BaseVD里面的方法

D:\code-program\cinder-ocata_cinder\cinder\volume\driver.py
@six.add_metaclass(abc.ABCMeta)
class BaseVD(object):
def get_migrate_volume_progress(self, context, volume, src_path=None,
dest_path=None,
migration_mode='HOST_BASED'):
if migration_mode is None and volume['id'] in self._migration_info:
migration_mode = self._migration_info[volume['id']]
# NOTE(fengzy): If the volume is migrated using dd command,
# e.g. volume migration from LVM to LVM, mode is HOST_BASED.
# For the volume is migrated using file I/O, mode is FILE_BASED,
# DRIVER_BASED need driver support. And now our mode only
# HOST_BASED and FILE_BASED, no DRIVER_BASED.
#由于是lvm到lvm的迁移,因此mode是基于主机的 HOST_BASED
if migration_mode == self.HOST_BASED:-----走该分支
return self.get_host_based_volume_progress(volume, src_path,-----对步骤二进行详解
dest_path)
elif migration_mode == self.DRIVER_BASED:
progress = self.get_migration_progress(
context, volume)
if progress:
return six.text_type(progress)
else:
return self.UNKNOWN_PROGRESS
elif migration_mode == self.FILE_BASED:
key_handle = volume['id'] + 'dest_handle'
if key_handle in self._migration_info:
handle = self._migration_info[key_handle]
if handle:
try:
size_in_bytes = int(volume['size']) * units.Gi
if not handle.closed:
pro = six.text_type(
handle.tell() * 100 / size_in_bytes)
self._migration_info[volume['id'] +
'previous_progress'] = pro
return pro
else:
return '100'
except ValueError:
return self._migration_info[volume['id'] +
'previous_progress']
else:
return self._migration_info[volume['id'] +
'previous_progress']
return self.UNKNOWN_PROGRESS 对步骤二进行详解
def get_host_based_volume_progress(self, volume, src_path=None,
dest_path=None):
key_source = volume['id'] + 'source'
key_dest = volume['id'] + 'dest'
if dest_path is None:
dest_path = self._migration_info.get(key_dest, None)
if not dest_path:
return '0'
if src_path is None:
src_path = self._migration_info.get(key_source, None)
if not src_path:
return '0' pid = self.get_pid_for_host_based_migration(volume['id'], src_path,--获取dd拷贝命令的pid信息
dest_path)
if pid:
#迁移进度的算法,按照文件大小的相除进行计算的
self._migration_info[volume['id'] + 'pid'] = pid
size_in_bytes = int(volume['size']) * units.Gi
position_path = ('/proc/%s/fdinfo/1') % pid
try:
output = utils.read_file_as_root(position_path)
position = self._get_position(output)
progress = six.text_type(position * 100 / size_in_bytes)
self._migration_info[volume['id'] +
'previous_progress'] = progress
return progress
except exception.FileNotFound:
return self._migration_info.get(
volume['id'] + 'previous_progress', '0')
else:
return self._migration_info.get(
volume['id'] + 'previous_progress', '0') def get_pid_for_host_based_migration(self, volume_id, src_path,
dest_path):
# Get the PID for the block copy command for the source volume.
pid = self._migration_info.get(volume_id + 'pid', None)
if pid is None:
pid = volume_utils.get_process_pid('dd', src_path,
dest_path)
return pid
D:\code-program\cinder-ocata_cinder\cinder\volume\utils.py
def get_process_pid(command_name, src_path, dest_path):
for proc in psutil.process_iter():
try:
p_info = proc.as_dict(attrs=['pid', 'name', 'cmdline'])
except psutil.NoSuchProcess:
pass
else:
is_in_path = "if=" + src_path in p_info['cmdline'] and\
"of=" + dest_path in p_info['cmdline']
if command_name == p_info['name'] and is_in_path:
return p_info['pid']
return None

 三、迁移的例子

[root@test network-scripts]# ps -ef |grep dd
root 2 0 0 2015 ? 00:00:00 [kthreadd]
root 516 1 86 08:42 ? 08:51:10 /usr/libexec/qemu-kvm -name instance-0000dcaf -S -M rhel6.5.0 -cpu SandyBridge,+erms,+smep,+fsgsbase,+pdpe1gb,+rdrand,+f16c,+osxsave,+dca,+pcid,+pdcm,+xtpr,+tm2,+est,+smx,+vmx,+ds_cpl,+monitor,+dtes64,+pbe,+tm,+ht,+ss,+acpi,+ds,+vme -enable-kvm -m 32768 -realtime mlock=off -smp 16,sockets=16,cores=1,threads=1 -uuid e664cce7-a4ac-410b-a775-38c19b576836 -smbios type=1,manufacturer=Red Hat Inc.,product=OpenStack Nova,version=2014.1.1-5.el6,serial=6d3753e6-3570-415a-89e3-ea2bd6e4559d,uuid=e664cce7-a4ac-410b-a775-38c19b576836 -nodefconfig -nodefaults -chardev socket,id=charmonitor,path=/var/lib/libvirt/qemu/instance-0000dcaf.monitor,server,nowait -mon chardev=charmonitor,id=monitor,mode=control -rtc base=utc,driftfix=slew -no-kvm-pit-reinjection -no-shutdown -device piix3-usb-uhci,id=usb,bus=pci.0,addr=0x1.0x2 -device virtio-serial-pci,id=virtio-serial0,bus=pci.0,addr=0x4 -drive file=/os_instance/e664cce7-a4ac-410b-a775-38c19b576836/disk,if=none,id=drive-virtio-disk0,format=qcow2,cache=writethrough -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x5,drive=drive-virtio-disk0,id=virtio-disk0,bootindex=1 -drive file=/dev/mapper/vg_os-volume--54549594--66ac--4edd--97a6--410071d7798e,if=none,id=drive-virtio-disk1,format=raw,serial=54549594-66ac-4edd-97a6-410071d7798e,cache=none -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x6,drive=drive-virtio-disk1,id=virtio-disk1 -drive file=/dev/mapper/vg_os-volume--c9945a36--ac4b--4a55--92e6--4a7c361b7649,if=none,id=drive-virtio-disk2,format=raw,serial=c9945a36-ac4b-4a55-92e6-4a7c361b7649,cache=none -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x7,drive=drive-virtio-disk2,id=virtio-disk2 -drive file=/os_instance/e664cce7-a4ac-410b-a775-38c19b576836/disk.config,if=none,media=cdrom,id=drive-ide0-1-1,readonly=on,format=raw,cache=writethrough -device ide-drive,bus=ide.1,unit=1,drive=drive-ide0-1-1,id=ide0-1-1 -netdev tap,fd=24,id=hostnet0,vhost=on,vhostfd=25 -device virtio-net-pci,netdev=hostnet0,id=net0,mac=fa:16:3e:6e:ba:a3,bus=pci.0,addr=0x3 -chardev file,id=charserial0,path=/os_instance/e664cce7-a4ac-410b-a775-38c19b576836/console.log -device isa-serial,chardev=charserial0,id=serial0 -chardev pty,id=charserial1 -device isa-serial,chardev=charserial1,id=serial1 -chardev pty,id=charchannel0 -device virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,id=channel0,name=com.redhat.spice.0 -spice port=5900,addr=0.0.0.0,seamless-migration=on -k en-us -vga qxl -global qxl-vga.ram_size=67108864 -global qxl-vga.vram_size=67108864 -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x8
root 3157 1876 0 01:38 ? 00:00:00 sudo cinder-rootwrap /etc/cinder/rootwrap.conf dd if=/dev/mapper/vg_os-volume--54549594--66ac--4edd--97a6--410071d7798e of=/dev/disk/by-path/ip-192.168.0.1:3260-iscsi-iqn.2010-10.org.openstack:volume-d39b3037-893d-4590-8fc3-ecfbc476d8b8-lun-1 count=1048576 bs=1M iflag=direct oflag=direct
root 3158 3157 0 01:38 ? 00:00:00 /usr/bin/python /usr/bin/cinder-rootwrap /etc/cinder/rootwrap.conf dd if=/dev/mapper/vg_os-volume--54549594--66ac--4edd--97a6--410071d7798e of=/dev/disk/by-path/ip-192.168.0.1:3260-iscsi-iqn.2010-10.org.openstack:volume-d39b3037-893d-4590-8fc3-ecfbc476d8b8-lun-1 count=1048576 bs=1M iflag=direct oflag=direct
root 3160 3158 0 01:38 ? 00:02:50 /bin/dd if=/dev/mapper/vg_os-volume--54549594--66ac--4edd--97a6--410071d7798e of=/dev/disk/by-path/ip-192.168.0.1:3260-iscsi-iqn.2010-10.org.openstack:volume-d39b3037-893d-4590-8fc3-ecfbc476d8b8-lun-1 count=1048576 bs=1M iflag=direct oflag=direct
root 17245 1 0 2019 ? 12:49:45 /opt/promes/exporter/node_exporter_p18/node_exporter-0.18.1.linux-amd64/node_exporter --web.listen-address=:19100
root 26012 12253 0 18:55 pts/3 00:00:00 grep dd
root 27426 2 0 2016 ? 00:00:29 [ib_addr]
[root@testnetwork-scripts]# [root@test by-path]# ls
ip-192.168.0.2:3260-iscsi-iqn.2010-10.org.openstack:volume-d39b3037-893d-4590-8fc3-ecfbc476d8b8-lun-1 pci-0000:01:00.0-scsi-0:2:0:0-part2
pci-0000:01:00.0-scsi-0:2:0:0 pci-0000:01:00.0-scsi-0:2:1:0
pci-0000:01:00.0-scsi-0:2:0:0-part1 pci-0000:01:00.0-scsi-0:2:1:0-part1

  

 

  

cinder 卷迁移进度的代码分析的更多相关文章

  1. OpenStack 虚拟机冷/热迁移的实现原理与代码分析

    目录 文章目录 目录 前文列表 冷迁移代码分析(基于 Newton) Nova 冷迁移实现原理 热迁移代码分析 Nova 热迁移实现原理 向 libvirtd 发出 Live Migration 指令 ...

  2. cinder migrate基础内容-源码分析

    一.cinder-api服务入口 D:\code-program\cinder-codejuno\api\contrib\admin_actions.py from cinder import vol ...

  3. 完整全面的Java资源库(包括构建、操作、代码分析、编译器、数据库、社区等等)

    构建 这里搜集了用来构建应用程序的工具. Apache Maven:Maven使用声明进行构建并进行依赖管理,偏向于使用约定而不是配置进行构建.Maven优于Apache Ant.后者采用了一种过程化 ...

  4. JQuery data API实现代码分析

    JQuery data 接口是什么? .data() Store arbitrary data associated with the matched elements or return the v ...

  5. Linux时间子系统之(十七):ARM generic timer驱动代码分析

    专题文档汇总目录 Notes:ARM平台Clock/Timer架构:System counter.Timer以及两者之间关系:Per cpu timer通过CP15访问,System counter通 ...

  6. rocketmq生产者代码分析

    rocketmq生产者代码分析 环境安装 参考http://rocketmq.apache.org/docs/quick-start/ ,配置环境变量 export NAMESRV_ADDR=loca ...

  7. 2018-2019-2 20165312《网络攻防技术》Exp4 恶意代码分析

    2018-2019-2 20165312<网络攻防技术>Exp4 恶意代码分析 知识点总结 1.有关schtasks schtacks的作用:安排命令和程序定期运行或在指定时间内运行.从计 ...

  8. 【转载】word2vec原理推导与代码分析

    本文的理论部分大量参考<word2vec中的数学原理详解>,按照我这种初学者方便理解的顺序重新编排.重新叙述.题图来自siegfang的博客.我提出的Java方案基于kojisekig,我 ...

  9. 2017-2018-2 20155314《网络对抗技术》Exp4 恶意代码分析

    2017-2018-2 20155314<网络对抗技术>Exp4 恶意代码分析 目录 实验要求 实验内容 实验环境 基础问题回答 预备知识 实验步骤 1 静态分析 1.1 使用virsca ...

随机推荐

  1. Python匿名函数_return语句

    Python匿名函数: 使用 lambda 关键字创建匿名函数: lambda 定义的函数只是一个表达式,而不是代码块 lambda 函数拥有自己的命名空间,不能够访问参数列表之外的 或 全局命名空间 ...

  2. Numpy random函数

    import numpy as np # 生成一个随机数组 np.random.randint(0,6,3) # array([1, 1, 3]) # 生成一个随机数组(二维数组) np.random ...

  3. 【FZYZOJ】「Paladin」瀑布 题解(期望+递推)

    题目描述 CX在Minecraft里建造了一个刷怪塔来杀僵尸.刷怪塔的是一个极高极高的空中浮塔,边缘是瀑布.如果僵尸被冲入瀑布中,就会掉下浮塔摔死.浮塔每天只能工作 $t$秒,刷怪笼只能生成 $N$  ...

  4. Junit4 测试代码

    Junit4 测试代码 import org.junit.Test; import org.junit.runner.RunWith; @RunWith(SpringJUnit4ClassRunner ...

  5. 32-关键字:abstract

    abstract: 抽象的 1.可以用来修饰:类.方法 2.具体的:abstract修饰类:抽象类 * > 此类不能实例化 * > 抽象类中一定有构造器,便于子类实例化时调用(涉及:子类对 ...

  6. 可能是Asp.net Core On host、 docker、kubernetes(K8s) 配置读取的最佳实践

    写在前面 为了不违反广告法,我竭尽全力,不过"最佳实践"确是标题党无疑,如果硬要说的话 只能是个人最佳实践. 问题引出 ​ 可能很多新手都会遇到同样的问题:我要我的Asp.net ...

  7. 借助GPU Boost和K80 Autoboost提高性能

    原网站:https://devblogs.nvidia.com/increase-performance-gpu-boost-k80-autoboost/ 由于我主要使用nvidia-smi,故nvc ...

  8. UI自动化填写问卷(selenium)+定时任务(懒人必备)

    1.自动填报 UI自动化 selenium 开发程序动机:天天有人催着填写问卷,弄的头大.主要还是懒的每天一个个去填写内容. 开发总时长:2个小时:学习+开发+修改 遇到的小问题: 在自动化填写地图的 ...

  9. “随手记”APP与已经发布的记账软件“鲨鱼记账”的差距

    我们使用并观察了“鲨鱼记账”APP,发现,我们的软件真的还有很多不足的地方.就功能这方面来说:“鲨鱼记账”APP有更多的收入.支出分类:就界面来说:“鲨鱼记账”APP有比我们优美太多的页面和背景.但是 ...

  10. C语言学习笔记之原码反码补码

    原码:就是我们自己看的,以及机器输出给我们看的 补码:机器永远是以补码的形式将数据保存在计算机中 正数: 原码=反码=补码 负数: 反码:原码的符号位不变,其他位取反 ,1变0   0变1 补码:机器 ...