一文看懂ovirt的supervdsmd服务

在ovirt的计算节点上supervdsmd.service是有root用户权限的,可以操作系统底层的资源,其他的服务需要与之通讯来完成对资源的操作。

其主要完成两个工作:

动态扩展_SuperVdsm和启动BaseManager(multiprocessing.managers)服务端。

然后就是监听其他服务发送过的API请求并执行。

一.动态扩展_SuperVdsm

关键代码:

if _glusterEnabled:
    for name, func in listPublicFunctions(GLUSTER_MGMT_ENABLED):
        setattr(_SuperVdsm, name, bind(logDecorator(func)))

上述代码实现的功能是:

把gluster目录下的模块的函数到取出来,在函数名字之前加了字符串gluster,然后赋给_SuperVdsm。

关键代码:

for _, module_name, _ in pkgutil.iter_modules([supervdsm_api.
                                               __path__[0]]):
    module = importlib.import_module('%s.%s' %
                                     (supervdsm_api.__name__,
                                      module_name))
    api_funcs = [f for _, f in module.__dict__.iteritems()
                 if callable(f) and getattr(f, 'exposed_api', False)]
    for func in api_funcs:
        setattr(_SuperVdsm, func.__name__, bind(logDecorator(func)))

上述代码实现的功能是:

把supervdsm_api目录下的模块中被@expose的函数到取出来,直接赋给_SuperVdsm。这样就为给supervdsmd.service添加新的API提供了很简单的方法:只要在supervdsm_api文件夹下新建一个pthon文件就可以自动导出新的API了。

setattr之前的_SuperVdsm:

初始的_SuperVdsm中函数很少,都在class _SuperVdsm中定义,例如mount、multipath_status、removeDeviceMapping等。

setattr之后的_SuperVdsm:

动态扩展之后的_SuperVdsm中函数包含了所有要导出的API函数,包括三部分API:

1.原来_SuperVdsm的API,例如mount、multipath_status、getdeviSCSIinfo等;

2.gluster文件夹下导出的API,例如gluster/cli.py中的snapshotInfo等;

3.supervdsm_api文件夹下导出的API,例如supervdsm_api/hwinfo.py中的getHardwareInfo等。

二.启动BaseManager(multiprocessing.managers)服务端

启动一个BaseManager的serve_forever线程程,它监听/var/run/vdsm/svdsm.sock,它的callable设置为_SuperVdsm供BaseManager的客户端来调用其中的API。(供调用的API在前面已经全部赋给了_SuperVdsm)

关键代码:

manager = _SuperVdsmManager(address=address, authkey='')
manager.register('instance', callable=_SuperVdsm)
server = manager.get_server()
servThread = concurrent.thread(server.serve_forever)
servThread.start()

其中_SuperVdsmManager的定义:

class _SuperVdsmManager(BaseManager):
    pass

到此supervdsmd.service的任务就完成了,剩下的就是等着client来调用_SuperVdsm中的API了。

三.client(例如vdsmd.service)如何与supervdsmd.service通信

在common/supervdsm.py中实现了BaseManager(multiprocessing.managers)的clinet: SuperVdsmProxy:

class SuperVdsmProxy(object):
    def _connect(self):
        self._manager = _SuperVdsmManager(address=ADDRESS, authkey='')
        self._manager.register('instance')
        self._manager.register('open')
        try:
            function.retry(
                self._manager.connect, Exception, timeout=60, tries=3)

在vdsmd.service中使用SuperVdsmProxy来调用supervdsmd.service的API的方法:

from vdsm.common import supervdsm
supervdsm.getProxy().xxxxxxAPI()

也可以自己写一个python文件来调用supervdsmd.service的API

例如:

from vdsm.common import supervdsm
print supervdsm.getProxy().getHardwareInfo()

下面是完整的架构图:

BaseManager例子

为了更好的理解BaseManager的工作过程,我们把vdsm中关于BaseManager(multiprocessing.managers)的服务端和客户端代码单独摘出来,组成一个可运行的domo程序:

服务端:

from multiprocessing.managers import BaseManager
class _SuperVdsmManager(BaseManager):
    pass
class _SuperVdsm(object):
    def test_api(*args, **kwargs):
        return "this is server"
def start_server():
    manager = _SuperVdsmManager(address='/tmp/test.sock', authkey='')
    manager.register('instance', callable=_SuperVdsm)
    server = manager.get_server()
    server.serve_forever()
start_server()

客户端:

class ProxyCaller(object):
    def __init__(self, supervdsmProxy, funcName):
        self._funcName = funcName
        self._supervdsmProxy = supervdsmProxy
    def __call__(self, *args, **kwargs):
        callMethod = lambda: \
            getattr(self._supervdsmProxy._svdsm, self._funcName)(*args,
                                                                 **kwargs)
        return callMethod()
class SuperVdsmProxy(object):
    def __init__(self):
        self._manager = None
        self._svdsm = None
        self._connect()
    def open(self, *args, **kwargs):
        return self._manager.open(*args, **kwargs)
    def _connect(self):
        self._manager = _SuperVdsmManager(address='/tmp/test.sock', authkey='')
        self._manager.register('instance')
        self._manager.register('open')
        self._manager.connect()
        self._svdsm = self._manager.instance()
    def __getattr__(self, name):
        return ProxyCaller(self, name)
def start_client():
    instance = SuperVdsmProxy()
    print instance.test_api()
start_client()


关注本公众号,了解更多关于云计算虚拟化的知识。

原文发布于微信公众号 - 虚拟化云计算(openstack_openstack)

原文发表时间:2018-04-04

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏张首富-小白的成长历程

Linux软件包安装--三魔鬼

yum是基于rpm的软件包管理器,他可以使系统管理人员交互和自动化地更细与管理rpm包,他能自动从服务器下载RPM包并安装,他可以自动处理依赖关系,自动安装所有...

3122
来自专栏左瞅瞅,右瞅瞅

nc命令详解

NetCat,在网络工具中有“瑞士军刀”美誉,其有Windows和Linux的版本。因为它短小精悍(1.84版本也不过25k,旧版本或缩减版甚至更小)、功能实用...

3101
来自专栏杨龙飞前端

npm 常用配置

npm config list/ls 显示配置信息 npm config list/ls -l 更详细 npm -h 显示帮助信息,建议多查看 npm -l d...

3943
来自专栏自由而无用的灵魂的碎碎念

解决windows 10无法打开.hlp帮助文件的问题

最近学习UML,使用的Rational Rose 7.0,使用帮助时,才发现windows 10无法打开.hlp的帮助文件。虽然win10默认定向到微软支持页面...

1393
来自专栏jeremy的技术点滴

现代Web开发教程系列_02

3027
来自专栏小灰灰

Java并发学习之线程状态及Thread常用方法详解

线程状态及Thread常用方法详解 I. 线程状态 在前面线程创建的一篇博文中,明确说明只有在调用 Thread#start()方法之后,线程才会启动;那线程...

2227
来自专栏北京马哥教育

Linux基础急速入门:用 TCPDUMP 抓包

简介 网络数据包截获分析工具。支持针对网络层、协议、主机、网络或端口的过滤。并提供and、or、not等逻辑语句帮助去除无用的信息。 tcpdump - dum...

3798
来自专栏分布式系统进阶

Kafka的消息是如何被消费的?Kafka源码分析-汇总

1843
来自专栏IT技术精选文摘

从HTTP/0.9到HTTP/2:一文读懂HTTP协议的历史演变和设计思路

HTTP 协议是互联网的基础协议,也是网页开发的必备知识,最新版本 HTTP/2 更是让它成为技术热点。

1194
来自专栏大内老A

使命必达: 深入剖析WCF的可靠会话[原理揭秘篇](下)

上面一部分我们站在信道层的角度剖析了WCF为了实现可靠会话在信道层进行的一系列消息交换,或者说客户端和服务端的RS信道为了实现可靠消息传输所进行一轮又一轮的握手...

1979

扫码关注云+社区

领取腾讯云代金券