在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()
关注微信公众号【虚拟化云计算】,阅读更多虚拟化云计算知识,纯技术干货更新不停。扫下面:
感谢大佬分享!