Delete oslo-incubator code & switch to oslo.service
Change-Id: Ie0e70d3f603d61e8c7ad95b7c548008776c1af51
This commit is contained in:
parent
4981d083c4
commit
94d8230a9e
@ -1,348 +0,0 @@
|
||||
Aaron Rosen <aaronorosen@gmail.com>
|
||||
Abhijeet Malawade <Abhijeet.Malawade@nttdata.com>
|
||||
Abhishek Kekane <abhishek.kekane@nttdata.com>
|
||||
Adam Gandelman <adam.gandelman@canonical.com>
|
||||
Adam Gandelman <adamg@ubuntu.com>
|
||||
Alberto Planas <aplanas@gmail.com>
|
||||
Alessandro Pilotti <ap@pilotti.it>
|
||||
Alessio Ababilov <aababilo@yahoo-inc.com>
|
||||
Alessio Ababilov <aababilov@griddynamics.com>
|
||||
Alex Gaynor <alex.gaynor@gmail.com>
|
||||
Alex Meade <mr.alex.meade@gmail.com>
|
||||
Alexander Gordeev <agordeev@mirantis.com>
|
||||
Alexander Tivelkov <ativelkov@mirantis.com>
|
||||
Amala Basha <princessbasha@gmail.com>
|
||||
AmalaBasha <amala.alungal@RACKSPACE.COM>
|
||||
AmalaBasha <princessbasha@gmail.com>
|
||||
Anastasia Vlaskina <alatynskaya@mirantis.com>
|
||||
Andreas Jaeger <aj@suse.de>
|
||||
Andrew Hutchings <andrew@linuxjedi.co.uk>
|
||||
Andrew Melton <andrew.melton@rackspace.com>
|
||||
Andrew Tranquada <andrew.tranquada@rackspace.com>
|
||||
Andrey Brindeyev <abrindeyev@griddynamics.com>
|
||||
Andy McCrae <andy.mccrae@gmail.com>
|
||||
Anita Kuno <akuno@lavabit.com>
|
||||
Arnaud Legendre <arnaudleg@gmail.com>
|
||||
Artur Svechnikov <asvechnikov@mirantis.com>
|
||||
Ashish Jain <ashish.jain14@wipro.com>
|
||||
Ashwini Shukla <ashwini.shukla@rackspace.com>
|
||||
Aswad Rangnekar <aswad.rangnekar@nttdata.com>
|
||||
Attila Fazekas <afazekas@redhat.com>
|
||||
Avinash Prasad <avinash.prasad@nttdata.com>
|
||||
Balazs Gibizer <balazs.gibizer@ericsson.com>
|
||||
Bartosz Fic <bartosz.fic@intel.com>
|
||||
Ben Nemec <bnemec@us.ibm.com>
|
||||
Ben Roble <ben.roble@rackspace.com>
|
||||
Bernhard M. Wiedemann <bwiedemann@suse.de>
|
||||
Bhuvan Arumugam <bhuvan@apache.org>
|
||||
Boris Pavlovic <boris@pavlovic.me>
|
||||
Brant Knudson <bknudson@us.ibm.com>
|
||||
Brian Cline <bcline@softlayer.com>
|
||||
Brian D. Elliott <bdelliott@gmail.com>
|
||||
Brian Elliott <bdelliott@gmail.com>
|
||||
Brian Elliott <brian.elliott@rackspace.com>
|
||||
Brian Lamar <brian.lamar@rackspace.com>
|
||||
Brian Rosmaita <brian.rosmaita@rackspace.com>
|
||||
Brian Waldon <brian.waldon@rackspace.com>
|
||||
Cerberus <matt.dietz@rackspace.com>
|
||||
Chang Bo Guo <guochbo@cn.ibm.com>
|
||||
ChangBo Guo(gcb) <eric.guo@easystack.cn>
|
||||
Chmouel Boudjnah <chmouel@chmouel.com>
|
||||
Chris Allnutt <chris.allnutt@rackspace.com>
|
||||
Chris Behrens <cbehrens@codestud.com>
|
||||
Chris Buccella <buccella@linux.vnet.ibm.com>
|
||||
Chris Buccella <chris.buccella@antallagon.com>
|
||||
Chris Fattarsi <chris.fattarsi@pistoncloud.com>
|
||||
Christian Berendt <berendt@b1-systems.de>
|
||||
Christopher MacGown <chris@pistoncloud.com>
|
||||
Chuck Short <chuck.short@canonical.com>
|
||||
Cindy Pallares <cindy.pallaresq@gmail.com>
|
||||
Clark Boylan <clark.boylan@gmail.com>
|
||||
Cory Wright <corywright@gmail.com>
|
||||
Dan Prince <dprince@redhat.com>
|
||||
Danny Al-Gaaf <danny.al-gaaf@bisect.de>
|
||||
Davanum Srinivas <davanum@gmail.com>
|
||||
Davanum Srinivas <dims@linux.vnet.ibm.com>
|
||||
Dave Chen <wei.d.chen@intel.com>
|
||||
Dave Walker (Daviey) <email@daviey.com>
|
||||
David Koo <david.koo@huawei.com>
|
||||
David Peraza <dperaza@linux.vnet.ibm.com>
|
||||
David Ripton <dripton@redhat.com>
|
||||
Dean Troyer <dtroyer@gmail.com>
|
||||
DennyZhang <denny@unitedstack.com>
|
||||
Derek Higgins <derekh@redhat.com>
|
||||
Dirk Mueller <dirk@dmllr.de>
|
||||
Dmitry Kulishenko <dmitryk@yahoo-inc.com>
|
||||
Dolph Mathews <dolph.mathews@gmail.com>
|
||||
Donal Lafferty <donal.lafferty@citrix.com>
|
||||
Doron Chen <cdoron@il.ibm.com>
|
||||
Doug Hellmann <doug.hellmann@dreamhost.com>
|
||||
Doug Hellmann <doug@doughellmann.com>
|
||||
Duncan McGreggor <duncan@dreamhost.com>
|
||||
Eddie Sheffield <eddie.sheffield@rackspace.com>
|
||||
Edward Hope-Morley <edward.hope-morley@canonical.com>
|
||||
Eldar Nugaev <enugaev@griddynamics.com>
|
||||
Elena Ezhova <eezhova@mirantis.com>
|
||||
Eoghan Glynn <eglynn@redhat.com>
|
||||
Eric Brown <browne@vmware.com>
|
||||
Eric Windisch <eric@cloudscaling.com>
|
||||
Erno Kuvaja <jokke@hp.com>
|
||||
Eugeniya Kudryashova <ekudryashova@mirantis.com>
|
||||
Ewan Mellor <ewan.mellor@citrix.com>
|
||||
Fabio M. Di Nitto <fdinitto@redhat.com>
|
||||
Fei Long Wang <flwang@catalyst.net.nz>
|
||||
Fei Long Wang <flwang@cn.ibm.com>
|
||||
Fengqian Gao <fengqian.gao@intel.com>
|
||||
Flaper Fesp <flaper87@gmail.com>
|
||||
Flavio Percoco <flaper87@gmail.com>
|
||||
Florent Flament <florent.flament-ext@cloudwatt.com>
|
||||
Gabriel Hurley <gabriel@strikeawe.com>
|
||||
Gauvain Pocentek <gauvain.pocentek@objectif-libre.com>
|
||||
Geetika Batra <geetika791@gmail.com>
|
||||
George Peristerakis <george.peristerakis@enovance.com>
|
||||
Georgy Okrokvertskhov <gokrokvertskhov@mirantis.com>
|
||||
Gerardo Porras <gporras@yahoo-inc.com>
|
||||
Gorka Eguileor <geguileo@redhat.com>
|
||||
Grant Murphy <grant.murphy@hp.com>
|
||||
Haiwei Xu <xu-haiwei@mxw.nes.nec.co.jp>
|
||||
He Yongli <yongli.he@intel.com>
|
||||
Hemanth Makkapati <hemanth.makkapati@mailtrust.com>
|
||||
Hemanth Makkapati <hemanth.makkapati@rackspace.com>
|
||||
Hengqing Hu <hudayou@hotmail.com>
|
||||
Hirofumi Ichihara <ichihara.hirofumi@lab.ntt.co.jp>
|
||||
Hui Xiang <hui.xiang@canonical.com>
|
||||
Ian Cordasco <ian.cordasco@rackspace.com>
|
||||
Iccha Sethi <iccha.sethi@rackspace.com>
|
||||
Igor A. Lukyanenkov <ilukyanenkov@griddynamics.com>
|
||||
Ihar Hrachyshka <ihrachys@redhat.com>
|
||||
Ildiko Vancsa <ildiko.vancsa@ericsson.com>
|
||||
Ilya Pekelny <ipekelny@mirantis.com>
|
||||
Inessa Vasilevskaya <ivasilevskaya@mirantis.com>
|
||||
Ionuț Arțăriși <iartarisi@suse.cz>
|
||||
Isaku Yamahata <yamahata@valinux.co.jp>
|
||||
J. Daniel Schmidt <jdsn@suse.de>
|
||||
Jakub Ruzicka <jruzicka@redhat.com>
|
||||
James Carey <jecarey@us.ibm.com>
|
||||
James E. Blair <jeblair@hp.com>
|
||||
James Li <yueli.m@gmail.com>
|
||||
James Morgan <james.morgan@rackspace.com>
|
||||
James Polley <jp@jamezpolley.com>
|
||||
Jamie Lennox <jamielennox@redhat.com>
|
||||
Jared Culp <jared.culp@rackspace.com>
|
||||
Jasakov Artem <ayasakov@mirantis.com>
|
||||
Jason Koelker <jason@koelker.net>
|
||||
Jason Kölker <jason@koelker.net>
|
||||
Jay Pipes <jaypipes@gmail.com>
|
||||
Jeremy Stanley <fungi@yuggoth.org>
|
||||
Jesse Andrews <anotherjesse@gmail.com>
|
||||
Jesse J. Cook <jesse.cook@rackspace.com>
|
||||
Jia Dong <jiadong.jia@huawei.com>
|
||||
Jinwoo 'Joseph' Suh <jsuh@isi.edu>
|
||||
Joe Gordon <joe.gordon0@gmail.com>
|
||||
Joe Gordon <jogo@cloudscaling.com>
|
||||
Johannes Erdfelt <johannes.erdfelt@rackspace.com>
|
||||
John Bresnahan <jbresnah@redhat.com>
|
||||
John Lenihan <john.lenihan@hp.com>
|
||||
John Warren <jswarren@us.ibm.com>
|
||||
Jon Bernard <jobernar@redhat.com>
|
||||
Joseph Suh <jsuh@isi.edu>
|
||||
Josh Durgin <josh.durgin@dreamhost.com>
|
||||
Josh Durgin <josh.durgin@inktank.com>
|
||||
Josh Kearney <josh@jk0.org>
|
||||
Joshua Harlow <harlowja@yahoo-inc.com>
|
||||
Juan Manuel Olle <juan.m.olle@intel.com>
|
||||
Juerg Haefliger <juerg.haefliger@hp.com>
|
||||
Julia Varlamova <jvarlamova@mirantis.com>
|
||||
Julien Danjou <julien@danjou.info>
|
||||
Jun Hong Li <junhongl@cn.ibm.com>
|
||||
Justin Santa Barbara <justin@fathomdb.com>
|
||||
Justin Shepherd <jshepher@rackspace.com>
|
||||
KIYOHIRO ADACHI <adachi@mxs.nes.nec.co.jp>
|
||||
Kamil Rykowski <kamil.rykowski@intel.com>
|
||||
Kasey Alusi <kasey.alusi@gmail.com>
|
||||
Ken Pepple <ken.pepple@gmail.com>
|
||||
Ken Thomas <krt@yahoo-inc.com>
|
||||
Kent Wang <kent.wang@intel.com>
|
||||
Keshava Bharadwaj <kb.sankethi@gmail.com>
|
||||
Kevin L. Mitchell <kevin.mitchell@rackspace.com>
|
||||
Kui Shi <skuicloud@gmail.com>
|
||||
Kun Huang <gareth@unitedstack.com>
|
||||
Lakshmi N Sampath <lakshmi.sampath@hp.com>
|
||||
Lars Gellrich <lars.gellrich@hp.com>
|
||||
Leam <leam.hall@mailtrust.com>
|
||||
Leandro I. Costantino <leandro.i.costantino@intel.com>
|
||||
Liu Yuan <namei.unix@gmail.com>
|
||||
Lorin Hochstein <lorin@nimbisservices.com>
|
||||
Louis Taylor <kragniz@gmail.com>
|
||||
Louis Taylor <louis@kragniz.eu>
|
||||
Luis A. Garcia <luis@linux.vnet.ibm.com>
|
||||
Major Hayden <major@mhtx.net>
|
||||
Mark J. Washenberger <mark.washenberger@markwash.net>
|
||||
Mark J. Washenberger <mark.washenberger@rackspace.com>
|
||||
Mark McLoughlin <markmc@redhat.com>
|
||||
Mark Washenberger <mark.washenberger@rackspace.com>
|
||||
Martin Kletzander <mkletzan@redhat.com>
|
||||
Maru Newby <mnewby@internap.com>
|
||||
Masashi Ozawa <mozawa@cloudian.com>
|
||||
Matt Dietz <matt.dietz@rackspace.com>
|
||||
Matt Fischer <matt@mattfischer.com>
|
||||
Matt Riedemann <mriedem@us.ibm.com>
|
||||
Matthew Booth <mbooth@redhat.com>
|
||||
Matthew Treinish <treinish@linux.vnet.ibm.com>
|
||||
Matthias Schmitz <matthias@sigxcpu.org>
|
||||
Maurice Leeflang <maurice@leeflang.net>
|
||||
Mauro S. M. Rodrigues <maurosr@linux.vnet.ibm.com>
|
||||
Michael J Fork <mjfork@us.ibm.com>
|
||||
Michael Still <mikal@stillhq.com>
|
||||
Michal Dulko <michal.dulko@intel.com>
|
||||
Mike Fedosin <mfedosin@mirantis.com>
|
||||
Mike Lundy <mike@pistoncloud.com>
|
||||
Monty Taylor <mordred@inaugust.com>
|
||||
Nassim Babaci <nassim.babaci@cloudwatt.com>
|
||||
Nicholas Kuechler <nkuechler@gmail.com>
|
||||
Nicolas Simonds <nic@metacloud.com>
|
||||
Nikhil Komawar <nikhil.komawar@rackspace.com>
|
||||
Nikhil Komawar <nikhilskomawar@gmail.com>
|
||||
Nikolaj Starodubtsev <nstarodubtsev@mirantis.com>
|
||||
Noboru Arai <arai@mxa.nes.nec.co.jp>
|
||||
Noboru arai <arai@mxa.nes.nec.co.jp>
|
||||
Oleksii Chuprykov <ochuprykov@mirantis.com>
|
||||
Olena Logvinova <ologvinova@mirantis.com>
|
||||
Pamela-Rose Virtucio <virtu006@umn.edu>
|
||||
Patrick Mezard <patrick@mezard.eu>
|
||||
Paul Bourke <paul-david.bourke@hp.com>
|
||||
Paul Bourke <pauldbourke@gmail.com>
|
||||
Paul McMillan <paul.mcmillan@nebula.com>
|
||||
Pavan Kumar Sunkara <pavan.sss1991@gmail.com>
|
||||
Pawel Koniszewski <pawel.koniszewski@intel.com>
|
||||
Pawel Skowron <pawel.skowron@intel.com>
|
||||
Peng Yong <ppyy@pubyun.com>
|
||||
Pete Zaitcev <zaitcev@kotori.zaitcev.us>
|
||||
Pranali Deore <pranali11.deore@nttdata.com>
|
||||
PranaliDeore <pranali11.deore@nttdata.com>
|
||||
Pádraig Brady <P@draigBrady.com>
|
||||
Pádraig Brady <pbrady@redhat.com>
|
||||
Radu <mateescu@ca.ibm.com>
|
||||
Rainya Mosher <rainya.mosher@rackspace.com>
|
||||
Rajesh Tailor <rajesh.tailor@nttdata.com>
|
||||
Ray Chen <oldsharp@163.com>
|
||||
Reynolds Chin <benzwt@gmail.com>
|
||||
Rick Clark <rick@openstack.org>
|
||||
Rick Harris <rconradharris@gmail.com>
|
||||
Robert Collins <rbtcollins@hp.com>
|
||||
Rohan Kanade <rkanade@redhat.com>
|
||||
Roman Bogorodskiy <bogorodskiy@gmail.com>
|
||||
Roman Bogorodskiy <rbogorodskiy@mirantis.com>
|
||||
Roman Vasilets <rvasilets@mirantis.com>
|
||||
Rongze Zhu <zrzhit@gmail.com>
|
||||
RongzeZhu <zrzhit@gmail.com>
|
||||
Russell Bryant <rbryant@redhat.com>
|
||||
Russell Sim <russell.sim@gmail.com>
|
||||
Sabari Kumar Murugesan <smurugesan@vmware.com>
|
||||
Sam Morrison <sorrison@gmail.com>
|
||||
Sam Stavinoha <smlstvnh@gmail.com>
|
||||
Samuel Merritt <sam@swiftstack.com>
|
||||
Sascha Peilicke <saschpe@gmx.de>
|
||||
Sascha Peilicke <saschpe@suse.de>
|
||||
Sathish Nagappan <sathish.nagappan@nebula.com>
|
||||
Sean Dague <sdague@linux.vnet.ibm.com>
|
||||
Sean Dague <sean@dague.net>
|
||||
Sergey Nikitin <snikitin@mirantis.com>
|
||||
Sergey Skripnick <sskripnick@mirantis.com>
|
||||
Sergey Vilgelm <svilgelm@mirantis.com>
|
||||
Sergio Cazzolato <sergio.j.cazzolato@intel.com>
|
||||
Shane Wang <shane.wang@intel.com>
|
||||
Soren Hansen <soren.hansen@rackspace.com>
|
||||
Stan Lagun <slagun@mirantis.com>
|
||||
Steve Kowalik <steven@wedontsleep.org>
|
||||
Steve Lewis <stevelle@gmail.com>
|
||||
Stuart McLaren <stuart.mclaren@hp.com>
|
||||
Sulochan Acharya <sulochan.acharya@rackspace.co.uk>
|
||||
Svetlana Shturm <sshturm@mirantis.com>
|
||||
Taku Fukushima <tfukushima@dcl.info.waseda.ac.jp>
|
||||
Tatyana Leontovich <tleontov@yahoo-inc.com>
|
||||
Therese McHale <therese.mchale@hp.com>
|
||||
Thierry Carrez <thierry@openstack.org>
|
||||
Thomas Bechtold <tbechtold@suse.com>
|
||||
Thomas Bechtold <thomasbechtold@jpberlin.de>
|
||||
Thomas Leaman <thomas.leaman@hp.com>
|
||||
Tim Daly, Jr <timjr@yahoo-inc.com>
|
||||
Toan Nguyen <toan.nguyen@rackspace.com>
|
||||
Tom Hancock <tom.hancock@hp.com>
|
||||
Tom Leaman <thomas.leaman@hp.com>
|
||||
Tomas Hancock <tom.hancock@hp.com>
|
||||
Travis Tripp <travis.tripp@hp.com>
|
||||
Unmesh Gurjar <unmesh.gurjar@nttdata.com>
|
||||
Unmesh Gurjar <unmesh.gurjar@vertex.co.in>
|
||||
Vaibhav Bhatkar <vaibhav.bhatkar@gmail.com>
|
||||
Venkatesh Sampath <venkatesh.sampath@outlook.com>
|
||||
Venkatesh Sampath <venkatesh.sampath@rackspace.com>
|
||||
Victor Morales <victor.morales@intel.com>
|
||||
Victor Sergeyev <vsergeyev@mirantis.com>
|
||||
Vincent Untz <vuntz@suse.com>
|
||||
Vishvananda Ishaya <vishvananda@gmail.com>
|
||||
Vitaliy Kolosov <vkolosov@griddynamics.com>
|
||||
Vyacheslav Vakhlyuev <vvakhlyuev@mirantis.com>
|
||||
Wayne A. Walls <wayne.walls@rackspace.com>
|
||||
Wayne Okuma <wayne.okuma@hp.com>
|
||||
Wen Cheng Ma <wenchma@cn.ibm.com>
|
||||
Wu Wenxiang <wu.wenxiang@99cloud.net>
|
||||
YAMAMOTO Takashi <yamamoto@valinux.co.jp>
|
||||
Yaguang Tang <heut2008@gmail.com>
|
||||
Yanis Guenane <yanis.guenane@enovance.com>
|
||||
Yufang Zhang <yufang521247@gmail.com>
|
||||
Yuriy Taraday <yorik.sar@gmail.com>
|
||||
Yusuke Ide <idzzyzzbi@gmail.com>
|
||||
ZHANG Hua <zhuadl@cn.ibm.com>
|
||||
Zhenguo Niu <zhenguo@unitedstack.com>
|
||||
Zhi Yan Liu <zhiyanl@cn.ibm.com>
|
||||
ZhiQiang Fan <aji.zqfan@gmail.com>
|
||||
ZhiQiang Fan <zhiqiang.fan@huawei.com>
|
||||
Zhiteng Huang <zhiteng.huang@intel.com>
|
||||
Zhongyue Luo <zhongyue.nah@intel.com>
|
||||
abhishek-kekane <abhishek.kekane@nttdata.com>
|
||||
abhishekkekane <abhishek.kekane@nttdata.com>
|
||||
amalaba <princessbasha@gmail.com>
|
||||
ankitagrawal <ankit11.agrawal@nttdata.com>
|
||||
ankur <ankur.gupta@nectechnologies.in>
|
||||
annegentle <anne@openstack.org>
|
||||
daisy-ycguo <daisy.ycguo@gmail.com>
|
||||
eddie-sheffield <eddie.sheffield@rackspace.com>
|
||||
eos2102 <eos2102@gmail.com>
|
||||
gengjh <gengjh@cn.ibm.com>
|
||||
henriquetruta <henrique@lsd.ufcg.edu.br>
|
||||
huangtianhua <huangtianhua@huawei.com>
|
||||
hzrandd <82433422@qq.com>
|
||||
iccha <iccha.sethi@rackspace.com>
|
||||
iccha-sethi <iccha.sethi@rackspace.com>
|
||||
iccha.sethi <iccha.sethi@rackspace.com>
|
||||
isethi <iccha.sethi@rackspace.com>
|
||||
jakedahn <jake@ansolabs.com>
|
||||
jare6412 <jared.culp@mailtrust.com>
|
||||
jaypipes@gmail.com <>
|
||||
jola-mirecka <jola.mirecka@hp.com>
|
||||
lawrancejing <lawrancejing@gmail.com>
|
||||
leseb <sebastien.han@enovance.com>
|
||||
ling-yun <zengyunling@huawei.com>
|
||||
liuqing <jing.liuqing@99cloud.net>
|
||||
liyingjun <liyingjun1988@gmail.com>
|
||||
liyingjun <yingjun.li@kylin-cloud.com>
|
||||
lizheming <lizheming.li@huawei.com>
|
||||
llg8212 <lilinguo@huawei.com>
|
||||
ls1175 <liusheng@huawei.com>
|
||||
marianitadn <maria.nita.dn@gmail.com>
|
||||
mathrock <nathanael.i.burton.work@gmail.com>
|
||||
nanhai liao <nanhai.liao@kylin-cloud.com>
|
||||
pran1990 <praneshpg@gmail.com>
|
||||
ravikumar-venkatesan <ravikumar.venkatesan@hp.com>
|
||||
sai krishna sripada <krishna1256@gmail.com>
|
||||
sarvesh-ranjan <saranjan@cisco.com>
|
||||
shreeduth-awasthi <shreeduth.awasthi@tcs.com>
|
||||
shrutiranade38 <shrutiranade38@gmail.com>
|
||||
shu,xinxin <xinxin.shu@intel.com>
|
||||
sridevik <koushiksridevi8@gmail.com>
|
||||
sridevik <sridevi.koushik@rackspace.com>
|
||||
tanlin <lin.tan@intel.com>
|
||||
tmcpeak <travis_mcpeak@symantec.com>
|
||||
wanghong <w.wanghong@huawei.com>
|
||||
yangxurong <yangxurong@huawei.com>
|
@ -13,4 +13,4 @@ Pull requests submitted through GitHub will be ignored.
|
||||
|
||||
Bugs should be filed on Launchpad, not GitHub:
|
||||
|
||||
https://bugs.launchpad.net/glance
|
||||
https://bugs.launchpad.net/daisycloud-core
|
2866
code/daisy/ChangeLog
2866
code/daisy/ChangeLog
File diff suppressed because it is too large
Load Diff
@ -1,11 +1,11 @@
|
||||
glance Style Commandments
|
||||
daisycloud-core Style Commandments
|
||||
=======================
|
||||
|
||||
- Step 1: Read the OpenStack Style Commandments
|
||||
http://docs.openstack.org/developer/hacking/
|
||||
- Step 2: Read on
|
||||
|
||||
glance Specific Commandments
|
||||
daisycloud-core Specific Commandments
|
||||
--------------------------
|
||||
|
||||
- [G316] Change assertTrue(isinstance(A, B)) by optimal assert like
|
||||
|
@ -1,11 +1,9 @@
|
||||
======
|
||||
Glance
|
||||
Daisy
|
||||
======
|
||||
|
||||
Glance is a project that defines services for discovering, registering,
|
||||
retrieving and storing virtual machine images.
|
||||
Daisy(Openstack project name: daisycloud-core) provides automated deployment and
|
||||
management of OpenStack and other distributed systems.
|
||||
|
||||
Use the following resources to learn more:
|
||||
|
||||
* `Official Glance documentation <http://docs.openstack.org/developer/glance/>`_
|
||||
* `Official Client documentation <http://docs.openstack.org/developer/python-glanceclient/>`_
|
||||
## Website
|
||||
http://www.daisycloud.org
|
@ -37,7 +37,7 @@ from daisy.common import config
|
||||
from daisy.common import exception
|
||||
from daisy.common import wsgi
|
||||
from daisy import notifier
|
||||
from daisy.openstack.common import systemd
|
||||
from oslo_service import systemd
|
||||
|
||||
# Monkey patch socket, time, select, threads
|
||||
eventlet.patcher.monkey_patch(all=False, socket=True, time=True,
|
||||
|
@ -28,7 +28,7 @@ from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from daisy.common import exception
|
||||
from daisy.common import config
|
||||
from daisy.openstack.common import loopingcall
|
||||
from oslo_service import loopingcall
|
||||
from daisy.orchestration import manager
|
||||
import six
|
||||
|
||||
|
@ -34,7 +34,7 @@ from daisy.common import config
|
||||
from daisy.common import utils
|
||||
from daisy.common import wsgi
|
||||
from daisy import notifier
|
||||
from daisy.openstack.common import systemd
|
||||
from oslo_service import systemd
|
||||
|
||||
# Monkey patch socket and time
|
||||
eventlet.patcher.monkey_patch(all=False, socket=True, time=True, thread=True)
|
||||
|
@ -1,122 +0,0 @@
|
||||
# Copyright 2015 OpenStack Foundation.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
"""
|
||||
A mixin that validates the given body for jsonpatch-compatibility.
|
||||
The methods supported are limited to listed in METHODS_ALLOWED
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
import jsonschema
|
||||
|
||||
import daisy.common.exception as exc
|
||||
from daisy.openstack.common._i18n import _
|
||||
|
||||
|
||||
class JsonPatchValidatorMixin(object):
|
||||
# a list of allowed methods allowed according to RFC 6902
|
||||
ALLOWED = ["replace", "test", "remove", "add", "copy"]
|
||||
PATH_REGEX_COMPILED = re.compile("^/[^/]+(/[^/]+)*$")
|
||||
|
||||
def __init__(self, methods_allowed=["replace", "remove"]):
|
||||
self.schema = self._gen_schema(methods_allowed)
|
||||
self.methods_allowed = [m for m in methods_allowed
|
||||
if m in self.ALLOWED]
|
||||
|
||||
@staticmethod
|
||||
def _gen_schema(methods_allowed):
|
||||
"""
|
||||
Generates a jsonschema for jsonpatch request based on methods_allowed
|
||||
"""
|
||||
# op replace needs no 'value' param, so needs a special schema if
|
||||
# present in methods_allowed
|
||||
basic_schema = {
|
||||
"type": "array",
|
||||
"items": {"properties": {"op": {"type": "string",
|
||||
"enum": methods_allowed},
|
||||
"path": {"type": "string"},
|
||||
"value": {"type": ["string",
|
||||
"object",
|
||||
"integer",
|
||||
"array",
|
||||
"boolean"]}
|
||||
},
|
||||
"required": ["op", "path", "value"],
|
||||
"type": "object"},
|
||||
"$schema": "http://json-schema.org/draft-04/schema#"
|
||||
}
|
||||
if "remove" in methods_allowed:
|
||||
methods_allowed.remove("remove")
|
||||
no_remove_op_schema = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"op": {"type": "string", "enum": methods_allowed},
|
||||
"path": {"type": "string"},
|
||||
"value": {"type": ["string", "object",
|
||||
"integer", "array", "boolean"]}
|
||||
},
|
||||
"required": ["op", "path", "value"]}
|
||||
op_remove_only_schema = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"op": {"type": "string", "enum": ["remove"]},
|
||||
"path": {"type": "string"}
|
||||
},
|
||||
"required": ["op", "path"]}
|
||||
|
||||
basic_schema = {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [no_remove_op_schema, op_remove_only_schema]},
|
||||
"$schema": "http://json-schema.org/draft-04/schema#"
|
||||
}
|
||||
return basic_schema
|
||||
|
||||
def validate_body(self, body):
|
||||
try:
|
||||
jsonschema.validate(body, self.schema)
|
||||
# now make sure everything is ok with path
|
||||
return [{"path": self._decode_json_pointer(e["path"]),
|
||||
"value": e.get("value", None),
|
||||
"op": e["op"]} for e in body]
|
||||
except jsonschema.ValidationError:
|
||||
raise exc.InvalidJsonPatchBody(body=body, schema=self.schema)
|
||||
|
||||
def _check_for_path_errors(self, pointer):
|
||||
if not re.match(self.PATH_REGEX_COMPILED, pointer):
|
||||
msg = _("Json path should start with a '/', "
|
||||
"end with no '/', no 2 subsequent '/' are allowed.")
|
||||
raise exc.InvalidJsonPatchPath(path=pointer, explanation=msg)
|
||||
if re.search('~[^01]', pointer) or pointer.endswith('~'):
|
||||
msg = _("Pointer contains '~' which is not part of"
|
||||
" a recognized escape sequence [~0, ~1].")
|
||||
raise exc.InvalidJsonPatchPath(path=pointer, explanation=msg)
|
||||
|
||||
def _decode_json_pointer(self, pointer):
|
||||
"""Parses a json pointer. Returns a pointer as a string.
|
||||
|
||||
Json Pointers are defined in
|
||||
http://tools.ietf.org/html/draft-pbryan-zyp-json-pointer .
|
||||
The pointers use '/' for separation between object attributes.
|
||||
A '/' character in an attribute name is encoded as "~1" and
|
||||
a '~' character is encoded as "~0".
|
||||
"""
|
||||
self._check_for_path_errors(pointer)
|
||||
ret = []
|
||||
for part in pointer.lstrip('/').split('/'):
|
||||
ret.append(part.replace('~1', '/').replace('~0', '~').strip())
|
||||
return '/'.join(ret)
|
@ -1,16 +0,0 @@
|
||||
oslo-incubator
|
||||
--------------
|
||||
|
||||
A number of modules from oslo-incubator are imported into this project.
|
||||
You can clone the oslo-incubator repository using the following url:
|
||||
|
||||
git://git.openstack.org/openstack/oslo-incubator
|
||||
|
||||
These modules are "incubating" in oslo-incubator and are kept in sync
|
||||
with the help of oslo-incubator's update.py script. See:
|
||||
|
||||
https://wiki.openstack.org/wiki/Oslo#Syncing_Code_from_Incubator
|
||||
|
||||
The copy of the code should never be directly modified here. Please
|
||||
always update oslo-incubator first and then run the script to copy
|
||||
the changes across.
|
@ -1,45 +0,0 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""oslo.i18n integration module.
|
||||
|
||||
See http://docs.openstack.org/developer/oslo.i18n/usage.html
|
||||
|
||||
"""
|
||||
|
||||
try:
|
||||
import oslo_i18n
|
||||
|
||||
# NOTE(dhellmann): This reference to o-s-l-o will be replaced by the
|
||||
# application name when this module is synced into the separate
|
||||
# repository. It is OK to have more than one translation function
|
||||
# using the same domain, since there will still only be one message
|
||||
# catalog.
|
||||
_translators = oslo_i18n.TranslatorFactory(domain='glance')
|
||||
|
||||
# The primary translation function using the well-known name "_"
|
||||
_ = _translators.primary
|
||||
|
||||
# Translators for log levels.
|
||||
#
|
||||
# The abbreviated names are meant to reflect the usual use of a short
|
||||
# name like '_'. The "L" is for "log" and the other letter comes from
|
||||
# the level.
|
||||
_LI = _translators.log_info
|
||||
_LW = _translators.log_warning
|
||||
_LE = _translators.log_error
|
||||
_LC = _translators.log_critical
|
||||
except ImportError:
|
||||
# NOTE(dims): Support for cases where a project wants to use
|
||||
# code from oslo-incubator, but is not ready to be internationalized
|
||||
# (like tempest)
|
||||
_ = _LI = _LW = _LE = _LC = lambda x: x
|
@ -1,151 +0,0 @@
|
||||
# Copyright (c) 2012 OpenStack Foundation.
|
||||
# Administrator of the National Aeronautics and Space Administration.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import copy
|
||||
import errno
|
||||
import gc
|
||||
import logging
|
||||
import os
|
||||
import pprint
|
||||
import socket
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
import eventlet.backdoor
|
||||
import greenlet
|
||||
from oslo_config import cfg
|
||||
|
||||
from daisy.openstack.common._i18n import _LI
|
||||
|
||||
help_for_backdoor_port = (
|
||||
"Acceptable values are 0, <port>, and <start>:<end>, where 0 results "
|
||||
"in listening on a random tcp port number; <port> results in listening "
|
||||
"on the specified port number (and not enabling backdoor if that port "
|
||||
"is in use); and <start>:<end> results in listening on the smallest "
|
||||
"unused port number within the specified range of port numbers. The "
|
||||
"chosen port is displayed in the service's log file.")
|
||||
eventlet_backdoor_opts = [
|
||||
cfg.StrOpt('backdoor_port',
|
||||
help="Enable eventlet backdoor. %s" % help_for_backdoor_port)
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.register_opts(eventlet_backdoor_opts)
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def list_opts():
|
||||
"""Entry point for oslo-config-generator.
|
||||
"""
|
||||
return [(None, copy.deepcopy(eventlet_backdoor_opts))]
|
||||
|
||||
|
||||
class EventletBackdoorConfigValueError(Exception):
|
||||
def __init__(self, port_range, help_msg, ex):
|
||||
msg = ('Invalid backdoor_port configuration %(range)s: %(ex)s. '
|
||||
'%(help)s' %
|
||||
{'range': port_range, 'ex': ex, 'help': help_msg})
|
||||
super(EventletBackdoorConfigValueError, self).__init__(msg)
|
||||
self.port_range = port_range
|
||||
|
||||
|
||||
def _dont_use_this():
|
||||
print("Don't use this, just disconnect instead")
|
||||
|
||||
|
||||
def _find_objects(t):
|
||||
return [o for o in gc.get_objects() if isinstance(o, t)]
|
||||
|
||||
|
||||
def _print_greenthreads():
|
||||
for i, gt in enumerate(_find_objects(greenlet.greenlet)):
|
||||
print(i, gt)
|
||||
traceback.print_stack(gt.gr_frame)
|
||||
print()
|
||||
|
||||
|
||||
def _print_nativethreads():
|
||||
for threadId, stack in sys._current_frames().items():
|
||||
print(threadId)
|
||||
traceback.print_stack(stack)
|
||||
print()
|
||||
|
||||
|
||||
def _parse_port_range(port_range):
|
||||
if ':' not in port_range:
|
||||
start, end = port_range, port_range
|
||||
else:
|
||||
start, end = port_range.split(':', 1)
|
||||
try:
|
||||
start, end = int(start), int(end)
|
||||
if end < start:
|
||||
raise ValueError
|
||||
return start, end
|
||||
except ValueError as ex:
|
||||
raise EventletBackdoorConfigValueError(port_range, ex,
|
||||
help_for_backdoor_port)
|
||||
|
||||
|
||||
def _listen(host, start_port, end_port, listen_func):
|
||||
try_port = start_port
|
||||
while True:
|
||||
try:
|
||||
return listen_func((host, try_port))
|
||||
except socket.error as exc:
|
||||
if (exc.errno != errno.EADDRINUSE or
|
||||
try_port >= end_port):
|
||||
raise
|
||||
try_port += 1
|
||||
|
||||
|
||||
def initialize_if_enabled():
|
||||
backdoor_locals = {
|
||||
'exit': _dont_use_this, # So we don't exit the entire process
|
||||
'quit': _dont_use_this, # So we don't exit the entire process
|
||||
'fo': _find_objects,
|
||||
'pgt': _print_greenthreads,
|
||||
'pnt': _print_nativethreads,
|
||||
}
|
||||
|
||||
if CONF.backdoor_port is None:
|
||||
return None
|
||||
|
||||
start_port, end_port = _parse_port_range(str(CONF.backdoor_port))
|
||||
|
||||
# NOTE(johannes): The standard sys.displayhook will print the value of
|
||||
# the last expression and set it to __builtin__._, which overwrites
|
||||
# the __builtin__._ that gettext sets. Let's switch to using pprint
|
||||
# since it won't interact poorly with gettext, and it's easier to
|
||||
# read the output too.
|
||||
def displayhook(val):
|
||||
if val is not None:
|
||||
pprint.pprint(val)
|
||||
sys.displayhook = displayhook
|
||||
|
||||
sock = _listen('localhost', start_port, end_port, eventlet.listen)
|
||||
|
||||
# In the case of backdoor port being zero, a port number is assigned by
|
||||
# listen(). In any case, pull the port number out here.
|
||||
port = sock.getsockname()[1]
|
||||
LOG.info(
|
||||
_LI('Eventlet backdoor listening on %(port)s for process %(pid)d') %
|
||||
{'port': port, 'pid': os.getpid()}
|
||||
)
|
||||
eventlet.spawn_n(eventlet.backdoor.backdoor_server, sock,
|
||||
locals=backdoor_locals)
|
||||
return port
|
@ -1,149 +0,0 @@
|
||||
# Copyright 2011 OpenStack Foundation.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import contextlib
|
||||
import errno
|
||||
import logging
|
||||
import os
|
||||
import stat
|
||||
import tempfile
|
||||
|
||||
from oslo_utils import excutils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
_FILE_CACHE = {}
|
||||
DEFAULT_MODE = stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO
|
||||
|
||||
|
||||
def ensure_tree(path, mode=DEFAULT_MODE):
|
||||
"""Create a directory (and any ancestor directories required)
|
||||
|
||||
:param path: Directory to create
|
||||
:param mode: Directory creation permissions
|
||||
"""
|
||||
try:
|
||||
os.makedirs(path, mode)
|
||||
except OSError as exc:
|
||||
if exc.errno == errno.EEXIST:
|
||||
if not os.path.isdir(path):
|
||||
raise
|
||||
else:
|
||||
raise
|
||||
|
||||
|
||||
def read_cached_file(filename, force_reload=False):
|
||||
"""Read from a file if it has been modified.
|
||||
|
||||
:param force_reload: Whether to reload the file.
|
||||
:returns: A tuple with a boolean specifying if the data is fresh
|
||||
or not.
|
||||
"""
|
||||
global _FILE_CACHE
|
||||
|
||||
if force_reload:
|
||||
delete_cached_file(filename)
|
||||
|
||||
reloaded = False
|
||||
mtime = os.path.getmtime(filename)
|
||||
cache_info = _FILE_CACHE.setdefault(filename, {})
|
||||
|
||||
if not cache_info or mtime > cache_info.get('mtime', 0):
|
||||
LOG.debug("Reloading cached file %s" % filename)
|
||||
with open(filename) as fap:
|
||||
cache_info['data'] = fap.read()
|
||||
cache_info['mtime'] = mtime
|
||||
reloaded = True
|
||||
return (reloaded, cache_info['data'])
|
||||
|
||||
|
||||
def delete_cached_file(filename):
|
||||
"""Delete cached file if present.
|
||||
|
||||
:param filename: filename to delete
|
||||
"""
|
||||
global _FILE_CACHE
|
||||
|
||||
if filename in _FILE_CACHE:
|
||||
del _FILE_CACHE[filename]
|
||||
|
||||
|
||||
def delete_if_exists(path, remove=os.unlink):
|
||||
"""Delete a file, but ignore file not found error.
|
||||
|
||||
:param path: File to delete
|
||||
:param remove: Optional function to remove passed path
|
||||
"""
|
||||
|
||||
try:
|
||||
remove(path)
|
||||
except OSError as e:
|
||||
if e.errno != errno.ENOENT:
|
||||
raise
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def remove_path_on_error(path, remove=delete_if_exists):
|
||||
"""Protect code that wants to operate on PATH atomically.
|
||||
Any exception will cause PATH to be removed.
|
||||
|
||||
:param path: File to work with
|
||||
:param remove: Optional function to remove passed path
|
||||
"""
|
||||
|
||||
try:
|
||||
yield
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
remove(path)
|
||||
|
||||
|
||||
def file_open(*args, **kwargs):
|
||||
"""Open file
|
||||
|
||||
see built-in open() documentation for more details
|
||||
|
||||
Note: The reason this is kept in a separate module is to easily
|
||||
be able to provide a stub module that doesn't alter system
|
||||
state at all (for unit tests)
|
||||
"""
|
||||
return open(*args, **kwargs)
|
||||
|
||||
|
||||
def write_to_tempfile(content, path=None, suffix='', prefix='tmp'):
|
||||
"""Create temporary file or use existing file.
|
||||
|
||||
This util is needed for creating temporary file with
|
||||
specified content, suffix and prefix. If path is not None,
|
||||
it will be used for writing content. If the path doesn't
|
||||
exist it'll be created.
|
||||
|
||||
:param content: content for temporary file.
|
||||
:param path: same as parameter 'dir' for mkstemp
|
||||
:param suffix: same as parameter 'suffix' for mkstemp
|
||||
:param prefix: same as parameter 'prefix' for mkstemp
|
||||
|
||||
For example: it can be used in database tests for creating
|
||||
configuration files.
|
||||
"""
|
||||
if path:
|
||||
ensure_tree(path)
|
||||
|
||||
(fd, path) = tempfile.mkstemp(suffix=suffix, dir=path, prefix=prefix)
|
||||
try:
|
||||
os.write(fd, content)
|
||||
finally:
|
||||
os.close(fd)
|
||||
return path
|
@ -1,45 +0,0 @@
|
||||
# Copyright 2011 OpenStack Foundation.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Local storage of variables using weak references"""
|
||||
|
||||
import threading
|
||||
import weakref
|
||||
|
||||
|
||||
class WeakLocal(threading.local):
|
||||
def __getattribute__(self, attr):
|
||||
rval = super(WeakLocal, self).__getattribute__(attr)
|
||||
if rval:
|
||||
# NOTE(mikal): this bit is confusing. What is stored is a weak
|
||||
# reference, not the value itself. We therefore need to lookup
|
||||
# the weak reference and return the inner value here.
|
||||
rval = rval()
|
||||
return rval
|
||||
|
||||
def __setattr__(self, attr, value):
|
||||
value = weakref.ref(value)
|
||||
return super(WeakLocal, self).__setattr__(attr, value)
|
||||
|
||||
|
||||
# NOTE(mikal): the name "store" should be deprecated in the future
|
||||
store = WeakLocal()
|
||||
|
||||
# A "weak" store uses weak references and allows an object to fall out of scope
|
||||
# when it falls out of scope in the code that uses the thread local storage. A
|
||||
# "strong" store will hold a reference to the object so that it never falls out
|
||||
# of scope.
|
||||
weak_store = WeakLocal()
|
||||
strong_store = threading.local()
|
@ -1,147 +0,0 @@
|
||||
# Copyright 2010 United States Government as represented by the
|
||||
# Administrator of the National Aeronautics and Space Administration.
|
||||
# Copyright 2011 Justin Santa Barbara
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import logging
|
||||
import sys
|
||||
import time
|
||||
|
||||
from eventlet import event
|
||||
from eventlet import greenthread
|
||||
|
||||
from daisy.openstack.common._i18n import _LE, _LW
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
# NOTE(zyluo): This lambda function was declared to avoid mocking collisions
|
||||
# with time.time() called in the standard logging module
|
||||
# during unittests.
|
||||
_ts = lambda: time.time()
|
||||
|
||||
|
||||
class LoopingCallDone(Exception):
|
||||
"""Exception to break out and stop a LoopingCallBase.
|
||||
|
||||
The poll-function passed to LoopingCallBase can raise this exception to
|
||||
break out of the loop normally. This is somewhat analogous to
|
||||
StopIteration.
|
||||
|
||||
An optional return-value can be included as the argument to the exception;
|
||||
this return-value will be returned by LoopingCallBase.wait()
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, retvalue=True):
|
||||
""":param retvalue: Value that LoopingCallBase.wait() should return."""
|
||||
self.retvalue = retvalue
|
||||
|
||||
|
||||
class LoopingCallBase(object):
|
||||
def __init__(self, f=None, *args, **kw):
|
||||
self.args = args
|
||||
self.kw = kw
|
||||
self.f = f
|
||||
self._running = False
|
||||
self.done = None
|
||||
|
||||
def stop(self):
|
||||
self._running = False
|
||||
|
||||
def wait(self):
|
||||
return self.done.wait()
|
||||
|
||||
|
||||
class FixedIntervalLoopingCall(LoopingCallBase):
|
||||
"""A fixed interval looping call."""
|
||||
|
||||
def start(self, interval, initial_delay=None):
|
||||
self._running = True
|
||||
done = event.Event()
|
||||
|
||||
def _inner():
|
||||
if initial_delay:
|
||||
greenthread.sleep(initial_delay)
|
||||
|
||||
try:
|
||||
while self._running:
|
||||
start = _ts()
|
||||
self.f(*self.args, **self.kw)
|
||||
end = _ts()
|
||||
if not self._running:
|
||||
break
|
||||
delay = end - start - interval
|
||||
if delay > 0:
|
||||
LOG.warn(_LW('task %(func_name)r run outlasted '
|
||||
'interval by %(delay).2f sec'),
|
||||
{'func_name': self.f, 'delay': delay})
|
||||
greenthread.sleep(-delay if delay < 0 else 0)
|
||||
except LoopingCallDone as e:
|
||||
self.stop()
|
||||
done.send(e.retvalue)
|
||||
except Exception:
|
||||
LOG.exception(_LE('in fixed duration looping call'))
|
||||
done.send_exception(*sys.exc_info())
|
||||
return
|
||||
else:
|
||||
done.send(True)
|
||||
|
||||
self.done = done
|
||||
|
||||
greenthread.spawn_n(_inner)
|
||||
return self.done
|
||||
|
||||
|
||||
class DynamicLoopingCall(LoopingCallBase):
|
||||
"""A looping call which sleeps until the next known event.
|
||||
|
||||
The function called should return how long to sleep for before being
|
||||
called again.
|
||||
"""
|
||||
|
||||
def start(self, initial_delay=None, periodic_interval_max=None):
|
||||
self._running = True
|
||||
done = event.Event()
|
||||
|
||||
def _inner():
|
||||
if initial_delay:
|
||||
greenthread.sleep(initial_delay)
|
||||
|
||||
try:
|
||||
while self._running:
|
||||
idle = self.f(*self.args, **self.kw)
|
||||
if not self._running:
|
||||
break
|
||||
|
||||
if periodic_interval_max is not None:
|
||||
idle = min(idle, periodic_interval_max)
|
||||
LOG.debug('Dynamic looping call %(func_name)r sleeping '
|
||||
'for %(idle).02f seconds',
|
||||
{'func_name': self.f, 'idle': idle})
|
||||
greenthread.sleep(idle)
|
||||
except LoopingCallDone as e:
|
||||
self.stop()
|
||||
done.send(e.retvalue)
|
||||
except Exception:
|
||||
LOG.exception(_LE('in dynamic looping call'))
|
||||
done.send_exception(*sys.exc_info())
|
||||
return
|
||||
else:
|
||||
done.send(True)
|
||||
|
||||
self.done = done
|
||||
|
||||
greenthread.spawn(_inner)
|
||||
return self.done
|
@ -1,495 +0,0 @@
|
||||
# Copyright 2010 United States Government as represented by the
|
||||
# Administrator of the National Aeronautics and Space Administration.
|
||||
# Copyright 2011 Justin Santa Barbara
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Generic Node base class for all workers that run on hosts."""
|
||||
|
||||
import errno
|
||||
import logging
|
||||
import os
|
||||
import random
|
||||
import signal
|
||||
import sys
|
||||
import time
|
||||
|
||||
try:
|
||||
# Importing just the symbol here because the io module does not
|
||||
# exist in Python 2.6.
|
||||
from io import UnsupportedOperation # noqa
|
||||
except ImportError:
|
||||
# Python 2.6
|
||||
UnsupportedOperation = None
|
||||
|
||||
import eventlet
|
||||
from eventlet import event
|
||||
from oslo_config import cfg
|
||||
|
||||
from daisy.openstack.common import eventlet_backdoor
|
||||
from daisy.openstack.common._i18n import _LE, _LI, _LW
|
||||
from daisy.openstack.common import systemd
|
||||
from daisy.openstack.common import threadgroup
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _sighup_supported():
|
||||
return hasattr(signal, 'SIGHUP')
|
||||
|
||||
|
||||
def _is_daemon():
|
||||
# The process group for a foreground process will match the
|
||||
# process group of the controlling terminal. If those values do
|
||||
# not match, or ioctl() fails on the stdout file handle, we assume
|
||||
# the process is running in the background as a daemon.
|
||||
# http://www.gnu.org/software/bash/manual/bashref.html#Job-Control-Basics
|
||||
try:
|
||||
is_daemon = os.getpgrp() != os.tcgetpgrp(sys.stdout.fileno())
|
||||
except OSError as err:
|
||||
if err.errno == errno.ENOTTY:
|
||||
# Assume we are a daemon because there is no terminal.
|
||||
is_daemon = True
|
||||
else:
|
||||
raise
|
||||
except UnsupportedOperation:
|
||||
# Could not get the fileno for stdout, so we must be a daemon.
|
||||
is_daemon = True
|
||||
return is_daemon
|
||||
|
||||
|
||||
def _is_sighup_and_daemon(signo):
|
||||
if not (_sighup_supported() and signo == signal.SIGHUP):
|
||||
# Avoid checking if we are a daemon, because the signal isn't
|
||||
# SIGHUP.
|
||||
return False
|
||||
return _is_daemon()
|
||||
|
||||
|
||||
def _signo_to_signame(signo):
|
||||
signals = {signal.SIGTERM: 'SIGTERM',
|
||||
signal.SIGINT: 'SIGINT'}
|
||||
if _sighup_supported():
|
||||
signals[signal.SIGHUP] = 'SIGHUP'
|
||||
return signals[signo]
|
||||
|
||||
|
||||
def _set_signals_handler(handler):
|
||||
signal.signal(signal.SIGTERM, handler)
|
||||
signal.signal(signal.SIGINT, handler)
|
||||
if _sighup_supported():
|
||||
signal.signal(signal.SIGHUP, handler)
|
||||
|
||||
|
||||
class Launcher(object):
|
||||
"""Launch one or more services and wait for them to complete."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize the service launcher.
|
||||
|
||||
:returns: None
|
||||
|
||||
"""
|
||||
self.services = Services()
|
||||
self.backdoor_port = eventlet_backdoor.initialize_if_enabled()
|
||||
|
||||
def launch_service(self, service):
|
||||
"""Load and start the given service.
|
||||
|
||||
:param service: The service you would like to start.
|
||||
:returns: None
|
||||
|
||||
"""
|
||||
service.backdoor_port = self.backdoor_port
|
||||
self.services.add(service)
|
||||
|
||||
def stop(self):
|
||||
"""Stop all services which are currently running.
|
||||
|
||||
:returns: None
|
||||
|
||||
"""
|
||||
self.services.stop()
|
||||
|
||||
def wait(self):
|
||||
"""Waits until all services have been stopped, and then returns.
|
||||
|
||||
:returns: None
|
||||
|
||||
"""
|
||||
self.services.wait()
|
||||
|
||||
def restart(self):
|
||||
"""Reload config files and restart service.
|
||||
|
||||
:returns: None
|
||||
|
||||
"""
|
||||
cfg.CONF.reload_config_files()
|
||||
self.services.restart()
|
||||
|
||||
|
||||
class SignalExit(SystemExit):
|
||||
def __init__(self, signo, exccode=1):
|
||||
super(SignalExit, self).__init__(exccode)
|
||||
self.signo = signo
|
||||
|
||||
|
||||
class ServiceLauncher(Launcher):
|
||||
def _handle_signal(self, signo, frame):
|
||||
# Allow the process to be killed again and die from natural causes
|
||||
_set_signals_handler(signal.SIG_DFL)
|
||||
raise SignalExit(signo)
|
||||
|
||||
def handle_signal(self):
|
||||
_set_signals_handler(self._handle_signal)
|
||||
|
||||
def _wait_for_exit_or_signal(self, ready_callback=None):
|
||||
status = None
|
||||
signo = 0
|
||||
|
||||
LOG.debug('Full set of CONF:')
|
||||
CONF.log_opt_values(LOG, logging.DEBUG)
|
||||
|
||||
try:
|
||||
if ready_callback:
|
||||
ready_callback()
|
||||
super(ServiceLauncher, self).wait()
|
||||
except SignalExit as exc:
|
||||
signame = _signo_to_signame(exc.signo)
|
||||
LOG.info(_LI('Caught %s, exiting'), signame)
|
||||
status = exc.code
|
||||
signo = exc.signo
|
||||
except SystemExit as exc:
|
||||
status = exc.code
|
||||
finally:
|
||||
self.stop()
|
||||
|
||||
return status, signo
|
||||
|
||||
def wait(self, ready_callback=None):
|
||||
systemd.notify_once()
|
||||
while True:
|
||||
self.handle_signal()
|
||||
status, signo = self._wait_for_exit_or_signal(ready_callback)
|
||||
if not _is_sighup_and_daemon(signo):
|
||||
return status
|
||||
self.restart()
|
||||
|
||||
|
||||
class ServiceWrapper(object):
|
||||
def __init__(self, service, workers):
|
||||
self.service = service
|
||||
self.workers = workers
|
||||
self.children = set()
|
||||
self.forktimes = []
|
||||
|
||||
|
||||
class ProcessLauncher(object):
|
||||
def __init__(self):
|
||||
"""Constructor."""
|
||||
|
||||
self.children = {}
|
||||
self.sigcaught = None
|
||||
self.running = True
|
||||
rfd, self.writepipe = os.pipe()
|
||||
self.readpipe = eventlet.greenio.GreenPipe(rfd, 'r')
|
||||
self.handle_signal()
|
||||
|
||||
def handle_signal(self):
|
||||
_set_signals_handler(self._handle_signal)
|
||||
|
||||
def _handle_signal(self, signo, frame):
|
||||
self.sigcaught = signo
|
||||
self.running = False
|
||||
|
||||
# Allow the process to be killed again and die from natural causes
|
||||
_set_signals_handler(signal.SIG_DFL)
|
||||
|
||||
def _pipe_watcher(self):
|
||||
# This will block until the write end is closed when the parent
|
||||
# dies unexpectedly
|
||||
self.readpipe.read()
|
||||
|
||||
LOG.info(_LI('Parent process has died unexpectedly, exiting'))
|
||||
|
||||
sys.exit(1)
|
||||
|
||||
def _child_process_handle_signal(self):
|
||||
# Setup child signal handlers differently
|
||||
def _sigterm(*args):
|
||||
signal.signal(signal.SIGTERM, signal.SIG_DFL)
|
||||
raise SignalExit(signal.SIGTERM)
|
||||
|
||||
def _sighup(*args):
|
||||
signal.signal(signal.SIGHUP, signal.SIG_DFL)
|
||||
raise SignalExit(signal.SIGHUP)
|
||||
|
||||
signal.signal(signal.SIGTERM, _sigterm)
|
||||
if _sighup_supported():
|
||||
signal.signal(signal.SIGHUP, _sighup)
|
||||
# Block SIGINT and let the parent send us a SIGTERM
|
||||
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
||||
|
||||
def _child_wait_for_exit_or_signal(self, launcher):
|
||||
status = 0
|
||||
signo = 0
|
||||
|
||||
# NOTE(johannes): All exceptions are caught to ensure this
|
||||
# doesn't fallback into the loop spawning children. It would
|
||||
# be bad for a child to spawn more children.
|
||||
try:
|
||||
launcher.wait()
|
||||
except SignalExit as exc:
|
||||
signame = _signo_to_signame(exc.signo)
|
||||
LOG.info(_LI('Child caught %s, exiting'), signame)
|
||||
status = exc.code
|
||||
signo = exc.signo
|
||||
except SystemExit as exc:
|
||||
status = exc.code
|
||||
except BaseException:
|
||||
LOG.exception(_LE('Unhandled exception'))
|
||||
status = 2
|
||||
finally:
|
||||
launcher.stop()
|
||||
|
||||
return status, signo
|
||||
|
||||
def _child_process(self, service):
|
||||
self._child_process_handle_signal()
|
||||
|
||||
# Reopen the eventlet hub to make sure we don't share an epoll
|
||||
# fd with parent and/or siblings, which would be bad
|
||||
eventlet.hubs.use_hub()
|
||||
|
||||
# Close write to ensure only parent has it open
|
||||
os.close(self.writepipe)
|
||||
# Create greenthread to watch for parent to close pipe
|
||||
eventlet.spawn_n(self._pipe_watcher)
|
||||
|
||||
# Reseed random number generator
|
||||
random.seed()
|
||||
|
||||
launcher = Launcher()
|
||||
launcher.launch_service(service)
|
||||
return launcher
|
||||
|
||||
def _start_child(self, wrap):
|
||||
if len(wrap.forktimes) > wrap.workers:
|
||||
# Limit ourselves to one process a second (over the period of
|
||||
# number of workers * 1 second). This will allow workers to
|
||||
# start up quickly but ensure we don't fork off children that
|
||||
# die instantly too quickly.
|
||||
if time.time() - wrap.forktimes[0] < wrap.workers:
|
||||
LOG.info(_LI('Forking too fast, sleeping'))
|
||||
time.sleep(1)
|
||||
|
||||
wrap.forktimes.pop(0)
|
||||
|
||||
wrap.forktimes.append(time.time())
|
||||
|
||||
pid = os.fork()
|
||||
if pid == 0:
|
||||
launcher = self._child_process(wrap.service)
|
||||
while True:
|
||||
self._child_process_handle_signal()
|
||||
status, signo = self._child_wait_for_exit_or_signal(launcher)
|
||||
if not _is_sighup_and_daemon(signo):
|
||||
break
|
||||
launcher.restart()
|
||||
|
||||
os._exit(status)
|
||||
|
||||
LOG.info(_LI('Started child %d'), pid)
|
||||
|
||||
wrap.children.add(pid)
|
||||
self.children[pid] = wrap
|
||||
|
||||
return pid
|
||||
|
||||
def launch_service(self, service, workers=1):
|
||||
wrap = ServiceWrapper(service, workers)
|
||||
|
||||
LOG.info(_LI('Starting %d workers'), wrap.workers)
|
||||
while self.running and len(wrap.children) < wrap.workers:
|
||||
self._start_child(wrap)
|
||||
|
||||
def _wait_child(self):
|
||||
try:
|
||||
# Block while any of child processes have exited
|
||||
pid, status = os.waitpid(0, 0)
|
||||
if not pid:
|
||||
return None
|
||||
except OSError as exc:
|
||||
if exc.errno not in (errno.EINTR, errno.ECHILD):
|
||||
raise
|
||||
return None
|
||||
|
||||
if os.WIFSIGNALED(status):
|
||||
sig = os.WTERMSIG(status)
|
||||
LOG.info(_LI('Child %(pid)d killed by signal %(sig)d'),
|
||||
dict(pid=pid, sig=sig))
|
||||
else:
|
||||
code = os.WEXITSTATUS(status)
|
||||
LOG.info(_LI('Child %(pid)s exited with status %(code)d'),
|
||||
dict(pid=pid, code=code))
|
||||
|
||||
if pid not in self.children:
|
||||
LOG.warning(_LW('pid %d not in child list'), pid)
|
||||
return None
|
||||
|
||||
wrap = self.children.pop(pid)
|
||||
wrap.children.remove(pid)
|
||||
return wrap
|
||||
|
||||
def _respawn_children(self):
|
||||
while self.running:
|
||||
wrap = self._wait_child()
|
||||
if not wrap:
|
||||
continue
|
||||
while self.running and len(wrap.children) < wrap.workers:
|
||||
self._start_child(wrap)
|
||||
|
||||
def wait(self):
|
||||
"""Loop waiting on children to die and respawning as necessary."""
|
||||
|
||||
systemd.notify_once()
|
||||
LOG.debug('Full set of CONF:')
|
||||
CONF.log_opt_values(LOG, logging.DEBUG)
|
||||
|
||||
try:
|
||||
while True:
|
||||
self.handle_signal()
|
||||
self._respawn_children()
|
||||
# No signal means that stop was called. Don't clean up here.
|
||||
if not self.sigcaught:
|
||||
return
|
||||
|
||||
signame = _signo_to_signame(self.sigcaught)
|
||||
LOG.info(_LI('Caught %s, stopping children'), signame)
|
||||
if not _is_sighup_and_daemon(self.sigcaught):
|
||||
break
|
||||
|
||||
for pid in self.children:
|
||||
os.kill(pid, signal.SIGHUP)
|
||||
self.running = True
|
||||
self.sigcaught = None
|
||||
except eventlet.greenlet.GreenletExit:
|
||||
LOG.info(_LI("Wait called after thread killed. Cleaning up."))
|
||||
|
||||
self.stop()
|
||||
|
||||
def stop(self):
|
||||
"""Terminate child processes and wait on each."""
|
||||
self.running = False
|
||||
for pid in self.children:
|
||||
try:
|
||||
os.kill(pid, signal.SIGTERM)
|
||||
except OSError as exc:
|
||||
if exc.errno != errno.ESRCH:
|
||||
raise
|
||||
|
||||
# Wait for children to die
|
||||
if self.children:
|
||||
LOG.info(_LI('Waiting on %d children to exit'), len(self.children))
|
||||
while self.children:
|
||||
self._wait_child()
|
||||
|
||||
|
||||
class Service(object):
|
||||
"""Service object for binaries running on hosts."""
|
||||
|
||||
def __init__(self, threads=1000):
|
||||
self.tg = threadgroup.ThreadGroup(threads)
|
||||
|
||||
# signal that the service is done shutting itself down:
|
||||
self._done = event.Event()
|
||||
|
||||
def reset(self):
|
||||
# NOTE(Fengqian): docs for Event.reset() recommend against using it
|
||||
self._done = event.Event()
|
||||
|
||||
def start(self):
|
||||
pass
|
||||
|
||||
def stop(self, graceful=False):
|
||||
self.tg.stop(graceful)
|
||||
self.tg.wait()
|
||||
# Signal that service cleanup is done:
|
||||
if not self._done.ready():
|
||||
self._done.send()
|
||||
|
||||
def wait(self):
|
||||
self._done.wait()
|
||||
|
||||
|
||||
class Services(object):
|
||||
|
||||
def __init__(self):
|
||||
self.services = []
|
||||
self.tg = threadgroup.ThreadGroup()
|
||||
self.done = event.Event()
|
||||
|
||||
def add(self, service):
|
||||
self.services.append(service)
|
||||
self.tg.add_thread(self.run_service, service, self.done)
|
||||
|
||||
def stop(self):
|
||||
# wait for graceful shutdown of services:
|
||||
for service in self.services:
|
||||
service.stop()
|
||||
service.wait()
|
||||
|
||||
# Each service has performed cleanup, now signal that the run_service
|
||||
# wrapper threads can now die:
|
||||
if not self.done.ready():
|
||||
self.done.send()
|
||||
|
||||
# reap threads:
|
||||
self.tg.stop()
|
||||
|
||||
def wait(self):
|
||||
self.tg.wait()
|
||||
|
||||
def restart(self):
|
||||
self.stop()
|
||||
self.done = event.Event()
|
||||
for restart_service in self.services:
|
||||
restart_service.reset()
|
||||
self.tg.add_thread(self.run_service, restart_service, self.done)
|
||||
|
||||
@staticmethod
|
||||
def run_service(service, done):
|
||||
"""Service start wrapper.
|
||||
|
||||
:param service: service to run
|
||||
:param done: event to wait on until a shutdown is triggered
|
||||
:returns: None
|
||||
|
||||
"""
|
||||
service.start()
|
||||
done.wait()
|
||||
|
||||
|
||||
def launch(service, workers=1):
|
||||
if workers is None or workers == 1:
|
||||
launcher = ServiceLauncher()
|
||||
launcher.launch_service(service)
|
||||
else:
|
||||
launcher = ProcessLauncher()
|
||||
launcher.launch_service(service, workers=workers)
|
||||
|
||||
return launcher
|
@ -1,105 +0,0 @@
|
||||
# Copyright 2012-2014 Red Hat, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""
|
||||
Helper module for systemd service readiness notification.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import socket
|
||||
import sys
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _abstractify(socket_name):
|
||||
if socket_name.startswith('@'):
|
||||
# abstract namespace socket
|
||||
socket_name = '\0%s' % socket_name[1:]
|
||||
return socket_name
|
||||
|
||||
|
||||
def _sd_notify(unset_env, msg):
|
||||
notify_socket = os.getenv('NOTIFY_SOCKET')
|
||||
if notify_socket:
|
||||
sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
|
||||
try:
|
||||
sock.connect(_abstractify(notify_socket))
|
||||
sock.sendall(msg)
|
||||
if unset_env:
|
||||
del os.environ['NOTIFY_SOCKET']
|
||||
except EnvironmentError:
|
||||
LOG.debug("Systemd notification failed", exc_info=True)
|
||||
finally:
|
||||
sock.close()
|
||||
|
||||
|
||||
def notify():
|
||||
"""Send notification to Systemd that service is ready.
|
||||
|
||||
For details see
|
||||
http://www.freedesktop.org/software/systemd/man/sd_notify.html
|
||||
"""
|
||||
_sd_notify(False, 'READY=1')
|
||||
|
||||
|
||||
def notify_once():
|
||||
"""Send notification once to Systemd that service is ready.
|
||||
|
||||
Systemd sets NOTIFY_SOCKET environment variable with the name of the
|
||||
socket listening for notifications from services.
|
||||
This method removes the NOTIFY_SOCKET environment variable to ensure
|
||||
notification is sent only once.
|
||||
"""
|
||||
_sd_notify(True, 'READY=1')
|
||||
|
||||
|
||||
def onready(notify_socket, timeout):
|
||||
"""Wait for systemd style notification on the socket.
|
||||
|
||||
:param notify_socket: local socket address
|
||||
:type notify_socket: string
|
||||
:param timeout: socket timeout
|
||||
:type timeout: float
|
||||
:returns: 0 service ready
|
||||
1 service not ready
|
||||
2 timeout occurred
|
||||
"""
|
||||
sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
|
||||
sock.settimeout(timeout)
|
||||
sock.bind(_abstractify(notify_socket))
|
||||
try:
|
||||
msg = sock.recv(512)
|
||||
except socket.timeout:
|
||||
return 2
|
||||
finally:
|
||||
sock.close()
|
||||
if 'READY=1' in msg:
|
||||
return 0
|
||||
else:
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# simple CLI for testing
|
||||
if len(sys.argv) == 1:
|
||||
notify()
|
||||
elif len(sys.argv) >= 2:
|
||||
timeout = float(sys.argv[1])
|
||||
notify_socket = os.getenv('NOTIFY_SOCKET')
|
||||
if notify_socket:
|
||||
retval = onready(notify_socket, timeout)
|
||||
sys.exit(retval)
|
@ -1,149 +0,0 @@
|
||||
# Copyright 2012 Red Hat, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import logging
|
||||
import threading
|
||||
|
||||
import eventlet
|
||||
from eventlet import greenpool
|
||||
|
||||
from daisy.openstack.common import loopingcall
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _thread_done(gt, *args, **kwargs):
|
||||
"""Callback function to be passed to GreenThread.link() when we spawn()
|
||||
Calls the :class:`ThreadGroup` to notify if.
|
||||
|
||||
"""
|
||||
kwargs['group'].thread_done(kwargs['thread'])
|
||||
|
||||
|
||||
class Thread(object):
|
||||
"""Wrapper around a greenthread, that holds a reference to the
|
||||
:class:`ThreadGroup`. The Thread will notify the :class:`ThreadGroup` when
|
||||
it has done so it can be removed from the threads list.
|
||||
"""
|
||||
def __init__(self, thread, group):
|
||||
self.thread = thread
|
||||
self.thread.link(_thread_done, group=group, thread=self)
|
||||
|
||||
def stop(self):
|
||||
self.thread.kill()
|
||||
|
||||
def wait(self):
|
||||
return self.thread.wait()
|
||||
|
||||
def link(self, func, *args, **kwargs):
|
||||
self.thread.link(func, *args, **kwargs)
|
||||
|
||||
|
||||
class ThreadGroup(object):
|
||||
"""The point of the ThreadGroup class is to:
|
||||
|
||||
* keep track of timers and greenthreads (making it easier to stop them
|
||||
when need be).
|
||||
* provide an easy API to add timers.
|
||||
"""
|
||||
def __init__(self, thread_pool_size=10):
|
||||
self.pool = greenpool.GreenPool(thread_pool_size)
|
||||
self.threads = []
|
||||
self.timers = []
|
||||
|
||||
def add_dynamic_timer(self, callback, initial_delay=None,
|
||||
periodic_interval_max=None, *args, **kwargs):
|
||||
timer = loopingcall.DynamicLoopingCall(callback, *args, **kwargs)
|
||||
timer.start(initial_delay=initial_delay,
|
||||
periodic_interval_max=periodic_interval_max)
|
||||
self.timers.append(timer)
|
||||
|
||||
def add_timer(self, interval, callback, initial_delay=None,
|
||||
*args, **kwargs):
|
||||
pulse = loopingcall.FixedIntervalLoopingCall(callback, *args, **kwargs)
|
||||
pulse.start(interval=interval,
|
||||
initial_delay=initial_delay)
|
||||
self.timers.append(pulse)
|
||||
|
||||
def add_thread(self, callback, *args, **kwargs):
|
||||
gt = self.pool.spawn(callback, *args, **kwargs)
|
||||
th = Thread(gt, self)
|
||||
self.threads.append(th)
|
||||
return th
|
||||
|
||||
def thread_done(self, thread):
|
||||
self.threads.remove(thread)
|
||||
|
||||
def _stop_threads(self):
|
||||
current = threading.current_thread()
|
||||
|
||||
# Iterate over a copy of self.threads so thread_done doesn't
|
||||
# modify the list while we're iterating
|
||||
for x in self.threads[:]:
|
||||
if x is current:
|
||||
# don't kill the current thread.
|
||||
continue
|
||||
try:
|
||||
x.stop()
|
||||
except eventlet.greenlet.GreenletExit:
|
||||
pass
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
|
||||
def stop_timers(self):
|
||||
for x in self.timers:
|
||||
try:
|
||||
x.stop()
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
self.timers = []
|
||||
|
||||
def stop(self, graceful=False):
|
||||
"""stop function has the option of graceful=True/False.
|
||||
|
||||
* In case of graceful=True, wait for all threads to be finished.
|
||||
Never kill threads.
|
||||
* In case of graceful=False, kill threads immediately.
|
||||
"""
|
||||
self.stop_timers()
|
||||
if graceful:
|
||||
# In case of graceful=True, wait for all threads to be
|
||||
# finished, never kill threads
|
||||
self.wait()
|
||||
else:
|
||||
# In case of graceful=False(Default), kill threads
|
||||
# immediately
|
||||
self._stop_threads()
|
||||
|
||||
def wait(self):
|
||||
for x in self.timers:
|
||||
try:
|
||||
x.wait()
|
||||
except eventlet.greenlet.GreenletExit:
|
||||
pass
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
current = threading.current_thread()
|
||||
|
||||
# Iterate over a copy of self.threads so thread_done doesn't
|
||||
# modify the list while we're iterating
|
||||
for x in self.threads[:]:
|
||||
if x is current:
|
||||
continue
|
||||
try:
|
||||
x.wait()
|
||||
except eventlet.greenlet.GreenletExit:
|
||||
pass
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
@ -1,8 +0,0 @@
|
||||
[DEFAULT]
|
||||
|
||||
# The list of modules to copy from oslo-incubator
|
||||
module=install_venv_common
|
||||
module=service
|
||||
|
||||
# The base module to hold the copy of openstack.common
|
||||
base=daisy
|
@ -1,30 +0,0 @@
|
||||
Rally job related files
|
||||
=======================
|
||||
|
||||
This directory contains rally tasks and plugins that are run by OpenStack CI.
|
||||
|
||||
Structure
|
||||
---------
|
||||
|
||||
* plugins - directory where you can add rally plugins. Almost everything in
|
||||
Rally is a plugin. Benchmark context, Benchmark scenario, SLA checks, Generic
|
||||
cleanup resources, ....
|
||||
|
||||
* extra - all files from this directory will be copy pasted to gates, so you
|
||||
are able to use absolute paths in rally tasks.
|
||||
Files will be located in ~/.rally/extra/*
|
||||
|
||||
* glance.yaml is a task that is run in gates against OpenStack (nova network)
|
||||
deployed by DevStack
|
||||
|
||||
|
||||
Useful links
|
||||
------------
|
||||
|
||||
* More about Rally: https://rally.readthedocs.org/en/latest/
|
||||
|
||||
* How to add rally-gates: https://rally.readthedocs.org/en/latest/rally_gatejob.html
|
||||
|
||||
* About plugins: https://rally.readthedocs.org/en/latest/plugins.html
|
||||
|
||||
* Plugin samples: https://github.com/stackforge/rally/tree/master/doc/samples/plugins
|
@ -1,5 +0,0 @@
|
||||
Extra files
|
||||
===========
|
||||
|
||||
All files from this directory will be copy pasted to gates, so you are able to
|
||||
use absolute path in rally tasks. Files will be in ~/.rally/extra/*
|
@ -1,45 +0,0 @@
|
||||
---
|
||||
GlanceImages.create_and_list_image:
|
||||
-
|
||||
args:
|
||||
image_location: "http://download.cirros-cloud.net/0.3.1/cirros-0.3.1-x86_64-disk.img"
|
||||
container_format: "bare"
|
||||
disk_format: "qcow2"
|
||||
runner:
|
||||
type: "constant"
|
||||
times: 20
|
||||
concurrency: 5
|
||||
context:
|
||||
users:
|
||||
tenants: 1
|
||||
users_per_tenant: 1
|
||||
|
||||
GlanceImages.create_and_delete_image:
|
||||
-
|
||||
args:
|
||||
image_location: "http://download.cirros-cloud.net/0.3.1/cirros-0.3.1-x86_64-disk.img"
|
||||
container_format: "bare"
|
||||
disk_format: "qcow2"
|
||||
runner:
|
||||
type: "constant"
|
||||
times: 20
|
||||
concurrency: 5
|
||||
context:
|
||||
users:
|
||||
tenants: 5
|
||||
users_per_tenant: 2
|
||||
|
||||
GlancePlugin.create_and_list:
|
||||
-
|
||||
args:
|
||||
image_location: "~/.rally/extra/fake.img"
|
||||
container_format: "bare"
|
||||
disk_format: "qcow2"
|
||||
runner:
|
||||
type: "constant"
|
||||
times: 700
|
||||
concurrency: 7
|
||||
context:
|
||||
users:
|
||||
tenants: 1
|
||||
users_per_tenant: 1
|
@ -1,9 +0,0 @@
|
||||
Rally plugins
|
||||
=============
|
||||
|
||||
All *.py modules from this directory will be auto-loaded by Rally and all
|
||||
plugins will be discoverable. There is no need of any extra configuration
|
||||
and there is no difference between writing them here and in rally code base.
|
||||
|
||||
Note that it is better to push all interesting and useful benchmarks to Rally
|
||||
code base, this simplifies administration for Operators.
|
@ -1,91 +0,0 @@
|
||||
# Copyright 2014 Mirantis Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
""" Sample of plugin for Glance.
|
||||
|
||||
For more Glance related benchmarks take a look here:
|
||||
github.com/stackforge/rally/blob/master/rally/benchmark/scenarios/glance/
|
||||
|
||||
About plugins: https://rally.readthedocs.org/en/latest/plugins.html
|
||||
|
||||
Rally concepts https://wiki.openstack.org/wiki/Rally/Concepts
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from rally.benchmark.scenarios import base
|
||||
from rally.benchmark import utils as bench_utils
|
||||
|
||||
|
||||
class GlancePlugin(base.Scenario):
|
||||
|
||||
@base.atomic_action_timer("glance.create_image_label")
|
||||
def _create_image(self, image_name, container_format,
|
||||
image_location, disk_format, **kwargs):
|
||||
"""Create a new image.
|
||||
|
||||
:param image_name: String used to name the image
|
||||
:param container_format: Container format of image.
|
||||
Acceptable formats: ami, ari, aki, bare, and ovf.
|
||||
:param image_location: image file location used to upload
|
||||
:param disk_format: Disk format of image. Acceptable formats:
|
||||
ami, ari, aki, vhd, vmdk, raw, qcow2, vdi, and iso.
|
||||
:param **kwargs: optional parameters to create image
|
||||
|
||||
returns: object of image
|
||||
"""
|
||||
|
||||
kw = {
|
||||
"name": image_name,
|
||||
"container_format": container_format,
|
||||
"disk_format": disk_format,
|
||||
}
|
||||
|
||||
kw.update(kwargs)
|
||||
|
||||
try:
|
||||
if os.path.isfile(os.path.expanduser(image_location)):
|
||||
kw["data"] = open(os.path.expanduser(image_location))
|
||||
else:
|
||||
kw["copy_from"] = image_location
|
||||
|
||||
image = self.clients("glance").images.create(**kw)
|
||||
|
||||
image = bench_utils.wait_for(
|
||||
image,
|
||||
is_ready=bench_utils.resource_is("active"),
|
||||
update_resource=bench_utils.get_from_manager(),
|
||||
timeout=100,
|
||||
check_interval=0.5)
|
||||
|
||||
finally:
|
||||
if "data" in kw:
|
||||
kw["data"].close()
|
||||
|
||||
return image
|
||||
|
||||
@base.atomic_action_timer("glance.list_images_label")
|
||||
def _list_images(self):
|
||||
return list(self.clients("glance").images.list())
|
||||
|
||||
@base.scenario(context={"cleanup": ["glance"]})
|
||||
def create_and_list(self, container_format,
|
||||
image_location, disk_format, **kwargs):
|
||||
self._create_image(self._generate_random_name(),
|
||||
container_format,
|
||||
image_location,
|
||||
disk_format,
|
||||
**kwargs)
|
||||
self._list_images()
|
@ -2,7 +2,8 @@
|
||||
# of appearance. Changing the order has an impact on the overall integration
|
||||
# process, which may cause wedges in the gate later.
|
||||
|
||||
pbr>=0.6,!=0.7,<1.0
|
||||
pbr>=1.6 # Apache-2.0
|
||||
|
||||
#
|
||||
# The greenlet package must be compiled with gcc and needs
|
||||
# the Python.h headers. Make sure you install the python-dev
|
||||
@ -30,14 +31,6 @@ stevedore>=1.3.0,<1.4.0 # Apache-2.0
|
||||
taskflow>=0.7.1,<0.8.0
|
||||
keystonemiddleware>=1.5.0,<1.6.0
|
||||
WSME>=0.6
|
||||
# For openstack/common/lockutils
|
||||
posix_ipc
|
||||
|
||||
# For Swift storage backend.
|
||||
python-swiftclient>=2.2.0,<2.5.0
|
||||
|
||||
# For VMware storage backed.
|
||||
oslo_vmware>=0.11.1,<0.12.0 # Apache-2.0
|
||||
|
||||
# For paste.util.template used in keystone.common.template
|
||||
Paste
|
||||
@ -54,12 +47,10 @@ oslo_log>=1.0.0,<1.1.0 # Apache-2.0
|
||||
oslo_messaging>=1.8.0,<1.9.0 # Apache-2.0
|
||||
oslo_policy>=0.3.1,<0.4.0 # Apache-2.0
|
||||
oslo_serialization>=1.4.0,<1.5.0 # Apache-2.0
|
||||
oslo.service>=0.1.0 # Apache-2.0
|
||||
|
||||
retrying>=1.2.3,!=1.3.0 # Apache-2.0
|
||||
osprofiler>=0.3.0 # Apache-2.0
|
||||
|
||||
# Glance Store
|
||||
glance_store>=0.3.0,<0.5.0 # Apache-2.0
|
||||
|
||||
# Artifact repository
|
||||
semantic_version>=2.3.1
|
||||
|
Loading…
Reference in New Issue
Block a user