什麼是stevedore?html
stevedore是創建在setuptools的entry point的功能上的,用於python程序動態加載代碼,在openstack中被多個組件使用:好比ceilometer,neutron的plugin。固然,你能夠直接使用python
python的某些黑魔法實現插件的加載,但太原始了。stevedore基於entry point提供了更高層次的封裝。linux
stevedore的官方文檔在此:http://docs.openstack.org/developer/stevedore/ web
學習和入門setuptools:http://www.360doc.com/content/14/0306/11/13084517_358166737.shtml sql
官方文檔的部分翻譯:http://www.360doc.com/content/14/0429/19/9482_373285413.shtml docker
來自華爲孔令賢(源地址非該人博客)的setup.py詳解:http://blog.sina.com.cn/s/blog_4951301d0101etvj.html json
偶計劃在sora項目中引入stevedore與oslo.config簡化某些開發的組件,先是測試了stevedore,寫了個簡單的scheduler插件websocket
環境準備:
dom
安裝stevedore庫,及組織相關目錄python2.7
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