什么是stevedore?
stevedore是建立在setuptools的entry point的功能上的,用于python程序动态加载代码,在openstack中被多个组件使用:比如ceilometer,neutron的plugin。当然,你可以直接使用
python的某些黑魔法实现插件的加载,但太原始了。stevedore基于entry point提供了更高层次的封装。
stevedore的官方文档在此:http://docs.openstack.org/developer/stevedore/
学习和入门setuptools:http://www.360doc.com/content/14/0306/11/13084517_358166737.shtml
官方文档的部分翻译:http://www.360doc.com/content/14/0429/19/9482_373285413.shtml
来自华为孔令贤(源地址非该人博客)的setup.py详解:http://blog.sina.com.cn/s/blog_4951301d0101etvj.html
偶计划在sora项目中引入stevedore与oslo.config简化某些开发的组件,先是测试了stevedore,写了个简单的scheduler插件
环境准备:
安装stevedore库,及组织相关目录
pip install stevedore
mkdir sora
cd sora
mkdir scheduler #scheduler在sora目录中
构建这样一个目录树:
步骤:
创建一个抽象类scheduler,新的plugin要继承scheduler并重写相关方法scheduler
#sora/scheduler/base.py
import abc
class scheduler(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def scheduler(self,data):
pass
继承base类创建插件simple与memory
#sora/scheduler/memory.py
import base
class memoryscheduler(base.scheduler):
def scheduler(self,data):
id = data[max(data['memory'])]
return id
#sora/scheduler/simple.py
import base
import random
class simplescheduler(base.scheduler):
def scheduler(self,data):
id = data[random.choice(data['memory'])]
return id
simple插件是随机选择一个节点id,而memory则选择内存剩余最多的节点id
编写setup.py
#sora/setup.py
from setuptools import setup, find_packages
setup(
name='sora-scheduler',
version='1.0',
description='sora.scheduler',
author='hochikong',
author_email='hochikong',
platforms=['Any'],
scripts=[],
# provides=['sora.scheduler',
# ],
packages=find_packages(),
include_package_data=True,
entry_points={
'sora.scheduler': [
'memorybase = scheduler.memory:memoryscheduler',
'randombase = scheduler.simple:simplescheduler',
],
},
zip_safe=False,
)
安装自己编写的包:
root@workgroup1:~/sora# python setup.py install
running install
running bdist_egg
running egg_info
creating sora_scheduler.egg-info
writing sora_scheduler.egg-info/PKG-INFO
writing top-level names to sora_scheduler.egg-info/top_level.txt
writing dependency_links to sora_scheduler.egg-info/dependency_links.txt
writing entry points to sora_scheduler.egg-info/entry_points.txt
writing manifest file 'sora_scheduler.egg-info/SOURCES.txt'
reading manifest file 'sora_scheduler.egg-info/SOURCES.txt'
writing manifest file 'sora_scheduler.egg-info/SOURCES.txt'
installing library code to build/bdist.linux-x86_64/egg
running install_lib
running build_py
creating build
creating build/lib.linux-x86_64-2.7
creating build/lib.linux-x86_64-2.7/scheduler
copying scheduler/__init__.py -> build/lib.linux-x86_64-2.7/scheduler
copying scheduler/base.py -> build/lib.linux-x86_64-2.7/scheduler
copying scheduler/memory.py -> build/lib.linux-x86_64-2.7/scheduler
copying scheduler/simple.py -> build/lib.linux-x86_64-2.7/scheduler
creating build/bdist.linux-x86_64
creating build/bdist.linux-x86_64/egg
creating build/bdist.linux-x86_64/egg/scheduler
copying build/lib.linux-x86_64-2.7/scheduler/__init__.py -> build/bdist.linux-x86_64/egg/scheduler
copying build/lib.linux-x86_64-2.7/scheduler/base.py -> build/bdist.linux-x86_64/egg/scheduler
copying build/lib.linux-x86_64-2.7/scheduler/memory.py -> build/bdist.linux-x86_64/egg/scheduler
copying build/lib.linux-x86_64-2.7/scheduler/simple.py -> build/bdist.linux-x86_64/egg/scheduler
byte-compiling build/bdist.linux-x86_64/egg/scheduler/__init__.py to __init__.pyc
byte-compiling build/bdist.linux-x86_64/egg/scheduler/base.py to base.pyc
byte-compiling build/bdist.linux-x86_64/egg/scheduler/memory.py to memory.pyc
byte-compiling build/bdist.linux-x86_64/egg/scheduler/simple.py to simple.pyc
creating build/bdist.linux-x86_64/egg/EGG-INFO
copying sora_scheduler.egg-info/PKG-INFO -> build/bdist.linux-x86_64/egg/EGG-INFO
copying sora_scheduler.egg-info/SOURCES.txt -> build/bdist.linux-x86_64/egg/EGG-INFO
copying sora_scheduler.egg-info/dependency_links.txt -> build/bdist.linux-x86_64/egg/EGG-INFO
copying sora_scheduler.egg-info/entry_points.txt -> build/bdist.linux-x86_64/egg/EGG-INFO
copying sora_scheduler.egg-info/not-zip-safe -> build/bdist.linux-x86_64/egg/EGG-INFO
copying sora_scheduler.egg-info/top_level.txt -> build/bdist.linux-x86_64/egg/EGG-INFO
creating dist
creating 'dist/sora_scheduler-1.0-py2.7.egg' and adding 'build/bdist.linux-x86_64/egg' to it
removing 'build/bdist.linux-x86_64/egg' (and everything under it)
Processing sora_scheduler-1.0-py2.7.egg
creating /usr/local/lib/python2.7/dist-packages/sora_scheduler-1.0-py2.7.egg
Extracting sora_scheduler-1.0-py2.7.egg to /usr/local/lib/python2.7/dist-packages
Adding sora-scheduler 1.0 to easy-install.pth file
Installed /usr/local/lib/python2.7/dist-packages/sora_scheduler-1.0-py2.7.egg
Processing dependencies for sora-scheduler==1.0
Finished processing dependencies for sora-scheduler==1.0
尝试手动加载插件:
root@workgroup1:~/sora# python
Python 2.7.6 (default, Mar 22 2014, 22:59:56)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from scheduler.memory import memoryscheduler
>>> dt = {13:'id1',324:'id2',434:'id3','memory':[13,324,434]}
>>> driver = memoryscheduler()
>>> driver.scheduler(dt)
'id3'
>>>
不过手动加载并没有太大意义
使用stevedore的drivermanager:
>>> from stevedore import driver
>>> dt = {13:'id1',324:'id2',434:'id3','memory':[13,324,434]}
>>> mgr = driver.DriverManager(
... namespace='sora.scheduler',
... name='randombase',
... invoke_on_load=True, #设置为true,即载入后自动实例化插件类,如果是函数,则调用
... )
>>> mgr.driver.scheduler(dt)
'id3'
>>> mgr.driver.scheduler(dt)
'id2'
>>> mgr.driver.scheduler(dt)
'id3'
>>> mgr.driver.scheduler(dt)
'id2'
>>> mgr.driver.scheduler(dt)
'id1'
>>>
这里我导入了randombase,怎样调用plugin里的方法很明显了
顺带检查下python中我的包的安装状况:
root@workgroup1:~# cd /usr/local/lib/python2.7/dist-packages/
root@workgroup1:/usr/local/lib/python2.7/dist-packages# ls
amqp OpenSSL
amqp-1.4.6.dist-info pbr
anyjson pbr-1.3.0.dist-info
anyjson-0.3.3.egg-info pika
backports pika-0.9.14.egg-info
backports.ssl_match_hostname-3.4.0.2.egg-info psutil
billiard psutil-2.2.1.egg-info
billiard-3.3.0.19.egg-info _psutil_linux.so
_billiard.so _psutil_posix.so
bottle-0.12.8.egg-info pymongo
bottle.py pymongo-2.8.egg-info
bottle.pyc pyOpenSSL-0.15.1.dist-info
bson python_etcd-0.3.3.egg-info
celery pytz
celery-3.1.17.dist-info pytz-2015.2.dist-info
docker six-1.9.0.dist-info
docker_py-1.0.0.egg-info six.py
easy-install.pth six.pyc
etcd sora_scheduler-1.0-py2.7.egg
eventlet SQLAlchemy-0.9.9-py2.7-linux-x86_64.egg
eventlet-0.17.1.dist-info stevedore
funtests stevedore-1.6.0.dist-info
glances tests
Glances-2.3.egg-info virtualenv-12.0.7.dist-info
greenlet-0.4.5.egg-info virtualenv.py
greenlet.so virtualenv.pyc
gridfs virtualenv_support
kombu websocket
kombu-3.0.24.dist-info websocket_client-0.25.0.egg-info
可以看到里面有个sora_scheduler-1.0-py2.7.egg目录,查看一下:
我不太清楚为什么python在导入scheduler模块时,并不需要指明sora_scheduler-1.0-py2.7.egg,可能与egg有关,执行import scheduler时,导入的是sora_scheduler-1.0-py2.7.egg目录下
的scheduler包,同样的还有SQLAlchemy,有一个SQLAlchemy-0.9.9-py2.7-linux-x86_64.egg,导入时只需执行import sqlalchemy
疑问:
可能有人会问,如果我想添加新的插件要怎么办,我想,最好的方法就是修改setup.py,更新安装一次该包即可
参考:
http://docs.openstack.org/developer/stevedore/
http://www.360doc.com/content/14/0306/11/13084517_358166737.shtml
http://www.360doc.com/content/14/0429/19/9482_373285413.shtml