diff -Nru python-novaclient-2.15.0/AUTHORS python-novaclient-2.16.0/AUTHORS --- python-novaclient-2.15.0/AUTHORS 2013-09-18 12:39:10.000000000 +0000 +++ python-novaclient-2.16.0/AUTHORS 2014-02-26 16:29:29.000000000 +0000 @@ -1,208 +1 @@ -Aaron Lee -Aaron Rosen -Aarti Kriplani -Abhishek Lahiri -Adam Gandelman -Adam Spiers -Akihiro MOTOKI -Alan Pevec -Alessandro Pilotti -Alessio Ababilov -Alessio Ababilov -Alex Gaynor -Alex Glikson -Alex Meade -Alvaro Lopez Garcia -Andrew Bogott -Andrew Laski -Andrey Brindeyev -Andy Hill -Andy McCrae -Andy Smith -Anita Kuno -Anthony Young -Antony Messerli -Arata Notsu -Armando Migliaccio -Avishay Traeger -Bartosz Górski -Ben Nemec -Ben Nemec -Brian Elliott -Brian Lamar -Brian Waldon -Chang Bo Guo -Chmouel Boudjnah -Chmouel Boudjnah -Chris Behrens -Chris Jones -Chris Krelle -Chris Yeoh -Christian Berendt -Christoph Gysin -Christopher MacGown -Chuck -Chuck Short -Clark Boylan -Cole Robinson -Cyril Roelandt -Dan Prince -Dan Smith -Dan Wendlandt -Daniel P. Berrange -Daniel Wallace -Davanum Srinivas -Dave Walker (Daviey) -Dave Wilde -David Scannell -David Wittman -Dean Troyer -Dirk Mueller -Dominik Heidler -Doug Hellmann -Ed Leafe -Eldar Nugaev -Emanuele Rocca -Eoghan Glynn -Eric Harney -Flaper Fesp -François Charlier -Gabriel Hurley -Gaurav Gupta -Ghe Rivero -Gordon Chung -Haiwei Xu -Hans Lindgren -Hengqing Hu -Hugh Saunders -Ilya Alekseyev -Jake Dahn -Jakub Ruzicka -James E. Blair -James Meredith -Jason Kölker -Jason Straw -Jay Pipes -Jesse Andrews -Jiajun Liu -Jianing YANG -Joe Gordon -Joe Gordon -Joe Heck -Johannes Erdfelt -John Garbutt -John Tran -Josh Kearney -Joshua Harlow -Julie Pichon -Julien Danjou -Kaushik Chandrashekar -Ken'ichi Ohmichi -Kevin L. Mitchell -Kiall Mac Innes -Kieran Spear -Kirill Shileev -Kravchenko Pavel -Kurt Taylor -Leo Toyoda -Lorin Hochstein -Lorin Hochstein -Lvov Maxim -Mahesh Panchaksharaiah -Major Hayden -Mark McClain -Mark McLoughlin -Masayuki Igawa -Matt Dietz -Matt Stephenson -Matt Thompson -Matthew Treinish -Melanie Witt -Michael Basnight -Michael Still -Mike Lundy -Mitsuhiko Yamazaki -Monty Taylor -Nachi Ueno -Nicholas Mistry -Nick Shobe -Nicolas Simonds -Nikola Dipanov -Nikolay Sokolov -Noorul Islam K M -Ollie Leahy -Paul Voccio -Paul Voccio -Pavel Shkitin -Peng Yong -Phil Day -Pádraig Brady -Rami Vaknin -Rick Harris -Robie Basak -Rohan Rhishikesh Kanade -Roman Podolyaka -Russell Bryant -Russell Cloran -Sandy Walsh -SandyWalsh -Sascha Peilicke -Sathish Nagappan -Scott Devoid -Scott Moser -Sean Dague -Sean McCully -Sergey Lukjanov -Shane Wang -Stanislaw Pitucha -Stef T -Sulochan Acharya -Sumanth Nagadavalli -Svetlana Shturm -Thierry Carrez -Thomas Schreiber -TianTian Gao -Trey Morris -Ubuntu -Unmesh Gurjar -Unmesh Gurjar -Vasyl Khomenko -Victoria Martínez de la Cruz -Vincent Hou -Vincent Untz -Vishvananda Ishaya -Vitaliy Kolosov -William Wolf -Wu Wenxiang -Xavier Queralt -Xiao Hanyu -Yaguang Tang -Yaguang Tang -Your Name -Yufang Zhang -Yunhong, Jiang -Yuriy Taraday -Yuuichi Fujioka -Zane Bitter -Zhenguo Niu -Zhi Yan Liu -Zhiteng Huang -Ziad Sawalha -annegentle -fujioka yuuichi -gengjh -gtt116 -guoqingzhang -hwbi -ivan-zhu -jakedahn -liuan -liyingjun -lrqrun -lzyeval -masumotok -melwitt -sathish-nagappan -unicell -zhiyanliu -Édouard Thuleau + diff -Nru python-novaclient-2.15.0/ChangeLog python-novaclient-2.16.0/ChangeLog --- python-novaclient-2.15.0/ChangeLog 2013-09-18 12:39:10.000000000 +0000 +++ python-novaclient-2.16.0/ChangeLog 2014-02-26 16:29:28.000000000 +0000 @@ -1,11402 +1,1011 @@ -commit 45fcd6f7bae0aa7b72d9d0da919ff253df98319e -Merge: 4e8caf8 889f568 -Author: Jenkins -Date: Tue Sep 17 21:20:37 2013 +0000 +CHANGES +======= - Merge "assertEquals is deprecated, use assertEqual" +2.16.0 +------ -commit 4e8caf8ed6f51c0202092c75ac13ef8c86c0ff56 -Merge: ecb9b8b bec4e51 -Author: Jenkins -Date: Tue Sep 17 18:43:30 2013 +0000 - - Merge "Add delete method to Flavor class" - -commit ecb9b8bf3c83adfb23704f9c0c8258356a2381a4 -Merge: ff97f4d 97da33f -Author: Jenkins -Date: Tue Sep 17 18:43:00 2013 +0000 - - Merge "Allow name argument to flavor-access-add" - -commit ff97f4de78601f044537accfdae7659798537a8b -Merge: 0af541c 605a7ed -Author: Jenkins -Date: Tue Sep 17 18:42:53 2013 +0000 - - Merge "python3: Fix Traceback while running unit tests" - -commit 0af541c7275c0fac609bed2ae451e09e4af710f7 -Merge: 607e6e9 450f02e -Author: Jenkins -Date: Tue Sep 17 18:42:19 2013 +0000 - - Merge "python3: Compatibility for iteritems differences" - -commit 607e6e9aaec65f12f27f06f2b61d0d31616c0882 -Merge: e9f2620 4f3c2c9 -Author: Jenkins -Date: Tue Sep 17 18:42:17 2013 +0000 - - Merge "python3: Fix traceback while running unit tests" - -commit e9f2620a3ed0fd017fad61ba29c93f4156df906a -Merge: ed817c8 aeef15d -Author: Jenkins -Date: Tue Sep 17 18:10:21 2013 +0000 - - Merge "Modify --num-instances flag description to clarify limit upper bound" - -commit ed817c8dc72c558d9938300042368f5af415072d -Merge: 80eb827 2e8900b -Author: Jenkins -Date: Tue Sep 17 18:10:20 2013 +0000 - - Merge "Add a block device for the image when using BDMv2" - -commit 80eb82792a4abf37867a9320d296ab9887e43a07 -Merge: 7edda20 043ef5b -Author: Jenkins -Date: Tue Sep 17 17:37:33 2013 +0000 - - Merge "Fix the print order of quota-show" - -commit 043ef5b7573fa2eb2aa825057a06a666764120fd -Author: Ken'ichi Ohmichi -Date: Tue Sep 10 17:21:54 2013 +0900 - - Fix the print order of quota-show - - Current "nova qouta-show" prints quotas by random order like the - following: - - $ nova quota-show - +-----------------------------+-------+ - | Property | Value | - +-----------------------------+-------+ - | metadata_items | 128 | - | injected_file_content_bytes | 10240 | - | ram | 51200 | - | floating_ips | 10 | - | key_pairs | 100 | - | instances | 10 | - | security_group_rules | 20 | - | injected_files | 5 | - | cores | 20 | - | fixed_ips | -1 | - | injected_file_path_bytes | 255 | - | security_groups | 10 | - +-----------------------------+-------+ - $ - - This patch fixes its order for fitting to the option order of - "nova quota-update" like the following: - - $ nova quota-show - +-----------------------------+-------+ - | Quota | Limit | - +-----------------------------+-------+ - | instances | 10 | - | cores | 20 | - | ram | 51200 | - | floating_ips | 10 | - | fixed_ips | -1 | - | metadata_items | 128 | - | injected_files | 5 | - | injected_file_content_bytes | 10240 | - | injected_file_path_bytes | 255 | - | key_pairs | 100 | - | security_groups | 10 | - | security_group_rules | 20 | - +-----------------------------+-------+ - - Fixes bug #1223233 - - Change-Id: I482fd26b9114ac718dc4a16753e7692213bd3690 - -commit 889f5680a99e9c2ed11dadec79cfb2c3ef3e7761 -Author: Chang Bo Guo -Date: Mon Sep 16 17:20:54 2013 -0700 - - assertEquals is deprecated, use assertEqual - - assertEquals is deprecated in Python 2.7 , need drop it - - http://docs.python.org/2/library/unittest.html#deprecated-aliases - - Change-Id: I5aeeb3b289e1d29f6338fc9fd47e680909f0a133 - -commit 7edda206b17a5ef0914c630ae10ee7e1afcc1568 -Author: Vitaliy Kolosov -Date: Mon Sep 9 16:28:12 2013 +0300 - - Small bugfix for client v3 - - Client.__init__ method used self.os_cache variable in an internal method call - though this variable had not been initialized earlier. - In addition, unittests added for full coverage of client v3. - - Change-Id: I421f82932b65f137932d933e04d42064bec0d08d - -commit aeef15d6d34867556fa73824739d2bd0e07b933f -Author: Abhishek Lahiri -Date: Sat Sep 14 03:47:01 2013 +0000 - - Modify --num-instances flag description to clarify limit upper bound - - Closes Bug:#1220703 - - Modified --num-instances flag description in shell.py to clarify that - number of instances spawned are limited by the quota. - - Change-Id: I29fa175f310ab1e073dca5f453a3540dcdde933d - Signed-off-by: Abhishek Lahiri - -commit 2e8900b6dceb0574a79c2885ea7f0291fd3e8dca -Author: Xavier Queralt -Date: Fri Sep 13 18:27:45 2013 +0200 - - Add a block device for the image when using BDMv2 - - Right now the cli was already adding a block device when it was passed - an image_id to boot from and more than one block device mapping v2. This - is done because nova expects the image to be another block device - mapping and would ignore it otherwise. - - This patch moves this functionality from the cli to the base module so - users of the module can benefit from this and also to prevent some - misunderstandings that may arise when using BDMv2 and the image gets - ignored by nova. In the future we should handle this in the nova side - assuming a new BDM when an image is provided. - - Fixes bug #1225061 - - Change-Id: I29f31c24f958cfa8b68b33edc63e0d7031aa241f - -commit 450f02efe3310ce62a2a5ffc1cfc4318b2474289 -Author: Chuck Short -Date: Sat Sep 7 13:52:01 2013 -0400 - - python3: Compatibility for iteritems differences - - In python3 dict.iteritems(), dict.iterkeys(), and - dict.itervalues() are no longer supported. So use - six.iteritems() where it is appropriate. - - blueprint python3-novaclient - - Change-Id: I8c39bfe426d08d36215b55c3245dcfc69ec72517 - Signed-off-by: Chuck Short - -commit 4f3c2c92a461e015bf620be3b2d398a952a5a89a -Author: Chuck Short -Date: Fri Sep 6 11:03:18 2013 -0400 - - python3: Fix traceback while running unit tests - - While running unit tests with python3, we get the following traceback: - - TypeError: 'map' object is not subscriptable - - In python3, a map returns an iterable object of type map, - and is not subscriptable. - - Refactor to not use indicies so that it is python2 and python3 - compat. - - blueprint python3-novaclient - - Change-Id: Iaf0de19f08fa3e91ee79c174ccc86a8bbe4acdc8 - Signed-off-by: Chuck Short - -commit 605a7ed2f24f7ac26a9e7bd9961be144e50cc5e4 -Author: Chuck Short -Date: Fri Sep 6 08:52:45 2013 -0400 - - python3: Fix Traceback while running unit tests - - Python3 uses the the concepts of text and (binary) data - instead of Unicode strings and 8-bit strings. In python3 - all text is unicode; however encoded unicode is represented - as binary data. - - Use the six module to use six.binary_types and six.text_types - where apporiate: - - six.text_type unicode() in python2 and str in python3. - - six.basestring() in python2 and str in python3. - - blueprint python3-novaclient - - Change-Id: Ie7b393abe6beac22eaf127b7fc7bbc372c338211 - Signed-off-by: Chuck Short - -commit 9a1304bfab56d7aad1d65d1c6cde3303b64d70ce -Merge: 447cf8d 28f9773 -Author: Jenkins -Date: Wed Sep 11 22:07:13 2013 +0000 - - Merge "Python3: Use six.StringIO for io.Bytes()" - -commit 447cf8d6e5299aff456fc9c928e73720791c2ed3 -Merge: 500bb62 9d8869e -Author: Jenkins -Date: Wed Sep 11 18:09:43 2013 +0000 - - Merge "Python3: Fix traceback while running unit tests" - -commit 500bb6244d4896e7fee94219cefc4426b1360b40 -Merge: 3523ba9 69f8de6 -Author: Jenkins -Date: Tue Sep 10 16:47:32 2013 +0000 - - Merge "Add support for os-assisted-volume-snapshots" - -commit 3523ba90f68d55ac20fb044d9acbe6c53fecbf1f -Author: Vitaliy Kolosov -Date: Mon Sep 9 12:11:32 2013 +0300 - - Unittests added for client v1_1 - - Unittests test_client_set_management_url_v1_1 and - test_client_get_reset_timings_v1_1 added. - New methods covered: - * client.set_management_url() - * client.get_timings() - * client.reset_timings() - - Change-Id: I46cac01864a11fbaffc284d26f63b8e00f2631f0 - -commit 9d8869e01c51f2611c187c45701033f507f40e2a -Author: Chuck Short -Date: Sat Sep 7 12:33:31 2013 -0400 - - Python3: Fix traceback while running unit tests - - While running the unit tests with python3 the following - traceback appears: - - TypeError: can't use a string pattern on a bytes-like object - - This is due to the way that python2 and python3 handles unicodes. - - Change-Id: I401f1cefed69780073222cae98d8da4c3d8031a8 - Signed-off-by: Chuck Short - -commit 28f97734203a2df33805291673104742d45d34f3 -Author: Chuck Short -Date: Sat Sep 7 12:27:46 2013 -0400 - - Python3: Use six.StringIO for io.Bytes() - - The newer version of six (1.4.1) provides six.StringIO which - is a fake file object for textual data. It's an alias for StringIO.StringIO - in python2 and io.StringIO in Python3. - - Use the fake object where approiate. - - Change-Id: I364001933b4f2305ac27b293a9a4a3fec36c8a49 - Signed-off-by: Chuck Short - -commit cab46172253add86a5a25431a1af4066d29418bc -Author: Chuck Short -Date: Fri Sep 6 08:02:31 2013 -0400 - - Update oslo from oslo-incubator - - Update oslo from oslo-incubator includes various python3 - fixes. - - Change-Id: Ie30a4c319125c3d4fb704254f8553bc8fd960eae - Signed-off-by: Chuck Short - -commit bec4e51df4aef33d2c76889af56258cc00fed357 -Author: Ken'ichi Ohmichi -Date: Thu Aug 29 11:33:59 2013 +0900 - - Add delete method to Flavor class - - In tempest, some tests use delete() method of each resource class - (Server, SecurityGroup, etc.) for cleaning up when each test finishes. - Now we are adding some tests, which create a Flavor instance, to tempest - and we need the delete() method of Flavor class. - - Fixes bug #1218156 - - Change-Id: I210d62aa45510858346315046cf57ea7b1de7b7b - -commit 6a85c954c53f868251413db51cc1d9616acd4d02 -Author: Xavier Queralt -Date: Fri Jul 26 09:23:19 2013 +0200 - - New syntax to boot from a block device mapping - - Add new arguments and syntax for booting from a block device mapping - that use the new os-block-device-mapping-v2-boot extension. These - allow to: - - * boot from an image, volume or snapshot (--image, --boot-volume, --snapshot) - * attach any type of block device (--block-device). - * attach an swap disk on boot (--swap). - * attach an ephemeral disk on boot (--ephemeral). - - blueprint: improve-block-device-handling - - DocImpact - - Change-Id: I1aadeafed82b3bd1febcf0d1c3e64b258d6abeda - -commit 97da33fcf599efeb29d7e496d34a450c78c557f5 -Author: fujioka yuuichi -Date: Mon Sep 2 11:03:50 2013 +0900 - - Allow name argument to flavor-access-add - - Administrator cannot use the flavor name in arguments of - "nova flavor-access-add" and "nova flavor-access-remove". - - This patch fixes this problem. - - Change-Id: I68b267dc071382f1978efc2088cd8e837455e8b4 - Related-Bug: #1205298 - -commit d770bb3aabffbe63afad62b489f64fe556a748b6 -Merge: 756a433 12d5b95 -Author: Jenkins -Date: Sun Sep 1 14:06:10 2013 +0000 - - Merge "Add interface for listing security groups of an instance" - -commit 69f8de69d59084e0ca6b85834a3029193b17469b -Author: Russell Bryant -Date: Thu Aug 29 20:03:28 2013 -0400 - - Add support for os-assisted-volume-snapshots - - This patch adds support for the assisted volume snapshots API extension. - This is used by Cinder to ask Nova to perform a volume snapshot on its - behalf. It's required when the volume is actually file backed (like - qcow2) and the hypervisor needs to be involved in the snapshot - operation. - - Required for blueprint qemu-assisted-snapshots - - Change-Id: I50ee9bf92c8de98528638d1724fe35e07bed729e - -commit 756a4333e6845468ba82c2ba8be245a849bc8507 -Author: Yufang Zhang -Date: Wed Aug 7 21:37:28 2013 +0800 - - Suport instance list pagination in novaclient, Part I - - Bug 1209242 - - nova-api has supported pagination for long. A marker and limit - option could be passed to nova-api to get a slice of instances. - It makes sense to enable this feature in novaclient, so that - horizon could use it for pagination supporting. Modification to - shell.py would be submitted in a separate patch. - - Further change will also pass 'sort_key' and 'sort_dir' to - nova-api, as long as nova supports this. - - This is part of blueprint support-pagination-for-instance-list - - Change-Id: Ieb5f2c1eb31b9f7e95b62b51ea7dc338e3970d04 - -commit 72c0a13b0a0858a1a4cb093368c0d4d1cf24969f -Merge: 9ce24f2 3c2a817 -Author: Jenkins -Date: Thu Aug 29 14:26:17 2013 +0000 - - Merge "Added 'nova migration-list' command" - -commit 9ce24f214bd62d75dcf7b8c0a252f16c93a98e0d -Merge: d6139aa 73a0e72 -Author: Jenkins -Date: Thu Aug 29 12:04:52 2013 +0000 - - Merge "change 'Host' object's 'host' attribute to 'host_name'" - -commit d6139aabda217fd0d6404ce06625ba80701b4986 -Merge: 3851245 d978245 -Author: Jenkins -Date: Thu Aug 29 12:03:49 2013 +0000 - - Merge "Added support for running the tests under PyPy with tox" - -commit 3851245ec41da10704e08651bba663c8af5524f4 -Merge: c970dc3 d925f55 -Author: Jenkins -Date: Thu Aug 29 04:17:22 2013 +0000 - - Merge "Fix the help messages to specify image/flavor name" - -commit 12d5b9578bf7b4149ad84800fd2336d87d3311ef -Author: Noorul Islam K M -Date: Mon Aug 5 14:11:58 2013 +0530 - - Add interface for listing security groups of an instance - - This is already available in nova but not exposed via client. - - * novaclient/v1_1/servers.py: - New interface to list security groups of an instance. - - * novaclient/v1_1/shell.py: - New sub command list-secgroup. - - * novaclient/tests/v1_1/fakes.py, - novaclient/tests/v1_1/test_servers.py, - novaclient/tests/v1_1/test_shell.py: - Add corresponding tests. - - Implements: blueprint servers-list-secgroup - - Change-Id: I505bcffdbb15b84bfd73cae5ef5a8fb9c69bd7b9 - -commit c970dc3dd4fbb1a825a9e305b5aa6dd504c6b212 -Merge: dc1b1cd c450b39 -Author: Jenkins -Date: Thu Aug 29 01:17:12 2013 +0000 - - Merge "python3: Fix imports for py2/py3" - -commit dc1b1cda06de6e720e0b984d7fc3d5e5a78eb71f -Merge: 2e97eb7 e0e5c2d -Author: Jenkins -Date: Wed Aug 28 19:18:43 2013 +0000 - - Merge "Fix and gate on H501, no locals for string formatting" - -commit d9782457fcc4539a0dbe795831114b6fc756d23c -Author: Alex Gaynor -Date: Wed Aug 28 09:35:28 2013 -0700 - - Added support for running the tests under PyPy with tox - - This is a precursor to having them run under check and gate. - - Change-Id: I105404d45cd4be93909ea5a272fc7e7c0c6d78cb - -commit 2e97eb7e533deb549c206b9e06c012b6550ff703 -Merge: 61a8063 fe5f07e -Author: Jenkins -Date: Wed Aug 28 14:15:47 2013 +0000 - - Merge "Upgrade to Hacking 0.7" - -commit c450b39828a06c99a4bdb386398d8bd29c4193fa -Author: Chuck Short -Date: Mon Aug 19 20:51:48 2013 -0400 - - python3: Fix imports for py2/py3 - - Python3 reorganized the standard library and moved several functions - to different modules. Six provides a consistent interface - to them through the fake six.moves module. - - However, the urlparse, urllib2, etc modules have been combined - into one module which Six does not support so we do it via - py3kcompat. - - Modules such as StringIO and CStringIO have been removed - completely so we use the io module. - - Change-Id: I53adac11b634de2c710fc39def36bcec96366710 - Signed-off-by: Chuck Short - -commit fe5f07e891f45886a0e0e00134db36f310566ebd -Author: Joe Gordon -Date: Fri Aug 23 16:51:46 2013 -0400 - - Upgrade to Hacking 0.7 - - There was a bug in hacking 0.6 that broke H202, assertRaises Exception - too broad, so switch to Hacking 0.7 and fix the one H202 bug. - - Change-Id: I0ec9532ffbb6b3c8dbd775e6da7bc879b0a6737a - -commit 61a80639545cf44e3e4141dbaa5afab0259c574a -Author: Chuck Short -Date: Fri Aug 9 13:59:02 2013 +0000 - - Sync py3kcompat from oslo - - Python3 reorganized the standard library and moved several - functions to different modules and combined modules. Six - provides a consistent interface to the module through - six.moves - - However urllib/urlparse is not covered by six.moves so - py3kcompat adds python2/python3 compatibility layer for - urllib/urlparse. - - Change-Id: If1436d2260f1c8b6df8c514c8730e7bcf0e648b8 - Signed-off-by: Chuck Short - -commit 27700f9b3610a90b4bb47cbe7abd635acc76ad0d -Merge: 5e8957a 476e50f -Author: Jenkins -Date: Fri Aug 23 01:33:06 2013 +0000 - - Merge "Allow name argument to flavor-access-add" - -commit 5e8957a2b7e81e3ea145b2c6fb545d1bed605f7f -Merge: dd55f7e fa2867f -Author: Jenkins -Date: Fri Aug 23 01:29:37 2013 +0000 - - Merge "Update mailmap" - -commit dd55f7e91a68db3f1ba65611be8da02bde25c3fc -Merge: de5a246 d0619bc -Author: Jenkins -Date: Fri Aug 23 01:29:36 2013 +0000 - - Merge "Update mailmap" - -commit de5a24683bf150a0f1e5a5a3cd0eb72de18be1f5 -Merge: 6d73aba 626c480 -Author: Jenkins -Date: Fri Aug 23 01:29:35 2013 +0000 - - Merge "Update oslo" - -commit 6d73abaf8a983f59e422ae2539d7854d6844b7a5 -Merge: 8dbd684 930a10a -Author: Jenkins -Date: Thu Aug 22 05:21:33 2013 +0000 - - Merge "Add support for swap_volume" - -commit fa2867f1bd572a7728b1b051bbf04b3846be563c -Author: hwbi -Date: Tue Aug 20 22:00:51 2013 -0700 - - Update mailmap - - Change-Id: I0f1f8b65db311fee9303dcf1a68c8057d9d778ab - -commit d0619bc64558e26dae39eb669c4bc0d699d63f8d -Author: guoqingzhang -Date: Tue Aug 20 21:48:06 2013 -0700 - - Update mailmap - - Change-Id: Ic3050ae029b367f099346dc99e76e33bd47bdc33 - -commit 3c2a817efcb6954f3c8246c32ce997b9e3a4d000 -Author: Mahesh Panchaksharaiah -Date: Fri Jul 19 14:55:23 2013 +0530 - - Added 'nova migration-list' command - - This command lets Admin's list migrations by applying filters - - Implements: blueprint list-resizes-through-admin-api - Change-Id: I587c62dab537186cfc8b387fbc46cdb56fb9976c - -commit e0e5c2dfe51373f33041c2412581491175432006 -Author: Joe Gordon -Date: Thu Aug 15 19:11:28 2013 -0400 - - Fix and gate on H501, no locals for string formatting - - Change-Id: I07e4a1a733639a343d4b3ee20927d50ba04bd7a3 - -commit 626c4805595678875c5950d30926b126ab679bb8 -Author: Chuck Short -Date: Wed Aug 14 15:05:52 2013 -0400 - - Update oslo - - Update gettext, striutils, timeutils and install_venv_common - from oslo. - - Change-Id: Ibd9067e3e2be335ef75f0e4a5e4000d143030ab7 - Signed-off-by: Chuck Short - -commit 476e50f4d7f7c7f3231bca8beb194776c28b2267 -Author: Yuuichi Fujioka -Date: Mon Jul 29 05:32:01 2013 +0900 - - Allow name argument to flavor-access-add - - Administrator cannot use the flavor name in arguments of - "nova flavor-access-add" and "nova flavor-access-remove" - in following conditions. - - 1. The flavor is non-public. - 2. The falvor doesn't belong administrator's tenant. - - This patch fixes this problem. - - Change-Id: Ic5e3222d0ff62667e003a61e6a94e85833da5d11 - Fixes: bug #1205298 - -commit 8dbd684a5cbf9fe5cdc0ab1f38930a6f6794726d -Author: Chuck Short -Date: Fri Aug 9 15:15:04 2013 +0000 - - python3: Fix traceback while running tests - - Fix: - - TypeError: Unicode-objects must be encoded before hashing - - while running tests. This is due to the fact in python3 hashlib.md5 - works with bytes and we are passing unicode strings. - - Change-Id: I27a57d6afb2412e11bc2802e4559d56c5b5592a9 - Signed-off-by: Chuck Short - -commit 23ac42a43fb4859d1064e2de6f987c2ba92719a3 -Merge: 54cac5f ce08598 -Author: Jenkins -Date: Tue Aug 13 10:18:31 2013 +0000 - - Merge "Updated from global requirements" - -commit 54cac5f3407363dade76dd24ab5826606261c2e4 -Merge: 9e67f28 99d9784 -Author: Jenkins -Date: Tue Aug 13 01:15:42 2013 +0000 - - Merge "Remove old references" - -commit 9e67f280a2dec9b2fac7e1ef13ed1112c954fcad -Merge: b7d71f9 211dfe6 -Author: Jenkins -Date: Tue Aug 13 01:14:04 2013 +0000 - - Merge "Enable v3 api code" - -commit b7d71f9e838f170b6db3da575512b94a388056d3 -Merge: 01635a2 c0e6d24 -Author: Jenkins -Date: Tue Aug 13 01:14:03 2013 +0000 - - Merge "Begin adding v3 api support" - -commit 01635a2add3e85a5e3932f450a209e8eb9add67b -Merge: 545806c 1f85f57 -Author: Jenkins -Date: Mon Aug 12 22:16:47 2013 +0000 - - Merge "FakeClient: fix the arguments of a string format." - -commit 545806cd154575a0056969e24dabef65f7b01a4e -Merge: 10f500d 0331a01 -Author: Jenkins -Date: Mon Aug 12 18:14:21 2013 +0000 - - Merge "Clean up inaccurate docstrings of server list() method" - -commit d925f55d0c232dd2fe4f2d066f0aa2ef09444fca -Author: Ken'ichi Ohmichi -Date: Mon Aug 12 13:58:03 2013 +0900 - - Fix the help messages to specify image/flavor name - - User can specify flavor/image name as the arguments of "nova boot" - command instead of their ids, but the help messages does not explain - that. This fixes the help messages. - - Fixes: bug #1211156 - - Change-Id: I47813c8ebbe5fc83d627f016e3751918b3ab11cb - -commit 0331a01cfc4a2d9197998b0b33d2e02dc04b0197 -Author: Yufang Zhang -Date: Wed Aug 7 17:53:05 2013 +0800 - - Clean up inaccurate docstrings of server list() method - - Clean up the inaccurate docstrings of server list() method and - refactor them to standerd format. - - Change-Id: I4c17aba7ce5eb430ddd10305135e11e3ce5dc446 - -commit 10f500de831c339d24005173ee8f1478ad4fe3fa -Merge: 9114cbf aee0a29 -Author: Jenkins -Date: Fri Aug 9 19:18:41 2013 +0000 - - Merge "Fix typo and grammar in docstring only" - -commit 99d978409f0d455ba148d4d5ee8545c9f99cd126 -Author: Ben Nemec -Date: Thu Aug 8 12:33:10 2013 -0500 - - Remove old references - - The v3 code references v1_1 code because it's a straight-across - copy. Remove those in preparation for adding the actual v3 - versions. - - bp v3-api - - Change-Id: I359c6c5fc70dd91fa418802cc8048e186f5d09a4 - -commit 211dfe6ea706ec861daa3138d95b70c3427e0eed -Author: Ben Nemec -Date: Tue Aug 6 12:48:24 2013 -0500 - - Enable v3 api code - - Add mappings to enable v3 code - - bp v3-api - - Change-Id: I035e5b9d65c06ce5691573832bb9b6c4c705b121 - -commit c0e6d24819019dfffb56ec37d8504ae4af163352 -Author: Ben Nemec -Date: Tue Aug 6 12:39:49 2013 -0500 - - Begin adding v3 api support - - Create the v3 directory and populate it with some of the basic - files from v2 that will be needed. These files are straight - copies so that v3-specific changes will be easier to see in - subsequent changes. - - Extensions will be added individually in future changes. - - bp v3-api - - Change-Id: I9538c70ccc6fb001ce2fd43ccfd41870f247c67e - -commit 73a0e7298aeb7ff43e70a865d2350923d269db69 -Author: liuan -Date: Thu Aug 8 16:45:49 2013 +0800 - - change 'Host' object's 'host' attribute to 'host_name' - - The function __repr__ of Host class which is located in hosts.py try to - access 'host' attribute, source code is "self.host",But in fact, Host object - don't has this attribute, it should be 'host_name'! We can find this attribute - from nova/api/openstack/compute/contrib/hosts.py file. - - So I simply change 'self.host' to 'self.host_name'. - - Change-Id: Ie76ba04da7592a596ab728fec981e9a1dbcc6a5f - Fixes: bug 1210043 - -commit ce08598a69b7bb20c8e937e7fe8aed3b65e72919 -Author: Monty Taylor -Date: Wed Aug 7 18:55:28 2013 -0300 - - Updated from global requirements - - Change-Id: Ic4a43955526fcde313ad2f2afec8fafeb87f37a6 - -commit 9114cbfb8e19f1491eee5b18305e258022536a84 -Merge: fe31607 f7d3948 -Author: Jenkins -Date: Thu Aug 8 01:46:00 2013 +0000 - - Merge "Do not restrict flavor to only ID and integers" - -commit f7d3948b2395fcee7e9826f567ededffc50305db -Author: Chmouel Boudjnah -Date: Wed Aug 7 14:55:53 2013 +0200 - - Do not restrict flavor to only ID and integers - - - Flavors with strings and not just ID/UUID strings are valid. - - Closes-Bug: 1209060 - - Change-Id: Idee389fce40f8982b263e1a4349a8565140b6584 - -commit aee0a29733a1f38038fb7a038b426ca1c8fa9b97 -Author: Noorul Islam K M -Date: Mon Aug 5 07:11:57 2013 +0530 - - Fix typo and grammar in docstring only - - Change-Id: I1e34ada679c56b996c6aa4652b43d1652f3c375f - -commit fe31607d1ba2596a5df7452b6c2227215e5397d3 -Author: Mark McClain -Date: Tue Aug 6 15:25:00 2013 -0400 - - remove requests version max - - This change removes the max version specified for requests since the - requirements project no longer limits it to 1.2.2. - - Change-Id: I96d14b4a84d975e8b08e9271db8d5e13d78019ae - -commit ec5861644c3a7a77bcbbdd8cda7e33165fbb4601 -Author: Monty Taylor -Date: Mon Aug 5 17:50:29 2013 -0300 - - Sync with global requirements - - Change-Id: I8333e17d8edaa5853ac47f9d53de8c44d1c5d5cb - -commit 930a10abf91618bf5454aea71d4429a811c34cbf -Author: Avishay Traeger -Date: Thu Aug 1 15:40:03 2013 +0300 - - Add support for swap_volume - - Add client support for swap_volume, which allows swapping a volume - currently attached to an instance with a different volume which is not - attached. The contents of the old volume will be copied onto the new - volume. This was added in nova commit - 8f51b120b430c7c21399256f37e1d8f75d030484. - - Change-Id: I98323d594617c1c435e403d9f3ddc4ff4fa74da6 - -commit 0c0f093744a928f464af3986d848e70cbd636758 -Merge: 0d45408 852e2e5 -Author: Jenkins -Date: Sun Aug 4 13:31:50 2013 +0000 - - Merge "Check whether the security group id is integer" - -commit 1f85f57faf35e371464e157c3e77333be827111d -Author: Cyril Roelandt -Date: Fri Aug 2 15:32:12 2013 +0000 - - FakeClient: fix the arguments of a string format. - - Fix the number of arguments in the string format in - FakeClient.assert_called_anytime(). - - Change-Id: I9d415d6d216a6e301254ba21b63109182d71e8bd - -commit 0d454089c9f507bf128673a07d780fbfdba981f0 -Author: Brian Elliott -Date: Wed Jul 31 15:53:26 2013 -0500 - - Support programmatic use of disk config extension - - Allow servers to be created, resized, and rebuilt with the disk_config - option: - - http://api.openstack.org/api-ref.html#ext-os-disk-config - - There is a separate extension that exists for disk config already, but - it only works via the novaclient CLI interface, not via programmatic use - of python-novaclient as a library. - - assert changes in tests/v1_1/fakes allow for other data in rebuild - and resize requests. - - Change-Id: I8051ffb8747cf5c67b0199d22fbbe80306b01499 - -commit 852e2e5f3116844ea996bec6a1c9b15a463928da -Author: Vincent Hou -Date: Wed Jul 31 05:47:53 2013 -0400 - - Check whether the security group id is integer - - Fixed Bug 1206847. - - Change-Id: I2194d6538a5c5475b876ee026b5d625be2df076f - -commit 4ab2b60850239851824c801275ad8f2b09274a35 -Merge: 7d1eeb6 7fdb52a -Author: Jenkins -Date: Wed Jul 31 05:32:45 2013 +0000 - - Merge "Fixing host-action on V2" - -commit 7d1eeb6e43a38b5dd89972fae96e1eaa0378936e -Merge: caf884d ddda3f3 -Author: Jenkins -Date: Wed Jul 31 00:55:41 2013 +0000 - - Merge "Fix net-id metavar for interface-attach" - -commit caf884dd3ac956a71faf626e7553b0402ff617af -Merge: 95e7d70 8311862 -Author: Jenkins -Date: Wed Jul 31 00:47:14 2013 +0000 - - Merge "Fix the help text process and the generated wrong help" - -commit 95e7d7026679f37e15329bc5f1791c3da8bb3e93 -Merge: 8b5dcee 0d061f0 -Author: Jenkins -Date: Tue Jul 30 17:55:26 2013 +0000 - - Merge "Merge v1_1's base module into main base module" - -commit 7fdb52ac74bd896073f4f0f7bd0a21c1c32187ea -Author: Sumanth Nagadavalli -Date: Tue Jul 30 15:09:09 2013 +0530 - - Fixing host-action on V2 - - Changed host-actions to GET from POST for reboot, startup - and shutdown, as per nova-api reference documentation. - - Change-Id: I863b75960b2e427fd9384a336727132ca3c130c6 - Fixes: bug #1206425 - -commit 8b5dcee15eb82cd81d604be94e8f395627af4120 -Author: liyingjun -Date: Tue Jul 30 10:18:59 2013 +0800 - - Add user quota client API support - - Implements blueprint user-quota-related-client-api - - This patch adds user arguments to the following subcommands: - * quota-show - * quota-update - * quota-delete - - Change-Id: I6556de366a758f7550e9b26357f231666caae419 - -commit ddda3f31d86598c90e4cbdee9fca1d3bd2ff59a4 -Author: David Wittman -Date: Mon Jul 29 17:19:29 2013 -0500 - - Fix net-id metavar for interface-attach - - The metavariable for net-id was incorrectly set to `fixed_ip`. - This commit correctly sets the metavar to `net_id`. - - Change-Id: I9bfb442af99848cf43d1f3b78967b785506ac54f - -commit 5fe9408d2e53ac24a578d0ed568a4cede303fe58 -Author: Christian Berendt -Date: Wed Jul 17 16:48:04 2013 +0200 - - make findall in novaclient/base.py more efficient - - Use /resources instead of /resources/detail to resolve - the resource ID by the name and load the details of the - resource in a separate step. This reduces the overhead - to resolve the resource ID and results in a better runtime - performance. - - This patch does not solve the issue that the name resolving - takes place on the client side. For solving this issue new - Nova API methods are necessary. - - fixes bug #1202179 - - Change-Id: Ib753b1d090cb74b2d137c68f6899dad4ae2ec1ca - -commit 83118620d22fb26147da2455a4828b8237b9b370 -Author: Masayuki Igawa -Date: Mon Jul 29 14:36:31 2013 +0900 - - Fix the help text process and the generated wrong help - - The wrong help text of bash-completion is generated by the process of - choosing first line from the source code comment. We should get the all - help text from the source code comment, and use it. - - So this commit removes this unnecessary process, and also fix the - README.rst for proper help text. - - Fixes bug 1206005 - - Change-Id: Id4f5b6a7722197f09eb366ba8f3e643e1af91805 - -commit 2a45c7570f35c0ac78692b26f215e7dfa49fca79 -Merge: d5687ac cc2c0a8 -Author: Jenkins -Date: Sat Jul 27 14:57:30 2013 +0000 - - Merge "Enable force_delete and restore instance via novaclient." - -commit 0d061f0aeb1edaca66fd4e4b633d84b6a018d4b2 -Author: Xavier Queralt -Date: Fri Jul 26 08:32:34 2013 +0200 - - Merge v1_1's base module into main base module - - This class was forked from novaclient.base when adding v1.1 support and - and because v1.0 is no longer supported it can be merged again. - - blueprint: improve-block-device-handling - - Change-Id: I3113eff522a9dc280f48053001afa9e1a0cad3e3 - -commit d5687acff670c70abc0c118c62b5fe1c9c0e1188 -Merge: 3bc9cee de250bf -Author: Jenkins -Date: Fri Jul 26 09:28:55 2013 +0000 - - Merge "Add name argument to hypervisor commands" - -commit 3bc9cee729b04af8ee398cf38995d056d9dea96a -Merge: ee7b01a 4025b7e -Author: Jenkins -Date: Fri Jul 26 09:28:08 2013 +0000 - - Merge "Add name argument to aggregate commands" - -commit ee7b01a86d239f32c60a105c1d72db2d2850aaab -Merge: 3f0312e 1b5ed91 -Author: Jenkins -Date: Fri Jul 26 08:40:02 2013 +0000 - - Merge "recognize 429 as an rate limiting status" - -commit 3f0312eabcfcf0c54a7ea0b6075b7292515f15c5 -Author: Chuck Short -Date: Wed Jul 24 13:47:41 2013 -0400 - - Remove python 2.4 and python 2.5 support. - - As a project we do not support python 2.4 or python 2.5 - and these versions of python are not tested, so remove - the compatibility code. - - Change-Id: I267d9e7e83d85322c45d56d9c5256b514224ad8c - Signed-off-by: Chuck Short - -commit 2a19ba3031c4db9457e0df44b1eeb0c81c5347ea -Merge: 58d436e 912288c -Author: Jenkins -Date: Tue Jul 23 21:40:16 2013 +0000 - - Merge "make v2_auth and plugin_auth explictly return their results" - -commit 58d436ed88fdd6d66594ddfccf113aab1eb025ff -Merge: f702c25 f50ff36 -Author: Jenkins -Date: Tue Jul 23 01:01:32 2013 +0000 - - Merge "Skip setting volume_size if not given" - -commit cc2c0a8e6f853f16688fb7e4ec0217b34adbec92 -Author: Yufang Zhang -Date: Fri Jun 28 19:30:10 2013 +0800 - - Enable force_delete and restore instance via novaclient. - - Bug 1195670 - - Nova supports force_delete or restore instance in the API level, - thus it makes sense to support this feature in novaclient. - - Change-Id: I7cc3d2d2a7ab8dfe043176a3ea97c10deae683c9 - -commit 4025b7e5e3642792d55128bddc96491dc34e0434 -Author: Ken'ichi Ohmichi -Date: Fri Jul 19 09:58:52 2013 +0900 - - Add name argument to aggregate commands - - Fixes #Bug 1202901 - - This patch adds name arguments to the following subcommands: - * aggregate-update - * aggregate-delete - * aggregate-set-metadata - * aggregate-add-host - * aggregate-remove-host - * aggregate-details - - Change-Id: I93f44a12b6d5a91b448f6f8d238311d58bf40c01 - -commit de250bf170517ae187b14c4c19912964631b4a0e -Author: Ken'ichi Ohmichi -Date: Fri Jul 19 12:29:49 2013 +0900 - - Add name argument to hypervisor commands - - Fixes #Bug 1202920 - - This patch adds name arguments to the following subcommands: - * hypervisor-show - * hypervisor-uptime - - Change-Id: I9adfb699775d2d8f8ca45a7a28621e634bc03055 - -commit 1b5ed91650c7797fea0701112f95413183fef321 -Author: Jiajun Liu -Date: Tue Jul 16 09:35:42 2013 +0000 - - recognize 429 as an rate limiting status - - currently novaclient recognize 413 as rate limiting status while - it shoule be 429 according to HTTP protocol. - - fixes bug 1191874 - - Change-Id: Ib1ae54f7d13d0ca579dd264e8d0d7630770e92d6 - -commit 74506b83fedf72de90fd56bb7a978676700e7180 -Merge: a45c49b d095b8a -Author: Jenkins -Date: Mon Jul 15 17:50:40 2013 +0000 - - Merge "CLI for disable service reason" - -commit f702c25d4364583d6532bf11b2cce1107994bcce -Author: Julie Pichon -Date: Fri Jul 12 08:27:28 2013 +0100 - - Fix backwards-incompatible API change (method signature) - - project_id was changed to projectid in a previous changeset. - - Fixes bug 1203001 - - Change-Id: If9c21ae4f3cfbeb89569f6e4bd415c2041dc6294 - -commit 9b7d4702883ff08364733e1af2fa470c33805724 -Merge: 32f38fe 70e6cd9 -Author: Jenkins -Date: Fri Jul 19 13:21:21 2013 +0000 - - Merge "Fix interface-list got none mac address." - -commit 32f38fe19e7be3a2fd5ca9116f03c42984a4eb0b -Merge: af7ca70 02f906b -Author: Jenkins -Date: Thu Jul 18 21:51:19 2013 +0000 - - Merge "Allow tenant ID for authentication" - -commit af7ca70e3e676bbd8cd20c3847233e6e25a71fde -Author: Dirk Mueller -Date: Thu Jun 27 17:49:55 2013 +0200 - - Fix and enable gating on H402 - - End one-line docstrings with punctuation. - Change them to command style where necessary. - - Change-Id: I8ff689c3a2f20d489286f80112c6dc95c97f2f31 - -commit 0c775cbd78addcd998e4d665723c5c003fdac5b7 -Merge: 2645e97 c360c3e -Author: Jenkins -Date: Tue Jul 16 21:05:33 2013 +0000 - - Merge "Add AgregatesManager.get()" - -commit 2645e97a05d6b5974346da8e30ab229a64b2b9f8 -Merge: ca56219 1b3cd6f -Author: Jenkins -Date: Tue Jul 16 21:05:32 2013 +0000 - - Merge "Clean up and make HACKING.rst point to openstack-dev/hacking" - -commit ca56219a71e720beca9b9602556996b858c4c289 -Merge: da711d5 b5c9101 -Author: Jenkins -Date: Tue Jul 16 21:05:30 2013 +0000 - - Merge "Remove uncessary code related to nova start/stop" - -commit da711d56d2f51cd863c061076676dc841e0b0b07 -Merge: 74506b8 2770e05 -Author: Jenkins -Date: Tue Jul 16 20:05:49 2013 +0000 - - Merge "Adds zsh completion" - -commit c360c3e8dad8bdf9f86b8f8596a956e518d0f526 -Author: Dean Troyer -Date: Thu Jul 11 14:23:32 2013 -0500 - - Add AgregatesManager.get() - - utils.find_resource() uses manager.get() as part of converting Resource - names to IDs. AggregatesManager had get_details() instead of get(). - - Add AggregatesManager.get(), leaving .get_details() in place for backward - API compatibility. - - Bug: 1200341 - - Change-Id: I7d238bbe43e1760e31f1a9ba783c668246f20844 - -commit f50ff361e27a8ca688c0f1ba448bbc8bfb284905 -Author: Dirk Mueller -Date: Thu Jun 27 19:13:01 2013 +0200 - - Skip setting volume_size if not given - - When the block-device parameters skip volume_size, - don't set it. Setting to an empty volume_size - would be invalid as it has to be an integer, - and Nova API will reject the request if api validation - is implemented. (proposed e.g. at - https://review.openstack.org/#/c/34749/) - - Fixes bug LP #1199539 - - Change-Id: I7ab518886abf8d449caf1c70563a79a990d7765e - -commit 70e6cd97906fde9a888bae6eadc435560b64ec09 -Author: gtt116 -Date: Wed Jul 10 17:45:22 2013 +0800 - - Fix interface-list got none mac address. - - novaclient expect the response json body has a column 'mac_address', but - actually is 'mac_addr'. This patch is a quick fix. Just print out - "mac_addr" is readable enough. - - Fix bug: #1199706 - - Change-Id: I68823a3d719ee2f5d9d8b6227ca8eb858fc270c3 - -commit a45c49bafcd8060bb671dbc1bf15266a2a5e8d65 -Merge: a5558f8 8c4e145 -Author: Jenkins -Date: Wed Jul 10 04:09:58 2013 +0000 - - Merge "python3: Fix unicode compatibility python2/python3" - -commit b5c91018e0067a29453c6aa3963e8ce6ecf89b2f -Author: Xiao Hanyu -Date: Tue Jul 9 14:31:16 2013 +0800 - - Remove uncessary code related to nova start/stop - - 'nova start' and 'nova stop' actually send request with 'os-start' - and 'os-stop', instead of 'start' and 'stop'. - - Change-Id: I1472e1b648dae8f3b281a113adb60421a00e5a48 - -commit 912288c4862e4023cb1952ce3e37453dc5cff883 -Author: Nicolas Simonds -Date: Tue Jul 2 16:49:03 2013 -0700 - - make v2_auth and plugin_auth explictly return their results - - In cases where the respective authentication methods return - non-NoneTypes, (e.g., HTTP 305 redirects) they would get dropped - on the floor previously. - - This patch set splits the test_auth_redirect unit test into two - nearly-identical unit tests to exercise the different code paths. - Without the patch, the test_v2_auth_redirect unit test fails with - an HTTP 401 error - - Change-Id: I2018bc5b73ce86d6d5383958375d5dbbde2e763c - Fixes: Bug 1197191 - -commit a5558f8780c78a9f57d58b0c4ee706cd66bb1c06 -Author: Monty Taylor -Date: Fri Jul 5 23:11:26 2013 -0400 - - Sync install_venv_common from oslo - - The current version of install_venv_common uses the --distribute flag - in its creation of the virtualenv. This causes some upgrade problems - with the new versions of distribute and setuptools. The solution to - those problems is to get off of the distribute bandwagon. - - Change-Id: I5efe196c46b12d88c853f8362ebcbf0cc6f1573d - -commit 1b3cd6ff9e9c77dbb267d293877c0c55c3a0382e -Author: Joe Gordon -Date: Mon Jul 8 11:38:33 2013 +0200 - - Clean up and make HACKING.rst point to openstack-dev/hacking - - Instead of having a full local copy of HACKING Reference the OpenStack - hacking guide (openstack-dev/hacking) and remove duplicate sections. - - Change-Id: Iaabc27c42d74b7441c17e63db15724f64114620b - -commit d095b8a335ec7cdc61b4f2db99ae06346c0879be -Author: Sulochan Acharya -Date: Fri Jun 28 17:24:54 2013 -0500 - - CLI for disable service reason - - Adds cli option to allow users to give reason - for service-disable. Also adds disabled reason - as a column in service list, so any disabled service - can be seen with reason. - - A recent nova change that allows disable-log-reason - allows users to provide reason for disabling service. - This just adds the cli option for the method. - - Blueprint record-reason-for-disabling-service - - Change-Id: If263788c34279d6b4c568d5e0320448d2ff67a12 - -commit 02f906bcd6866b24fa0b48d47f573197b17f0753 -Author: Phil Day -Date: Thu Jun 27 22:57:10 2013 +0100 - - Allow tenant ID for authentication - - Tenant names are not necessarily unique for a User, so the client - should also allow authentication by tenant_id - - If both ID and Name are specificed then use the ID - - Fixes bug 1195454 - - Change-Id: Ib62aabc3702db88f02259cd721f9efb31404bcb7 - -commit 5c8616d03ecc271a79c6c41ce54bfbf719bb940f -Merge: e3dfc5a 07fd520 -Author: Jenkins -Date: Wed Jul 3 02:55:35 2013 +0000 - - Merge "python3: Fix print statements" - -commit e3dfc5a40711122841302f9de2f701dcc9f88b6f -Merge: c865cee a25d4fe -Author: Jenkins -Date: Tue Jul 2 22:10:45 2013 +0000 - - Merge "python3: Compatibility for iteritems differences" - -commit c865cee9a180de4a32ce590a03bdec9cd5dcc7b7 -Merge: 0bf5f49 c7e9b1b -Author: Jenkins -Date: Mon Jul 1 06:11:18 2013 +0000 - - Merge "Bring stdout/stderr capturing in line w/ nova" - -commit 0bf5f49bcbd49538845802f60faf9cd0398299df -Merge: b526c9b 0134008 -Author: Jenkins -Date: Sun Jun 30 07:12:15 2013 +0000 - - Merge "Fixup trivial License Header mismatch." - -commit 2770e059e9b5a3b36298b701e12827aea183acfd -Author: Daniel Wallace -Date: Fri Jun 28 20:19:55 2013 -0500 - - Adds zsh completion - - Use nova bash-completion to add native zsh completion using built in - parameter expansion. Nothing spectacular or new, this is mostly so that - zsh users do not need to autoload bashcompinit just to use nova. - - Change-Id: I56f62f036e0c85e79197f4c7dfd25abf7eb4110a - Implements: zsh completion - -commit c7e9b1b8dc23894f3a74e0d63591705c59f81f98 -Author: Matt Thompson -Date: Thu Jun 20 15:52:04 2013 +0100 - - Bring stdout/stderr capturing in line w/ nova - - In .testr.conf, we reference OS_STDOUT_CAPTURE / OS_STDERR_CAPTURE - while in novaclient/tests/utils.py we reference OS_STDOUT_NOCAPTURE - and OS_STDERR_NOCAPTURE. This change brings things more in line - with nova project by referencing OS_STDOUT_CAPTURE / OS_STDERR_CAPTURE - in both locations. - - Change-Id: I22efdec84bef78e99d1d95303cadade6011d76a2 - Fixes: bug #1192997 - -commit 0134008f9b305958e65eb02972b6237789189467 -Author: Dirk Mueller -Date: Thu Jun 27 21:42:11 2013 +0200 - - Fixup trivial License Header mismatch. - - The currently proposed Hacking check H103 - compares the license boilerplate header in - source files with a known good version. - Fix up the syntactical-only mismatches with - that check. - - Change-Id: Ie8861b9ded858aabb4cebbe9db656e8cccc9efed - -commit b526c9beff3f88d792d4c5a17d68f357eaf139ac -Author: Ben Nemec -Date: Wed Jun 26 13:56:57 2013 -0500 - - Remove Diablo compatibility options - - According to the fixme in the code, these should have been removed - in Folsom. - - Change-Id: If11c576e45931b72c227f51a0b8f63bc5f7dd4cb - -commit 07fd520d161b8612e8e3e33155cc633c73ee7088 -Author: Chuck Short -Date: Wed Jun 26 14:35:49 2013 -0400 - - python3: Fix print statements - - Fix print statements while running with python3. This is - due to the fact that the print() has changed between - python2 and python3. - - Change-Id: I3af57cf8925e0fcfb34981f5b72ed989ba9f6cd4 - Signed-off-by: Chuck Short - -commit abb57b693485056a077e0b8912061219e2bd4eac -Merge: 05ca996 ea47123 -Author: Jenkins -Date: Tue Jun 25 22:34:42 2013 +0000 - - Merge "Return Customer's Quota Usage through Admin API" - -commit a25d4fe59aac92eece3f080f16fdca7ffc453064 -Author: Chuck Short -Date: Mon Jun 24 08:32:05 2013 -0500 - - python3: Compatibility for iteritems differences - - In python3 dict.iteritems(), dict.iterkeys(), and - dict.itervalues() are no longer supported. So use - six.iteritems() where it is appropriate. - - Change-Id: I8b07dc2a89d790ec275d45f859e1644e9b00c837 - Signed-off-by: Chuck Short - -commit 8c4e145b926e9d29a14dbc0e3886239b312475f4 -Author: Chuck Short -Date: Mon Jun 24 10:03:19 2013 -0500 - - python3: Fix unicode compatibility python2/python3 - - Python3 enforces the distinction between byte strings and text strings - more rigorously than python2. So use six.text_type/six.u() - where appropriate - - Change-Id: I890e19cb857e10f0292aabdaebaa8e7a7bd8db23 - Signed-off-by: Chuck Short - -commit 05ca996e6757bb5241b2ed7e080344b66fda4598 -Merge: cb42b95 85a4f6c -Author: Jenkins -Date: Fri Jun 21 13:48:52 2013 +0000 - - Merge "Update help for --nic opt and make net-id or port-id required" - -commit ea4712369b55b28b804526326e42ff751f8b605b -Author: Mahesh Panchaksharaiah -Date: Thu Apr 25 13:39:41 2013 +0530 - - Return Customer's Quota Usage through Admin API - - Modified the used limits API for Admin to retrieve - the used limits for a customer. Changes done to the - nova client to fetch limits for a given tenant. - - This is related to changes made in nova, - https://review.openstack.org/#/c/27468/ - - Change-Id: Id53576eb35d6dab7cb655f8427091e95a6f75a6d - Implements: blueprint customer-quota-through-admin-api - -commit cb42b95f1f708d723482aed38427304c1348e3ad -Merge: 909a53b ee411a6 -Author: Jenkins -Date: Thu Jun 20 16:33:58 2013 +0000 - - Merge "Cells Support" - -commit 909a53b161b8936dddb40dd25e346c2cbb8db416 -Author: Eoghan Glynn -Date: Wed Jun 19 18:27:24 2013 +0000 - - Discard possibly expired token before re-authenticating - - Fixes bug 1192656 - - Previously, the attempt to re-authenticate on possible token - expiry actually re-used the expired token, which was clearly - bound to fail in the expired case. - - Now the old authentication state is discarded before attempting - re-authentication. - - Change-Id: I3fd125702061f7ac84eb501d2a488aab5b2385b9 - -commit 8baf20cb223b97d223b2580b67c054da4a8c2dc6 -Merge: 576006e 267dbd2 -Author: Jenkins -Date: Tue Jun 18 18:12:43 2013 +0000 - - Merge "Support force update quota" - -commit 267dbd292c5681daaa5659f8f2ce644a80a54a08 -Author: gengjh -Date: Sat Jun 15 10:07:49 2013 +0800 - - Support force update quota - - Once we have additional check when update quota in - https://review.openstack.org/#/c/25887/, we need provide --force option - when run 'nova quota-update'. - - Since the change in nova server has been merged, we need re-enable the - changes in nova client side. - - Fix bug 1160749 - - Change-Id: Iceb67c5816312fafed8a68e48a8a136c03d0bb5b - -commit 85a4f6cb51001ffec1ea1cea79482c82278d346b -Author: Matt Thompson -Date: Fri Jun 14 16:04:13 2013 +0100 - - Update help for --nic opt and make net-id or port-id required - - Commit updates help string for --nic option to reflect that specifying - net-id and port-id keys are optional but that at least one is - required. Additionally, we change _boot in novaclient/v1_1/shell.py - to raise an exception if random keys are added to --nic string and if - --nic string does not contain net-id or port-id keys. - - Change-Id: Icf94c395bd09160aa6a1b849eb464d72e410e1ae - Fixes: bug #1052356 - Fixes: bug #1191139 - -commit 576006ec6185b766585b07ace5f0934440874019 -Merge: 913448c be299d8 -Author: Jenkins -Date: Mon Jun 17 23:21:40 2013 +0000 - - Merge "Adds support for ExtendedFloatingIps APi extension" - -commit be299d8424074f411118b74044a5e040bda4956d -Author: Phil Day -Date: Fri May 17 12:39:46 2013 +0100 - - Adds support for ExtendedFloatingIps APi extension - - Allow a floating IP to be associated to a specific fixed IP - - This is the client side of: - https://review.openstack.org/#/c/26113/15 - - Change-Id: I05f8a0dc60268535231b95a6664719015f67a318 - -commit 913448c931040771620ff584d4e3995aef57b39f -Merge: f41b76c 7f03b09 -Author: Jenkins -Date: Mon Jun 17 16:03:52 2013 +0000 - - Merge "Migrate each instances of a host to another." - -commit f41b76cf1b8def8f8e3f60918fa26d1c13fe7730 -Merge: 52fc0ab 87bd54f -Author: Jenkins -Date: Wed Jun 12 23:32:43 2013 +0000 - - Merge "The 'nova keypair-show key_name' command added." - -commit 52fc0ab815adb8f5fcdcce31b0994536c0c1c96c -Merge: 1542a29 fa0d6e8 -Author: Jenkins -Date: Wed Jun 12 23:30:15 2013 +0000 - - Merge "Exit w/ valid code when no servers are deleted." - -commit 1542a2913a2bcb91b114c0317962698fb737d39a -Merge: 76d566b cdee7e1 -Author: Jenkins -Date: Wed Jun 12 21:09:38 2013 +0000 - - Merge "Set default value of flavorid to "auto"" - -commit 76d566b760466b23b352bfb8597f46f7a34d3aeb -Merge: 3457394 66a9896 -Author: Jenkins -Date: Wed Jun 12 02:55:35 2013 +0000 - - Merge "Add update method of security group name and description" - -commit 34573942bf1452823b29dd4e89d58a23de186f17 -Author: Monty Taylor -Date: Tue Jun 11 11:40:34 2013 -0700 - - Remove explicit distribute depend. - - Causes issues with the recent re-merge with setuptools. Advice from - upstream is to stop doing explicit depends. - - Change-Id: I729ed2f646aa514fbb7b7dfc4a070df2f7b27ff4 - -commit ee411a6a2ecbd8063e9088ac3e60075d6812c246 -Author: Kaushik Chandrashekar -Date: Mon Jun 10 14:15:06 2013 +0530 - - Cells Support - - Adding support for Cell show and Cell capacities calls - - Implements: blueprint cell-capacity - Change-Id: I83243cf224a4487d720d55d8942d28c52924b734 - -commit cdee7e12c0fbee38285d54c5143bc7274dc9f383 -Author: Jianing YANG -Date: Tue Jun 11 17:07:30 2013 +0800 - - Set default value of flavorid to "auto" - - Fixes: Bug #1189877 - Change-Id: I80a0834c5f1d264b64f14d78fa2f71b1e4d9d89a - -commit 7f03b092a4b55536af37e6b8f1ffd3a3cde1ed02 -Author: Aarti Kriplani -Date: Thu Jun 6 15:49:58 2013 +0530 - - Migrate each instances of a host to another. - - Added a new extension that adds the ability for admins to migrate all - servers of a host to another available hosts. - - Implements blueprint host-servers-migrate - Change-Id: I4e9c4be7ceb098d7a3bf553fd44addd46e8bce72 - -commit d040ac9c3f2325a85f77c43a6a2d304fb20d73f8 -Merge: 265f68c d43b923 -Author: Jenkins -Date: Mon Jun 10 17:58:51 2013 +0000 - - Merge "Delete a quota through admin api." - -commit 265f68c30e53624bee7cc16d1a1c0192a2ba655e -Merge: b12de59 96706d5 -Author: Jenkins -Date: Mon Jun 10 17:32:05 2013 +0000 - - Merge "Set/Delete metadata on all instances of a host." - -commit b12de594c4e39a97cfc66c4f0453a2be3b2468b8 -Merge: e476179 0d678ed -Author: Jenkins -Date: Mon Jun 10 14:49:03 2013 +0000 - - Merge "Evacuate each instance from one host to another" - -commit 96706d502fd6f2b5c85dfea422740269f28b89e2 -Author: Aarti Kriplani -Date: Tue Jun 4 16:15:20 2013 +0530 - - Set/Delete metadata on all instances of a host. - - Adding a wrapper for all instances of a host, to be able to set/delete - metadata for all instances at once. - - Implements blueprint tag-instances-of-host - Change-Id: I3d1a9ab54aad60bfccd0ece2285d145031fb5e15 - -commit 87bd54ff135baeddc80b9fa232fe9be1fc17db55 -Author: Sergey Lukjanov -Date: Sun Jun 2 19:37:01 2013 +0400 - - The 'nova keypair-show key_name' command added. - - * 'os-keypairs' api extension used. - - Change-Id: Idbb529135b6629f02306c49d8095b5fcf94770cc - -commit e476179c65617f61df0e804c865f5e728d83ec59 -Author: Dirk Mueller -Date: Fri Jun 7 15:58:47 2013 +0200 - - Use Python 3.x compatible except: construct - - Per (proposed) hacking H203 check, use the non-deprecated - except x as y: construct, which works with any - Python version >= 2.6 - - Change-Id: Ib7cab00cb8f219154663a4d51a855a1a2718e8cb - -commit d43b923d8a0509b39c5521153def078a422a491a -Author: Aarti Kriplani -Date: Mon Jun 3 17:33:17 2013 +0530 - - Delete a quota through admin api. - - Exposes the quota-delete api implemented as part of - blueprint admin-api-for-delete-quota - Change-Id: Iab358f0fcf2dfb41bcd9a3a5b73d590d3f55cd6c - -commit fa0d6e85a2117c61e1f4b1728d49a2c67d509cdf -Author: Matt Thompson -Date: Tue Jun 4 10:39:10 2013 +0100 - - Exit w/ valid code when no servers are deleted. - - This change updates do_delete in v1_1/shell.py to keep track of - deletion failures and raises an exception when all of the specified - servers cannot be deleted. This in turn causes nova client to exit - with a correct exit code when no successful deletes occur. - - Change-Id: I16ee7a4c754cf2e8add09a41becbcc37edc767ff - Fixes: bug #1185009 - -commit 0d678ed4bb355a80211144e698da22b287b23027 -Author: Aarti Kriplani -Date: Fri May 10 12:04:42 2013 -0500 - - Evacuate each instance from one host to another - - Added a new extension that adds the ability for admins to evacuate an - entire host to another host. This internally uses the - existing server.evacuate api. - The target host is optional so that a free host will be chosen by the - scheduler in the api. - Implements: blueprint evacuate-host - - Change-Id: I2352836d01952e281e15edb9bdd1b912106516d6 - -commit f67c5e0cf9b067ff616145579952b47a0ed2c420 -Merge: 67c8055 8820623 -Author: Jenkins -Date: Mon Jun 3 19:16:47 2013 +0000 - - Merge "python3: Introduce py33 to tox.ini" - -commit 8820623d2a32c0a314c811ad58e974c8417df225 -Author: Chuck Short -Date: Sat Jun 1 19:40:09 2013 -0500 - - python3: Introduce py33 to tox.ini - - Introduce py33 to tox.ini to make testing with - python3 easier. - - Change-Id: I2f339a2ccf113ff14db64c2bbc67a93bd0270962 - Signed-off-by: Chuck Short - -commit 67c80558b1419faa1fd648410e5b9c332a0b367b -Author: Dirk Mueller -Date: Sat Jun 1 15:49:51 2013 +0200 - - Start using Hacking and PyFlakes - - Only blacklisting those warnings that are numerous, - so that in principle Hacking and PyFlakes warnings - are tested. Fix the easy ones alongway. - - Change-Id: I571f51ebf570ac114509f2dcd71cdce281e7c70a - -commit 66a98966bf8924b01c983ac9ac31d4e45476339c -Author: Zhenguo Niu -Date: Wed May 22 16:28:34 2013 +0800 - - Add update method of security group name and description - - make it possible to edit the name and description of - common security groups, we can not rename the default. - nova patch : https://review.openstack.org/#/c/29490/ - - Fixes: bug #918393 - - Change-Id: I559f2fa09c1f205d3bbe7352fc169152e6b38586 - -commit def5df2760b38b1493548722ddd49082f3773c31 -Author: Adam Gandelman -Date: Wed May 29 14:20:43 2013 -0700 - - Fix shell tests for older prettytable versions. - - Fix the shell tests so they pass for all supported prettytable - versions, as per requirements.txt (>=0.6,<0.8). - - Fixes bug: #1185580. - - Change-Id: I8dca23faa3c178494656ebc8088b6d1994e9869f - -commit 1bb98248082d48de39df59fc081e45be1b66b2d7 -Merge: 2e84697 a8ed2f2 -Author: Jenkins -Date: Wed May 29 20:33:13 2013 +0000 - - Merge "Improve error messages for invalid --nic / --file." - -commit 2e84697bed12c58b920a13e1d15c8748536c60ef -Merge: 4b8f932 37da28c -Author: Jenkins -Date: Wed May 29 18:55:51 2013 +0000 - - Merge "Provide nova CLI man page." - -commit 4b8f932b50c7cb000ea85a5079484299dd34d0f0 -Merge: c6b913c ff85bd4 -Author: Jenkins -Date: Wed May 29 18:50:50 2013 +0000 - - Merge "100% test coverage for security groups and rules" - -commit 37da28cff4be133f19d5b48ca0257e62c1c49992 -Author: Jakub Ruzicka -Date: Fri May 24 17:37:51 2013 +0200 - - Provide nova CLI man page. - - Resolves: bug 1130815 - Blueprint: clients-man-pages - - Provide basic but hopefully useful man page. - - Change-Id: I6c520fa3acdb82dd564b758b9cdc448eecc6d6ce - -commit c6b913cbc78e582f9bf89bf74b63a6267c1b8c15 -Merge: c34c371 f2559c4 -Author: Jenkins -Date: Wed May 29 16:39:18 2013 +0000 - - Merge "Add MethodNotAllowed and Conflict exception classes" - -commit a8ed2f273adb39327e0bc1bbd33c45fefc272814 -Author: Hugh Saunders -Date: Tue May 28 15:27:20 2013 +0100 - - Improve error messages for invalid --nic / --file. - - Implemented by catching the valueerror thrown when unpacking a split to - two variables but the split string is not present. - - Change-Id: I9930fe828c932e103fdad1b88c3434f097664f31 - -commit ff85bd4025db92d318e19bd4d933848a344d5ab4 -Author: Emanuele Rocca -Date: Fri May 24 19:04:37 2013 +0200 - - 100% test coverage for security groups and rules - - This patch achieves full test coverage for security_group and - security_group_rules by: - - - Fixing the arguments used in test_invalid_parameters_create - - Testing the __str__ and delete methods of SecurityGroupRule - - Adding a test for the ___str__ method of SecurityGroup - - Change-Id: I9cfbc68761f158754aa4b339238d29cc587c91e1 - -commit f2559c4c39af60d8704b813ae0e8effa427a73a0 -Author: Brian Waldon -Date: Sun May 26 08:14:30 2013 -0700 - - Add MethodNotAllowed and Conflict exception classes - - It is expected to recieve a 405 or a 409 from Nova, but novaclient presents - them as a generic ClientException. This patch adds MethodNotAllowed - and Conflict classes to represent these HTTP responses. - - Change-Id: If89cee04ebd74daaa28ea30b5c57cdc63edc1551 - -commit c34c371e963f04f44339c07dfcd40b7814e3217f -Author: Monty Taylor -Date: Sat May 18 07:26:28 2013 -0700 - - Move tests into the novaclient package. - - tests/__init__.py implies a package in the global namespace. These - tests are not global python tests, but rather tests for novaclient. - - Change-Id: Ifeb8082aa010d15dddc9ae02e35589bc78ad48cc - -commit 51f05965e0743dac3792cc3c88dd836b6aaefcc7 -Author: Monty Taylor -Date: Sat May 18 07:18:44 2013 -0700 - - Add CONTRIBUTING file. - - This adds a pointer to how to contribute. Also, github will show - this on the pull requests page, so having one of these is a friendly - way to let people know we don't use those. - - Change-Id: I36829798adacb0f6b8144502baeff64ca84e32b6 - -commit 3bbdcda9d23b54079733ff6f06000cf311eff629 -Author: Monty Taylor -Date: Sat May 18 07:17:04 2013 -0700 - - Rename requires files to standard names. - - The python community groks requirements.txt and test-requirements.txt as - reasonably standard files. We should use those filenames to make our - information more discoverable. - - Fixes bug 1179008 - - Change-Id: I50a7c46f880e4257fa31d7d322d7bf70b0f5d3a6 - -commit 1a0b7b0a649657e2662e62f17322f61e8d7e9ed3 -Author: Monty Taylor -Date: Sat May 18 07:11:26 2013 -0700 - - Code cleanup in advance of flake8. - - Change-Id: Ia2b463fdf3092aa72147eeda41faad4733fddd46 - -commit 9d4db6f740fe00f50c77920b5ef7a4fbd08d181f -Author: Monty Taylor -Date: Sat May 18 07:13:38 2013 -0700 - - Migrate to flake8. - - Fixes bug 1172444. - - Change-Id: I0d8faa0819738456a28aaf5cc859f510a2b3ed68 - -commit c305a458926f66d717d827dbad4596a7b22a02eb -Author: Sean Dague -Date: Fri May 24 09:04:09 2013 -0400 - - Revert "Support force update quota" - - This reverts commit e8b665edbfcd86488f75ed0b79dafdedbf8f5950. - - The previous commit created an incompatibility in using new nova - client with older nova server. Nova client needs to be always - releasable, and work with all nova server API versions out there. - - Fixes bug #1173353 - - Change-Id: I2c07d109af4a35bc3b98dedaf991d5d3cc6fdd3b - -commit c07f05ed33b382d14def6d4cef8fd194ddfc9f49 -Merge: 3f06551 e8e7a0e -Author: Jenkins -Date: Fri May 24 06:27:09 2013 +0000 - - Merge "Only add logging handlers if there currently aren't any" - -commit 3f065513a9b6cb3932a3ce8ab24ac0288a9847fd -Merge: ecbf770 d274077 -Author: Jenkins -Date: Thu May 23 15:42:55 2013 +0000 - - Merge "Convert to more modern openstack-common.conf format." - -commit e8e7a0e04fa6ced2e5a02a533d29a20d3014b4a8 -Author: Nicolas Simonds -Date: Tue May 21 16:23:50 2013 -0700 - - Only add logging handlers if there currently aren't any - - This corrects an odd problem where Horizon would stand up multiple - client objects, which would cause duplicate/triplicate/dozens of - repeated log lines in its log files, due to multiple identical - handlers being added to the logging object - - Fixes Bug 1182678 - - Change-Id: I1f3bae0a39f28412c99e5d04f4364611f2a5facb - -commit d27407798d8d7e75cfba7c31b577bc872ddb1ce7 -Author: Michael Still -Date: Tue May 21 14:42:00 2013 +1000 - - Convert to more modern openstack-common.conf format. - - Change-Id: Ib02edb34b02d63f2dcf6fa08a224e5ec1fa02525 - -commit ecbf7705d12ea63025bbd10d47b80c30e4caff52 -Author: Emanuele Rocca -Date: Wed May 22 18:24:08 2013 +0200 - - Cleanup unused local variables - - This patch cleans up a few unused local variables, found with pyflakes. - - Change-Id: Id65acc5d47380c7d6bfbbfe075dc23e1de30813c - -commit bc0ad1cb9dcee8c5c3c11a9dd894ad7c8763f147 -Author: Shane Wang -Date: Tue May 21 13:55:53 2013 +0800 - - Reuse oslo for is_uuid_like() implementation - - In the original code, isalnum() in is_uuid_like() doesn't allow "-", - while for UUID, format like aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa should be - allowed. This patch is to reuse uuidutils's API in oslo. - - Change-Id: I339974c75a32d27f8e4443a1b97bb6e410933aa4 - Signed-off-by: Shane Wang - -commit 2925d5bbdad04b3862730dccf337a9e8dd95ce21 -Merge: 986d700 20a3595 -Author: Jenkins -Date: Tue May 21 16:26:25 2013 +0000 - - Merge "Synchronize code from oslo" - -commit 986d700c553c83452c8ab0c5ab83bea449762544 -Merge: 307e1a6 b1802a5 -Author: Jenkins -Date: Tue May 21 07:56:30 2013 +0000 - - Merge "Cleanup nova subcommands for security groups and rules" - -commit 20a3595e3e1b14ca600321c9325ed5f5bd46f968 -Author: Shane Wang -Date: Tue May 21 13:49:39 2013 +0800 - - Synchronize code from oslo - - Use commit 8d0228837c40c02d93d80ae0a179275ac2d7f277 - Merge "Break out common functionality for filters and weights" - (Fri May 17 12:12:40 2013 +0000) - - Change-Id: Ib2ec8ff64e036a07fad2a38319a9a4c40a698898 - Signed-off-by: Shane Wang - -commit 307e1a601244b60bb007d35594737fb72f22ec75 -Merge: f08ac04 c9fc9b5 -Author: Jenkins -Date: Mon May 20 17:16:08 2013 +0000 - - Merge "Make ManagerWithFind abstract and fix its descendants" - -commit f08ac04a27fe6bc2969252bcc4578d12f242f1f4 -Author: Roman Podolyaka -Date: Sat May 18 11:53:18 2013 +0300 - - Migrate to pbr. - - openstack.common.setup and openstack.common.version are now in the - standalone library pbr, so all projects using those two should - migrate. - - Fixes bug 1179007. - - Change-Id: I7ac1c37f0bf148619dffff8f454db05fc192e471 - -commit b1802a59bb275b204bf8306048a466dd16aa546c -Author: Shane Wang -Date: Thu May 16 14:30:22 2013 +0800 - - Cleanup nova subcommands for security groups and rules - - The Changes include: - - Sanity check for from_port, to_port, and IP protocol when adding - a security rule - - Print one more column 'Id' for security groups - - If there are multiple security groups with the same name, the group - can't be deleted unless an ID is specified. However, there is no code - to search and delete security group by ID. So, _get_secgroup() will - get group by ID if the input is like a UUID. If not found, then get - group by name. - - Some corresponding changes for help messages. - - Test case changes after adding sanity check. - - Change-Id: Ibd82d8404bdd64e4bca2f8b25756bfaff7b28194 - Signed-off-by: Shane Wang - -commit c9fc9b5b8ff12218e26a71e0660f774bb3546eb3 -Author: Alessio Ababilov -Date: Wed May 15 16:45:01 2013 +0300 - - Make ManagerWithFind abstract and fix its descendants - - ManagerWithFind requires list() method in its descendants. - Make it abstract and fix its improper descendants that do - not implement list() (SecurityGroupRuleManager and many others). - - Fixes: bug #1180393 - Change-Id: Ic8b466a57554018092c31c6d6b3ea62f181d7000 - -commit 64e43fde43e478af8dc95ccc0904dfca0d0dbe0c -Merge: c314bd5 3c97f76 -Author: Jenkins -Date: Wed May 15 11:13:26 2013 +0000 - - Merge "Cleanup some flavor commands" - -commit c314bd587cd302ce777bad662b30ba6d87115967 -Merge: 075e9ca e745b46 -Author: Jenkins -Date: Wed May 15 11:12:22 2013 +0000 - - Merge "Fix for --bridge-interface being ignore by nova network-create" - -commit 3c97f768e5e175c1f2217be9d976fee8cbdca58b -Author: Shane Wang -Date: Tue May 14 21:47:10 2013 +0800 - - Cleanup some flavor commands - - Some cleanups include: - - Add flavor sub-commands into README.rst - - Check flavor ID when creating a flavor - - Remove check_uuid_like() because it isn't used - - Remove parameter cs in some _print_XXX functions because cs is - not used - - Change-Id: If47ce557d33db05f53e382f0670f436e05a340b7 - Signed-off-by: Shane Wang - -commit 075e9ca76ec67eb3b95fc068a60be1ee070114ed -Author: Shane Wang -Date: Tue May 14 11:21:08 2013 +0800 - - Fix the default parameter in print_list - - Because sort_index = 0 by default, "if sort_index is not None" doesn't - make any sense. - Here sort_index should be None by default, which means "donot want to - sort". - - Change-Id: I823ab75eb7a92bdc426dd96a3d1e56f187118729 - Signed-off-by: Shane Wang - -commit e745b4626e6066ea498d7b70212602bff8449fb8 -Author: Andy McCrae -Date: Mon May 13 11:21:18 2013 +0100 - - Fix for --bridge-interface being ignore by nova network-create - - Change-Id: I84b3264e9cbf78c1af27a3f2fd9690f60f710299 - Fixes: bug #1179437 - -commit 892671173d2d74636febbeeadd392d4fb89ff10f -Merge: 670cf15 eae3d72 -Author: Jenkins -Date: Sat May 11 00:06:23 2013 +0000 - - Merge "Expose retry_after attribute of OverLimit exception" - -commit 670cf1529c977d5428aaa28bd58c1f64bd0989a7 -Merge: f5b8fe2 e009bec -Author: Jenkins -Date: Tue Apr 30 07:42:53 2013 +0000 - - Merge "Adds extended status fields to nova list" - -commit f5b8fe27411881bc9ed45eaf36521aef2971074d -Merge: a3a7ebf 789d156 -Author: Jenkins -Date: Mon Apr 29 22:50:43 2013 +0000 - - Merge "Allow deleting multiple images from shell" - -commit a3a7ebfe863c047f68dd43b5c9a45ee40359750a -Author: Brian Waldon -Date: Mon Apr 29 14:05:40 2013 -0700 - - Add setuptools_git-*.egg to .gitignore - - Change-Id: I97128363b13414e9037cf54ffc52a3db405b13a1 - -commit eae3d724c08b7bf13ef2ae5588fc0df4cbcc271c -Author: Brian Waldon -Date: Mon Apr 29 11:34:24 2013 -0700 - - Expose retry_after attribute of OverLimit exception - - Fixes bug 1174469 - - Change-Id: Ic1e67f6f91d4fe2072ff68dfb36330cd86c1d5b4 - -commit e009bec2208d2f38896160a1ea677a3014f851e5 -Author: Dave Wilde -Date: Sun Apr 28 07:37:33 2013 -0500 - - Adds extended status fields to nova list - - The nova list command now includes 'Task State' and 'Power State' fields to - bring parity with the dashboard. - - * Add helper function _translate_extended_states() - to convert extended states to human - - Fixes: bug #954750 - - Change-Id: I564b7f88e9e2524d8e4ffe21a51608c5e3b23d2d - -commit 201b74b6cc4e458d3b19a948352952e53048b79f -Author: Brian Waldon -Date: Mon Apr 29 11:33:32 2013 -0700 - - Clean up exceptions.from_response - - Change-Id: I359a911c0813697f091517de493be403e8c1d8a3 - -commit 0cdc85e136fdc4755d1b60089cd5f79590466b5b -Merge: c2e5ec0 c15c8f8 -Author: Jenkins -Date: Mon Apr 29 16:11:41 2013 +0000 - - Merge "Synchronize code from oslo" - -commit 789d15608d5863f31ee0240c38998cd3e630cefb -Author: Sulochan Acharya -Date: Sat Apr 27 03:54:53 2013 -0500 - - Allow deleting multiple images from shell - - Adds nargs to image-delete to allow deleting - multiple images through cli. - - Adds shell test for multiple image-delete. - Also makes a small correction in fakes to - correct image id of the second image to 2. - - Fixes bug #1173511 - - Change-Id: I167a97cab75a6df544901e965d2cfa3c10a3958e - -commit c2e5ec05c5c11888426415f5296514f7fbdf9d4b -Merge: 50fe79b e5d2e2c -Author: Jenkins -Date: Mon Apr 29 15:52:47 2013 +0000 - - Merge "Fix nova instance-action-list output field and order" - -commit c15c8f8e97ab9eae9486101bb17021160e40b15a -Author: Alessio Ababilov -Date: Mon Apr 29 11:48:09 2013 +0300 - - Synchronize code from oslo - - Use commit 8c964a25a0904f4153eb4fbcfb3cfd4d8a357e0c - Do not import openstack.common.log in strutils - (Mon Apr 29 11:13:51 2013 +0300) - - Changes: - 8c964a2 Do not import openstack.common.log in strutils - e700d92 Replaces standard logging with common logging - 47e9e98 Fix the co-authored-by processing. - 6e8b9ba Include Co-authored-by entries in AUTHORS. - 547ab34 Fix Copyright Headers - Rename LLC to Foundation - 2cb8e45 support ISO 8601 micro-second precision - - Change-Id: Ida31e60ecac5ba89e72a1d8b0a79fd608ad19092 - -commit 50fe79b47d566bb0d15c9517b7b64d758688d853 -Author: Kieran Spear -Date: Wed Apr 24 17:55:48 2013 +1000 - - Add 'flavor-list --all' admin switch - - Nova gives admins public flavors and flavors from their own projects - only by default. For flavor management, admins need to see all flavors - regardless of access. - - Changes: - - Adds an 'is_public' argument to flavors.list() that mirrors the - Nova API. is_public=None can be used to see all flavors. - - Adds an --all switch to flavor-list in the CLI for use by admins - when all flavors are wanted. - - Fixes bug 1172179. - - Change-Id: I915cd2d8266cb6e32c80691a6ff27d8a23488c98 - -commit b9f27f6d94b22e488a5763bad5f0000417878232 -Merge: 27e904a 3396894 -Author: Jenkins -Date: Mon Apr 22 19:19:29 2013 +0000 - - Merge "Make list flavor show extra specs optional." - -commit e5d2e2c2d4c7fa413517080edad907c757737872 -Author: Leo Toyoda -Date: Mon Apr 22 14:31:02 2013 +0900 - - Fix nova instance-action-list output field and order - - 'instance-action-list' is not possible to identify the order - and time of the specified instance actions. - This patch fixes the sort of 'Start_time' and add field. - - Change-Id: If9e6aaf8eb631819bf8e1c915cb1da64d6fcd2f4 - Implements: blueprint instance-action-list-output - -commit 339689483da3c1591211762ef631d432844ff9ef -Author: Ubuntu -Date: Wed Apr 17 13:12:36 2013 +0000 - - Make list flavor show extra specs optional. - - Flavor list will get each flavors extra_specs by making fresh requests to nova. - When there are lots of flavors, the flavor list will take a while to run. So - let us make show extra-specs optional. - - Fix bug: #1166455 - - Change-Id: I86aef1035be6a88b8d9fb49a89f5a608a72589dd - -commit 27e904af69a913d1705b348e90a1dd0da58376af -Author: Roman Podolyaka -Date: Thu Apr 18 18:01:54 2013 +0300 - - Use HTTP keep-alive feature in HTTPClient class - - Currently HTTPClient creates a new TCP connection for each - API request. We could actually reuse created connections by - relying upon HTTP keep-alive feature. That would enable us - to do a few queries in a row more efficiently. - - Fixes bug 1170385. - - Change-Id: Ie6d8fb9670938e3790017509a242630b67abd794 - -commit dccdd02e4840f27d5476d3fe06967bc2718ec386 -Author: gtt116 -Date: Wed Apr 17 13:51:37 2013 +0000 - - Cleanup unused import - - Change-Id: Id7d110110f238077630c9b9ee4d643654844dd3e - -commit 74132e50788138e9f7d8ff7de88fa49290b500ee -Merge: 3a1058a 328805f -Author: Jenkins -Date: Sun Apr 14 22:49:00 2013 +0000 - - Merge "Add coverage-reset command to reset Nova coverage data." - -commit 3a1058a889d31faa5d100794cb96901b971302b4 -Merge: bb74749 2a495c0 -Author: Jenkins -Date: Thu Apr 11 20:43:50 2013 +0000 - - Merge "make sure .get() also updates _info" - -commit bb747498c48a96bef6d5f26e74e270d1819a9a48 -Merge: c230812 e8b665e -Author: Jenkins -Date: Thu Apr 11 20:43:48 2013 +0000 - - Merge "Support force update quota" - -commit c23081201779365354bc01346100d5422f43c2ea -Author: Haiwei Xu -Date: Thu Apr 11 18:00:00 2013 +0900 - - Make --vlan option work in network-create in VLAN mode - - When creating a network with network-create, DuplicateVlan exception - happens whatever the --vlan option is set. This is because --vlan - option isn't read correctly by novaclient. This patch fixes this - bug. - - Fixes bug 1167779 - - Change-Id: I3bf0e8d96d995632698f5aa1b1a07ead9e553c70 - -commit e8b665edbfcd86488f75ed0b79dafdedbf8f5950 -Author: gengjh -Date: Mon Apr 8 17:30:02 2013 +0800 - - Support force update quota - - Once we have additional check when update quota in - https://review.openstack.org/#/c/25887/, we need provide --force option - when run 'nova quota-update'. - - Fix bug 1160749 - - DocImpact - - Change-Id: Ib8d94d4eaa846f620abad5fb55017ac3fb0b322a - -commit 2a495c03d5cac4470f65c9f4dd513f3facfa6fdb -Author: Mike Lundy -Date: Wed Apr 10 14:09:21 2013 -0700 - - make sure .get() also updates _info - - Having the _info get out of sync with the actual attributes is kind of a - trap for the unwary. _info is used in preference to the attributes in - many places, and letting it get out of sync means that the method of - retrieval (get() vs. list()) influences the result. - - Change-Id: I9d9bf086fa790b811c520b2fa317f95cb1921805 - -commit 328805f2bb219f53c49084a52e5eba763e536ba8 -Author: Mitsuhiko Yamazaki -Date: Tue Apr 9 18:20:03 2013 +0900 - - Add coverage-reset command to reset Nova coverage data. - - Add a new command coverage-reset to enable users to reset - coverage data. - This also adds unit tests on coverage-reset command. - - Fixes bug: 1164331 - - Change-Id: I101e38165206224927d8ce32c8663a8d9403450b - -commit 5f3dbfdfdd9c9f05aea6833f6d7b749ceeac685b -Merge: 1216a32 8ce2330 -Author: Jenkins -Date: Tue Apr 9 10:54:33 2013 +0000 - - Merge "Fix problem with nova --version" - -commit 1216a32a287ac3c276c4ad15c70a12ab3f5d9dba -Author: Bartosz Górski -Date: Mon Apr 8 07:04:11 2013 -0700 - - Fixing shell command 'service-disable' description - - Fixes: bug #1166217 - Change-Id: I0ba609750551540f9cd91492191b222961e99fb1 - -commit 69f9971da54b46a8883148e4cef6346c7933b6ec -Author: Kevin L. Mitchell -Date: Mon Apr 8 16:38:07 2013 -0500 - - Correct a unit test failure that crept into trunk - - At some point, the "nova list" command started returning an - empty table when no results were obtained, while the - tests.test_shell.ShellTest.test_password test was expecting - a single newline. Whichever commit caused this change in - behavior somehow made it past the gate without forcing the - test to be updated. - - This commit fixes the issue by changing the output that - test_shell.test_password is expecting. - - Fixes bug 1166464. - - Change-Id: I57636b4a1e525c440925caba0bbb51bbcd94b080 - -commit 8ce233024700f70f23d26c5f68b0ffa445eccc32 -Author: Davanum Srinivas -Date: Sat Apr 6 23:07:48 2013 -0400 - - Fix problem with nova --version - - Update to latest openstack.common.version.py and fix __init__.py - to get "nova --version" to work properly again - - Fixes LP# 1165325 - - Change-Id: I29e54cd4cf79759407f3967518e9be575abd994a - -commit ea94b09ad712adcf932a4f217e4061522ad875d1 -Author: Haiwei Xu -Date: Thu Mar 28 19:42:00 2013 +0900 - - Make "multi_host" True when it is set to 'T' in network_create. - - Fixes bug 1161297 - Even if creating a network with the "--multi_host=T", the "multi_host" - property of the new network is still "False". - This is because nova server interprets 'T' to "False". - This patch fixes the problem. - - Change-Id: I171c7dc72cb515c47ea106558080eafa10dee873 - -commit 0fc4e120432c6231800e02b437f49477660caa64 -Merge: 62cf0f4 20ede68 -Author: Jenkins -Date: Thu Apr 4 06:52:09 2013 +0000 - - Merge "Fix IBM copyright strings" - -commit 62cf0f4f2238427fbdcf12e0b879d2dae61a3099 -Merge: 5073b80 90b3a1c -Author: Jenkins -Date: Wed Apr 3 03:20:00 2013 +0000 - - Merge "Allow for bypass_url when using proxy_token" - -commit 20ede68edee89340994d0a6d42122c7484062abf -Author: Kurt Taylor -Date: Tue Apr 2 18:36:18 2013 -0400 - - Fix IBM copyright strings - - Update IBM copyright strings to one consistant format - - Change-Id: Iabd059132cc3092b6dbbaa6c1f19fb93acee0a30 - -commit 90b3a1c505570eae29c74c197a9800916d8bffcd -Author: Alex Meade -Date: Tue Apr 2 15:48:44 2013 -0400 - - Allow for bypass_url when using proxy_token - - Change-Id: I1cb76f79fbf2fe02ce012aaa278f50987c073831 - -commit 5073b8080ad28bc45c22acc748919cfb2695533b -Author: Alex Meade -Date: Tue Apr 2 15:43:47 2013 -0400 - - Fix mispelt x-auth-token header - - Fixes bug 1163546 - - Change-Id: I4b40ee2be950ee2cd13217f954d72fe1e42a1d6c - -commit beda22a2bba24ec8d717fe6a8050921ec772ab2e -Merge: 0aa6200 bc2ee48 -Author: Jenkins -Date: Tue Apr 2 17:29:37 2013 +0000 - - Merge "Remove actions command from servers." - -commit 0aa6200544f0a15ab759b47091a30c6ee214a755 -Merge: d195c6a adb5941 -Author: Jenkins -Date: Tue Apr 2 16:10:35 2013 +0000 - - Merge "catch NoKeyringDaemonError from gnomekeyring" - -commit d195c6a6f7ca39c39e95c49220ed74ceb52f1afd -Merge: 3eedc20 abd75f2 -Author: Jenkins -Date: Tue Apr 2 16:10:34 2013 +0000 - - Merge "Improve authentication plugins management." - -commit 3eedc20086f842001b2ce678109fa9c0bb5c21ba -Merge: 3af3c8b 7f0df56 -Author: Jenkins -Date: Tue Apr 2 16:10:31 2013 +0000 - - Merge "Skip security groups w/ no protocol." - -commit 3af3c8b7b80e506f4081f35f1e5af59c2d9a76f4 -Merge: 49ab03e 94173a3 -Author: Jenkins -Date: Tue Apr 2 16:10:29 2013 +0000 - - Merge "Use correct filter name for listing of instances" - -commit bc2ee484f56fd105b4a66ce047fd1c422c68772a -Author: Vishvananda Ishaya -Date: Tue Apr 2 08:51:39 2013 -0700 - - Remove actions command from servers. - - It appears that this command was inherited from the original - cloudservers client code. It hasn't ever worked with nova. It - is confusing now because we have the instance actions command. - - Fixes bug 1163033 - - Change-Id: Id0b36c01cdbd5034d0a7886b809269d838c36b45 - -commit 49ab03e6a68fd5b02aaba213e7ab94468f6600ad -Author: Alan Pevec -Date: Tue Apr 2 12:16:37 2013 +0200 - - do not ignore --os-cache - - Change-Id: Ib8808da00967163faa9ce05e580605f4e499891d - -commit abd75f24b1ffc0afab51f7f6c09e3759e5465823 -Author: Alvaro Lopez Garcia -Date: Wed Mar 6 16:41:46 2013 +0100 - - Improve authentication plugins management. - - The current auth plugin system lacks some functionality to be used with - other methods that might require additional configuration options or - that do not require a user to pass some options that are now compulsory - (for example, X.509 authentication needs to get a certificate file, and - does not need either a username or a password). This commit extends - the current system to handle these extra features, while remaining - compatible with older plugins. - - DocImpact: We should documment how to implement additional - authentication plugins, such as BasicAuth, X509, etc. - Implements: blueprint authentication-plugins - - Change-Id: I7b0ef4981efba8160dea94bf852dba7e2e4068f5 - -commit 7f0df56ea355bbccd8fb5db4d557dbbf126991af -Author: Dan Prince -Date: Sun Mar 31 21:16:26 2013 -0400 - - Skip security groups w/ no protocol. - - When using Nova w/ the new Quantum security groups driver security - groups can exist which have no protocol. Theses entries - cause ERROR: 'NoneType' object has no attribute 'upper' - when you try to delete other (editable) security groups. - - This patch updates novaclient so that it skips over entries with - no protocol when determining which security group to delete. - This fixes novaclient so that deleting *any* security group works - when the new quantum security group driver is enabled. - - Fixes LP Bug #1162622. - - Change-Id: Ida07b6429eae988a9a64535381082a500f31a521 - -commit adb5941df991543b4383817a3e6f30daad42879c -Author: Davanum Srinivas -Date: Mon Mar 18 12:02:25 2013 -0400 - - catch NoKeyringDaemonError from gnomekeyring - - Looks like we need to add more exceptions, start to maintain - a tuple of exceptions - - Change-Id: I3a027f5d2d8f82fe397e3096ff82358040f3729e - -commit 593adf229aacabf66ce8aea4f147c131c9765374 -Merge: 1696954 cdab772 -Author: Jenkins -Date: Thu Mar 28 15:57:04 2013 +0000 - - Merge "Ensure shell tests use isolated env variables set" - -commit 16969543ba61a356697e1ecf0d5d39aa861101d8 -Merge: cdb583a 0206c2d -Author: Jenkins -Date: Thu Mar 28 14:58:00 2013 +0000 - - Merge "Update to latest openstack.common.setup." - -commit cdb583ae3b1d383b104194ba0e893b6ea15b6343 -Merge: 243c8ff 23ee4b8 -Author: Jenkins -Date: Thu Mar 28 13:55:55 2013 +0000 - - Merge "setuptools: remove data_files section" - -commit cdab77259a5410fe4e89e90e2d83b316216d0e9b -Author: Roman Podolyaka -Date: Thu Mar 28 13:28:37 2013 +0200 - - Ensure shell tests use isolated env variables set - - Fixes bug 1161008. - - Change-Id: Id9d76f39c898d4cff65aefa636e9dd2f092d42bd - -commit 0206c2d5dd37c3ce1440b5083574979129f12e77 -Author: Monty Taylor -Date: Thu Mar 28 06:34:53 2013 +0100 - - Update to latest openstack.common.setup. - - We actually don't need the silly versioninfo file at all anymore. - - Change-Id: Ic759c39a29b07d41a96849db84a7f9990ec8a3eb - -commit 243c8ff6a817ac3dd5d6c34407d3d6aa111b1d7c -Merge: 655765a 54d4b1d -Author: Jenkins -Date: Wed Mar 27 23:11:18 2013 +0000 - - Merge "Update tools/pip-requires for prettytable" - -commit 23ee4b818d800d08abf123a65c69213c0eff0900 -Author: Christoph Gysin -Date: Wed Mar 27 20:39:09 2013 +0200 - - setuptools: remove data_files section - - versioninfo is already included through include_package_data - - Change-Id: I53c28bd26a19d86704c918fa185cde9759140dc1 - -commit 94173a3f989c87d0dce1ecdc0ad733b4621fea44 -Author: Roman Podolyaka -Date: Wed Mar 27 16:48:02 2013 +0200 - - Use correct filter name for listing of instances - - nova list --tenant tenant_id leads to the following query to Nova API: - - GET /v2/{admin_tenant_id}/servers/detail?project_id={tenant_id} - - While Nova actually expects: - - GET /v2/{admin_tenant_id}/servers/detail?tenant_id={tenant_id} - - Fixes bug 1134382. - - Change-Id: I222208bcc9aaf547cd0b1c52dc8856123a823b8e - -commit 655765a5eac161be8209e62950ecde7b4da84d1a -Merge: f03575a 0f7404d -Author: Jenkins -Date: Tue Mar 26 05:54:48 2013 +0000 - - Merge "Add support for retrieving instance-actions info" - -commit f03575a8c742cb789c89620fc171edd5e75d426d -Merge: d7f1a71 46cd432 -Author: Jenkins -Date: Tue Mar 26 05:54:46 2013 +0000 - - Merge "Split commands properly for bash completion test." - -commit d7f1a71311dc8da730d281ac8c73618d3c00dc02 -Author: Andrew Laski -Date: Mon Mar 25 16:41:46 2013 -0400 - - Don't check build/ for pep8 violations - - There's no need to run pep8 on the build dir, and it contains E502 false - positives due to some part of the build process adding line - continuations in places that they're not needed. - - Change-Id: I7ea19aea2b9e46503aa8acc06ce6b9d7ea18113a - -commit 09c8626bdc3b6eed3e5b72d12c3095d470643a54 -Merge: f786178 114bd74 -Author: Jenkins -Date: Mon Mar 25 20:22:08 2013 +0000 - - Merge "Remove extraneous output during testing" - -commit 0f7404d7a8f5b6948ae050f6bd434483be42522d -Author: Andrew Laski -Date: Mon Mar 25 12:56:34 2013 -0400 - - Add support for retrieving instance-actions info - - Adds an extension for querying instance-actions info on an instance. - There are two new commands: 'instance-action-list ' which lists - actions that have been recorded for that instance, and 'instance-action - ' which provides more details for the action with - that request_id on that server. - - Change-Id: I22492d682d50b78f522f10269221fea9483df6dd - -commit 46cd432bc24ededc55560e84ef5ccd30384a69ff -Author: Andrew Laski -Date: Mon Mar 25 13:03:38 2013 -0400 - - Split commands properly for bash completion test. - - The bash completion test was trying to loop over some options in order - to test that they appeared in the output. This splits the list so that - proper looping occurs. This helps protect against test failures when - new options are added and the bash completion output changes order. - - Change-Id: I81517038953fb429e8d98b762c77749bbbc0e8d7 - -commit 114bd74fd2c4358ae16c0b86faf9b43c8d686344 -Author: Andrew Laski -Date: Mon Mar 25 13:38:28 2013 -0400 - - Remove extraneous output during testing - - During shell tests commands were being passed to novaclient and output - was being printed to stdout. This quickly scrolls useful test output - offscreen, so lets suppress it. - - Also removed a print call from a test. - - Change-Id: I31c8bf2f92a64d781c9e3350213f2e1503b960ad - -commit f78617803c9b34e52086b519ba5683f015418fda -Author: Roman Podolyaka -Date: Tue Mar 19 17:27:28 2013 +0200 - - Use setuptools-git to include files from the repo - - Fixes bug 1029511. - - Change-Id: I5aef29ad10ac73a9645111f993621d596321ffcf - -commit 54d4b1d355bd8be9ac358eadc425e3495d786e45 -Author: Chris Krelle -Date: Fri Mar 22 12:48:14 2013 -0700 - - Update tools/pip-requires for prettytable - - changes pip-requires from: - prettytable>=0.6,<0.7 - to: - prettytable>=0.6,<0.8 - - Change-Id: Ic04d38078ad06e43947b5e98b26576a4c51dbbb0 - Authored-by: Chris Krelle - -commit 609cbcef17cd0051ecb86bc60a29cf9c2be2517f -Author: Masayuki Igawa -Date: Fri Mar 22 21:29:55 2013 +0900 - - Fix keypair-delete help documents - - The help documents of keypair-delete parameter should indicate "name". - - Fixes bug 1158733 - - Change-Id: Ib7e648d22024828f8a4e5b3b51c5ed8f6b4dc057 - -commit 22b8856815d95a1a9920f4bdbab63f4c56dbd75d -Merge: 59f8360 b94fbf5 -Author: Jenkins -Date: Wed Mar 20 21:00:00 2013 +0000 - - Merge "Make os-services API extensions consistent with Nova" - -commit 59f8360d7e087ae99a9dcac84c6c81542aa1c94a -Author: Michael Still -Date: Sat Mar 16 06:53:37 2013 +1100 - - Add support for the new fixed_ip quota. - - Required for bug 1125468. - - Change-Id: If9f8f31a9fd35497a308ae13351685e470e20cd0 - -commit 7850fcdc0740aa86a7bdead3fe2ce42133acebdd -Merge: e9e05d7 301500d -Author: Jenkins -Date: Fri Mar 15 17:35:55 2013 +0000 - - Merge "Remove unused import" - -commit e9e05d7dfe6809adc009f79ca3ee08a332488094 -Author: Alvaro Lopez Garcia -Date: Wed Mar 13 16:47:16 2013 +0100 - - Set up debug level on root logger. - - If we set up the debug level on the root logger, this can be used by the - submodules that might need to print some debug output. - - Change-Id: I2a00b40d4748cc62e6081df7d6a44622f5ad4467 - -commit 301500d6c8931b8c884c78dc046e8950a10392ad -Author: Wu Wenxiang -Date: Fri Mar 15 12:50:57 2013 +0800 - - Remove unused import - - Remove unused import line in tests/v1_1/test_quotas.py - - Change-Id: I07b23d945a361015974b546a455d9cd5a48a5b3d - -commit c5b579926feb208c785f028d48c6eaf9c36768fc -Author: Davanum Srinivas -Date: Wed Mar 13 18:09:17 2013 -0400 - - Fix Copyright Headers from LLC to Foundation - - follow the lead from nova and oslo projects - - Change-Id: I270c5f1e4eefa4b72e292bfb4a4c60de0c3f6e4a - -commit c97707b0f20cd0cd483f0f5fd11737f7bf51e986 -Merge: d4509dd efafde0 -Author: Jenkins -Date: Wed Mar 13 21:54:13 2013 +0000 - - Merge "Use keyring for testing" - -commit d4509dd2ad1e740250f46bb281de3b6bcf39de85 -Author: Andy Hill -Date: Wed Mar 13 08:10:48 2013 -0500 - - Removes tenant IDs checking for nova quota operations. - - Until there is a way to validate tenant IDs, remove the existing checks. - - Fixes bug #1154582 - - Change-Id: If10fac17b919190c1492cfbf1be9950284a82197 - -commit c12f4bc0e37973e26c2109c7f85f505b776b5574 -Merge: f294635 65b55d8 -Author: Jenkins -Date: Tue Mar 12 20:17:07 2013 +0000 - - Merge "Revert API changes in "Unify Manager._update behaviour"" - -commit b94fbf59a2899cf08116c6f1e4eb3c4cec8666df -Author: Hans Lindgren -Date: Tue Mar 12 10:52:27 2013 +0100 - - Make os-services API extensions consistent with Nova - - Updates the os-services API extensions to match the Nova changes - proposed in I932160d64fdd3aaeb2ed90a092ecc7a36dcc9665. - - Resolves bug 1147746. - - Change-Id: Ib0f24dea8e937a8e1a1604b1cbf19d96bcdbcd8f - -commit 65b55d8f9b4ff7ccbd137e94087949a8c92c1de2 -Author: Hans Lindgren -Date: Thu Mar 7 21:49:30 2013 +0100 - - Revert API changes in "Unify Manager._update behaviour" - - This revert some of commit 63073104665ee4597cf3b7aa8dc2295a8a7db794, - specifically the changes made to the API since those changes were - never merged in Nova. - - Resolves bug 1145768. - - Change-Id: I8f83c5a33cfed0c3a659f5221b8b2e730ca9463f - -commit efafde0c4c24609f3efd851cfb6f36d8ccd1c5d5 -Author: Alessio Ababilov -Date: Mon Mar 11 16:13:15 2013 +0200 - - Use keyring for testing - - Mention keyring in test-requires as in python-keystoneclient. - So, keyring support is enabled in shell.py and tested. - - Change-Id: Icb712a07b995b47b286ed0528e04ae1d5ec195d2 - -commit f294635c16cbf56ee90647de4fb2a35c171174a1 -Author: Scott Devoid -Date: Thu Feb 7 12:15:13 2013 -0600 - - Show Tenant_ID for secgroup-list with all-tenant - - For the secgroup-list command, append the Tenant_ID - column if the --all-tenants flag is used. - - Fixes bug #1118477 - - Change-Id: If2ff108cb0aec1327ceecc47a8c5ed9a08678e51 - -commit 5c9fc0246826e4895a4f12f207b24e9792824681 -Merge: 2f2f4fc 1882b99 -Author: Jenkins -Date: Mon Mar 11 16:43:23 2013 +0000 - - Merge "Check if tenant flag is uuid_like for all quota operations" - -commit 2f2f4fcf2b80f7a6fd38bf093855ed3f89f8afd7 -Merge: b01ce12 21dca44 -Author: Jenkins -Date: Mon Mar 11 16:43:19 2013 +0000 - - Merge "Add wrap option to nova credentials for humans" - -commit b01ce12995f3533b25f074d3eb85d973364f69f6 -Merge: 9f4ef60 47e6bc2 -Author: Jenkins -Date: Mon Mar 11 16:37:11 2013 +0000 - - Merge "Decodes input and encodes output" - -commit 9f4ef600e8543b276ecbd7925bddea43b0adc858 -Merge: 219f1df 650f1c3 -Author: Jenkins -Date: Mon Mar 11 10:54:30 2013 +0000 - - Merge "Extend test coverage for v1_1/shell.py" - -commit 219f1dfb5a24e60fa1d700fd42348261472deb40 -Merge: 82704d4 f73df49 -Author: Jenkins -Date: Sat Mar 9 01:42:43 2013 +0000 - - Merge "Additional "Unify Manager._update behaviour" cleanup" - -commit 82704d4649300fdc7340fd76d9e8cdba317bc5a9 -Merge: 0e569e1 92fef8b -Author: Jenkins -Date: Fri Mar 8 20:07:04 2013 +0000 - - Merge "Remove prov_vlan_id from baremetal" - -commit f73df49e4ff79b7b48503310269b4ec908a197c5 -Author: Hans Lindgren -Date: Fri Mar 8 13:09:46 2013 +0100 - - Additional "Unify Manager._update behaviour" cleanup - - Make _update always return an instance of self.resource_class. - - This is in preparation for fixing bug 1145768 by reverting the API - changes made in the original "Unify Manager._update behaviour" change. - - This is to avoid needing to revert some of the cleanup that was made - in that change. - - Change-Id: I842bda40a0dc168689a7dd8b88433c3cebef5839 - -commit 21dca44202a3f0899a997ee8b1678017052c2731 -Author: Joe Gordon -Date: Fri Mar 1 23:07:18 2013 +0000 - - Add wrap option to nova credentials for humans - - When using Keystone PKI, a token ID can be over 3200 chars long. - Add optional --wrap option to make 'keystone token-get' human readable - By default wrap=64 (to fit in 80 char terminal). And can be turned off by - setting wrap=0 - - Fix bug 1131001 - - Change-Id: I50be7ebb4323ab1bf07af557403f5136b49080a4 - -commit 1882b99734f5b0091d3b8c2662fea26980f05327 -Author: Joe Gordon -Date: Tue Mar 5 01:55:30 2013 +0000 - - Check if tenant flag is uuid_like for all quota operations - - Fix bug 1145706 - - Change-Id: I9089ea4f968797b248f80bf84027a602e59ccd00 - -commit 0e569e1d9bdff686c131b12b08c05ff9046d8842 -Merge: b606948 f1e5a88 -Author: Jenkins -Date: Thu Mar 7 21:28:38 2013 +0000 - - Merge "Fix typo in error message" - -commit b606948593990140d2c081f43fd38078eddf28c9 -Author: Masayuki Igawa -Date: Thu Mar 7 18:49:35 2013 +0900 - - Fix nova boot --num-instances option checking - - 'args.num_instances' should be checked by None because of '0 == False'. - This patch fixes the checking. - - Fixes bug 1151787 - - Change-Id: Iede860caa5c2d03d49471f375d687c3e40102372 - -commit f1e5a88d2b4ea7cd0e3e44aa42ddbb108641c625 -Author: Alvaro Lopez Garcia -Date: Wed Mar 6 15:40:37 2013 +0100 - - Fix typo in error message - - Change-Id: Ia37ec318329dc527b30a1835e4a52ace14b2bda3 - -commit 650f1c3d5343c2997c9789e9c2d924e4507c8f32 -Author: Vasyl Khomenko -Date: Wed Mar 6 07:08:22 2013 -0500 - - Extend test coverage for v1_1/shell.py - - Added unit tests for shell code, that wasn't covered before. - - Implements: blueprint python-novaclient-unittests - Change-Id: Id9973b1edb39ab76e7a232c262ae073cf44dfc0a - -commit 47e6bc25ae647c9b83b394cfc5734490855acbe2 -Author: Flaper Fesp -Date: Mon Mar 4 18:11:54 2013 +0100 - - Decodes input and encodes output - - Currently novaclient doesn't handle properly incoming and outgoing - encode / decode process. As a solution for this, this patch implements a - decoding process for all data incoming from the user side and decodes - everything going out of the client, i.e: http requests, prints, etc. - - This patch introduces a new module (strutils.py) taken from - oslo-incubator in order to use 2 of the functions present in it: - - About safe_(decode|encode): - - Both functions try to encode / decode the incoming text using the - stdin encoding, fallback to python's default encoding if that - returns None or to UTF-8 as the last option. - - In both functions only basestring objects are accepted and they both - raise TypeError if an object of another type is passed. - - About the general novaclient changes: - - In order to better support non-ASCII characters, it is a good - practice to use unicode interanlly and encode everything that has to - go out. This patch aims to do that and introduces this behaviour in - the client. - - Testing: - - A good test (besides using tox) is to use nova client with and - without setting any locale (export LANG=). - - Fixes bug: 1061156 - - Change-Id: I20b75e42b0c3dac89f1048faa1127253a64f86c7 - -commit 8ac304f7f577ffe7d0264e1248e4ae87bd74fc65 -Author: Vasyl Khomenko -Date: Thu Feb 21 11:15:50 2013 -0500 - - Fixed bug with password prompt, added tests - - Fixes: bug #1131237 - - Change-Id: Ifcd9543ed5ac9526e32025ff3acd51d36b27a224 - -commit 39b6e00eedef66c2a13e625500c7427fb5096890 -Merge: 413bff3 feaff79 -Author: Jenkins -Date: Fri Mar 1 23:51:43 2013 +0000 - - Merge "Fixes the output of 'os-evacuate' command." - -commit 413bff3e11f4a0226b571e3560b88f9de5427885 -Merge: 29a652c e043bd1 -Author: Jenkins -Date: Fri Mar 1 23:51:09 2013 +0000 - - Merge "Accept 201 status code on POST" - -commit 29a652c60d3b816032acb18230b065bb42331688 -Merge: 4e2c829 8be810b -Author: Jenkins -Date: Fri Mar 1 23:50:42 2013 +0000 - - Merge "Fix how tests were failing due to missing attributes." - -commit 4e2c8291354c4a968efcfe1b500de23c11f01b4f -Merge: 58a780c 68e6af7 -Author: Jenkins -Date: Fri Mar 1 23:50:39 2013 +0000 - - Merge "A minimum of Python3 fixes so that installation works without errors/warnings." - -commit 58a780c95a903c42887423aef269172dcc8dcafc -Merge: 929e6d8 25ae8f0 -Author: Jenkins -Date: Fri Mar 1 23:48:41 2013 +0000 - - Merge "Allows admins to reset-network of an instance" - -commit 929e6d8913d352450a4f0072cf82553ab0123e0a -Merge: 9ab600f 8811ced -Author: Jenkins -Date: Fri Mar 1 23:01:14 2013 +0000 - - Merge "Added limit to image-list in a preparatory step toward addressing bug 1001345." - -commit 9ab600fb8030183cd58e40b2f0ac6d9fd74e46cb -Author: Vasyl Khomenko -Date: Fri Feb 22 12:59:06 2013 -0500 - - Make ip_protocol parameter in security groups rules case insensitive - - Added convert ip_protocol to uppercase. - Added tests - - Fixes: bug #1052725 - - Change-Id: I966ddad0800556b1cc848003d07d4a897ce1b9c1 - -commit feaff79919bc2d99cb190fedf140c3c30db2ba99 -Author: Alex Glikson -Date: Mon Feb 25 06:35:27 2013 +0200 - - Fixes the output of 'os-evacuate' command. - - Change-Id: I5f02e66f316acdd10df42bec3f6628a8efe5fd97 - Fixes: bug #1132790 - -commit aac5767894c81b69dc40337a7ac61a5072eeb42c -Author: Rami Vaknin -Date: Sat Feb 23 16:23:27 2013 +0200 - - Update the docstring of cloudpipe-configure command - - Change-Id: Iab820200664618769f11b2d21a3731ef6b81a877 - -commit e043bd1560e6f2f071870c2be09748163fe70b97 -Author: Gordon Chung -Date: Fri Feb 22 13:33:40 2013 -0500 - - Accept 201 status code on POST - - On POST requests, keystone should return '201 Created' according to - api docs. - - Related to but not dependent on: - https://bugs.launchpad.net/keystone/+bug/1131119 - - Change-Id: I04c398ad7946f5ddcfd2059e4f8d97608e5d0ed3 - -commit 8be810b59cb5877d5324f706abf9e6941b5603e3 -Author: Joshua Harlow -Date: Fri Feb 22 18:15:08 2013 +0000 - - Fix how tests were failing due to missing attributes. - - Fixes: bug #1131845 - - For unknown reasons all tests continued to pass even after - this change was introduced, besides that being a very odd thing - to have happen it is better to fix said attributes for those - that are running the tests individually in there own CI pipelines. - - Change-Id: Iee6acc1d4a528afb840459ca47d754ec7bae8f32 - -commit 34c8a6bb7ad605b107a6f89b7018284811b5fadf -Author: Davanum Srinivas -Date: Thu Feb 21 11:41:02 2013 -0500 - - Missing import for gnomekeyring - - follow on to previous attempt to fix to bug 1116302, - looks like we missed an import - - Fixes LP#1116302 - - Change-Id: If56e3cedaa63a594907bb851a2701bd64806ed85 - -commit 68e6af73bafde67894780e5d2317084847109edf -Author: Thomas Schreiber -Date: Wed Feb 20 09:46:57 2013 +0100 - - A minimum of Python3 fixes so that installation works without errors/warnings. - - Fixes bug: 1130937 - Change-Id: I740652fcd5804fc1c120fc409afdf4693c8e5781 - -commit 25ae8f077051ffd2b9348e22e991694722b962a3 -Author: Sulochan Acharya -Date: Wed Feb 20 08:12:44 2013 -0600 - - Allows admins to reset-network of an instance - - Adding some functionality to allow admins to call on - resetNetwork action. Fixes bug #1130766 - - Change-Id: I3d0945b115d565bd2c54a5526ba51036e941a28f - -commit 92fef8b29169e69d1adfee8fb7378003a408f0c9 -Author: Arata Notsu -Date: Wed Feb 20 08:49:03 2013 +0900 - - Remove prov_vlan_id from baremetal - - In nova, this parameter is not used - (and will be unacceptable soon) - - Change-Id: I072a204bef49940fb2ddc8dc44480b570bc3212c - -commit 5c8caf06e9003ea8f9dd055da6f576d22be41104 -Author: Dan Smith -Date: Mon Feb 18 10:16:36 2013 -0500 - - Add support for os-attach-interfaces - - This is dependent on nova change: - - I4f8f677af58afcb928379e5cf859388d1da45d51 - - Related to blueprint network-adapter-hotplug - - Change-Id: Ieef603e85c6557cbfd2fe4ae7109e6ca235ba51d - -commit 8811ced00738059d4aee9db0d586eb8724bb1055 -Author: Anita Kuno -Date: Sun Feb 17 01:53:40 2013 +0000 - - Added limit to image-list in a preparatory step toward addressing bug 1001345. - - Currently novaclient doesn't use the limit or marker params. - As a step to addressing bug 1001345 which requires pagination, - this patch introduces the use of limit as an option - passed to the image-list function. - - Change-Id: Ia32f9e923b4eb9bcdde3b7bc1722c59d7791d104 - -commit f35635be470b29398a267d1bc92fac3af46e851f -Author: Vasyl Khomenko -Date: Mon Dec 17 10:58:08 2012 -0200 - - Extend test coverage (shell, fping) - - Added unit tests for shell code, that wasn't covered before. - - Implements: bp/python-novaclient-unittests - Change-Id: I76e3df05d53e6c08e224feb30eb90ae819d8cdce - -commit 85785309fa9c6e7c743caab28b4f3107e928d453 -Merge: 23d4561 e800196 -Author: Jenkins -Date: Fri Feb 15 23:43:22 2013 +0000 - - Merge "Support showing extra fields in server list" - -commit 23d45611b95aaf0e91df3d3a600e4cd242d7587c -Merge: 76bacaa 430ef70 -Author: Jenkins -Date: Fri Feb 15 23:41:49 2013 +0000 - - Merge "Avoid doing a deep copy on the availability zone manager" - -commit 76bacaa64566857f78860be83952070e3ac10a81 -Merge: 28653e8 c0e85a8 -Author: Jenkins -Date: Fri Feb 15 23:41:42 2013 +0000 - - Merge "Allow extensions to provide a name when discovered on the python path." - -commit 28653e855092641a98800c5bfc8b6eb634cf2afc -Merge: 7ca20df a926216 -Author: Jenkins -Date: Fri Feb 15 23:40:34 2013 +0000 - - Merge "Expand and improve baremetal API." - -commit 7ca20df4fa305f343cc567ee382193832390e4d7 -Merge: 60fd879 c97879a -Author: Jenkins -Date: Fri Feb 15 23:40:31 2013 +0000 - - Merge "Fix nova availability-zone-list for admin users" - -commit 60fd879f9bb573dc3c8c4f2b0f25280a3b27b5ca -Merge: 1324652 9f0cf6a -Author: Jenkins -Date: Fri Feb 15 23:40:25 2013 +0000 - - Merge "Make availability_zone in aggregate_create optional" - -commit 132465231a1517aa79c5fad0eb4949a7e02bd763 -Author: Davanum Srinivas -Date: Thu Feb 14 20:58:01 2013 -0500 - - Issue when gnomekeyring is present but not the current backend - - Issue was identified in the review for the previous - patch for bug 1116302. Took this chance to rename _IOError - to a better name (KeyringIOError) - - Change-Id: I321353d519eaebea27617702f92ecafe2052eb8e - -commit 430ef7071e8ea86b71fd4d266bb175549980dff1 -Author: David Scannell -Date: Thu Feb 14 15:28:52 2013 -0500 - - Avoid doing a deep copy on the availability zone manager - - When novaclient is in debug mode then the HTTPClient will - configure its logger with a StreamHandler that holds an - instance of thread.lock, which cannot be copied. As a result - running novaclient with the --debug flag will cause errors - and mask real issues being debugged. - - Fixes bug 1123561 - - Change-Id: Idf19d62ff3e5b02b029f9089f403a697164231ac - -commit c0e85a84b0ef60047f9435ef5035d0f65e446847 -Author: David Scannell -Date: Wed Feb 13 13:47:45 2013 -0500 - - Allow extensions to provide a name when discovered on the python path. - - Using novaclient with some extensions via python code, you might have an - invocation like this: - - extensions = shell.OpenStackComputeShell()._discover_extensions("1.1") - novaclient = Client("1.1", user, apikey, project, authurl, extensions=extensions, - endpoint_type=shell.DEFAULT_NOVA_ENDPOINT_TYPE, - service_type=shell.DEFAULT_NOVA_SERVICE_TYPE) - - If you have an extension like 'myextension.py' in the v1_1/contrib directory, you'll - end up with a very sensible attribute on the resulting novaclient object, i.e. - - novaclient.myextension - - If you have a package distributed in the package myextension_python_novaclient_ext, - then it'll automatically be picked up as an extension (awesome!) but the name is not - as intuitive. - - novaclient.myextension_python_novaclient_ext - - This patch simply changes this to allow the Extension to provide a name for itself. - The possibility of collisions exists, but is not really any more significant than - before (where you might have different versions of the same package installed in the - system or heck, even a bizarrely named 'myextension_python_novaclient_ext.py' in the - contrib/ directory). - - Fixes bug 1058366 - - Change-Id: Ie68463ffd7a939744e035b20fd50a7dc8da605de - -commit d1d4f33aca4f9753dd31972ea53ddc831b52fbfc -Author: Davanum Srinivas -Date: Mon Feb 11 15:55:33 2013 -0500 - - Fix IOError with gnomekeyring.find_network_password_sync - - find_network_password_sync throws a gnomekeyring.IOError - when a non-root user tries to run nova client - from a ssh console. If we don't catch this exception nova client - throws the traceback (shown in the bug report) and stops. - If we catch this exception (just like we catch ValueError), - and return None, Nova client executes just fine. - - Fixes LP# 1116302 - - Change-Id: If6937b3f8eafb1dc55224b2ca2bd0f93ae07f8c6 - -commit a92621680895282a2a24065314e4bcea8fdc688c -Author: Chris Jones -Date: Tue Feb 12 21:17:05 2013 +0000 - - Expand and improve baremetal API. - - This adds an additional command to list the interfaces associated with a - baremetal node. - - It also fixes some docstrings and renames the existing interface - commands to be more consistent with the node commands. - - Change-Id: Ia6ae383d76adb1c9d632bf69ec22438f1412c66f - -commit 67b3db2bbcf2813f3ea99e28a445cb5e0c92f618 -Merge: 0933c64 2b81789 -Author: Jenkins -Date: Wed Feb 13 02:03:55 2013 +0000 - - Merge "Corrects 2nd argument type for logging" - -commit c97879a3f24ac51a8b7673590445014eeb046381 -Author: Joe Gordon -Date: Tue Feb 12 23:22:34 2013 +0000 - - Fix nova availability-zone-list for admin users - - Don't need to convert returned timestamp - - Fix bug 1123381 - - Change-Id: I1dbc82475b44b8d321fffb512083fc7a3b13153d - -commit 9f0cf6a54719fff845c7446dbba89f5e9503564c -Author: Joe Gordon -Date: Tue Feb 12 22:55:08 2013 +0000 - - Make availability_zone in aggregate_create optional - - Aggregates do not require an availability zone any more, but in order to - keep the current API, allow for availability zone to be set to None (the new - default value) - - Fixes bug 1123468 - - Change-Id: I216c4fc808a91b0a5f602ee02ae1bca46adb73f4 - -commit 2b81789f1a86c4446aea20465cccbe08e3a820ae -Author: Victoria Martínez de la Cruz -Date: Tue Feb 12 11:46:02 2013 -0300 - - Corrects 2nd argument type for logging - - Fixes a regression introduced in commit - c73afa9fd1df14bff9186c1e73ac8f3593ef81db. - - This completely breaks Horizon in last - DevStack version. - - Change-Id: Ib754c6ea325534399a34ff76a290475ac652fea9 - Fixes: bug #1122958 - -commit 0933c64251b24e1558676ef7f9d6ab446e386fea -Author: Mitsuhiko Yamazaki -Date: Mon Feb 4 14:08:52 2013 +0900 - - Add format options to 'nova coverage-report'. - - This adds --html and --xml options to 'nova coverage-report' - to enable selection of coverage report format. - If specifying none of these, text-formatted report will be created. - - This also adds --combine option to 'nova coverage-start' to make sure - that 'nova coverage-report --html' works fine. - - Fixes bug 1114766 - - Change-Id: I9fee26bd5c45cac35f425ac7abbced4e2f3ff4df - -commit 0db2ff24c6e7e9104fbe1edc867297a40642ffcb -Merge: 320e2ff 2eeab72 -Author: Jenkins -Date: Mon Feb 11 20:25:52 2013 +0000 - - Merge "Fix run_tests.sh --coverage" - -commit 320e2ffc005f534be6a84050a38fd8e5de35c480 -Merge: c73afa9 0b4590c -Author: Jenkins -Date: Mon Feb 11 17:33:20 2013 +0000 - - Merge "Mask permissions on private key files" - -commit c73afa9fd1df14bff9186c1e73ac8f3593ef81db -Author: Sascha Peilicke -Date: Mon Jan 21 12:00:54 2013 +0100 - - Update to requests >= 0.8 - - The requests module dropped all configuration with the 1.0.0 release. - There's no danger_mode and no 'verbose'' mode. The former - shouldn't be necessary anymore and the latter can be done by setting - a different log handler for the request.logging root logger. - - Change-Id: Iec169ef6e39097814cdbf1b777bc0590236692ba - -commit 0b4590cb2438b4ec1fd8842d7ae3f2627059cabc -Author: Zane Bitter -Date: Fri Feb 1 09:39:07 2013 +0100 - - Mask permissions on private key files - - When using "nova x509-create-cert", the private key should be written to - a file with the permissions 0400, not (world-readable) 0644, in line - with how ssh private keys are treated. - - bug 1112605 - - Change-Id: I0b20378efba38fa58f4ad9a33cd15b3432ebb8a2 - Signed-off-by: Zane Bitter - -commit 2eeab72aee2a278c591b9dba5b1723d47ddb90b8 -Author: Kieran Spear -Date: Mon Feb 11 11:21:26 2013 +1100 - - Fix run_tests.sh --coverage - - Looks like a couple of typos crept in here preventing coverage - generation. - - Change-Id: I08a61a67dadc5dcd334f9f288d8ee6719d469ca1 - -commit e8001968607492218cce4c2a408e54836f627212 -Author: Kieran Spear -Date: Thu Feb 7 19:24:11 2013 +1100 - - Support showing extra fields in server list - - Adds a --fields argument that sets the fields to display. - ID is always displayed. - - Fixes bug #1076473 - - Change-Id: If3462e6a490ea16da4834a7f40f96b111c9e8227 - -commit 1ea7e65d851caa21d9ff746f67ba00c47d1bf4ad -Merge: dae0337 17b251d -Author: Jenkins -Date: Sun Feb 10 02:35:42 2013 +0000 - - Merge "management_url not set by authenticate method" - -commit dae03378c7358567295bc72198848697a9ddc387 -Merge: 4516efa 3724528 -Author: Jenkins -Date: Sun Feb 10 02:35:40 2013 +0000 - - Merge "Update .coveragerc" - -commit 17b251d8b064595470accd0769c03de840d7394c -Author: Sean McCully -Date: Fri Feb 8 14:54:36 2013 -0600 - - management_url not set by authenticate method - - Fixes Bug 1109243. - If management_url not set, raise UnAuthorized exception, - otherwise url chaining methods fail and cause NoneType - exceptions. - - Change-Id: I19e87a5dcfcf93b4fa1d423bd99de352679fa16d - -commit 3724528db78e2ff1f8b475b0ff58e4fbf5291bbf -Author: Alessio Ababilov -Date: Wed Feb 6 16:47:06 2013 +0200 - - Update .coveragerc - - Set up proper source and omit options. - - Change-Id: I966256a3a3bd37b438e98e7bcf1402482c42b567 - Implements: blueprint update-coveragerc - -commit e389e8a6b4505bcb86fb9ed60881c322009675e0 -Merge: ef6aaa8 cda7f7a -Author: Jenkins -Date: Tue Feb 5 18:58:06 2013 +0000 - - Merge "Fix default format of 'nova coverage-report'" - -commit 4516efa8db29f9b551f24efe1045d015c5c16cdb -Author: Zhi Yan Liu -Date: Tue Feb 5 15:14:18 2013 +0800 - - Show the summary or details of all availability zones of a region - - Adding "availability-zone-list" sub-command allow user list all - availability zones and its status in a region. - * summary list for normal user: list availability zones summary whitin a - flat view. - * details list for administrator user: list availability zones details - within a tree view, include zones, hosts and components. - - Implement one workitem for bp:show-availability-zone - - Change-Id: Id87fe470c7e0f6fbfb9465551f63717724b5fc18 - -commit ef6aaa88f8750afc5b372ae561a6b4cd1f813452 -Merge: f905b6b 7a95186 -Author: Jenkins -Date: Tue Feb 5 04:32:31 2013 +0000 - - Merge "Live migration with an auto selection of dest." - -commit f905b6bd5b8f0a0e95bcfb8edb85a98bb49664dc -Merge: 96630b8 7f8f3ce -Author: Jenkins -Date: Tue Feb 5 04:32:28 2013 +0000 - - Merge "Add help about the id 'auto' for flavor-create" - -commit 96630b8248bc51a0a9dd111dd3cac170a237813e -Author: Joe Gordon -Date: Fri Feb 1 12:13:19 2013 -0800 - - Upgrade to pep8 1.3.3 - - Also expand scope of what is covered by pep8 test - - Change-Id: Ifc8924914b5a0d625bc8df6442ee85eb21459cde - -commit 3ca976d4a076c13c7d68de859a8821cc281c9271 -Author: Anita Kuno -Date: Fri Feb 1 14:44:51 2013 +0000 - - Fixed 7 pep8 errors. - - Change-Id: I2d509ed383fd8d6cef91dd0c58a51eafc6995bda - -commit 7a95186047e4945a5543bcb335095c40ab1c1b76 -Author: Svetlana Shturm -Date: Fri Feb 1 13:30:26 2013 +0000 - - Live migration with an auto selection of dest. - - Change-Id: I2e0880b0e5b0565e138ad7f72d88ccd7e431e79f - Blueprint: live-migration-scheduling - DocImpact: - -commit 0c55976957169e07a317969b10cb4282ad518587 -Merge: e31a650 c8a6c6b -Author: Jenkins -Date: Fri Feb 1 06:31:12 2013 +0000 - - Merge "Add usage command to show usage for single tenant" - -commit 7f8f3ce0f8be26cda74230c260d863127b147bdb -Author: Masayuki Igawa -Date: Fri Feb 1 13:50:56 2013 +0900 - - Add help about the id 'auto' for flavor-create - - The id parameter of 'nova flavor-create' can be specified 'auto' now. - But the help document is not mentioned about that. This patch fixes it. - - Fixes bug 1112154 - - Change-Id: I6df71746a0036c6b6d05467e28343fad2972c128 - -commit e31a650be294b1a749be50ca0fb9ba3d2a8c5cde -Merge: 9d23923 1e4a778 -Author: Jenkins -Date: Fri Feb 1 06:00:46 2013 +0000 - - Merge "Store tenant_id from keystone and use for quotas" - -commit cda7f7a5050e88bc99bfdd823cfff625dc5933ea -Author: Mitsuhiko Yamazaki -Date: Thu Jan 31 17:44:48 2013 +0900 - - Fix default format of 'nova coverage-report' - - 'nova coverage-report' returns an error because nova server returns - error if the format is HTML and combine is False. - And 'nova coverage-start' and 'nova coverage-report' do it now. - - After applying this patch, we can avoid this problem and text format - report is created when we use 'nova coverage-report' - - Fixes bug 1110972 - - Change-Id: Ib3d05453de638157152a50ea814e44e6cbc19348 - -commit c8a6c6b10e9b9ebfd9f72dba769ced3fae7b985f -Author: Vishvananda Ishaya -Date: Thu Jan 31 12:30:58 2013 -0800 - - Add usage command to show usage for single tenant - - The usage-list command is admin-only so add a usage command so - that users can see their usage like they do in horizon. Only - admins can see usage for other tenants, so default the value of - tenant to the tenant_id of the current credentials. - - Change-Id: Icd6fec36f1f4145b92b227031e5df23db11737f0 - -commit 1e4a778bf85c20d81f475f9cb04fe8c94a1753d5 -Author: Vishvananda Ishaya -Date: Thu Jan 31 11:51:29 2013 -0800 - - Store tenant_id from keystone and use for quotas - - Some calls in nova require a tenant_id when it could be interpreted - from the current authentication data, so save the tenant id and - use it in the quotas command if tenant_id is not specified. - - Change-Id: I89647cfe9da73bc474ef80a61a5678db42a5571c - -commit 9d239236b9bf40e45bc4ec73fad4f1cff5e6aa37 -Author: Arata Notsu -Date: Thu Jan 31 10:45:31 2013 +0900 - - Show the details of the added bare-metal resource - - On subcommand baremetal-node-create or baremetal-add-interface, - the details of the added resource (a node or an interface) are - printed. This is useful in a script (e.g. devstack). - - Some refactoring are also included. - - Change-Id: I25f019f3dda33de5b49ab2c5442762283be1cf5a - -commit 1e1d95d5592039fc2b342bc7918d56449adbec82 -Merge: 8d825c6 364ef41 -Author: Jenkins -Date: Wed Jan 30 23:45:32 2013 +0000 - - Merge "Fix bash completion on osx" - -commit 8d825c61c984303968d01abcf7ae60ca32da4af2 -Merge: 7c6f538 7b2097e -Author: Jenkins -Date: Wed Jan 30 22:10:48 2013 +0000 - - Merge "Migrate from nose to testr." - -commit 7c6f538cf6bc86ecfd9cb25f1bf7f14a6652b592 -Author: Joshua Harlow -Date: Wed Jan 30 12:53:35 2013 -0800 - - Fix the usage of password, keyrings, and tokens. - - Fix how you keep on getting prompted for the password - all over the place and at the wrong time (the keyring code - should be used before a auth request, and not during). - - Fix this by trying to use the token first (which comes from - the keyring module), then falling back to using the password - (which will get a token, and then store said token so that it - isn't fetched again). - - Change-Id: I58e69f3b3fbcc7a467797f25695b7ca59178a1d7 - -commit b5b37108cc8ed758d280d9afa4cf5801dc7f6950 -Merge: a510afd b0e0319 -Author: Jenkins -Date: Wed Jan 30 01:32:42 2013 +0000 - - Merge "Added homedir path expansion for keypair-add." - -commit b0e0319c6656a42040c7d5a0670548249634b665 -Author: Anita Kuno -Date: Tue Jan 29 16:38:36 2013 +0000 - - Added homedir path expansion for keypair-add. - - Change-Id: I76c5454952824dc9c238d82af74f82ae5fc888b5 - Fixes: Bug #1065366 - -commit 7b2097e706e944ce868e633467b89f728a5d5042 -Author: Monty Taylor -Date: Mon Dec 24 19:58:11 2012 -0600 - - Migrate from nose to testr. - - Run tests with testr for parallel execution. - - Part of blueprint grizzly-testtools. - - Change-Id: I38e8a2df12678002e19264a53bad26e80265c6e4 - -commit a510afdbdf5597dee182ff39025d15679c8c0223 -Merge: 972663b e2edcef -Author: Jenkins -Date: Tue Jan 29 20:04:40 2013 +0000 - - Merge "_get_secgroup returns first group even if multiple groups match" - -commit 972663b64f1f8eccd429b1e7531cb997d0a4a4ae -Merge: c70144a aecd984 -Author: Jenkins -Date: Tue Jan 29 20:04:38 2013 +0000 - - Merge "Adds baremetal nova API support" - -commit c70144aced21fa705755d0c7724e2599dd7aeb26 -Merge: fb3a32a 168636e -Author: Jenkins -Date: Tue Jan 29 20:04:35 2013 +0000 - - Merge "Check tenant_id's format in "nova quota-update"" - -commit fb3a32a9ec5ed6b29f45c91b1e59050425ee2444 -Merge: 3c700ff 0614ae7 -Author: Jenkins -Date: Tue Jan 29 20:04:33 2013 +0000 - - Merge "ClientExceptions should include url and method" - -commit 3c700ffe3bb7c6d96f4b888403aa90f6cb13b133 -Merge: dbc186a ffe13ef -Author: Jenkins -Date: Tue Jan 29 20:04:29 2013 +0000 - - Merge "RateLimit does not have method attribute" - -commit dbc186aa880f86308ae2d3c6dbd3b664830b9ce7 -Merge: 1206969 f9aa5ec -Author: Jenkins -Date: Tue Jan 29 20:03:36 2013 +0000 - - Merge "make print_dict split strings with newlines into multiple rows" - -commit 12069693d1b0ccd41006dd1801e61f4102636960 -Merge: 4e0035b 3b72eb8 -Author: Jenkins -Date: Tue Jan 29 20:03:32 2013 +0000 - - Merge "Allow for image selection using the metadata properties." - -commit 4e0035b70d4ae813c4b6b4b219365726dc3c9363 -Merge: 7b6f0be 9fd2c8a -Author: Jenkins -Date: Tue Jan 29 20:03:29 2013 +0000 - - Merge "Allow request timeout to be specified." - -commit e2edcef40d8e3faa06126e9b9a01458c3cd14672 -Author: Aaron Rosen -Date: Fri Jan 25 15:01:12 2013 -0800 - - _get_secgroup returns first group even if multiple groups match - - Nova's security group api layer ensures that a given tenant is not able to - create multiple security groups with the same name. That said, if one is the - admin user and does: - "nova secgroup-delete " - The first security group that is returned with that name will be removed, - which might not have been what the user intended to do. In addition, quantum - allows multiple security groups to be created with the same name therefore - this change is needed to ensure the correct behavior when nova has a quantum - security group proxy. - - Fixes bug 1105542 - - Change-Id: I99734355026e2ad18056c2f4180b5740fda8775a - -commit 364ef418b4b71336cec52869718056a1b6ce2273 -Author: Vishvananda Ishaya -Date: Fri Jan 25 15:46:01 2013 -0800 - - Fix bash completion on osx - - The osx version of sed does not support \s so replace uses of it - with [ ] and clean up the regex a bit. - - Change-Id: Ic6fd2e4234352ddb8ec70d42b44ad00a3906db0e - -commit 168636e744012f264310897603eb4e3dde6d1df8 -Author: Haiwei Xu -Date: Wed Dec 26 11:24:55 2012 +0000 - - Check tenant_id's format in "nova quota-update" - - Fix bug 1088835 - "nova quota-update" command is executed without checking the format of - the tenant_id argument. The tenant_id should be in the format of UUID. - The tenant_id of quotas should be in accord with the form of keystone's - tenant_id. So this patch checks the format of the tenant_id when "nova - quota-update" command is executed. - - Change-Id: I47c4f2ff9adbab5da4697270dcf024ac88e24529 - -commit 0614ae75f6f92ba990a55a355bfec97438b9fb15 -Author: Sean McCully -Date: Wed Jan 23 11:14:41 2013 -0600 - - ClientExceptions should include url and method - - Fixes Bug 1103557. - novaclient abstracts out http request from user/client - making it unknown to user what root cause behind nova client - exceptions being raised. By including url and method in exception - handling, this allows user to handle accordingly. - - Change-Id: I1a509bb932b3fd029bd0870ab699a39e21da19bb - -commit 7b6f0be8004bad874f642efaabee72dd60ad92c4 -Merge: 5b8099c 3e190c5 -Author: Jenkins -Date: Wed Jan 23 16:38:15 2013 +0000 - - Merge "Ensure list output function can support non-sorting printing" - -commit aecd98430a53a6dc5258f19c81cb013001b4d338 -Author: Chris Jones -Date: Tue Jan 22 13:58:25 2013 +0000 - - Adds baremetal nova API support - - This implements the various REST API calls that BareMetal adds to Nova. - (The nova API is implemented in review 19077) - - Change-Id: I187862e9aa5dea41a7edf716aa75cc3d9982fbc8 - -commit ffe13ef94aceb527dfcbb54603cf652d8b60a97f -Author: Sean McCully -Date: Tue Jan 22 16:12:02 2013 -0600 - - RateLimit does not have method attribute - - Fixes Bug #1103220. - RateLimit class raises Exceptions anytime __repr__ - is called because cls does not have method attribute. - - Change-Id: I7db2e1a3afddaae18d006e0cc884e9910afb8eaf - -commit f9aa5ec834410c0e5d37d14ba701344e91941cfc -Author: Melanie Witt -Date: Thu Jan 10 01:27:33 2013 +0000 - - make print_dict split strings with newlines into multiple rows - - When printing a dict e.g. "nova show" one of the properties - is "fault". When the user is admin, "details" of the fault - is shown, which includes a backtrace. This causes the - printing of the table to be unreadable as the backtrace - overflows the table row. This patch adds a separate row - for each substring after splitting on newlines. - - Change-Id: I4c1bc8725a2bb6970be2c884c5e044d9eade8302 - -commit 3b72eb886f4e7e29a14467469f0873bffdca3033 -Author: Joshua Harlow -Date: Mon Jan 14 16:52:47 2013 -0800 - - Allow for image selection using the metadata properties. - - Instead of forcing users to remember a image name and/or uuid - instead allow them to specify a image metadata property to 'key' - off of. - - For example: - - I want to boot a image of ubuntu. This could now be a property - set in the image metadata and the following could be used to - find said image. - - $ nova boot my-vm --image-with type=ubuntu - - Now that user does not need to care what ubuntu version is being - selected or what the uuid is or what the image name is, they just - know that some image with ubuntu will likely get selected. - - Change-Id: Ifaf71e282b8411d2e303cb52fd2623f6cf0bf32a - -commit 5b8099cd0e86443697192fcdd58633a2550b4d4c -Author: Daniel P. Berrange -Date: Wed Jan 2 18:37:25 2013 +0000 - - Add support for get_spice_console RPC API - - Add the new get_spice_console API mirroring the impl of - the existing get_vnc_console support. - - Blueprint: libvirt-spice - Change-Id: Id549de57ebbed95dc01749838ed539b3b47efc8b - Signed-off-by: Daniel P. Berrange - -commit 3e190c5e494f6a5a77fdaec781ea947978e25ff2 -Author: zhiyanliu -Date: Thu Jan 17 11:51:46 2013 +0800 - - Ensure list output function can support non-sorting printing - - Ensure list printing function in utils can handle non-sorting - calls. Allow result list can be formatted and outputted without any - sorting field, keep natural order to the list printing. Adding necessary - checking to avoid prettytable (0.6.1 for me) exception: "Invalid field - name: None!". - - Fix bug: #1099732 - - Change-Id: Ied869d987e608fff8b8b5f5a65d21e02f0cebeaa - Signed-off-by: zhiyanliu - -commit 9fd2c8a59da7e7e328f4813f6fbc834fc560b25d -Author: Joshua Harlow -Date: Fri Jan 11 21:44:56 2013 -0800 - - Allow request timeout to be specified. - - Add a new cli argument (--timeout) which - is by default 600 seconds which will be - set in the requests library so that timeouts - can occur correctly. - - Change-Id: I716ac15fe08f42c9464ee43010bc8fd2667bcbde - -commit 020ff909cc312da0e67f293ea14a81423dac6b15 -Author: Vishvananda Ishaya -Date: Fri Jan 11 14:30:41 2013 -0800 - - Implement get password for novaclient - - This will download and decrypt a base64 encoded encrypted password - from the os-server-password extension. It depends on the user - having openssl installed, but if there is an error of any kind it - will print out the encoded and encrypted password instead. - - It also implements clear_password which will delete the password - so it can no longer be retrieved. - - Change-Id: I2c4e6c3f03b70dc98d6d339381648a6058f46e21 - -commit 24087862c72bc8b4fc05108baf408075900f8016 -Merge: 0295fca 020de7c -Author: Jenkins -Date: Tue Jan 15 19:53:14 2013 +0000 - - Merge "Fix a couple of broken shell tests" - -commit 0295fca1a2e9a2558e7672541063547e21c9b185 -Merge: 38fb974 b5f3307 -Author: Jenkins -Date: Tue Jan 15 19:53:12 2013 +0000 - - Merge "Update hosts API action calls (startup etc.)" - -commit 38fb9743e0548aed8a09e911d26ed34d71cb8c98 -Merge: fe7d791 207969f -Author: Jenkins -Date: Tue Jan 15 19:53:10 2013 +0000 - - Merge "When logging request include request data" - -commit fe7d7919931b68b7280b1c4738552a467a67a741 -Merge: c9e8666 9e319ec -Author: Jenkins -Date: Tue Jan 15 19:53:06 2013 +0000 - - Merge "Add support for instance evacuate." - -commit c9e8666111807ee5ca7c1e0cd8b234f3ab78cb25 -Merge: 6daef75 2d3e0d9 -Author: Jenkins -Date: Tue Jan 15 19:53:02 2013 +0000 - - Merge "Fix the help text of add-fixed-ip" - -commit 6daef75d5030b9204423abe170de1aaf20911f47 -Merge: dffd415 53aee5c -Author: Jenkins -Date: Tue Jan 15 19:16:11 2013 +0000 - - Merge "Move from untitest2 to testtools." - -commit dffd415fba15c177cc3b809194159cacfd44772f -Author: Matt Dietz -Date: Tue Dec 18 15:03:55 2012 +0000 - - Adds tenant network support to the client - - Modifies novaclient, changing the existing networks implementation to a - more appropriate os-admin-networks namespace, and supplements with a - tenant-base network extenion that lives under the os-networks namespace - as a Nova API extension. Also removes from the duplicately named network - test methods. - - Implements: blueprint tenant-networks - - Change-Id: I54c9f017b86fc413f1646c7bded8cebd94f6a287 - -commit 7b124b88723b31dab079de36700cecfcc2c86332 -Merge: 4410339 6f58066 -Author: Jenkins -Date: Mon Jan 14 19:40:48 2013 +0000 - - Merge "Update functionality of coverage extension." - -commit 6f580661f647bf5085edff75689eb28565728acb -Author: Matthew Treinish -Date: Thu Jan 3 17:11:06 2013 -0500 - - Update functionality of coverage extension. - - Change If1aa25fc7237e9bb5100d2a4a8e560f0a68eba61 adds additional - functionality to the coverage extension. Mainly returning the - data file path for the 'stop' action and adding support for - generating html reports. This commit adds support for this new - functionality. - - Change-Id: Icd147350d5c038f6b9c8063e77a75370eb8422e9 - -commit 020de7cebc774cdb6518ddc9070b5a5309da9a0a -Author: Vishvananda Ishaya -Date: Fri Jan 11 14:56:23 2013 -0800 - - Fix a couple of broken shell tests - - Pyflakes picked up a couple of duplicated names. Rename the one - that is correct and delete the incorrect one. - - Change-Id: Id4af1269a030be5a725bbbbcf3400341b09fddc3 - -commit b5f3307e8013d5817eee5022dd026e06caef792f -Author: Alessio Ababilov -Date: Thu Jan 10 20:49:22 2013 +0400 - - Update hosts API action calls (startup etc.) - - These calls are now implemented as normal - POST os-hosts/{host_name}/action requests. - - Change-Id: I8cd401e3b4e552c6787d1f984041ad3c345e6eca - -commit 207969f6cdcc965895238586fc011bdbdd2173bf -Author: Andrew Laski -Date: Thu Jan 10 11:20:07 2013 -0500 - - When logging request include request data - - When the --debug flag is used it should print out the body of a POST - request. It did that previously but the kwargs dict used for the - request stopped using 'body' which is what the logging relied on. This - changes it to use 'data' which is a string representation of what was in - 'body'. - - Bug 1098241 - - Change-Id: I82f36e59b459706d9d5a3a38563a45c80e84c6e2 - -commit 9e319ece374c7208668f4c2e3a31f1e7be21562f -Author: Kravchenko Pavel -Date: Mon Jan 7 18:46:59 2013 +0200 - - Add support for instance evacuate. - - This adds support for server evacuation from failed host. - Adds CLI command: - - nova evacuate [--password pwd] [--on-shared-storage] - - Depends on the approval of change: - https://review.openstack.org/#change,17991 - - Change-Id: Icd91c0484b2db532861e23163d043737ad04117a - -commit 4410339a453f8385809cd62a3a0289efc3964157 -Merge: e31023f 6307310 -Author: Jenkins -Date: Fri Jan 4 18:02:46 2013 +0000 - - Merge "Unify Manager._update behaviour" - -commit 2d3e0d949e5d2b63c13a0f82b0ab2b4227a5a3e1 -Author: Nikola Dipanov -Date: Fri Jan 4 17:03:08 2013 +0100 - - Fix the help text of add-fixed-ip - - Makes the help text of the add-fixed-ip less confusing by pointing out - that the IP address is taken from the given network and assigned to the - server. - - Change-Id: Iaf4641f65a5872ee70273d5b972ff5da0ddd7b1d - -commit 53aee5cf4b66c98c1142a57244d7466249e44f1f -Author: Monty Taylor -Date: Mon Dec 24 19:11:38 2012 -0600 - - Move from untitest2 to testtools. - - Use testtools as the base testclass. Use fixtures library for managing - fixtures. - - Part of blueprint grizzly-testtools - - Change-Id: Iac5af286b988787acf7049344641aadf140b9398 - -commit e31023fee104ff69fd14a01703b8e62aeff088a1 -Merge: 4cf314b eb7c390 -Author: Jenkins -Date: Thu Jan 3 19:29:57 2013 +0000 - - Merge "Update README.rst" - -commit eb7c3907d18a639a095b39b5d44b5c15a21adea2 -Author: Lorin Hochstein -Date: Mon Dec 31 16:29:53 2012 -0500 - - Update README.rst - - Update the README to remove PENDING links to non-existent docs, and - to remove Rackspace-specific references. - - Change-Id: I08311e0da3d181c3817573be93f6eed6e15e3812 - -commit 63073104665ee4597cf3b7aa8dc2295a8a7db794 -Author: Alessio Ababilov -Date: Sat Dec 22 20:12:20 2012 +0400 - - Unify Manager._update behaviour - - Now _update call usually returns an instance of self.resource_class. - This simplifies the code and makes novaclient closer to keystoneclient. - - Also, update hosts and services API according to changes on nova. - (If50a6b6e20f9b3fe66d486bb9b15d3eb4b62daf9). - - Change-Id: I447e49e5fce0afba8a9c1a5df6dfa7200cc93e18 - -commit 4cf314b2ecb1d6138b925d0b3f96cea9646cd022 -Author: Ken'ichi Ohmichi -Date: Sun Dec 23 04:51:56 2012 +0900 - - Fix some usage messages of 'nova volume-*' - - 'nova volume-show', 'nova volume-delete', 'nova volume-snapshot-show' - and 'nova volume-snapshot-delete' can be specified by ID or name as - the argument. - But that is not described on the usage messages. - This patch fixes the usage messages. - - Fixes bug 1093172 - - Change-Id: I3dcdd2aca923e9304efd9ea7b467d5b81cd642a7 - -commit fba20df12c376185eecfa21a4f54b66a72fc5365 -Author: Yaguang Tang -Date: Thu Dec 20 17:55:33 2012 +0800 - - add num_instances option for nova boot. - - fix bug #1092475. - - Change-Id: I584b27c1f24c6a5183a2289e77580f204db2e4db - -commit aa1df04badd0b1326be9aff0512948b85804f621 -Author: Dean Troyer -Date: Tue Dec 18 14:05:29 2012 -0600 - - Use requests module for HTTP/HTTPS - - * Implement correct certificate verification - * Add --os-cacert - * Rework tests for requests - - Pinned requests module to < 1.0 as 1.0.2 is now current in pipi - as of 17Dec2012. - - Blueprint: tls-verify - - Change-Id: I9a25a94c8dfcaf483c4c8328439809d65cf10b38 - -commit ac2ed549e58396ed471c759388ece9dbc07432a2 -Merge: c946fd2 eaf3c36 -Author: Jenkins -Date: Thu Dec 20 18:08:29 2012 +0000 - - Merge "Specify some arguments by name." - -commit c946fd2b8400177ca1fbd0bc50eb158e8db4c6c6 -Merge: c819312 9937419 -Author: Jenkins -Date: Thu Dec 20 18:05:28 2012 +0000 - - Merge "Fix find for alphanumeic flavor id/name" - -commit c81931226db3d4e9e8e0f85d3722b8f27879378c -Merge: e6e22db c59de35 -Author: Jenkins -Date: Thu Dec 20 17:38:49 2012 +0000 - - Merge "Add support for the coverage extension." - -commit 993741988804fcba6efbab0cf182300c779c00e5 -Author: Rohan Rhishikesh Kanade -Date: Sun Dec 16 23:18:39 2012 -0800 - - Fix find for alphanumeic flavor id/name - - Fixes LP bug #1089299 - - Change-Id: Ia9cc756b85096532acfc9ecacd1330de8a765fba - -commit e6e22dbe77cbcb9e2078ab8574ebb75575ab2168 -Author: Eoghan Glynn -Date: Wed Dec 19 20:07:41 2012 +0000 - - Make --tenant a required arg for quota-show - - Fixes LP 1088519 - - Previously, novaclient was incorrectly defaulting to the tenant name - as the tenant ID when retrieving quota thresholds via the os-quota-sets - API extension, in an apparent attempt to default to the current tenant - if no specific tenant is explicitly requested. - - As a result, the default quotas were always returned, regardless of - whether there were specific overridden quotas for this tenant. - - We now require that the --tenant option is always specified for the - quota-show verb, as a sensible default isn't always possible - (because the tenant ID may be opaque to the client, for example when - the auth token is cached in the keyring from a previous call out to - keystone - now the tenant ID is of course generally embedded in the - nova publicURL retrieved from the service catalog, but that is not - guaranteed to be the case, i.e. I don't think we can safely make - assumptions about that URL format). - - This change also makes the quota-show verb more consistent with the - quota-update verb, which currently requires that the tenant is - always explicitly specified. - - Change-Id: I1706ad993059e70ca0e2f3bcf7b1d06cbcc39f2d - -commit c59de35be22abec7351c6b8b3dbb53f79eaafe92 -Author: Matthew Treinish -Date: Wed Dec 12 16:32:35 2012 -0500 - - Add support for the coverage extension. - - This adds support for the coverage extension and also adds 3 - CLI commands to interact with coverage: - - nova coverage-start - - nova coverage-stop - - nova coverage-report - - 'nova coverage-report' has a required '--filename' argument - which gives the filename for the generated report files. - - Change-Id: I9cb002b0e32cfe5572878d2c8436270663c0ae96 - -commit eaf3c366c34c64f2e0a6ce0ada2b2db7ff09fc5b -Author: Ken'ichi Ohmichi -Date: Wed Dec 19 04:23:36 2012 +0900 - - Specify some arguments by name. - - 'nova boot', 'nova flavor-key', 'nova flavor-show' and the other subcommands - can be specified by a flavor name also. - But 'nova flavor-delete' and 'nova list --flavor' cannot, also 'nova list - --image' cannot be specified by a image name. - I feel it is user-friendly that a user can specify arguments by name. - - By this patch, a user can do it like the following. - - Before appying this patch: - $ nova flavor-delete m1.tiny - ERROR: Flavor m1.tiny could not be found. (HTTP 404) (Request-ID: req-af2c049f-1b77-42cf-a9ed-a3914626bc83) - $ - $ nova list --flavor m1.tiny - ERROR: Flavor could not be found (HTTP 422) (Request-ID: req-dbfd5df2-77d7-4a71-a3e6-b1f7fd25b96c) - $ - $ nova list --image cirros-0.3.0-x86_64-uec - - $ - - After appying this patch: - $ nova flavor-delete m1.tiny - $ - $ nova list --flavor m1.tiny - +--------------------------------------+--------+--------+------------------+ - | ID | Name | Status | Networks | - +--------------------------------------+--------+--------+------------------+ - | 2f003e0e-bfdf-4f56-bdf9-276732e640a0 | test01 | ACTIVE | private=10.0.0.2 | - +--------------------------------------+--------+--------+------------------+ - $ - $ nova list --image cirros-0.3.0-x86_64-uec - +--------------------------------------+--------+--------+------------------+ - | ID | Name | Status | Networks | - +--------------------------------------+--------+--------+------------------+ - | 2f003e0e-bfdf-4f56-bdf9-276732e640a0 | test01 | ACTIVE | private=10.0.0.2 | - +--------------------------------------+--------+--------+------------------+ - $ - - Fixes bug 1091814 - - Change-Id: Ic7f6ce76608a448dea3c151bc349391fbf3fa456 - -commit 8d3650048a34f5c900b01d2f72d8fc50beff87ac -Merge: df8db07 35b1896 -Author: Jenkins -Date: Fri Dec 14 15:14:11 2012 +0000 - - Merge "Add optional argument to include reservations in os-used-limits" - -commit df8db07495984c6158e4c1e1d218c10594439c5e -Merge: e2c549e 08d0c05 -Author: Jenkins -Date: Thu Dec 13 16:10:21 2012 +0000 - - Merge "Add nova client support for nova-manage agent command" - -commit e2c549e066aa18340f1c5c16a2954e4c699de8dc -Merge: 3928f7e 80a72e1 -Author: Jenkins -Date: Thu Dec 13 00:38:59 2012 +0000 - - Merge "Makes the OS_NO_CACHE env variable work again" - -commit 80a72e1a92aa103a07286060b9cf34444afd5526 -Author: Vishvananda Ishaya -Date: Wed Dec 12 15:41:31 2012 -0800 - - Makes the OS_NO_CACHE env variable work again - - The commit to replace --os-no-cache with --os-no-cache works fine - with the cli options, but the env variable is stored in os_cache - which has the opposite of the intended effect. This patch converts - the variable to a bool and then inverts it before it stores it - in os_cache. This makes it work properly again. - - Fixes bug 1089696 - - Change-Id: Iea12806603ecdc39c6475ad4d6f867ebb1e01633 - -commit 35b18965e496f5c05dde9ba177edc4bafb97efe2 -Author: Julie Pichon -Date: Wed Dec 12 16:55:10 2012 +0000 - - Add optional argument to include reservations in os-used-limits - - Fixes bug #1089271 - - Change-Id: I01a3823a4f4b1045e4f8e35f749fc9233bef4489 - -commit 3928f7e80bd1b98f19994605c84219f6f077d76d -Merge: e483455 2dc70a1 -Author: Jenkins -Date: Wed Dec 12 18:32:30 2012 +0000 - - Merge "Fix argument checking method for 'nova list --flavor' command." - -commit 08d0c05013483e89054bf8c0261c24965a4b40b1 -Author: ivan-zhu -Date: Mon Nov 12 17:04:49 2012 +0800 - - Add nova client support for nova-manage agent command - - This add four CLI (agent-list/agent-create/agent-delete/agent-modify) - in nova-client - - so we can use: - 'nova agent-list' like 'nova-manage agent list' with one optional - parameter. Show a list of all agent-builds. Filter by hypervisor. - The difference between the two commands is that 'nova agent-list' - will display the id of the agent build, 'nova-manage agent list' - will not. - - 'nova agent-create' like 'nova-manage agent create'. It will create - a agent build. - - 'nova agent-delete id' will delete the agent-build with specific id. - - 'nova agent-modfiy' will update the version, url, md5hash of the agent - build with specific id. - - This patch depends on https://review.openstack.org/#/c/15831/ - Implements one workitem of blueprint apis-for-nova-manage - - Change-Id: Ic7589077d130efa5abc77252bd79addcaea483c8 - -commit e483455a1281412a8b38a483a3f167a2fd27f5d9 -Author: Dan Prince -Date: Fri Dec 7 11:47:49 2012 -0500 - - Adds --os-cache to replace old --no-cache. - - Deprecates the old --no-cache option in favor of --os-cache. - - The old CLI args (--no_cache and --no-cache) and ENV option - (OS_NO_CACHE) are still supported but no longer show up - in help. - - The new option for --os-cache can also be set via the OS_CACHE ENV - variable... which now defaults to False. This should be much more user friendly. - - Fixes LP Bug #1087776. - - Change-Id: I3cea089c7e11ce75f22c2d7f3242b02b80441323 - -commit f37bbae5f6771a6b94f22213e91abda8f6b7c3d3 -Merge: fe2ea84 cf70a2d -Author: Jenkins -Date: Tue Dec 11 17:55:03 2012 +0000 - - Merge "Adds support for security group/rules quotas." - -commit fe2ea846bbdf3eacd86ee81515ddf1911c2e805f -Merge: 409314d b6e1430 -Author: Jenkins -Date: Tue Dec 11 17:28:07 2012 +0000 - - Merge "Fix a wrong substition for '-h' in bash completion" - -commit 409314d91898ae5c0069023a9310df1f9a2130a2 -Merge: 6795ad1 68e98fb -Author: Jenkins -Date: Tue Dec 11 17:27:47 2012 +0000 - - Merge "add host-update help info param." - -commit cf70a2d6f6d950b872a7f47ec5350b01121e5c9f -Author: Dan Prince -Date: Thu Nov 29 14:40:48 2012 -0500 - - Adds support for security group/rules quotas. - - Updates novaclient's quota and quota_class handlers to support - the security_groups and security_group_rules quotas that are now in - Nova. - - Fixes LP Bug #1084682. - - Change-Id: I04d90681d535124d7d497e06e8c1ea4f2cb8f4f4 - -commit 6795ad1ab21dd83ccc372e1e155483c691544384 -Merge: 1c5d52b 99647e2 -Author: Jenkins -Date: Tue Dec 11 17:10:36 2012 +0000 - - Merge "Fixed nics param ignored when bdm is specified" - -commit 1c5d52b2d54c81aff7288347d16bc5e81eb1b3bb -Merge: 64b4676 f279433 -Author: Jenkins -Date: Tue Dec 11 16:44:34 2012 +0000 - - Merge "Adds support for key_pairs quota." - -commit 64b4676c6b092e9815f0732c07ecacd51bdd2336 -Merge: cdb2b5e 955b94c -Author: Jenkins -Date: Tue Dec 11 16:44:11 2012 +0000 - - Merge "Adds support for injected_file_path_bytes quota." - -commit cdb2b5e14246f5827a39616a1e5e5a9ac0361cb4 -Merge: 6c1a0ca e68b834 -Author: Jenkins -Date: Tue Dec 11 16:29:16 2012 +0000 - - Merge "Adds nova client support for nova-manage network command" - -commit 6c1a0ca5bd02ecb11b7748188f06078b9c4516cf -Merge: 1378ddd 4e3aa56 -Author: Jenkins -Date: Tue Dec 11 14:12:04 2012 +0000 - - Merge "Adds nova client support for nova-manage floating command" - -commit 1378ddd4436cf3b0252705a088022e7cec2d95ed -Merge: 18deaf4 00aa8cf -Author: Jenkins -Date: Tue Dec 11 14:03:30 2012 +0000 - - Merge "Add nova client support for nova-manage account scrub command" - -commit e68b834fcfb0beb278e95f6bf5fdfacc3e7c1e1d -Author: Chris Yeoh -Date: Mon Nov 26 13:00:23 2012 +1030 - - Adds nova client support for nova-manage network command - - Adds the following commands: - - nova network-disassociate - - nova network-associate-host - - nova network-associate-project - - nova network-create - - This patch depends on https://review.openstack.org/#/c/15491/ - - Change-Id: I44c7d0bf6ba545cf1ed6f6f8390bab836fe52f9d - Implements: blueprint apis-for-nova-manage - -commit 68e98fbcb6bf859b4934b3419f3679f615cae495 -Author: Yaguang Tang -Date: Mon Dec 10 20:35:14 2012 +0800 - - add host-update help info param. - - fix bug 1084445 - - Change-Id: I042927a4abf73636d592cd5a3379a6d575f761a4 - -commit 2dc70a17a45f2e9d2a81f6de1c8c3a9da6f1563f -Author: Ken'ichi Ohmichi -Date: Mon Dec 10 09:39:32 2012 +0000 - - Fix argument checking method for 'nova list --flavor' command. - - According to Vish's comment for patchese 1, flavor-id is uuid/int - and it is a problem that uuid cannot be specified in 'nova list --flavor'. - This patch fixes the problem. - - Fixes bug 1076818 - - Change-Id: I7d216efb59c7f567067ca19b695c7f93de009bd6 - -commit b6e14300ca5f78633d51b9f3edc297efb12abc58 -Author: Akihiro MOTOKI -Date: Sat Dec 8 03:25:21 2012 +0900 - - Fix a wrong substition for '-h' in bash completion - - Fix bug #1087808 - - Change-Id: I4b90e892997105027076428c5f3dd8c42b682cb2 - -commit 99647e23a2e393bc7c176dd8b8f0f3f76ebb5103 -Author: Unmesh Gurjar -Date: Thu Dec 6 05:34:00 2012 -0800 - - Fixed nics param ignored when bdm is specified - - 1. Fixed the issue of 'nics' parameter getting ignored in boot - command when block_device_mapping is specified. - 2. Added unit test coverage. - - Fixes LP: #1004572 - - Change-Id: I1b720b8527406ee664f084167426f778793a436f - -commit f279433e53fd09ff1574b1c2204da08f36a1c694 -Author: Dan Prince -Date: Thu Nov 29 14:29:33 2012 -0500 - - Adds support for key_pairs quota. - - Updates novaclient's quota and quota_class handlers to support - the key_pairs quota that is now in Nova. - - Fixes LP Bug #1084674. - - Change-Id: I0eb357a5f7d5dba73f002066ea381cec818f1492 - -commit 955b94c1f7b7c8a181312ef9d323878b068c641b -Author: Dan Prince -Date: Thu Nov 29 14:14:44 2012 -0500 - - Adds support for injected_file_path_bytes quota. - - Updates novaclient's quota and quota_class handlers to support - the injected_file_path_bytes quota that is now in Nova. - - Fixes LP Bug #1084672. - - Change-Id: I2156816fd09bdd388e3acb8143b041e927f33511 - -commit 4e3aa56fe77e47f0b2eba057d751e2459fb88913 -Author: Chris Yeoh -Date: Wed Nov 28 18:39:15 2012 +1030 - - Adds nova client support for nova-manage floating command - - Adds the following commands: - - nova floating-ip-bulk-list - - nova floating-ip-bulk-create - - nova floating-ip-bulk-delete - - Change-Id: Ia183a7a478d23fee3552d43a866ba96abb7472b2 - Implements: blueprint apis-for-nova-manage - -commit 18deaf47918e5baa655fabb9776d294571363608 -Merge: fef3af7 494040d -Author: Jenkins -Date: Thu Nov 29 19:11:11 2012 +0000 - - Merge "Remove unnecessary casts in flavor create." - -commit fef3af70725be74763d4ad95c624407dfde25b2a -Merge: 926b334 27d7ad9 -Author: Jenkins -Date: Thu Nov 29 19:10:38 2012 +0000 - - Merge "Validate that rxtx_factor is a float." - -commit 926b334613169d59f91d522218d3418a69952d98 -Merge: c4f0f50 4f6419b -Author: Jenkins -Date: Thu Nov 29 19:10:19 2012 +0000 - - Merge "Adds nova client support for nova-manage vpn command" - -commit c4f0f50a2a8f043f66cb010fbcf1e2ec5b7dcd23 -Merge: b2338b9 3839d28 -Author: Jenkins -Date: Thu Nov 29 18:51:08 2012 +0000 - - Merge "Adds nova client support for nova-manage fixed command" - -commit b2338b9a33547f600233b21bc64e74985327ce70 -Merge: b9d60c1 ff69e4d -Author: Jenkins -Date: Thu Nov 29 18:50:20 2012 +0000 - - Merge "Implement fping calls in nova client" - -commit 494040d7fe36ddd00c8813a6e894e53b1abf31be -Author: Dan Prince -Date: Tue Nov 27 11:05:53 2012 -0500 - - Remove unnecessary casts in flavor create. - - We already cast and validate these variables above... no - need to cast them again. - - Change-Id: I87b967925ae77c70eb07a42f3ae050703d44a427 - -commit 27d7ad9d8632bdc67e25757a42a91109e393fbf9 -Author: Dan Prince -Date: Tue Nov 27 10:59:43 2012 -0500 - - Validate that rxtx_factor is a float. - - Nova stores rxtx_factor as a float internally and as such - novaclient should validate that a float is specified - when creating a flavor. - - Fixes LP Bug #1083651. - - Change-Id: I75f9440d3fe2a0e72ea592f2259640623400ae73 - -commit 4f6419b5553e853f5720084ba01fc0b4cc1f6220 -Author: Chris Yeoh -Date: Mon Nov 26 14:21:35 2012 +1030 - - Adds nova client support for nova-manage vpn command - - Adds "nova cloudpipe-configure" command - Adds shell tests for cloudpipe-list and cloudpipe-create commands which - already exist - - This patch depends on https://review.openstack.org/#/c/15854/ - - Change-Id: I784f5bf0f25a2d8cae4b7c2c6ccf345842ffe352 - Implements: blueprint apis-for-nova-manage - -commit b9d60c1fd2f887992fc1f6c2246b1f0f11efe1a9 -Author: Joe Gordon -Date: Mon Nov 26 14:26:53 2012 -0800 - - Fix aggregate command help messages. - - Fixes bug 1083343 - - Change-Id: I315a0629bb33480952f2280b053b8db8cb83a1ea - -commit 00aa8cf9ee2b9063b4aff2a70eaf30e5f4203959 -Author: ivan-zhu -Date: Sun Nov 25 20:00:55 2012 +0800 - - Add nova client support for nova-manage account scrub command - - This add a CLI in scrub in nova-client. - - so we can use "nova scrub project_id" like "nova-manage account - scrub project_id".It will delete data associated with project. - - Change-Id: I6e76fe4357fcdc3765f3ece70d9b6b07c23b59bd - -commit 3839d284da8bb269ca392727f0716ddc2238b880 -Author: Chris Yeoh -Date: Thu Nov 22 22:43:59 2012 +1030 - - Adds nova client support for nova-manage fixed command - - Adds the following commands: - - "fixed-ip-get " - displays information about the fixed ip ip_addr - - "fixed-ip-reserve " - reserves the fixed ip ip_addr - - "fixed-ip-unreserve " - unreserves the fixed ip ip_addr - - Change-Id: I6a5c8b9f7ab359adeb57b86240279649cd421801 - Implements: blueprint apis-for-nova-manage - -commit ff69e4d3830f463afa48ca432600224f29a2c238 -Author: Alessio Ababilov -Date: Mon Nov 19 11:33:50 2012 +0200 - - Implement fping calls in nova client - - Implements blueprint novaclient-fping - - Provide fping API calls in nova client as well as unit tests. API is - accessed by `fping` field of nova client. - Methods: - * list(all_tenants=False|True, include=[VM ids], exclude=[VM ids]) - - perform fping for all VMs in current project (or all projects if - all_tenants==True) - * get(server object or id) - perform fping for single instance - - Change-Id: Ic3eda142781d1a14f2cfc83626672a579fc93a7d - -commit dc6285c810b696949597dcde6717bb3f3a6c47c9 -Author: Julie Pichon -Date: Wed Nov 21 18:16:17 2012 +0000 - - Expand help message for 'migrate' to explain how the new host is selected - - Fixes bug 1078247 - - Change-Id: Iedfd6fc957fd1c2e53f7685b02bd33e16d9342e9 - -commit 572c8bbf8020c2bcd3d6e529574ee8866ba3cbea -Merge: 0173a3c 3fd0c77 -Author: Jenkins -Date: Wed Nov 21 17:18:08 2012 +0000 - - Merge "Boot from volume without image supplied" - -commit 0173a3cd7085502ac1b9cd39858e5cc9de16bb02 -Merge: 1558d5d e9b015c -Author: Jenkins -Date: Wed Nov 21 17:18:01 2012 +0000 - - Merge "Cleans up the flavor creation code. Fixes bug 1080891." - -commit 1558d5d537d89852339a01a18bb8cbb4198bbb52 -Merge: 92de98c 3ea4ba9 -Author: Jenkins -Date: Wed Nov 21 17:12:04 2012 +0000 - - Merge "Added --extra-opts to the nova ssh command" - -commit 92de98c8f68cc22b88dd164ca473eb86dbf1e45a -Merge: bc141de 5d5df17 -Author: Jenkins -Date: Wed Nov 21 17:12:03 2012 +0000 - - Merge "fix hypervisor-servers for hypervisors without servers" - -commit bc141de141e5e9796f4b1c0891e90cda65d726f5 -Merge: f790ccc aac4fff -Author: Jenkins -Date: Wed Nov 21 17:12:01 2012 +0000 - - Merge "Make sure create_image returns result" - -commit f790ccc6bc05a60b378bb7555083d8a8a228fb46 -Merge: 89c46e6 c819c2f -Author: Jenkins -Date: Wed Nov 21 17:10:15 2012 +0000 - - Merge "make tenant id optional for quota-defaults and quota-show" - -commit 89c46e6325f588069e951397fe2522e28d153c36 -Merge: 47355b7 d037172 -Author: Jenkins -Date: Wed Nov 21 17:09:23 2012 +0000 - - Merge "Add nova client support for nova-manage service command" - -commit 47355b741b50a63227fb38e6be6b485902efe3e5 -Author: Nikola Dipanov -Date: Fri Nov 16 10:00:46 2012 +0100 - - Improved quota output - - This patch makes the output of quota show a bit more informative - by not setting a simple None to a non-existing quota, but not showing it - all together. - - Kind of fixes bug #1078906 - and also bug #1078089 - - Change-Id: Ic42837d218a80f37e0c6d56625c9804d076f444c - -commit 3fd0c77d07419606a81f257b8876394ec5b374de -Author: Nikola Dipanov -Date: Wed Nov 7 18:58:58 2012 +0100 - - Boot from volume without image supplied - - Allow for booting instances from volume without the image parameter - supplied. This change is related to the change - I530760cfaa5eb0cae590c7383e0840c6b3f896b9 - in opnestack/nova. It allows for boot to work with no image supplied - to accommodate booting from volumes only. - - It also makes it possible to interpret show servers that were started - without images, so from volumes only - - Change-Id: I5ba9b0f35a5084aa91eca260f46cac83b8b6591e - -commit 3ea4ba9fc97b05ad93af8f9aa6f6bc2a638b9a36 -Author: Nick Shobe -Date: Sat Nov 17 04:26:08 2012 -0600 - - Added --extra-opts to the nova ssh command - - This will allow for remote command execution and advanced ssh options - like portforwarding and connection sharing. - The goal is to support ssh commands like - nova ssh fe55adc9-cb1e-44a4-bd36-6a537b238172 --extra-opts='-NfnMS ~/.ssh/master-fe55adc9-cb1e-44a4-bd36-6a537b238172' - and ssh fe55adc9-cb1e-44a4-bd36-6a537b238172 --extra-opts='-t "sudo puppet agent --test"' - This will alow easier scripting of the cli... It is not intended - however to replace using the nova python api. Therefore I kept it simple. - - Change-Id: Icce811caf637fc92c6d6374bfb846ea9525a7e05 - -commit e9b015c7e14843784debc0d68cfe070c9778f80d -Author: Gabriel Hurley -Date: Sat Nov 17 18:18:48 2012 -0800 - - Cleans up the flavor creation code. Fixes bug 1080891. - - Change-Id: Idc76cd01d1537ab87723a05ab8dd81015284e3c8 - -commit aa8d44c551643bb97e039624d602bd4ad07cbe9c -Author: Paul Voccio -Date: Fri Nov 16 11:34:12 2012 -0600 - - Adding support to filter instances by tenant from the admin api - - Change-Id: I37a2c5ad7bbe3e005e96416ea974051a82879adc - -commit aac4fff1532cc96302cd1566406c6d3b3fe60e47 -Author: Stanislaw Pitucha -Date: Fri Nov 9 10:49:02 2012 +0000 - - Make sure create_image returns result - - manager.servers.create_image() returned uuid of the snapshot, but - Server.create_image() didn't. Make them work the same. - - Change-Id: I763197ac8ae542e7ce13569d8ce7e98ec92ccc63 - -commit c819c2fb50c63554d70f735a6463c911f2f6d8eb -Author: Christian Berendt -Date: Fri Nov 9 10:52:23 2012 +0100 - - make tenant id optional for quota-defaults and quota-show - - When using quota-defaults or quota-show without specifing a tenant - the currently used tenant should be used. - - Change-Id: I1ef71b68673dd4a95cbf8b5a8dc901fb6eb06865 - -commit 5d5df1763d83296464a3c4a9c5c82e9a5057edee -Author: Christian Berendt -Date: Thu Nov 8 17:06:24 2012 +0100 - - fix hypervisor-servers for hypervisors without servers - - At the moment hypervisor-servers throws an AttributeError for - hypervisors with no assigned instances. This patch checks first - if there are assigned instances before looping through them to - avoid the exception. - - fixes bug 1076435 - - Change-Id: I504e3f234fd041325b63295fab77f9ed3f704db0 - -commit aa5622147faa0de137f67c6be45dbdb3e11320f6 -Author: melwitt -Date: Wed Nov 7 22:58:32 2012 +0000 - - discover extensions via entry points - - Currently, nova client can only discover extensions in two ways: - - 1. Installing the extension in the novaclient/v1_1/contrib/ directory. - 2. Installing the extension in the top-level python path or modifying - the path to be picked up by pkgutils.iter_modules() - - This patch allows a third, more flexible option of discovering - extensions via entry points. This means the extension can be - installed anywhere and entry points can be registered with python - to be picked up by pkg_resources.iter_entry_points(). - To register an entry point, simply add the extension module to - the setup() call in setup.py like this: - - setuptools.setup( - name='mydistribution', - packages=setuptools.find_packages(), - entry_points={ - 'novaclient.extension' : [ - 'foo = mydistribution.mynovaclientexts.foo' - ] - }, - ) - - Change-Id: Ic1e223a9173546131e742506897f585f4ac65767 - -commit 4ad512b50e0c2190fbd4ef077256faf808496e2b -Author: Christian Berendt -Date: Thu Nov 8 21:03:13 2012 +0100 - - show help when calling without arguments - - When calling nova without arguments you'll receive the following - output: - - error: too few arguments - Try 'nova help ' for more information. - - Changing 'and' to 'or' the help is also shown when calling nova - without arguments. I think that's the expected behavior. - - Change-Id: Id14f0292ad00e6e45ad66dd010f449c3abbf3871 - -commit d037172b701afd66d1ac187a3c7e4a76130a8f4f -Author: ivan-zhu -Date: Thu Nov 8 17:56:18 2012 +0800 - - Add nova client support for nova-manage service command - - Implements the one workitem of blueprint apis-for-nova-manage - - This add three CLI (service-list/sevice-enable/service-diabel) in - nova-client. - - So we can use: - "nova service-list" like "nova-manage service list" with two optional - parameters. Show a list of all running services. Filter by host and - service name. - - "nova service-enable hostname servicename" like "nova-manage service - enable hostname servicename". It will enable the service specified by - hostname and serviename. - - "nova service-disable hostname servicename" like "nova-manage service - diable hostname servicename". It will disable the service specified by - hostname and serviename. - - This patch depends on https://review.openstack.org/#/c/15206/ - - Change-Id: I01d4cee4ef95c1783f6181f8b840244e748387e5 - -commit a84300f020e79adcaad313aff7f7ee11d9c18d1a -Merge: 40ef419 33b2830 -Author: Jenkins -Date: Wed Nov 7 22:38:54 2012 +0000 - - Merge "Allows deletion of multiple servers through CLI" - -commit 40ef4197e982b840f9c3363bc83bf16600f763c5 -Merge: a31d285 51faac4 -Author: Jenkins -Date: Tue Nov 6 17:45:56 2012 +0000 - - Merge "Add ability of nova client to display availability zones when listing hosts" - -commit a31d285f6e7d5516d69319424db06608050107f6 -Merge: 887f831 e9c16ca -Author: Jenkins -Date: Tue Nov 6 17:13:56 2012 +0000 - - Merge "Updated the help text for nova list command." - -commit 887f8314689a71144d4f5c5365d2253e8c662921 -Merge: 0dea78c 8be01b6 -Author: Jenkins -Date: Tue Nov 6 06:48:57 2012 +0000 - - Merge "Fixes setup compatibility issue on Windows" - -commit e9c16ca33ad035fda38d42ec3f7e9e40e56cbf6b -Author: Unmesh Gurjar -Date: Sun Nov 4 23:20:37 2012 -0800 - - Updated the help text for nova list command. - - Few options in the nova list command are admin specific. Updated the help text - to specify the admin only options explitcitly. - - Fixes LP: #1055983 - - Change-Id: Icf8a76e79b9d5399298dacce31b1cc0873f63d71 - -commit 8be01b650e4669132c0d27481781bdf5688079ec -Author: Alessandro Pilotti -Date: Mon Nov 5 17:47:05 2012 +0200 - - Fixes setup compatibility issue on Windows - - Fixes Bug #1052161 - - "python setup.py build" fails on Windows due to a hardcoded shell path: - /bin/sh - - setup.py updated using openstack-common/update.py - - Change-Id: I9c8cf84ada189d8f27448ecda23f51c021d08818 - -commit 0dea78c851a7d43df5ffa9c00bbbc09e857560f0 -Author: Jesse Andrews -Date: Sat Nov 3 16:18:53 2012 -0700 - - include projectid in the cache key - - fixes bug #1074771 - - Change-Id: I0fc1638405c2f4de61255d3efc1b6096ead0742b - -commit 7ddc2fdfcdc0bfa6ada3d150a87ab3d930259538 -Author: Nikola Dipanov -Date: Fri Nov 2 18:06:51 2012 +0100 - - Fixes utils.findresource checking for integer - - Fixes the novaclient.utils.find_resource function to properly handle - non integer values and not break with an AttributeError. - - Adds a test case to test a few more non valid inputs. - - Fixes bug #1065367 - - Change-Id: Iaa2025f4eb580234f754596c3572e2f87872170e - -commit 33b2830e9c81f87fb37e51eca65f6e98143d1e06 -Author: Sulochan Acharya -Date: Thu Nov 1 17:43:39 2012 -0500 - - Allows deletion of multiple servers through CLI - - Adds nargs to argparse for delete command to allow - multiple (optional) positional server argument. This - allows users to delete multiple servers using nova delete. - For example: - nova delete xxx yyy aaa zzz will delete valid servers - xxx, yyy and zzz and print exception msg for invalid - delete of server aaa. - - Fixes bug892061 - - Change-Id: I2abe6329e489bfbd3e5ae699e97ef098b38c4537 - -commit 51faac4a0902ced715c3022985ca4ba7e4aeeaba -Author: ivan-zhu -Date: Wed Oct 24 17:31:56 2012 +0800 - - Add ability of nova client to display availability zones when listing hosts - - Implements the one workitem of blueprint apis-for-nova-manage - - Add an optional parameter for nova host-list - Now, we can use the command: nova host-list --zone nova - It will return the hosts that availability_zone=nova. - This patch depends on https://review.openstack.org/#/c/14741/ - - Change-Id: Ide41e75e7d1471e23d19f51e63a8d9951337a411 - -commit f04a24c6ad397439c7f38e381eac1f3b272eba88 -Merge: 7bf93a5 67d4d7e -Author: Jenkins -Date: Wed Oct 31 18:07:44 2012 +0000 - - Merge "Auto-Assign Flavor ID" - -commit 7bf93a52f8828822c8949fe66bc79e8c035d1330 -Author: Russell Cloran -Date: Mon Oct 29 23:09:26 2012 -0700 - - Validate that boolean parameters are boolean - - Ensure that values which are supposed to be boolean look like correct - user input, instead of assuming that any non true-looking input is - False. - - Also, update the flavor manager to raise a CommandError if is_public is - not a boolean value. - - Fixes bug 1059414 - - Change-Id: I3275e4bba103b14081becf91f723f1be060391e5 - -commit 67d4d7e0fdc6a990484340299a7920b8d64d6a13 -Author: sathish-nagappan -Date: Mon Oct 29 14:26:32 2012 -0700 - - Auto-Assign Flavor ID - - Auto-assign a flavor ID if the user enters "auto" for the ID. - - Change-Id: I745744b9ca44668477635c20df5e2ece6cbf1c27 - -commit 05bbe0fa0efc9abe5461e7e2d3fef7b72d625955 -Merge: 8617a88 2f7b032 -Author: Jenkins -Date: Fri Oct 26 17:04:24 2012 +0000 - - Merge "Pull in latest openstack-common changes and fix a minor PEP8 issue." - -commit 2f7b032910cce500f09a5d2a257595d573bdb116 -Author: Josh Kearney -Date: Thu Oct 25 11:43:56 2012 -0500 - - Pull in latest openstack-common changes and fix a minor PEP8 issue. - - Latest openstack-common commit: d887090b5a31672e4a12f302b3818e2b0933bef0 - - Change-Id: I5a4ffb043ab24f8618a8285112c0c5992ea129e7 - -commit 8617a88765968341c6dc6e8e44b3d2e6038106a7 -Merge: f100953 805ba8f -Author: Jenkins -Date: Wed Oct 24 00:33:46 2012 +0000 - - Merge "Exception handling for 'nova flavor-create' arguments" - -commit f1009534953ed9662e5fe15f71987263c63d6678 -Merge: 4d3f33d 3463559 -Author: Jenkins -Date: Tue Oct 23 15:57:57 2012 +0000 - - Merge "Add support for backup instance." - -commit 4d3f33d141dfc10c553bfc649dbfebf4fe7dec15 -Author: Doug Hellmann -Date: Mon Oct 22 18:46:41 2012 -0400 - - Add OpenStack trove classifier for PyPI - - Add trove classifier to have the client listed among the - other OpenStack-related projets on PyPI. - - Change-Id: If9e10b065d0c54825fb9138893c78cda3ef79ca2 - Signed-off-by: Doug Hellmann - -commit 805ba8fdc1763306f4a6dbdc3de274b5c2597485 -Author: Sathish Nagappan -Date: Wed Oct 17 21:31:34 2012 -0700 - - Exception handling for 'nova flavor-create' arguments - - Fixes client side Bug #1056935 - - Throws an exception if the user does not input integers for the - corresponding parameters. - - Change-Id: I4c4b8148f6565bc5a3b348dbde8c2cf0da00234a - -commit 34635597a68d0626f9806c9b1220600a955e0ea4 -Author: TianTian Gao -Date: Mon Oct 15 14:33:52 2012 +0800 - - Add support for backup instance. - - fix bug: 1066665 - - Change-Id: I1e2c3b2cd9d9e50073b87762973147795059f067 - -commit e8c22cd130759fc6ab89c027cf34df19333878b9 -Merge: ccabbe7 81c01e5 -Author: Jenkins -Date: Wed Oct 10 16:57:11 2012 +0000 - - Merge "Encode user data to utf-8 when creating a server" - -commit ccabbe77de4a411f8728236969e9a5a50ec79a65 -Merge: c8696a5 ccc4291 -Author: Jenkins -Date: Wed Oct 10 04:00:52 2012 +0000 - - Merge "Add simple os-api extension cli extension" - -commit ccc4291c52eb4f68e37691bbe7df34450e89df7a -Author: Joshua Harlow -Date: Tue Sep 18 16:36:17 2012 -0700 - - Add simple os-api extension cli extension - - Add a useful extension that will show you what - openstack api extensions are available for usage - and print out the result into a nice little table. - - Useful as a example for others to base contrib/ - extensions off of. - - Example @ http://paste.openstack.org/show/20989/ - - Change-Id: I5b72f5ea73c00f1c1a0f09f670d744c820e05837 - -commit c8696a59e32ccd0d20dafa86a85379dd7e214a77 -Merge: 6a86308 a9a66ae -Author: Jenkins -Date: Thu Oct 4 22:52:20 2012 +0000 - - Merge "Raises Exception on improper Auth Configuration" - -commit 6a8630867f0563e2699caf35d3669f8e83256c5f -Merge: aa171ca f391591 -Author: Jenkins -Date: Thu Oct 4 21:47:10 2012 +0000 - - Merge "Add missing port-id usage info." - -commit a9a66ae7a750e507a0dda4bc9b2f9f62b9cd98a2 -Author: Stef T -Date: Thu Oct 4 16:20:23 2012 -0400 - - Raises Exception on improper Auth Configuration - - Addresses bug 1061848. - - Basically, this bug comes about from not properly - setting up the auth_system for novaclient. In this - case, an exception of EndPointNotFound is flung. - - Change-Id: I12533aefd9d0425dd83e2e4c63f4dd5ff6faae71 - -commit aa171ca12b336f9a927dbdec0d598f30386b6501 -Author: Vincent Untz -Date: Fri Sep 28 12:42:37 2012 +0200 - - Do not prefer ALL_TENANTS environment variable to command line arguments - - As pointed out in https://review.openstack.org/#/c/13708/ command line - arguments should have higher priority. - - Also, do not fail if the environment variable is not representing an - int. - - Change-Id: Ie6cd5b2d6aae47236ba0fe6d594d0c8095e9e422 - -commit 81c01e535cecc54c2e6e847000638b52fec506af -Author: Vincent Untz -Date: Fri Sep 28 11:48:38 2012 +0200 - - Encode user data to utf-8 when creating a server - - This is needed for data that we don't read from IO directly, since we're - base64-encoding the user data, and this requires ther user data to not - be of the unicode type. - - We're being tolerant, as we'll accept user data that is already in a str - object. - - Fixes: bug 1049161 - Change-Id: I4320670de564c8029c7aef14da2492c6f8752efe - -commit c01fae73700047072a1a27add416eb61ee5cb1b0 -Author: Vincent Untz -Date: Wed Sep 26 14:54:57 2012 +0200 - - Add --all-tenants option to volume-list - - The list and secgroup-list commands have this option, and - nova-volume/cinder respect this search option too nowadays. - - Change-Id: Ie95432727dec9702e09a0ce314bf418f6a36b799 - -commit cdebf729b06d9465ab080fd5b15e433f70f8fe45 -Merge: e01c25b 02d3aad -Author: Jenkins -Date: Fri Sep 21 21:56:06 2012 +0000 - - Merge "Show volume and snapshot data on create" - -commit 02d3aaddf2e3dac92418455a5f4639d6f6e0764c -Author: Vishvananda Ishaya -Date: Thu Sep 20 14:31:52 2012 +0000 - - Show volume and snapshot data on create - - nova volume-create and nova volume-snapshot-create do not display - the data returned from the api. This makes it difficult to find - the id of of the newly created object. - - Fixes bug 1053432 - - Change-Id: Ie25566f4e7d05d98421a5ea9e75521d40282a40d - -commit e01c25bdb18fdc6f5f16db6b3df8865bf569af51 -Merge: fb7c3ad df542ab -Author: Jenkins -Date: Thu Sep 20 05:07:48 2012 +0000 - - Merge "expose os-networks extension to CLI" - -commit fb7c3ad9e7c6ab717f2e357b6c66446438255fd2 -Merge: 99f1da1 aaa38ce -Author: Jenkins -Date: Wed Sep 19 16:05:53 2012 +0000 - - Merge "Work around httplib2 tunnelling bug" - -commit 99f1da1201b7261f4df182d375cb1333eeb423ee -Merge: 746ea00 03a5650 -Author: Jenkins -Date: Wed Sep 19 15:48:04 2012 +0000 - - Merge "Show POST in debug with curl." - -commit 746ea00f1553de9754f33ba807efef92184740c2 -Merge: bfb0f70 0e7df4c -Author: Jenkins -Date: Wed Sep 19 15:46:00 2012 +0000 - - Merge "Make region case insensitive." - -commit bfb0f70f40fdea6ee7b75dc2fb44baeadceb646d -Author: Alessandro Pilotti -Date: Tue Sep 18 00:05:27 2012 +0300 - - Fixes setup compatibility issue on Windows - - Fixes Bug #1052161 - - "python setup.py build" fails on Windows due to a hardcoded shell path: - /bib/sh - - Change-Id: I34f58ea09317c0be6ac23c5d9591bc83bc78782b - -commit 55dd9aeb63831ffaf06e14fb84c977a6e25ccbc5 -Author: Trey Morris -Date: Fri Sep 14 17:35:33 2012 -0500 - - allow empty network list to be requested - - Change-Id: I776a429fb62e335e458f45466f0c362e1270e319 - -commit aaa38ce0e54d97d744826e0b353ec79329cbaf91 -Author: Mark McLoughlin -Date: Fri Sep 14 18:31:24 2012 +0100 - - Work around httplib2 tunnelling bug - - Fixes bug #1051007 - - httplib2 defaults to using HTTP CONNECT tunnelling even for plain HTTP - connections. This is problematic with proxies configured to only allow - tunnelling to port 443. This is the default configuration for squid. - - Hack around the problem by forcing httplib2 to use the HTTP_NO_TUNNEL - proxy type which disables tunnelling except for port 443. - - Change-Id: I59cd95ed74a9bb795779fc38fbc0935266cc8b22 - -commit eb20c5ad6e8499ce137b20713166e854a70367f8 -Merge: 5cdc584 fc2d622 -Author: Jenkins -Date: Fri Sep 14 16:41:53 2012 +0000 - - Merge "Add support for all-tenants search opt to secgroup-list" - -commit fc2d622bac7928302273a374d7cdd3547f609ec6 -Author: Eoghan Glynn -Date: Fri Sep 14 11:31:30 2012 +0000 - - Add support for all-tenants search opt to secgroup-list - - Related to bug 1046054. - - Once I6157e408 lands, we will be respecting the all-tenants search option - in the security groups retrieval API. Hence the CLI should be capable of - adding this option when appropriate. - - Change-Id: If1217a5ffc7316e4661326c38da9b2956424ab05 - -commit df542ab43e4502a153ca88ee10c36dd4ef0694a2 -Author: Vishvananda Ishaya -Date: Mon Sep 10 23:31:52 2012 +0000 - - expose os-networks extension to CLI - - Change-Id: Ia62a9333ec6f0d8b9178fae0313e94cae043f84b - -commit 5cdc584efd30467aaac6b859eb51d6749127194c -Author: Eric Harney -Date: Thu Sep 13 15:01:50 2012 -0400 - - Add support for Unicode secgroup names - - Fixes bug 934081. - - Previously, manipulating secgroups with Unicode names would fail - in _get_secgroup, due to the command-line argument being a raw - byte string, and the secgroup name from cs.security_groups.list() - being a Unicode string. This causes a UnicodeWarning and the - "if secgroup == s.name" test to fail for the desired secgroup, so - secgroup-add-rule and secgroup-delete would fail. - - This change converts them to byte strings for comparison, fixing - these commands. - - Likewise, error messages containing Unicode secgroup names would - fail to print. (i.e. "Security group already exists") - - Change-Id: Ie90cb49b8f11e3283fe509e95a8e9fd468cc9892 - -commit 40cb8ef8337eaff3704ccacae3131ca908620897 -Merge: 3dd0393 59a9578 -Author: Jenkins -Date: Wed Sep 12 22:01:05 2012 +0000 - - Merge "Makes handling of nic args more robust" - -commit 3dd0393fbba7af225f9cc2262ba0ebdeea214456 -Author: Yunhong, Jiang -Date: Tue Sep 11 19:58:32 2012 +0800 - - Support flavor extra specs in nova client - - Add flavor extra specs so that user can list/set/unset - extra specs in nova client - - blueprint extra-specs-in-nova-client - - Change-Id: I6ad7293e29764648c79943c4d05f3a09931af411 - Signed-off-by: Yunhong, Jiang - -commit 247b53022bced6d831e9ad10fb64fe520d00660b -Author: Major Hayden -Date: Tue Sep 11 15:04:53 2012 -0500 - - Optionally faster 'nova show' - - Running show against an instance UUID calls for the - instance/flavor/image data. This patch allows --minimal - to be passed and the extra lookups will be skipped. - - Change-Id: I76e9ac58a67b7cb595ca08c173ec9758119b46ae - -commit 59a9578c3c28b50c6f3c465ba100e33335af4568 -Author: Vishvananda Ishaya -Date: Tue Sep 11 05:46:28 2012 +0000 - - Makes handling of nic args more robust - - Legacy users of novaclient may not pass all of the new nic args, - so this patch only passes them on if they are set. - - Fixes bug 1044231 - - Change-Id: I1c8323a3a09613ad4e8dfcc1dfe379dbda50f125 - -commit aa9d97350333e3ab5d14d5d4bca5baa957701570 -Merge: 8cff1a2 5611025 -Author: Jenkins -Date: Mon Sep 10 18:24:34 2012 +0000 - - Merge "Show instances built from deleted snapshots" - -commit 56110251908fc4feead8de6e4b40b34381c9a509 -Author: Major Hayden -Date: Mon Sep 10 10:36:17 2012 -0500 - - Show instances built from deleted snapshots - - novaclient current throws an image not found error when you use the 'show' - command against an instance that was built from a snapshot which was - subsequently deleted. - - Change-Id: If950b4582d0af9947c30fb24eea78a0829edecf3 - -commit 8cff1a20bc3962ec147f5f7c6807bc4c863eae36 -Author: Andrew Laski -Date: Fri Sep 7 15:59:42 2012 -0400 - - Add ConnectionRefused exception. - - When novaclient gets a Connection Refused it now presents that as a - ConnectionRefused exception with appropriate information rather than as - an HTTP exception. Addresses bug 1047078. - - vagrant@precise64:/opt/stack/python-novaclient$ nova image-list - ERROR: ConnectionRefused: '[Errno 111] Connection refused' - - Change-Id: Iebf4d78a524004d5e79d2219b35f90fbd38ee690 - -commit d6f767f8a3239aa314a9322720d0e543f2e07065 -Merge: 671afc3 e8b6aae -Author: Jenkins -Date: Fri Sep 7 12:47:48 2012 +0000 - - Merge " Add the image_id arg to volume create" - -commit 671afc344c6830e5c97ec3905a7fb1d998c43d8c -Merge: dfa1c71 ee2405d -Author: Jenkins -Date: Thu Sep 6 22:35:02 2012 +0000 - - Merge "Add -X to DELETE and PUT in debug mode" - -commit dfa1c71e910e624c3983e6db1aab0ec9b085a3cd -Merge: 66ea8f9 9754f1d -Author: Jenkins -Date: Thu Sep 6 20:22:50 2012 +0000 - - Merge "Fix PEP8 issues." - -commit 66ea8f9bfb0cf404e2e26954fb576e176d92cf5e -Merge: 46a87dc f2d2e4c -Author: Jenkins -Date: Wed Sep 5 21:58:31 2012 +0000 - - Merge "Fix usage-list date range to use UTC time" - -commit f2d2e4cb0621b27b2b3f864c4352a94174174240 -Author: Mark McLoughlin -Date: Mon Sep 3 20:06:09 2012 +0100 - - Fix usage-list date range to use UTC time - - Fixes bug #1045456 - - The date range in Nova's os-simple-tenant-usage is expected to be in UTC - time since launch/termination dates are stored in the DB in UTC time and - we use the client supplied parameters to query DB without conversion. - - Switch from using datetime.today() to datetime.utcnow() to fix the issue. - - Add a test for the default date range. - - Import timeutils from openstack-common so we can control the return value - of utcnow() in the tests. - - Change-Id: Iac77e3a4cc9561714d1492c54cef931f9764531e - -commit 03a5650cb2435be2e7a3817d89409513bf381a0e -Author: Chmouel Boudjnah -Date: Thu Aug 30 19:52:16 2012 +0200 - - Show POST in debug with curl. - - - When debugging with switch --debug display show the POST request directly - in the curl command line making easy to copy and paste. - - Change-Id: Id62ef2c32a3e9d492dd2d34c4bd7575bda10eb0f - -commit 46a87dc8758aaf666800b37f3d5a3bd3999063a6 -Author: Sulochan Acharya -Date: Thu Aug 30 10:49:40 2012 -0500 - - Fixes doc string and string formatting - - A small change to fix a doc sting mistake and a string formatting - error on floatingIP. Fixes bug 1043906. - - Change-Id: I212e317efb81afdb450fd79f16552fd393e86bd9 - -commit e8b6aae14a3164ec321c79a614e7ba6367bef192 -Author: Ollie Leahy -Date: Wed Aug 29 13:14:21 2012 +0100 - - Add the image_id arg to volume create - - This fixes bug 1042158 and is a port of - Josh Durgin's fix to python-cinderclient - - Patch set 2, remove unnecessary secondary option for - image_id - - Change-Id: If028f784f1c6de9b47705cb580711849d1c00060 - -commit 0e7df4c9fcb0cea9af9b46e0eb6ee7a91ea8059e -Author: Chmouel Boudjnah -Date: Wed Aug 29 13:13:09 2012 +0200 - - Make region case insensitive. - - - Match region in case insensitive way. - - Change-Id: I4d97372e7804acd6b735275ed279b78332ba4eef - -commit 9754f1daa8cd9ed8dbe22c436d8449aabb99f2b0 -Author: lrqrun -Date: Wed Aug 29 13:36:55 2012 +0800 - - Fix PEP8 issues. - - Fix some pep8 issues in doc/source/conf.py make the code looks pretty. - - Change-Id: I7cc284a0155d531d3890941f8c62c04f54d1a2d6 - -commit ee2405d642ff777ecd11cf516efcfe3b54a6d3bf -Author: Joe Gordon -Date: Tue Aug 28 12:26:39 2012 -0700 - - Add -X to DELETE and PUT in debug mode - - Fix bug 1042914 - - Change-Id: I3cded071c12dce0f7eb93b39d5942f0602bd77ba - -commit 3a8942562d31661c254372fba95ce0fd211048a1 -Merge: 6de710f f160a20 -Author: Jenkins -Date: Mon Aug 27 20:23:39 2012 +0000 - - Merge "Implement project specific flavors API, client bindings" - -commit 6de710fa18fb32509ad7987355fc04cd0fa7b221 -Merge: 6e6e806 9101741 -Author: Jenkins -Date: Mon Aug 27 20:22:56 2012 +0000 - - Merge "Change '_' to '-' in options" - -commit 6e6e8060d4e9e73eae4b003c9757169c98aec576 -Merge: 2a7dd86 b54330b -Author: Jenkins -Date: Mon Aug 27 20:12:17 2012 +0000 - - Merge "Adding --version option" - -commit 2a7dd867fa291dcc33add04dc80f8fb5199fa731 -Merge: b52e3be bad092f -Author: Jenkins -Date: Mon Aug 27 20:11:52 2012 +0000 - - Merge "Add nosehtmloutput as a test dependency." - -commit b52e3bef72ce31c90bdd300735828ae48581b769 -Merge: f0929b0 d9dc91b -Author: Jenkins -Date: Mon Aug 27 20:10:20 2012 +0000 - - Merge "split req and response logging this allows capture of timestamps prior to and after request for timing also did some pep8 1.3 cleanup while I was in there" - -commit f0929b0ebb3ce1e3dbb4d48b1326cd6746cafe20 -Merge: ae431ab 845c97b -Author: Jenkins -Date: Mon Aug 27 20:05:18 2012 +0000 - - Merge "Implement network calls in nova client" - -commit f160a20fd942422f3e2e203d37556d502de6632b -Author: unicell -Date: Mon Aug 13 20:25:05 2012 +0800 - - Implement project specific flavors API, client bindings - - blueprint project-specific-flavors - - This change implements client bindings for the project specific flavor API in following change - https://review.openstack.org/#/c/11270/ - - Change-Id: Id8d559985f9369f53926e63ee5f5ce23a051e25b - -commit f391591713a3bd16c521a68063a2c529c5f62ccb -Author: Yaguang Tang -Date: Mon Aug 27 16:03:46 2012 +0800 - - Add missing port-id usage info. - - Change-Id: I3e5de32265512c0f692bda6d322c95be0d1b8851 - -commit ae431aba0d3829728d7e7fda6053f8eb4c417759 -Merge: 8ccd905 52d24b1 -Author: Jenkins -Date: Sat Aug 25 02:06:07 2012 +0000 - - Merge "Added -nic port-id= support" - -commit 9101741960ac4bc9b81539bf6bfb2dedeb7e68d9 -Author: Dean Troyer -Date: Wed Aug 22 13:01:17 2012 -0500 - - Change '_' to '-' in options - - This changes every command-line option with a '_' in its name - and changes them to '-'. The old option names are maintained - for backward compatibility but are no longer in the help text. - - BP command-options - - Note: there is a dodgy hack in novaclient/shell.py to handle - usage-list's --end option that conflicts with --endpoint-type - if --endpoint_type is also present for backward compatibility. - If --endpoint_type is not added to the parser it works. Go figure. - Better solutions that do not break backward compatibility are welcome. - - Rebased due to https://review.openstack.org/11072 merging. - Note: --availability_zone changed to --availability-zone with no - backward compatability since this s a new option. - - Change-Id: I09ab546659be0a0d3f0eadb22ab5e13fac2f059d - -commit b54330bfd255faaec6edae8b99053269a13607d3 -Author: Rick Harris -Date: Fri Aug 24 18:01:30 2012 +0000 - - Adding --version option - - Change-Id: I7d37af1ddee186af22457baea9af71a955720053 - -commit 8ccd9059d62a96815c25f6a5ea3510322bc599e6 -Merge: bab694e 1a47ac1 -Author: Jenkins -Date: Fri Aug 24 19:13:55 2012 +0000 - - Merge "Add availability_zone support for volume creation." - -commit 52d24b19f9bb520c65b4dd937c5997592fa273ab -Author: Nachi Ueno -Date: Wed Aug 15 17:52:27 2012 +0000 - - Added -nic port-id= support - - Fixes bug 1037202 - - Change-Id: I72d252edb7ce5fda61b88a9f9548d59d59a56156 - -commit 845c97b7e99ec71c9aed2230fac990096ec0ea88 -Author: Alessio Ababilov -Date: Wed Aug 22 15:41:50 2012 +0300 - - Implement network calls in nova client - - Implements blueprint novaclient-networks - - Provide network API calls in nova client as well - as unit tests. API is accessed by `networks` field - of nova client. - Methods: - * list() - return network list - * get(network object or id) - return requested network - * delete(network object or id) - delete requested network - * create(network properties) - create a new network with requested - properties - * disassociate(network object or id) - disassociate the network - from its project - * add(network object or id[optional]) - associate the current - project with a network - - Change-Id: Ie6ab11cd2ad6e1625ead4b08c6beab5b845291a1 - -commit bad092f3506ad05769d658efc9d22a5e32a9aed7 -Author: Clark Boylan -Date: Tue Aug 21 14:36:36 2012 -0700 - - Add nosehtmloutput as a test dependency. - - Adding nosehtmloutput as a test dependency allows nose to output its - results to an html file. This will be used by Jenkins to save logs on - a different server. - - Change-Id: Iab55c018b0f41d9ffabd931329ab487df8ab9cae - -commit d9dc91be610f7ab5cc0119c11008105a50269260 -Author: Joe Heck -Date: Thu Aug 16 17:57:09 2012 -0700 - - split req and response logging - this allows capture of timestamps prior to and after request for timing - also did some pep8 1.3 cleanup while I was in there - - Change-Id: I7fdc3f812d22c9e903279541219c53b35f510706 - -commit bab694ef1d579aca453996e3e9729d96a26e570a -Merge: 2819b2a 41ce1b8 -Author: Jenkins -Date: Wed Aug 15 18:05:35 2012 +0000 - - Merge "Relex prettytable depend to match glanceclient." - -commit 2819b2aa30cd11ba9a79da520a966b7c9d1936d3 -Merge: b97262d 3a521ee -Author: Jenkins -Date: Wed Aug 15 18:05:31 2012 +0000 - - Merge "Adds support for autogenerated device on attach" - -commit b97262d3573a97bfa6228dc3cb8127f2bf643ef2 -Merge: 5204689 576a64f -Author: Jenkins -Date: Wed Aug 15 18:05:24 2012 +0000 - - Merge "Allow resources to use any field as 'name'" - -commit 52046892e5417c41ab74739712d5b9eb02c3a2fc -Merge: 8305708 86c713b -Author: Jenkins -Date: Wed Aug 15 17:58:54 2012 +0000 - - Merge "Allow different auth providers via plugin system." - -commit 8305708d28d93cf6a9957aac649130fea7f5c6c5 -Merge: 077cc0b cdae4e1 -Author: Jenkins -Date: Wed Aug 15 17:58:51 2012 +0000 - - Merge "set admin password during instance creation" - -commit 1a47ac1dfb286a27de3afa313e7df2d385d553f8 -Author: Zhiteng Huang -Date: Thu Aug 9 16:43:14 2012 +0800 - - Add availability_zone support for volume creation. - - Add '--availability_zone' flag to 'create' sub command in order to allow - user to speicify target availability zone for volume. - - Change-Id: Ie20760cdbf6a8fa5869ed5e79dc0ac56d2741cb2 - -commit 3a521eef75b3387b4e1548a712081b288049d315 -Author: Vishvananda Ishaya -Date: Mon Aug 6 22:24:58 2012 +0000 - - Adds support for autogenerated device on attach - - In order to keep backwards compatibility, use 'auto' as a positional - parameter to allow nova to automatically generate the device name - for the attached volume. - - Also, prints the result of the attach so that the user can see which - device was selected. - - Change-Id: I25ad8eac48b9a085268627435b68ad20d1fb3c4c - -commit 576a64fbb5820d306bafdd334a01f853de07d462 -Author: Vishvananda Ishaya -Date: Wed Aug 8 11:18:13 2012 -0700 - - Allow resources to use any field as 'name' - - The 'name' field for some resources is called something different, - for example 'display_name' for volumes. There was a hack in our - find method to search for display_name as well. - - This change adds a new class variable to a Resource to tell it - which attribute to use for searching by name. Volumes and snapshots - were switched to use 'display_name' and hypervisors were switched - to use 'hypervisor_hostname'. - - Tests fixed and added. - - Fixes bug 1034536 - - Change-Id: I1b4fb969d42c59d1ab8e3e275a563bbe158e9264 - -commit 077cc0bf22e378c4c4b970f2331a695e440a939f -Author: Chmouel Boudjnah -Date: Mon Aug 6 09:11:18 2012 +0200 - - gitignore ChangeLog and add to MANIFEST.in. - - Change-Id: I6dde5a0411f3e814bb34c0936010f1b46a4248a3 - -commit 86c713b17ac8984b54ff767d83ab41037e7a7833 -Author: Chmouel Boudjnah -Date: Thu Aug 2 16:41:47 2012 +0200 - - Allow different auth providers via plugin system. - - - Remove the NOVA_RAX_AUTH hack and provide (temporary) compatibility - with the new system. - - Example plugin for RAX and HP provided here : - RAX - https://github.com/emonty/rackspace-auth-openstack - HP - https://github.com/emonty/hpcloud-auth-openstack - - Plugin are allowed to specify their own auth_url directly. - - Thanks to mtaylor for helping on this. - - Change-Id: Ie96835be617c6a20d9c3fc3bd1536083aecfdc0b - -commit f15974b80dba9da1dee9433c8a44547fd5efd940 -Author: SandyWalsh -Date: Wed Aug 1 13:23:07 2012 -0500 - - Better handling of stale tokens (no more 401's) - - There was a problem with stale tokens generating 401's. The - headers for the request where not replacing the stale token - with the freshly obtained one. This patch remedies that. - - Change-Id: I8e7c7e01fddeec17ad9ff4254b1223820bb8e2b7 - -commit cefd0fc80e2c52f86b5196bf202b9ac0f94d5866 -Author: James Meredith -Date: Wed Jul 25 10:55:32 2012 -0500 - - change image list and network list data - to be sorted by name rather than UUID - - Change-Id: I3a0faa56dbb85c916c93b5065bda90f99bb3937c - -commit 41ce1b839a4f0fc36372db7e9855c8f7689f9fda -Author: Monty Taylor -Date: Thu Jul 26 12:08:04 2012 -0500 - - Relex prettytable depend to match glanceclient. - - Change-Id: Ic820a3cef791455a78e2aaa9e20c7ee42bed33a8 - -commit c41f5f643af136ccb9cdc40902a6cebfdebaa518 -Merge: 85d591b 7ef0786 -Author: Jenkins -Date: Tue Jul 24 15:23:21 2012 +0000 - - Merge "Fix image-create --poll race-condition." - -commit 85d591b1d88b7e6d174c8eabd41dda14162a8bbc -Author: Kevin L. Mitchell -Date: Mon Jul 23 17:10:27 2012 -0500 - - Add call to get hypervisor statistics - - Adds an admin API call to retrieve the compute node statistics for an - entire nova instance. Counts up all hypervisors and sums all their - values (vcpus, vcpus_used, etc.). - - Change-Id: I0a3df235282089f1313d08ae5b89dadbd1db9840 - -commit 7ef0786d9e6172a9df0d33a1113f27569bd7f522 -Author: Rick Harris -Date: Mon Jul 23 22:05:22 2012 +0000 - - Fix image-create --poll race-condition. - - This fixes a race-condition caused by `do_image_create` with polling - enabled returning after the image has finished uploading but before the - instance `task_state` was cleared out. - - This would cause a snapshot taken immediately afterwards to fail because - the `task_state` would still be in the `image_snapshot` state. - - The (short-term) fix is to add an addition poll-loop that ensures the - `task_state` field is cleared-out as well. - - Change-Id: I3adeed24ecea127c8bdd12143634a6ce5da64330 - -commit cdae4e152f1b56df89766102c9d004188232fe3c -Author: Alessio Ababilov -Date: Thu Jul 19 18:25:41 2012 +0300 - - set admin password during instance creation - - Fix bug #1026650 - - Change-Id: Ie52751021275d1c7f718b84e7a2e66420131ce4d - -commit 186a38cbc67cec061b524701f3a6ffac476399ec -Author: Sascha Peilicke -Date: Fri Jul 20 10:20:32 2012 +0200 - - Clarify usage of --insecure flag - - Change-Id: Iad52212ea2ba7bfc93c597c23cc6314f9916edb9 - -commit b9e1d618724c5d2570850c9203786eea897ac363 -Merge: d50cf70 33cc7b1 -Author: Jenkins -Date: Tue Jul 17 15:24:09 2012 +0000 - - Merge "Add support for modification of instance Security Group" - -commit d50cf705d3e0d81710c7e47bd43ddf17d67a3af8 -Merge: 667dcc3 dde84eb -Author: Jenkins -Date: Tue Jul 17 15:22:36 2012 +0000 - - Merge "Flavor-list sort by ID numerically" - -commit 667dcc313ce0e1ddb1c240c1769f88954da1158a -Merge: 77206eb c3f2957 -Author: Jenkins -Date: Fri Jul 13 18:13:14 2012 +0000 - - Merge "Install test-requires in development venv." - -commit 77206eb6d7a2978209896ce902a896b2858419a6 -Author: Rick Harris -Date: Thu Jul 5 17:08:12 2012 +0000 - - Fix resize polling. - - The `--poll` option for resize is not working because it is looking for - `verify-resize` instead of `verify_resize`. - - Change-Id: I824ee019047121d49789a8311a1b315aa36fa295 - -commit 33cc7b1826dd1b72b93ba45931270a80e20f5477 -Author: TianTian Gao -Date: Sun Jul 8 13:28:12 2012 +0800 - - Add support for modification of instance Security Group - - Change-Id: Ie4196281a34a83316425eada871865e4a33fab5d - -commit dff56d84ccd1f235be5a4611b65189599444a9be -Author: Kevin L. Mitchell -Date: Fri Jun 29 17:17:05 2012 -0500 - - Add support for hypervisor-uptime. - - Adds support for the new uptime call to the hypervisors extension to - nova. This allows the results of "uptime" on the hypervisor to be - returned to the caller. Note that currently, only XenAPI implements - the underlying method; if the version of nova uses another virt - driver, the result will be a 501 error. - - Change-Id: I34cc92557e6d22705a5591e54404b32245dbe16a - -commit c3f295729ee1cf3b9aad928d7c296603e2a13cfc -Author: Sascha Peilicke -Date: Mon Jul 9 17:31:34 2012 +0200 - - Install test-requires in development venv. - - Otherwise ./run_tests.sh may fail - - Change-Id: Id37117a2dfd53144b8f062767afcf17825fd5d6e - -commit 5a98ed711222f91c02bc10bc79463d27b921342c -Merge: db50e76 99d97b9 -Author: Jenkins -Date: Thu Jul 5 15:46:51 2012 +0000 - - Merge "'endpoints' and 'credentials' work with token caching." - -commit 99d97b9d4e6a4af1ecb72cab2a793f5b5b87f490 -Author: SandyWalsh -Date: Thu Jul 5 09:45:46 2012 -0300 - - 'endpoints' and 'credentials' work with token caching. - - The recently introduced token caching busted these two commands - since there was no longer a ServiceCatalog to access. This patch - disables token caching for these commands. - - LP1020669 - - Change-Id: I198acea44fca99b4c907c11198813412df5559bd - -commit db50e76e0ccd405bb96e462ef2cb8fbd63783564 -Author: Sandy Walsh -Date: Tue Jul 3 11:40:18 2012 -0300 - - This should fix a problem with overly aggressive token caching. - - Previously I was only using the service name and auth url as the - token cache key. This was posing problems with services that have - multiple endpoints and/or are needing different service types - (like volume). Now we take all endpoint selection criteria - into account. - - See LP1019054 - - Change-Id: Ideecca805bb0d0754bcc74e536821f32170b9857 - -commit dde84ebdb88c2e97bf42fa7e2107a5dcb5bb357b -Author: John Tran -Date: Fri Jun 29 12:57:10 2012 -0700 - - Flavor-list sort by ID numerically - - Fixes bug 1016680 - the flavors list created has - ID field value as a unicode string therefore sort - on it not the same as numerical. - - Change-Id: I71f2c8583cca33d2f1be2a2daa856ecec524267e - -commit 6483ad10a7062677a834167d2f228da1a0120954 -Author: Major Hayden -Date: Mon Jul 2 15:22:59 2012 -0500 - - Bring back the output from client.http_log() - - Change-Id: If7c583751abe9ae60f299515a5f7778db72fa70c - -commit bd833c80967590682097a0f61a14c6202add9802 -Merge: 0b55c53 cd1e7b9 -Author: Jenkins -Date: Mon Jul 2 17:19:49 2012 +0000 - - Merge "Update for blueprint general-host-aggregates" - -commit 0b55c534a3ce3e6d9b5d9e853fd89a19dcb0b69c -Merge: be09db7 44038f3 -Author: Jenkins -Date: Mon Jul 2 17:19:47 2012 +0000 - - Merge "don't bash-complete the '-h' option" - -commit be09db71b88baee3cec6275d9a69b2a2cc2b3357 -Merge: 20aa3ab 888cfeb -Author: Jenkins -Date: Mon Jul 2 17:11:26 2012 +0000 - - Merge "Add host-list command" - -commit 20aa3ab779c300285e6dadbaf184091e3037255b -Merge: a117885 2a97d61 -Author: Jenkins -Date: Mon Jul 2 17:10:59 2012 +0000 - - Merge "Small doc cleanup round." - -commit a11788515e800a95d5b83448c2a9403eed509bdf -Author: Kevin L. Mitchell -Date: Wed Jun 27 18:45:28 2012 -0500 - - Add hypervisor information extension. - - Adds support for a new nova extension for getting information about - hypervisors (as opposed to compute hosts), including a list of - hypervisors matching a regular expression (database regular - expression, i.e., %'s) and a list of hypervisors with the list of - instances living on those hypervisors. - - Change-Id: I7353991ffbf484da175a0912ee46e80f623e230f - -commit 08cf0bf95ef99a0e39122ef99eb559e2d739716d -Merge: f785532 d4c9b12 -Author: Jenkins -Date: Fri Jun 29 16:48:19 2012 +0000 - - Merge "Indicate unused variables and other misc. house cleaning." - -commit f78553211c064fddedb2461f03327282f7aa5433 -Author: Sandy Walsh -Date: Thu Jun 28 17:00:47 2012 -0300 - - More friendly keyring support when token caching is off. - - The token caching would always try to save the token even - if --no_cache was specified. The downside of this is - environments where there is no keyring agent it would prompt - for a password. Now, if --no_cache is specified it won't try - to save the token. - - Also ability to reset timings (--timings) which is handy for - client-driven profiling efforts. Yes, this should be a separate - branch, but it's so tiny it's hardly worth the effort. - - I'd also like to take this time to express my admiration for - Brian Waldon. A stalwart young fellow and a fine coder. - - Change-Id: I97c2c5f6864fe156a3e204927b2831b74fb1c893 - -commit 0248ae78ecf5b7e9cddf74b9e25714b0bf02d60b -Author: Sandy Walsh -Date: Thu Jun 28 13:00:56 2012 -0300 - - Whoops, the last changes to keyring introduced some problems with v1.1 - auth tests. - - Change-Id: I09605be563da5f026a45549d59bc0a6a1dd1d8a2 - -commit 0c5b97725401097aafaabba784beb8e9d35690ad -Merge: 1c6e044 632a8ec -Author: Jenkins -Date: Wed Jun 27 22:10:55 2012 +0000 - - Merge "Add read_versioninfo method" - -commit 1c6e044bdcd8d61d7ba4e9f24afef4d5bfe24fdb -Author: Sandy Walsh -Date: Mon Jun 18 17:37:45 2012 -0300 - - Auth token caching on by default. --no_cache to disable. Better bypass support too. - - Will use and/or store your Openstack Auth token in the operating - system's keyring if available. Cuts about a 1/2 second off operations. - - Change-Id: Ibe2dc0c49baefd23afe3844a78c1df884a4fb7c7 - -commit 34915a0ea917cb158b654dd2a91a9bfe63057039 -Merge: e8609c9 bb117a2 -Author: Jenkins -Date: Wed Jun 27 19:08:54 2012 +0000 - - Merge "Update Contributing blurb in the docs." - -commit e8609c990e28f45c153d597e870f69bb81658e4a -Merge: b7c5184 ac43f63 -Author: Jenkins -Date: Wed Jun 27 19:08:08 2012 +0000 - - Merge "Filter out v1.0 endpoints" - -commit 888cfeb2c3c6a0fb38c6573708b611f73d4664b2 -Author: Joe Gordon -Date: Tue Jun 19 02:35:39 2012 +0000 - - Add host-list command - - Rename describe_resource => host-describe - - Change-Id: Ic3548c3404ccbb1abd2ea9f096e3df8950d43e89 - -commit d4c9b12f39501186e812fba31c314bf813a4cfc0 -Author: Josh Kearney -Date: Tue Jun 26 11:34:31 2012 -0500 - - Indicate unused variables and other misc. house cleaning. - - Change-Id: I4529d8b6b27dddb1b79ee2167a054b471eaf0dbc - -commit b7c51840b93297f0902891a10e42145eaddd3f38 -Merge: 24ad114 7546198 -Author: Jenkins -Date: Wed Jun 27 16:51:51 2012 +0000 - - Merge "Turn multiple hints with the same key into a list" - -commit 44038f33977402f8ce4e18e7d308a520ea17b780 -Author: Dominik Heidler -Date: Wed Jun 27 11:53:57 2012 +0200 - - don't bash-complete the '-h' option - - Change-Id: Iafd424355167883a10048a0fc0ed13515186a047 - -commit 632a8ec89e37d35bc501ea8c584de0fe472d3937 -Author: Monty Taylor -Date: Tue Jun 26 21:03:40 2012 -0500 - - Add read_versioninfo method - - Change-Id: Ida728f07f253d15c9ce64da1be4ba4f3a7022ca7 - -commit 7546198cb042309ce89f5ddda3d783c41e76eca6 -Author: Vishvananda Ishaya -Date: Tue Jun 26 09:40:22 2012 -0700 - - Turn multiple hints with the same key into a list - - * Related to bug 1017988 - - Change-Id: I331191042d81fe857f0dac5421bf40b634cc23d5 - -commit 24ad114d3b29b46328b2544453606b6d69d1e045 -Author: Monty Taylor -Date: Tue Jun 26 11:04:48 2012 -0500 - - Cleanup of setup.py usage of openstack-common. - - Change-Id: Id74cd3aec982b84851ce84bbb5207d86da04bc63 - -commit 65529cd9294fc5d9669dadd9cc372a35eee678ae -Author: Monty Taylor -Date: Mon Jun 11 18:00:07 2012 -0400 - - Implement post-tag versioning numbering. - - Change-Id: If886d1ee70420fe52776663ec9cf75bf31d54012 - -commit 2a97d614b4ec40d9c3816f04a5e2876e9a621ece -Author: annegentle -Date: Mon Jun 25 18:53:09 2012 -0500 - - Small doc cleanup round. - - - Changes theme to default instead of nature. - - Explains in terms of Compute API instead of Rackspace - - Remove outdated reference to nova-manage command - - Remove unnecessary whitespace - - Change-Id: I43d16cd053af0b4be48450fd638f9d17f9e5c4e7 - -commit bb117a2d45a95ff88eabccd1bf42b14dbf00e76a -Author: Clark Boylan -Date: Fri Jun 22 10:16:49 2012 -0700 - - Update Contributing blurb in the docs. - - Contributing blurb previously mentioned using Github pull requests. - Contributions should go to Gerrit instead. - - Change-Id: Id7b7f968fa5a3785c19704b4c1c2408f48b335ca - -commit cd1e7b9d90afc57b979c729d928bb3f9a1cce260 -Author: Joe Gordon -Date: Wed Jun 20 21:34:37 2012 +0000 - - Update for blueprint general-host-aggregates - - * Remove Operation state from aggregate results - - Change-Id: I884b7f4c527debadb3a22b574b5d2879d28dd0f9 - -commit 3dd0d3be63b4bf35aede852d096deff9be5b63e4 -Author: Kevin L. Mitchell -Date: Wed Jun 20 15:22:17 2012 -0500 - - Admin action to reset states. - - Adds support for the new Nova Admin API action which resets the state - of an instance. This will at least allow easy clean-up from bugs - which corrupt the state of an instance and inhibit the owner of the - instance from deleting it. - - Change-Id: I47d1d75e3bd2a07b3b75302b512122b27d5d79d9 - -commit ac43f6389ff1f4f15b8778ab062edb10bbe9af6e -Author: Ziad Sawalha -Date: Mon Jun 18 16:51:11 2012 -0500 - - Filter out v1.0 endpoints - - - Addresses bug 1014860 - - v1.0 endpoints should not be considered valid endpoints - by python-novaclient - - also ignores other unkown versions (for when 3 comes out) - - includes updated catalog tests - - Change-Id: I73bd9b0dbede74ee0d975caa86145219e30262fc - -commit a2a62a5f71d9e24d3c2dbe91df38517141e7c577 -Author: Sandy Walsh -Date: Fri Jun 15 15:12:23 2012 -0300 - - option to bypass managment endpoint and timings support - - --timings = show timings for each call made to nova (including auth) - --bypass_url = api node endpoint to use instead of one from service catalog - - For example: - nova --timings --bypass_url=http://10.24.31.37:8774/v1.1/nova-staging boot --image f304d266-0a49-4877-b34c-63aea8360297 --flavor 3 delete_me_2 - - Change-Id: Ib2a258b7e969ad56ce4ee2bd64c61310278cb856 - -commit d94edf1469e65a993ca98b961463d87187e0440b -Merge: 032d02b 983b28d -Author: Jenkins -Date: Fri Jun 15 15:30:20 2012 +0000 - - Merge "Fix spelling errors in aggregates section" - -commit 032d02b189eb39f9c42f75a32f64943f7494c5e1 -Merge: 8dce04a ebceca9 -Author: Jenkins -Date: Thu Jun 14 21:00:51 2012 +0000 - - Merge "Move docs to doc." - -commit 8dce04a1cf4ed7f04b0677c451947283e20047e6 -Author: Josh Kearney -Date: Wed Jun 13 10:03:23 2012 -0500 - - Removes NOVACLIENT_DEBUG from client code. - - It's OK to do this because only the shell uses the --debug arg. The code that - uses the client code will set the log level appropriately. - - Fixes bug 922742. - - Change-Id: I9e925f53c17c73f4442121e52811d52603afab29 - -commit 983b28d05182e55031c997fd6ca5e30f5a699984 -Author: Joe Gordon -Date: Mon Jun 11 17:49:22 2012 -0700 - - Fix spelling errors in aggregates section - - Change-Id: I7bd0533861168eef31dcd055ae79746f1a1a6dc7 - -commit ebceca94146b2ab004dfb88069ee3a6917b460ad -Author: Clark Boylan -Date: Mon Jun 11 14:13:55 2012 -0700 - - Move docs to doc. - - To better facilitate the building and publishing of sphinx - documentation by Jenkins we are moving all openstack projects with - sphinx documentation to a common doc tree structure. Documentation - goes in project/doc/source and build results go in project/doc/build. - - Change-Id: I868df12e3c15cc30043e782ce0a609b9574295cd - -commit d263f1f7b8220b482c5f912c4c1b240d260d93dc -Merge: f4c4527 7745b35 -Author: Jenkins -Date: Mon Jun 11 18:00:11 2012 +0000 - - Merge "Lock prettytable dep at v0.6" - -commit f4c4527bc1c633ed3bc5e5581bad3f79f53090ef -Merge: 051aa3d ff6162e -Author: Jenkins -Date: Mon Jun 11 17:02:25 2012 +0000 - - Merge "Add .tox to .gitignore" - -commit 7745b35b698df9cc08c681aa5a1d52d6346030cb -Author: Brian Waldon -Date: Mon Jun 11 09:57:00 2012 -0700 - - Lock prettytable dep at v0.6 - - Specifically set the prettytable dependency so we can reliably - align data in table cells. - - Change-Id: I1787c4100248b2a75405df690931110c76803413 - -commit 051aa3d7dd54a453165a839dee9e2bb6de203abf -Author: Josh Kearney -Date: Mon Jun 11 11:44:38 2012 -0500 - - Removed generate_authors.sh since it's no longer used. - - Change-Id: I2ad9b4c77323baa0f4aef444e84fb93781cf7886 - -commit eb9b17532fdf23d1969b5de888a8a3dae8bc1303 -Author: John Tran -Date: Wed May 16 11:03:32 2012 -0700 - - nova show cmd displays unique flavor and image id - - Fixes bug 917855. Added unique id of flavor and - image objs to output of nova show vm - - Change-Id: I9c4c4db3d604b130a2629ce0c664ca106f08b869 - -commit 3f4591142fb3cb692877a2a814806e3bd574557b -Author: Brian Waldon -Date: Mon Jun 11 08:09:12 2012 -0700 - - Use openstack-common for AUTHORS generation - - Also add .mailmap entries for Jake Dahn and James E. Blair - - Change-Id: I1ec02aa5302922f3db6a3ad457f4f7c6a006ba00 - -commit ff6162ebba061451a0559ac3f16e7b777e61ed2d -Author: Brian Waldon -Date: Mon Jun 11 08:29:48 2012 -0700 - - Add .tox to .gitignore - - Change-Id: I1502a2ade9e1dadf20428de7fae0f16aa751696b - -commit 855d1578fc28a49d57009d99915b0097d1a1e4e4 -Merge: e41d8bd 9dcafe1 -Author: Jenkins -Date: Thu Jun 7 15:14:45 2012 +0000 - - Merge "doc: fix and clarify the --meta option help" - -commit e41d8bd09e80863d39fe1fab4d45f65573eeb69c -Merge: 5c5b098 3ed72ba -Author: Jenkins -Date: Thu Jun 7 15:14:43 2012 +0000 - - Merge "Adds flavor-show support." - -commit 5c5b098f7cbaef44152b1df7a771e71e932c0664 -Author: Vishvananda Ishaya -Date: Fri Jun 1 01:39:20 2012 +0000 - - Add start and stop to server actions - - Change-Id: I7fc52a87519813e38090f05dd9646b800c5c1813 - -commit 3ed72ba246d565c21338a437f64ba0077c334a14 -Author: Dan Prince -Date: Fri Jun 1 13:00:02 2012 -0400 - - Adds flavor-show support. - - Fixes LP Bug #1007516. - - Change-Id: I0c1c814968af416a796be1daec38290f6237d650 - -commit 9dcafe16b095dfe3ca76637ae5b3caed059ad7a2 -Author: Pádraig Brady -Date: Fri Jun 1 13:32:09 2012 +0100 - - doc: fix and clarify the --meta option help - - Change-Id: Iba758a9014d43581a044131a7394738b0448cc18 - -commit 10a9cb22bd84181ccf773d3ea082868ff69a9070 -Merge: 66fe385 af634ab -Author: Jenkins -Date: Tue May 29 22:29:55 2012 +0000 - - Merge "Lock pep8 at v1.1" - -commit 66fe385a40fb118bb72098daa008faccc31ca649 -Merge: d15f216 73bc2ed -Author: Jenkins -Date: Fri May 25 13:35:42 2012 +0000 - - Merge "Turn on verbose test output." - -commit af634abb1ec535d4d1d505b88c8393e67a5585af -Author: Brian Waldon -Date: Thu May 24 07:13:12 2012 -0700 - - Lock pep8 at v1.1 - - We can't depend on pep8 not to add new rules and break our tests. - - Change-Id: Iac5c79f7c00fcaeff3ef957d138754d63425a256 - -commit d15f216b2dced23e793a53aed3dde147fc134acc -Merge: cb8eea4 c949513 -Author: Jenkins -Date: Wed May 23 14:52:05 2012 +0000 - - Merge "make nova bash-complete faster and more accurate" - -commit 73bc2ed038256337540fcc80405a639ea4de0371 -Author: Monty Taylor -Date: Fri May 18 08:33:17 2012 -0400 - - Turn on verbose test output. - - Change-Id: I811e8c2cbbdd107794af3fc8f70757e3b609a479 - -commit cb8eea487532720922a76ec246327ead4cb627ce -Author: Monty Taylor -Date: Wed May 16 10:40:33 2012 -0400 - - Align tox.ini with standards. - - Change-Id: Iab112bae0187d025b9b0b6c88208d6706093a184 - -commit c9495134690a1818fccfec0b8a5717dc31ea5633 -Author: Dominik Heidler -Date: Tue May 15 11:25:11 2012 +0200 - - make nova bash-complete faster and more accurate - - - cache output of "nova bash-complete" - - distinguish between flags and commands (based on already typed text) - - Change-Id: I85bd1c2198eef222540cf12063a3b233b0d6db12 - -commit 66522fdc9c09a65b87fe412e7bea87e4761ec43d -Merge: 636f32b be5c63e -Author: Jenkins -Date: Wed May 9 20:21:40 2012 +0000 - - Merge "removed int requirement for volume_id on snaps" - -commit 636f32b00aef03202efc2c7fb16ee36c166f2bfc -Author: Chuck -Date: Thu Apr 12 15:41:35 2012 -0500 - - refactored --service_name to only work with compute calls and added - --volume_service_name for volume calls - - Change-Id: I2b1188fb57f9576daebfaceaddc6eea44a47b4ee - -commit be5c63e678a248007796c9e49f05df75242be0b8 -Author: Chuck -Date: Tue May 8 22:02:21 2012 -0500 - - removed int requirement for volume_id on snaps - - Change-Id: Ibec28174bb438f86cc91561ee642d4da67c9d5d2 - -commit d743f92dc2cd25e7dd4bb7571e8542e53d9b7db1 -Author: Ghe Rivero -Date: Mon May 7 10:06:19 2012 +0200 - - Updated to new prettytable api. Fixes bug 995818 - - In 0.6, printt() (wrapper to get_string) has been removed. - Updated to use get_string(), backward available since 0.2 release. - - Change-Id: Ica292757ec3de5004f27afbc5c8ee11d839421df - -commit 997a472983d6883b694aa3d6d1ffed4160ea09ad -Merge: bea0bf9 f47f603 -Author: Jenkins -Date: Thu May 3 22:41:29 2012 +0000 - - Merge "Limit hint/nic parsing to one split on '='" - -commit bea0bf9d517175e2f9f019019fb268b766296752 -Merge: 04c9d02 c135cf8 -Author: Jenkins -Date: Thu May 3 19:14:03 2012 +0000 - - Merge "Fix LP #990667 - Keypair __repr__ referencesuuid" - -commit 04c9d02011efc8ea46cb48432d194fed878819bf -Merge: f1eda61 c36ac8b -Author: Jenkins -Date: Thu May 3 19:04:56 2012 +0000 - - Merge "really output the description of an exception" - -commit f1eda6144bd5f5d8d0fdfd533233e8938f649f69 -Merge: d43f172 ade27e2 -Author: Jenkins -Date: Thu May 3 18:44:39 2012 +0000 - - Merge "Allow server name to be specified for actions and diagnostics." - -commit ade27e211d7c7505e7d0b09750fd10de46932b71 -Author: Alex Meade -Date: Wed May 2 15:28:23 2012 -0400 - - Allow server name to be specified for actions and diagnostics. - - Fixes bug 963026 - - Change-Id: I1662d229b4dcbc2e56d9701190191d94d603c63b - -commit d43f1720715442631eb330f3609a63fd729a1640 -Author: Vishvananda Ishaya -Date: Wed May 2 00:35:52 2012 +0000 - - Don't force volume id to int and allow search by name - - * required for change 6511 to merge - - Change-Id: Ia8d28ca7cce4c00aa0b3f1fe1da6719ec99d6fe4 - -commit 081c8e9824d25b2a4ff2b71c5336c739bb75fc1d -Merge: c00b47c 1602966 -Author: Jenkins -Date: Tue May 1 20:51:37 2012 +0000 - - Merge "Display the request id on error response." - -commit c00b47cdbc4a951e770400526b34f8154057b315 -Merge: cdfd1da bdccfbc -Author: Jenkins -Date: Mon Apr 30 21:00:38 2012 +0000 - - Merge "Raise exception on all 4xx and 5xx responses." - -commit c135cf8ef69cd704d709556d3ab108bf3562843f -Author: Jay Pipes -Date: Sat Apr 28 14:27:08 2012 -0400 - - Fix LP #990667 - Keypair __repr__ referencesuuid - - Replaces reference to non-existant uuid property with - existant id property in Keypair.__repr__ - - Change-Id: I3aab0dce2c1f0f3cb5160e54a00a96b02f600854 - -commit cdfd1da4d0f6ed859e36cefc49e585f7c4b86e1a -Merge: 765f551 ed3a2bb -Author: Jenkins -Date: Thu Apr 26 19:17:08 2012 +0000 - - Merge "update README.rst,add args "service_type" when getting endpoints." - -commit c36ac8b3d7361e24b3157c72622477227dd77248 -Author: Christian Berendt -Date: Thu Apr 26 18:02:39 2012 +0200 - - really output the description of an exception - - example without patch: - - nova [...] flavor-delete 123 - ERROR: - - example with this patch: - - nova [...] flavor-delete 123 - ERROR: Flavor 123 could not be found. (HTTP 404) - - fixes bug 981286 - - Change-Id: I9c5cead521e48b4970850262fb9af279ec5a7753 - -commit f47f603c668f964631e5dce9641ac98ac33bc624 -Author: Brian Waldon -Date: Fri Apr 20 09:54:15 2012 -0700 - - Limit hint/nic parsing to one split on '=' - - * Make sure we split a scheduler hint like 'a=b=c' into ('a', 'b=c') rather than ('a', 'b', 'c') - * Also apply fix to --nic argument - * Fixes bug 986213 - - Change-Id: Icbc6938ea332bd70a82890bf4dc0744b2471bc24 - -commit ed3a2bb7222f2cb4bf40c57145b1e7b225d26040 -Author: Your Name -Date: Wed Apr 18 14:31:28 2012 +0800 - - update README.rst,add args "service_type" when getting endpoints. - - Change-Id: Ib7e05f8eaff84e26869ec1a098ea98edd213018b - -commit 765f551a267f07e43eb3acb92835ac7e5d6ca31b -Author: Josh Kearney -Date: Thu Apr 12 14:16:31 2012 -0500 - - Rename NOVA_VERSION to OS_COMPUTE_API_VERSION. - - Fixes bug 940432. - - Change-Id: I18187eb68d936632b4ae78676a0a9f062afba8f2 - -commit bdccfbc88b7ca1cafe51ce39c58d18914a969dbb -Author: Yuriy Taraday -Date: Fri Apr 13 18:56:44 2012 +0400 - - Raise exception on all 4xx and 5xx responses. - - Fixes bug 965826. - - Change-Id: I44ce602176320b1e60e4c927e19a7eec232923b9 - -commit d6d7386fad20fe3165419b3ab2ee51bd90b46e2c -Author: Brian Lamar -Date: Fri Apr 13 01:15:14 2012 -0400 - - Update unittests to be Python 2.6 compatible. - - Fixes bug 980504 by introducing unittest2 module into novaclient. - - Change-Id: I613665eb174598a162795cec737078f960adc4cf - -commit 16029661851221ab820489cfead4f8d2dd3b6f93 -Author: Alex Meade -Date: Wed Apr 11 13:52:45 2012 -0400 - - Display the request id on error response. - - This changes displays the request id when an error code is returned - from the API. - - Change-Id: I70621fe7477a4612334af32e83f3ee8c5340371d - -commit ad4a04a64e3a49c5613e766a9f93727cd6b8a678 -Author: Adam Spiers -Date: Thu Apr 5 13:24:50 2012 +0100 - - Make '--help' argument more useful. - - With no other arguments, '--help' now outputs the same as 'help', so - that the list of subcommands are no longer omitted. Additionally, - '$subcommand --help' now yields the same output as 'help $subcommand'. - - Change-Id: Iabd926574e296ad14b622862b9fba038fdede66e - -commit 565d144611710ed7591244892a936549f91e9473 -Author: Andrew Bogott -Date: Mon Mar 26 12:07:21 2012 -0500 - - Fixed the subcommand error message for nova shell. - - Previously we were giving advice like this: - - "Try 'nova volume-show help' for more information." - - Bad advice -- that doesn't work. Now when there's a subcommand - specified we make a proper suggestion: - - "Try 'nova help volume-show' for more information." - - Change-Id: I6ef49f9e4e1b67074f51ab442abd4a196d437b00 - -commit 9485608cefe1ebfe301c057077fd0a7c8b7f5e0e -Merge: c8eaea3 f3709bc -Author: Jenkins -Date: Tue Apr 10 19:06:18 2012 +0000 - - Merge "add packages using find_packages()" - -commit c8eaea3be552984203f7666a34e320d59edba663 -Merge: f220e8f 60c70e2 -Author: Jenkins -Date: Tue Apr 10 18:49:02 2012 +0000 - - Merge "set 'compute' as default endpoint bug fix for #970808" - -commit f220e8f7011eafbc0a0de5c43bde90edc2065311 -Merge: 0028eb4 5f51219 -Author: Jenkins -Date: Tue Apr 10 18:34:24 2012 +0000 - - Merge "Add -i/--identity option to 'nova ssh'." - -commit 0028eb4ac2bf9729247ad64d65469e4e572ac74a -Author: Rick Harris -Date: Mon Apr 9 20:32:37 2012 +0000 - - Request ID when name is ambiguous. - - Fixes bug 931605 - - Change-Id: If0778915d964995dbb6647d56ed21075aec08baa - -commit ea448e24971c58e9edc7d837c6dfef3941a6c878 -Author: Brian Waldon -Date: Tue Apr 3 19:16:05 2012 -0700 - - Set resources as loaded on get - - * Setting a resource to loaded prevents future lazy-loading - * Remove lookup by uuid in getid helper as it is no longer used - * Fixes bug 971183 - - Change-Id: Idd9d39ded41b94b08b03476c30e50277b477423d - -commit f6014dd8c530e121ae96a53ae6664bc24eb85781 -Author: Josh Kearney -Date: Mon Apr 2 12:27:30 2012 -0500 - - Miscellaneous code cleanup. - - Change-Id: I6028247466378327f03b71dc2063dd2777b9382a - -commit f3709bc6b6288752aaee93ea051278841d7039de -Author: Peng Yong -Date: Sun Apr 1 18:33:56 2012 +0800 - - add packages using find_packages() - - Change-Id: Ib745254276b67cc09f6a9e8d3ac8f5aea7741903 - -commit 60c70e2e0274e24f96ebf117c983843024a7172a -Author: Peng Yong -Date: Sun Apr 1 21:10:16 2012 +0800 - - set 'compute' as default endpoint - bug fix for #970808 - - Change-Id: I44c33266370891bc99d08e5a3bf2d950cd9e36f1 - -commit 5f51219d97f682c00fb751e6644668fa4b9e53b9 -Author: Russell Bryant -Date: Fri Mar 30 16:26:08 2012 -0400 - - Add -i/--identity option to 'nova ssh'. - - Add an option for specify a private key to use with 'nova ssh'. '-i' - was chosen to match the option this maps to in ssh. - - Change-Id: Iecb2a20a34816e8f1ea80c1f66fac476037a798f - -commit 2db73cd5a1facb888d9c1cfb75d350b8b53f9a0e -Author: Russell Bryant -Date: Fri Mar 30 14:34:57 2012 -0400 - - Improve 'nova ssh' error message. - - Fix bug 969499. - - If you ran "nova ssh " and the instance has no public IP - addresses, the output you got was: - - ERROR: 'public' - - This patch makes it so you get a friendlier error in this case: - - ERROR: No public addresses found for ''. - - Change-Id: I176decf90f472f9b0768e4d0c2bcabd55fe7198a - -commit 8632032a6999cbb27b3a2064df8e8e8813692dd8 -Author: Dan Prince -Date: Fri Mar 30 10:48:06 2012 -0400 - - Fix spelling of curent in list sec groups. - - Change-Id: I248b4c506fda155f74cc6231877c2e50bdc517fa - -commit 262886b29734c480056c80a7f8d928487fee1f62 -Merge: 6556686 8395b06 -Author: Jenkins -Date: Thu Mar 29 23:49:27 2012 +0000 - - Merge "Remove serverId lookup in volume attachments" - -commit 6556686508b7d54422832bc7f7f70602d954838b -Merge: d4f7ffc ee40c04 -Author: Jenkins -Date: Mon Mar 26 18:51:55 2012 +0000 - - Merge "Set up the log handler only once." - -commit d4f7ffc6684dc95d4fde079c13f5dd609400debf -Merge: e7d35bf 97953f5 -Author: Jenkins -Date: Sat Mar 24 02:47:25 2012 +0000 - - Merge "Improve the error message from the nova shell" - -commit ee40c044162d3e62351ee6d8647beb06900d0c66 -Author: James E. Blair -Date: Fri Mar 23 23:04:54 2012 +0000 - - Set up the log handler only once. - - When the NOVACLIENT_DEBUG environment variable is set, each time - python-novaclient outputs HTTP debugging information, it outputs - n copies of the information, where n is the number of times it has - output debugging information previously. - - This is because a logging handler is added each time the log output - rather than only once on initialization. - - This patch moves the log handler setup into module level. - - Fixes bug 963547. - - Change-Id: Icf503e39723d591951810dea0118ffbb41107775 - -commit 8395b06175990476ff4c8820f864622c8c96340c -Author: Brian Waldon -Date: Fri Mar 23 14:58:32 2012 -0700 - - Remove serverId lookup in volume attachments - - We had to look for serverId and server_id to properly represent what - server a volume was attached to. We can undo the fix to pass gating now - that the necessary branches have landed. - - Change-Id: I97957749ea4dd8a7fb5763f7abc75237d795dd23 - -commit e7d35bf5c5ca6c80f4b86d55c8e760f9e87ffda2 -Author: Brian Waldon -Date: Fri Mar 23 09:19:29 2012 -0700 - - Handle server_id and serverId in volume list - - * This is a temporary patch to get past the devstack gate - * Helps fix bug 943053 - - Change-Id: Id40f0c9d7b603029b1b6de6742fe7bff2482fe05 - -commit 67b88b5fb8e8d1bf315d9a03c8416f40f7dcd8d9 -Merge: 79e90e5 0191005 -Author: Jenkins -Date: Thu Mar 22 17:39:30 2012 +0000 - - Merge "Added cloudpipe support. Fixes bug 962286" - -commit 79e90e5ff74f01c88603e0a06e4ebd57dbc0a992 -Merge: 204ffab 6b594c9 -Author: Jenkins -Date: Thu Mar 22 17:33:38 2012 +0000 - - Merge "Add missing tools and tox.ini to tarball" - -commit 0191005de3610fd30372dba1282b0110a0382a3e -Author: Alvaro Lopez Garcia -Date: Thu Mar 22 12:23:39 2012 +0100 - - Added cloudpipe support. Fixes bug 962286 - - Change-Id: Id1c580a085d0bf9699689c5d6d8c8103d7d4a3f8 - -commit 204ffabe38db7265331974fc346bcfafe6956fec -Author: Andrew Bogott -Date: Tue Mar 13 18:11:49 2012 -0500 - - Proposed HACKING guidelines for string encoding. - - Change-Id: Ifc120e33f08868ead8b02320dc982f5528db4965 - -commit bfcd962d97d8a4151737c409ae0219e7dc07517f -Merge: d83af0a 39e252a -Author: Jenkins -Date: Wed Mar 21 18:16:58 2012 +0000 - - Merge "Fixes bug #959262 - Prevent a failure to create the cache directory from causing an exception." - -commit d83af0a1f4875b64885c25046eeb2d0bee02acde -Merge: 3d9a228 c444900 -Author: Jenkins -Date: Wed Mar 21 17:02:42 2012 +0000 - - Merge "Implement quota classes." - -commit 6b594c9f32088251a5848db2b427f7a76aeb17ee -Author: Thierry Carrez -Date: Wed Mar 21 15:41:12 2012 +0100 - - Add missing tools and tox.ini to tarball - - Fix MANIFEST.in to include missing tools and tox.ini in - generated tarballs. Fixes bug 960027 - - Change-Id: I2e13aa89b7db4c98bb9c884c40d4858047c579f1 - -commit 39e252ad056ff65c7c326095938deb1eb50c4b40 -Author: Kiall Mac Innes -Date: Wed Mar 21 12:19:30 2012 +0000 - - Fixes bug #959262 - Prevent a failure to create the cache directory from causing an exception. - - Change-Id: Ia80b50b32f5e3d0e76f4a1b251e23bbd3c70666e - -commit 97953f52e135dc7cd2052092717c2a28003ed014 -Author: Pádraig Brady -Date: Tue Mar 6 17:28:23 2012 +0000 - - Improve the error message from the nova shell - - Output 'nova help' on error rather than `nova' - - Change-Id: I71c3fb6786472c42b0bfd93a085168ba75d37590 - Old-Change-Id: I67360589a4af5697d3f90afa74b8504eefaf4976 - -commit 3d9a2284d38ba5f8bc1666cae37822b845b6aeb0 -Author: Rick Harris -Date: Tue Mar 20 23:15:41 2012 +0000 - - Adds NOVACLIENT_INSECURE option. - - Fixes bug 960704 - - Change-Id: I885fddaac57c113b66b4b71120c2a537fa391b09 - -commit c444900d310e725fc0c225ca5e17765506198919 -Author: Kevin L. Mitchell -Date: Wed Mar 14 16:14:56 2012 -0500 - - Implement quota classes. - - Nova's quota class support allows entire classes of quotas to be - associated with projects, which makes it easier to set specific - quotas across multiple projects. This change adds client-side - support for manipulating quota classes. - - Change-Id: I7ee14d16aa51957dcdc1ea5c7a9d5b6bd1656f33 - -commit bb2876b4d55051ef83b25685a62f752bf812d820 -Author: Thierry Carrez -Date: Tue Mar 20 08:07:22 2012 +0100 - - Open Folsom - - Switch version to 2012.2 to open Folsom cycle. - - Change-Id: I8bc51e436b09e68275424914c43f4f2717045956 - -commit 7615e513be35591a47fd59edb0df649fdd16ce9c -Author: jakedahn -Date: Mon Mar 19 15:36:55 2012 -0700 - - Adding Console Log to CLI - - * Fixes bug 957518 - * Command is as follows: nova console-log --length=20 - * Also updated the readme with new cli output. - - Change-Id: I7874c7c9533b5389f7107ae375d4fa9f8fee7c49 - -commit cc72d6dfe2bcc8977932c6f76ce6d0de30ee04ee -Author: Dean Troyer -Date: Tue Mar 13 22:30:52 2012 -0500 - - Change CLIAuth arg names - - Change the argument names used for common Keystone authentication per the - updated http://wiki.openstack.org/CLIAuth: - - --auth_url -> --os_auth_url - --password -> --os_password - --username -> --os_username - --tenant_name -> os_tenant_name - --region_name -> os_region_name - - All old args are depricated but available for backward compatibility. - - Fixes bug 954531 - - Change-Id: Ic67c447e4e4b8d793f587c789cecd149446194f3 - -commit f90aa8c91ab94ceabed667bc080c07bb94c0ec2d -Author: Anthony Young -Date: Tue Mar 13 23:18:41 2012 -0700 - - Add suport for instance locking/unlocking. - - * Fixes bug 954746 - - Change-Id: I055597014fd44313780b8a9f10cdbc94196f8efb - -commit 24b9e8055c17fa11573c7e5db18d50279b6af169 -Merge: 2d2eb3e 4ff001d -Author: Jenkins -Date: Sat Mar 10 05:02:09 2012 +0000 - - Merge "Fixes lp#948685 proxy_token and proxy_tenant_id behavior" - -commit 2d2eb3e90d3560abca94dc915326c18a7b87a6c5 -Merge: b22ec22 2cc1a37 -Author: Jenkins -Date: Fri Mar 9 21:58:46 2012 +0000 - - Merge "Add --poll for instance snapshots." - -commit 2cc1a37e08c682ab9506fa34b77a521d6eabd087 -Author: Rick Harris -Date: Thu Mar 8 06:32:51 2012 +0000 - - Add --poll for instance snapshots. - - Change-Id: I8199a089250fe7b499c8693e3c1c999f52a842d9 - -commit b22ec22336def07a0678fd0c548fb87ea48c6eab -Author: Rick Harris -Date: Tue Mar 6 00:33:37 2012 +0000 - - Add human-friendly ID support. - - Allows a user to interact with certain models (image, flavors, and - servers currently) using a human-friendly identifier which is a - slugified form of the model name. - - Example: - - nova boot --image debian-6-squeeze --flavor 256mb-instance myinst - - Change-Id: I43dbedac3493d010c1ec9ba8b8bb1007ff7ac499 - -commit 4ff001d2322cc5c3e14f8c9901b289c2a64fd172 -Author: Michael Basnight -Date: Tue Mar 6 22:40:28 2012 -0600 - - Fixes lp#948685 proxy_token and proxy_tenant_id behavior - - * renamed token to proxy_token because of its usage - * added a proxy_tenant_id for new keystone tokens/id/?belongsTo - - Change-Id: Ic7e65612620e5a54f04eddb79bffed7e2df6fba2 - -commit 0528368fb9173eaa7d3e8bf41948b8cc73b11ae8 -Merge: 632ef2f 332f96e -Author: Jenkins -Date: Wed Mar 7 06:32:10 2012 +0000 - - Merge "Remove trailing whitespaces in regular file" - -commit 632ef2f31dfc8873de0ff66b0c382d46f9b4c5fd -Merge: 3de2969 5d65693 -Author: Jenkins -Date: Tue Mar 6 19:08:21 2012 +0000 - - Merge "Adds --ipv6 and --port to ssh convience command." - -commit 3de29697c53ff4849a638e4749905825d3eeb232 -Author: Rick Harris -Date: Mon Mar 5 22:16:40 2012 +0000 - - Separate UUID caches for different endpoints. - - Change-Id: I06f127ac9ed522860bb929b789a158a4e4fac98f - -commit 332f96e89bb1ccafcbeea8032017a66efdf9e6cc -Author: Hengqing Hu -Date: Sat Mar 3 12:34:58 2012 +0800 - - Remove trailing whitespaces in regular file - - Change-Id: Iecc6fee3c8201541a42845db38874fd572fa2771 - -commit 5d6569378d35b1bc36028357274b33d8ef71b24d -Author: Rick Harris -Date: Thu Mar 1 18:59:02 2012 +0000 - - Adds --ipv6 and --port to ssh convience command. - - Fixes bug 944245 - - Change-Id: I680f145410ba3275efb81a1c464651ef0f6c49e7 - -commit 01873d08cc64d2fd11d3fcef54c86ce1109186a7 -Author: Rick Harris -Date: Thu Feb 23 18:57:11 2012 +0000 - - Add --poll for long running actions. - - This will block while the action completes, reporting progress if it - makes sense. - - Change-Id: I93ae3d74bdd8bb1968263b24bb7c955ee5799216 - -commit 30e11332031c8b5c288f95747867855e29514c3e -Author: Scott Moser -Date: Fri Feb 17 16:29:59 2012 -0500 - - Add support for volume types - - * Depends on https://review.openstack.org/4600 - - Change-Id: I56eace59f774623a2cb878657b3b797420c48408 - -commit 6d8e445b794aa4611e75835ace905dd73d3a342f -Merge: 03f54c5 7373740 -Author: Jenkins -Date: Mon Feb 27 18:17:32 2012 +0000 - - Merge "Fix for backward compatibility with stable/diablo flavors" - -commit 03f54c57e13f27324f0ac5aa556bf4ca94e3ed0e -Author: Vishvananda Ishaya -Date: Fri Feb 24 02:30:48 2012 +0000 - - Makes novaclient use the volumes endpoint - - * Depends on https://review.openstack.org/#change,4479 - * Adds support to change service type including tests - * Adds decorator for methods that need to use another service type - * Changes volume and snapshots to use the volume endpoint - * These extensions will move into the volume client once it exists - * Fixes bug 940017 - - Change-Id: I683e4ca6c67e278d8aa8a9acec3dc0f1872f43f2 - -commit 73737407422cff4f99eccfa7649d757b8cd27dd9 -Author: Anthony Young -Date: Thu Feb 23 14:11:29 2012 -0800 - - Fix for backward compatibility with stable/diablo flavors - - * Gracefully handle missing ephemeral attribute - * Fixes bug 939766 - - Change-Id: Iaff7a684ac03386ce821ba0007923c0f5f5e39ce - -commit 39bfd0585b8f1a08ebb62f429f7fb7fa57d6f982 -Merge: 924c5cc 97eaa1f -Author: Jenkins -Date: Wed Feb 22 22:34:53 2012 +0000 - - Merge "Add support for ephemeral_gb to novaclient." - -commit 924c5cc2f827f3a61ef360dc012471c70b52ded8 -Merge: cec7069 ddc1b2c -Author: Jenkins -Date: Tue Feb 21 21:36:17 2012 +0000 - - Merge "bug 932408: python-novaclient miss OSAPI host operations" - -commit 97eaa1f56fd32c168f98d45e1d5464f9ca851a58 -Author: Anthony Young -Date: Tue Feb 21 13:21:31 2012 -0800 - - Add support for ephemeral_gb to novaclient. - - * Fixes bug 932423 - - Change-Id: I57620db469f34aaf1ae61c6ef116a21ac9787e40 - -commit cec7069aa386eb48d432511932b197f50cab7fb0 -Author: Scott Moser -Date: Fri Feb 17 16:29:59 2012 -0500 - - allow '=' inside value of --meta=key=value - - Previously, you could not specify '--meta=mykey=value=1', as the - second '=' would cause an exception when creating a dictionary. - - The key name cannot contain a '=', but the value can, so we split only - once on '='. - - Fixes bug 934515. - - Change-Id: Ia416c3df59283fa963eb80370457e6c481336915 - -commit ddc1b2c083323781334fdca7467b4914e823e0d6 -Author: Armando Migliaccio -Date: Tue Feb 14 22:56:42 2012 +0000 - - bug 932408: python-novaclient miss OSAPI host operations - - add client bindings for host-related actions. - - Change-Id: I98b3c11ec189029bafe73f499070ab132de640af - -commit bca5acddafcf0cc7864022db92ae47ee1c61b29f -Author: Rick Harris -Date: Tue Feb 14 21:57:56 2012 +0000 - - Add ssh convenience command - - Change-Id: I8fc7bc3f0d9f415e83aa333dc4d8d5663300ff87 - -commit 68662fbc4ff10be28c3d94edd76ad0c887675beb -Merge: b58f15a 6fe7797 -Author: Jenkins -Date: Thu Feb 16 18:55:20 2012 +0000 - - Merge "Removes zones" - -commit b58f15a3a03f6eb170a9f81fe5eeb9b861bb9d70 -Merge: 1ee77c7 d991699 -Author: Jenkins -Date: Thu Feb 16 16:41:30 2012 +0000 - - Merge "add support for --config-drive 'boot' command" - -commit 1ee77c7fe314e015d14d9d5444fc21e84227bc47 -Author: Dave Walker (Daviey) -Date: Wed Feb 15 11:22:05 2012 +0000 - - Allow UUID_CACHE_DIR overriding via env variable. - - This is declared as NOVACLIENT_UUID_CACHE_DIR. - Resolves bug 932468 , defaulting to previous behaviour. - Added myself to AUTHORS - - Change-Id: I154500517d7c882a4a090588a95f4b3bfee70595 - -commit 6fe77972f5c28df813ee9ee788b8fcdc50f5953d -Author: Chris Behrens -Date: Tue Feb 14 22:04:14 2012 +0000 - - Removes zones - - As per the openstack meeting today, we will be removing zones from nova - for the Essex release. Therefore, we should remove it from - python-novaclient. - - Change-Id: Iccb363e4d7f24f3e0808dd9cda3b7558be76bae2 - -commit 7601bef9ef70ce69f544e0ffda904a04552bc38c -Author: Dean Troyer -Date: Mon Feb 6 11:28:46 2012 -0600 - - Fixes bug 925644: move dotfiles into dir - - Moves ~/.novaclient_cached_*_uuids into ~/.novaclient/*-uuid-cache - - Change-Id: I7dcd3678118f6c59ce81f83862c20da94d90bb74 - -commit d99169909dc719c16634e09370b0216dd4a457eb -Author: Scott Moser -Date: Thu Feb 9 22:26:37 2012 -0500 - - add support for --config-drive 'boot' command - - This just adds an optional '--config-drive' flag to the nova 'boot' - command. It allows the user to pass in a string. If the string is - 1, or case insensitive 'true': turn on config drive - 0, "" or case insensitive 'false' : disable config drive - anything else: pass directly through to let it be determined server side. - This would allow the volume id to be passed through. - - Change-Id: I220e6d8d285243e708237cd9012093e62b67b6e5 - -commit 5f89c8487d9b0cfe27cafd30d6d2a134290dafd9 -Author: Cole Robinson -Date: Fri Jan 20 16:28:09 2012 -0500 - - shell: Hook --debug up to more stuff - - Particularly to pythons logging infrastructure, and to always print - a backtrace if the CLI throws an exception. Show --debug in the - help output since end users may certainly have legitimate reasons for - wanting debug output. - - Change-Id: Icfdaaf5511db8eecbf650e7ef4437b342b560141 - -commit 8873e35eee7acb90e803b7427430edc12774439d -Merge: 3f9c3a6 87dab38 -Author: Jenkins -Date: Mon Feb 13 20:44:49 2012 +0000 - - Merge "Fix bug 904364: Consistiently handle trailing '/' on URLs" - -commit 3f9c3a6f1a57b11c05e162df0d1be9500b41dae3 -Author: Josh Kearney -Date: Thu Feb 9 14:34:12 2012 -0600 - - Properly handle KeyErrors. - - Change-Id: I350d737950a64881ed01e87e3d8fb2b6011f0bcc - -commit cb9a7a37a86688de59bf654e93266fcef96bd42b -Author: Paul Voccio -Date: Mon Feb 6 11:14:12 2012 -0600 - - adding credentials and endpoints output for debugging - - Change-Id: I74e12172d8c05df257c4b908e3278712a66f795a - -commit e2d869d1daaca1047665fc47afe5f162e884035b -Author: Dean Troyer -Date: Fri Feb 3 16:03:07 2012 -0600 - - Fixes bug 924588: Remove proto-keystone client from novaclient - - Change-Id: Ib3f3b8bfdefe56a13889796948a0186309c9a313 - -commit 3b010683126944a4508c1ad042217603f16608cb -Merge: 55bb8d7 0847282 -Author: Jenkins -Date: Fri Feb 3 23:44:25 2012 +0000 - - Merge "moves the "help" in the usage information of a wrong command to the correct position" - -commit 55bb8d7f53caa92245b8ec75663b0f37b9f96d50 -Merge: ce76160 d2be395 -Author: Jenkins -Date: Fri Feb 3 23:36:08 2012 +0000 - - Merge "Add --all_tenants option to 'nova list'." - -commit 87dab38b2b1ff7abaea9e456ca75286d0bba716c -Author: Dean Troyer -Date: Fri Feb 3 14:48:51 2012 -0600 - - Fix bug 904364: Consistiently handle trailing '/' on URLs - - novaclient used to require a trailing '/' on --auth-url and would - mysteriously break if it was not present. This is mostly due to - urlparse.urljoin()'s behaviour; it was only used here for concatenation - so it was eliminated and trailing '/' chars consistiently stripped. - All url concatenation now requires the second element to begin - with '/'. - - Change-Id: I99e95ea92682d917348201bc3190a1e77bbcbff0 - -commit ce761604a9a4f360a60966bb3b9dcc31d4a44aad -Merge: 19580ca 029f6fc -Author: Jenkins -Date: Fri Feb 3 22:00:04 2012 +0000 - - Merge "Adding describe-resource subcommand" - -commit 19580ca3f92230fe792c577bc6b96a52d459018c -Merge: 3a3f2b4 fe4fa9d -Author: Jenkins -Date: Fri Feb 3 16:15:32 2012 +0000 - - Merge "Add Accept: applicaton/json header to all service requests. Fixes bug 904436" - -commit 029f6fcbe5031a8d8cb0b9aead6e0a7cb37a8c44 -Author: masumotok -Date: Fri Feb 3 19:04:30 2012 +0900 - - Adding describe-resource subcommand - - Change-Id: I1acabee03be6bae194788176271acd9ae0e74bb3 - -commit fe4fa9daef26508c1e614e0a570b32e03821ee88 -Author: Matt Stephenson -Date: Thu Feb 2 16:37:55 2012 -0800 - - Add Accept: applicaton/json header to all service requests. Fixes bug 904436 - - Change-Id: I5f7c78f0ea516a7a96c32b1f745686e130c2b9af - -commit 3a3f2b4ff871e3ac61ca2a0b95903c54be9f7a22 -Author: Dean Troyer -Date: Thu Feb 2 10:32:30 2012 -0600 - - Blueprint cli-auth: common cli args - - Depricate --apikey, --projectid, --url (though still present for - compatibility). Fully support OS_* env vars per - http://wiki.openstack.org/CLIAuth Password Flow. - - Fixes lp897304 - - Change-Id: I655631194ed62133c24f30c9114e6fdc0fa77636 - -commit ae10b4bf5885e309a4f6c02952e9c6ffc5e8cac0 -Merge: 6dcdd21 9f216ab -Author: Jenkins -Date: Thu Feb 2 22:14:51 2012 +0000 - - Merge "Adding live migration subcommand" - -commit d2be395649f3737c14ca34e4aacdcd8c8d985bc6 -Author: Dan Prince -Date: Sat Jan 28 23:00:56 2012 -0500 - - Add --all_tenants option to 'nova list'. - - Fixes LP Bug #916219. - - Change-Id: Ibebabc2eb8ca77466085ed17b7a9805ccfebe484 - -commit 6dcdd2150dd9e02b86aa2cab006905bcf31cbd12 -Merge: 8b046fd f512f54 -Author: Jenkins -Date: Thu Feb 2 15:37:07 2012 +0000 - - Merge "Fix datetime issue with usage_data." - -commit 9f216abb47c1ab1fffe33f87b0fe2dc61b14f0fa -Author: masumotok -Date: Wed Feb 1 17:27:45 2012 +0900 - - Adding live migration subcommand - - Change-Id: I01c22502e3d13bb56de0a49a05d68b4c443f7055 - -commit 8b046fdeeb6654b459c99239f9adaac0f19c7b77 -Merge: 9d4b854 361d4d0 -Author: Jenkins -Date: Wed Feb 1 22:29:26 2012 +0000 - - Merge "Implementing Scheduling Hints." - -commit 9d4b854ff1f1b3795d51c5439a59f24b7c284fbc -Merge: 38bc7ea 9c6a1ac -Author: Jenkins -Date: Wed Feb 1 22:18:57 2012 +0000 - - Merge "do not require NOVA_VERSION in env, default to 1.1" - -commit 38bc7ea5707a1f6c84e55f3c684666db63cf21e9 -Author: Ziad Sawalha -Date: Tue Jan 31 18:08:22 2012 -0600 - - Handle Ambiguous Endpoints Correctly - - - Added --service_name argument to allow selecting - endpoints by service name - - Renamed endpoint_name argument to endpoint_type (this breaks - compatibility) - - Return AmbiguousEndpoints error if more than one endpoint - matches filter - - Also addresses bug 924052 - - Use case: - $ nova --projectid xxx --version 1.1 --password xxx --username xxx --url https://identity.openstackcloud.com/ image-list - Found more than one valid endpoint. Use a more restrictive filter - AmbiguousEndpoints: [ - {'serviceName': 'New Cloud', 'region': 'Test', 'publicURL': 'https://test.openstackcloud.com/v1.1/tttt', 'tenantId': 'tttt'}, - {'serviceName': 'Old Cloud', 'publicURL': 'https://servers.openstackcloud.com/v1.0/tttt', 'tenantId': 'tttt'}] - - $ nova --projectid tttt --version 1.1 --password xxx --username xxx --url https://identity.openstackcloud.com/ --service_name 'New Cloud' image-list - +--------------------------------------+-----------------------------+--------+--------+ - | ID | Name | Status | Server | - +--------------------------------------+-----------------------------+--------+--------+ - | 346f4039-a81e-4444-9223-4a3d13592a07 | Debian Squeeze (6.0) | ACTIVE | | - | ac8985ea-c09e-4544-82af-eb459a02a6b2 | Fedora 15 | ACTIVE | | - | ddddc02e-92fa-4f44-b36f-55b39bf66a67 | CentOS 5.6 | ACTIVE | | - +--------------------------------------+-----------------------------+--------+--------+ - - Change-Id: I9a10b9ad5e5b9cf6e762659013496a93a79774db - -commit 361d4d0b313db0ae302b358c6794f66158ef5242 -Author: jakedahn -Date: Thu Jan 26 14:57:06 2012 -0800 - - Implementing Scheduling Hints. - - * Extends server create action. - * adds --hint key=value to cli. User can use multiple --hint definitions. - - Change-Id: I4928dcbc3f321b8be7bd1f7461be1490666e2059 - -commit c3a0c702eee5454ddbd539f0af28f5f2dab8ee28 -Author: Brian Waldon -Date: Sun Jan 29 11:52:43 2012 -0800 - - Remove non-working --key_path argument on boot - - We can't inject an authorized_keys file since we can't control - the permissions of the file. Fixes bug 897214. - - Change-Id: I3263f0818e78ef048fdb35e858a22687dc46c381 - -commit f512f54bcccfa78b6bb77b691987cdde3ee98f35 -Author: Dan Prince -Date: Sun Jan 29 15:34:20 2012 -0500 - - Fix datetime issue with usage_data. - - Fixes LP Bug #923475. - - Change-Id: I663629142a8bd3ca8384ef8759d9138f8604db50 - -commit 0213eb4c0a364759e9de2fa25f46b43235db94bb -Author: John Garbutt -Date: Fri Jan 13 13:36:01 2012 +0000 - - blueprint host-aggregates: client bindings - - These are the client bindings for the new aggregate api added into nova in the following change: - https://review.openstack.org/#change,3109 - - Change-Id: I97e0223aa18d01450f82848c5be9bce78b83ef39 - -commit 0847282fd8d1f7d9a2cb985b492307a42d439a4f -Author: Christian Berendt -Date: Thu Jan 26 13:36:39 2012 +0100 - - moves the "help" in the usage information of a wrong command to the correct position - - fixes bug 922047 - - Change-Id: I9fdd76bd995a9bc4c469a8bcb47fe0e7f8a3d261 - -commit 36be4bf5759ae1f22c6eeeff5be01cf20e068bf3 -Author: jakedahn -Date: Fri Jan 20 15:08:53 2012 -0800 - - Implementing client for new x509 support in nova. - - * This depends on the approval of vishy's changes here: https://review.openstack.org/#change,3199 - * Adds novaclient library code, and cli. - CLI Use: - nova x509-create-cert [private_key_filename] [cert_filename] - nova x509-get-root-cert [cert_filename] - - Change-Id: If5b833b90bfb5bc16ea4636abb667717a67065d3 - -commit 25bb2a4125087ffe54aab41cdbce83a00bcb28e7 -Merge: 2f293a4 55ec391 -Author: Jenkins -Date: Wed Jan 25 01:06:56 2012 +0000 - - Merge "Catch novaclient up with renaming and other nova changes." - -commit 2f293a414488519af72f133915e2f56dbd67c588 -Merge: 632c608 65eb4a9 -Author: Jenkins -Date: Tue Jan 24 23:49:37 2012 +0000 - - Merge "Add flavor create/delete support" - -commit 632c608c5d400d4eb64a97e80876962e5e6e99af -Merge: c3b043b 5907f8c -Author: Jenkins -Date: Tue Jan 24 23:39:26 2012 +0000 - - Merge "Match create_image on server object and manager" - -commit 65eb4a9fb28a637dcc6408916398d15d8fc6a3fd -Author: Cole Robinson -Date: Thu Jan 19 19:57:04 2012 -0500 - - Add flavor create/delete support - - Makes use of the new nova module for flavor creation/deletion (still - under review at https://review.openstack.org/#change,3197 - - tests and cli commands added. - - v2: - Fix tests - Fix pep8 violations - - v3: - Drop unused import - - v4: - Usage defaults to end date 'tomorrow' - - v5: - Undo unintentional change - - v6: - Drop useless comment - Fix meta var name for flavor-delete command - - Change-Id: I14baa02d5cbe5eaf17875c285c993508b1671a13 - -commit c3b043be0e2309197776195ceb82d190aaa9046b -Author: Cole Robinson -Date: Sun Jan 22 18:56:39 2012 -0500 - - Add a 'usage' module and 'usage-list' cli command - - This module talks to the nova extenstion os-simple-tenant-usage, - replacing the openstackx module currently used by horizon. - - v2: - Fix some pep8 and style violations - - v4: - Have usage-list default to including todays usage - - v5: - Fix a HACKING violation - Fix rebase conflicts - - Change-Id: Ica0b128c7b807b839abf23b4026e48bbee08b1be - -commit de9813c6c596243d920a2b7552189a29fecb2fb2 -Author: Anthony Young -Date: Tue Jan 24 11:20:51 2012 -0800 - - Implement virtual interfaces servers api - - * Needed for openstackx dep removal - * No cli provided in this patch - - Change-Id: I873aed9e6887018db6169fffec79fc19ffc743be - -commit 44cc8542bc3236917439a4d70fe07b37bf84dcd7 -Author: Rick Harris -Date: Mon Jan 23 19:31:01 2012 +0000 - - Print adminPass when rescuing an instance. - - Fixes bug 920600 - - Change-Id: I8555545bbf9ce85809c4f32bcf652b20116fe8f3 - -commit 9c6a1ac205775e25c1e1ae3ac34a84849bf333a1 -Author: Scott Moser -Date: Mon Jan 23 13:10:03 2012 -0500 - - do not require NOVA_VERSION in env, default to 1.1 - - fixes bug 920474. - - the nova client was not defaulting to version 1.1 unless NOVA_VERSION was - set. This makes version 1.1 the default if NOVA_VERSION is not set in the - environment. - - It also makes shell.py usable from a git checkout as in: - PYTHONPATH=$PWD python novaclient/shell.py image-list - - Change-Id: I02b7e060d1c0694639fcb146a7394b92014c140b - -commit 5907f8ca9a2848aaffb9d2ab5faaf0ef5d4f3bc4 -Author: Brian Waldon -Date: Thu Jan 19 22:55:13 2012 -0800 - - Match create_image on server object and manager - - Fixing bug 910198 - - Change-Id: I436418cb041a751314498dde9efb4b326549672a - -commit 55ec3912e79766928115a590f3cd76cfd78f4589 -Author: Andrew Bogott -Date: Sun Jan 15 20:05:10 2012 -0600 - - Catch novaclient up with renaming and other nova changes. - - Added novaclient support for dns domain manipulation. - - This includes additions to the 'nova' commandline tool. - - For blueprint public-and-private-dns. - - Change-Id: I97b36d69f5f4abfbfa0ce416a347efa202fe3a0b - -commit 94f18f953c9f2d10be439a1ba97f549d7435b12f -Merge: 2c6c34d 4b9621c -Author: Jenkins -Date: Wed Jan 18 06:29:01 2012 +0000 - - Merge "Fix bad api call, 'migrate' is an action." - -commit 2c6c34dd1171dc7d687e15a062598b338084864d -Author: Anthony Young -Date: Thu Dec 29 00:35:29 2011 +0000 - - Add server.get_vnc_console functionality to python-novaclient - - Change-Id: I8784161ba0ff5adff10045097ed691246bee6e63 - -commit 4b9621cfae4da485d9f7be0b6b5ff61890461289 -Author: François Charlier -Date: Tue Jan 10 14:58:47 2012 +0100 - - Fix bad api call, 'migrate' is an action. - - 'migrate' was not called the way it is defined in the Nova api now. - - Fix bug 907547 - - Change-Id: I6f304809281e676c22f83492f9d0bb85e9528314 - -commit 559949c9b0ffa2dd5fcb173498d1b6ea92a0ceca -Author: Rick Harris -Date: Tue Jan 17 08:25:30 2012 +0000 - - Adding rebuild/resize hooks. - - References bug 917306 - - Change-Id: I6a65221b3bf218e631d74616c37fcdaf9bc16976 - -commit a2508aa9202638580d86a5975c6d5e144db2f6c8 -Merge: 317803d d175054 -Author: Jenkins -Date: Tue Jan 17 00:21:17 2012 +0000 - - Merge "Fix Quota ant SecurityGroup resources refreshing." - -commit 317803d245a8b914037408a12ddba25bebbe1939 -Merge: 764421b ee4696a -Author: Jenkins -Date: Tue Jan 17 00:12:05 2012 +0000 - - Merge "Clean FloatingIPDNS resource" - -commit 764421b44b53748681ba29f4013f90d5d24ac837 -Merge: d7fb1f3 149b248 -Author: Jenkins -Date: Mon Jan 16 21:25:13 2012 +0000 - - Merge "Get ImpLoader from ImpImporter for Py2.6" - -commit d7fb1f33cca07403944a4a4324dd19e28cc023a9 -Author: jakedahn -Date: Mon Jan 9 14:49:12 2012 -0800 - - Implementing Floating Ip Pools. - - See vishy's nova branch: https://review.openstack.org/#change,2892 - - Change-Id: I6a5bec55edd21f659674f478282e65fd6b1b0b1e - -commit 149b248a27aa185f0d86efaf90d1479f1e82192e -Author: Rick Harris -Date: Tue Jan 10 21:33:07 2012 +0000 - - Get ImpLoader from ImpImporter for Py2.6 - - Fixes bug 914476 - - Change-Id: I9fc8b89e66e8d8501262b3f93ce0b60470525426 - -commit c747f153ec103e52d3e743ba6257fba1c6796426 -Merge: 8651e97 4ff2770 -Author: Jenkins -Date: Tue Jan 10 12:51:13 2012 +0000 - - Merge "PEP8 python-novaclient cleanup" - -commit 8651e97afa92557211aab52a1dfde62bda0cc81f -Merge: 269d43a e984072 -Author: Jenkins -Date: Mon Jan 9 21:49:53 2012 +0000 - - Merge "Added command-line interfaces for the floating ip DNS api to nova." - -commit 269d43a38de26e2d95043351ef3c216e7ff067ee -Author: Rick Harris -Date: Fri Jan 6 16:37:28 2012 -0600 - - Discover extensions via Python's import paths - - Change-Id: I0f3b216737fad26157b20f0cf75c78108e4cfdbc - -commit 4ff27703d077fc83bb715060a774faf4a15e9736 -Author: lzyeval -Date: Wed Jan 4 09:54:39 2012 +0800 - - PEP8 python-novaclient cleanup - - Fixes bug #911552 - - The None, True, and False values are singletons. - - All variable *comparisons* to singletons should use 'is' or 'is not'. - All variable *evaluations* to boolean should use 'if' or 'if not'. - All Object type comparisons should use isinstance() - instead of comparing types directly - - Change-Id: Ia5571e58e2662c652f0e996d8c1a1acb4531623d - -commit 138dad3992f6b145768349cc854c2a79954b95e8 -Merge: 20be4a0 b921f21 -Author: Jenkins -Date: Thu Jan 5 19:35:53 2012 +0000 - - Merge "Add tox.ini file." - -commit 20be4a0add7824c8c2066fb8f2d00cfc31556d27 -Author: Chris Behrens -Date: Wed Jan 4 16:03:04 2012 -0800 - - show 409 responses - - 409s are getting eaten... and nova uses this to return error when not in - the correct state to do an operation. - - Change-Id: I76e9e98a89deb19e6b8aa32426fa31d6d66b8fdd - -commit e98407272d01b2098a1490456cacd9c4298857d3 -Author: Andrew Bogott -Date: Fri Dec 30 16:18:15 2011 -0600 - - Added command-line interfaces for the floating ip DNS api to nova. - - For blueprint public-and-private-dns. - - Change-Id: Idf89d532559c32cbaf015d17203ee927f18e985b - -commit 4c61a894570be736d0d102a7d6510b3984585247 -Merge: c879ee8 e0174b5 -Author: Jenkins -Date: Wed Jan 4 16:45:47 2012 +0000 - - Merge "Abstract Client building into novaclient.client" - -commit d17505462db3876a781016b16464e8ed967ae50d -Author: François Charlier -Date: Tue Jan 3 17:00:29 2012 +0100 - - Fix Quota ant SecurityGroup resources refreshing. - - The Quota and SecurityGroup resources were not refreshed correctly. - - Change-Id: I5b0a9efc07bc7ef05673256df5785aca931f64d8 - -commit ee4696aaa1d087045fff3ba0a8fc3eb03078f276 -Author: François Charlier -Date: Tue Jan 3 17:17:31 2012 +0100 - - Clean FloatingIPDNS resource - - create() and get() are not needed here : - - it's not the role of the resource to call 'create'. - - 'get' is here to refresh the resource. There's no mean to retrieve - for sure the resource (get by IP address *or* by name only). - - Change-Id: I97f4c26264b4abd0c1c8cdd91acc23ab6d6d008e - -commit c879ee8cc51777ab26fcb4cc6dfc590d77d3598d -Author: Monty Taylor -Date: Mon Jan 2 14:02:36 2012 -0800 - - Install a good version of pip in the venv. - - Change-Id: Ie318fa032fb6e88f250b1e67dbd903648cf8ea5b - -commit b99d66d3ade380f27a97007ec5d1ef28362ddaaa -Merge: 97d7b16 3758c26 -Author: Jenkins -Date: Sat Dec 31 00:09:33 2011 +0000 - - Merge changes I4c483825,Iba6ef2c1 - - * changes: - utils.find_resource fixes + fix for volumes - Add list() method to ManagerWithFind - -commit b921f21afe74c31e4957eef58abbf8d2484e5cc5 -Author: Monty Taylor -Date: Fri Dec 30 14:54:19 2011 -0800 - - Add tox.ini file. - - Adds support for using tox to do multi-version unittesting. - - Change-Id: I4476c44dd99b22d6ef96696848363d994670bf7d - -commit 97d7b16f03978e783adcb93ba2131c8fc552ebd8 -Merge: d18954f af7c33e -Author: Jenkins -Date: Fri Dec 30 18:38:25 2011 +0000 - - Merge "Fix typo in endpoint_name help string" - -commit d18954f4a8cf489d5e32766120f647c7a1057e92 -Author: François Charlier -Date: Fri Dec 30 17:40:02 2011 +0100 - - Add missing returns and remove superfluous ones - - Some methods which should have returned objects dit not return and some - methods which don't return anything used return ... Fixed all that and - added tests to detect two returns which were missing. - - Fixes bug 892058 - - Change-Id: If59468cfe1c7b1ab74ed0bfc6f81590dfd5dd668 - -commit af7c33ec431c03ad76a060100aaa7261adc08dd9 -Author: Julien Danjou -Date: Fri Dec 30 17:22:08 2011 +0100 - - Fix typo in endpoint_name help string - - Change-Id: Ibee3175b26af3eec033cdf2f35e49f268eef3796 - Signed-off-by: Julien Danjou - -commit b8e6ec895e65f246b93b16692c4c58c89fb47c18 -Merge: c9d87f9 61fb882 -Author: Jenkins -Date: Thu Dec 29 22:43:04 2011 +0000 - - Merge "python-novaclient missing pep8 in pip-requires" - -commit c9d87f9bacae04443de1889533e91b18e0df8236 -Author: Andrew Bogott -Date: Wed Dec 28 17:33:43 2011 -0600 - - Add the python api for floating IP DNS. - - For blueprint public-and-private-dns. - - Change-Id: I73d64f9e0ea6a1c913f427d1fd07b76d19e9f6a3 - -commit e0174b51bd20ac39b998eca4afdb510916cc61e8 -Author: Brian Waldon -Date: Thu Dec 29 15:37:05 2011 -0500 - - Abstract Client building into novaclient.client - - This prevents clients of the pythonic api from having to know the - internal module structure. - - Change-Id: Idd5c522ac3ff6c2d7915f96ed327323ec83d54fc - -commit 90212e9317581eace8c4329367f5645403a30989 -Author: Brian Waldon -Date: Thu Dec 29 11:10:04 2011 -0500 - - Remove unused imports and fix NameError on exc - - Change-Id: Ie35ccd7abaada74acb298ace97ae88eb0e0cce1e - -commit 24388696551f97d41195241ff1a3bb0087305039 -Author: Andrew Bogott -Date: Wed Dec 28 17:28:56 2011 -0600 - - Improve the test framework to handle urls with args. - - Now a url like 'os-foo-bar/blah?arg1=apple&arg2=orange' will - invoke a fake function like 'os_foo_bar_blah' and receive - the arguments (arg1=apple, arg2=orange) as part of its - kwargs. - - Change-Id: If2905ed0f335128ccd4100997354dfe12e0017fd - -commit f849419ab20b926caebf362b4e4df1985f847a7e -Merge: 01a2b6c d2e054f -Author: Jenkins -Date: Wed Dec 28 23:24:20 2011 +0000 - - Merge "Simplifying get_console_output client interface." - -commit 01a2b6ca5fb4c5b1b2896ae5fdc7d9f1272f27e8 -Merge: 4d5946a d7f04e1 -Author: Jenkins -Date: Wed Dec 28 23:20:11 2011 +0000 - - Merge "Removing cache-busting query param (fresh)" - -commit d2e054f07acd01de3fd00e5df260ee5ddae9dece -Author: jakedahn -Date: Wed Dec 28 15:12:28 2011 -0800 - - Simplifying get_console_output client interface. - - Now instead of doing server.get_console_output()[0]['output'] - You can do: server.get_console_output() - - Change-Id: Ic8a3f435fa0111feaa0d5cd42943dd2c7c243fb9 - -commit d7f04e19fea9c9d7ba28e3ca13adf413259e41d2 -Author: Brian Waldon -Date: Wed Dec 28 17:12:26 2011 -0500 - - Removing cache-busting query param (fresh) - - Change-Id: I9154baef778fd2790f4933918f3a48ec94fc7214 - -commit 4d5946afab43a33dfa280afc479eaec0560f0a01 -Author: jakedahn -Date: Wed Dec 28 13:04:43 2011 -0800 - - Adding return statement to get_console_output - - fixes bug 909483 - - Change-Id: Ic5e425319f7fe97b6f04f324f085632147cf13d0 - -commit 61fb88280a302e429ecb5712ca994383ce1e913c -Author: lzyeval -Date: Wed Dec 28 10:38:16 2011 +0800 - - python-novaclient missing pep8 in pip-requires - - Fixes bug #909210 - - Change-Id: I5be35665aa057997c7911aa903c4a123b8329111 - -commit eee43516b84ff11087d7a73e92691298bbd7f4b2 -Merge: 88bdfdd 6ba0c64 -Author: Jenkins -Date: Tue Dec 27 20:09:25 2011 +0000 - - Merge "Allow to not specify image if block_device_mapping is set" - -commit 3758c260a0b432affbe511068384854e5f9684df -Author: Julien Danjou -Date: Tue Dec 13 16:59:15 2011 +0100 - - utils.find_resource fixes + fix for volumes - - Nova volumes do not have a name property but a displayName one, therefore we - modify find_resource() so it looks for this. Then, we modify the test suite - for utils.py so it uses the novaclient.base.ManagerWithFind class for its - FakeManager rather than implementing its own find() method. This way we are - sure that the utils.py functions work correctly with ManagerWithFind and its - way to search in objects list. - - FakeResource class is now used, whereas it was not before. - - Change-Id: I4c4838250e6987e05022e1607e8d099eb8fb7fff - Signed-off-by: Julien Danjou - -commit 3fcf4a13740af5c82ef394fffe1bd3761a67757c -Author: Julien Danjou -Date: Tue Dec 13 16:57:14 2011 +0100 - - Add list() method to ManagerWithFind - - ManagerWithFind.find() method wants to use self.list() but Manager does not - provides it. Therefore, it's better to implement it as an interface here, - and raise a NotImplementedError. - - Change-Id: Iba6ef2c1f789c2eb12b210d42261d63796db3407 - Signed-off-by: Julien Danjou - -commit 88bdfdd12f832c0bfbde6680828d86fa4e2f74e1 -Author: Rick Harris -Date: Wed Dec 21 19:25:19 2011 +0000 - - Extensions can now modify resources. - - Change-Id: I0d9c1050428d0ccf2e2b18053d75e0465463c08b - -commit 68d0abb061abd8f20baf8bf5f2be4c7b80ce8069 -Author: Jesse Andrews -Date: Wed Dec 21 09:59:01 2011 -0800 - - more work towards standardize config - - Change-Id: I63ca85c56a61b8412bdc8bf30d6a179b134faff4 - blueprint: cli-auth - -commit 6ba0c64cc27d147b42e5d6a919490c4bcdf2bd0f -Author: Julien Danjou -Date: Tue Dec 13 18:19:43 2011 +0100 - - Allow to not specify image if block_device_mapping is set - - Change-Id: Ibdd900264f2e80e9d9c04de6d3bcb60b546fa3f2 - Signed-off-by: Julien Danjou - -commit 26ba43db9dae3b166acac407a84ba25aa3d766fa -Author: Jake Dahn -Date: Tue Oct 25 16:55:33 2011 -0700 - - Adding support for the os-getConsoleOutput server action. - - Change-Id: I8b4a82ba42e00e5b312d7cad79c2f9725c6b48a7 - -commit 450952b5987414769a74625540ed5565dece8ea7 -Merge: 487032a 49284dc -Author: Jenkins -Date: Tue Dec 20 18:54:57 2011 +0000 - - Merge "Add 'discover' command for Keystone discovery and version listing" - -commit 49284dc5cdbaeb70ebc5c56b9cdefbc40df9460d -Author: Ziad Sawalha -Date: Thu Nov 17 05:12:46 2011 -0600 - - Add 'discover' command for Keystone discovery and version listing - - Added @unauthenticated decorator to mark subcommands that do not - need authentication. And checks to skip authentication for these - commands. - Added novaclient.keystone to setup.py - - Change-Id: Id2fd60af305c30a950bdbae8f897192bfae4d797 - -commit 487032ae07ea1ec703df4839fd9f251368b61ecf -Author: lzyeval -Date: Tue Dec 20 11:49:45 2011 +0800 - - User friendly help message - - Fixes bug #892066 - - Change-Id: Ibeb86c5a9ae0f1dcc313c77fdf923a2eb37de505 - -commit e20dcd8cd74fd5076a0aa669b076df82f9056c57 -Merge: 1e8c0bf 95f277a -Author: Jenkins -Date: Mon Dec 19 20:19:37 2011 +0000 - - Merge "standardize environmental settings for cli auth" - -commit 1e8c0bfa3f88362fc965e18cd5898a8578c5733f -Author: Julien Danjou -Date: Mon Dec 19 17:25:48 2011 +0100 - - Do no depends on argparse for Python >= 2.7 - - Python >= 2.7 has argparse has a builtin module, so there's no need to add - it to the this list of requirements. - - Change-Id: I647cec70a564b1d184f0cb2aca6caf4d6478c403 - Signed-off-by: Julien Danjou - -commit 95f277a09ff5acda1535b76b9faefe05ffb28e50 -Author: Jesse Andrews -Date: Fri Dec 16 00:10:47 2011 -0800 - - standardize environmental settings for cli auth - - a first pass at common configuration between cli tools - https://blueprints.launchpad.net/openstack-common/+spec/cli-auth - - Change-Id: Ie1354268ef647fb265ad9f30e730ddcac990e7f7 - -commit 3661be66730efd4bce32fd54e2443c42ad91edbd -Author: Rick Harris -Date: Thu Dec 15 23:10:59 2011 +0000 - - Removed v1.0 support. - - Change-Id: I6850075a2ac0e1558aa94539e73f4fb939dfb318 - -commit b3f48f70647ebebe227dc03b1e0ae119010599d9 -Author: Rick Harris -Date: Thu Dec 15 22:38:05 2011 +0000 - - Making contrib a Python package - - Change-Id: Ibfde2e5cbececeec0b6a17f7d71da207f582a5c7 - -commit 82d3099a08c78754bbf21097b34bcdb0268717ab -Merge: 50169b9 bb879dd -Author: Jenkins -Date: Thu Dec 15 21:12:38 2011 +0000 - - Merge "Adding extension framework." - -commit bb879dd10b37a884a7e724d7a7cbd204041061e0 -Author: Rick Harris -Date: Thu Dec 15 19:39:33 2011 +0000 - - Adding extension framework. - - Change-Id: If882f7a822ef6b1e58666b3af6f7166ab0a230fe - -commit 50169b9017e8c65e14bf8b3c7e0d8ce1a1b28bad -Author: Julien Danjou -Date: Thu Dec 15 11:59:06 2011 +0100 - - Fix typo in README - - Change-Id: If165635e3cf73488b305d0b2c4fc9515b7a0849f - Signed-off-by: Julien Danjou - -commit a905e5fe0713a55c7b7ee7384b145fc3f4a18ba9 -Author: Brian Waldon -Date: Fri Dec 9 14:26:06 2011 -0500 - - Accept 1 and 2 as version choices - - - removes all unused imports - - update .gitignore with new venv path - - Change-Id: I3e8199b72dc83268115133d7c73335ffb6060f9a - -commit 6509fe253f9e40f217d6c483941af6fa56bc23f7 -Author: Josh Kearney -Date: Tue Dec 13 15:54:09 2011 -0600 - - Add support for RAX authentication. - - Change-Id: Ia9180a3919373d3ec2e794d4dffe21838b23fc95 - -commit 1acbbb0c2d1fc152102635f0b7f66910a945b479 -Author: Monty Taylor -Date: Wed Dec 14 10:14:08 2011 -0500 - - Align run_tests.sh with nova. - - We need for run_tests.sh to accept the same inputs and outputs from a CI - perspective. In this case, the easiest way was just to port in run_test.py. - Additionally, we need with_venv.sh to exist. - - Change-Id: I25e659ed796c8a70239aab610f5b014b35443b67 - -commit ccb5f8f1b4227753a3a13f8a171321d796621c55 -Author: Thierry Carrez -Date: Wed Dec 14 11:22:32 2011 +0100 - - Switch versioning to common Nova versioning - - Use "2012.1" as the version for python-novaclient, to align with - Nova common versioning (starting with Essex-2, python-novaclient - is shipped as a Nova project deliverable. Fixes bug 904182. - - Change-Id: I85d742a346bbaae1dc92a476c140f7f862a0828c - -commit b45ea3ac450a8e0a3b82b2f05d2340c33da8c53c -Author: Julien Danjou -Date: Tue Dec 13 17:35:50 2011 +0100 - - Fix PEP8 error - - Change-Id: Ib8f4027af6f0583c60ca937328cc84a34909b4a4 - Signed-off-by: Julien Danjou - -commit f737a8c3bbbd30428cdecec500d2275a5f74ba89 -Author: Monty Taylor -Date: Fri Dec 9 13:37:03 2011 -0800 - - Add MANIFEST.in and setup.cfg back. - - These files are actually needed - without MANIFEST.in, files are missing - from the source tarball which is used in debian packaging. setup.cfg is - needed for configuration of the sphinx doc build commands. - - Additionally, I added listings for the other files in the root to - MANIFEST.in so that the source tarball would be complete. - - Change-Id: Ia0f281663b58baaf2ee23f627d4b1887d0eddfe9 - -commit 959c44ff5956b7e42134aef319f33f2b756bfcc7 -Author: Brian Waldon -Date: Tue Dec 6 12:11:50 2011 -0500 - - Adding 'absolute-limits' and 'rate-limits' - - Change-Id: Ie1dff62f3a3dd74e96c8cad7c079b7378d25ae46 - -commit 11a4ecfe44dafad17105e585c35fbf27d1b3ae0a -Merge: 578fc1c 596eb3c -Author: Jenkins -Date: Wed Dec 7 20:07:27 2011 +0000 - - Merge "Fixing all remaining pep8 errors" - -commit 596eb3c0a5fdde14fb1d0ddafd7f9262285f6735 -Author: Brian Waldon -Date: Wed Dec 7 14:37:17 2011 -0500 - - Fixing all remaining pep8 errors - - Change-Id: Iaf50bce4a6d458b37bc5e790b7d3ee56085c3e36 - -commit 578fc1cb72264ed54270daf956eb867bd5829520 -Author: Brian Waldon -Date: Wed Dec 7 11:12:35 2011 -0500 - - Clean up image-list cli command - - - properly determine what server an image was created from - - remove mapping of server id to name in image-list - - remove an extra image list query in imgae-list - - Change-Id: Ib7c8fd784d21e658cb57dd9f9f2cd39e1cb11121 - -commit f866c6ec3fd1f54d5d80cd5a59bf33932fe83d65 -Author: Brian Waldon -Date: Wed Dec 7 11:40:45 2011 -0500 - - Clean up image-show - - - parse server entity to just an id - - parse metadata out into separate rows - - Change-Id: I8927b148714a7f5ed64bbb74bd79193e258cb34d - -commit 9067f2607716706796b9ef25e627c99092712d76 -Author: Lorin Hochstein -Date: Thu Dec 1 22:13:07 2011 -0500 - - Updated README.rst - - - Changed link from Rackspace API docs to OpenStack API docs - - Fixed Github link - - Added Launchpad link - - Added Gerrit link - - Change-Id: I0494e4c4a8722c182c63515cb6079d2c1557b52f - -commit b61a8d8c2483847ab34ed41b473c833cbc4df4a6 -Author: Aaron Lee -Date: Thu Dec 1 11:09:38 2011 -0600 - - Converting rxtx_cap and rxtx_quota to rxtx_factor - - And adding myself to AUTHORS - - Change-Id: I88d3d4c290ab883cf52945edeec62acbee3761d0 - -commit 2f49282bd0260953cc4de85a62189c237a699b67 -Author: Kiall Mac Innes -Date: Tue Nov 29 21:54:09 2011 +0000 - - Gracefully handle failure to cache UUID's. Bug #897885. - - Change-Id: I2ef58a218277b2a62c0e24c907250421dccffe9a - -commit 674c63e99d1f99d4238dff3329faeb8f19235d2e -Merge: f48d8cb 72c5ca3 -Author: Jenkins -Date: Mon Nov 28 20:00:17 2011 +0000 - - Merge "Change 'zone_blob' key to 'blob' in create server. bug 893183" - -commit f48d8cb5e69dd09826114803e8018fc00809137d -Merge: 69f7e87 58af45c -Author: Jenkins -Date: Mon Nov 28 00:24:57 2011 +0000 - - Merge "Adding UUID cache for bash autocompletion." - -commit 72c5ca3aeca8782def98d9254b73a44be80c8b07 -Author: Édouard Thuleau -Date: Tue Nov 22 10:20:49 2011 +0100 - - Change 'zone_blob' key to 'blob' in create server. - bug 893183 - - The OSAPI looks for key 'blob' to check if a build plan - is associated to a create request server. But the - novaclient uses the key 'zone_blob'. - - Change-Id: I85fd3629e1b3a2f142ac9296418e361aff5c5e4b - -commit 69f7e87b16ca5413a4270967c7e325c2f1a227ea -Author: Kevin L. Mitchell -Date: Mon Nov 21 16:05:54 2011 -0600 - - Fix spacing errors in authentication exceptions. - - Change-Id: I44c7aaac3c6f7ad01b4580bc3ffcf3ce798936d8 - -commit 58af45c9471107ce54cea5fe5d4ca7cc0bff56fa -Author: Rick Harris -Date: Sat Nov 19 18:14:10 2011 -0600 - - Adding UUID cache for bash autocompletion. - - Change-Id: I3d8abea8d99c406f237b8e500e1decf8d24f22d9 - -commit 0e1e38d2e43fddb90b8010bd3e43b3da641cf643 -Author: Chris Behrens -Date: Thu Nov 17 12:48:58 2011 -0800 - - Revert api_key change in novaclient Client argument - - Fixes bug 891442 - - Also, still need to support NOVA_API_KEY environment variable for now. - Bump version to 2.6.8 so we can get this into pypi - Updated setup.py to build properly - - Change-Id: I16233ac559bf44b78666118d68975509da6bfb0d - -commit 7a179e6577f176bedfe7a1faa39081c416dbd2e7 -Merge: 149e00b 49efa22 -Author: Jenkins -Date: Thu Nov 17 18:42:15 2011 +0000 - - Merge "Rewriting admin-only calls as server actions" - -commit 149e00bcf5eeb16e4e5cc13840cdb6d0fe2897e3 -Author: Josh Kearney -Date: Wed Nov 16 15:21:25 2011 -0600 - - Adds bash completion support and cleans up setup.py. - - Also removes some unnecessary files and updates the AUTHORS file. - - Change-Id: Iefa502ce08cbf34038d2e04d0460ae43468a4255 - -commit 49efa22054818db3bd68f06dd1ace17e65c70345 -Author: Brian Waldon -Date: Wed Nov 16 15:06:57 2011 -0800 - - Rewriting admin-only calls as server actions - - Change-Id: I3345dac84675aa8e7eb6cd72180ca53296937082 - -commit d14e421ade04ecac86d0bd7bb56ded1c66f88ad9 -Author: James E. Blair -Date: Wed Nov 16 09:27:59 2011 -0800 - - Add rfc.sh. - - This is a tool to help with submitting changes to gerrit. - - Change-Id: I962c8e79bf10d881548a9c258065fb83a5d89cb4 - -commit 2229163a7a4f47e2b8306bcdf7d42183fd6967de -Author: James E. Blair -Date: Wed Nov 16 09:22:28 2011 -0800 - - Add .gitreview config file for gerrit. - - The CI team is developing a new tool, git-review: - - https://github.com/openstack-ci/git-review - - which is intendend to replace rfc.sh. This adds a .gitreview file - so that it can automatically determine the canonical gerrit location - for the repository when first run. - - Change-Id: I4d71e9a8b5463e29449a3da2739a15f40970354b - -commit 464fbbcb603eb9c61aa52a86b4e2b6e6b0b8e7e9 -Merge: 007c795 36f34d9 -Author: Sandy Walsh -Date: Wed Nov 16 08:51:01 2011 -0800 - - Merge pull request #144 from jstraw/master - - Add parent server information to the shell output of image-list - - Rushed through for gerrit move - -commit 007c795a9322ca0596d863a7c514cf296bf83d41 -Merge: 1f4971a 69c5327 -Author: Sandy Walsh -Date: Wed Nov 16 08:49:12 2011 -0800 - - Merge pull request #149 from SandyWalsh/endpoint_name - - added --endpoint_name support - - Rushed through for gerrit move - -commit 69c5327363a27466efae19436348c7ec44e98263 -Author: Sandy Walsh -Date: Wed Nov 16 08:47:37 2011 -0800 - - pep8 - -commit 4f107d7463c03ff8e3f0b04f2c38797432060cda -Author: Sandy Walsh -Date: Wed Nov 16 08:45:33 2011 -0800 - - fix tests - -commit f53675a4dd632506c7f474d386917cbd7e5aef61 -Merge: 13b7edf 1f4971a -Author: Sandy Walsh -Date: Wed Nov 16 08:44:31 2011 -0800 - - trunk merge - -commit 1f4971a1360b27ce25d05a1d6d518ca53856a649 -Merge: 897592d 00f0531 -Author: Sandy Walsh -Date: Wed Nov 16 08:38:52 2011 -0800 - - Merge pull request #150 from SandyWalsh/remove_api_key - - Remove api key - -commit 897592d8e3bfd94a9f27cd2e91f284671d5416f2 -Merge: 50a2f62 528b3e4 -Author: Sandy Walsh -Date: Tue Nov 15 18:40:38 2011 -0800 - - Merge pull request #137 from danwent/master - - novaclient changes to use os-create-server API extensions for v1.1 - - (pushing through to prepare for gerrit move) - -commit 528b3e4d4446cdfffcb3ba4c6e02a8b1db9abf04 -Author: Dan Wendlandt -Date: Tue Nov 15 18:32:16 2011 -0800 - - Add support for specifying VIF networks while booting. - - Specifying VIF network while booting uses a subset of the - os-create-server-ext. Goal is that the CLI syntax - is sufficiently general that we can expand it to incorporate other - parameters once the API supports them (e.g., v6_fixed_ip, specifying - IP by melange subnet, etc.). The syntax is supposed to slightly mirror - creating server NICs with KVM. - -commit 50a2f62f1cb286bf571cf7e62827aaeb86a72e32 -Merge: 216be72 ff48a3e -Author: Sandy Walsh -Date: Tue Nov 15 12:14:08 2011 -0800 - - Merge pull request #136 from gagupta/master - - Enabled creating a volume from a snapshot - -commit 216be725977bdef38611b03bbe3cdffa421ef0e0 -Merge: f513bdc 7adecf7 -Author: Sandy Walsh -Date: Mon Nov 14 09:24:29 2011 -0800 - - Merge pull request #151 from klmitch/keystone-redirect - - Follow redirects when calling out to Keystone. - -commit 7adecf7c3bef46e133e7145d4e7e0ed1b7453ee5 -Author: Kevin L. Mitchell -Date: Mon Nov 14 10:39:16 2011 -0600 - - Use a try/finally to ensure state restoration - -commit 5bc980105bdf7b5423d15b81f8d7f29763f82b3b -Author: Kevin L. Mitchell -Date: Wed Nov 9 16:54:58 2011 -0600 - - Follow redirects when calling out to Keystone. - -commit ff48a3e1ec95cc12688b1b72189a114d2b4fadda -Merge: 3d03a25 f513bdc -Author: Gaurav Gupta -Date: Wed Nov 9 10:49:51 2011 -0800 - - Merge branch 'master' of git://github.com/rackspace/python-novaclient - - Conflicts: - novaclient/v1_1/shell.py - -commit 3d03a25363b49adf5e298ef53e6d6116a20b1194 -Author: Gaurav Gupta -Date: Wed Nov 9 10:36:16 2011 -0800 - - Modified as per code-review comments: - - Renaned snapshot to volume-snapshot - - Created a new file for volume snapshots - - Review: - https://github.com/rackspace/python-novaclient/pull/136#issuecomment-2623509 - -commit 00f05317efb8bab78d487a7c36571082269d3139 -Author: Sandy Walsh -Date: Wed Nov 9 07:18:22 2011 -0800 - - few missing references to api_key - -commit cdde0d22cd4b9be02fd2080687ebd02fda80b7f3 -Author: Sandy Walsh -Date: Wed Nov 9 07:10:46 2011 -0800 - - tests working - -commit c386221bd8f757fe98abd076d21f3a1fdd9712e2 -Author: Sandy Walsh -Date: Wed Nov 9 04:35:39 2011 -0800 - - started - -commit 13b7edfc420d3cf537cbb43f66f73356aa891eb8 -Author: Sandy Walsh -Date: Tue Nov 8 10:27:41 2011 -0800 - - added --endpoint_name support - -commit f513bdccc5dd92c0959ea4d061fb08ca00c62b87 -Merge: beb40d3 e4d6ec7 -Author: Kevin L. Mitchell -Date: Fri Nov 4 13:10:22 2011 -0700 - - Merge pull request #148 from rconradharris/add_back_admin_pass - - Add back display of adminPass to boot - -commit e4d6ec757a79e8ce5183f1ee67d372541d7e411b -Author: Rick Harris -Date: Fri Nov 4 19:57:52 2011 +0000 - - Add back display of adminPass to boot - -commit beb40d3adcc15e57d72678be1c1a5aa522b9520f -Merge: fcfa928 05a1ef7 -Author: comstud -Date: Fri Nov 4 11:53:07 2011 -0700 - - Merge pull request #147 from SandyWalsh/flavors_are_strings - - Boot now works with limited info returned from server - -commit 05a1ef7e95adcdcb907b2c980866abf790b465d0 -Author: Sandy Walsh -Date: Fri Nov 4 11:41:40 2011 -0700 - - Boot now works with limited info returned from server - -commit 36f34d998365bfdfb20dc26c890238127e1fd24d -Author: Jason Straw -Date: Thu Nov 3 23:46:08 2011 -0500 - - fixed missing line continuation characters in shell.py - - updated tests to use serverId 1234 instead of 12 to - allow the tests to function on new image list - -commit 690f3d386600d6c55607bd41b920d458da7f75ac -Author: Jason Straw -Date: Thu Nov 3 22:44:22 2011 -0500 - - PEP8 cleanups of utils, and the v1_?/shell.py files - -commit 4443a069acfa3ddadeaee4c3ee45e0e865bbd6f3 -Merge: 66d8bc4 fcfa928 -Author: Jason Straw -Date: Thu Nov 3 22:29:25 2011 -0500 - - Merge branch 'master' of git://github.com/rackspace/python-novaclient - -commit fcfa9288e081631d350d97deb318d0ebe5e6dd10 -Merge: 4397298 1f8c6f8 -Author: Sandy Walsh -Date: Thu Nov 3 10:29:21 2011 -0700 - - Merge pull request #145 from nmistry/master - - Command line arg to disable ssl certificate validation - -commit 1f8c6f8ee2cf173e682f678a4311d3a0829979c3 -Author: Nicholas Mistry -Date: Thu Nov 3 11:52:42 2011 -0500 - - minor pep8 tweaks - -commit 507231fa7af285b183fc0a37011b89b2c35859af -Author: Nicholas Mistry -Date: Thu Nov 3 11:34:44 2011 -0500 - - corrected argument order and replaced tabs with spaces. - -commit 1015cab9fdeee4ada5fe5fe6da8bddf77bc2cdd8 -Merge: f68120f 4397298 -Author: Nicholas Mistry -Date: Thu Nov 3 11:06:24 2011 -0500 - - resolved merge conflict. - -commit f68120f9d22b7d50ca18a89bbb845ebd4ca61ac2 -Author: Nicholas Mistry -Date: Thu Nov 3 11:00:58 2011 -0500 - - added a space after url - -commit 4397298b36fb838d926e9d708499fb3a0e8f8106 -Merge: 2b0d82c 557b4ee -Author: Sandy Walsh -Date: Thu Nov 3 08:16:05 2011 -0700 - - Merge pull request #141 from SandyWalsh/new_keystone_admin_port - - New keystone admin port - -commit 84076fed6c569219cb431da66fc9e16de1782b0b -Author: Nicholas Mistry -Date: Thu Nov 3 02:13:36 2011 -0500 - - Added the option --insecure. This disables SSL certificate validation. - -commit 66d8bc49b70be382b2699d2b883ce265ff915e02 -Author: Jason Straw -Date: Sun Oct 30 17:20:47 2011 -0500 - - Updated the novaclient shell to display the parent server id that the image came from. - -commit 98cbe4620e3f5eb73abf530521957e9d5fd7fc6c -Author: Gaurav Gupta -Date: Wed Oct 26 10:57:08 2011 -0700 - - Fixed description for block_device_mapping parameter - -commit 557b4eee470b3ee403eddce65eeb28cb55476561 -Author: Sandy Walsh -Date: Tue Oct 25 16:49:22 2011 -0700 - - minor fixes - -commit c37a8b33714c0ad6f6697a81770d48b2726d1e18 -Author: Gaurav Gupta -Date: Tue Oct 25 13:45:59 2011 -0700 - - Added support for boot from volume (or snapshot) - -commit 440e03ec4899b7b2e73bc047c8983ac5a8a6a651 -Author: Sandy Walsh -Date: Tue Oct 25 09:38:37 2011 -0700 - - version update - -commit 0a3eda6cdd5e6d2141b04c1ddff1296f1be0b0b7 -Author: Sandy Walsh -Date: Tue Oct 25 09:34:23 2011 -0700 - - minor tweaks and long overdue pep8 - -commit 881427de9d6cdf70df25d072b7a601c0d42e5293 -Author: Sandy Walsh -Date: Tue Oct 25 06:28:30 2011 -0700 - - new service catalog semantics - -commit 5c38baf65a39800b48a2d7b696b3090ea775176a -Author: Gaurav Gupta -Date: Wed Oct 19 10:54:27 2011 -0700 - - Added support for listing/creating/deleting snapshots of nova volumes. Also - implemented the supporting CLI commands. - Requires the OS API extension, 'os-snapshots' - -commit 2a0b3b5311d4294d6f0505d137b7e5da9b00e81c -Merge: 66f2432 2b0d82c -Author: Gaurav Gupta -Date: Wed Oct 19 08:33:56 2011 -0700 - - Merge branch 'master' of git://github.com/rackspace/python-novaclient - -commit 66f2432f659f9b4a2fc6c5b322c98ec2545d5b0e -Author: Gaurav Gupta -Date: Wed Oct 19 08:31:16 2011 -0700 - - Updated volume-create command to accept an optional attribute, snapshot_id. - This enables the user to create a volume from a snapshot. - -commit 2b0d82c05cf9f19c01752a75804cdcadf80e82ee -Merge: b2d3d21 aba2ced -Author: Sandy Walsh -Date: Mon Oct 17 15:44:42 2011 -0700 - - Merge pull request #135 from gabrielhurley/keystone_client_url_for - - Fixes #133 -- Keystone Client fetches correct service type and endpoint. - -commit aba2ced0fb42489a6a7d03574a2111112f2e8a56 -Author: Gabriel Hurley -Date: Mon Oct 17 14:42:23 2011 -0700 - - Fixes #133 -- Keystone Client fetches correct service type and endpoint. - - Made ServiceCatalog.url_for more configurable by allowing keyword arguments to control which service type is fetched and which endpoint is returned instead of having those values hard-coded to "compute" and "publicURL" respectively. The fix to keystone.client.Client allows the openstackx Account API to be deprecated in openstack-dashboard. - -commit b2d3d2104934ea2044790b658888256c006df0c5 -Merge: e4a0e24 10c1f4b -Author: Jesse Andrews -Date: Mon Oct 17 14:26:09 2011 -0700 - - Merge pull request #134 from cloudbuilders/keypair - - Implementing work with keypairs and add feature for boot command - -commit 10c1f4b11b59a43edddac690db763b93cde521fe -Author: Jesse Andrews -Date: Mon Oct 17 14:23:04 2011 -0700 - - fix tests - -commit 4a168d5460b7ff42588d22239b665bd691abb0e2 -Author: Jesse Andrews -Date: Mon Oct 17 14:18:38 2011 -0700 - - typo - -commit 6955852694a266f881447261d0079a50dbba78cc -Merge: e4a0e24 d6e6e04 -Author: Jesse Andrews -Date: Mon Oct 17 14:09:25 2011 -0700 - - merged and fixed pshkitin's keypair work - -commit d6e6e044eab38a81c0ddd228cdc7825efec61bd8 -Author: Jesse Andrews -Date: Mon Oct 17 13:57:56 2011 -0700 - - doc improvements - -commit e4a0e2411bcce39aa254423d39b09e53bb5877da -Merge: a76c9a3 0b0abff -Author: Jesse Andrews -Date: Mon Oct 17 13:34:49 2011 -0700 - - Merge pull request #128 from UnmeshG/master - - Added support to specify few more boot options. - -commit a76c9a321822ba89260011ca72fa6715fa95c33e -Merge: 13a2077 32510bd -Author: Jesse Andrews -Date: Mon Oct 17 13:33:06 2011 -0700 - - Merge pull request #125 from gagupta/master - - Added CLI commands to access nova volume - -commit 0b0abff45226645c73c29f57a8ab595f17bdf194 -Author: Unmesh Gurjar -Date: Mon Oct 17 12:46:05 2011 +0530 - - Added support to specify more boot options. - - User data can be a file name only, removed support for user data string. - -commit 32510bdee9a3030f3ecdc0ddb87ee06318ced15e -Merge: cd9f3cb 13a2077 -Author: Gaurav Gupta -Date: Sun Oct 16 15:27:25 2011 -0700 - - Merge branch 'master' of git://github.com/rackspace/python-novaclient - - Conflicts: - novaclient/v1_1/shell.py - -commit cd9f3cb47e7fc02e843867cac7bd8c309ebb24f5 -Author: Gaurav Gupta -Date: Sun Oct 16 15:21:53 2011 -0700 - - Updated volume attach/detach commands to accept server name (in addition to - server id). - Code review comments: - https://github.com/rackspace/python-novaclient/pull/125/files#r169829 - -commit 13a2077b7a60319ff72382100f801f157e6e6203 -Merge: 960cfbe ac163b4 -Author: Jesse Andrews -Date: Fri Oct 14 10:55:37 2011 -0700 - - Merge pull request #130 from cloudbuilders/security_groups_cli - - Security groups cli - -commit ac163b43479bd8ca2c2761ef4cdf962853fe38f1 -Merge: 16809a1 960cfbe -Author: Anthony Young -Date: Fri Oct 14 17:43:57 2011 +0000 - - Merge remote-tracking branch 'rackspace/master' into security_groups_cli - - Conflicts: - novaclient/v1_1/shell.py - -commit 960cfbe32803b7bb97840f41c22a7c103dbf3757 -Merge: 16b083d 48e1064 -Author: Jesse Andrews -Date: Fri Oct 14 10:38:35 2011 -0700 - - Merge pull request #129 from cloudbuilders/floating_ip_cli - - Add cli for floating ips - -commit 4df5a2f363c28ce33805f21e54bb43a6f8edce3e -Author: Pavel Shkitin -Date: Wed Oct 12 13:57:26 2011 +0400 - - Booting server with specific key is implemented - -commit 0ce3f979102b074e79ab18d5449132fc6b010135 -Author: Pavel Shkitin -Date: Wed Oct 5 16:25:31 2011 +0400 - - Added commands to work with keypairs - -commit 16809a16fa82f102391abe4c02001a6cd96e172e -Author: Anthony Young -Date: Tue Oct 11 22:30:48 2011 +0000 - - make description consistent - -commit 6498d41c4246e219f6ae678a35217efa256182f4 -Author: Anthony Young -Date: Tue Oct 11 22:28:22 2011 +0000 - - remove extra space - -commit 356a92ee1463e0db0cb9c93c6a2dd7c1ecf8bf7f -Author: Anthony Young -Date: Tue Oct 11 22:10:23 2011 +0000 - - add ability to create source group rules - -commit 6a20ed5e3b3fcd45762072495047778416ba2b75 -Author: Anthony Young -Date: Tue Oct 11 20:40:01 2011 +0000 - - don't expose ids to end user - -commit bad314991e31cd625367faa2c9ca00220e3e68b2 -Author: Anthony Young -Date: Tue Oct 11 08:24:14 2011 +0000 - - work on formatting for secgroup rules - -commit 48e10643b39276af194b947e7bb295fc2e688dd5 -Author: Anthony Young -Date: Tue Oct 11 07:54:33 2011 +0000 - - display floating ip on create - -commit 8cb15843d1da0a608750c3037121241f08d14453 -Author: Anthony Young -Date: Tue Oct 11 07:48:55 2011 +0000 - - Add CLI for security groups and rules - -commit 9a5a7c9253c500bbaa9ad52fe9a9f31aee7b01e8 -Author: Anthony Young -Date: Tue Oct 11 04:18:30 2011 +0000 - - raise exception if floating_ip is not found in floating-ip-delete - -commit 4154b903646c9b52efbd956fb74479a3dff00df2 -Author: Anthony Young -Date: Tue Oct 11 04:07:08 2011 +0000 - - Add cli for floating ips - -commit 772609aa45253fa616d9c70c97587397068b9370 -Author: Unmesh Gurjar -Date: Mon Oct 10 19:40:05 2011 +0530 - - Added support to specify more boot options. - - Added Parameters: availability zone, security groups and user data. - -commit 16b083ddca71d60ec1745e9961441667b16204be -Merge: 2e2172c 8ef6268 -Author: Sandy Walsh -Date: Fri Oct 7 13:30:41 2011 -0700 - - Merge pull request #127 from rconradharris/issue126 - - Don't filter endpoints when filter_value is non-truthy. - -commit 8ef626811519b633296eac28941d95f85fc27bad -Author: Rick Harris -Date: Fri Oct 7 17:12:05 2011 +0000 - - Don't filter endpoints when filter_value is non-truthy. - - Fixes #126 - -commit 2e2172c5f5add4cc8b38c5be19cd86c18f285eee -Merge: 19d11e3 42e726f -Author: Sandy Walsh -Date: Fri Sep 30 08:01:58 2011 -0700 - - Merge pull request #124 from SandyWalsh/new_keystone_auth - - now uses tenantName vs. tenantId to auth - -commit bfefddada1fbf14571e8b20d7ece7243c2de7290 -Merge: 234205b 19d11e3 -Author: Gaurav Gupta -Date: Thu Sep 29 08:14:39 2011 -0700 - - Merge remote-tracking branch 'upstream/master' - -commit 234205bf538489dfc9c42858b104224170259278 -Author: Gaurav Gupta -Date: Thu Sep 29 08:09:50 2011 -0700 - - Added the following CLI commands to access nova volumes: - volume-attach Attach a volume to a server. - volume-create Add a new volume. - volume-delete Remove a volume. - volume-detach Detach a volume from a server. - volume-list List all the volumes. - volume-show Show details about a volume. - -commit 42e726ffedab909f49a0f216ca7091b41b68fd35 -Author: Sandy Walsh -Date: Wed Sep 28 11:00:15 2011 -0700 - - now uses tenantName vs. tenantId to auth - -commit 19d11e39ae4a5ac660c7ba25b9f360c844a65deb -Merge: 4b6345e acf8a27 -Author: Josh Kearney -Date: Tue Sep 27 14:03:59 2011 -0700 - - Merge pull request #121 from gagupta/master - - Added support for nova-volume extension - -commit 4b6345e3545f6fd78e5905c8da51e86b4d1091f6 -Merge: a3d7bb0 96e04e6 -Author: Sandy Walsh -Date: Mon Sep 26 15:25:21 2011 -0700 - - Merge pull request #123 from SandyWalsh/new_keystone_auth - - New keystone auth - -commit 96e04e64e9305cf71955cd7b311a17cbf83f8bff -Author: Sandy Walsh -Date: Mon Sep 26 12:59:04 2011 -0700 - - version bump - -commit 9cd9635c42dfb46b8e0b8a95e3becc357def0cdf -Author: Sandy Walsh -Date: Mon Sep 26 12:58:03 2011 -0700 - - removed unicode casts - -commit 4a53b06e0e2af5db407aa03bd4f4791332287008 -Author: Sandy Walsh -Date: Mon Sep 26 12:53:29 2011 -0700 - - cleaned up exception handling - -commit 8491c7602707ce8b36e7a76a35c407ef269a0452 -Author: Sandy Walsh -Date: Mon Sep 26 12:28:43 2011 -0700 - - new service catalog implementation. - -commit 2d5f6b2df6887c2a3f849cbcca7da85fd3094823 -Author: Sandy Walsh -Date: Mon Sep 26 07:41:42 2011 -0700 - - change auth cred format for keystone - -commit acf8a2783a90df5fd613db6cc0298dd9e2888387 -Author: Gaurav Gupta -Date: Thu Sep 22 06:45:04 2011 -0700 - - Added methods to get, attach and detach volumes to/from running instances - -commit 74e92a6914bcc2add9992b7db037669b1c195382 -Author: Gaurav Gupta -Date: Wed Sep 21 12:31:53 2011 -0700 - - Added support to access nova-volume api (v1.1 extension) - - Only the basic functionality (create, delete, list) is implemented - -commit a3d7bb0014cc985f1c4c3f766f42bf577ecb9c8c -Merge: e993af6 f932961 -Author: Jason Kölker -Date: Wed Sep 21 07:42:28 2011 -0700 - - Merge pull request #118 from SandyWalsh/service_catalog_regions - - Service Catalog region & reusing user token support - -commit e993af6b50085e3d00af24b0c9a9a006c71f6589 -Merge: dcd0e9a c032cc9 -Author: Chmouel Boudjnah -Date: Tue Sep 20 14:47:39 2011 -0700 - - Merge pull request #119 from chmouel/fix-booting-1_0 - - Make sure flavor is a type of int. - -commit dcd0e9aaa21dda45d490b771c6e7a7c6ab2ab13c -Merge: 1ed1f5e 791432c -Author: Sandy Walsh -Date: Tue Sep 20 07:10:52 2011 -0700 - - Merge pull request #120 from cloudbuilders/key_name_in_servers_create - - add key_name to servers.create - -commit 791432cf7309229c10dd75cf0939c59ec5d28f75 -Author: Anthony Young -Date: Tue Sep 20 00:51:00 2011 -0700 - - add todo to update doc strings so that they reflect extension/optional-ness - -commit ad6d3ca60ea72dd440eaae3d47bc1a72599f806f -Author: Anthony Young -Date: Tue Sep 20 00:48:00 2011 -0700 - - update doc strings - -commit 4aaa47705b29be6695a80402eee9041027287d6f -Author: Anthony Young -Date: Tue Sep 20 00:20:52 2011 -0700 - - add key_name to servers.create - -commit c032cc9cd44b7c8ae353b3bc39ff028b4136664c -Author: Chmouel Boudjnah -Date: Tue Sep 20 00:20:09 2011 +0200 - - Make sure flavor is a type of int. - - This shell.py is getting very very confusing. - -commit f93296125261a0d4e0b6a43be9241b3f4b4b94e2 -Author: Sandy Walsh -Date: Thu Sep 15 18:15:59 2011 -0700 - - removed debugging - -commit acd1e0370fb31d3ed7cc33f7bb37ebdbc5162b1d -Author: Sandy Walsh -Date: Thu Sep 15 18:12:16 2011 -0700 - - token support - -commit b047f3cf051b3e2e881156eadca56c1a019debb5 -Merge: cfab90b 1ed1f5e -Author: Sandy Walsh -Date: Thu Sep 15 18:11:34 2011 -0700 - - Merge branch 'master' of github.com:rackspace/python-novaclient into service_catalog_regions - -commit cfab90bddf2325915fb93af63e9efd31793cd55d -Author: Sandy Walsh -Date: Tue Sep 13 19:43:57 2011 -0700 - - fixed unknown service - -commit 9b767784d83b52f3e001dcfa3b5964284030bfec -Author: Sandy Walsh -Date: Mon Sep 12 06:39:11 2011 -0700 - - properly uses keystone admin endpoint for token lookup - -commit 1ed1f5e863d3013c453cc31c61699216fbc6912e -Merge: 9a5c20d 186b468 -Author: Jesse Andrews -Date: Sun Sep 11 20:14:18 2011 -0700 - - Merge pull request #108 from chmouel/userdata - - Add userdata support. - -commit 2c3a865f6b408d85aaeaafafd9ff9cdcee5d8cb4 -Author: Sandy Walsh -Date: Fri Sep 9 06:33:38 2011 -0700 - - proxy token support - no tests - -commit f7d38c2568d55c10f70397562f08a6d4266a527a -Author: Sandy Walsh -Date: Wed Sep 7 13:30:20 2011 -0700 - - readme fix - -commit 55a09cd93524706bcaff04c12c631abafec25aa7 -Author: Sandy Walsh -Date: Wed Sep 7 13:02:50 2011 -0700 - - service catalog with multiple endpoints per service - -commit 159dbd8076b17a180fc6ec90b8f141d1f746999b -Merge: 9deb35f 9a5c20d -Author: Sandy Walsh -Date: Tue Sep 6 08:52:03 2011 -0700 - - Merge branch 'master' of github.com:rackspace/python-novaclient into zone-add-optional-creds - -commit 9a5c20d2d48d9d1b14a439c2defc3954277d4a5d -Merge: 6b56f3b 0acc0cc -Author: Chmouel Boudjnah -Date: Fri Sep 2 13:13:22 2011 -0700 - - Merge pull request #112 from chmouel/debugging-by-environement-variable - - Add ability to force debugging via os environ. - -commit 0acc0cce69a9b58695087ffaa1dee6d26046d3ff -Author: Chmouel Boudjnah -Date: Fri Sep 2 14:25:12 2011 -0500 - - Add ability to force debugging via os environ. - - Currently we can do debug from the command line or integratng to an - application which has already logging configured. But if we want to do - it to experiment via ipython the process is quite cumbersome. This allow - to have an environement variable called NOVACLIENT_DEBUG which enable - debugging when set and defined. - -commit 9deb35f36ee726bcfa4d335405ea50997a1d52e1 -Merge: 2acc75b 6b56f3b -Author: Sandy Walsh -Date: Fri Sep 2 12:13:22 2011 -0700 - - merge fixup - -commit 2acc75b96ea8192238ab7d2ebe508190d0291d29 -Author: Sandy Walsh -Date: Fri Sep 2 12:09:33 2011 -0700 - - version bump - -commit 909b9118c2df7a1bcc2ae19dfdefad2be6dee554 -Author: Sandy Walsh -Date: Fri Sep 2 12:07:18 2011 -0700 - - readme - -commit 0cd6ed62fd127e893eb05272b4541719fee82c0f -Author: Sandy Walsh -Date: Fri Sep 2 11:44:25 2011 -0700 - - service catalog as auth parameter - -commit 11f31651acd7db3035353aca342fcdbf020c8777 -Author: Sandy Walsh -Date: Fri Sep 2 10:34:51 2011 -0700 - - service name support - -commit 6b56f3be13956f2e6158f860fbfa9215e1bd6b30 -Merge: ba96890 07795ce -Author: Josh Kearney -Date: Fri Sep 2 09:01:49 2011 -0700 - - Merge pull request #111 from klmitch/loaded-zones - - Extend lazy loading support to Weighting - -commit 07795ce412dee54a0d3f5646c611926a79333545 -Author: Kevin L. Mitchell -Date: Fri Sep 2 10:56:46 2011 -0500 - - Extend lazy loading support to Weighting - -commit ba96890aaec328d785c6afb428b28c5b22680cb0 -Merge: 89a5976 10e6ae8 -Author: Chmouel Boudjnah -Date: Fri Sep 2 07:44:39 2011 -0700 - - Merge pull request #107 from chmouel/master - - Fix unit-tests - -commit 10e6ae8c3f6e89559ffc0d1f8264cc336c6cd404 -Author: Chmouel Boudjnah -Date: Fri Sep 2 09:40:00 2011 -0500 - - Fix unittests breakage in test_shell - - For some method like test_image_meta_bad_action we are testing a - SystemExit to be thrown and object self.shell has no time to get - instantatiated which is OK in this case, so we make sure the method is - there before launching it. - -commit 89a59761b6535fdcc8062517e42ca626da6f5106 -Merge: be53d30 1776cbf -Author: Chmouel Boudjnah -Date: Fri Sep 2 07:12:12 2011 -0700 - - Merge pull request #110 from chmouel/fix-get-information-by-name - - Fix #109 (nova show name not working). - -commit 1776cbfbd85538ff572a5571171478374ab55a0e -Author: Chmouel Boudjnah -Date: Thu Sep 1 20:15:53 2011 -0500 - - Fix #109 (nova show name not working). - - By default when searching via name we will do a findall(name=blah) and - due a REST /details which is not the same as a .get() and doesn't get - the information about flavors and images. This fix it as we redo the - call with the id which does a .get() to get all informations. - -commit 186b4689b5619d98f643bd84d2aba76eb8af196e -Author: Chmouel Boudjnah -Date: Thu Sep 1 16:37:30 2011 -0500 - - Add userdata support. - - Based on Jesse first shot at it. Make it accept file like object as well - like we do for file injection on server creation. - -commit be53d30569f62e4018a58ef7662fbd88d041f905 -Merge: fe3dbf0 6b4791b -Author: Josh Kearney -Date: Thu Sep 1 13:50:12 2011 -0700 - - Merge pull request #104 from throughnothing/instance_metadata - - Instance metadata set/delete - -commit fe3dbf056521a3ccaf6c3b90eb495fae7a281437 -Merge: 51610e9 25977cd -Author: Josh Kearney -Date: Thu Sep 1 13:46:25 2011 -0700 - - Merge pull request #106 from chmouel/fix-unittest-breakage - - Remove extra NOVA_PROJECT_ID - -commit 25977cd47cbe6b2f13e5491942e670cfaa377cc0 -Author: Chmouel Boudjnah -Date: Thu Sep 1 15:38:28 2011 -0500 - - Remove extra NOVA_PROJECT_ID - -commit 51610e9949fbd1baa39899046f89378eeac58014 -Merge: 2b1b109 7c8ae25 -Author: Josh Kearney -Date: Thu Sep 1 13:38:31 2011 -0700 - - Merge pull request #105 from chmouel/fix-unittest-breakage - - Fix unittests breakage from merge 3507905 - -commit 7c8ae25a89aefa768443f465ce30ead7eb30cd12 -Author: Chmouel Boudjnah -Date: Thu Sep 1 15:35:44 2011 -0500 - - Fix unittests breakage from merge 3507905 - - PEP8 the file along the way. - -commit 2b1b109aab24ab639bf8a5c16588bde75a8ca8d1 -Merge: 230c4f4 c31aeb1 -Author: Josh Kearney -Date: Thu Sep 1 13:07:37 2011 -0700 - - Merge pull request #101 from basak/master - - Fix test installation exclude - -commit 230c4f4bea57ae27641a1287fc6897da9a1d7368 -Merge: 3507905 14c2bd2 -Author: Josh Kearney -Date: Thu Sep 1 13:04:17 2011 -0700 - - Merge pull request #100 from throughnothing/image_metadata - - Add support for adding/updating/deleting image metadata - -commit 3507905a7aa0e9463535d5de8aa56c753c7e6ccc -Merge: 3f22be9 40333f0 -Author: Josh Kearney -Date: Thu Sep 1 13:02:54 2011 -0700 - - Merge pull request #99 from chmouel/no-auth-url-error - - ensure we have auth_url and project_id fo the CLI when using API greater 1.0 - -commit 3f22be9b2659333560b6e972c05dcfcf7f459322 -Merge: 85b281b 2afd70d -Author: Chmouel Boudjnah -Date: Thu Sep 1 13:01:25 2011 -0700 - - Merge pull request #97 from chmouel/dont-assume-defaults - - Do not assume default for image and flavor. - -commit 85b281bd03ee19df7df16455f46e8caa42d1f0dc -Merge: c35bd29 441536d -Author: Chmouel Boudjnah -Date: Thu Sep 1 12:56:21 2011 -0700 - - Merge pull request #102 from chmouel/more-debugging - - Add body in debugging. - -commit 6b4791bf48675753633ca21687adfa3cf5f18788 -Author: William Wolf -Date: Thu Sep 1 11:40:16 2011 -0400 - - Add 'meta' command to allow set/delete of metadata items on servers. - Added ability to run multiple assert_called tests from one test function. - -commit 44bf2079ca4bbefcc8e93f27b702a8928827622c -Author: William Wolf -Date: Thu Sep 1 11:40:33 2011 -0400 - - add build, dist, python-novaclient.egg-info to .gitignore - -commit c35bd291e399c2bfb8ba80889153f476bb3171a3 -Merge: 597ef2f 526c5ce -Author: Josh Kearney -Date: Thu Sep 1 10:33:30 2011 -0700 - - Merge pull request #103 from SandyWalsh/fix_2_6_5_tests - - Fix 2 6 5 tests - -commit 526c5ce733b6ad153f510cf278b14907cc73e939 -Author: Sandy Walsh -Date: Thu Sep 1 10:28:56 2011 -0700 - - fixes odd __get_attr__ behavior in 2.6.5 - -commit 88d67be08d77599748d438fa107d4d721fcbdc35 -Merge: 48fe330 597ef2f -Author: Sandy Walsh -Date: Thu Sep 1 10:21:36 2011 -0700 - - conflict fixed - -commit 48fe330daba3a96258836e12eeea42c49d31c9fb -Author: Sandy Walsh -Date: Thu Sep 1 10:20:38 2011 -0700 - - catch misssing id - -commit 441536daf16493c025838a989472065fb33e2e2b -Author: Chmouel Boudjnah -Date: Thu Sep 1 11:50:13 2011 -0500 - - Add body in debugging. - -commit c31aeb19be1b0a09ace8b03727385041d610188f -Author: Robie Basak -Date: Thu Sep 1 10:27:39 2011 +0100 - - Fix test installation exclude - - With exclude=['tests'], tests.v1_0 and tests.v1_1 do not get excluded, - causing "python setup.py install" to pollute dist-packages with "tests" - rather than going under novaclient/ - - exclude=['tests', 'tests.*'] fixes this. - - LP: #838298 - Also see LP: #825127 comment #3 - -commit 14c2bd2d763d3aa366b551f879bfd551abed88ef -Author: William Wolf -Date: Wed Aug 31 12:59:21 2011 -0400 - - Add support for image metadata to be viewed, added, updated, and deleted. - -commit d2905832fa98c41ba80ea934b97f9cf65e50b6fb -Author: William Wolf -Date: Wed Aug 31 15:58:12 2011 -0400 - - Bump the release version - -commit 1b64a3823f27dc0e52a61f2fd736c4716b15a4eb -Author: Sandy Walsh -Date: Wed Aug 31 11:55:01 2011 -0700 - - fixed up zone-add - -commit 597ef2f5b6bd51da02cc4c83c6295a5e3cb3f3c9 -Merge: 857ee8f db38b4c -Author: Sandy Walsh -Date: Wed Aug 31 07:37:32 2011 -0700 - - Merge pull request #96 from bcwaldon/lazyload-limit - - Limit resource lazyloading - -commit db38b4c830f01819105bebcca969950a701b6253 -Merge: e05ae5d 857ee8f -Author: Brian Waldon -Date: Wed Aug 31 09:30:09 2011 -0400 - - Merge branch 'master' of http://github.com/rackspace/python-novaclient into lazyload-limit - - Conflicts: - novaclient/base.py - -commit e05ae5ded302cb3baae5610fcc17a674b4eda770 -Author: Brian Waldon -Date: Wed Aug 31 09:24:31 2011 -0400 - - Reducing v1_1.base to just booting manager - -commit 7f3237e143e5527083e15c25c7638c6702edff9a -Author: Sandy Walsh -Date: Tue Aug 30 07:27:37 2011 -0700 - - tests working - -commit d191177bd5c8514b00da8fe97ff6df3ff2df6034 -Author: Sandy Walsh -Date: Tue Aug 30 07:13:44 2011 -0700 - - in progress - adding zone name - -commit 40333f008c9086c7152c1928b8fe2da76854fcef -Author: Chmouel Boudjnah -Date: Tue Aug 30 08:57:49 2011 -0500 - - ensure we have auth_url and project_id for !1.0 - - Make sure we have an auth_url or project_id when API version is not 1.0 - -commit 2afd70d268689d64701970b64c85d270971dbbc5 -Author: Chmouel Boudjnah -Date: Tue Aug 30 08:39:17 2011 -0500 - - Updated error message as suggested by bcwaldon - - Remove the "see nova {image,flavor}-list" as this should go to help as - suggested by bcwaldon. - -commit 667fb76e07361512d79e0744328acf79e0558fd9 -Merge: b96b4d0 857ee8f -Author: Sandy Walsh -Date: Tue Aug 30 05:50:30 2011 -0700 - - Merge branch 'master' of github.com:rackspace/python-novaclient into zone-add-optional-creds - -commit b96b4d039aa2d66db8bcd90bb1fdfcd1d6834b87 -Author: Sandy Walsh -Date: Tue Aug 30 05:50:12 2011 -0700 - - take auth token param - -commit 8ac20e7447f2bf107e0477d588ece41f6b1fb1ba -Author: Chmouel Boudjnah -Date: Mon Aug 29 23:18:47 2011 -0500 - - Do not assume default for image and flavor. - - Not every cloud as a flavor name 256M and a image name called Ubuntu* - make it compulsory to pass a name/image for 1.1 OpenStack (1.0 is - usually Rackspace Cloud which has that by default). - -commit 857ee8f6a2f4ad1765996d259223affe0419529a -Merge: 32e34b6 e485919 -Author: Sandy Walsh -Date: Mon Aug 29 20:29:49 2011 -0700 - - Merge pull request #93 from Cerberus98/no_user_pass - - Client changes for username and password in zone add - -commit 32e34b60493f37c4a0c1a5a41daa60b3e6ec5c56 -Merge: ced66c7 530e0b0 -Author: Jesse Andrews -Date: Mon Aug 29 14:22:00 2011 -0700 - - Merge pull request #94 from chmouel/fix-loop-on-class-without-get - - Fix unittests - -commit ced66c735b0bd4f96f2f70064a8d3838bce9e118 -Merge: 5969022 9fe5498 -Author: Jesse Andrews -Date: Mon Aug 29 14:16:59 2011 -0700 - - Merge pull request #91 from chmouel/keystone - - Update #74 to master. - -commit 4e456d6bbc37f4694aafb8e35a435656b52c5a25 -Author: Brian Waldon -Date: Mon Aug 29 17:00:13 2011 -0400 - - expanding on concept of 'loaded' - -commit 39068edfb785fcbd0d210928b9cf76ef9fe1a81e -Author: Brian Waldon -Date: Mon Aug 29 16:33:22 2011 -0400 - - limiting resource lazyloading to a single query - -commit 9fe54984ed3a3dd89e0983625312d875a5c2de52 -Author: Chmouel Boudjnah -Date: Fri Aug 26 16:06:51 2011 -0700 - - Fix extra # char as noticed by jk0 - -commit bf2ef4d9ac3c8ed28a14fa7417e4d4ce1417ffd0 -Author: Chmouel Boudjnah -Date: Fri Aug 26 16:02:08 2011 -0700 - - Add piston service_catalog. - -commit 3d2ccb0b60e80fce468c1e03a073d564f45da459 -Author: Chmouel Boudjnah -Date: Fri Aug 26 16:00:38 2011 -0700 - - Add anotherjesse keystone here. - -commit 530e0b0f8e4388ab51253c3514c5e26f9d31c7e1 -Author: Chmouel Boudjnah -Date: Fri Aug 26 15:29:50 2011 -0700 - - Fix loop properly. - -commit 713133ed8e98369332ec71a8cbeaebbbfc7a2eae -Author: Chmouel Boudjnah -Date: Fri Aug 26 15:28:55 2011 -0700 - - Make sure we can do a get on the base class. - - or this will loop forever and sometime (like keypairs) there is classes - that don't have a get method. - -commit e4859196ad207376c619b2fb942c202f4b2a4993 -Author: Matt Dietz -Date: Fri Aug 26 15:20:02 2011 -0500 - - Client changes for username and password in zone add - -commit 5969022401e41a7794c89ef0d2695fb2dacd3ef3 -Merge: fe02df3 5a5cfc6 -Author: Jesse Andrews -Date: Fri Aug 26 10:29:04 2011 -0700 - - Merge pull request #92 from cloudbuilders/floating_ips_redux - - Support for Floating Ips - -commit fe02df36ba0da4f366139f2f7282e92a82b1bb9d -Merge: 72d41b1 38da8b4 -Author: Jesse Andrews -Date: Fri Aug 26 10:28:39 2011 -0700 - - Merge pull request #71 from cloudbuilders/security_groups - - Security groups implementation - -commit 5a5cfc65712be607d90d85967140956fc6b01aa2 -Author: Anthony Young -Date: Thu Aug 25 14:10:59 2011 -0700 - - fix for chmouel's comment, and tweaks to tests - -commit 8ec0ae6ab0ed69c5acd1101b19d8971d06be4a7c -Author: Anthony Young -Date: Wed Aug 24 22:51:53 2011 -0700 - - support for floating_ips + D4 - -commit 38da8b4e8549307d79fd76734ed5993451ce7b49 -Author: Anthony Young -Date: Wed Aug 24 20:29:35 2011 -0700 - - make __repr__ more useful with default behavior, rather than juse displaying id - -commit 7357d3326d83a085e88936c4856fa477d1942b8a -Merge: 43d52b1 541d578 -Author: Anthony Young -Date: Wed Aug 24 20:17:47 2011 -0700 - - Merge remote branch 'rackspace/master' into security_groups - - Conflicts: - tests/v1_1/fakes.py - -commit 43d52b1f3d693270b1fbb0068e6f921e02b9c010 -Author: Anthony Young -Date: Wed Aug 24 18:21:42 2011 -0700 - - a few tweaks to get the client talking to nova - -commit 72d41b1e38034f5d7aedc849d85e7f670aca529a -Merge: 3c254c0 dd37389 -Author: Josh Kearney -Date: Wed Aug 24 10:38:58 2011 -0700 - - Merge pull request #88 from bcwaldon/rebuild-adminPass - - Updating for new rebuild format - -commit fd7fe5206c485640cc816c2835ad36ca2efdb6e9 -Merge: 1879131 3c254c0 -Author: Sandy Walsh -Date: Wed Aug 24 06:52:30 2011 -0700 - - Merge remote branch 'rackspace/master' into zone-add-optional-creds - -commit 3c254c002ae01f09b431a49fb4c1800e98182ae6 -Merge: 541d578 d648231 -Author: Sandy Walsh -Date: Wed Aug 24 06:24:18 2011 -0700 - - Merge pull request #86 from bcwaldon/integer_instance_name - - Support Integer-like Resource Names - -commit 1879131403157197ee09c9630d589e1f0e7944ca -Author: Sandy Walsh -Date: Wed Aug 24 05:32:40 2011 -0700 - - more cleanup - -commit 7cb2f3e527a881805ead25fab1cbd7f3f1125f22 -Merge: a8dc5e4 541d578 -Author: Sandy Walsh -Date: Wed Aug 24 05:30:15 2011 -0700 - - Merge remote branch 'rackspace/master' - - Conflicts: - novaclient/client.py - -commit 0756829b435bb134c431d7fec441661b947c32e6 -Author: Anthony Young -Date: Tue Aug 23 20:59:25 2011 -0700 - - progress on security groups - -commit dd37389108f0c7dd29e97dd59d09e017e46bd3ef -Author: Brian Waldon -Date: Tue Aug 23 23:22:57 2011 -0400 - - updating version - -commit 25911f94b2ab87ecd7c9e0730cf1dee5b291e9be -Author: Brian Waldon -Date: Tue Aug 23 23:17:25 2011 -0400 - - updating for new rebuild format - -commit d648231425e522f4a37b4c07ddee6680ce6eb404 -Author: Brian Waldon -Date: Mon Aug 22 15:17:06 2011 -0400 - - adding tests - -commit 79a532b9106d0aa2b3b70073974d06abfc447f87 -Author: Brian Waldon -Date: Mon Aug 22 15:13:26 2011 -0400 - - cleaning up find_resource method to support str/int ids, uuids, and integer-like names - -commit 541d578b90a640afd3f90214a4ebad7f7872d5b2 -Author: Chmouel Boudjnah -Date: Mon Aug 22 11:56:01 2011 -0700 - - Fix #85 - - Use internal dictionary self._info to get the keypair uuid (which equal - to name in this case). - -commit 79a34e9dbba3e87e63832084c02f114d25a7a8ef -Merge: f361298 0d997e0 -Author: Josh Kearney -Date: Mon Aug 22 10:04:10 2011 -0700 - - Merge pull request #79 from cloudbuilders/quota-fixes - - Quota fixes - -commit f361298676e14068e4495e04199e2aba42d6c2cd -Merge: c42b374 328a425 -Author: Josh Kearney -Date: Mon Aug 22 10:01:28 2011 -0700 - - Merge pull request #84 from cloudbuilders/shell-test-fixes - - Fixed Shell Tests - -commit 328a4255541acdfba85d1ecd8b360b62ec0f3e76 -Author: Jake Dahn -Date: Sat Aug 20 22:22:22 2011 -0700 - - fixing the shell tests - -commit c42b374ed8b6ea4b7fb43125c6100c40214f6247 -Merge: 66ecf7c b8f5c91 -Author: Josh Kearney -Date: Thu Aug 18 15:17:46 2011 -0700 - - Merge pull request #83 from jk0/master - - Fixed 1.0 and unit tests. - -commit b8f5c91f864e50ea3e94aa23be37a7b8171eeae2 -Author: Josh Kearney -Date: Thu Aug 18 17:16:38 2011 -0500 - - Fixed 1.0 and unit tests. - -commit 66ecf7c768d2a032c301250227843b883be77d1f -Merge: c844c89 fb72dff -Author: Sandy Walsh -Date: Thu Aug 18 10:17:18 2011 -0700 - - Merge pull request #82 from jk0/master - - Updated rescue in 1.0 and added unit tests. - -commit fb72dff889b05cbcd12694b771cdef8ccfd7bb4f -Author: Josh Kearney -Date: Thu Aug 18 12:04:55 2011 -0500 - - Added support for 1.0 and added unit tests. - -commit c844c89ac4cf0065af1add102e8de6dcd60f15d9 -Merge: 1a9a149 b9d194e -Author: Sandy Walsh -Date: Thu Aug 18 09:53:35 2011 -0700 - - Merge pull request #81 from jk0/master - - Update rescue/unrescue calls to use public API - -commit b9d194e99dede7686df1a7f8ee96908ace0ab0f2 -Author: Josh Kearney -Date: Thu Aug 18 11:51:26 2011 -0500 - - Updated rescue/unrescue to use public API. - -commit 0d997e01fbdb8d58aa462b0b49220137156e2d7e -Author: Jake Dahn -Date: Tue Aug 16 14:27:01 2011 -0700 - - removing extra space - -commit 0476cb6b75f774e514d0ec18e8917bcc016f35bb -Author: Jake Dahn -Date: Tue Aug 16 13:36:45 2011 -0700 - - updating quotas and tests with the format which recently landed in nova - -commit 5a5352069886b2e9ea2aeabfa6d14ae380e21a88 -Author: Jake Dahn -Date: Mon Aug 15 13:38:40 2011 -0700 - - fixing up a few pep8 issues, and pointing client to the new endpoint - -commit 1a9a14951e04a221219e117282737c319b95bb5c -Merge: 4b2899d 5f241d9 -Author: Sandy Walsh -Date: Tue Aug 16 07:04:53 2011 -0700 - - Merge pull request #62 from chemikadze/redirect-support - - Redirection handling. - -commit 4b2899da2f90f9dcc114d852e80e9f30cd654831 -Author: Chmouel Boudjnah -Date: Tue Aug 16 10:13:52 2011 +0200 - - Properly make image_id a requirement to be int. - - Fix #69 - -commit e530110c9103f61d4e809f2eb77ef3c758514b13 -Author: Chmouel Boudjnah -Date: Tue Aug 16 10:08:51 2011 +0200 - - Make sure the image id is an integer. - - Fix #69 - -commit 5f241d9b8c0115f04eef9a6445bd1a5ab74f6ef7 -Merge: 0ec2cbb a97722d -Author: Nikolay Sokolov -Date: Mon Aug 15 10:36:55 2011 +0400 - - Merge with trunk - -commit 128608f0865726ad4b45be3fdbf68cbd19bc4be5 -Author: Jesse Andrews -Date: Sat Aug 13 16:37:55 2011 -0700 - - really fixed - -commit d302f2089a31c3bea09ec667ec033a17eb5ea999 -Author: Jesse Andrews -Date: Sat Aug 13 16:36:47 2011 -0700 - - accidentally deleted a comment when fixing conflict - -commit d1b9732aecf6db17e187a8b37a167abd7f84b17e -Merge: 2cb86c5 a97722d -Author: Jesse Andrews -Date: Sat Aug 13 16:17:21 2011 -0700 - - Merge remote-tracking branch 'rax/master' into security_groups - -commit 2cb86c56d1ba8cdc5d054988a7dc6a302efe2271 -Author: Jesse Andrews -Date: Sat Aug 13 16:06:50 2011 -0700 - - pep8 issues - -commit a97722dedf490c7546b99e10f68be406e9f9468a -Merge: 4294327 2b70b75 -Author: Josh Kearney -Date: Sat Aug 13 08:59:15 2011 -0700 - - Merge pull request #73 from cloudbuilders/more_keystonization - - update readme to talk about keystone with CLI and use 1.1 api - -commit 2b70b75537302838d70dd0c032b857eb2e76f774 -Author: Jesse Andrews -Date: Fri Aug 12 23:47:25 2011 -0700 - - update readme to talk about keystone with CLI and use 1.1 api - -commit 9c17fad86d8dcde86a0acc84313f1f16b496abe7 -Author: Dean Troyer -Date: Fri Aug 12 10:38:10 2011 -0500 - - Switch API path to match http://bazaar.launchpad.net/~tpatil/nova/os-security-groups/revision/1369 - -commit a6f08974a110f1c1a6a7c9096bd25e36c839fff9 -Author: Dean Troyer -Date: Fri Aug 12 10:02:54 2011 -0500 - - Fix API path - -commit 42943277a05d22c9ee4047aaf369440d23102631 -Merge: d14d2b0 fc8e5e3 -Author: Josh Kearney -Date: Fri Aug 12 07:24:33 2011 -0700 - - Merge pull request #72 from comstud/search-fixups - - Search fixups - -commit fc8e5e3fe3a1164eb2e923ed599e63a2af1a4f3c -Author: Chris Behrens -Date: Thu Aug 11 21:45:26 2011 -0700 - - fix display_name references that should have been instance_name - -commit 37f1958eeb56d5443c3e88976f72e69b0eb2e703 -Author: Chris Behrens -Date: Thu Aug 11 21:41:50 2011 -0700 - - removed fixed_ip from v1.1 shell. Use --ip instead. Fixed up rest of other search options from last commit - -commit dcd5544133f1cc1171f8078b2ed54143b52fb064 -Author: Chris Behrens -Date: Thu Aug 11 21:38:41 2011 -0700 - - start add of --image, --flavor, --status, and --host options to 'list' command. also fix up differences with --name and --display_name compared to how nova implementation turned out - -commit 9070f3231f8ffbee1d5da4ce39d3a3e49096afd2 -Author: Dean Troyer -Date: Thu Aug 11 16:07:20 2011 -0500 - - Security groups cleanups - -commit 0ec2cbbe8277f271df3735d85197c9e5978df3c4 -Author: Nikolay Sokolov -Date: Thu Aug 11 13:48:12 2011 +0400 - - Added redirect tests, changed wrong status in test_authenticate_success. - -commit ee9655c218b0374864b3af631bed2e4165624601 -Author: Nikolay Sokolov -Date: Thu Aug 11 13:43:51 2011 +0400 - - Added self.auth_url updating, WrongResponse exception. - -commit d14d2b05ec231c1d818a35edb9cf5cabd29b2a11 -Merge: 064a98b 016dca2 -Author: Matt Dietz -Date: Wed Aug 10 19:37:38 2011 -0700 - - Merge pull request #68 from cloudbuilders/doc_keystone - - add note about keystone / auth 2.0 - -commit 016dca2a824850b933cbc3d3589583f020f7f7d9 -Author: Jesse Andrews -Date: Wed Aug 10 16:16:38 2011 -0700 - - add note about keystone / auth 2.0 - -commit e7fdf8c98f0c16a67477a409563b7700f45bf00f -Author: Dean Troyer -Date: Wed Aug 10 17:20:21 2011 -0500 - - Clean up id handling and pass basic tests - -commit ecdd2fcef66b293ff794527224f31c6c1c9a779a -Author: Dean Troyer -Date: Wed Aug 10 14:55:50 2011 -0500 - - Add security group rules - -commit c487b9fac107e397ab5472cb3d4ea1b1c9bcef72 -Author: Dean Troyer -Date: Wed Aug 10 14:21:09 2011 -0500 - - Eradicate TABs, make tests run - -commit 064a98bb724f8153e06c247eb534c0b6c206bd80 -Merge: 5ece6de 5f64a85 -Author: Josh Kearney -Date: Wed Aug 10 12:00:27 2011 -0700 - - Merge pull request #56 from cloudbuilders/keypairs - - keypair extension - -commit 5f64a85114233da984faf2ca8f2d862353e5ed9e -Author: Jesse Andrews -Date: Wed Aug 10 11:56:50 2011 -0700 - - missed a conflict - -commit 2e59567f975fe2b1624e1e65cf3c13266b5c7629 -Merge: 6c15f6f 5ece6de -Author: Jesse Andrews -Date: Wed Aug 10 11:55:39 2011 -0700 - - merge master - -commit 97674358da1f71a92d08be2f3b89bab1b1e46a32 -Author: Dean Troyer -Date: Wed Aug 10 13:53:58 2011 -0500 - - Initial security groups code - -commit 5ece6de8ed87e5760552733dcee5e6e20b54c463 -Merge: 406181f 461d3e7 -Author: Sandy Walsh -Date: Wed Aug 10 11:48:38 2011 -0700 - - Merge pull request #65 from cloudbuilders/quotas - - add support for quotas - -commit 406181f53f6a9e4014779f8ddeabd97170bba0d2 -Merge: c8b3b13 4b5b0b6 -Author: Sandy Walsh -Date: Wed Aug 10 10:50:20 2011 -0700 - - Merge pull request #67 from bcwaldon/auth_failure - - KeyError: 'x-server-management-url' - -commit 4b5b0b6edf809dbca0069f00c4cdbd04f532c772 -Author: Brian Waldon -Date: Wed Aug 10 13:46:34 2011 -0400 - - adding unittest - -commit f6273ba08d6ccf87c3e6c8e8c54ef3c934b41646 -Author: Brian Waldon -Date: Wed Aug 10 13:30:33 2011 -0400 - - removing extra newline - -commit 36f26a566422278b911a1ba5df74b331f2c02800 -Author: Brian Waldon -Date: Wed Aug 10 13:27:28 2011 -0400 - - adding email to .mailmap - -commit 1f7605cb7e5d5f427f8efabe4907b65320b7d967 -Author: Brian Waldon -Date: Wed Aug 10 13:25:17 2011 -0400 - - catching authorization failure (x-server-management-url KeyError) - -commit 6c15f6f98c61d3f9ee0882524953639364d82160 -Author: Jesse Andrews -Date: Tue Aug 9 16:39:29 2011 -0700 - - bring up-to-date with lp:~cloudbuilders/nova/os-keypairs - -commit 6761406d830b4450f2fcd53d7e09329e07dba609 -Author: Jesse Andrews -Date: Sat Aug 6 13:08:53 2011 -0700 - - keypair api - -commit 461d3e7e2f000619a6113c340e39cbcbb95e58e9 -Author: termie -Date: Tue Aug 9 13:12:09 2011 -0700 - - add license headers - -commit 17208cec6a77f939c68e393c7d3c23695bb35dbb -Author: termie -Date: Mon Aug 8 14:48:07 2011 -0700 - - add support for quotas - -commit dfa2c86087554c59b08fc035624f8afa31534c4b -Author: Nokolay Sokolov -Date: Tue Aug 9 01:44:01 2011 +0400 - - pep8, again - -commit eff34ef4013912426be511c3235adab1eac305c5 -Author: Nokolay Sokolov -Date: Tue Aug 9 01:41:51 2011 +0400 - - Recursion handling. - -commit c8b3b13615d4b3874c792549a8467e88575138b9 -Author: Josh Kearney -Date: Mon Aug 8 16:06:31 2011 -0500 - - Added .mailmap file for AUTHORS. - -commit 360ee0a34b37edd71525708127f5bed6e43f5e9b -Merge: 811ba10 f39ca09 -Author: Josh Kearney -Date: Mon Aug 8 13:58:13 2011 -0700 - - Merge pull request #64 from piston/conform_to_openstack_standards - - Fixes copyright notice and adds script to gen AUTHORS - -commit f39ca09c0d614cc8db68957084ff628e1b07c171 -Author: Christopher MacGown -Date: Mon Aug 8 13:55:56 2011 -0700 - - Updated authors and fixed tools/generate_authors.sh - -commit a0942f41898bf1a52f397ee1e671a0d4cf88c454 -Author: Christopher MacGown -Date: Mon Aug 8 13:41:29 2011 -0700 - - Fixes copyright notice and adds script to gen AUTHORS - -commit d25c627adda61737ccac408a981fa126455e7e96 -Author: Jesse Andrews -Date: Sat Aug 6 13:08:53 2011 -0700 - - keypair api - -commit 811ba10e51ae4903c0e5fa46e1a697eaf137f5a5 -Merge: 2072f88 6d1361c -Author: Josh Kearney -Date: Mon Aug 8 13:34:19 2011 -0700 - - Merge pull request #61 from bcwaldon/boot_output - - nova boot output cleanup - -commit 2072f88dcd09e86d06d0cae8a267541767ad453c -Merge: 7e5a474 536be15 -Author: Josh Kearney -Date: Mon Aug 8 13:33:38 2011 -0700 - - Merge pull request #63 from cloudbuilders/whitespace_cleanups - - Whitespace cleanups - -commit e52d095a46f4d486db6bb58717b09d5fc3642797 -Author: Nokolay Sokolov -Date: Tue Aug 9 00:28:46 2011 +0400 - - pep8 - -commit b3af99fa15629ec20d84eedd931ec5d3d0c43034 -Author: Nokolay Sokolov -Date: Tue Aug 9 00:26:41 2011 +0400 - - Status code 305 fix, ClientExceptions if we can not handle response - -commit 536be15a8777963d9151f36bfdecc85b39b9656b -Author: termie -Date: Mon Aug 8 13:20:44 2011 -0700 - - whitespace cleanups - -commit 2d785404eda907ea39fe6928491d87bff49bcd94 -Author: Christopher MacGown -Date: Sun Aug 7 10:59:11 2011 -0700 - - pep8 cleanups after the rebase - -commit 39291fe0e86a6e8546df8f16640afd5e3ff174ab -Author: Christopher MacGown -Date: Sun Aug 7 10:45:36 2011 -0700 - - Adds run_tests.sh and virtualenv support. - - Basically make it so that a starting dev can run the tests without a - priori knowledge about what the tests require. Unless run_tests.sh is - run with the -N flag it will create a virtualenv .novaclient-venv, - install the dependencies into it, and then run the tests with the - venv sourced. Also includes the -p|--pep8 flag from nova's - run_tests.sh interface to easily run pep8 against both novaclient and - the tests directory. - - Fix the pep8 violation in tests/v1_1/test_shell.py - -commit 0efc51ec9d9bbbec9d17bf8c27f11c2c505c83de -Author: Christopher MacGown -Date: Sat Aug 6 18:15:35 2011 -0700 - - pep8 in tests - -commit f54367490d5796fb1827158c031dff1ec9ecf09a -Author: Christopher MacGown -Date: Sat Aug 6 00:41:48 2011 -0700 - - pep8 in novaclient - -commit 8f19567ecd037b77ab366c0bfd4f01bbcf70b971 -Author: Christopher MacGown -Date: Fri Aug 5 23:37:37 2011 -0700 - - Add Hacking and Authors to bring this into accordance with OpenStack coding standards - -commit a8dc5e46d00c282d35d683e77e1341774159dede -Author: Sandy Walsh -Date: Mon Aug 8 13:23:07 2011 -0700 - - redirect - -commit 5853354a7bdbe56053bd286873a0d2305c7c858b -Author: Nokolay Sokolov -Date: Tue Aug 9 00:06:55 2011 +0400 - - Redirection handling. - -commit 6d1361c9f41b20b3b95223d76fc4bfd8d6df7782 -Author: Brian Waldon -Date: Mon Aug 8 11:44:41 2011 -0400 - - cleaning up boot output; upping version - -commit 7e5a474d0d42ce88977d418016398c04ee393c72 -Merge: db32374 b1b2dee -Author: Sandy Walsh -Date: Mon Aug 8 06:47:42 2011 -0700 - - Merge pull request #57 from piston/make_keystone_auth_work - - Make it possible to authenticate against keystone - -commit db32374ee46e2e6e9d94553ff9de1629de04d056 -Merge: f5a078c cc9d68c -Author: Sandy Walsh -Date: Mon Aug 8 06:43:02 2011 -0700 - - Merge pull request #60 from amesserl/nova_version_docs - - Added documentation for NOVA_VERSION - -commit cc9d68cf09944e4eb7d3a541fc41854bf252f07e -Author: Antony Messerli -Date: Sun Aug 7 14:00:23 2011 -0500 - - Added documentation for NOVA_VERSION - -commit b1b2dee9bdaf31622400eb04e7ec62da6c6a9138 -Author: Christopher MacGown -Date: Fri Aug 5 23:17:35 2011 -0700 - - Make it possible to authenticate against keystone - -commit f5a078c7eb7f3ae49a8bed9f88d47e52cab7c561 -Merge: ae1b052 4a4e9a6 -Author: Josh Kearney -Date: Fri Aug 5 11:26:27 2011 -0700 - - Merge pull request #52 from Cerberus98/dead_bodies_redux - - Removed the bodies again - -commit 4a4e9a60e81702041dcc225325dea0c9cba7487a -Author: Matt Dietz -Date: Fri Aug 5 13:23:34 2011 -0500 - - Removed the bodies again - -commit ae1b0521f04998725ebcad71b92e4085bf11ff8b -Author: Josh Kearney -Date: Fri Aug 5 10:38:29 2011 -0500 - - Corrected docs. - -commit a03a654031e5973085c3f12007517cd6c991743c -Author: Sandy Walsh -Date: Fri Aug 5 06:52:28 2011 -0700 - - off by one - -commit 1bb422b3a3fee0d2b98b6d3fae933cf36a29e91d -Author: Sandy Walsh -Date: Fri Aug 5 06:48:23 2011 -0700 - - Missed a conflict - -commit d81b0d84c1aef8955c45a5117239baba1058dc85 -Merge: 4b8879a 6fa86a2 -Author: Sandy Walsh -Date: Fri Aug 5 06:40:34 2011 -0700 - - manual merge - -commit 6fa86a22409ab73911168b2a0aa70f9adb583abf -Author: Brian Lamar -Date: Thu Aug 4 17:52:12 2011 -0400 - - Accidently had a reference to ipgroup still. - -commit cc7156933fa90d98cd18c6e2f928571ae3a32cd3 -Author: Brian Lamar -Date: Thu Aug 4 17:07:22 2011 -0400 - - Merged v1.0 functionality into v1.1 so we don't lose any features by...upgrading? - -commit 46a2d5a3d905df8c9a5597ea59d748faaf247001 -Author: Brian Lamar -Date: Thu Aug 4 15:53:30 2011 -0400 - - Fix for failing tests because boot response now requests additional information. - -commit b2f339be5481f9325a7b27406ab5c04d52624f3a -Merge: 008b43f be3a11d -Author: Brian Lamar -Date: Thu Aug 4 12:29:02 2011 -0700 - - Merge pull request #1 from bcwaldon/v1.1-formatting - - V1.1 formatting fixes - -commit be3a11d27e4753240417859191bf49452df37a22 -Merge: 6b4e9c5 008b43f -Author: root -Date: Thu Aug 4 18:40:54 2011 +0000 - - Merge branch 'v1.1-split-and-support' of http://github.com/blamarvt/python-novaclient into v1.1-formatting - -commit 6b4e9c5c8b79671d6bdf633d22a61eda0638f01f -Author: root -Date: Thu Aug 4 18:39:21 2011 +0000 - - formatting updates - -commit 008b43facc98f77a193927270902f15848234dc4 -Author: Brian Lamar -Date: Thu Aug 4 12:40:25 2011 -0400 - - novaclient -> nova in some documentation as per feedback - -commit e1f374c65cbb3ec7c78e3d22ade84fefb496f3b2 -Author: Brian Lamar -Date: Thu Aug 4 12:37:01 2011 -0400 - - Removed unneeded print. - -commit 5b6b34e0c5b715ed068d8d50a04e69c49617d039 -Author: Brian Lamar -Date: Thu Aug 4 12:35:41 2011 -0400 - - Change create-image back to image-create, and increased version to 2.6.0 - -commit 32fd202ab0df89ef881c33c4fa93e5ea2cfdfa9b -Author: Brian Lamar -Date: Thu Aug 4 10:55:08 2011 -0400 - - Updated --version to default to NOVA_VERSION, quick fix. - -commit ea4b625e7bbf8a2c5581a0879ffe9e7bf7ddb80b -Author: Brian Lamar -Date: Thu Aug 4 10:52:53 2011 -0400 - - Updated --version to default to NOVA_VERSION - -commit c0c5f6925e2e119612cb516d3c0e8460c343f2bd -Author: Brian Lamar -Date: Thu Aug 4 10:24:36 2011 -0400 - - osc -> novaclient - -commit 6c73d4c3b69b0b44299384b05907c086e7e996b4 -Author: Brian Lamar -Date: Thu Aug 4 09:13:46 2011 -0400 - - Cleaned up v1.0 and v1.1 test setup to remove globals and encapsulate custom asserts. Still duplicate code, but closer to being able to remove. Now tests set up OpenStackClient much closer to how users will do it, minus the stubbing of the client. - -commit fc8253f2ca4a9fb22af2ea0c966d5bf122339f49 -Author: Brian Lamar -Date: Wed Aug 3 18:38:29 2011 -0400 - - Wrong client was getting loaded. - -commit c9422d5e3b92ff3713dad9911ab5520b1547e15c -Author: Brian Lamar -Date: Wed Aug 3 18:18:51 2011 -0400 - - Grrrr, bad import. - -commit 57ebb51e2149896984a019a8ae42cd5e87041479 -Author: Brian Lamar -Date: Wed Aug 3 18:14:47 2011 -0400 - - Tests now run correctly for v1.1 and v1.0 - -commit 9080e80832bb782fd85ae5c4b3b7a0a745379af6 -Author: Brian Lamar -Date: Wed Aug 3 17:58:39 2011 -0400 - - Updated the default version back to 1.0, as there are some quirks with 1.1 - -commit 454daa2cba9058d0e744b398ce6af0135b5b27b7 -Author: Brian Lamar -Date: Wed Aug 3 17:41:33 2011 -0400 - - Tests working again...merged in some work we did earlier. - -commit f8496672cc61ffba052a8c9626e24fde18519010 -Author: Brian Lamar -Date: Wed Aug 3 16:36:03 2011 -0400 - - Split everything down the middle into v1_0 and v1_1, including tests. - -commit 4b8879a8eb3fb80494ff16d4b96490fec9aa2161 -Merge: 20251cc 40a2bf9 -Author: Josh Kearney -Date: Fri Jul 29 12:44:50 2011 -0700 - - Merge pull request #39 from bcwaldon/master - - Server Backup Update - -commit 40a2bf9fa8f904957adb546c8f150a4f30ea431b -Author: Brian Waldon -Date: Fri Jul 29 11:29:53 2011 -0400 - - bumping version and updating README - -commit ca8aa158fc0d1ab9f653f79f4bb5169a7884b0b6 -Author: Brian Waldon -Date: Fri Jul 29 10:06:05 2011 -0400 - - updating server backup action; pep8 fixes - -commit 20251ccc2ff7a8d030647c92c9a5a288ed5c1229 -Merge: 25596fe d72ea5d -Author: Josh Kearney -Date: Wed Jul 13 11:03:56 2011 -0700 - - Merge pull request #32 from SandyWalsh/master - - Removed incorrect server dump at the end of add/remove-fixed-ip() - -commit d72ea5df95a2c3952339241c7e6bd7d4a8956d92 -Author: Sandy Walsh -Date: Wed Jul 13 10:31:58 2011 -0700 - - removed server dump after add/remove fixed-ip - -commit 25596fef72b3b32a37bae2d2e4c9188953d834b5 -Merge: 5560117 1920e32 -Author: comstud -Date: Tue Jul 12 15:11:08 2011 -0700 - - Merge pull request #31 from SandyWalsh/master - - 2.5.8 and all public/private ips shown - -commit 1920e32b1f18113cf0bb746f80e88dab3fb434c2 -Author: Sandy Walsh -Date: Tue Jul 12 14:54:20 2011 -0700 - - version bump - -commit be03eb5fa42490d794e9e5572a0a80ac01dd9175 -Merge: d76d6c9 5560117 -Author: Sandy Walsh -Date: Tue Jul 12 14:50:31 2011 -0700 - - Merge branch 'master' of github.com:rackspace/python-novaclient - -commit d76d6c9f1f2e83da86c15e11c3609476a7e0cf1f -Author: Sandy Walsh -Date: Tue Jul 12 14:41:56 2011 -0700 - - fixed public private ip list - -commit 5560117e77da5ff3481e4710c40ef6bae3341e47 -Merge: ecc2ede 5e987ff -Author: Sandy Walsh -Date: Tue Jul 12 10:13:29 2011 -0700 - - Merge pull request #30 from comstud/servers-search - - added various search options to list command - -commit 5e987ffc30ed9460c1bf13bdbca13df1f1ea45a0 -Author: Chris Behrens -Date: Tue Jul 12 02:12:03 2011 -0700 - - added various search options to list command. will need a version bump as i changed the 'list' api that nova uses. after version bump, my search nova branch will need pip-requires updated to match - -commit ecc2ede1b1e1a75b4d78c985d147f40814511ece -Merge: f1a8117 5f08840 -Author: Josh Kearney -Date: Fri Jul 8 12:15:58 2011 -0700 - - Merge pull request #28 from jerdfelt/master - - Clarify usage for zone-delete - -commit f1a81175ec997b6fb0eb990c7ed8a9ce6672635b -Merge: 0118cb3 2bba8e2 -Author: Josh Kearney -Date: Fri Jul 8 12:14:26 2011 -0700 - - Merge pull request #29 from SandyWalsh/2bba8e2e2b08a53d7dea828047406074826d7622 - - Adds add_fixed_ip and remove_fixed_ip to servers action. - -commit 6efed32d28bb8ae90260b95d70828e3142bfe331 -Author: Sandy Walsh -Date: Fri Jul 8 10:57:27 2011 -0700 - - docs - -commit 2bba8e2e2b08a53d7dea828047406074826d7622 -Author: Sandy Walsh -Date: Fri Jul 8 10:54:43 2011 -0700 - - added add/remove fixed_ip actions to servers - -commit 5f08840b559dc508062d1675ffa389e86c019da8 -Author: Johannes Erdfelt -Date: Thu Jul 7 22:51:27 2011 +0000 - - Clarify description so usage doesn't imply name is the only valid value - -commit 0118cb316158c8f11b635bfb08dcaee43b4e6218 -Merge: f81fc89 eb0d5c7 -Author: comstud -Date: Thu Jul 7 15:15:23 2011 -0700 - - Merge pull request #27 from EdLeafe/master - - Added support for request timeouts. - -commit eb0d5c75b7be1a78803a7f938ee0e1ac70556dea -Author: Ed Leafe -Date: Thu Jul 7 21:07:49 2011 +0000 - - Added support for request timeouts. - -commit f81fc89cc8aa5bd2cce7fccd0d469af6325512b0 -Merge: ede425d 9b31d54 -Author: jerdfelt -Date: Thu Jul 7 11:39:35 2011 -0700 - - Merge pull request #26 from jk0/master - - Migrations! - -commit 9b31d54aa2b08a59c7e7f67ba78a0e8e0ae3e88e -Author: Josh Kearney -Date: Thu Jul 7 13:33:17 2011 -0500 - - Added migration functionality. - -commit ede425d3abfd62412d4d449006936350994d4a67 -Merge: c1b1420 cee51f8 -Author: Josh Kearney -Date: Tue Jun 28 12:54:50 2011 -0700 - - Merge pull request #25 from jk0/master - - Refactored backup rotation code. - -commit cee51f8aff494c1e7dd266e2a24c9dc9bb7b18f8 -Author: Josh Kearney -Date: Fri Jun 24 14:48:14 2011 -0500 - - Refactored backup rotation. - -commit c1b1420b68ba50ed3f0dc66cb071e36d278d2a36 -Merge: 68b115d 8a52343 -Author: Sandy Walsh -Date: Fri Jun 24 12:08:07 2011 -0700 - - Merge pull request #23 from jk0/master - - Implement backup with rotation. - -commit 8a523431e3db9a1390933036532dc9f2ffacf17f -Author: Josh Kearney -Date: Fri Jun 24 13:27:02 2011 -0500 - - Review feedback. - -commit 518ca43ef758c08b29d87ac238483d29ce3fc6ea -Author: Josh Kearney -Date: Fri Jun 24 13:22:20 2011 -0500 - - Fixed unit tests. - -commit 68b115d77033e4bc93497aa20eca486148d65020 -Merge: ef72c18 0f0ea33 -Author: Sandy Walsh -Date: Fri Jun 24 10:55:35 2011 -0700 - - Merge pull request #24 from comstud/num-instances-fixes - - 'x' instances fixes. - -commit ef72c18f5e4967ba50048e4eea11d3202ae1d920 -Merge: 787b369 6b25dd6 -Author: Sandy Walsh -Date: Fri Jun 24 10:54:07 2011 -0700 - - Merge pull request #22 from comstud/master - - Makes novaclient try to use UUID on subsequent calls instead of ID (the integer ID) - -commit ff87b8c449cd5eee042d91c5dc4ad4f98bc184cb -Merge: 787b369 04ef226 -Author: Josh Kearney -Date: Fri Jun 24 12:25:45 2011 -0500 - - Merge branch 'backups' - -commit 04ef22667633672d0f14eec49fe6ac3ef26200c6 -Author: Josh Kearney -Date: Fri Jun 24 12:24:26 2011 -0500 - - Implemented backup with rotation. - -commit 0f0ea3305a87dc8d74e5e5d7f7328849608f7fe4 -Author: Chris Behrens -Date: Thu Jun 23 22:39:10 2011 -0700 - - for creating 'x' instances, min_count > max_count check was reversed - make max/min_instances a little more sane by making them 'int' types - fix issue where only specifying --min_instances didn't work - -commit 6b25dd66dfeae29bb8fdf253833d47f252c9bb71 -Author: Chris Behrens -Date: Thu Jun 23 21:49:10 2011 -0700 - - Due to how novaclient works, it tends to do a 'get' first on whatever ID - you pass on command line. Then it does the real command, re-using the - ID found in the 'get' call, instead of the initial ID that you specified - (which may have been a UUID). - - This makes it use the UUID from the initial 'get' call if it finds it, - so that commands work across zones. 'nova delete UUID', for instance, - wouldn't recurse zones as novaclient was doing a delete on the integer - ID, even though you specified a UUID. - - This change has a side effect of trying to find 'uuid' in Image and - Flavors as well, but it'll fall back to using the integer ID. - -commit 787b369e6c9cfd402f37ffe81bb54b18a8b55fdb -Merge: a5ef8fc 9e86dd0 -Author: Josh Kearney -Date: Thu Jun 23 16:10:53 2011 -0700 - - Merge pull request #21 from comstud/master - - various zones changes/fixes. - -commit a5ef8fc5bc6e9c1a170d5fe617f09e4b6ae59258 -Merge: 459e51b 5b566a0 -Author: Josh Kearney -Date: Thu Jun 23 16:10:06 2011 -0700 - - Merge pull request #21 from comstud/master - - various zones changes/fixes. - -commit 9e86dd0634db384bc495fcc323fd6db97e890a62 -Author: Chris Behrens -Date: Thu Jun 23 15:07:05 2011 -0700 - - Cleaned up the query_string generation for 'nova list' - Made --recurse_zones not need an '=argument'. - -commit 5b566a0f5c46e012549041336e37d56674e8b252 -Author: Chris Behrens -Date: Thu Jun 23 09:50:20 2011 -0700 - - Added --recurse_zones option to 'list' - Added --fixed_ip option to 'list' to find a particular instance by IP - Fixed issue with 'show' when --recurse_zones=1 and specifying UUID - - Squashed commit of the following: - - commit 34e86d8209012817f6534bff31551edd32ec1fc1 - Author: Chris Behrens - Date: Thu Jun 23 09:35:09 2011 -0700 - - only lookup the server details once for the show command - - commit 3e3438cf903fc46fcf280c728b119f0214545251 - Author: Chris Behrens - Date: Thu Jun 23 07:39:18 2011 -0700 - - if recursing zones, display UUID instead of Id - - commit a42c63ad7af1bdb8604890d8c7302e730360e3e3 - Author: Chris Behrens - Date: Thu Jun 23 07:20:25 2011 -0700 - - recurse zones fixes - - commit 1fe63dcf98ec8e37307dcce0b63895ce88f31ce2 - Author: Chris Behrens - Date: Thu Jun 23 04:46:27 2011 -0700 - - Add --fixed_ip and --recurse_zones options to shell 'list' command - servers.list takes fixed_ip, project_id, and recurse_zones options now - -commit 459e51b14edf7f04d88569991a0c3945a735c948 -Author: Sandy Walsh -Date: Tue Jun 21 12:11:49 2011 -0700 - - fixup - -commit 9ab5f6611c62446089753df6aa4524738acc18d1 -Author: Sandy Walsh -Date: Tue Jun 21 04:57:48 2011 -0700 - - release note update - -commit 2069b17f8b6627a19e90a9b872eb1a5b5f573c6c -Author: Sandy Walsh -Date: Tue Jun 21 04:54:01 2011 -0700 - - tests working again for weight_scale/weight_offset - -commit 46855896a890d268c77d79bb5c9ae27ed219e655 -Author: Sandy Walsh -Date: Mon Jun 20 19:16:15 2011 -0700 - - fixed up tests after trunk merge and bumped version - -commit 3e9a5489496f956fbc72810e198d3c053416e227 -Merge: a6360be 15cfb4c -Author: Sandy Walsh -Date: Mon Jun 20 18:43:44 2011 -0700 - - Merge pull request #20 from comstud/master - - adds --min_instances and --max_instances to zone-boot - -commit a6360bea5201df707d3bf765f541970288997ae9 -Author: Sandy Walsh -Date: Mon Jun 20 18:40:57 2011 -0700 - - version bump - -commit 961d757e702d0dc401913987eb95e0660593eafd -Author: Sandy Walsh -Date: Mon Jun 20 18:09:52 2011 -0700 - - fixed project_id tests - -commit 15cfb4cd35fd1cf0c4cab8e6ef234f51a365ec27 -Author: Chris Behrens -Date: Mon Jun 20 16:26:57 2011 +0000 - - Merged my 'create-num-instances' branch which adds support for --min_instances and --max_instances to zone-boot - - Squashed commit of the following: - - commit f8a9d157c1b6989ca61430b2829c69bafead9731 - Author: Chris Behrens - Date: Mon Jun 20 16:24:26 2011 +0000 - - updated tests for min_count/max_count - - commit e093e9e883159d42a67ba8799f46fa0cdf333077 - Author: Chris Behrens - Date: Mon Jun 20 16:13:16 2011 +0000 - - adds --min_instances and --max_instances options to nova zone-boot - -commit 4417c96e1e973a91c95de260228b243720fbb9f6 -Merge: 7edce02 6aa43b1 -Author: Josh Kearney -Date: Fri Jun 17 08:46:46 2011 -0700 - - Merge pull request #19 from Cerberus98/instance_for_accounts - - Instance for accounts - -commit 7edce02045c23b02bd3f2db94dcd74db8a9a2f90 -Author: Sandy Walsh -Date: Wed Jun 15 09:50:16 2011 -0700 - - version bumped - -commit c794bdfafe8d29b1dd9b9ea038bac9ab4e266ef3 -Author: Sandy Walsh -Date: Wed Jun 15 09:48:24 2011 -0700 - - trunk merge - -commit dbef80d2fbaef0134d4b700fafa134c9cba202d4 -Merge: 7a9e006 ff7e725 -Author: Sandy Walsh -Date: Wed Jun 15 09:47:50 2011 -0700 - - Merge pull request #14 from usrleon/master - - Updated README.rst and shell.rst about PROJECT_ID option - -commit 6aa43b168854ff421245edba8de11998c89b14fa -Author: Matt Dietz -Date: Mon Jun 13 15:18:11 2011 -0500 - - Typo fix - -commit 6c907a7cbbfc2a5e810b6ac48f17c40af9fb9ddb -Author: Matt Dietz -Date: Mon Jun 13 15:14:02 2011 -0500 - - Added the missing files - -commit 129d56611c35366b34328cdb7fab41a672a9db5e -Author: Matt Dietz -Date: Mon Jun 13 15:13:33 2011 -0500 - - Added a method to create instances on behalf of an account via the admin API methods for openstack - -commit ff7e725f9201db22ecb890c997c396960d083d0b -Author: Lvov Maxim -Date: Mon Jun 13 16:16:58 2011 +0400 - - changed docs about using project id - -commit 7a9e006a2f8e6128102c34de0f79ad148018d917 -Author: Sandy Walsh -Date: Fri Jun 10 07:25:13 2011 -0700 - - bumped version # after project_id update - -commit cbca828f7c64e88f4bb7fa0b3eb9e6ffc5090a02 -Merge: 3c10087 882a266 -Author: Sandy Walsh -Date: Fri Jun 10 07:23:10 2011 -0700 - - Merge pull request #13 from usrleon/master - - support for X-Auth-Project-Id api header - -commit 3c10087824c7c04c47de92fa4fbb075afefce80f -Merge: d778d42 c100f21 -Author: Josh Kearney -Date: Thu Jun 9 12:59:05 2011 -0500 - - Merge branch 'master' of github.com:rackspace/python-novaclient - -commit c100f21d3d01e661e92a7961a7963604d097be83 -Merge: 117e455 182b3a7 -Author: Josh Kearney -Date: Thu Jun 9 10:11:09 2011 -0700 - - Merge pull request #12 from klmitch/master - - Add add_fixed_ip() and remove_fixed_ip() on servers - -commit d778d4278e952b33cd0bd4fcc08a3e589fdbb223 -Author: Josh Kearney -Date: Thu Jun 9 10:38:01 2011 -0500 - - Don't restrict ids to int. - -commit 882a266387dfdd630f45fa5b86adb83a3df843d3 -Author: Lvov Maxim -Date: Thu Jun 9 11:57:46 2011 +0400 - - fix errors - -commit 0853ebebedd8663c6348ae59e22a37745a2bd8fb -Author: Lvov Maxim -Date: Thu Jun 9 10:39:13 2011 +0400 - - support for project id header - -commit 182b3a71963b93f8485a356ced01c0e62646bf2d -Author: Kevin L. Mitchell -Date: Wed Jun 8 11:18:43 2011 -0500 - - Now that I understand how to build extensions, I understand how this - extension will be built, and can fully implement add_fixed_ip() and - remove_fixed_ip() - -commit 0b43ddbc936122ba155c07490daeffb2d0fdeba7 -Author: Kevin L. Mitchell -Date: Tue Jun 7 17:56:33 2011 -0500 - - Add the basic calls for add_fixed_ip/remove_fixed_ip. - - Implementation depends on extensions to the OpenStack API - -commit 117e455bb668791678f5c0bc7a08195fe2bfa527 -Author: Sandy Walsh -Date: Fri Jun 3 06:57:33 2011 -0700 - - defaults back to no detail - -commit ddf8ef6d2c6a2bdb17eb7c391278e76d786a3eb9 -Author: Sandy Walsh -Date: Fri Jun 3 06:30:24 2011 -0700 - - tweaks - -commit d96f3c54621eef0b3a007124b8af32f4a9aebe71 -Merge: e4d7575 512c88c -Author: Sandy Walsh -Date: Fri Jun 3 06:16:54 2011 -0700 - - griddynamics better logging - -commit e4d75757c68ffcb7fcc1de5e85739baf910a340a -Author: Sandy Walsh -Date: Wed Jun 1 11:50:32 2011 -0700 - - reservation_id optional parameter added to GET /servers (aka 'list') - -commit 7090a6c8e0394acea445b0215b98d7102cf3700d -Author: Sandy Walsh -Date: Mon May 30 18:04:13 2011 -0700 - - works properly with zone-boot - -commit 512c88cce801f3e550f3874c47f1dd86c6b875d5 -Merge: 2a9e0b4 868d57a -Author: Ilya Alekseyev -Date: Mon May 30 10:57:47 2011 -0700 - - Merge pull request #4 from Reldan/master - - Improving tests for undetailed images - -commit 868d57a9a04bb96b51a80ce276eac45c37e3af4b -Author: Eldar Nugaev -Date: Mon May 30 21:42:46 2011 +0400 - - Improving tests - -commit 2a9e0b485c4bb243b3049b4d6802252f6948963f -Merge: 6b94a87 6a3a139 -Author: Andrey Brindeyev -Date: Mon May 30 03:35:07 2011 -0700 - - Merge pull request #3 from Reldan/master - - Added parameter detailed to list - -commit 6a3a139846fd2c05b2ac910f2c658e3713bc82c2 -Author: Eldar Nugaev -Date: Mon May 30 14:31:56 2011 +0400 - - Added parameter detailed to list - -commit 6cb04897af98e9bc2b2f5cc7b119737f5548fe9b -Author: Sandy Walsh -Date: Fri May 27 07:39:22 2011 -0700 - - zone select support and version bump to 2.4.3 - -commit 6b94a876c00d71928d08db10e67e1da0bacdc4c4 -Merge: 0a3f94a 76a631d -Author: Andrey Brindeyev -Date: Wed May 25 07:02:17 2011 -0700 - - Merge pull request #2 from kshileev/master - - logging for HTTP req-resp - -commit 76a631d2f7c349446c6d8612b293834702306a4f -Author: Kirill Shileev -Date: Wed May 25 17:10:53 2011 +0400 - - fix to reviewer comment: add check if logging disabled - -commit ad292c029abbe1f950b55af472830926dfd525f8 -Author: Kirill Shileev -Date: Wed May 25 16:48:40 2011 +0400 - - improve perfomance on string concat in logging - -commit be1d6d7a3bd42bd5d506dce5d76e24692ac2af44 -Author: Kirill Shileev -Date: Wed May 25 14:10:20 2011 +0400 - - add logging for http request-response - -commit 2ec3c3febd4e3f8c369c40f72f4ab7b0e74227e2 -Author: Sandy Walsh -Date: Mon May 23 12:08:42 2011 -0700 - - zone select - -commit 0a3f94adbc7b5793a9e458256b03c94bbe8cb6c6 -Merge: f862a6f 1114249 -Author: Andrey Brindeyev -Date: Fri May 20 10:52:33 2011 -0700 - - Merge pull request #1 from kshileev/master - - add list_flavor with GET /flavors without detail - -commit 1114249c18c4ac2650515e24b389579c3eabc01d -Author: Kirill Shileev -Date: Fri May 20 21:41:56 2011 +0400 - - add undetailed flavor list - -commit f216dbd2e4cf7b4b7ea22b732fbf6f004bc45fb7 -Merge: 30e7951 f862a6f -Author: Sandy Walsh -Date: Thu May 19 06:58:48 2011 -0700 - - Merge branch 'master' of github.com:rackspace/python-novaclient - -commit 30e7951a7a6022920b2c0cb8ee17fb5559b13823 -Author: Sandy Walsh -Date: Thu May 19 06:58:41 2011 -0700 - - zone_blob support added to server.create - -commit f862a6f61810784886f71f2fbf997db6696cd892 -Author: Sandy Walsh -Date: Fri Apr 8 15:36:39 2011 -0300 - - fixed flavor-list columns - -commit dc4626fb44f398274dd69cbd0685c58c98ed8cf3 -Author: Sandy Walsh -Date: Wed Mar 16 05:43:50 2011 -0700 - - added support for missing flavors/images - -commit c4119ddc22c84f5df191f2edb680e34236e65029 -Author: Sandy Walsh -Date: Thu Mar 10 10:40:42 2011 -0800 - - up'ed version to suit pypi distribution update - -commit d33a7c461f1344aef9dd420aaa717f4b2c628009 -Author: Sandy Walsh -Date: Fri Feb 25 02:18:55 2011 -0800 - - fixed software license - -commit bcf65fe16e19d6e90b4597537ad13fd05af65be7 -Author: Sandy Walsh -Date: Fri Feb 25 02:11:32 2011 -0800 - - version 2.4 - -commit 8e615f4446816b69ffde7bff6ba99c85d34d1e2f -Author: Sandy Walsh -Date: Fri Feb 25 02:00:13 2011 -0800 - - Added Jacob Kaplan-Moss copyright notices on older/untouched files. - -commit bd18c7e429248e13ce726231a4b0362ff8d82b0d -Author: Sandy Walsh -Date: Sat Feb 26 05:04:40 2011 -0400 - - renamed to novaclient and fixed flavor tests - -commit 8611fc25985eea24411de55bb99f84f936f1118d -Author: Sandy Walsh -Date: Thu Feb 24 17:59:42 2011 -0400 - - missing docstring quote - -commit edff3ce1f466496e3e02215726c580eb7e818d49 -Author: Sandy Walsh -Date: Thu Feb 24 17:58:25 2011 -0400 - - tweaked release notes - -commit 9db6490f44c715b7f86d4a9d053a7f738e9389c4 -Author: Sandy Walsh -Date: Thu Feb 24 17:52:49 2011 -0400 - - removed copyright/license notices from files not significantly changed. - -commit cc27b6d4591806da1da2ef54201ed5389e65617e -Author: Sandy Walsh -Date: Thu Feb 24 13:54:10 2011 -0400 - - renamed cmdline tool from novatools to nova. Changed version to 2.1. Changed license to Apache. Added copyright notices. Cleaner exception reporting in non-debug scnario. - -commit 27709a3e245826b75c1397ef643c9b98f59b3a7c -Merge: 560c314 c65a0a1 -Author: Josh Kearney -Date: Thu Feb 17 16:12:16 2011 -0600 - - Merge remote branch 'SandyWalsh/master' - -commit c65a0a186771a0d8248f0213e77cc77025fbbaeb -Author: Sandy Walsh -Date: Thu Feb 17 17:56:16 2011 -0400 - - fixed setup - -commit db357e580de1afcdaa0321d64e2bb5f0d68e06d9 -Author: Sandy Walsh -Date: Thu Feb 17 12:09:24 2011 -0800 - - longer zone list - -commit 560c314666d644975e531b40fe4d37a213583ea9 -Author: Josh Kearney -Date: Wed Feb 16 11:10:13 2011 -0600 - - Added full flavor detail support - -commit 82227aa77f25a0dc629da7435603116378fe7a6a -Author: Sandy Walsh -Date: Tue Feb 15 11:16:30 2011 -0800 - - zone info works - -commit 6ad9c5365cb690832f75d455b6c1eb6f54029917 -Author: Sandy Walsh -Date: Tue Feb 15 11:34:06 2011 -0400 - - get this zone status - -commit b97c9760ad4ba75393fd5f1866a88d181c701b42 -Author: Sandy Walsh -Date: Mon Feb 14 14:35:37 2011 -0800 - - removed Username from zone info - -commit 88a57e2a4af0d7d0dac0c066d6bfdaa97ce51988 -Author: Sandy Walsh -Date: Mon Feb 14 14:27:21 2011 -0800 - - NOVA_TOOLS_* -> NOVA_*, --debug - -commit 9034c4618a03c869adb7104303377b2cfd9f8316 -Author: Sandy Walsh -Date: Wed Feb 9 18:31:22 2011 -0400 - - removed zone name, renamed auth_url to api_url, added username/password - -commit 637ddefbbed90799cb6e48359c415058eaa0f032 -Author: Sandy Walsh -Date: Wed Feb 9 11:16:51 2011 -0400 - - zone shell cmds & tests added - -commit 315b20b9c1e924b8d362721a3068e4c4f40cc6d0 -Author: Sandy Walsh -Date: Tue Feb 8 17:41:28 2011 -0400 - - zone tests pass - -commit 7dddd46f0113d62b55792c72860a455b63a0eb58 -Author: Sandy Walsh -Date: Tue Feb 8 17:40:58 2011 -0400 - - zone tests pass - -commit f0c713658fb41ed4349b489b16b0602934712ba9 -Author: Sandy Walsh -Date: Tue Feb 8 14:45:21 2011 -0400 - - tests pass again - -commit ef93d6ffdf0ae392997bdb97365574809ab3d10f -Author: Sandy Walsh -Date: Tue Feb 8 10:43:31 2011 -0400 - - zones - -commit 4e2f2e21d358131e2884c71ce2f013a4ac720b59 -Author: Sandy Walsh -Date: Tue Feb 8 09:27:22 2011 -0400 - - Renamed all CloudServers to OpenStack and python-cloudservers to python-novatools - -commit 7e2c002b2a1fcd507ffe8d98c08478ee6c2e7600 -Author: Sandy Walsh -Date: Tue Feb 8 08:58:26 2011 -0400 - - installer fixup - -commit f900d999a53883291e0fb6fd08cbcd32633eb36d -Author: Sandy Walsh -Date: Tue Feb 8 08:54:34 2011 -0400 - - README update and rename cloudservers to novatools - -commit e77baddbabc57570fa45e183c604750ab4ae3a2c -Author: Sandy Walsh -Date: Thu Jan 27 23:51:35 2011 -0600 - - Starting on child zone support - -commit 7304ed80df265b3b11a0018a826ce2e38c052572 -Author: Josh Kearney -Date: Tue Jan 25 14:01:22 2011 -0600 - - Initial commit from fork \ No newline at end of file +* Fix typo in novaclient +* Updated from global requirements +* Invalid client version message unclear +* Remove None for dict.get() +* Replace assertEqual(None, *) with assertIsNone in tests +* Fix i18n messages in novaclient, part II +* Update broken command line reference link +* Fix spelling miss of password_func variable +* Fix copy/paste errors in print messages +* Remove invalid parameter of quota-update +* Remove tox locale overrides +* Fix python 3.3 unit test job +* Adds support for the get_rdp_console API +* Fixed polling after boot in shell +* Update my mailmap +* Fix Serivce class AttributeError +* [UT] Fixed floating_ip_pools fake return to expected one +* [UT] Removed duplicate key from dict in fake baremetal_node +* Fixed multi validation and wrong fail calls in unit tests +* Fixed super constructor call for TestResponse class +* Flavor ExtraSpecs containing '/' cannot be deleted +* Removed undefined method in install_env.py file +* Fix i18n messages in novaclient, part I +* Adds ability to boot a server via the Nova V3 API +* Removes unsupported volume commands from V3 API support +* Reuse Resource from oslo +* Updates nova client to use the latest oslo files +* Using common methods from oslo cliutils +* Add tests for boot method of v3 shell +* Replace basestring by six.string_types +* Removes use of timeutils.set_time_override +* Fix logic for "nova flavor-show 0#" +* Sync with global requirements +* Don't call CS if a token + URL are provided +* Sync cliutils from oslo +* Sync apiclient from oslo +* Fix QuotaClassSet and their tests +* assertTrue(isinstance) replace by assertIsInstance +* Remove the coverage extension code +* shell: refactor boot to use _print_server +* Don't slugify() None names +* Adds volume support for the V3 API +* Fixes ambiguous cli output between "None" and NoneType +* Support list deleted servers for admin +* Using floating-ip-{associate|disassociate} +* Removes vim configuration headers +* Adds quota usage support for the V3 API +* Fix tab-completion of --flags under OS X +* Remove class_name parameter from quota_class +* Ensure that the diagnostics are user friendly +* Code cleanup: use oslo's to_slug() instead of slugify() +* Added v3 interfaces in reference doc +* Enable pep8 check for config.py in doc +* Generate interfaces reference doc +* Ensure that nova client prints dictionaries and arrays correctly +* Replace some utils.bool_from_str with strutils +* Allow empty response in service-list +* Nova aggregate-details should be more human friendly +* Removed duplicated import +* Adding additional tests for novaclient ssh +* Fix "device" as the optional para on volume-attach +* Adds simple tenant usage support for the Nova V3 API +* Adds keypairs support for the Nova V3 API +* Adds certificates support for Nova V3 API +* Adds aggregates support for Nova V3 API +* Adds hypervisor support for Nova V3 API +* Adds services support for Nova V3 API +* Adds second part of quotas support for Nova V3 API +* Adds first part of quotas support for Nova V3 API +* Adds availability zone support for Nova V3 API +* Adds basic servers support for the Nova V3 API +* add support for nova ssh user@host +* remove duplicate six import +* Allow multiple volume delete from cli like Cinder +* Fixed autodoc can't import/find class error +* Expose the rebuild preserve-ephemeral extension +* Stop using deprecated keyring backends +* Adds images support for Nova V3 API +* Remove commands not supported by Nova V3 API +* Adds agent support for Nova V3 API +* Adds flavor access support for Nova V3 API +* Adds flavor support for Nova V3 API +* Enables H403 pep8 rules +* Allow graceful shutdown on Ctrl+C +* Enables H306 pep8 rules +* Enables E711,E721,E712 pep8 rules +* Updates tox.ini to use new features +* Updated from global requirements +* Remove the release.rst file +* Fix docstring on novaclient +* add support for server set metadata item +* Fix incorrect help message on flavor_access action +* Fix inappropriate comment for delete FloatingIP +* Enable hacking check for Apache 2.0 license +* Sets default service type for Nova V3 API +* Fix the inappropriate comment for flavor +* Adds a --show option to the image-create subcommand +* Updates .gitignore +* Allows users to retrieve ciphered VM passwords +* Fix inappropriate comment for flavor create api +* Fix typo in novaclient +* Removes unnecessary pass +* Updated from global requirements +* Discrepancy between README.rst and nova help +* nova security-group-* should support uuid as input +* Change "project" to "project_id" in cloudpipe-create +* Fix single H234 Bug to make Hacking 0.8 pass +* Flatten hypervisor-show dictionary for printing +* Revert "Nova aggregate-details should be more human friendly" +* Update mailmap for Joe Gordon +* Print security groups as a human readable list +* Adds locking to completion caches +* Nova aggregate-details should be more human friendly +* Make 'nova ssh' automatically fall back to private address +* Quote URL in curl output to handle query params +* Add --insecure to curl output if required +* Apply six for metaclass +* Updated from global requirements +* Remove deprecated NOVA_RAX_AUTH +* Print dicts in alphabetical order +* Make os-cache retry on an invalid token +* Document and make OS_CACHE work +* Revert "Add-in some re-auth logic when using os_cache" +* Align mocking pattern for test case +* py33: use six.StringIO() to mock stdout/stderr +* py33: sort the files parameters of "--files" +* py33: sort hosts while treeize AvailabilityZone +* py33: unify the input of request to json format +* py33: align the order of parameters for urlencode() +* py33: sort dict for test_add_floating_ip_to_fixed +* py33: iteration order of dict is unpredictable +* Updated from global requirements +* py33: 'str' does not support the buffer interface +* assertEquals is deprecated, use assertEqual +* py33: align the order of parameters for urlencode() +* Add shelve/unshelve/shelve-offload command +* py33: uuid verification in find_resource() +* py33: don't encode security_group +* Add-in some re-auth logic when using os_cache +* if we have a valid auth token, use it instead of generating a new one +* py33: safe_encode() returns bytes in Python 3 +* py33: unknown encoding: base64 Edit +* Fix AttributeError in Keypair._add_details() +* Fixed several test failures on Python3 +* Make nova CLI use term "server" where possible +* py33: dict.keys() is not a list in python3 +* Corrected several usage of keys() for Python 3 +* py33: 'dict_keys' object does not support indexing +* Corrected usage of len(filter(...)) +* Update pbr usage +* Clean up a little cruft +* Novaclient shell list command should support a minimal server list + +2.15.0 +------ + +* Add v3 HostManager +* Create v3 tests directory +* Fix the print order of quota-show +* assertEquals is deprecated, use assertEqual +* Small bugfix for client v3 +* Modify --num-instances flag description to clarify limit upper bound +* Add a block device for the image when using BDMv2 +* python3: Compatibility for iteritems differences +* python3: Fix traceback while running unit tests +* python3: Fix Traceback while running unit tests +* Unittests added for client v1_1 +* Python3: Fix traceback while running unit tests +* Python3: Use six.StringIO for io.Bytes() +* Update oslo from oslo-incubator +* Add delete method to Flavor class +* New syntax to boot from a block device mapping +* Allow name argument to flavor-access-add +* Add support for os-assisted-volume-snapshots +* Suport instance list pagination in novaclient, Part I +* Add interface for listing security groups of an instance +* Added support for running the tests under PyPy with tox +* python3: Fix imports for py2/py3 +* Upgrade to Hacking 0.7 +* Sync py3kcompat from oslo +* Update mailmap +* Update mailmap +* Added 'nova migration-list' command +* Fix and gate on H501, no locals for string formatting +* Update oslo +* Allow name argument to flavor-access-add +* python3: Fix traceback while running tests +* Fix the help messages to specify image/flavor name +* Clean up inaccurate docstrings of server list() method +* Remove old references +* Enable v3 api code +* Begin adding v3 api support +* change 'Host' object's 'host' attribute to 'host_name' +* Updated from global requirements +* Do not restrict flavor to only ID and integers +* Fix typo and grammar in docstring only + +2.14.1 +------ + +* remove requests version max + +2.14.0 +------ + +* Sync with global requirements +* Add support for swap_volume +* FakeClient: fix the arguments of a string format +* Support programmatic use of disk config extension +* Check whether the security group id is integer +* Fixing host-action on V2 +* Add user quota client API support +* Fix net-id metavar for interface-attach +* make findall in novaclient/base.py more efficient +* Fix the help text process and the generated wrong help +* Remove python 2.4 and python 2.5 support +* Enable force_delete and restore instance via novaclient +* Add name argument to aggregate commands +* Add name argument to hypervisor commands +* recognize 429 as an rate limiting status +* Fix backwards-incompatible API change (method signature) +* Fix and enable gating on H402 +* Add AgregatesManager.get() +* Skip setting volume_size if not given +* Fix interface-list got none mac address +* Remove uncessary code related to nova start/stop +* make v2_auth and plugin_auth explictly return their results +* Sync install_venv_common from oslo +* Clean up and make HACKING.rst point to openstack-dev/hacking +* CLI for disable service reason +* Allow tenant ID for authentication +* Adds zsh completion +* Bring stdout/stderr capturing in line w/ nova +* Fixup trivial License Header mismatch +* Remove Diablo compatibility options +* python3: Fix print statements +* python3: Compatibility for iteritems differences +* python3: Fix unicode compatibility python2/python3 +* Return Customer's Quota Usage through Admin API +* Discard possibly expired token before re-authenticating +* Support force update quota +* Update help for --nic opt and make net-id or port-id required +* Adds support for ExtendedFloatingIps APi extension +* Remove explicit distribute depend +* Cells Support +* Set default value of flavorid to "auto" +* Migrate each instances of a host to another +* Set/Delete metadata on all instances of a host +* The 'nova keypair-show key_name' command added +* Use Python 3.x compatible except: construct +* Delete a quota through admin api +* Exit w/ valid code when no servers are deleted +* Evacuate each instance from one host to another +* python3: Introduce py33 to tox.ini +* Start using Hacking and PyFlakes +* Add update method of security group name and description +* Fix shell tests for older prettytable versions +* Provide nova CLI man page +* Improve error messages for invalid --nic / --file +* 100% test coverage for security groups and rules +* Add MethodNotAllowed and Conflict exception classes +* Move tests into the novaclient package +* Add CONTRIBUTING file +* Rename requires files to standard names +* Code cleanup in advance of flake8 +* Migrate to flake8 +* Revert "Support force update quota" +* Only add logging handlers if there currently aren't any +* Convert to more modern openstack-common.conf format +* Cleanup unused local variables +* Reuse oslo for is_uuid_like() implementation +* Synchronize code from oslo +* Migrate to pbr +* Cleanup nova subcommands for security groups and rules +* Make ManagerWithFind abstract and fix its descendants +* Cleanup some flavor commands +* Fix the default parameter in print_list +* Fix for --bridge-interface being ignore by nova network-create +* Add setuptools_git-*.egg to .gitignore +* Expose retry_after attribute of OverLimit exception +* Adds extended status fields to nova list +* Clean up exceptions.from_response +* Allow deleting multiple images from shell +* Synchronize code from oslo +* Add 'flavor-list --all' admin switch +* Fix nova instance-action-list output field and order +* Make list flavor show extra specs optional +* Use HTTP keep-alive feature in HTTPClient class +* Cleanup unused import +* Make --vlan option work in network-create in VLAN mode +* Support force update quota +* make sure .get() also updates _info +* Add coverage-reset command to reset Nova coverage data +* Fixing shell command 'service-disable' description +* Correct a unit test failure that crept into trunk +* Fix problem with nova --version +* Make "multi_host" True when it is set to 'T' in network_create +* Fix IBM copyright strings +* Allow for bypass_url when using proxy_token + +2.13.0 +------ + +* Fix mispelt x-auth-token header +* Remove actions command from servers +* do not ignore --os-cache +* Improve authentication plugins management +* Skip security groups w/ no protocol +* catch NoKeyringDaemonError from gnomekeyring +* Ensure shell tests use isolated env variables set +* Update to latest openstack.common.setup +* setuptools: remove data_files section +* Use correct filter name for listing of instances + +2.12.0 +------ + +* Don't check build/ for pep8 violations +* Add support for retrieving instance-actions info +* Split commands properly for bash completion test +* Remove extraneous output during testing +* Use setuptools-git to include files from the repo +* Update tools/pip-requires for prettytable +* Fix keypair-delete help documents +* Add support for the new fixed_ip quota +* Set up debug level on root logger +* Remove unused import +* Fix Copyright Headers from LLC to Foundation +* Removes tenant IDs checking for nova quota operations +* Make os-services API extensions consistent with Nova +* Revert API changes in "Unify Manager._update behaviour" +* Use keyring for testing +* Show Tenant_ID for secgroup-list with all-tenant +* Additional "Unify Manager._update behaviour" cleanup +* Add wrap option to nova credentials for humans +* Check if tenant flag is uuid_like for all quota operations +* Fix nova boot --num-instances option checking +* Fix typo in error message +* Extend test coverage for v1_1/shell.py +* Decodes input and encodes output +* Fixed bug with password prompt, added tests +* Make ip_protocol parameter in security groups rules case insensitive +* Fixes the output of 'os-evacuate' command +* Update the docstring of cloudpipe-configure command +* Accept 201 status code on POST +* Fix how tests were failing due to missing attributes +* Missing import for gnomekeyring +* A minimum of Python3 fixes so that installation works without errors/warnings +* Allows admins to reset-network of an instance +* Remove prov_vlan_id from baremetal +* Add support for os-attach-interfaces +* Added limit to image-list in a preparatory step toward addressing bug 1001345 +* Extend test coverage (shell, fping) + +2.11.1 +------ + +* Issue when gnomekeyring is present but not the current backend +* Avoid doing a deep copy on the availability zone manager +* Allow extensions to provide a name when discovered on the python path +* Fix IOError with gnomekeyring.find_network_password_sync +* Expand and improve baremetal API +* Fix nova availability-zone-list for admin users +* Make availability_zone in aggregate_create optional +* Corrects 2nd argument type for logging + +2.11.0 +------ + +* Add format options to 'nova coverage-report' +* Update to requests >= 0.8 +* Mask permissions on private key files +* Fix run_tests.sh --coverage +* Support showing extra fields in server list +* management_url not set by authenticate method +* Update .coveragerc +* Show the summary or details of all availability zones of a region +* Upgrade to pep8 1.3.3 +* Fixed 7 pep8 errors +* Live migration with an auto selection of dest +* Add help about the id 'auto' for flavor-create +* Fix default format of 'nova coverage-report' +* Add usage command to show usage for single tenant +* Store tenant_id from keystone and use for quotas +* Show the details of the added bare-metal resource +* Fix the usage of password, keyrings, and tokens +* Added homedir path expansion for keypair-add +* Migrate from nose to testr +* _get_secgroup returns first group even if multiple groups match +* Fix bash completion on osx +* Check tenant_id's format in "nova quota-update" +* ClientExceptions should include url and method +* Adds baremetal nova API support +* RateLimit does not have method attribute +* make print_dict split strings with newlines into multiple rows +* Allow for image selection using the metadata properties +* Add support for get_spice_console RPC API +* Ensure list output function can support non-sorting printing +* Allow request timeout to be specified +* Implement get password for novaclient +* Adds tenant network support to the client +* Update functionality of coverage extension +* Fix a couple of broken shell tests +* Update hosts API action calls (startup etc.) +* When logging request include request data +* Add support for instance evacuate +* Fix the help text of add-fixed-ip +* Move from untitest2 to testtools +* Update README.rst +* Unify Manager._update behaviour +* Fix some usage messages of 'nova volume-*' +* add num_instances option for nova boot +* Use requests module for HTTP/HTTPS +* Fix find for alphanumeic flavor id/name +* Make --tenant a required arg for quota-show +* Add support for the coverage extension +* Specify some arguments by name +* Makes the OS_NO_CACHE env variable work again +* Add optional argument to include reservations in os-used-limits +* Add nova client support for nova-manage agent command +* Adds --os-cache to replace old --no-cache +* Adds support for security group/rules quotas +* Adds nova client support for nova-manage network command +* add host-update help info param +* Fix argument checking method for 'nova list --flavor' command +* Fix a wrong substition for '-h' in bash completion +* Fixed nics param ignored when bdm is specified +* Adds support for key_pairs quota +* Adds support for injected_file_path_bytes quota +* Adds nova client support for nova-manage floating command + +2.10.0 +------ + +* Remove unnecessary casts in flavor create +* Validate that rxtx_factor is a float +* Adds nova client support for nova-manage vpn command +* Fix aggregate command help messages +* Add nova client support for nova-manage account scrub command +* Adds nova client support for nova-manage fixed command +* Implement fping calls in nova client +* Expand help message for 'migrate' to explain how the new host is selected +* Improved quota output +* Boot from volume without image supplied +* Added --extra-opts to the nova ssh command +* Cleans up the flavor creation code. Fixes bug 1080891 +* Adding support to filter instances by tenant from the admin api +* Make sure create_image returns result +* make tenant id optional for quota-defaults and quota-show +* fix hypervisor-servers for hypervisors without servers +* discover extensions via entry points +* show help when calling without arguments +* Add nova client support for nova-manage service command +* Updated the help text for nova list command +* Fixes setup compatibility issue on Windows +* include projectid in the cache key +* Fixes utils.findresource checking for integer +* Allows deletion of multiple servers through CLI +* Add ability of nova client to display availability zones when listing hosts +* Validate that boolean parameters are boolean +* Auto-Assign Flavor ID +* Pull in latest openstack-common changes and fix a minor PEP8 issue +* Add OpenStack trove classifier for PyPI +* Exception handling for 'nova flavor-create' arguments +* Add support for backup instance +* Add simple os-api extension cli extension +* Raises Exception on improper Auth Configuration +* Do not prefer ALL_TENANTS environment variable to command line arguments +* Encode user data to utf-8 when creating a server +* Add --all-tenants option to volume-list + +2.9.0 +----- + +* Show volume and snapshot data on create +* Fixes setup compatibility issue on Windows +* allow empty network list to be requested +* Work around httplib2 tunnelling bug +* Add support for all-tenants search opt to secgroup-list +* expose os-networks extension to CLI +* Add support for Unicode secgroup names +* Support flavor extra specs in nova client +* Optionally faster 'nova show' +* Makes handling of nic args more robust +* Show instances built from deleted snapshots +* Add ConnectionRefused exception + +2.8.0 +----- + +* Fix usage-list date range to use UTC time +* Show POST in debug with curl +* Fixes doc string and string formatting +* Add the image_id arg to volume create +* Make region case insensitive +* Fix PEP8 issues +* Add -X to DELETE and PUT in debug mode +* Implement project specific flavors API, client bindings +* Add missing port-id usage info +* Change '_' to '-' in options +* Adding --version option +* Added -nic port-id= support +* Implement network calls in nova client +* Add nosehtmloutput as a test dependency +* split req and response logging this allows capture of timestamps prior to and after request for timing also did some pep8 1.3 cleanup while I was in there +* Add availability_zone support for volume creation +* Adds support for autogenerated device on attach +* Allow resources to use any field as 'name' +* gitignore ChangeLog and add to MANIFEST.in +* Allow different auth providers via plugin system +* Better handling of stale tokens (no more 401's) +* change image list and network list data to be sorted by name rather than UUID +* Relex prettytable depend to match glanceclient + +2.7.0 +----- + +* Add call to get hypervisor statistics +* Fix image-create --poll race-condition +* set admin password during instance creation +* Clarify usage of --insecure flag +* Fix resize polling +* Add support for modification of instance Security Group +* Add support for hypervisor-uptime +* Install test-requires in development venv +* 'endpoints' and 'credentials' work with token caching +* This should fix a problem with overly aggressive token caching +* Flavor-list sort by ID numerically +* Bring back the output from client.http_log() + +2.6.10 +------ + +* Add hypervisor information extension +* More friendly keyring support when token caching is off +* Whoops, the last changes to keyring introduced some problems with v1.1 auth tests +* Auth token caching on by default. --no_cache to disable. Better bypass support too +* Add host-list command +* Indicate unused variables and other misc. house cleaning +* don't bash-complete the '-h' option +* Add read_versioninfo method +* Turn multiple hints with the same key into a list +* Cleanup of setup.py usage of openstack-common +* Implement post-tag versioning numbering +* Small doc cleanup round +* Update Contributing blurb in the docs +* Update for blueprint general-host-aggregates + +2.6.1 +----- + +* Admin action to reset states +* Filter out v1.0 endpoints +* option to bypass managment endpoint and timings support +* Removes NOVACLIENT_DEBUG from client code +* Fix spelling errors in aggregates section +* Move docs to doc +* Lock prettytable dep at v0.6 +* Removed generate_authors.sh since it's no longer used +* nova show cmd displays unique flavor and image id +* Use openstack-common for AUTHORS generation +* Add .tox to .gitignore +* Add start and stop to server actions +* Adds flavor-show support +* doc: fix and clarify the --meta option help +* Lock pep8 at v1.1 +* Turn on verbose test output + +folsom-1 +-------- + +* Align tox.ini with standards +* make nova bash-complete faster and more accurate +* refactored --service_name to only work with compute calls and added --volume_service_name for volume calls +* removed int requirement for volume_id on snaps +* Updated to new prettytable api. Fixes bug 995818 +* Allow server name to be specified for actions and diagnostics +* Don't force volume id to int and allow search by name +* Fix LP #990667 - Keypair __repr__ referencesuuid +* really output the description of an exception +* Limit hint/nic parsing to one split on '=' +* update README.rst,add args "service_type" when getting endpoints +* Rename NOVA_VERSION to OS_COMPUTE_API_VERSION +* Raise exception on all 4xx and 5xx responses +* Update unittests to be Python 2.6 compatible +* Display the request id on error response +* Make '--help' argument more useful +* Fixed the subcommand error message for nova shell +* Request ID when name is ambiguous +* Set resources as loaded on get +* Miscellaneous code cleanup +* add packages using find_packages() +* set 'compute' as default endpoint bug fix for #970808 +* Add -i/--identity option to 'nova ssh' +* Improve 'nova ssh' error message +* Fix spelling of curent in list sec groups +* Set up the log handler only once +* Remove serverId lookup in volume attachments +* Handle server_id and serverId in volume list +* Added cloudpipe support. Fixes bug 962286 +* Proposed HACKING guidelines for string encoding +* Add missing tools and tox.ini to tarball +* Fixes bug #959262 - Prevent a failure to create the cache directory from causing an exception +* Improve the error message from the nova shell +* Adds NOVACLIENT_INSECURE option +* Implement quota classes +* Open Folsom + +essex-rc1 +--------- + +* Adding Console Log to CLI +* Change CLIAuth arg names +* Add suport for instance locking/unlocking +* Add --poll for instance snapshots +* Add human-friendly ID support +* Fixes lp#948685 proxy_token and proxy_tenant_id behavior +* Separate UUID caches for different endpoints +* Remove trailing whitespaces in regular file +* Adds --ipv6 and --port to ssh convience command +* Add --poll for long running actions + +essex-4 +------- + +* Add support for volume types +* Makes novaclient use the volumes endpoint +* Fix for backward compatibility with stable/diablo flavors +* Add support for ephemeral_gb to novaclient +* allow '=' inside value of --meta=key=value +* bug 932408: python-novaclient miss OSAPI host operations +* Add ssh convenience command +* Allow UUID_CACHE_DIR overriding via env variable +* Removes zones +* Fixes bug 925644: move dotfiles into dir +* add support for --config-drive 'boot' command +* shell: Hook --debug up to more stuff +* Properly handle KeyErrors +* adding credentials and endpoints output for debugging +* Fixes bug 924588: Remove proto-keystone client from novaclient +* Fix bug 904364: Consistiently handle trailing '/' on URLs +* Adding describe-resource subcommand +* Add Accept: applicaton/json header to all service requests. Fixes bug 904436 +* Blueprint cli-auth: common cli args +* Add --all_tenants option to 'nova list' +* Adding live migration subcommand +* Handle Ambiguous Endpoints Correctly +* Implementing Scheduling Hints +* Remove non-working --key_path argument on boot +* Fix datetime issue with usage_data +* blueprint host-aggregates: client bindings +* moves the "help" in the usage information of a wrong command to the correct position + +essex-3 +------- + +* Implementing client for new x509 support in nova +* Add flavor create/delete support +* Add a 'usage' module and 'usage-list' cli command +* Implement virtual interfaces servers api +* Print adminPass when rescuing an instance +* do not require NOVA_VERSION in env, default to 1.1 +* Match create_image on server object and manager +* Catch novaclient up with renaming and other nova changes +* Add server.get_vnc_console functionality to python-novaclient +* Fix bad api call, 'migrate' is an action +* Adding rebuild/resize hooks +* Implementing Floating Ip Pools +* Get ImpLoader from ImpImporter for Py2.6 +* Discover extensions via Python's import paths +* PEP8 python-novaclient cleanup +* show 409 responses +* Added command-line interfaces for the floating ip DNS api to nova +* Fix Quota ant SecurityGroup resources refreshing +* Clean FloatingIPDNS resource +* Install a good version of pip in the venv +* Add tox.ini file +* Add missing returns and remove superfluous ones +* Fix typo in endpoint_name help string +* Add the python api for floating IP DNS +* Abstract Client building into novaclient.client +* Remove unused imports and fix NameError on exc +* Improve the test framework to handle urls with args +* Simplifying get_console_output client interface +* Removing cache-busting query param (fresh) +* Adding return statement to get_console_output +* python-novaclient missing pep8 in pip-requires +* utils.find_resource fixes + fix for volumes +* Add list() method to ManagerWithFind +* Extensions can now modify resources +* more work towards standardize config +* Allow to not specify image if block_device_mapping is set +* Adding support for the os-getConsoleOutput server action +* Add 'discover' command for Keystone discovery and version listing +* User friendly help message +* Do no depends on argparse for Python >= 2.7 +* standardize environmental settings for cli auth +* Removed v1.0 support +* Making contrib a Python package +* Adding extension framework +* Fix typo in README +* Accept 1 and 2 as version choices +* Add support for RAX authentication +* Align run_tests.sh with nova + +essex-2 +------- + +* Switch versioning to common Nova versioning +* Fix PEP8 error +* Add MANIFEST.in and setup.cfg back +* Adding 'absolute-limits' and 'rate-limits' +* Fixing all remaining pep8 errors +* Clean up image-list cli command +* Clean up image-show +* Updated README.rst +* Converting rxtx_cap and rxtx_quota to rxtx_factor +* Gracefully handle failure to cache UUID's. Bug #897885 +* Change 'zone_blob' key to 'blob' in create server. bug 893183 +* Fix spacing errors in authentication exceptions +* Adding UUID cache for bash autocompletion +* Revert api_key change in novaclient Client argument +* Adds bash completion support and cleans up setup.py +* Rewriting admin-only calls as server actions +* Add rfc.sh +* Add .gitreview config file for gerrit +* pep8 +* fix tests +* trunk merge +* Add support for specifying VIF networks while booting +* Use a try/finally to ensure state restoration +* Follow redirects when calling out to Keystone +* Modified as per code-review comments: - Renaned snapshot to volume-snapshot - Created a new file for volume snapshots +* few missing references to api_key +* tests working +* started +* added --endpoint_name support +* Add back display of adminPass to boot +* Boot now works with limited info returned from server +* fixed missing line continuation characters in shell.py +* PEP8 cleanups of utils, and the v1_?/shell.py files +* minor pep8 tweaks +* corrected argument order and replaced tabs with spaces +* resolved merge conflict +* added a space after url +* Added the option --insecure. This disables SSL certificate validation +* Updated the novaclient shell to display the parent server id that the image came from +* Fixed description for block_device_mapping parameter +* minor fixes +* Added support for boot from volume (or snapshot) +* version update +* minor tweaks and long overdue pep8 +* new service catalog semantics +* Added support for listing/creating/deleting snapshots of nova volumes. Also implemented the supporting CLI commands. Requires the OS API extension, 'os-snapshots' +* Updated volume-create command to accept an optional attribute, snapshot_id. This enables the user to create a volume from a snapshot +* Fixes #133 -- Keystone Client fetches correct service type and endpoint +* fix tests +* typo +* merged and fixed pshkitin's keypair work +* doc improvements +* Added support to specify more boot options +* Updated volume attach/detach commands to accept server name (in addition to server id). Code review comments: https://github.com/rackspace/python-novaclient/pull/125/files#r169829 +* Booting server with specific key is implemented +* Added commands to work with keypairs +* make description consistent +* remove extra space +* add ability to create source group rules +* don't expose ids to end user +* work on formatting for secgroup rules +* display floating ip on create +* Add CLI for security groups and rules +* raise exception if floating_ip is not found in floating-ip-delete +* Add cli for floating ips +* Added support to specify more boot options +* Don't filter endpoints when filter_value is non-truthy +* Added the following CLI commands to access nova volumes: volume-attach Attach a volume to a server. volume-create Add a new volume. volume-delete Remove a volume. volume-detach Detach a volume from a server. volume-list List all the volumes. volume-show Show details about a volume +* now uses tenantName vs. tenantId to auth +* version bump +* removed unicode casts +* cleaned up exception handling +* new service catalog implementation +* change auth cred format for keystone +* Added methods to get, attach and detach volumes to/from running instances +* Added support to access nova-volume api (v1.1 extension) - Only the basic functionality (create, delete, list) is implemented +* add todo to update doc strings so that they reflect extension/optional-ness +* update doc strings +* add key_name to servers.create +* Make sure flavor is a type of int +* removed debugging +* token support +* fixed unknown service +* properly uses keystone admin endpoint for token lookup +* proxy token support - no tests +* readme fix +* service catalog with multiple endpoints per service +* Add ability to force debugging via os environ +* merge fixup +* version bump +* readme +* service catalog as auth parameter +* service name support +* Extend lazy loading support to Weighting +* Fix unittests breakage in test_shell +* Fix #109 (nova show name not working) +* Add userdata support +* Remove extra NOVA_PROJECT_ID +* Fix unittests breakage from merge 3507905 +* Add 'meta' command to allow set/delete of metadata items on servers. Added ability to run multiple assert_called tests from one test function +* add build, dist, python-novaclient.egg-info to .gitignore +* fixes odd __get_attr__ behavior in 2.6.5 +* conflict fixed +* catch misssing id +* Add body in debugging +* Fix test installation exclude +* Add support for image metadata to be viewed, added, updated, and deleted +* Bump the release version +* fixed up zone-add +* Reducing v1_1.base to just booting manager +* tests working +* in progress - adding zone name +* ensure we have auth_url and project_id for !1.0 +* Updated error message as suggested by bcwaldon +* take auth token param +* Do not assume default for image and flavor +* expanding on concept of 'loaded' +* limiting resource lazyloading to a single query +* Fix extra # char as noticed by jk0 +* Add piston service_catalog +* Add anotherjesse keystone here +* Fix loop properly +* Make sure we can do a get on the base class +* Client changes for username and password in zone add +* fix for chmouel's comment, and tweaks to tests +* support for floating_ips + D4 +* make __repr__ more useful with default behavior, rather than juse displaying id +* a few tweaks to get the client talking to nova +* more cleanup +* progress on security groups +* updating version +* updating for new rebuild format +* adding tests +* cleaning up find_resource method to support str/int ids, uuids, and integer-like names +* Fix #85 +* fixing the shell tests +* Fixed 1.0 and unit tests +* Added support for 1.0 and added unit tests +* Updated rescue/unrescue to use public API +* removing extra space +* updating quotas and tests with the format which recently landed in nova +* fixing up a few pep8 issues, and pointing client to the new endpoint +* Properly make image_id a requirement to be int +* Make sure the image id is an integer +* really fixed +* accidentally deleted a comment when fixing conflict +* pep8 issues +* update readme to talk about keystone with CLI and use 1.1 api +* Switch API path to match http://bazaar.launchpad.net/~tpatil/nova/os-security-groups/revision/1369 +* Fix API path +* fix display_name references that should have been instance_name +* removed fixed_ip from v1.1 shell. Use --ip instead. Fixed up rest of other search options from last commit +* start add of --image, --flavor, --status, and --host options to 'list' command. also fix up differences with --name and --display_name compared to how nova implementation turned out +* Security groups cleanups +* Added redirect tests, changed wrong status in test_authenticate_success +* Added self.auth_url updating, WrongResponse exception +* add note about keystone / auth 2.0 +* Clean up id handling and pass basic tests +* Add security group rules +* Eradicate TABs, make tests run +* missed a conflict +* merge master +* Initial security groups code +* adding unittest +* removing extra newline +* adding email to .mailmap +* catching authorization failure (x-server-management-url KeyError) +* bring up-to-date with lp:~cloudbuilders/nova/os-keypairs +* keypair api +* add license headers +* add support for quotas +* pep8, again +* Recursion handling +* Added .mailmap file for AUTHORS +* Updated authors and fixed tools/generate_authors.sh +* Fixes copyright notice and adds script to gen AUTHORS +* keypair api +* pep8 +* Status code 305 fix, ClientExceptions if we can not handle response +* whitespace cleanups +* pep8 cleanups after the rebase +* Adds run_tests.sh and virtualenv support +* pep8 in tests +* pep8 in novaclient +* Add Hacking and Authors to bring this into accordance with OpenStack coding standards +* redirect +* Redirection handling +* cleaning up boot output; upping version +* Added documentation for NOVA_VERSION +* Make it possible to authenticate against keystone +* Removed the bodies again +* Corrected docs +* off by one +* Missed a conflict + +2.6.0 +----- + +* manual merge +* Accidently had a reference to ipgroup still +* Merged v1.0 functionality into v1.1 so we don't lose any features by...upgrading? +* Fix for failing tests because boot response now requests additional information +* formatting updates +* novaclient -> nova in some documentation as per feedback +* Removed unneeded print +* Change create-image back to image-create, and increased version to 2.6.0 +* Updated --version to default to NOVA_VERSION, quick fix +* Updated --version to default to NOVA_VERSION +* osc -> novaclient +* Cleaned up v1.0 and v1.1 test setup to remove globals and encapsulate custom asserts. Still duplicate code, but closer to being able to remove. Now tests set up OpenStackClient much closer to how users will do it, minus the stubbing of the client +* Wrong client was getting loaded +* Grrrr, bad import +* Tests now run correctly for v1.1 and v1.0 +* Updated the default version back to 1.0, as there are some quirks with 1.1 +* Tests working again...merged in some work we did earlier +* Split everything down the middle into v1_0 and v1_1, including tests +* bumping version and updating README +* updating server backup action; pep8 fixes +* removed server dump after add/remove fixed-ip +* version bump +* fixed public private ip list +* added various search options to list command. will need a version bump as i changed the 'list' api that nova uses. after version bump, my search nova branch will need pip-requires updated to match +* docs +* added add/remove fixed_ip actions to servers +* Clarify description so usage doesn't imply name is the only valid value +* Added support for request timeouts +* Added migration functionality +* Refactored backup rotation +* Review feedback +* Fixed unit tests +* Implemented backup with rotation +* for creating 'x' instances, min_count > max_count check was reversed make max/min_instances a little more sane by making them 'int' types fix issue where only specifying --min_instances didn't work +* Due to how novaclient works, it tends to do a 'get' first on whatever ID you pass on command line. Then it does the real command, re-using the ID found in the 'get' call, instead of the initial ID that you specified (which may have been a UUID) +* Cleaned up the query_string generation for 'nova list' Made --recurse_zones not need an '=argument' +* Added --recurse_zones option to 'list' Added --fixed_ip option to 'list' to find a particular instance by IP Fixed issue with 'show' when --recurse_zones=1 and specifying UUID +* fixup +* release note update +* tests working again for weight_scale/weight_offset +* fixed up tests after trunk merge and bumped version +* version bump +* fixed project_id tests +* Merged my 'create-num-instances' branch which adds support for --min_instances and --max_instances to zone-boot +* version bumped +* trunk merge +* Typo fix +* Added the missing files +* Added a method to create instances on behalf of an account via the admin API methods for openstack +* changed docs about using project id +* bumped version # after project_id update +* Don't restrict ids to int +* fix errors +* support for project id header +* Now that I understand how to build extensions, I understand how this extension will be built, and can fully implement add_fixed_ip() and remove_fixed_ip() +* Add the basic calls for add_fixed_ip/remove_fixed_ip +* defaults back to no detail +* tweaks +* griddynamics better logging +* reservation_id optional parameter added to GET /servers (aka 'list') +* works properly with zone-boot +* Improving tests +* Added parameter detailed to list +* zone select support and version bump to 2.4.3 +* fix to reviewer comment: add check if logging disabled +* improve perfomance on string concat in logging +* add logging for http request-response +* zone select +* add undetailed flavor list +* zone_blob support added to server.create +* fixed flavor-list columns +* added support for missing flavors/images +* up'ed version to suit pypi distribution update +* fixed software license +* version 2.4 +* Added Jacob Kaplan-Moss copyright notices on older/untouched files +* renamed to novaclient and fixed flavor tests +* missing docstring quote +* tweaked release notes +* removed copyright/license notices from files not significantly changed +* renamed cmdline tool from novatools to nova. Changed version to 2.1. Changed license to Apache. Added copyright notices. Cleaner exception reporting in non-debug scnario +* fixed setup +* longer zone list +* Added full flavor detail support +* zone info works +* get this zone status +* removed Username from zone info +* NOVA_TOOLS_* -> NOVA_*, --debug +* removed zone name, renamed auth_url to api_url, added username/password +* zone shell cmds & tests added +* zone tests pass +* zone tests pass +* tests pass again +* zones +* Renamed all CloudServers to OpenStack and python-cloudservers to python-novatools +* installer fixup +* README update and rename cloudservers to novatools +* Starting on child zone support +* Initial commit from fork diff -Nru python-novaclient-2.15.0/debian/changelog python-novaclient-2.16.0/debian/changelog --- python-novaclient-2.15.0/debian/changelog 2014-02-23 13:52:30.000000000 +0000 +++ python-novaclient-2.16.0/debian/changelog 2014-03-06 20:33:00.000000000 +0000 @@ -1,8 +1,9 @@ -python-novaclient (1:2.15.0-0ubuntu2) trusty; urgency=medium +python-novaclient (1:2.16.0-0ubuntu1) trusty; urgency=low - * Rebuild to drop files installed into /usr/share/pyshared. + * New upstream release. + * debian/control: open icehouse release. - -- Matthias Klose Sun, 23 Feb 2014 13:52:30 +0000 + -- Chuck Short Thu, 06 Mar 2014 15:32:34 -0500 python-novaclient (1:2.15.0-0ubuntu1) saucy; urgency=low diff -Nru python-novaclient-2.15.0/debian/control python-novaclient-2.16.0/debian/control --- python-novaclient-2.15.0/debian/control 2013-09-24 18:57:01.000000000 +0000 +++ python-novaclient-2.16.0/debian/control 2014-03-06 20:33:00.000000000 +0000 @@ -3,39 +3,39 @@ Priority: optional Maintainer: Ubuntu Developers Build-Depends: debhelper (>= 7.0.50), - python-all (>= 2.6), - python-babel (>= 0.9.6), - python-d2to1, - python-distribute, - python-fixtures (>= 0.3.12), - python-keyring, - python-iso8601, - python-mock (>= 0.7), - python-pbr (>= 0.5.21), - python-prettytable (>= 0.6), - python-requests (>= 1.1), - python-setuptools, - python-six, - python-simplejson (>= 2.0.9), - python-testtools (>= 0.9.32), - testrepository (>= 0.0.17) + python-all (>= 2.6), + python-babel (>= 0.9.6), + python-d2to1, + python-distribute, + python-fixtures (>= 0.3.12), + python-keyring, + python-iso8601, + python-mock (>= 0.7), + python-pbr (>= 0.5.21), + python-prettytable (>= 0.6), + python-requests (>= 1.1), + python-setuptools, + python-six, + python-simplejson (>= 2.0.9), + python-testtools (>= 0.9.32), + testrepository (>= 0.0.17) X-Python-Version: >= 2.7 Standards-Version: 3.9.3 -Vcs-Browser: http://bazaar.launchpad.net/~ubuntu-server-dev/python-novaclient/havana/files -Vcs-Bzr: https://code.launchpad.net/~ubuntu-server-dev/python-novaclient/havana +Vcs-Browser: http://bazaar.launchpad.net/~ubuntu-server-dev/python-novaclient/icehouse/files +Vcs-Bzr: https://code.launchpad.net/~ubuntu-server-dev/python-novaclient/icehouse XS-Testsuite: autopkgtest Package: python-novaclient Architecture: all Depends: python-iso8601, - python-pkg-resources, - python-prettytable (>= 0.6), - python-requests (>= 1.1), - python-simplejson (>= 2.0.9), - python-six, - python-babel (>= 0.9.6), - ${misc:Depends}, - ${python:Depends} + python-pkg-resources, + python-prettytable (>= 0.6), + python-requests (>= 1.1), + python-simplejson (>= 2.0.9), + python-six, + python-babel (>= 0.9.6), + ${misc:Depends}, + ${python:Depends} XB-Python-Version: ${python:Versions} Description: client library for OpenStack Compute API Python novaclient library and nova CLI tool for interacting with OpenStack diff -Nru python-novaclient-2.15.0/doc/.gitignore python-novaclient-2.16.0/doc/.gitignore --- python-novaclient-2.15.0/doc/.gitignore 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/doc/.gitignore 2014-02-26 16:28:51.000000000 +0000 @@ -1 +1,2 @@ build/ +source/ref/ diff -Nru python-novaclient-2.15.0/doc/source/api.rst python-novaclient-2.16.0/doc/source/api.rst --- python-novaclient-2.15.0/doc/source/api.rst 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/doc/source/api.rst 2014-02-26 16:28:51.000000000 +0000 @@ -9,39 +9,14 @@ Usage ----- -First create an instance of :class:`OpenStack` with your credentials:: +First create a client instance with your credentials:: - >>> from novaclient import OpenStack - >>> nova = OpenStack(USERNAME, PASSWORD, AUTH_URL) + >>> from novaclient.client import Client + >>> nova = Client(VERSION, USERNAME, PASSWORD, PROJECT_ID, AUTH_URL) -Then call methods on the :class:`OpenStack` object: +Here ``VERSION`` can be: ``1.1``, ``2`` and ``3``. -.. class:: OpenStack - - .. attribute:: backup_schedules - - A :class:`BackupScheduleManager` -- manage automatic backup images. - - .. attribute:: flavors - - A :class:`FlavorManager` -- query available "flavors" (hardware - configurations). - - .. attribute:: images - - An :class:`ImageManager` -- query and create server disk images. - - .. attribute:: ipgroups - - A :class:`IPGroupManager` -- manage shared public IP addresses. - - .. attribute:: servers - - A :class:`ServerManager` -- start, stop, and manage virtual machines. - - .. automethod:: authenticate - -For example:: +Then call methods on its managers:: >>> nova.servers.list() [] @@ -59,9 +34,14 @@ >>> nova.servers.create("my-server", flavor=fl) +Reference +--------- + For more information, see the reference: .. toctree:: :maxdepth: 2 ref/index + ref/v1_1/index + ref/v3/index diff -Nru python-novaclient-2.15.0/doc/source/conf.py python-novaclient-2.16.0/doc/source/conf.py --- python-novaclient-2.15.0/doc/source/conf.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/doc/source/conf.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,4 +1,15 @@ # -*- coding: utf-8 -*- +# 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. # # python-novaclient documentation build configuration file, created by # sphinx-quickstart on Sun Dec 6 14:19:25 2009. @@ -18,6 +29,59 @@ # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.append(os.path.abspath('.')) +import os + +BASE_DIR = os.path.dirname(os.path.abspath(__file__)) +ROOT = os.path.abspath(os.path.join(BASE_DIR, "..", "..")) + +sys.path.insert(0, ROOT) +sys.path.insert(0, BASE_DIR) + + +def gen_ref(ver, title, names): + refdir = os.path.join(BASE_DIR, "ref") + pkg = "novaclient" + if ver: + pkg = "%s.%s" % (pkg, ver) + refdir = os.path.join(refdir, ver) + if not os.path.exists(refdir): + os.makedirs(refdir) + idxpath = os.path.join(refdir, "index.rst") + with open(idxpath, "w") as idx: + idx.write(("%(title)s\n" + "%(signs)s\n" + "\n" + ".. toctree::\n" + " :maxdepth: 1\n" + "\n") % {"title": title, "signs": "=" * len(title)}) + for name in names: + idx.write(" %s\n" % name) + rstpath = os.path.join(refdir, "%s.rst" % name) + with open(rstpath, "w") as rst: + rst.write(("%(title)s\n" + "%(signs)s\n" + "\n" + ".. automodule:: %(pkg)s.%(name)s\n" + " :members:\n" + " :undoc-members:\n" + " :show-inheritance:\n" + " :noindex:\n") + % {"title": name.capitalize(), + "signs": "=" * len(name), + "pkg": pkg, "name": name}) + +gen_ref(None, "Exceptions", ["exceptions"]) +gen_ref("v1_1", "Version 1.1, Version 2 API Reference", + ["flavors", "images", "servers", "hosts", "agents", "aggregates", + "availability_zones", "certs", "fixed_ips", "floating_ip_pools", + "floating_ips", "hypervisors", "keypairs", "limits", "networks", + "quota_classes", "quotas", "security_group_rules", + "security_groups", "services", "virtual_interfaces", + "volume_snapshots", "volumes", "volume_types"]) +gen_ref("v3", "Version 3 API Reference", + ["flavors", "hosts", "agents", "aggregates", "availability_zones", + "certs", "hypervisors", "images", "keypairs", "quotas", + "quotas_classes", "servers", "services"]) # -- General configuration ---------------------------------------------------- @@ -130,7 +194,7 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +# html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. diff -Nru python-novaclient-2.15.0/doc/source/index.rst python-novaclient-2.16.0/doc/source/index.rst --- python-novaclient-2.15.0/doc/source/index.rst 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/doc/source/index.rst 2014-02-26 16:28:51.000000000 +0000 @@ -25,16 +25,18 @@ shell api ref/index + ref/v1_1/index + ref/v3/index releases Contributing ============ -Code is hosted `on GitHub`_. Submit bugs to the Nova project on +Code is hosted at `git.openstack.org`_. Submit bugs to the Nova project on `Launchpad`_. Submit code to the openstack/python-novaclient project using `Gerrit`_. -.. _on GitHub: https://github.com/openstack/python-novaclient +.. _git.openstack.org: https://git.openstack.org/cgit/openstack/python-novaclient .. _Launchpad: https://launchpad.net/nova .. _Gerrit: http://wiki.openstack.org/GerritWorkflow diff -Nru python-novaclient-2.15.0/doc/source/man/nova.rst python-novaclient-2.16.0/doc/source/man/nova.rst --- python-novaclient-2.15.0/doc/source/man/nova.rst 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/doc/source/man/nova.rst 2014-02-26 16:28:51.000000000 +0000 @@ -76,7 +76,7 @@ SEE ALSO ======== -OpenStack Nova CLI Guide: http://docs.openstack.org/cli/quick-start/content/nova-cli-reference.html +OpenStack Nova CLI Guide: http://docs.openstack.org/cli-reference/content/novaclient_commands.html BUGS diff -Nru python-novaclient-2.15.0/doc/source/ref/backup_schedules.rst python-novaclient-2.16.0/doc/source/ref/backup_schedules.rst --- python-novaclient-2.15.0/doc/source/ref/backup_schedules.rst 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/doc/source/ref/backup_schedules.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,60 +0,0 @@ -Backup schedules -================ - -.. currentmodule:: novaclient - -Rackspace allows scheduling of weekly and/or daily backups for virtual -servers. You can access these backup schedules either off the API object as -:attr:`OpenStack.backup_schedules`, or directly off a particular -:class:`Server` instance as :attr:`Server.backup_schedule`. - -Classes -------- - -.. autoclass:: BackupScheduleManager - :members: create, delete, update, get - -.. autoclass:: BackupSchedule - :members: update, delete - - .. attribute:: enabled - - Is this backup enabled? (boolean) - - .. attribute:: weekly - - The day of week upon which to perform a weekly backup. - - .. attribute:: daily - - The daily time period during which to perform a daily backup. - -Constants ---------- - -Constants for selecting weekly backup days: - - .. data:: BACKUP_WEEKLY_DISABLED - .. data:: BACKUP_WEEKLY_SUNDAY - .. data:: BACKUP_WEEKLY_MONDAY - .. data:: BACKUP_WEEKLY_TUESDAY - .. data:: BACKUP_WEEKLY_WEDNESDA - .. data:: BACKUP_WEEKLY_THURSDAY - .. data:: BACKUP_WEEKLY_FRIDAY - .. data:: BACKUP_WEEKLY_SATURDAY - -Constants for selecting hourly backup windows: - - .. data:: BACKUP_DAILY_DISABLED - .. data:: BACKUP_DAILY_H_0000_0200 - .. data:: BACKUP_DAILY_H_0200_0400 - .. data:: BACKUP_DAILY_H_0400_0600 - .. data:: BACKUP_DAILY_H_0600_0800 - .. data:: BACKUP_DAILY_H_0800_1000 - .. data:: BACKUP_DAILY_H_1000_1200 - .. data:: BACKUP_DAILY_H_1200_1400 - .. data:: BACKUP_DAILY_H_1400_1600 - .. data:: BACKUP_DAILY_H_1600_1800 - .. data:: BACKUP_DAILY_H_1800_2000 - .. data:: BACKUP_DAILY_H_2000_2200 - .. data:: BACKUP_DAILY_H_2200_0000 diff -Nru python-novaclient-2.15.0/doc/source/ref/exceptions.rst python-novaclient-2.16.0/doc/source/ref/exceptions.rst --- python-novaclient-2.15.0/doc/source/ref/exceptions.rst 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/doc/source/ref/exceptions.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -Exceptions -========== - -.. currentmodule:: novaclient - -Exceptions ----------- - -Exceptions that the API might throw: - -.. automodule:: novaclient - :members: OpenStackException, BadRequest, Unauthorized, Forbidden, - NotFound, OverLimit - diff -Nru python-novaclient-2.15.0/doc/source/ref/flavors.rst python-novaclient-2.16.0/doc/source/ref/flavors.rst --- python-novaclient-2.15.0/doc/source/ref/flavors.rst 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/doc/source/ref/flavors.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -Flavors -======= - -From Rackspace's API documentation: - - A flavor is an available hardware configuration for a server. Each flavor - has a unique combination of disk space, memory capacity and priority for - CPU time. - -Classes -------- - -.. currentmodule:: novaclient - -.. autoclass:: FlavorManager - :members: get, list, find, findall - -.. autoclass:: Flavor - :members: - - .. attribute:: id - - This flavor's ID. - - .. attribute:: name - - A human-readable name for this flavor. - - .. attribute:: ram - - The amount of RAM this flavor has, in MB. - - .. attribute:: disk - - The amount of disk space this flavor has, in MB diff -Nru python-novaclient-2.15.0/doc/source/ref/images.rst python-novaclient-2.16.0/doc/source/ref/images.rst --- python-novaclient-2.15.0/doc/source/ref/images.rst 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/doc/source/ref/images.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -Images -====== - -.. currentmodule:: novaclient - -An "image" is a snapshot from which you can create new server instances. - -From Rackspace's own API documentation: - - An image is a collection of files used to create or rebuild a server. - Rackspace provides a number of pre-built OS images by default. You may - also create custom images from cloud servers you have launched. These - custom images are useful for backup purposes or for producing "gold" - server images if you plan to deploy a particular server configuration - frequently. - -Classes -------- - -.. autoclass:: ImageManager - :members: get, list, find, findall, create, delete - -.. autoclass:: Image - :members: delete - - .. attribute:: id - - This image's ID. - - .. attribute:: name - - This image's name. - - .. attribute:: created - - The date/time this image was created. - - .. attribute:: updated - - The date/time this instance was updated. - - .. attribute:: status - - The status of this image (usually ``"SAVING"`` or ``ACTIVE``). - - .. attribute:: progress - - During saving of an image this'll be set to something between - 0 and 100, representing a rough percentage done. - - .. attribute:: serverId - - If this image was created from a :class:`Server` then this attribute - will be set to the ID of the server whence this image came. diff -Nru python-novaclient-2.15.0/doc/source/ref/index.rst python-novaclient-2.16.0/doc/source/ref/index.rst --- python-novaclient-2.15.0/doc/source/ref/index.rst 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/doc/source/ref/index.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -API Reference -============= - -.. toctree:: - :maxdepth: 1 - - backup_schedules - exceptions - flavors - images - ipgroups - servers \ No newline at end of file diff -Nru python-novaclient-2.15.0/doc/source/ref/ipgroups.rst python-novaclient-2.16.0/doc/source/ref/ipgroups.rst --- python-novaclient-2.15.0/doc/source/ref/ipgroups.rst 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/doc/source/ref/ipgroups.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,46 +0,0 @@ -Shared IP addresses -=================== - -From the Rackspace API guide: - - Public IP addresses can be shared across multiple servers for use in - various high availability scenarios. When an IP address is shared to - another server, the cloud network restrictions are modified to allow each - server to listen to and respond on that IP address (you may optionally - specify that the target server network configuration be modified). Shared - IP addresses can be used with many standard heartbeat facilities (e.g. - ``keepalived``) that monitor for failure and manage IP failover. - - A shared IP group is a collection of servers that can share IPs with other - members of the group. Any server in a group can share one or more public - IPs with any other server in the group. With the exception of the first - server in a shared IP group, servers must be launched into shared IP - groups. A server may only be a member of one shared IP group. - -.. seealso:: - - Use :meth:`Server.share_ip` and `Server.unshare_ip` to share and unshare - IPs in a group. - -Classes -------- - -.. currentmodule:: novaclient - -.. autoclass:: IPGroupManager - :members: get, list, find, findall, create, delete - -.. autoclass:: IPGroup - :members: delete - - .. attribute:: id - - Shared group ID. - - .. attribute:: name - - Name of the group. - - .. attribute:: servers - - A list of server IDs in this group. diff -Nru python-novaclient-2.15.0/doc/source/ref/servers.rst python-novaclient-2.16.0/doc/source/ref/servers.rst --- python-novaclient-2.15.0/doc/source/ref/servers.rst 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/doc/source/ref/servers.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ -Servers -======= - -A virtual machine instance. - -Classes -------- - -.. currentmodule:: novaclient - -.. autoclass:: ServerManager - :members: get, list, find, findall, create, update, delete, share_ip, - unshare_ip, reboot, rebuild, resize, confirm_resize, - revert_resize - -.. autoclass:: Server - :members: update, delete, share_ip, unshare_ip, reboot, rebuild, resize, - confirm_resize, revert_resize - - .. attribute:: id - - This server's ID. - - .. attribute:: name - - The name you gave the server when you booted it. - - .. attribute:: imageId - - The :class:`Image` this server was booted with. - - .. attribute:: flavorId - - This server's current :class:`Flavor`. - - .. attribute:: hostId - - Rackspace doesn't document this value. It appears to be SHA1 hash. - - .. attribute:: status - - The server's status (``BOOTING``, ``ACTIVE``, etc). - - .. attribute:: progress - - When booting, resizing, updating, etc., this will be set to a - value between 0 and 100 giving a rough estimate of the progress - of the current operation. - - .. attribute:: addresses - - The public and private IP addresses of this server. This'll be a dict - of the form:: - - { - "public" : ["67.23.10.138"], - "private" : ["10.176.42.19"] - } - - You *can* get more than one public/private IP provisioned, but not - directly from the API; you'll need to open a support ticket. - - .. attribute:: metadata - - The metadata dict you gave when creating the server. - -Constants ---------- - -Reboot types: - -.. data:: REBOOT_SOFT -.. data:: REBOOT_HARD diff -Nru python-novaclient-2.15.0/doc/source/releases.rst python-novaclient-2.16.0/doc/source/releases.rst --- python-novaclient-2.15.0/doc/source/releases.rst 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/doc/source/releases.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,99 +0,0 @@ -============= -Release notes -============= - -2.5.8 (July 11, 2011) -===================== -* returns all public/private ips, not just first one -* better 'nova list' search options - -2.5.7 - 2.5.6 = minor tweaks - -2.5.5 (June 21, 2011) -===================== -* zone-boot min/max instance count added thanks to comstud -* create for user added thanks to cerberus -* fixed tests - -2.5.3 (June 15, 2011) -===================== -* ProjectID can be None for backwards compatability. -* README/docs updated for projectId thanks to usrleon - -2.5.1 (June 10, 2011) -===================== -* ProjectID now part of authentication - -2.5.0 (June 3, 2011) -================= - -* better logging thanks to GridDynamics - -2.4.4 (June 1, 2011) -================= - -* added support for GET /servers with reservation_id (and /servers/detail) - -2.4.3 (May 27, 2011) -================= - -* added support for POST /zones/select (client only, not cmdline) - -2.4 (March 7, 2011) -================= - -* added Jacob Kaplan-Moss copyright notices to older/untouched files. - - -2.3 (March 2, 2011) -================= - -* package renamed to python-novaclient. Module to novaclient - - -2.2 (March 1, 2011) -================= - -* removed some license/copywrite notices from source that wasn't - significantly changed. - - -2.1 (Feb 28, 2011) -================= - -* shell renamed to nova from novatools - -* license changed from BSD to Apache - -2.0 (Feb 7, 2011) -================= - -* Forked from https://github.com/jacobian/python-cloudservers - -* Rebranded to python-novatools - -* Auth URL support - -* New OpenStack specific commands added (pause, suspend, etc) - -1.2 (August 15, 2010) -===================== - -* Support for Python 2.4 - 2.7. - -* Improved output of :program:`cloudservers ipgroup-list`. - -* Made ``cloudservers boot --ipgroup `` work (as well as ``--ipgroup - ``). - -1.1 (May 6, 2010) -================= - -* Added a ``--files`` option to :program:`cloudservers boot` supporting - the upload of (up to five) files at boot time. - -* Added a ``--key`` option to :program:`cloudservers boot` to key the server - with an SSH public key at boot time. This is just a shortcut for ``--files``, - but it's a useful shortcut. - -* Changed the default server image to Ubuntu 10.04 LTS. diff -Nru python-novaclient-2.15.0/HACKING.rst python-novaclient-2.16.0/HACKING.rst --- python-novaclient-2.15.0/HACKING.rst 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/HACKING.rst 2014-02-26 16:28:51.000000000 +0000 @@ -2,7 +2,7 @@ ============================== - Step 1: Read the OpenStack Style Commandments - https://github.com/openstack-dev/hacking/blob/master/HACKING.rst + http://docs.openstack.org/developer/hacking - Step 2: Read on diff -Nru python-novaclient-2.15.0/.mailmap python-novaclient-2.16.0/.mailmap --- python-novaclient-2.15.0/.mailmap 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/.mailmap 2014-02-26 16:28:51.000000000 +0000 @@ -4,6 +4,7 @@ Chris Behrens comstud +Joe Gordon Johannes Erdfelt jerdfelt @@ -13,6 +14,8 @@ Andy Smith termie + + hwbi Nikolay Sokolov Nokolay Sokolov Nikolay Sokolov Nokolay Sokolov diff -Nru python-novaclient-2.15.0/novaclient/auth_plugin.py python-novaclient-2.16.0/novaclient/auth_plugin.py --- python-novaclient-2.15.0/novaclient/auth_plugin.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/auth_plugin.py 2014-02-26 16:28:51.000000000 +0000 @@ -15,11 +15,12 @@ # under the License. import logging -import pkg_resources +import pkg_resources import six from novaclient import exceptions +from novaclient.openstack.common.gettextutils import _ from novaclient import utils @@ -39,7 +40,7 @@ try: auth_plugin = ep.load() except (ImportError, pkg_resources.UnknownExtra, AttributeError) as e: - logger.debug("ERROR: Cannot load auth plugin %s" % ep.name) + logger.debug(_("ERROR: Cannot load auth plugin %s") % ep.name) logger.debug(e, exc_info=1) else: _discovered_plugins[ep.name] = auth_plugin diff -Nru python-novaclient-2.15.0/novaclient/base.py python-novaclient-2.16.0/novaclient/base.py --- python-novaclient-2.15.0/novaclient/base.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/base.py 2014-02-26 16:28:51.000000000 +0000 @@ -20,18 +20,20 @@ """ import abc -import base64 import contextlib import hashlib import inspect import os +import threading import six from novaclient import exceptions -from novaclient.openstack.common import strutils +from novaclient.openstack.common.apiclient import base from novaclient import utils +Resource = base.Resource + def getid(obj): """ @@ -50,6 +52,7 @@ etc.) and provide CRUD operations for them. """ resource_class = None + cache_lock = threading.RLock() def __init__(self, api): self.api = api @@ -90,46 +93,50 @@ Delete is not handled because listings are assumed to be performed often enough to keep the cache reasonably up-to-date. """ - base_dir = utils.env('NOVACLIENT_UUID_CACHE_DIR', - default="~/.novaclient") + # NOTE(wryan): This lock protects read and write access to the + # completion caches + with self.cache_lock: + base_dir = utils.env('NOVACLIENT_UUID_CACHE_DIR', + default="~/.novaclient") + + # NOTE(sirp): Keep separate UUID caches for each username + + # endpoint pair + username = utils.env('OS_USERNAME', 'NOVA_USERNAME') + url = utils.env('OS_URL', 'NOVA_URL') + uniqifier = hashlib.md5(username.encode('utf-8') + + url.encode('utf-8')).hexdigest() + + cache_dir = os.path.expanduser(os.path.join(base_dir, uniqifier)) + + try: + os.makedirs(cache_dir, 0o755) + except OSError: + # NOTE(kiall): This is typically either permission denied while + # attempting to create the directory, or the + # directory already exists. Either way, don't + # fail. + pass + + resource = obj_class.__name__.lower() + filename = "%s-%s-cache" % (resource, cache_type.replace('_', '-')) + path = os.path.join(cache_dir, filename) + + cache_attr = "_%s_cache" % cache_type + + try: + setattr(self, cache_attr, open(path, mode)) + except IOError: + # NOTE(kiall): This is typically a permission denied while + # attempting to write the cache file. + pass - # NOTE(sirp): Keep separate UUID caches for each username + endpoint - # pair - username = utils.env('OS_USERNAME', 'NOVA_USERNAME') - url = utils.env('OS_URL', 'NOVA_URL') - uniqifier = hashlib.md5(username.encode('utf-8') + - url.encode('utf-8')).hexdigest() - - cache_dir = os.path.expanduser(os.path.join(base_dir, uniqifier)) - - try: - os.makedirs(cache_dir, 0o755) - except OSError: - # NOTE(kiall): This is typicaly either permission denied while - # attempting to create the directory, or the directory - # already exists. Either way, don't fail. - pass - - resource = obj_class.__name__.lower() - filename = "%s-%s-cache" % (resource, cache_type.replace('_', '-')) - path = os.path.join(cache_dir, filename) - - cache_attr = "_%s_cache" % cache_type - - try: - setattr(self, cache_attr, open(path, mode)) - except IOError: - # NOTE(kiall): This is typicaly a permission denied while - # attempting to write the cache file. - pass - - try: - yield - finally: - cache = getattr(self, cache_attr, None) - if cache: - cache.close() - delattr(self, cache_attr) + try: + yield + finally: + cache = getattr(self, cache_attr, None) + if cache: + cache.close() + delattr(self, cache_attr) def write_to_completion_cache(self, cache_type, val): cache = getattr(self, "_%s_cache" % cache_type, None) @@ -163,13 +170,12 @@ return self.resource_class(self, body) +@six.add_metaclass(abc.ABCMeta) class ManagerWithFind(Manager): """ Like a `Manager`, but with additional `find()`/`findall()` methods. """ - __metaclass__ = abc.ABCMeta - @abc.abstractmethod def list(self): pass @@ -268,222 +274,3 @@ bdm.append(bdm_dict) return bdm - - def _boot(self, resource_url, response_key, name, image, flavor, - meta=None, files=None, userdata=None, - reservation_id=None, return_raw=False, min_count=None, - max_count=None, security_groups=None, key_name=None, - availability_zone=None, block_device_mapping=None, - block_device_mapping_v2=None, nics=None, scheduler_hints=None, - config_drive=None, admin_pass=None, disk_config=None, **kwargs): - """ - Create (boot) a new server. - - :param name: Something to name the server. - :param image: The :class:`Image` to boot with. - :param flavor: The :class:`Flavor` to boot onto. - :param meta: A dict of arbitrary key/value metadata to store for this - server. A maximum of five entries is allowed, and both - keys and values must be 255 characters or less. - :param files: A dict of files to overrwrite on the server upon boot. - Keys are file names (i.e. ``/etc/passwd``) and values - are the file contents (either as a string or as a - file-like object). A maximum of five entries is allowed, - and each file must be 10k or less. - :param reservation_id: a UUID for the set of servers being requested. - :param return_raw: If True, don't try to coearse the result into - a Resource object. - :param security_groups: list of security group names - :param key_name: (optional extension) name of keypair to inject into - the instance - :param availability_zone: Name of the availability zone for instance - placement. - :param block_device_mapping: A dict of block device mappings for this - server. - :param block_device_mapping_v2: A dict of block device mappings V2 for - this server. - :param nics: (optional extension) an ordered list of nics to be - added to this server, with information about - connected networks, fixed ips, etc. - :param scheduler_hints: (optional extension) arbitrary key-value pairs - specified by the client to help boot an instance. - :param config_drive: (optional extension) value for config drive - either boolean, or volume-id - :param admin_pass: admin password for the server. - :param disk_config: (optional extension) control how the disk is - partitioned when the server is created. - """ - body = {"server": { - "name": name, - "imageRef": str(getid(image)) if image else '', - "flavorRef": str(getid(flavor)), - }} - if userdata: - if hasattr(userdata, 'read'): - userdata = userdata.read() - - userdata = strutils.safe_encode(userdata) - body["server"]["user_data"] = base64.b64encode(userdata) - if meta: - body["server"]["metadata"] = meta - if reservation_id: - body["server"]["reservation_id"] = reservation_id - if key_name: - body["server"]["key_name"] = key_name - if scheduler_hints: - body['os:scheduler_hints'] = scheduler_hints - if config_drive: - body["server"]["config_drive"] = config_drive - if admin_pass: - body["server"]["adminPass"] = admin_pass - if not min_count: - min_count = 1 - if not max_count: - max_count = min_count - body["server"]["min_count"] = min_count - body["server"]["max_count"] = max_count - - if security_groups: - body["server"]["security_groups"] =\ - [{'name': sg} for sg in security_groups] - - # Files are a slight bit tricky. They're passed in a "personality" - # list to the POST. Each item is a dict giving a file name and the - # base64-encoded contents of the file. We want to allow passing - # either an open file *or* some contents as files here. - if files: - personality = body['server']['personality'] = [] - for filepath, file_or_string in files.items(): - if hasattr(file_or_string, 'read'): - data = file_or_string.read() - else: - data = file_or_string - personality.append({ - 'path': filepath, - 'contents': data.encode('base64'), - }) - - if availability_zone: - body["server"]["availability_zone"] = availability_zone - - # Block device mappings are passed as a list of dictionaries - if block_device_mapping: - body['server']['block_device_mapping'] = \ - self._parse_block_device_mapping(block_device_mapping) - elif block_device_mapping_v2: - # Append the image to the list only if we have new style BDMs - if image: - bdm_dict = {'uuid': image.id, 'source_type': 'image', - 'destination_type': 'local', 'boot_index': 0, - 'delete_on_termination': True} - block_device_mapping_v2.insert(0, bdm_dict) - - body['server']['block_device_mapping_v2'] = block_device_mapping_v2 - - if nics is not None: - # NOTE(tr3buchet): nics can be an empty list - all_net_data = [] - for nic_info in nics: - net_data = {} - # if value is empty string, do not send value in body - if nic_info.get('net-id'): - net_data['uuid'] = nic_info['net-id'] - if nic_info.get('v4-fixed-ip'): - net_data['fixed_ip'] = nic_info['v4-fixed-ip'] - if nic_info.get('port-id'): - net_data['port'] = nic_info['port-id'] - all_net_data.append(net_data) - body['server']['networks'] = all_net_data - - if disk_config is not None: - body['server']['OS-DCF:diskConfig'] = disk_config - - return self._create(resource_url, body, response_key, - return_raw=return_raw, **kwargs) - - -class Resource(object): - """ - A resource represents a particular instance of an object (server, flavor, - etc). This is pretty much just a bag for attributes. - - :param manager: Manager object - :param info: dictionary representing resource attributes - :param loaded: prevent lazy-loading if set to True - """ - HUMAN_ID = False - NAME_ATTR = 'name' - - def __init__(self, manager, info, loaded=False): - self.manager = manager - self._info = info - self._add_details(info) - self._loaded = loaded - - # NOTE(sirp): ensure `id` is already present because if it isn't we'll - # enter an infinite loop of __getattr__ -> get -> __init__ -> - # __getattr__ -> ... - if 'id' in self.__dict__ and len(str(self.id)) == 36: - self.manager.write_to_completion_cache('uuid', self.id) - - human_id = self.human_id - if human_id: - self.manager.write_to_completion_cache('human_id', human_id) - - @property - def human_id(self): - """Subclasses may override this provide a pretty ID which can be used - for bash completion. - """ - if self.NAME_ATTR in self.__dict__ and self.HUMAN_ID: - return utils.slugify(getattr(self, self.NAME_ATTR)) - return None - - def _add_details(self, info): - for (k, v) in six.iteritems(info): - try: - setattr(self, k, v) - self._info[k] = v - except AttributeError: - # In this case we already defined the attribute on the class - pass - - def __getattr__(self, k): - if k not in self.__dict__: - #NOTE(bcwaldon): disallow lazy-loading if already loaded once - if not self.is_loaded(): - self.get() - return self.__getattr__(k) - - raise AttributeError(k) - else: - return self.__dict__[k] - - def __repr__(self): - reprkeys = sorted(k for k in self.__dict__.keys() if k[0] != '_' and - k != 'manager') - info = ", ".join("%s=%s" % (k, getattr(self, k)) for k in reprkeys) - return "<%s %s>" % (self.__class__.__name__, info) - - def get(self): - # set_loaded() first ... so if we have to bail, we know we tried. - self.set_loaded(True) - if not hasattr(self.manager, 'get'): - return - - new = self.manager.get(self.id) - if new: - self._add_details(new._info) - - def __eq__(self, other): - if not isinstance(other, self.__class__): - return False - if hasattr(self, 'id') and hasattr(other, 'id'): - return self.id == other.id - return self._info == other._info - - def is_loaded(self): - return self._loaded - - def set_loaded(self, val): - self._loaded = val diff -Nru python-novaclient-2.15.0/novaclient/client.py python-novaclient-2.16.0/novaclient/client.py --- python-novaclient-2.15.0/novaclient/client.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/client.py 2014-02-26 16:28:52.000000000 +0000 @@ -3,12 +3,24 @@ # Copyright 2011 Piston Cloud Computing, 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. + """ OpenStack Client interface. Handles the REST calls and responses. """ import logging -import os import time import requests @@ -19,9 +31,10 @@ import simplejson as json from novaclient import exceptions +from novaclient.openstack.common.gettextutils import _ +from novaclient.openstack.common.py3kcompat import urlutils from novaclient import service_catalog from novaclient import utils -from novaclient.openstack.common.py3kcompat import urlutils class HTTPClient(object): @@ -36,13 +49,19 @@ timings=False, bypass_url=None, os_cache=False, no_cache=True, http_log_debug=False, auth_system='keystone', - auth_plugin=None, + auth_plugin=None, auth_token=None, cacert=None, tenant_id=None): self.user = user self.password = password self.projectid = projectid self.tenant_id = tenant_id + # This will be called by #_get_password if self.password is None. + # EG if a password can only be obtained by prompting the user, but a + # token is available, you don't want to prompt until the token has + # been proven invalid + self.password_func = None + if auth_system and auth_system != 'keystone' and not auth_plugin: raise exceptions.AuthSystemNotFound(auth_system) @@ -68,8 +87,8 @@ self.times = [] # [("item", starttime, endtime), ...] - self.management_url = None - self.auth_token = None + self.management_url = self.bypass_url or None + self.auth_token = auth_token self.proxy_token = proxy_token self.proxy_tenant_id = proxy_tenant_id self.keyring_saver = None @@ -97,7 +116,7 @@ rql.addHandler(ch) # Since we have already setup the root logger on debug, we # have to set it up here on WARNING (its original level) - # otherwise we will get all the requests logging messanges + # otherwise we will get all the requests logging messages rql.setLevel(logging.WARNING) # requests within the same session can reuse TCP connections from pool self.http = requests.Session() @@ -119,16 +138,17 @@ def reset_timings(self): self.times = [] - def http_log_req(self, args, kwargs): + def http_log_req(self, method, url, kwargs): if not self.http_log_debug: return string_parts = ['curl -i'] - for element in args: - if element in ('GET', 'POST', 'DELETE', 'PUT'): - string_parts.append(' -X %s' % element) - else: - string_parts.append(' %s' % element) + + if not kwargs.get('verify', True): + string_parts.append(' --insecure') + + string_parts.append(" '%s'" % url) + string_parts.append(' -X %s' % method) for element in kwargs['headers']: header = ' -H "%s: %s"' % (element, kwargs['headers'][element]) @@ -141,11 +161,10 @@ def http_log_resp(self, resp): if not self.http_log_debug: return - self._logger.debug( - "RESP: [%s] %s\nRESP BODY: %s\n", - resp.status_code, - resp.headers, - resp.text) + self._logger.debug(_("RESP: [%(status)s] %(headers)s\nRESP BODY: " + "%(text)s\n"), {'status': resp.status_code, + 'headers': resp.headers, + 'text': resp.text}) def request(self, url, method, **kwargs): kwargs.setdefault('headers', kwargs.get('headers', {})) @@ -157,12 +176,12 @@ del kwargs['body'] if self.timeout is not None: kwargs.setdefault('timeout', self.timeout) + kwargs['verify'] = self.verify_cert - self.http_log_req((url, method,), kwargs) + self.http_log_req(method, url, kwargs) resp = self.http.request( method, url, - verify=self.verify_cert, **kwargs) self.http_log_resp(resp) @@ -180,7 +199,6 @@ try: body = json.loads(resp.text) except ValueError: - pass body = None else: body = None @@ -214,9 +232,11 @@ return resp, body except exceptions.Unauthorized as e: try: - # frist discard auth token, to avoid the possibly expired + # first discard auth token, to avoid the possibly expired # token being re-used in the re-authentication attempt self.unauthenticate() + # overwrite bad token + self.keyring_saved = False self.authenticate() kwargs['headers']['X-Auth-Token'] = self.auth_token resp, body = self._time_request(self.management_url + url, @@ -225,6 +245,11 @@ except exceptions.Unauthorized: raise e + def _get_password(self): + if not self.password and self.password_func: + self.password = self.password_func() + return self.password + def get(self, url, **kwargs): return self._cs_request(url, 'GET', **kwargs) @@ -240,7 +265,8 @@ def _extract_service_catalog(self, url, resp, body, extract_token=True): """See what the auth service told us and process the response. We may get redirected to another site, fail or actually get - back a service catalog with a token and our endpoints.""" + back a service catalog with a token and our endpoints. + """ # content must always present if resp.status_code == 200 or resp.status_code == 201: @@ -262,13 +288,14 @@ self.management_url = management_url.rstrip('/') return None except exceptions.AmbiguousEndpoints: - print("Found more than one valid endpoint. Use a more " - "restrictive filter") + print(_("Found more than one valid endpoint. Use a more " + "restrictive filter")) raise except KeyError: raise exceptions.AuthorizationFailure() except exceptions.EndpointNotFound: - print("Could not find any suitable endpoint. Correct region?") + print(_("Could not find any suitable endpoint. Correct " + "region?")) raise elif resp.status_code == 305: @@ -291,7 +318,7 @@ # GET ...:5001/v2.0/tokens/#####/endpoints url = '/'.join([url, 'tokens', '%s?belongsTo=%s' % (self.proxy_token, self.proxy_tenant_id)]) - self._logger.debug("Using Endpoint URL: %s" % url) + self._logger.debug(_("Using Endpoint URL: %s") % url) resp, body = self._time_request( url, "GET", headers={'X-Auth-Token': self.auth_token}) return self._extract_service_catalog(url, resp, body, @@ -309,19 +336,16 @@ self.version = part break + if self.auth_token and self.management_url: + self._save_keys() + return + # TODO(sandy): Assume admin endpoint is 35357 for now. # Ideally this is going to have to be provided by the service catalog. new_netloc = netloc.replace(':%d' % port, ':%d' % (35357,)) admin_url = urlutils.urlunsplit( (scheme, new_netloc, path, query, frag)) - # FIXME(chmouel): This is to handle backward compatibiliy when - # we didn't have a plugin mechanism for the auth_system. This - # should be removed in the future and have people move to - # OS_AUTH_SYSTEM=rackspace instead. - if "NOVA_RAX_AUTH" in os.environ: - self.auth_system = "rackspace" - auth_url = self.auth_url if self.version == "v2.0": # FIXME(chris): This should be better. while auth_url: @@ -359,8 +383,13 @@ elif not self.management_url: raise exceptions.Unauthorized('Nova Client') + self._save_keys() + + def _save_keys(self): # Store the token/mgmt url in the keyring for later requests. - if self.keyring_saver and self.os_cache and not self.keyring_saved: + if (self.keyring_saver and self.os_cache and not self.keyring_saved + and self.auth_token and self.management_url + and self.tenant_id): self.keyring_saver.save(self.auth_token, self.management_url, self.tenant_id) @@ -372,7 +401,7 @@ raise exceptions.NoTokenLookupException() headers = {'X-Auth-User': self.user, - 'X-Auth-Key': self.password} + 'X-Auth-Key': self._get_password()} if self.projectid: headers['X-Auth-Project-Id'] = self.projectid @@ -401,7 +430,7 @@ else: body = {"auth": { "passwordCredentials": {"username": self.user, - "password": self.password}}} + "password": self._get_password()}}} if self.tenant_id: body['auth']['tenantId'] = self.tenant_id @@ -412,17 +441,18 @@ def _authenticate(self, url, body, **kwargs): """Authenticate and extract the service catalog.""" + method = "POST" token_url = url + "/tokens" # Make sure we follow redirects when trying to reach Keystone - resp, body = self._time_request( + resp, respbody = self._time_request( token_url, - "POST", + method, body=body, allow_redirects=True, **kwargs) - return self._extract_service_catalog(url, resp, body) + return self._extract_service_catalog(url, resp, respbody) def get_client_class(version): @@ -434,8 +464,9 @@ try: client_path = version_map[str(version)] except (KeyError, ValueError): - msg = "Invalid client version '%s'. must be one of: %s" % ( - (version, ', '.join(version_map.keys()))) + msg = _("Invalid client version '%(version)s'. must be one of: " + "%(keys)s") % {'version': version, + 'keys': ', '.join(version_map.keys())} raise exceptions.UnsupportedVersion(msg) return utils.import_class(client_path) diff -Nru python-novaclient-2.15.0/novaclient/crypto.py python-novaclient-2.16.0/novaclient/crypto.py --- python-novaclient-2.15.0/novaclient/crypto.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/crypto.py 2014-02-26 16:28:51.000000000 +0000 @@ -24,7 +24,8 @@ def decrypt_password(private_key, password): """Base64 decodes password and unecrypts it with private key. - Requires openssl binary available in the path""" + Requires openssl binary available in the path. + """ unencoded = base64.b64decode(password) cmd = ['openssl', 'rsautl', '-decrypt', '-inkey', private_key] proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, diff -Nru python-novaclient-2.15.0/novaclient/exceptions.py python-novaclient-2.16.0/novaclient/exceptions.py --- python-novaclient-2.15.0/novaclient/exceptions.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/exceptions.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,4 +1,17 @@ # Copyright 2010 Jacob Kaplan-Moss +# +# 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. + """ Exception definitions. """ @@ -6,7 +19,8 @@ class UnsupportedVersion(Exception): """Indicates that the user is trying to use an unsupported - version of the API""" + version of the API. + """ pass @@ -33,7 +47,8 @@ class NoTokenLookupException(Exception): """This form of authentication does not support looking up - endpoints from an existing token.""" + endpoints from an existing token. + """ pass @@ -206,9 +221,9 @@ details = "n/a" if hasattr(body, 'keys'): - error = body[body.keys()[0]] - message = error.get('message', None) - details = error.get('details', None) + error = body[list(body)[0]] + message = error.get('message') + details = error.get('details') kwargs['message'] = message kwargs['details'] = details diff -Nru python-novaclient-2.15.0/novaclient/openstack/common/apiclient/auth.py python-novaclient-2.16.0/novaclient/openstack/common/apiclient/auth.py --- python-novaclient-2.15.0/novaclient/openstack/common/apiclient/auth.py 1970-01-01 00:00:00.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/openstack/common/apiclient/auth.py 2014-02-26 16:28:51.000000000 +0000 @@ -0,0 +1,225 @@ +# Copyright 2013 OpenStack Foundation +# Copyright 2013 Spanish National Research Council. +# 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. + +# E0202: An attribute inherited from %s hide this method +# pylint: disable=E0202 + +import abc +import argparse +import logging +import os + +import six +from stevedore import extension + +from novaclient.openstack.common.apiclient import exceptions + + +logger = logging.getLogger(__name__) + + +_discovered_plugins = {} + + +def discover_auth_systems(): + """Discover the available auth-systems. + + This won't take into account the old style auth-systems. + """ + global _discovered_plugins + _discovered_plugins = {} + + def add_plugin(ext): + _discovered_plugins[ext.name] = ext.plugin + + ep_namespace = "novaclient.openstack.common.apiclient.auth" + mgr = extension.ExtensionManager(ep_namespace) + mgr.map(add_plugin) + + +def load_auth_system_opts(parser): + """Load options needed by the available auth-systems into a parser. + + This function will try to populate the parser with options from the + available plugins. + """ + group = parser.add_argument_group("Common auth options") + BaseAuthPlugin.add_common_opts(group) + for name, auth_plugin in six.iteritems(_discovered_plugins): + group = parser.add_argument_group( + "Auth-system '%s' options" % name, + conflict_handler="resolve") + auth_plugin.add_opts(group) + + +def load_plugin(auth_system): + try: + plugin_class = _discovered_plugins[auth_system] + except KeyError: + raise exceptions.AuthSystemNotFound(auth_system) + return plugin_class(auth_system=auth_system) + + +def load_plugin_from_args(args): + """Load required plugin and populate it with options. + + Try to guess auth system if it is not specified. Systems are tried in + alphabetical order. + + :type args: argparse.Namespace + :raises: AuthorizationFailure + """ + auth_system = args.os_auth_system + if auth_system: + plugin = load_plugin(auth_system) + plugin.parse_opts(args) + plugin.sufficient_options() + return plugin + + for plugin_auth_system in sorted(six.iterkeys(_discovered_plugins)): + plugin_class = _discovered_plugins[plugin_auth_system] + plugin = plugin_class() + plugin.parse_opts(args) + try: + plugin.sufficient_options() + except exceptions.AuthPluginOptionsMissing: + continue + return plugin + raise exceptions.AuthPluginOptionsMissing(["auth_system"]) + + +@six.add_metaclass(abc.ABCMeta) +class BaseAuthPlugin(object): + """Base class for authentication plugins. + + An authentication plugin needs to override at least the authenticate + method to be a valid plugin. + """ + + auth_system = None + opt_names = [] + common_opt_names = [ + "auth_system", + "username", + "password", + "tenant_name", + "token", + "auth_url", + ] + + def __init__(self, auth_system=None, **kwargs): + self.auth_system = auth_system or self.auth_system + self.opts = dict((name, kwargs.get(name)) + for name in self.opt_names) + + @staticmethod + def _parser_add_opt(parser, opt): + """Add an option to parser in two variants. + + :param opt: option name (with underscores) + """ + dashed_opt = opt.replace("_", "-") + env_var = "OS_%s" % opt.upper() + arg_default = os.environ.get(env_var, "") + arg_help = "Defaults to env[%s]." % env_var + parser.add_argument( + "--os-%s" % dashed_opt, + metavar="<%s>" % dashed_opt, + default=arg_default, + help=arg_help) + parser.add_argument( + "--os_%s" % opt, + metavar="<%s>" % dashed_opt, + help=argparse.SUPPRESS) + + @classmethod + def add_opts(cls, parser): + """Populate the parser with the options for this plugin. + """ + for opt in cls.opt_names: + # use `BaseAuthPlugin.common_opt_names` since it is never + # changed in child classes + if opt not in BaseAuthPlugin.common_opt_names: + cls._parser_add_opt(parser, opt) + + @classmethod + def add_common_opts(cls, parser): + """Add options that are common for several plugins. + """ + for opt in cls.common_opt_names: + cls._parser_add_opt(parser, opt) + + @staticmethod + def get_opt(opt_name, args): + """Return option name and value. + + :param opt_name: name of the option, e.g., "username" + :param args: parsed arguments + """ + return (opt_name, getattr(args, "os_%s" % opt_name, None)) + + def parse_opts(self, args): + """Parse the actual auth-system options if any. + + This method is expected to populate the attribute `self.opts` with a + dict containing the options and values needed to make authentication. + """ + self.opts.update(dict(self.get_opt(opt_name, args) + for opt_name in self.opt_names)) + + def authenticate(self, http_client): + """Authenticate using plugin defined method. + + The method usually analyses `self.opts` and performs + a request to authentication server. + + :param http_client: client object that needs authentication + :type http_client: HTTPClient + :raises: AuthorizationFailure + """ + self.sufficient_options() + self._do_authenticate(http_client) + + @abc.abstractmethod + def _do_authenticate(self, http_client): + """Protected method for authentication. + """ + + def sufficient_options(self): + """Check if all required options are present. + + :raises: AuthPluginOptionsMissing + """ + missing = [opt + for opt in self.opt_names + if not self.opts.get(opt)] + if missing: + raise exceptions.AuthPluginOptionsMissing(missing) + + @abc.abstractmethod + def token_and_endpoint(self, endpoint_type, service_type): + """Return token and endpoint. + + :param service_type: Service type of the endpoint + :type service_type: string + :param endpoint_type: Type of endpoint. + Possible values: public or publicURL, + internal or internalURL, + admin or adminURL + :type endpoint_type: string + :returns: tuple of token and endpoint strings + :raises: EndpointException + """ diff -Nru python-novaclient-2.15.0/novaclient/openstack/common/apiclient/base.py python-novaclient-2.16.0/novaclient/openstack/common/apiclient/base.py --- python-novaclient-2.15.0/novaclient/openstack/common/apiclient/base.py 1970-01-01 00:00:00.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/openstack/common/apiclient/base.py 2014-02-26 16:28:51.000000000 +0000 @@ -0,0 +1,491 @@ +# Copyright 2010 Jacob Kaplan-Moss +# Copyright 2011 OpenStack Foundation +# Copyright 2012 Grid Dynamics +# Copyright 2013 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. + +""" +Base utilities to build API operation managers and objects on top of. +""" + +# E1102: %s is not callable +# pylint: disable=E1102 + +import abc + +import six + +from novaclient.openstack.common.apiclient import exceptions +from novaclient.openstack.common.py3kcompat import urlutils +from novaclient.openstack.common import strutils + + +def getid(obj): + """Return id if argument is a Resource. + + Abstracts the common pattern of allowing both an object or an object's ID + (UUID) as a parameter when dealing with relationships. + """ + try: + if obj.uuid: + return obj.uuid + except AttributeError: + pass + try: + return obj.id + except AttributeError: + return obj + + +# TODO(aababilov): call run_hooks() in HookableMixin's child classes +class HookableMixin(object): + """Mixin so classes can register and run hooks.""" + _hooks_map = {} + + @classmethod + def add_hook(cls, hook_type, hook_func): + """Add a new hook of specified type. + + :param cls: class that registers hooks + :param hook_type: hook type, e.g., '__pre_parse_args__' + :param hook_func: hook function + """ + if hook_type not in cls._hooks_map: + cls._hooks_map[hook_type] = [] + + cls._hooks_map[hook_type].append(hook_func) + + @classmethod + def run_hooks(cls, hook_type, *args, **kwargs): + """Run all hooks of specified type. + + :param cls: class that registers hooks + :param hook_type: hook type, e.g., '__pre_parse_args__' + :param **args: args to be passed to every hook function + :param **kwargs: kwargs to be passed to every hook function + """ + hook_funcs = cls._hooks_map.get(hook_type) or [] + for hook_func in hook_funcs: + hook_func(*args, **kwargs) + + +class BaseManager(HookableMixin): + """Basic manager type providing common operations. + + Managers interact with a particular type of API (servers, flavors, images, + etc.) and provide CRUD operations for them. + """ + resource_class = None + + def __init__(self, client): + """Initializes BaseManager with `client`. + + :param client: instance of BaseClient descendant for HTTP requests + """ + super(BaseManager, self).__init__() + self.client = client + + def _list(self, url, response_key, obj_class=None, json=None): + """List the collection. + + :param url: a partial URL, e.g., '/servers' + :param response_key: the key to be looked up in response dictionary, + e.g., 'servers' + :param obj_class: class for constructing the returned objects + (self.resource_class will be used by default) + :param json: data that will be encoded as JSON and passed in POST + request (GET will be sent by default) + """ + if json: + body = self.client.post(url, json=json).json() + else: + body = self.client.get(url).json() + + if obj_class is None: + obj_class = self.resource_class + + data = body[response_key] + # NOTE(ja): keystone returns values as list as {'values': [ ... ]} + # unlike other services which just return the list... + try: + data = data['values'] + except (KeyError, TypeError): + pass + + return [obj_class(self, res, loaded=True) for res in data if res] + + def _get(self, url, response_key): + """Get an object from collection. + + :param url: a partial URL, e.g., '/servers' + :param response_key: the key to be looked up in response dictionary, + e.g., 'server' + """ + body = self.client.get(url).json() + return self.resource_class(self, body[response_key], loaded=True) + + def _head(self, url): + """Retrieve request headers for an object. + + :param url: a partial URL, e.g., '/servers' + """ + resp = self.client.head(url) + return resp.status_code == 204 + + def _post(self, url, json, response_key, return_raw=False): + """Create an object. + + :param url: a partial URL, e.g., '/servers' + :param json: data that will be encoded as JSON and passed in POST + request (GET will be sent by default) + :param response_key: the key to be looked up in response dictionary, + e.g., 'servers' + :param return_raw: flag to force returning raw JSON instead of + Python object of self.resource_class + """ + body = self.client.post(url, json=json).json() + if return_raw: + return body[response_key] + return self.resource_class(self, body[response_key]) + + def _put(self, url, json=None, response_key=None): + """Update an object with PUT method. + + :param url: a partial URL, e.g., '/servers' + :param json: data that will be encoded as JSON and passed in POST + request (GET will be sent by default) + :param response_key: the key to be looked up in response dictionary, + e.g., 'servers' + """ + resp = self.client.put(url, json=json) + # PUT requests may not return a body + if resp.content: + body = resp.json() + if response_key is not None: + return self.resource_class(self, body[response_key]) + else: + return self.resource_class(self, body) + + def _patch(self, url, json=None, response_key=None): + """Update an object with PATCH method. + + :param url: a partial URL, e.g., '/servers' + :param json: data that will be encoded as JSON and passed in POST + request (GET will be sent by default) + :param response_key: the key to be looked up in response dictionary, + e.g., 'servers' + """ + body = self.client.patch(url, json=json).json() + if response_key is not None: + return self.resource_class(self, body[response_key]) + else: + return self.resource_class(self, body) + + def _delete(self, url): + """Delete an object. + + :param url: a partial URL, e.g., '/servers/my-server' + """ + return self.client.delete(url) + + +@six.add_metaclass(abc.ABCMeta) +class ManagerWithFind(BaseManager): + """Manager with additional `find()`/`findall()` methods.""" + + @abc.abstractmethod + def list(self): + pass + + def find(self, **kwargs): + """Find a single item with attributes matching ``**kwargs``. + + This isn't very efficient: it loads the entire list then filters on + the Python side. + """ + matches = self.findall(**kwargs) + num_matches = len(matches) + if num_matches == 0: + msg = "No %s matching %s." % (self.resource_class.__name__, kwargs) + raise exceptions.NotFound(msg) + elif num_matches > 1: + raise exceptions.NoUniqueMatch() + else: + return matches[0] + + def findall(self, **kwargs): + """Find all items with attributes matching ``**kwargs``. + + This isn't very efficient: it loads the entire list then filters on + the Python side. + """ + found = [] + searches = kwargs.items() + + for obj in self.list(): + try: + if all(getattr(obj, attr) == value + for (attr, value) in searches): + found.append(obj) + except AttributeError: + continue + + return found + + +class CrudManager(BaseManager): + """Base manager class for manipulating entities. + + Children of this class are expected to define a `collection_key` and `key`. + + - `collection_key`: Usually a plural noun by convention (e.g. `entities`); + used to refer collections in both URL's (e.g. `/v3/entities`) and JSON + objects containing a list of member resources (e.g. `{'entities': [{}, + {}, {}]}`). + - `key`: Usually a singular noun by convention (e.g. `entity`); used to + refer to an individual member of the collection. + + """ + collection_key = None + key = None + + def build_url(self, base_url=None, **kwargs): + """Builds a resource URL for the given kwargs. + + Given an example collection where `collection_key = 'entities'` and + `key = 'entity'`, the following URL's could be generated. + + By default, the URL will represent a collection of entities, e.g.:: + + /entities + + If kwargs contains an `entity_id`, then the URL will represent a + specific member, e.g.:: + + /entities/{entity_id} + + :param base_url: if provided, the generated URL will be appended to it + """ + url = base_url if base_url is not None else '' + + url += '/%s' % self.collection_key + + # do we have a specific entity? + entity_id = kwargs.get('%s_id' % self.key) + if entity_id is not None: + url += '/%s' % entity_id + + return url + + def _filter_kwargs(self, kwargs): + """Drop null values and handle ids.""" + for key, ref in six.iteritems(kwargs.copy()): + if ref is None: + kwargs.pop(key) + else: + if isinstance(ref, Resource): + kwargs.pop(key) + kwargs['%s_id' % key] = getid(ref) + return kwargs + + def create(self, **kwargs): + kwargs = self._filter_kwargs(kwargs) + return self._post( + self.build_url(**kwargs), + {self.key: kwargs}, + self.key) + + def get(self, **kwargs): + kwargs = self._filter_kwargs(kwargs) + return self._get( + self.build_url(**kwargs), + self.key) + + def head(self, **kwargs): + kwargs = self._filter_kwargs(kwargs) + return self._head(self.build_url(**kwargs)) + + def list(self, base_url=None, **kwargs): + """List the collection. + + :param base_url: if provided, the generated URL will be appended to it + """ + kwargs = self._filter_kwargs(kwargs) + + return self._list( + '%(base_url)s%(query)s' % { + 'base_url': self.build_url(base_url=base_url, **kwargs), + 'query': '?%s' % urlutils.urlencode(kwargs) if kwargs else '', + }, + self.collection_key) + + def put(self, base_url=None, **kwargs): + """Update an element. + + :param base_url: if provided, the generated URL will be appended to it + """ + kwargs = self._filter_kwargs(kwargs) + + return self._put(self.build_url(base_url=base_url, **kwargs)) + + def update(self, **kwargs): + kwargs = self._filter_kwargs(kwargs) + params = kwargs.copy() + params.pop('%s_id' % self.key) + + return self._patch( + self.build_url(**kwargs), + {self.key: params}, + self.key) + + def delete(self, **kwargs): + kwargs = self._filter_kwargs(kwargs) + + return self._delete( + self.build_url(**kwargs)) + + def find(self, base_url=None, **kwargs): + """Find a single item with attributes matching ``**kwargs``. + + :param base_url: if provided, the generated URL will be appended to it + """ + kwargs = self._filter_kwargs(kwargs) + + rl = self._list( + '%(base_url)s%(query)s' % { + 'base_url': self.build_url(base_url=base_url, **kwargs), + 'query': '?%s' % urlutils.urlencode(kwargs) if kwargs else '', + }, + self.collection_key) + num = len(rl) + + if num == 0: + msg = "No %s matching %s." % (self.resource_class.__name__, kwargs) + raise exceptions.NotFound(404, msg) + elif num > 1: + raise exceptions.NoUniqueMatch + else: + return rl[0] + + +class Extension(HookableMixin): + """Extension descriptor.""" + + SUPPORTED_HOOKS = ('__pre_parse_args__', '__post_parse_args__') + manager_class = None + + def __init__(self, name, module): + super(Extension, self).__init__() + self.name = name + self.module = module + self._parse_extension_module() + + def _parse_extension_module(self): + self.manager_class = None + for attr_name, attr_value in self.module.__dict__.items(): + if attr_name in self.SUPPORTED_HOOKS: + self.add_hook(attr_name, attr_value) + else: + try: + if issubclass(attr_value, BaseManager): + self.manager_class = attr_value + except TypeError: + pass + + def __repr__(self): + return "" % self.name + + +class Resource(object): + """Base class for OpenStack resources (tenant, user, etc.). + + This is pretty much just a bag for attributes. + """ + + HUMAN_ID = False + NAME_ATTR = 'name' + + def __init__(self, manager, info, loaded=False): + """Populate and bind to a manager. + + :param manager: BaseManager object + :param info: dictionary representing resource attributes + :param loaded: prevent lazy-loading if set to True + """ + self.manager = manager + self._info = info + self._add_details(info) + self._loaded = loaded + + def __repr__(self): + reprkeys = sorted(k + for k in self.__dict__.keys() + if k[0] != '_' and k != 'manager') + info = ", ".join("%s=%s" % (k, getattr(self, k)) for k in reprkeys) + return "<%s %s>" % (self.__class__.__name__, info) + + @property + def human_id(self): + """Human-readable ID which can be used for bash completion. + """ + if self.NAME_ATTR in self.__dict__ and self.HUMAN_ID: + return strutils.to_slug(getattr(self, self.NAME_ATTR)) + return None + + def _add_details(self, info): + for (k, v) in six.iteritems(info): + try: + setattr(self, k, v) + self._info[k] = v + except AttributeError: + # In this case we already defined the attribute on the class + pass + + def __getattr__(self, k): + if k not in self.__dict__: + #NOTE(bcwaldon): disallow lazy-loading if already loaded once + if not self.is_loaded(): + self.get() + return self.__getattr__(k) + + raise AttributeError(k) + else: + return self.__dict__[k] + + def get(self): + # set_loaded() first ... so if we have to bail, we know we tried. + self.set_loaded(True) + if not hasattr(self.manager, 'get'): + return + + new = self.manager.get(self.id) + if new: + self._add_details(new._info) + + def __eq__(self, other): + if not isinstance(other, Resource): + return NotImplemented + # two resources of different types are not equal + if not isinstance(other, self.__class__): + return False + if hasattr(self, 'id') and hasattr(other, 'id'): + return self.id == other.id + return self._info == other._info + + def is_loaded(self): + return self._loaded + + def set_loaded(self, val): + self._loaded = val diff -Nru python-novaclient-2.15.0/novaclient/openstack/common/apiclient/client.py python-novaclient-2.16.0/novaclient/openstack/common/apiclient/client.py --- python-novaclient-2.15.0/novaclient/openstack/common/apiclient/client.py 1970-01-01 00:00:00.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/openstack/common/apiclient/client.py 2014-02-26 16:28:51.000000000 +0000 @@ -0,0 +1,358 @@ +# Copyright 2010 Jacob Kaplan-Moss +# Copyright 2011 OpenStack Foundation +# Copyright 2011 Piston Cloud Computing, Inc. +# Copyright 2013 Alessio Ababilov +# Copyright 2013 Grid Dynamics +# Copyright 2013 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. + +""" +OpenStack Client interface. Handles the REST calls and responses. +""" + +# E0202: An attribute inherited from %s hide this method +# pylint: disable=E0202 + +import logging +import time + +try: + import simplejson as json +except ImportError: + import json + +import requests + +from novaclient.openstack.common.apiclient import exceptions +from novaclient.openstack.common import importutils + + +_logger = logging.getLogger(__name__) + + +class HTTPClient(object): + """This client handles sending HTTP requests to OpenStack servers. + + Features: + - share authentication information between several clients to different + services (e.g., for compute and image clients); + - reissue authentication request for expired tokens; + - encode/decode JSON bodies; + - raise exceptions on HTTP errors; + - pluggable authentication; + - store authentication information in a keyring; + - store time spent for requests; + - register clients for particular services, so one can use + `http_client.identity` or `http_client.compute`; + - log requests and responses in a format that is easy to copy-and-paste + into terminal and send the same request with curl. + """ + + user_agent = "novaclient.openstack.common.apiclient" + + def __init__(self, + auth_plugin, + region_name=None, + endpoint_type="publicURL", + original_ip=None, + verify=True, + cert=None, + timeout=None, + timings=False, + keyring_saver=None, + debug=False, + user_agent=None, + http=None): + self.auth_plugin = auth_plugin + + self.endpoint_type = endpoint_type + self.region_name = region_name + + self.original_ip = original_ip + self.timeout = timeout + self.verify = verify + self.cert = cert + + self.keyring_saver = keyring_saver + self.debug = debug + self.user_agent = user_agent or self.user_agent + + self.times = [] # [("item", starttime, endtime), ...] + self.timings = timings + + # requests within the same session can reuse TCP connections from pool + self.http = http or requests.Session() + + self.cached_token = None + + def _http_log_req(self, method, url, kwargs): + if not self.debug: + return + + string_parts = [ + "curl -i", + "-X '%s'" % method, + "'%s'" % url, + ] + + for element in kwargs['headers']: + header = "-H '%s: %s'" % (element, kwargs['headers'][element]) + string_parts.append(header) + + _logger.debug("REQ: %s" % " ".join(string_parts)) + if 'data' in kwargs: + _logger.debug("REQ BODY: %s\n" % (kwargs['data'])) + + def _http_log_resp(self, resp): + if not self.debug: + return + _logger.debug( + "RESP: [%s] %s\n", + resp.status_code, + resp.headers) + if resp._content_consumed: + _logger.debug( + "RESP BODY: %s\n", + resp.text) + + def serialize(self, kwargs): + if kwargs.get('json') is not None: + kwargs['headers']['Content-Type'] = 'application/json' + kwargs['data'] = json.dumps(kwargs['json']) + try: + del kwargs['json'] + except KeyError: + pass + + def get_timings(self): + return self.times + + def reset_timings(self): + self.times = [] + + def request(self, method, url, **kwargs): + """Send an http request with the specified characteristics. + + Wrapper around `requests.Session.request` to handle tasks such as + setting headers, JSON encoding/decoding, and error handling. + + :param method: method of HTTP request + :param url: URL of HTTP request + :param kwargs: any other parameter that can be passed to +' requests.Session.request (such as `headers`) or `json` + that will be encoded as JSON and used as `data` argument + """ + kwargs.setdefault("headers", kwargs.get("headers", {})) + kwargs["headers"]["User-Agent"] = self.user_agent + if self.original_ip: + kwargs["headers"]["Forwarded"] = "for=%s;by=%s" % ( + self.original_ip, self.user_agent) + if self.timeout is not None: + kwargs.setdefault("timeout", self.timeout) + kwargs.setdefault("verify", self.verify) + if self.cert is not None: + kwargs.setdefault("cert", self.cert) + self.serialize(kwargs) + + self._http_log_req(method, url, kwargs) + if self.timings: + start_time = time.time() + resp = self.http.request(method, url, **kwargs) + if self.timings: + self.times.append(("%s %s" % (method, url), + start_time, time.time())) + self._http_log_resp(resp) + + if resp.status_code >= 400: + _logger.debug( + "Request returned failure status: %s", + resp.status_code) + raise exceptions.from_response(resp, method, url) + + return resp + + @staticmethod + def concat_url(endpoint, url): + """Concatenate endpoint and final URL. + + E.g., "http://keystone/v2.0/" and "/tokens" are concatenated to + "http://keystone/v2.0/tokens". + + :param endpoint: the base URL + :param url: the final URL + """ + return "%s/%s" % (endpoint.rstrip("/"), url.strip("/")) + + def client_request(self, client, method, url, **kwargs): + """Send an http request using `client`'s endpoint and specified `url`. + + If request was rejected as unauthorized (possibly because the token is + expired), issue one authorization attempt and send the request once + again. + + :param client: instance of BaseClient descendant + :param method: method of HTTP request + :param url: URL of HTTP request + :param kwargs: any other parameter that can be passed to +' `HTTPClient.request` + """ + + filter_args = { + "endpoint_type": client.endpoint_type or self.endpoint_type, + "service_type": client.service_type, + } + token, endpoint = (self.cached_token, client.cached_endpoint) + just_authenticated = False + if not (token and endpoint): + try: + token, endpoint = self.auth_plugin.token_and_endpoint( + **filter_args) + except exceptions.EndpointException: + pass + if not (token and endpoint): + self.authenticate() + just_authenticated = True + token, endpoint = self.auth_plugin.token_and_endpoint( + **filter_args) + if not (token and endpoint): + raise exceptions.AuthorizationFailure( + "Cannot find endpoint or token for request") + + old_token_endpoint = (token, endpoint) + kwargs.setdefault("headers", {})["X-Auth-Token"] = token + self.cached_token = token + client.cached_endpoint = endpoint + # Perform the request once. If we get Unauthorized, then it + # might be because the auth token expired, so try to + # re-authenticate and try again. If it still fails, bail. + try: + return self.request( + method, self.concat_url(endpoint, url), **kwargs) + except exceptions.Unauthorized as unauth_ex: + if just_authenticated: + raise + self.cached_token = None + client.cached_endpoint = None + self.authenticate() + try: + token, endpoint = self.auth_plugin.token_and_endpoint( + **filter_args) + except exceptions.EndpointException: + raise unauth_ex + if (not (token and endpoint) or + old_token_endpoint == (token, endpoint)): + raise unauth_ex + self.cached_token = token + client.cached_endpoint = endpoint + kwargs["headers"]["X-Auth-Token"] = token + return self.request( + method, self.concat_url(endpoint, url), **kwargs) + + def add_client(self, base_client_instance): + """Add a new instance of :class:`BaseClient` descendant. + + `self` will store a reference to `base_client_instance`. + + Example: + + >>> def test_clients(): + ... from keystoneclient.auth import keystone + ... from openstack.common.apiclient import client + ... auth = keystone.KeystoneAuthPlugin( + ... username="user", password="pass", tenant_name="tenant", + ... auth_url="http://auth:5000/v2.0") + ... openstack_client = client.HTTPClient(auth) + ... # create nova client + ... from novaclient.v1_1 import client + ... client.Client(openstack_client) + ... # create keystone client + ... from keystoneclient.v2_0 import client + ... client.Client(openstack_client) + ... # use them + ... openstack_client.identity.tenants.list() + ... openstack_client.compute.servers.list() + """ + service_type = base_client_instance.service_type + if service_type and not hasattr(self, service_type): + setattr(self, service_type, base_client_instance) + + def authenticate(self): + self.auth_plugin.authenticate(self) + # Store the authentication results in the keyring for later requests + if self.keyring_saver: + self.keyring_saver.save(self) + + +class BaseClient(object): + """Top-level object to access the OpenStack API. + + This client uses :class:`HTTPClient` to send requests. :class:`HTTPClient` + will handle a bunch of issues such as authentication. + """ + + service_type = None + endpoint_type = None # "publicURL" will be used + cached_endpoint = None + + def __init__(self, http_client, extensions=None): + self.http_client = http_client + http_client.add_client(self) + + # Add in any extensions... + if extensions: + for extension in extensions: + if extension.manager_class: + setattr(self, extension.name, + extension.manager_class(self)) + + def client_request(self, method, url, **kwargs): + return self.http_client.client_request( + self, method, url, **kwargs) + + def head(self, url, **kwargs): + return self.client_request("HEAD", url, **kwargs) + + def get(self, url, **kwargs): + return self.client_request("GET", url, **kwargs) + + def post(self, url, **kwargs): + return self.client_request("POST", url, **kwargs) + + def put(self, url, **kwargs): + return self.client_request("PUT", url, **kwargs) + + def delete(self, url, **kwargs): + return self.client_request("DELETE", url, **kwargs) + + def patch(self, url, **kwargs): + return self.client_request("PATCH", url, **kwargs) + + @staticmethod + def get_class(api_name, version, version_map): + """Returns the client class for the requested API version + + :param api_name: the name of the API, e.g. 'compute', 'image', etc + :param version: the requested API version + :param version_map: a dict of client classes keyed by version + :rtype: a client class for the requested API version + """ + try: + client_path = version_map[str(version)] + except (KeyError, ValueError): + msg = "Invalid %s client version '%s'. must be one of: %s" % ( + (api_name, version, ', '.join(version_map.keys()))) + raise exceptions.UnsupportedVersion(msg) + + return importutils.import_class(client_path) diff -Nru python-novaclient-2.15.0/novaclient/openstack/common/apiclient/exceptions.py python-novaclient-2.16.0/novaclient/openstack/common/apiclient/exceptions.py --- python-novaclient-2.15.0/novaclient/openstack/common/apiclient/exceptions.py 1970-01-01 00:00:00.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/openstack/common/apiclient/exceptions.py 2014-02-26 16:28:51.000000000 +0000 @@ -0,0 +1,439 @@ +# Copyright 2010 Jacob Kaplan-Moss +# Copyright 2011 Nebula, Inc. +# Copyright 2013 Alessio Ababilov +# Copyright 2013 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. + +""" +Exception definitions. +""" + +import inspect +import sys + +import six + + +class ClientException(Exception): + """The base exception class for all exceptions this library raises. + """ + pass + + +class MissingArgs(ClientException): + """Supplied arguments are not sufficient for calling a function.""" + def __init__(self, missing): + self.missing = missing + msg = "Missing argument(s): %s" % ", ".join(missing) + super(MissingArgs, self).__init__(msg) + + +class ValidationError(ClientException): + """Error in validation on API client side.""" + pass + + +class UnsupportedVersion(ClientException): + """User is trying to use an unsupported version of the API.""" + pass + + +class CommandError(ClientException): + """Error in CLI tool.""" + pass + + +class AuthorizationFailure(ClientException): + """Cannot authorize API client.""" + pass + + +class AuthPluginOptionsMissing(AuthorizationFailure): + """Auth plugin misses some options.""" + def __init__(self, opt_names): + super(AuthPluginOptionsMissing, self).__init__( + "Authentication failed. Missing options: %s" % + ", ".join(opt_names)) + self.opt_names = opt_names + + +class AuthSystemNotFound(AuthorizationFailure): + """User has specified a AuthSystem that is not installed.""" + def __init__(self, auth_system): + super(AuthSystemNotFound, self).__init__( + "AuthSystemNotFound: %s" % repr(auth_system)) + self.auth_system = auth_system + + +class NoUniqueMatch(ClientException): + """Multiple entities found instead of one.""" + pass + + +class EndpointException(ClientException): + """Something is rotten in Service Catalog.""" + pass + + +class EndpointNotFound(EndpointException): + """Could not find requested endpoint in Service Catalog.""" + pass + + +class AmbiguousEndpoints(EndpointException): + """Found more than one matching endpoint in Service Catalog.""" + def __init__(self, endpoints=None): + super(AmbiguousEndpoints, self).__init__( + "AmbiguousEndpoints: %s" % repr(endpoints)) + self.endpoints = endpoints + + +class HttpError(ClientException): + """The base exception class for all HTTP exceptions. + """ + http_status = 0 + message = "HTTP Error" + + def __init__(self, message=None, details=None, + response=None, request_id=None, + url=None, method=None, http_status=None): + self.http_status = http_status or self.http_status + self.message = message or self.message + self.details = details + self.request_id = request_id + self.response = response + self.url = url + self.method = method + formatted_string = "%s (HTTP %s)" % (self.message, self.http_status) + if request_id: + formatted_string += " (Request-ID: %s)" % request_id + super(HttpError, self).__init__(formatted_string) + + +class HTTPClientError(HttpError): + """Client-side HTTP error. + + Exception for cases in which the client seems to have erred. + """ + message = "HTTP Client Error" + + +class HttpServerError(HttpError): + """Server-side HTTP error. + + Exception for cases in which the server is aware that it has + erred or is incapable of performing the request. + """ + message = "HTTP Server Error" + + +class BadRequest(HTTPClientError): + """HTTP 400 - Bad Request. + + The request cannot be fulfilled due to bad syntax. + """ + http_status = 400 + message = "Bad Request" + + +class Unauthorized(HTTPClientError): + """HTTP 401 - Unauthorized. + + Similar to 403 Forbidden, but specifically for use when authentication + is required and has failed or has not yet been provided. + """ + http_status = 401 + message = "Unauthorized" + + +class PaymentRequired(HTTPClientError): + """HTTP 402 - Payment Required. + + Reserved for future use. + """ + http_status = 402 + message = "Payment Required" + + +class Forbidden(HTTPClientError): + """HTTP 403 - Forbidden. + + The request was a valid request, but the server is refusing to respond + to it. + """ + http_status = 403 + message = "Forbidden" + + +class NotFound(HTTPClientError): + """HTTP 404 - Not Found. + + The requested resource could not be found but may be available again + in the future. + """ + http_status = 404 + message = "Not Found" + + +class MethodNotAllowed(HTTPClientError): + """HTTP 405 - Method Not Allowed. + + A request was made of a resource using a request method not supported + by that resource. + """ + http_status = 405 + message = "Method Not Allowed" + + +class NotAcceptable(HTTPClientError): + """HTTP 406 - Not Acceptable. + + The requested resource is only capable of generating content not + acceptable according to the Accept headers sent in the request. + """ + http_status = 406 + message = "Not Acceptable" + + +class ProxyAuthenticationRequired(HTTPClientError): + """HTTP 407 - Proxy Authentication Required. + + The client must first authenticate itself with the proxy. + """ + http_status = 407 + message = "Proxy Authentication Required" + + +class RequestTimeout(HTTPClientError): + """HTTP 408 - Request Timeout. + + The server timed out waiting for the request. + """ + http_status = 408 + message = "Request Timeout" + + +class Conflict(HTTPClientError): + """HTTP 409 - Conflict. + + Indicates that the request could not be processed because of conflict + in the request, such as an edit conflict. + """ + http_status = 409 + message = "Conflict" + + +class Gone(HTTPClientError): + """HTTP 410 - Gone. + + Indicates that the resource requested is no longer available and will + not be available again. + """ + http_status = 410 + message = "Gone" + + +class LengthRequired(HTTPClientError): + """HTTP 411 - Length Required. + + The request did not specify the length of its content, which is + required by the requested resource. + """ + http_status = 411 + message = "Length Required" + + +class PreconditionFailed(HTTPClientError): + """HTTP 412 - Precondition Failed. + + The server does not meet one of the preconditions that the requester + put on the request. + """ + http_status = 412 + message = "Precondition Failed" + + +class RequestEntityTooLarge(HTTPClientError): + """HTTP 413 - Request Entity Too Large. + + The request is larger than the server is willing or able to process. + """ + http_status = 413 + message = "Request Entity Too Large" + + def __init__(self, *args, **kwargs): + try: + self.retry_after = int(kwargs.pop('retry_after')) + except (KeyError, ValueError): + self.retry_after = 0 + + super(RequestEntityTooLarge, self).__init__(*args, **kwargs) + + +class RequestUriTooLong(HTTPClientError): + """HTTP 414 - Request-URI Too Long. + + The URI provided was too long for the server to process. + """ + http_status = 414 + message = "Request-URI Too Long" + + +class UnsupportedMediaType(HTTPClientError): + """HTTP 415 - Unsupported Media Type. + + The request entity has a media type which the server or resource does + not support. + """ + http_status = 415 + message = "Unsupported Media Type" + + +class RequestedRangeNotSatisfiable(HTTPClientError): + """HTTP 416 - Requested Range Not Satisfiable. + + The client has asked for a portion of the file, but the server cannot + supply that portion. + """ + http_status = 416 + message = "Requested Range Not Satisfiable" + + +class ExpectationFailed(HTTPClientError): + """HTTP 417 - Expectation Failed. + + The server cannot meet the requirements of the Expect request-header field. + """ + http_status = 417 + message = "Expectation Failed" + + +class UnprocessableEntity(HTTPClientError): + """HTTP 422 - Unprocessable Entity. + + The request was well-formed but was unable to be followed due to semantic + errors. + """ + http_status = 422 + message = "Unprocessable Entity" + + +class InternalServerError(HttpServerError): + """HTTP 500 - Internal Server Error. + + A generic error message, given when no more specific message is suitable. + """ + http_status = 500 + message = "Internal Server Error" + + +# NotImplemented is a python keyword. +class HttpNotImplemented(HttpServerError): + """HTTP 501 - Not Implemented. + + The server either does not recognize the request method, or it lacks + the ability to fulfill the request. + """ + http_status = 501 + message = "Not Implemented" + + +class BadGateway(HttpServerError): + """HTTP 502 - Bad Gateway. + + The server was acting as a gateway or proxy and received an invalid + response from the upstream server. + """ + http_status = 502 + message = "Bad Gateway" + + +class ServiceUnavailable(HttpServerError): + """HTTP 503 - Service Unavailable. + + The server is currently unavailable. + """ + http_status = 503 + message = "Service Unavailable" + + +class GatewayTimeout(HttpServerError): + """HTTP 504 - Gateway Timeout. + + The server was acting as a gateway or proxy and did not receive a timely + response from the upstream server. + """ + http_status = 504 + message = "Gateway Timeout" + + +class HttpVersionNotSupported(HttpServerError): + """HTTP 505 - HttpVersion Not Supported. + + The server does not support the HTTP protocol version used in the request. + """ + http_status = 505 + message = "HTTP Version Not Supported" + + +# _code_map contains all the classes that have http_status attribute. +_code_map = dict( + (getattr(obj, 'http_status', None), obj) + for name, obj in six.iteritems(vars(sys.modules[__name__])) + if inspect.isclass(obj) and getattr(obj, 'http_status', False) +) + + +def from_response(response, method, url): + """Returns an instance of :class:`HttpError` or subclass based on response. + + :param response: instance of `requests.Response` class + :param method: HTTP method used for request + :param url: URL used for request + """ + kwargs = { + "http_status": response.status_code, + "response": response, + "method": method, + "url": url, + "request_id": response.headers.get("x-compute-request-id"), + } + if "retry-after" in response.headers: + kwargs["retry_after"] = response.headers["retry-after"] + + content_type = response.headers.get("Content-Type", "") + if content_type.startswith("application/json"): + try: + body = response.json() + except ValueError: + pass + else: + if hasattr(body, "keys"): + error = body[body.keys()[0]] + kwargs["message"] = error.get("message") + kwargs["details"] = error.get("details") + elif content_type.startswith("text/"): + kwargs["details"] = response.text + + try: + cls = _code_map[response.status_code] + except KeyError: + if 500 <= response.status_code < 600: + cls = HttpServerError + elif 400 <= response.status_code < 500: + cls = HTTPClientError + else: + cls = HttpError + return cls(**kwargs) diff -Nru python-novaclient-2.15.0/novaclient/openstack/common/apiclient/fake_client.py python-novaclient-2.16.0/novaclient/openstack/common/apiclient/fake_client.py --- python-novaclient-2.15.0/novaclient/openstack/common/apiclient/fake_client.py 1970-01-01 00:00:00.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/openstack/common/apiclient/fake_client.py 2014-02-26 16:28:51.000000000 +0000 @@ -0,0 +1,174 @@ +# Copyright 2013 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 fake server that "responds" to API methods with pre-canned responses. + +All of these responses come from the spec, so if for some reason the spec's +wrong the tests might raise AssertionError. I've indicated in comments the +places where actual behavior differs from the spec. +""" + +# W0102: Dangerous default value %s as argument +# pylint: disable=W0102 + +import json + +import requests +import six + +from novaclient.openstack.common.apiclient import client +from novaclient.openstack.common.py3kcompat import urlutils +from novaclient.openstack.common import strutils + + +def assert_has_keys(dct, required=[], optional=[]): + for k in required: + try: + assert k in dct + except AssertionError: + extra_keys = set(dct.keys()).difference(set(required + optional)) + raise AssertionError("found unexpected keys: %s" % + list(extra_keys)) + + +class TestResponse(requests.Response): + """Wrap requests.Response and provide a convenient initialization. + """ + + def __init__(self, data): + super(TestResponse, self).__init__() + self._content_consumed = True + if isinstance(data, dict): + self.status_code = data.get('status_code', 200) + # Fake the text attribute to streamline Response creation + text = data.get('text', "") + if isinstance(text, (dict, list)): + self._content = json.dumps(text) + default_headers = { + "Content-Type": "application/json", + } + else: + self._content = text + default_headers = {} + if six.PY3 and isinstance(self._content, six.string_types): + self._content = strutils.safe_encode(self._content) + self.headers = data.get('headers') or default_headers + else: + self.status_code = data + + def __eq__(self, other): + return (self.status_code == other.status_code and + self.headers == other.headers and + self._content == other._content) + + +class FakeHTTPClient(client.HTTPClient): + + def __init__(self, *args, **kwargs): + self.callstack = [] + self.fixtures = kwargs.pop("fixtures", None) or {} + if not args and not "auth_plugin" in kwargs: + args = (None, ) + super(FakeHTTPClient, self).__init__(*args, **kwargs) + + def assert_called(self, method, url, body=None, pos=-1): + """Assert than an API method was just called. + """ + expected = (method, url) + called = self.callstack[pos][0:2] + assert self.callstack, \ + "Expected %s %s but no calls were made." % expected + + assert expected == called, 'Expected %s %s; got %s %s' % \ + (expected + called) + + if body is not None: + if self.callstack[pos][3] != body: + raise AssertionError('%r != %r' % + (self.callstack[pos][3], body)) + + def assert_called_anytime(self, method, url, body=None): + """Assert than an API method was called anytime in the test. + """ + expected = (method, url) + + assert self.callstack, \ + "Expected %s %s but no calls were made." % expected + + found = False + entry = None + for entry in self.callstack: + if expected == entry[0:2]: + found = True + break + + assert found, 'Expected %s %s; got %s' % \ + (method, url, self.callstack) + if body is not None: + assert entry[3] == body, "%s != %s" % (entry[3], body) + + self.callstack = [] + + def clear_callstack(self): + self.callstack = [] + + def authenticate(self): + pass + + def client_request(self, client, method, url, **kwargs): + # Check that certain things are called correctly + if method in ["GET", "DELETE"]: + assert "json" not in kwargs + + # Note the call + self.callstack.append( + (method, + url, + kwargs.get("headers") or {}, + kwargs.get("json") or kwargs.get("data"))) + try: + fixture = self.fixtures[url][method] + except KeyError: + pass + else: + return TestResponse({"headers": fixture[0], + "text": fixture[1]}) + + # Call the method + args = urlutils.parse_qsl(urlutils.urlparse(url)[4]) + kwargs.update(args) + munged_url = url.rsplit('?', 1)[0] + munged_url = munged_url.strip('/').replace('/', '_').replace('.', '_') + munged_url = munged_url.replace('-', '_') + + callback = "%s_%s" % (method.lower(), munged_url) + + if not hasattr(self, callback): + raise AssertionError('Called unknown API method: %s %s, ' + 'expected fakes method name: %s' % + (method, url, callback)) + + resp = getattr(self, callback)(**kwargs) + if len(resp) == 3: + status, headers, body = resp + else: + status, body = resp + headers = {} + return TestResponse({ + "status_code": status, + "text": body, + "headers": headers, + }) diff -Nru python-novaclient-2.15.0/novaclient/openstack/common/apiclient/__init__.py python-novaclient-2.16.0/novaclient/openstack/common/apiclient/__init__.py --- python-novaclient-2.15.0/novaclient/openstack/common/apiclient/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/openstack/common/apiclient/__init__.py 2014-02-26 16:28:51.000000000 +0000 @@ -0,0 +1,14 @@ +# Copyright 2013 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. diff -Nru python-novaclient-2.15.0/novaclient/openstack/common/cliutils.py python-novaclient-2.16.0/novaclient/openstack/common/cliutils.py --- python-novaclient-2.15.0/novaclient/openstack/common/cliutils.py 1970-01-01 00:00:00.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/openstack/common/cliutils.py 2014-02-26 16:28:51.000000000 +0000 @@ -0,0 +1,213 @@ +# 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. + +# W0603: Using the global statement +# W0621: Redefining name %s from outer scope +# pylint: disable=W0603,W0621 + +import getpass +import inspect +import os +import sys +import textwrap + +import prettytable +import six +from six import moves + +from novaclient.openstack.common.apiclient import exceptions +from novaclient.openstack.common import strutils + + +def validate_args(fn, *args, **kwargs): + """Check that the supplied args are sufficient for calling a function. + + >>> validate_args(lambda a: None) + Traceback (most recent call last): + ... + MissingArgs: Missing argument(s): a + >>> validate_args(lambda a, b, c, d: None, 0, c=1) + Traceback (most recent call last): + ... + MissingArgs: Missing argument(s): b, d + + :param fn: the function to check + :param arg: the positional arguments supplied + :param kwargs: the keyword arguments supplied + """ + argspec = inspect.getargspec(fn) + + num_defaults = len(argspec.defaults or []) + required_args = argspec.args[:len(argspec.args) - num_defaults] + + def isbound(method): + return getattr(method, 'im_self', None) is not None + + if isbound(fn): + required_args.pop(0) + + missing = [arg for arg in required_args if arg not in kwargs] + missing = missing[len(args):] + if missing: + raise exceptions.MissingArgs(missing) + + +def arg(*args, **kwargs): + """Decorator for CLI args. + + Example: + + >>> @arg("name", help="Name of the new entity") + ... def entity_create(args): + ... pass + """ + def _decorator(func): + add_arg(func, *args, **kwargs) + return func + return _decorator + + +def env(*args, **kwargs): + """Returns the first environment variable set. + + If all are empty, defaults to '' or keyword arg `default`. + """ + for arg in args: + value = os.environ.get(arg) + if value: + return value + return kwargs.get('default', '') + + +def add_arg(func, *args, **kwargs): + """Bind CLI arguments to a shell.py `do_foo` function.""" + + if not hasattr(func, 'arguments'): + func.arguments = [] + + # NOTE(sirp): avoid dups that can occur when the module is shared across + # tests. + if (args, kwargs) not in func.arguments: + # Because of the semantics of decorator composition if we just append + # to the options list positional options will appear to be backwards. + func.arguments.insert(0, (args, kwargs)) + + +def unauthenticated(func): + """Adds 'unauthenticated' attribute to decorated function. + + Usage: + + >>> @unauthenticated + ... def mymethod(f): + ... pass + """ + func.unauthenticated = True + return func + + +def isunauthenticated(func): + """Checks if the function does not require authentication. + + Mark such functions with the `@unauthenticated` decorator. + + :returns: bool + """ + return getattr(func, 'unauthenticated', False) + + +def print_list(objs, fields, formatters=None, sortby_index=0, + mixed_case_fields=None): + """Print a list or objects as a table, one row per object. + + :param objs: iterable of :class:`Resource` + :param fields: attributes that correspond to columns, in order + :param formatters: `dict` of callables for field formatting + :param sortby_index: index of the field for sorting table rows + :param mixed_case_fields: fields corresponding to object attributes that + have mixed case names (e.g., 'serverId') + """ + formatters = formatters or {} + mixed_case_fields = mixed_case_fields or [] + if sortby_index is None: + kwargs = {} + else: + kwargs = {'sortby': fields[sortby_index]} + pt = prettytable.PrettyTable(fields, caching=False) + pt.align = 'l' + + for o in objs: + row = [] + for field in fields: + if field in formatters: + row.append(formatters[field](o)) + else: + if field in mixed_case_fields: + field_name = field.replace(' ', '_') + else: + field_name = field.lower().replace(' ', '_') + data = getattr(o, field_name, '') + row.append(data) + pt.add_row(row) + + print(strutils.safe_encode(pt.get_string(**kwargs))) + + +def print_dict(dct, dict_property="Property", wrap=0): + """Print a `dict` as a table of two columns. + + :param dct: `dict` to print + :param dict_property: name of the first column + :param wrap: wrapping for the second column + """ + pt = prettytable.PrettyTable([dict_property, 'Value'], caching=False) + pt.align = 'l' + for k, v in six.iteritems(dct): + # convert dict to str to check length + if isinstance(v, dict): + v = str(v) + if wrap > 0: + v = textwrap.fill(str(v), wrap) + # if value has a newline, add in multiple rows + # e.g. fault with stacktrace + if v and isinstance(v, six.string_types) and r'\n' in v: + lines = v.strip().split(r'\n') + col1 = k + for line in lines: + pt.add_row([col1, line]) + col1 = '' + else: + pt.add_row([k, v]) + print(strutils.safe_encode(pt.get_string())) + + +def get_password(max_password_prompts=3): + """Read password from TTY.""" + verify = strutils.bool_from_string(env("OS_VERIFY_PASSWORD")) + pw = None + if hasattr(sys.stdin, "isatty") and sys.stdin.isatty(): + # Check for Ctrl-D + try: + for _ in moves.range(max_password_prompts): + pw1 = getpass.getpass("OS Password: ") + if verify: + pw2 = getpass.getpass("Please verify: ") + else: + pw2 = pw1 + if pw1 == pw2 and pw1: + pw = pw1 + break + except EOFError: + pass + return pw diff -Nru python-novaclient-2.15.0/novaclient/openstack/common/gettextutils.py python-novaclient-2.16.0/novaclient/openstack/common/gettextutils.py --- python-novaclient-2.15.0/novaclient/openstack/common/gettextutils.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/openstack/common/gettextutils.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,5 +1,3 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - # Copyright 2012 Red Hat, Inc. # Copyright 2013 IBM Corp. # All Rights Reserved. @@ -26,13 +24,10 @@ import copy import gettext -import logging +import locale +from logging import handlers import os import re -try: - import UserString as _userString -except ImportError: - import collections as _userString from babel import localedata import six @@ -58,8 +53,10 @@ def _(msg): if USE_LAZY: - return Message(msg, 'novaclient') + return Message(msg, domain='novaclient') else: + if six.PY3: + return _t.gettext(msg) return _t.ugettext(msg) @@ -88,11 +85,6 @@ # messages in OpenStack. We override the standard _() function # and % (format string) operation to build Message objects that can # later be translated when we have more information. - # - # Also included below is an example LocaleHandler that translates - # Messages to an associated locale, effectively allowing many logs, - # each with their own locale. - def _lazy_gettext(msg): """Create and return a Message object. @@ -103,159 +95,183 @@ Message encapsulates a string so that we can translate it later when needed. """ - return Message(msg, domain) + return Message(msg, domain=domain) - import __builtin__ - __builtin__.__dict__['_'] = _lazy_gettext + from six import moves + moves.builtins.__dict__['_'] = _lazy_gettext else: localedir = '%s_LOCALEDIR' % domain.upper() - gettext.install(domain, - localedir=os.environ.get(localedir), - unicode=True) - - -class Message(_userString.UserString, object): - """Class used to encapsulate translatable messages.""" - def __init__(self, msg, domain): - # _msg is the gettext msgid and should never change - self._msg = msg - self._left_extra_msg = '' - self._right_extra_msg = '' - self.params = None - self.locale = None - self.domain = domain - - @property - def data(self): - # NOTE(mrodden): this should always resolve to a unicode string - # that best represents the state of the message currently - - localedir = os.environ.get(self.domain.upper() + '_LOCALEDIR') - if self.locale: - lang = gettext.translation(self.domain, - localedir=localedir, - languages=[self.locale], - fallback=True) + if six.PY3: + gettext.install(domain, + localedir=os.environ.get(localedir)) else: - # use system locale for translations - lang = gettext.translation(self.domain, - localedir=localedir, - fallback=True) - - full_msg = (self._left_extra_msg + - lang.ugettext(self._msg) + - self._right_extra_msg) - - if self.params is not None: - full_msg = full_msg % self.params - - return six.text_type(full_msg) - - def _save_dictionary_parameter(self, dict_param): - full_msg = self.data - # look for %(blah) fields in string; - # ignore %% and deal with the - # case where % is first character on the line - keys = re.findall('(?:[^%]|^)?%\((\w*)\)[a-z]', full_msg) - - # if we don't find any %(blah) blocks but have a %s - if not keys and re.findall('(?:[^%]|^)%[a-z]', full_msg): - # apparently the full dictionary is the parameter - params = copy.deepcopy(dict_param) + gettext.install(domain, + localedir=os.environ.get(localedir), + unicode=True) + + +class Message(six.text_type): + """A Message object is a unicode object that can be translated. + + Translation of Message is done explicitly using the translate() method. + For all non-translation intents and purposes, a Message is simply unicode, + and can be treated as such. + """ + + def __new__(cls, msgid, msgtext=None, params=None, domain='novaclient', *args): + """Create a new Message object. + + In order for translation to work gettext requires a message ID, this + msgid will be used as the base unicode text. It is also possible + for the msgid and the base unicode text to be different by passing + the msgtext parameter. + """ + # If the base msgtext is not given, we use the default translation + # of the msgid (which is in English) just in case the system locale is + # not English, so that the base text will be in that locale by default. + if not msgtext: + msgtext = Message._translate_msgid(msgid, domain) + # We want to initialize the parent unicode with the actual object that + # would have been plain unicode if 'Message' was not enabled. + msg = super(Message, cls).__new__(cls, msgtext) + msg.msgid = msgid + msg.domain = domain + msg.params = params + return msg + + def translate(self, desired_locale=None): + """Translate this message to the desired locale. + + :param desired_locale: The desired locale to translate the message to, + if no locale is provided the message will be + translated to the system's default locale. + + :returns: the translated message in unicode + """ + + translated_message = Message._translate_msgid(self.msgid, + self.domain, + desired_locale) + if self.params is None: + # No need for more translation + return translated_message + + # This Message object may have been formatted with one or more + # Message objects as substitution arguments, given either as a single + # argument, part of a tuple, or as one or more values in a dictionary. + # When translating this Message we need to translate those Messages too + translated_params = _translate_args(self.params, desired_locale) + + translated_message = translated_message % translated_params + + return translated_message + + @staticmethod + def _translate_msgid(msgid, domain, desired_locale=None): + if not desired_locale: + system_locale = locale.getdefaultlocale() + # If the system locale is not available to the runtime use English + if not system_locale[0]: + desired_locale = 'en_US' + else: + desired_locale = system_locale[0] + + locale_dir = os.environ.get(domain.upper() + '_LOCALEDIR') + lang = gettext.translation(domain, + localedir=locale_dir, + languages=[desired_locale], + fallback=True) + if six.PY3: + translator = lang.gettext else: - params = {} - for key in keys: - try: - params[key] = copy.deepcopy(dict_param[key]) - except TypeError: - # cast uncopyable thing to unicode string - params[key] = unicode(dict_param[key]) + translator = lang.ugettext - return params + translated_message = translator(msgid) + return translated_message - def _save_parameters(self, other): - # we check for None later to see if - # we actually have parameters to inject, - # so encapsulate if our parameter is actually None + def __mod__(self, other): + # When we mod a Message we want the actual operation to be performed + # by the parent class (i.e. unicode()), the only thing we do here is + # save the original msgid and the parameters in case of a translation + params = self._sanitize_mod_params(other) + unicode_mod = super(Message, self).__mod__(params) + modded = Message(self.msgid, + msgtext=unicode_mod, + params=params, + domain=self.domain) + return modded + + def _sanitize_mod_params(self, other): + """Sanitize the object being modded with this Message. + + - Add support for modding 'None' so translation supports it + - Trim the modded object, which can be a large dictionary, to only + those keys that would actually be used in a translation + - Snapshot the object being modded, in case the message is + translated, it will be used as it was when the Message was created + """ if other is None: - self.params = (other, ) + params = (other,) elif isinstance(other, dict): - self.params = self._save_dictionary_parameter(other) + params = self._trim_dictionary_parameters(other) else: - # fallback to casting to unicode, - # this will handle the problematic python code-like - # objects that cannot be deep-copied - try: - self.params = copy.deepcopy(other) - except TypeError: - self.params = unicode(other) - - return self - - # overrides to be more string-like - def __unicode__(self): - return self.data + params = self._copy_param(other) + return params - def __str__(self): - return self.data.encode('utf-8') + def _trim_dictionary_parameters(self, dict_param): + """Return a dict that only has matching entries in the msgid.""" + # NOTE(luisg): Here we trim down the dictionary passed as parameters + # to avoid carrying a lot of unnecessary weight around in the message + # object, for example if someone passes in Message() % locals() but + # only some params are used, and additionally we prevent errors for + # non-deepcopyable objects by unicoding() them. + + # Look for %(param) keys in msgid; + # Skip %% and deal with the case where % is first character on the line + keys = re.findall('(?:[^%]|^)?%\((\w*)\)[a-z]', self.msgid) + + # If we don't find any %(param) keys but have a %s + if not keys and re.findall('(?:[^%]|^)%[a-z]', self.msgid): + # Apparently the full dictionary is the parameter + params = self._copy_param(dict_param) + else: + params = {} + # Save our existing parameters as defaults to protect + # ourselves from losing values if we are called through an + # (erroneous) chain that builds a valid Message with + # arguments, and then does something like "msg % kwds" + # where kwds is an empty dictionary. + src = {} + if isinstance(self.params, dict): + src.update(self.params) + src.update(dict_param) + for key in keys: + params[key] = self._copy_param(src[key]) + + return params - def __getstate__(self): - to_copy = ['_msg', '_right_extra_msg', '_left_extra_msg', - 'domain', 'params', 'locale'] - new_dict = self.__dict__.fromkeys(to_copy) - for attr in to_copy: - new_dict[attr] = copy.deepcopy(self.__dict__[attr]) - - return new_dict - - def __setstate__(self, state): - for (k, v) in state.items(): - setattr(self, k, v) + def _copy_param(self, param): + try: + return copy.deepcopy(param) + except TypeError: + # Fallback to casting to unicode this will handle the + # python code-like objects that can't be deep-copied + return six.text_type(param) - # operator overloads def __add__(self, other): - copied = copy.deepcopy(self) - copied._right_extra_msg += other.__str__() - return copied + msg = _('Message objects do not support addition.') + raise TypeError(msg) def __radd__(self, other): - copied = copy.deepcopy(self) - copied._left_extra_msg += other.__str__() - return copied + return self.__add__(other) - def __mod__(self, other): - # do a format string to catch and raise - # any possible KeyErrors from missing parameters - self.data % other - copied = copy.deepcopy(self) - return copied._save_parameters(other) - - def __mul__(self, other): - return self.data * other - - def __rmul__(self, other): - return other * self.data - - def __getitem__(self, key): - return self.data[key] - - def __getslice__(self, start, end): - return self.data.__getslice__(start, end) - - def __getattribute__(self, name): - # NOTE(mrodden): handle lossy operations that we can't deal with yet - # These override the UserString implementation, since UserString - # uses our __class__ attribute to try and build a new message - # after running the inner data string through the operation. - # At that point, we have lost the gettext message id and can just - # safely resolve to a string instead. - ops = ['capitalize', 'center', 'decode', 'encode', - 'expandtabs', 'ljust', 'lstrip', 'replace', 'rjust', 'rstrip', - 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill'] - if name in ops: - return getattr(self.data, name) - else: - return _userString.UserString.__getattribute__(self, name) + def __str__(self): + # NOTE(luisg): Logging in python 2.6 tries to str() log records, + # and it expects specifically a UnicodeError in order to proceed. + msg = _('Message objects do not support str() because they may ' + 'contain non-ascii characters. ' + 'Please use unicode() or translate() instead.') + raise UnicodeError(msg) def get_available_languages(domain): @@ -277,7 +293,7 @@ # NOTE(luisg): Babel <1.0 used a function called list(), which was # renamed to locale_identifiers() in >=1.0, the requirements master list # requires >=0.9.6, uncapped, so defensively work with both. We can remove - # this check when the master list updates to >=1.0, and all projects udpate + # this check when the master list updates to >=1.0, and update all projects list_identifiers = (getattr(localedata, 'list', None) or getattr(localedata, 'locale_identifiers')) locale_identifiers = list_identifiers() @@ -288,38 +304,118 @@ return copy.copy(language_list) -def get_localized_message(message, user_locale): - """Gets a localized version of the given message in the given locale.""" - if isinstance(message, Message): - if user_locale: - message.locale = user_locale - return unicode(message) - else: - return message +def translate(obj, desired_locale=None): + """Gets the translated unicode representation of the given object. + If the object is not translatable it is returned as-is. + If the locale is None the object is translated to the system locale. -class LocaleHandler(logging.Handler): - """Handler that can have a locale associated to translate Messages. + :param obj: the object to translate + :param desired_locale: the locale to translate the message to, if None the + default system locale will be used + :returns: the translated object in unicode, or the original object if + it could not be translated + """ + message = obj + if not isinstance(message, Message): + # If the object to translate is not already translatable, + # let's first get its unicode representation + message = six.text_type(obj) + if isinstance(message, Message): + # Even after unicoding() we still need to check if we are + # running with translatable unicode before translating + return message.translate(desired_locale) + return obj + + +def _translate_args(args, desired_locale=None): + """Translates all the translatable elements of the given arguments object. + + This method is used for translating the translatable values in method + arguments which include values of tuples or dictionaries. + If the object is not a tuple or a dictionary the object itself is + translated if it is translatable. + + If the locale is None the object is translated to the system locale. + + :param args: the args to translate + :param desired_locale: the locale to translate the args to, if None the + default system locale will be used + :returns: a new args object with the translated contents of the original + """ + if isinstance(args, tuple): + return tuple(translate(v, desired_locale) for v in args) + if isinstance(args, dict): + translated_dict = {} + for (k, v) in six.iteritems(args): + translated_v = translate(v, desired_locale) + translated_dict[k] = translated_v + return translated_dict + return translate(args, desired_locale) + + +class TranslationHandler(handlers.MemoryHandler): + """Handler that translates records before logging them. + + The TranslationHandler takes a locale and a target logging.Handler object + to forward LogRecord objects to after translating them. This handler + depends on Message objects being logged, instead of regular strings. + + The handler can be configured declaratively in the logging.conf as follows: + + [handlers] + keys = translatedlog, translator + + [handler_translatedlog] + class = handlers.WatchedFileHandler + args = ('/var/log/api-localized.log',) + formatter = context + + [handler_translator] + class = openstack.common.log.TranslationHandler + target = translatedlog + args = ('zh_CN',) - A quick example of how to utilize the Message class above. - LocaleHandler takes a locale and a target logging.Handler object - to forward LogRecord objects to after translating the internal Message. + If the specified locale is not available in the system, the handler will + log in the default locale. """ - def __init__(self, locale, target): - """Initialize a LocaleHandler + def __init__(self, locale=None, target=None): + """Initialize a TranslationHandler :param locale: locale to use for translating messages :param target: logging.Handler object to forward LogRecord objects to after translation """ - logging.Handler.__init__(self) + # NOTE(luisg): In order to allow this handler to be a wrapper for + # other handlers, such as a FileHandler, and still be able to + # configure it using logging.conf, this handler has to extend + # MemoryHandler because only the MemoryHandlers' logging.conf + # parsing is implemented such that it accepts a target handler. + handlers.MemoryHandler.__init__(self, capacity=0, target=target) self.locale = locale - self.target = target + + def setFormatter(self, fmt): + self.target.setFormatter(fmt) def emit(self, record): - if isinstance(record.msg, Message): - # set the locale and resolve to a string - record.msg.locale = self.locale + # We save the message from the original record to restore it + # after translation, so other handlers are not affected by this + original_msg = record.msg + original_args = record.args + + try: + self._translate_and_log_record(record) + finally: + record.msg = original_msg + record.args = original_args + + def _translate_and_log_record(self, record): + record.msg = translate(record.msg, self.locale) + + # In addition to translating the message, we also need to translate + # arguments that were passed to the log method that were not part + # of the main message e.g., log.info(_('Some message %s'), this_one)) + record.args = _translate_args(record.args, self.locale) self.target.emit(record) diff -Nru python-novaclient-2.15.0/novaclient/openstack/common/importutils.py python-novaclient-2.16.0/novaclient/openstack/common/importutils.py --- python-novaclient-2.15.0/novaclient/openstack/common/importutils.py 1970-01-01 00:00:00.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/openstack/common/importutils.py 2014-02-26 16:28:51.000000000 +0000 @@ -0,0 +1,66 @@ +# 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 related utilities and helper functions. +""" + +import sys +import traceback + + +def import_class(import_str): + """Returns a class from a string including module and class.""" + mod_str, _sep, class_str = import_str.rpartition('.') + try: + __import__(mod_str) + return getattr(sys.modules[mod_str], class_str) + except (ValueError, AttributeError): + raise ImportError('Class %s cannot be found (%s)' % + (class_str, + traceback.format_exception(*sys.exc_info()))) + + +def import_object(import_str, *args, **kwargs): + """Import a class and return an instance of it.""" + return import_class(import_str)(*args, **kwargs) + + +def import_object_ns(name_space, import_str, *args, **kwargs): + """Tries to import object from default namespace. + + Imports a class and return an instance of it, first by trying + to find the class in a default namespace, then failing back to + a full path if not found in the default namespace. + """ + import_value = "%s.%s" % (name_space, import_str) + try: + return import_class(import_value)(*args, **kwargs) + except ImportError: + return import_class(import_str)(*args, **kwargs) + + +def import_module(import_str): + """Import a module.""" + __import__(import_str) + return sys.modules[import_str] + + +def try_import(import_str, default=None): + """Try to import a module and if it fails return default.""" + try: + return import_module(import_str) + except ImportError: + return default diff -Nru python-novaclient-2.15.0/novaclient/openstack/common/jsonutils.py python-novaclient-2.16.0/novaclient/openstack/common/jsonutils.py --- python-novaclient-2.15.0/novaclient/openstack/common/jsonutils.py 1970-01-01 00:00:00.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/openstack/common/jsonutils.py 2014-02-26 16:28:51.000000000 +0000 @@ -0,0 +1,182 @@ +# 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. + +''' +JSON related utilities. + +This module provides a few things: + + 1) A handy function for getting an object down to something that can be + JSON serialized. See to_primitive(). + + 2) Wrappers around loads() and dumps(). The dumps() wrapper will + automatically use to_primitive() for you if needed. + + 3) This sets up anyjson to use the loads() and dumps() wrappers if anyjson + is available. +''' + + +import datetime +import functools +import inspect +import itertools +import json +try: + import xmlrpclib +except ImportError: + # NOTE(jaypipes): xmlrpclib was renamed to xmlrpc.client in Python3 + # however the function and object call signatures + # remained the same. This whole try/except block should + # be removed and replaced with a call to six.moves once + # six 1.4.2 is released. See http://bit.ly/1bqrVzu + import xmlrpc.client as xmlrpclib + +import six + +from novaclient.openstack.common import gettextutils +from novaclient.openstack.common import importutils +from novaclient.openstack.common import timeutils + +netaddr = importutils.try_import("netaddr") + +_nasty_type_tests = [inspect.ismodule, inspect.isclass, inspect.ismethod, + inspect.isfunction, inspect.isgeneratorfunction, + inspect.isgenerator, inspect.istraceback, inspect.isframe, + inspect.iscode, inspect.isbuiltin, inspect.isroutine, + inspect.isabstract] + +_simple_types = (six.string_types + six.integer_types + + (type(None), bool, float)) + + +def to_primitive(value, convert_instances=False, convert_datetime=True, + level=0, max_depth=3): + """Convert a complex object into primitives. + + Handy for JSON serialization. We can optionally handle instances, + but since this is a recursive function, we could have cyclical + data structures. + + To handle cyclical data structures we could track the actual objects + visited in a set, but not all objects are hashable. Instead we just + track the depth of the object inspections and don't go too deep. + + Therefore, convert_instances=True is lossy ... be aware. + + """ + # handle obvious types first - order of basic types determined by running + # full tests on nova project, resulting in the following counts: + # 572754 + # 460353 + # 379632 + # 274610 + # 199918 + # 114200 + # 51817 + # 26164 + # 6491 + # 283 + # 19 + if isinstance(value, _simple_types): + return value + + if isinstance(value, datetime.datetime): + if convert_datetime: + return timeutils.strtime(value) + else: + return value + + # value of itertools.count doesn't get caught by nasty_type_tests + # and results in infinite loop when list(value) is called. + if type(value) == itertools.count: + return six.text_type(value) + + # FIXME(vish): Workaround for LP bug 852095. Without this workaround, + # tests that raise an exception in a mocked method that + # has a @wrap_exception with a notifier will fail. If + # we up the dependency to 0.5.4 (when it is released) we + # can remove this workaround. + if getattr(value, '__module__', None) == 'mox': + return 'mock' + + if level > max_depth: + return '?' + + # The try block may not be necessary after the class check above, + # but just in case ... + try: + recursive = functools.partial(to_primitive, + convert_instances=convert_instances, + convert_datetime=convert_datetime, + level=level, + max_depth=max_depth) + if isinstance(value, dict): + return dict((k, recursive(v)) for k, v in six.iteritems(value)) + elif isinstance(value, (list, tuple)): + return [recursive(lv) for lv in value] + + # It's not clear why xmlrpclib created their own DateTime type, but + # for our purposes, make it a datetime type which is explicitly + # handled + if isinstance(value, xmlrpclib.DateTime): + value = datetime.datetime(*tuple(value.timetuple())[:6]) + + if convert_datetime and isinstance(value, datetime.datetime): + return timeutils.strtime(value) + elif isinstance(value, gettextutils.Message): + return value.data + elif hasattr(value, 'iteritems'): + return recursive(dict(value.iteritems()), level=level + 1) + elif hasattr(value, '__iter__'): + return recursive(list(value)) + elif convert_instances and hasattr(value, '__dict__'): + # Likely an instance of something. Watch for cycles. + # Ignore class member vars. + return recursive(value.__dict__, level=level + 1) + elif netaddr and isinstance(value, netaddr.IPAddress): + return six.text_type(value) + else: + if any(test(value) for test in _nasty_type_tests): + return six.text_type(value) + return value + except TypeError: + # Class objects are tricky since they may define something like + # __iter__ defined but it isn't callable as list(). + return six.text_type(value) + + +def dumps(value, default=to_primitive, **kwargs): + return json.dumps(value, default=default, **kwargs) + + +def loads(s): + return json.loads(s) + + +def load(s): + return json.load(s) + + +try: + import anyjson +except ImportError: + pass +else: + anyjson._modules.append((__name__, 'dumps', TypeError, + 'loads', ValueError, 'load')) + anyjson.force_implementation(__name__) diff -Nru python-novaclient-2.15.0/novaclient/openstack/common/py3kcompat/__init__.py python-novaclient-2.16.0/novaclient/openstack/common/py3kcompat/__init__.py --- python-novaclient-2.15.0/novaclient/openstack/common/py3kcompat/__init__.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/openstack/common/py3kcompat/__init__.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,17 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2013 Canonical Ltd. -# 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. -# diff -Nru python-novaclient-2.15.0/novaclient/openstack/common/py3kcompat/urlutils.py python-novaclient-2.16.0/novaclient/openstack/common/py3kcompat/urlutils.py --- python-novaclient-2.15.0/novaclient/openstack/common/py3kcompat/urlutils.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/openstack/common/py3kcompat/urlutils.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,4 +1,3 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 # # Copyright 2013 Canonical Ltd. # All Rights Reserved. @@ -24,22 +23,36 @@ if six.PY3: # python3 + import urllib.error import urllib.parse + import urllib.request urlencode = urllib.parse.urlencode urljoin = urllib.parse.urljoin quote = urllib.parse.quote + quote_plus = urllib.parse.quote_plus parse_qsl = urllib.parse.parse_qsl + unquote = urllib.parse.unquote + unquote_plus = urllib.parse.unquote_plus urlparse = urllib.parse.urlparse urlsplit = urllib.parse.urlsplit urlunsplit = urllib.parse.urlunsplit + SplitResult = urllib.parse.SplitResult + + urlopen = urllib.request.urlopen + URLError = urllib.error.URLError + pathname2url = urllib.request.pathname2url else: # python2 import urllib + import urllib2 import urlparse urlencode = urllib.urlencode quote = urllib.quote + quote_plus = urllib.quote_plus + unquote = urllib.unquote + unquote_plus = urllib.unquote_plus parse = urlparse parse_qsl = parse.parse_qsl @@ -47,3 +60,8 @@ urlparse = parse.urlparse urlsplit = parse.urlsplit urlunsplit = parse.urlunsplit + SplitResult = parse.SplitResult + + urlopen = urllib2.urlopen + URLError = urllib2.URLError + pathname2url = urllib.pathname2url diff -Nru python-novaclient-2.15.0/novaclient/openstack/common/strutils.py python-novaclient-2.16.0/novaclient/openstack/common/strutils.py --- python-novaclient-2.15.0/novaclient/openstack/common/strutils.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/openstack/common/strutils.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,5 +1,3 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - # Copyright 2011 OpenStack Foundation. # All Rights Reserved. # @@ -25,7 +23,7 @@ import six -from novaclient.openstack.common.gettextutils import _ # noqa +from novaclient.openstack.common.gettextutils import _ # Used for looking up extensions of text @@ -60,12 +58,12 @@ return bool_from_string(subject) and 1 or 0 -def bool_from_string(subject, strict=False): +def bool_from_string(subject, strict=False, default=False): """Interpret a string as a boolean. A case-insensitive match is performed such that strings matching 't', 'true', 'on', 'y', 'yes', or '1' are considered True and, when - `strict=False`, anything else is considered False. + `strict=False`, anything else returns the value specified by 'default'. Useful for JSON-decoded stuff and config file parsing. @@ -90,7 +88,7 @@ 'acceptable': acceptable} raise ValueError(msg) else: - return False + return default def safe_decode(text, incoming=None, errors='strict'): @@ -101,10 +99,10 @@ values http://docs.python.org/2/library/codecs.html :returns: text or a unicode `incoming` encoded representation of it. - :raises TypeError: If text is not an isntance of str + :raises TypeError: If text is not an instance of str """ if not isinstance(text, six.string_types): - raise TypeError("%s can't be decoded" % type(text)) + raise TypeError(_("%s can't be decoded") % type(text)) if isinstance(text, six.text_type): return text @@ -144,21 +142,27 @@ values http://docs.python.org/2/library/codecs.html :returns: text or a bytestring `encoding` encoded representation of it. - :raises TypeError: If text is not an isntance of str + :raises TypeError: If text is not an instance of str """ if not isinstance(text, six.string_types): - raise TypeError("%s can't be encoded" % type(text)) + raise TypeError(_("%s can't be encoded") % type(text)) if not incoming: incoming = (sys.stdin.encoding or sys.getdefaultencoding()) if isinstance(text, six.text_type): - return text.encode(encoding, errors) + if six.PY3: + return text.encode(encoding, errors).decode(incoming) + else: + return text.encode(encoding, errors) elif text and encoding != incoming: # Decode text before encoding it with `encoding` text = safe_decode(text, incoming, errors) - return text.encode(encoding, errors) + if six.PY3: + return text.encode(encoding, errors).decode(incoming) + else: + return text.encode(encoding, errors) return text diff -Nru python-novaclient-2.15.0/novaclient/openstack/common/timeutils.py python-novaclient-2.16.0/novaclient/openstack/common/timeutils.py --- python-novaclient-2.15.0/novaclient/openstack/common/timeutils.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/openstack/common/timeutils.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,5 +1,3 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - # Copyright 2011 OpenStack Foundation. # All Rights Reserved. # @@ -50,9 +48,9 @@ try: return iso8601.parse_date(timestr) except iso8601.ParseError as e: - raise ValueError(unicode(e)) + raise ValueError(six.text_type(e)) except TypeError as e: - raise ValueError(unicode(e)) + raise ValueError(six.text_type(e)) def strtime(at=None, fmt=PERFECT_TIME_FORMAT): @@ -79,6 +77,9 @@ """Return True if before is older than seconds.""" if isinstance(before, six.string_types): before = parse_strtime(before).replace(tzinfo=None) + else: + before = before.replace(tzinfo=None) + return utcnow() - before > datetime.timedelta(seconds=seconds) @@ -86,6 +87,9 @@ """Return True if after is newer than seconds.""" if isinstance(after, six.string_types): after = parse_strtime(after).replace(tzinfo=None) + else: + after = after.replace(tzinfo=None) + return after - utcnow() > datetime.timedelta(seconds=seconds) @@ -117,12 +121,15 @@ utcnow.override_time = None -def set_time_override(override_time=datetime.datetime.utcnow()): +def set_time_override(override_time=None): """Overrides utils.utcnow. Make it return a constant time or a list thereof, one at a time. + + :param override_time: datetime instance or list thereof. If not + given, defaults to the current UTC time. """ - utcnow.override_time = override_time + utcnow.override_time = override_time or datetime.datetime.utcnow() def advance_time_delta(timedelta): @@ -175,6 +182,15 @@ datetime objects (as a float, to microsecond resolution). """ delta = after - before + return total_seconds(delta) + + +def total_seconds(delta): + """Return the total seconds of datetime.timedelta object. + + Compute total seconds of datetime.timedelta, datetime.timedelta + doesn't have method total_seconds in Python2.6, calculate it manually. + """ try: return delta.total_seconds() except AttributeError: @@ -185,8 +201,8 @@ def is_soon(dt, window): """Determines if time is going to happen in the next window seconds. - :params dt: the time - :params window: minimum seconds to remain to consider the time not soon + :param dt: the time + :param window: minimum seconds to remain to consider the time not soon :return: True if expiration is within the given duration """ diff -Nru python-novaclient-2.15.0/novaclient/openstack/common/uuidutils.py python-novaclient-2.16.0/novaclient/openstack/common/uuidutils.py --- python-novaclient-2.15.0/novaclient/openstack/common/uuidutils.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/openstack/common/uuidutils.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,5 +1,3 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - # Copyright (c) 2012 Intel Corporation. # All Rights Reserved. # diff -Nru python-novaclient-2.15.0/novaclient/service_catalog.py python-novaclient-2.16.0/novaclient/service_catalog.py --- python-novaclient-2.15.0/novaclient/service_catalog.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/service_catalog.py 2014-02-26 16:28:51.000000000 +0000 @@ -36,7 +36,8 @@ service_name=None, volume_service_name=None): """Fetch the public URL from the Compute service for a particular endpoint attribute. If none given, return - the first. See tests for sample service catalog.""" + the first. See tests for sample service catalog. + """ matching_endpoints = [] if 'endpoints' in self.catalog: # We have a bastardized service catalog. Treat it special. :/ diff -Nru python-novaclient-2.15.0/novaclient/shell.py python-novaclient-2.16.0/novaclient/shell.py --- python-novaclient-2.15.0/novaclient/shell.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/shell.py 2014-02-26 16:28:51.000000000 +0000 @@ -37,14 +37,6 @@ try: import keyring HAS_KEYRING = True - try: - if isinstance(keyring.get_keyring(), keyring.backend.GnomeKeyring): - import gnomekeyring - all_errors = (ValueError, - gnomekeyring.IOError, - gnomekeyring.NoKeyringDaemonError) - except Exception: - pass except ImportError: pass @@ -53,6 +45,8 @@ from novaclient import client from novaclient import exceptions as exc import novaclient.extension +from novaclient.openstack.common import cliutils +from novaclient.openstack.common.gettextutils import _ from novaclient.openstack.common import strutils from novaclient import utils from novaclient.v1_1 import shell as shell_v1_1 @@ -60,7 +54,13 @@ DEFAULT_OS_COMPUTE_API_VERSION = "1.1" DEFAULT_NOVA_ENDPOINT_TYPE = 'publicURL' -DEFAULT_NOVA_SERVICE_TYPE = 'compute' +# NOTE(cyeoh): Having the service type dependent on the API version +# is pretty ugly, but we have to do this because traditionally the +# catalog entry for compute points directly to the V2 API rather than +# the root, and then doing version discovery. +DEFAULT_NOVA_SERVICE_TYPE_MAP = {'1.1': 'compute', + '2': 'compute', + '3': 'computev3'} logger = logging.getLogger(__name__) @@ -71,10 +71,10 @@ try: value = float(text) except ValueError: - msg = "%s must be a float" % text + msg = _("%s must be a float") % text raise argparse.ArgumentTypeError(msg) if value <= 0: - msg = "%s must be greater than 0" % text + msg = _("%s must be greater than 0") % text raise argparse.ArgumentTypeError(msg) return value @@ -84,6 +84,7 @@ self.args = args self.client = client self.key = None + self._password = None def _validate_string(self, text): if text is None or len(text) == 0: @@ -137,7 +138,8 @@ # Nothing changed.... return if not all([management_url, auth_token, tenant_id]): - raise ValueError("Unable to save empty management url/auth token") + raise ValueError(_("Unable to save empty management url/auth " + "token")) value = "|".join([str(auth_token), str(management_url), str(tenant_id)]) @@ -145,10 +147,21 @@ @property def password(self): - if self._validate_string(self.args.os_password): - return self.args.os_password - verify_pass = utils.bool_from_str(utils.env("OS_VERIFY_PASSWORD")) - return self._prompt_password(verify_pass) + # Cache password so we prompt user at most once + if self._password: + pass + elif self._validate_string(self.args.os_password): + self._password = self.args.os_password + else: + verify_pass = strutils.bool_from_string( + utils.env("OS_VERIFY_PASSWORD", default=False), True) + self._password = self._prompt_password(verify_pass) + if not self._password: + raise exc.CommandError( + 'Expecting a password provided via either ' + '--os-password, env[OS_PASSWORD], or ' + 'prompted response') + return self._password @property def management_url(self): @@ -209,8 +222,8 @@ #FIXME(lzyeval): if changes occur in argparse.ArgParser._check_value choose_from = ' (choose from' progparts = self.prog.partition(' ') - self.exit(2, "error: %(errmsg)s\nTry '%(mainp)s help %(subp)s'" - " for more information.\n" % + self.exit(2, _("error: %(errmsg)s\nTry '%(mainp)s help %(subp)s'" + " for more information.\n") % {'errmsg': message.split(choose_from)[0], 'mainp': progparts[0], 'subp': progparts[2]}) @@ -241,72 +254,67 @@ parser.add_argument('--debug', default=False, action='store_true', - help="Print debugging output") - - parser.add_argument('--no-cache', - default=not utils.bool_from_str( - utils.env('OS_NO_CACHE', default='true')), - action='store_false', - dest='os_cache', - help=argparse.SUPPRESS) - parser.add_argument('--no_cache', - action='store_false', - dest='os_cache', - help=argparse.SUPPRESS) + help=_("Print debugging output")) parser.add_argument('--os-cache', - default=utils.env('OS_CACHE', default=False), + default=strutils.bool_from_string( + utils.env('OS_CACHE', default=False), True), action='store_true', - help="Use the auth token cache.") + help=_("Use the auth token cache. Defaults to False if " + "env[OS_CACHE] is not set.")) parser.add_argument('--timings', default=False, action='store_true', - help="Print call timing info") + help=_("Print call timing info")) parser.add_argument('--timeout', default=600, metavar='', type=positive_non_zero_float, - help="Set HTTP call timeout (in seconds)") + help=_("Set HTTP call timeout (in seconds)")) + + parser.add_argument('--os-auth-token', + default=utils.env('OS_AUTH_TOKEN'), + help='Defaults to env[OS_AUTH_TOKEN]') parser.add_argument('--os-username', metavar='', default=utils.env('OS_USERNAME', 'NOVA_USERNAME'), - help='Defaults to env[OS_USERNAME].') + help=_('Defaults to env[OS_USERNAME].')) parser.add_argument('--os_username', help=argparse.SUPPRESS) parser.add_argument('--os-password', metavar='', default=utils.env('OS_PASSWORD', 'NOVA_PASSWORD'), - help='Defaults to env[OS_PASSWORD].') + help=_('Defaults to env[OS_PASSWORD].')) parser.add_argument('--os_password', help=argparse.SUPPRESS) parser.add_argument('--os-tenant-name', metavar='', default=utils.env('OS_TENANT_NAME', 'NOVA_PROJECT_ID'), - help='Defaults to env[OS_TENANT_NAME].') + help=_('Defaults to env[OS_TENANT_NAME].')) parser.add_argument('--os_tenant_name', help=argparse.SUPPRESS) parser.add_argument('--os-tenant-id', metavar='', default=utils.env('OS_TENANT_ID'), - help='Defaults to env[OS_TENANT_ID].') + help=_('Defaults to env[OS_TENANT_ID].')) parser.add_argument('--os-auth-url', metavar='', default=utils.env('OS_AUTH_URL', 'NOVA_URL'), - help='Defaults to env[OS_AUTH_URL].') + help=_('Defaults to env[OS_AUTH_URL].')) parser.add_argument('--os_auth_url', help=argparse.SUPPRESS) parser.add_argument('--os-region-name', metavar='', default=utils.env('OS_REGION_NAME', 'NOVA_REGION_NAME'), - help='Defaults to env[OS_REGION_NAME].') + help=_('Defaults to env[OS_REGION_NAME].')) parser.add_argument('--os_region_name', help=argparse.SUPPRESS) @@ -319,21 +327,21 @@ parser.add_argument('--service-type', metavar='', - help='Defaults to compute for most actions') + help=_('Defaults to compute for most actions')) parser.add_argument('--service_type', help=argparse.SUPPRESS) parser.add_argument('--service-name', metavar='', default=utils.env('NOVA_SERVICE_NAME'), - help='Defaults to env[NOVA_SERVICE_NAME]') + help=_('Defaults to env[NOVA_SERVICE_NAME]')) parser.add_argument('--service_name', help=argparse.SUPPRESS) parser.add_argument('--volume-service-name', metavar='', default=utils.env('NOVA_VOLUME_SERVICE_NAME'), - help='Defaults to env[NOVA_VOLUME_SERVICE_NAME]') + help=_('Defaults to env[NOVA_VOLUME_SERVICE_NAME]')) parser.add_argument('--volume_service_name', help=argparse.SUPPRESS) @@ -341,7 +349,7 @@ metavar='', default=utils.env('NOVA_ENDPOINT_TYPE', default=DEFAULT_NOVA_ENDPOINT_TYPE), - help='Defaults to env[NOVA_ENDPOINT_TYPE] or ' + help=_('Defaults to env[NOVA_ENDPOINT_TYPE] or ') + DEFAULT_NOVA_ENDPOINT_TYPE + '.') # NOTE(dtroyer): We can't add --endpoint_type here due to argparse # thinking usage-list --end is ambiguous; but it @@ -354,8 +362,8 @@ metavar='', default=utils.env('OS_COMPUTE_API_VERSION', default=DEFAULT_OS_COMPUTE_API_VERSION), - help='Accepts 1.1 or 3, ' - 'defaults to env[OS_COMPUTE_API_VERSION].') + help=_('Accepts 1.1 or 3, ' + 'defaults to env[OS_COMPUTE_API_VERSION].')) parser.add_argument('--os_compute_api_version', help=argparse.SUPPRESS) @@ -369,10 +377,10 @@ parser.add_argument('--insecure', default=utils.env('NOVACLIENT_INSECURE', default=False), action='store_true', - help="Explicitly allow novaclient to perform \"insecure\" " + help=_("Explicitly allow novaclient to perform \"insecure\" " "SSL (https) requests. The server's certificate will " "not be verified against any certificate authorities. " - "This option should be used with caution.") + "This option should be used with caution.")) parser.add_argument('--bypass-url', metavar='', @@ -468,7 +476,7 @@ def _find_actions(self, subparsers, actions_module): for attr in (a for a in dir(actions_module) if a.startswith('do_')): - # I prefer to be hypen-separated instead of underscores. + # I prefer to be hyphen-separated instead of underscores. command = attr[3:].replace('_', '-') callback = getattr(actions_module, attr) desc = callback.__doc__ or '' @@ -501,7 +509,6 @@ format=streamformat) def main(self, argv): - # Parse args once to find version and debug settings parser = self.get_base_parser() (options, args) = parser.parse_known_args(argv) @@ -542,73 +549,95 @@ self.do_bash_completion(args) return 0 - (os_username, os_tenant_name, os_tenant_id, os_auth_url, - os_region_name, os_auth_system, endpoint_type, insecure, - service_type, service_name, volume_service_name, - bypass_url, os_cache, cacert, timeout) = ( - args.os_username, - args.os_tenant_name, args.os_tenant_id, - args.os_auth_url, - args.os_region_name, args.os_auth_system, - args.endpoint_type, args.insecure, args.service_type, - args.service_name, args.volume_service_name, - args.bypass_url, args.os_cache, - args.os_cacert, args.timeout) + os_username = args.os_username + os_password = None # Fetched and set later as needed + os_tenant_name = args.os_tenant_name + os_tenant_id = args.os_tenant_id + os_auth_url = args.os_auth_url + os_region_name = args.os_region_name + os_auth_system = args.os_auth_system + endpoint_type = args.endpoint_type + insecure = args.insecure + service_type = args.service_type + service_name = args.service_name + volume_service_name = args.volume_service_name + bypass_url = args.bypass_url + os_cache = args.os_cache + cacert = args.os_cacert + timeout = args.timeout + + # We may have either, both or none of these. + # If we have both, we don't need USERNAME, PASSWORD etc. + # Fill in the blanks from the SecretsHelper if possible. + # Finally, authenticate unless we have both. + # Note if we don't auth we probably don't have a tenant ID so we can't + # cache the token. + auth_token = args.os_auth_token if args.os_auth_token else None + management_url = bypass_url if bypass_url else None if os_auth_system and os_auth_system != "keystone": auth_plugin = novaclient.auth_plugin.load_plugin(os_auth_system) else: auth_plugin = None - # Fetched and set later as needed - os_password = None - if not endpoint_type: endpoint_type = DEFAULT_NOVA_ENDPOINT_TYPE if not service_type: - service_type = DEFAULT_NOVA_SERVICE_TYPE + os_compute_api_version = (options.os_compute_api_version or + DEFAULT_OS_COMPUTE_API_VERSION) + try: + service_type = DEFAULT_NOVA_SERVICE_TYPE_MAP[ + os_compute_api_version] + except KeyError: + service_type = DEFAULT_NOVA_SERVICE_TYPE_MAP[ + DEFAULT_OS_COMPUTE_API_VERSION] service_type = utils.get_service_type(args.func) or service_type + # If we have an auth token but no management_url, we must auth anyway. + # Expired tokens are handled by client.py:_cs_request + must_auth = not (cliutils.isunauthenticated(args.func) + or (auth_token and management_url)) + #FIXME(usrleon): Here should be restrict for project id same as # for os_username or os_password but for compatibility it is not. - if not utils.isunauthenticated(args.func): + if must_auth: if auth_plugin: auth_plugin.parse_opts(args) if not auth_plugin or not auth_plugin.opts: if not os_username: - raise exc.CommandError("You must provide a username " - "via either --os-username or env[OS_USERNAME]") + raise exc.CommandError(_("You must provide a username " + "via either --os-username or env[OS_USERNAME]")) if not os_tenant_name and not os_tenant_id: - raise exc.CommandError("You must provide a tenant name " + raise exc.CommandError(_("You must provide a tenant name " "or tenant id via --os-tenant-name, " "--os-tenant-id, env[OS_TENANT_NAME] " - "or env[OS_TENANT_ID]") + "or env[OS_TENANT_ID]")) if not os_auth_url: if os_auth_system and os_auth_system != 'keystone': os_auth_url = auth_plugin.get_auth_url() if not os_auth_url: - raise exc.CommandError("You must provide an auth url " + raise exc.CommandError(_("You must provide an auth url " "via either --os-auth-url or env[OS_AUTH_URL] " "or specify an auth_system which defines a " "default url with --os-auth-system " - "or env[OS_AUTH_SYSTEM]") + "or env[OS_AUTH_SYSTEM]")) if (options.os_compute_api_version and options.os_compute_api_version != '1.0'): if not os_tenant_name and not os_tenant_id: - raise exc.CommandError("You must provide a tenant name " + raise exc.CommandError(_("You must provide a tenant name " "or tenant id via --os-tenant-name, " "--os-tenant-id, env[OS_TENANT_NAME] " - "or env[OS_TENANT_ID]") + "or env[OS_TENANT_ID]")) if not os_auth_url: - raise exc.CommandError("You must provide an auth url " - "via either --os-auth-url or env[OS_AUTH_URL]") + raise exc.CommandError(_("You must provide an auth url " + "via either --os-auth-url or env[OS_AUTH_URL]")) self.cs = client.Client(options.os_compute_api_version, os_username, os_password, os_tenant_name, tenant_id=os_tenant_id, @@ -616,7 +645,7 @@ region_name=os_region_name, endpoint_type=endpoint_type, extensions=self.extensions, service_type=service_type, service_name=service_name, auth_system=os_auth_system, - auth_plugin=auth_plugin, + auth_plugin=auth_plugin, auth_token=auth_token, volume_service_name=volume_service_name, timings=args.timings, bypass_url=bypass_url, os_cache=os_cache, http_log_debug=options.debug, @@ -624,7 +653,7 @@ # Now check for the password/token of which pieces of the # identifying keyring key can come from the underlying client - if not utils.isunauthenticated(args.func): + if must_auth: helper = SecretsHelper(args, self.cs.client) if (auth_plugin and auth_plugin.opts and "os_password" not in auth_plugin.opts): @@ -632,43 +661,51 @@ else: use_pw = True - tenant_id, auth_token, management_url = (helper.tenant_id, - helper.auth_token, - helper.management_url) + tenant_id = helper.tenant_id + # Allow commandline to override cache + if not auth_token: + auth_token = helper.auth_token + if not management_url: + management_url = helper.management_url if tenant_id and auth_token and management_url: self.cs.client.tenant_id = tenant_id self.cs.client.auth_token = auth_token self.cs.client.management_url = management_url - # Try to auth with the given info, if it fails - # go into password mode... - try: - self.cs.authenticate() - use_pw = False - except (exc.Unauthorized, exc.AuthorizationFailure): - # Likely it expired or just didn't work... - self.cs.client.auth_token = None - self.cs.client.management_url = None - if use_pw: - # Auth using token must have failed or not happened - # at all, so now switch to password mode and save - # the token when its gotten... using our keyring - # saver - os_password = helper.password - if not os_password: - raise exc.CommandError( - 'Expecting a password provided via either ' - '--os-password, env[OS_PASSWORD], or ' - 'prompted response') - self.cs.client.password = os_password + self.cs.client.password_func = lambda: helper.password + elif use_pw: + # We're missing something, so auth with user/pass and save + # the result in our helper. + self.cs.client.password = helper.password self.cs.client.keyring_saver = helper try: - if not utils.isunauthenticated(args.func): + # This does a couple of bits which are useful even if we've + # got the token + service URL already. It exits fast in that case. + if not cliutils.isunauthenticated(args.func): self.cs.authenticate() except exc.Unauthorized: - raise exc.CommandError("Invalid OpenStack Nova credentials.") + raise exc.CommandError(_("Invalid OpenStack Nova credentials.")) except exc.AuthorizationFailure: - raise exc.CommandError("Unable to authorize user") + raise exc.CommandError(_("Unable to authorize user")) + + if os_compute_api_version == "3" and service_type != 'image': + # NOTE(cyeoh): create an image based client because the + # images api is no longer proxied by the V3 API and we + # sometimes need to be able to look up images information + # via glance when connected to the nova api. + image_service_type = 'image' + self.cs.image_cs = client.Client( + options.os_compute_api_version, os_username, + os_password, os_tenant_name, tenant_id=os_tenant_id, + auth_url=os_auth_url, insecure=insecure, + region_name=os_region_name, endpoint_type=endpoint_type, + extensions=self.extensions, service_type=image_service_type, + service_name=service_name, auth_system=os_auth_system, + auth_plugin=auth_plugin, + volume_service_name=volume_service_name, + timings=args.timings, bypass_url=bypass_url, + os_cache=os_cache, http_log_debug=options.debug, + cacert=cacert, timeout=timeout) args.func(self.cs, args) @@ -718,7 +755,7 @@ if args.command in self.subcommands: self.subcommands[args.command].print_help() else: - raise exc.CommandError("'%s' is not a valid subcommand" % + raise exc.CommandError(_("'%s' is not a valid subcommand") % args.command) else: self.parser.print_help() @@ -741,6 +778,9 @@ print("ERROR: %s" % strutils.safe_encode(six.text_type(e)), file=sys.stderr) sys.exit(1) + except KeyboardInterrupt as e: + print("Shutting down novaclient", file=sys.stderr) + sys.exit(1) if __name__ == "__main__": diff -Nru python-novaclient-2.15.0/novaclient/tests/fakes.py python-novaclient-2.16.0/novaclient/tests/fakes.py --- python-novaclient-2.15.0/novaclient/tests/fakes.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/fakes.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,3 +1,16 @@ +# +# 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 fake server that "responds" to API methods with pre-canned responses. diff -Nru python-novaclient-2.15.0/novaclient/tests/idfake.pem python-novaclient-2.16.0/novaclient/tests/idfake.pem --- python-novaclient-2.15.0/novaclient/tests/idfake.pem 1970-01-01 00:00:00.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/idfake.pem 2014-02-26 16:28:51.000000000 +0000 @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEA9QstF/7prDY7a9La7GS9TpMX+MWWXQgK6pHRLakDFp1WX1Q3 +Vly7rWitaZUGirUPMm181oJXBwkKlAxFD7hKjyHYaSswNszPYIAsVkc1+AO5epXz +g9kUBNtfg44Pg72UecwLrZ8JpmNZpJlKQOx6vF+yi7JmHrrIf6il/grIGUPzoT2L +yReimpyPoBrGtXhJYaCJ/XbKg1idRZiQdmwh1F/OmZWn9p0wunnsv08a0+qIywuw +WhG9/Zy9fjnEByfusS6gI0GIxDRL4RWzOqphd3PZzunwIBgEKFhgiki9+2DgcRVO +9I5wnDvfwQREJRZWh1uJa5ZTcfPa1EzZryVeOQIDAQABAoIBABxO3Te/cBk/7p9n +LXlPrfrszUEk+ljm+/PbQpIGy1+Kb5b1sKrebaP7ysS+vZG6lvXZZimVxx398mXm +APhu7tYYL9r+bUR3ZqGcTQLumRJ8w6mgtxANPN3Oxfr5p1stxIBJjTPSgpfhNFLq +joRvjUJDv+mZg2ibZVwyDHMLpdAdKp+3XMdyTLZcH9esqwii+natix7rHd1RuF85 +L1dfpxjkItwhgHsfdYS++5X3fRByFOhQ+Nhabh/kPQbQMcteRn1bN6zeCWBSglNb +Ka/ZrXb6ApRUc22Ji62mNO2ZPPekLJeCHk2h2E7ezYX+sGDNvvd/jHVDJJ20FjD1 +Z9KXuK0CgYEA/2vniy9yWd925QQtWbmrxgy6yj89feMH/LTv4qP298rGZ2nqxsyd +9pdBdb4NMsi4HmV5PG1hp3VRNBHl53DNh5eqzT8WEXnIF+sbrIU3KzrCVAx1kZTl ++OWKA6aVUsvvO3y85SOvInnsV+IsOGmU4/WBSjYoe39Bo7mq/YuZB9MCgYEA9ZlB +KBm6PjFdHQGNgedXahWzRcwC+ALCYqequPYqJolNzhrK4Uc2sWPSGdnldcHZ4XCQ +wbfCxUSwrMpA1oyuIQ0U4aowmOw5DjIueBWI8XBYEVRBlwvJwbXpBZ/DspGzTUDx +MBrrEwEaMadQvxhRnAzhp0rQAepatcz6Fgb1JkMCgYBMwDLiew5kfSav6JJsDMPW +DksurNQgeNEUmZYfx19V1EPMHWKj/CZXS9oqtEIpCXFyCNHmW4PlmvYcrGgmJJpN +7UAwzo0mES8UKNy2+Yy7W7u7H8dQSKrWILtZH3xtVcR8Xp4wSIm+1V40hkz9YpSP +71y7XQzLF1E1DnyYFZOVawKBgAFrmHfd5jjT2kD/sEzPBK9lXrsJmf7LLUqaw578 +NXQxmRSXDRNOcR+Hf0CNBQmwTE1EdGHaaTLw2cC2Drfu6lbgl31SmaNYwl+1pJUn +MrqKtseq4BI6jDkljypsKRqQQyQwOvTXQwLCH9+nowzn3Bj17hwkj51jOJESlWOp +OKO3AoGBALm+jjqyqX7gSnqK3FAumB8mlhv3yI1Wr1ctwe18mKfKbz17HxXRu9pF +K/6e7WMCA1p+jhoE8gj1h2WBcH0nV2qt8Ye8gJBbCi4dhI08o4AfrIV47oZx1RlO +qYcA1U9lyaODY5SL8+6PHOy5J/aYtuA+wvfEnWiCIdKQrhWetcn3 +-----END RSA PRIVATE KEY----- diff -Nru python-novaclient-2.15.0/novaclient/tests/test_auth_plugins.py python-novaclient-2.16.0/novaclient/tests/test_auth_plugins.py --- python-novaclient-2.15.0/novaclient/tests/test_auth_plugins.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/test_auth_plugins.py 2014-02-26 16:28:51.000000000 +0000 @@ -25,8 +25,8 @@ from novaclient import auth_plugin from novaclient import exceptions -from novaclient.v1_1 import client from novaclient.tests import utils +from novaclient.v1_1 import client def mock_http_request(resp=None): diff -Nru python-novaclient-2.15.0/novaclient/tests/test_base.py python-novaclient-2.16.0/novaclient/tests/test_base.py --- python-novaclient-2.15.0/novaclient/tests/test_base.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/test_base.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,8 +1,21 @@ +# +# 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 novaclient import base from novaclient import exceptions -from novaclient.v1_1 import flavors from novaclient.tests import utils from novaclient.tests.v1_1 import fakes +from novaclient.v1_1 import flavors cs = fakes.FakeClient() diff -Nru python-novaclient-2.15.0/novaclient/tests/test_client.py python-novaclient-2.16.0/novaclient/tests/test_client.py --- python-novaclient-2.15.0/novaclient/tests/test_client.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/test_client.py 2014-02-26 16:28:51.000000000 +0000 @@ -20,9 +20,11 @@ import novaclient.client import novaclient.extension import novaclient.tests.fakes as fakes +from novaclient.tests import utils import novaclient.v1_1.client import novaclient.v3.client -from novaclient.tests import utils + +import json class ClientTest(utils.TestCase): @@ -71,8 +73,16 @@ reauth_headers = {'Content-Type': 'application/json', 'Accept': 'application/json', 'User-Agent': 'python-novaclient'} - data = ('{"auth": {"tenantName": "project", "passwordCredentials":' - ' {"username": "user", "password": "password"}}}') + data = { + "auth": { + "tenantName": "project", + "passwordCredentials": { + "username": "user", + "password": "password" + } + } + } + expected = [mock.call('GET', 'http://example.com/servers/detail', timeout=mock.ANY, @@ -82,7 +92,7 @@ timeout=mock.ANY, headers=reauth_headers, allow_redirects=mock.ANY, - data=data, + data=json.dumps(data), verify=mock.ANY)] self.assertEqual(mock_request.call_args_list, expected) @@ -161,7 +171,7 @@ self.assertEqual(["somevalue"], cs.get_timings()) cs.reset_timings() - self.assertEquals(0, len(cs.get_timings())) + self.assertEqual(0, len(cs.get_timings())) def test_clent_extensions_v3(self): fake_attribute_name1 = "FakeAttribute1" @@ -176,8 +186,8 @@ cs = novaclient.v3.client.Client("user", "password", "project_id", auth_url="foo/v2", extensions=extensions) - self.assertTrue(isinstance(getattr(cs, fake_attribute_name1, None), - fakes.FakeManager)) + self.assertIsInstance(getattr(cs, fake_attribute_name1, None), + fakes.FakeManager) self.assertFalse(hasattr(cs, fake_attribute_name2)) @mock.patch.object(novaclient.client.HTTPClient, 'authenticate') @@ -186,3 +196,23 @@ auth_url="foo/v2") cs.authenticate() self.assertTrue(mock_authenticate.called) + + def test_get_password_simple(self): + cs = novaclient.client.HTTPClient("user", "password", "", "") + cs.password_func = mock.Mock() + self.assertEqual(cs._get_password(), "password") + self.assertFalse(cs.password_func.called) + + def test_get_password_none(self): + cs = novaclient.client.HTTPClient("user", None, "", "") + self.assertIsNone(cs._get_password()) + + def test_get_password_func(self): + cs = novaclient.client.HTTPClient("user", None, "", "") + cs.password_func = mock.Mock(return_value="password") + self.assertEqual(cs._get_password(), "password") + cs.password_func.assert_called_once_with() + + cs.password_func = mock.Mock() + self.assertEqual(cs._get_password(), "password") + self.assertFalse(cs.password_func.called) diff -Nru python-novaclient-2.15.0/novaclient/tests/test_discover.py python-novaclient-2.16.0/novaclient/tests/test_discover.py --- python-novaclient-2.15.0/novaclient/tests/test_discover.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/test_discover.py 2014-02-26 16:28:51.000000000 +0000 @@ -13,9 +13,10 @@ # License for the specific language governing permissions and limitations # under the License. -import mock import imp import inspect + +import mock import pkg_resources import novaclient.shell diff -Nru python-novaclient-2.15.0/novaclient/tests/test_http.py python-novaclient-2.16.0/novaclient/tests/test_http.py --- python-novaclient-2.15.0/novaclient/tests/test_http.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/test_http.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,3 +1,16 @@ +# +# 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 mock import requests diff -Nru python-novaclient-2.15.0/novaclient/tests/test_service_catalog.py python-novaclient-2.16.0/novaclient/tests/test_service_catalog.py --- python-novaclient-2.15.0/novaclient/tests/test_service_catalog.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/test_service_catalog.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,3 +1,16 @@ +# +# 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 novaclient import exceptions from novaclient import service_catalog from novaclient.tests import utils diff -Nru python-novaclient-2.15.0/novaclient/tests/test_shell.py python-novaclient-2.16.0/novaclient/tests/test_shell.py --- python-novaclient-2.15.0/novaclient/tests/test_shell.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/test_shell.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,6 +1,19 @@ -import io +# +# 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 prettytable import re +import six import sys from distutils.version import StrictVersion @@ -36,15 +49,16 @@ self.useFixture(fixtures.MonkeyPatch( 'novaclient.client.get_client_class', mock.MagicMock)) - self.nc_util = mock.patch('novaclient.utils.isunauthenticated').start() + self.nc_util = mock.patch( + 'novaclient.openstack.common.cliutils.isunauthenticated').start() self.nc_util.return_value = False def shell(self, argstr, exitcodes=(0,)): orig = sys.stdout orig_stderr = sys.stderr try: - sys.stdout = io.BytesIO() - sys.stderr = io.BytesIO() + sys.stdout = six.StringIO() + sys.stderr = six.StringIO() _shell = novaclient.shell.OpenStackComputeShell() _shell.main(argstr.split()) except SystemExit: @@ -169,6 +183,8 @@ @mock.patch('sys.stdin', side_effect=mock.MagicMock) @mock.patch('getpass.getpass', return_value='password') def test_password(self, mock_getpass, mock_stdin): + mock_stdin.encoding = "utf-8" + # default output of empty tables differs depending between prettytable # versions if (hasattr(prettytable, '__version__') and @@ -198,3 +214,33 @@ self.assertEqual(required, message.args) else: self.fail('CommandError not raised') + + def _test_service_type(self, version, service_type, mock_client): + if version is None: + cmd = 'list' + else: + cmd = '--os-compute-api-version %s list' % version + self.make_env() + self.shell(cmd) + _, client_kwargs = mock_client.call_args_list[0] + self.assertEqual(service_type, client_kwargs['service_type']) + + @mock.patch('novaclient.client.Client') + def test_default_service_type(self, mock_client): + self._test_service_type(None, 'compute', mock_client) + + @mock.patch('novaclient.client.Client') + def test_v1_1_service_type(self, mock_client): + self._test_service_type('1.1', 'compute', mock_client) + + @mock.patch('novaclient.client.Client') + def test_v2_service_type(self, mock_client): + self._test_service_type('2', 'compute', mock_client) + + @mock.patch('novaclient.client.Client') + def test_v3_service_type(self, mock_client): + self._test_service_type('3', 'computev3', mock_client) + + @mock.patch('novaclient.client.Client') + def test_v_unknown_service_type(self, mock_client): + self._test_service_type('unknown', 'compute', mock_client) diff -Nru python-novaclient-2.15.0/novaclient/tests/test_utils.py python-novaclient-2.16.0/novaclient/tests/test_utils.py --- python-novaclient-2.15.0/novaclient/tests/test_utils.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/test_utils.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,12 +1,25 @@ +# +# 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 sys import mock import six -from novaclient import exceptions -from novaclient import utils from novaclient import base +from novaclient import exceptions from novaclient.tests import utils as test_utils +from novaclient import utils UUID = '8e8ec658-c7b0-4243-bdf8-6f7f2952c0d0' @@ -29,9 +42,15 @@ resources = [ FakeResource('1234', {'name': 'entity_one'}), FakeResource(UUID, {'name': 'entity_two'}), - FakeResource('5678', {'name': '9876'}) + FakeResource('5678', {'name': '9876'}), + FakeResource('01234', {'name': 'entity_three'}) ] + is_alphanum_id_allowed = None + + def __init__(self, alphanum_id_allowed=False): + self.is_alphanum_id_allowed = alphanum_id_allowed + def get(self, resource_id): for resource in self.resources: if resource.id == str(resource_id): @@ -104,6 +123,11 @@ output = utils.find_resource(display_manager, 'entity_three') self.assertEqual(output, display_manager.get('4242')) + def test_find_in_alphanum_allowd_manager_by_str_id_(self): + alphanum_manager = FakeManager(True) + output = utils.find_resource(alphanum_manager, '01234') + self.assertEqual(output, alphanum_manager.get('01234')) + class _FakeResult(object): def __init__(self, name, value): @@ -113,6 +137,31 @@ class PrintResultTestCase(test_utils.TestCase): @mock.patch('sys.stdout', six.StringIO()) + def test_print_dict(self): + dict = {'key': 'value'} + utils.print_dict(dict) + self.assertEqual(sys.stdout.getvalue(), + '+----------+-------+\n' + '| Property | Value |\n' + '+----------+-------+\n' + '| key | value |\n' + '+----------+-------+\n') + + @mock.patch('sys.stdout', six.StringIO()) + def test_print_dict_wrap(self): + dict = {'key1': 'not wrapped', + 'key2': 'this will be wrapped'} + utils.print_dict(dict, wrap=16) + self.assertEqual(sys.stdout.getvalue(), + '+----------+--------------+\n' + '| Property | Value |\n' + '+----------+--------------+\n' + '| key1 | not wrapped |\n' + '| key2 | this will be |\n' + '| | wrapped |\n' + '+----------+--------------+\n') + + @mock.patch('sys.stdout', six.StringIO()) def test_print_list_sort_by_str(self): objs = [_FakeResult("k1", 1), _FakeResult("k3", 2), @@ -163,3 +212,92 @@ '| k3 | 3 |\n' '| k2 | 2 |\n' '+------+-------+\n') + + @mock.patch('sys.stdout', six.StringIO()) + def test_print_dict_dictionary(self): + dict = {'k': {'foo': 'bar'}} + utils.print_dict(dict) + self.assertEqual(sys.stdout.getvalue(), + '+----------+----------------+\n' + '| Property | Value |\n' + '+----------+----------------+\n' + '| k | {"foo": "bar"} |\n' + '+----------+----------------+\n') + + @mock.patch('sys.stdout', six.StringIO()) + def test_print_dict_list_dictionary(self): + dict = {'k': [{'foo': 'bar'}]} + utils.print_dict(dict) + self.assertEqual(sys.stdout.getvalue(), + '+----------+------------------+\n' + '| Property | Value |\n' + '+----------+------------------+\n' + '| k | [{"foo": "bar"}] |\n' + '+----------+------------------+\n') + + @mock.patch('sys.stdout', six.StringIO()) + def test_print_dict_list(self): + dict = {'k': ['foo', 'bar']} + utils.print_dict(dict) + self.assertEqual(sys.stdout.getvalue(), + '+----------+----------------+\n' + '| Property | Value |\n' + '+----------+----------------+\n' + '| k | ["foo", "bar"] |\n' + '+----------+----------------+\n') + + +class FlattenTestCase(test_utils.TestCase): + def test_flattening(self): + squashed = utils.flatten_dict( + {'a1': {'b1': 1234, + 'b2': 'string', + 'b3': set((1, 2, 3)), + 'b4': {'c1': ['l', 'l', ['l']], + 'c2': 'string'}}, + 'a2': ['l'], + 'a3': ('t',)}) + + self.assertEqual({'a1_b1': 1234, + 'a1_b2': 'string', + 'a1_b3': set([1, 2, 3]), + 'a1_b4_c1': ['l', 'l', ['l']], + 'a1_b4_c2': 'string', + 'a2': ['l'], + 'a3': ('t',)}, + squashed) + + def test_pretty_choice_list(self): + l = [] + r = utils.pretty_choice_list(l) + self.assertEqual(r, "") + + l = ["v1", "v2", "v3"] + r = utils.pretty_choice_list(l) + self.assertEqual(r, "'v1', 'v2', 'v3'") + + def test_pretty_choice_dict(self): + d = {} + r = utils.pretty_choice_dict(d) + self.assertEqual(r, "") + + d = {"k1": "v1", + "k2": "v2", + "k3": "v3"} + r = utils.pretty_choice_dict(d) + self.assertEqual(r, "'k1=v1', 'k2=v2', 'k3=v3'") + + +class ValidationsTestCase(test_utils.TestCase): + def test_validate_flavor_metadata_keys_with_valid_keys(self): + valid_keys = ['key1', 'month.price', 'I-Am:AK-ey.01-', 'spaces and _'] + utils.validate_flavor_metadata_keys(valid_keys) + + def test_validate_flavor_metadata_keys_with_invalid_keys(self): + invalid_keys = ['/1', '?1', '%1', '<', '>', '\1'] + for key in invalid_keys: + try: + utils.validate_flavor_metadata_keys([key]) + self.fail("Invalid key passed validation: %s" % key) + except exceptions.CommandError as ce: + self.assertTrue(key in str(ce)) diff -Nru python-novaclient-2.15.0/novaclient/tests/utils.py python-novaclient-2.16.0/novaclient/tests/utils.py --- python-novaclient-2.15.0/novaclient/tests/utils.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/utils.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,3 +1,16 @@ +# +# 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 os import fixtures @@ -29,13 +42,13 @@ """ def __init__(self, data): + super(TestResponse, self).__init__() self._text = None - super(TestResponse, self) if isinstance(data, dict): - self.status_code = data.get('status_code', None) - self.headers = data.get('headers', None) + self.status_code = data.get('status_code') + self.headers = data.get('headers') # Fake the text attribute to streamline Response creation - self._text = data.get('text', None) + self._text = data.get('text') else: self.status_code = data diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/contrib/fakes.py python-novaclient-2.16.0/novaclient/tests/v1_1/contrib/fakes.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/contrib/fakes.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/contrib/fakes.py 2014-02-26 16:28:51.000000000 +0000 @@ -12,8 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -from novaclient.v1_1 import client from novaclient.tests.v1_1 import fakes +from novaclient.v1_1 import client class FakeClient(fakes.FakeClient): @@ -50,7 +50,6 @@ { "id": 1, "instance_uuid": None, - "pm_address": "1.2.3.4", "interfaces": [], "cpus": 2, "local_gb": 10, @@ -113,7 +112,7 @@ def post_os_baremetal_nodes_1_action(self, **kw): body = kw['body'] - action = body.keys()[0] + action = list(body)[0] if action == "add_interface": return ( 200, {}, { diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/contrib/test_baremetal.py python-novaclient-2.16.0/novaclient/tests/v1_1/contrib/test_baremetal.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/contrib/test_baremetal.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/contrib/test_baremetal.py 2014-02-26 16:28:51.000000000 +0000 @@ -33,18 +33,18 @@ nl = cs.baremetal.list() cs.assert_called('GET', '/os-baremetal-nodes') for n in nl: - self.assertTrue(isinstance(n, baremetal.BareMetalNode)) + self.assertIsInstance(n, baremetal.BareMetalNode) def test_get_node(self): n = cs.baremetal.get(1) cs.assert_called('GET', '/os-baremetal-nodes/1') - self.assertTrue(isinstance(n, baremetal.BareMetalNode)) + self.assertIsInstance(n, baremetal.BareMetalNode) def test_create_node(self): n = cs.baremetal.create("service_host", 1, 1024, 2048, "aa:bb:cc:dd:ee:ff") cs.assert_called('POST', '/os-baremetal-nodes') - self.assertTrue(isinstance(n, baremetal.BareMetalNode)) + self.assertIsInstance(n, baremetal.BareMetalNode) def test_delete_node(self): n = cs.baremetal.get(1) @@ -54,7 +54,7 @@ def test_node_add_interface(self): i = cs.baremetal.add_interface(1, "bb:cc:dd:ee:ff:aa", 1, 2) cs.assert_called('POST', '/os-baremetal-nodes/1/action') - self.assertTrue(isinstance(i, baremetal.BareMetalNodeInterface)) + self.assertIsInstance(i, baremetal.BareMetalNodeInterface) def test_node_remove_interface(self): cs.baremetal.remove_interface(1, "bb:cc:dd:ee:ff:aa") diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/contrib/test_list_extensions.py python-novaclient-2.16.0/novaclient/tests/v1_1/contrib/test_list_extensions.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/contrib/test_list_extensions.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/contrib/test_list_extensions.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,3 +1,16 @@ +# +# 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 novaclient import extension from novaclient.v1_1.contrib import list_extensions diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/contrib/test_migrations.py python-novaclient-2.16.0/novaclient/tests/v1_1/contrib/test_migrations.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/contrib/test_migrations.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/contrib/test_migrations.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,5 +1,3 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - # 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 @@ -30,13 +28,13 @@ ml = cs.migrations.list() cs.assert_called('GET', '/os-migrations') for m in ml: - self.assertTrue(isinstance(m, migrations.Migration)) + self.assertIsInstance(m, migrations.Migration) def test_list_migrations_with_filters(self): ml = cs.migrations.list('host1', 'finished', 'child1') cs.assert_called('GET', - '/os-migrations?status=finished&host=host1' - '&cell_name=child1') + '/os-migrations?cell_name=child1&host=host1' + '&status=finished') for m in ml: - self.assertTrue(isinstance(m, migrations.Migration)) + self.assertIsInstance(m, migrations.Migration) diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/contrib/test_tenant_networks.py python-novaclient-2.16.0/novaclient/tests/v1_1/contrib/test_tenant_networks.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/contrib/test_tenant_networks.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/contrib/test_tenant_networks.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,5 +1,3 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - # Copyright 2012 OpenStack Foundation # All Rights Reserved. # diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/fakes.py python-novaclient-2.16.0/novaclient/tests/v1_1/fakes.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/fakes.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/fakes.py 2014-02-26 16:28:51.000000000 +0000 @@ -20,8 +20,8 @@ from novaclient import client as base_client from novaclient import exceptions -from novaclient.openstack.common import strutils from novaclient.openstack.common.py3kcompat import urlutils +from novaclient.openstack.common import strutils from novaclient.tests import fakes from novaclient.tests import utils from novaclient.v1_1 import client @@ -79,7 +79,7 @@ (method, url, callback)) # Note the call - self.callstack.append((method, url, kwargs.get('body', None))) + self.callstack.append((method, url, kwargs.get('body'))) status, headers, body = getattr(self, callback)(**kwargs) r = utils.TestResponse({ @@ -320,6 +320,16 @@ "Server Label": "DB 1" }, "OS-EXT-SRV-ATTR:host": "computenode2", + "security_groups": [{ + 'id': 1, 'name': 'securitygroup1', + 'description': 'FAKE_SECURITY_GROUP', + 'tenant_id': '4ffc664c198e435e9853f2538fbcd7a7' + }, + { + 'id': 2, 'name': 'securitygroup2', + 'description': 'ANOTHER_FAKE_SECURITY_GROUP', + 'tenant_id': '4ffc664c198e435e9853f2538fbcd7a7' + }], }, { "id": 9012, @@ -391,7 +401,7 @@ return (200, {}, r) def put_servers_1234(self, body, **kw): - assert body.keys() == ['server'] + assert list(body) == ['server'] fakes.assert_has_keys(body['server'], optional=['name', 'adminPass']) return (204, {}, body) @@ -413,6 +423,9 @@ def post_servers_1234_metadata(self, **kw): return (204, {}, {'metadata': {'test_key': 'test_value'}}) + def put_servers_1234_metadata_test_key(self, **kw): + return (200, {}, {'meta': {'test_key': 'test_value'}}) + def get_servers_1234_diagnostics(self, **kw): return (200, {}, {'data': 'Fake diagnostics'}) @@ -473,8 +486,27 @@ # Server password # + # Testing with the following password and key + # + # Clear password: FooBar123 + # + # RSA Private Key: novaclient/tests/idfake.pem + # + # Encrypted password + # OIuEuQttO8Rk93BcKlwHQsziDAnkAm/V6V8VPToA8ZeUaUBWwS0gwo2K6Y61Z96r + # qG447iRz0uTEEYq3RAYJk1mh3mMIRVl27t8MtIecR5ggVVbz1S9AwXJQypDKl0ho + # QFvhCBcMWPohyGewDJOhDbtuN1IoFI9G55ZvFwCm5y7m7B2aVcoLeIsJZE4PLsIw + # /y5a6Z3/AoJZYGG7IH5WN88UROU3B9JZGFB2qtPLQTOvDMZLUhoPRIJeHiVSlo1N + # tI2/++UsXVg3ow6ItqCJGgdNuGG5JB+bslDHWPxROpesEIHdczk46HCpHQN8f1sk + # Hi/fmZZNQQqj1Ijq0caOIw== def get_servers_1234_os_server_password(self, **kw): - return (200, {}, {'password': ''}) + return (200, {}, {'password': + 'OIuEuQttO8Rk93BcKlwHQsziDAnkAm/V6V8VPToA8ZeUaUBWwS0gwo2K6Y61Z96r' + 'qG447iRz0uTEEYq3RAYJk1mh3mMIRVl27t8MtIecR5ggVVbz1S9AwXJQypDKl0ho' + 'QFvhCBcMWPohyGewDJOhDbtuN1IoFI9G55ZvFwCm5y7m7B2aVcoLeIsJZE4PLsIw' + '/y5a6Z3/AoJZYGG7IH5WN88UROU3B9JZGFB2qtPLQTOvDMZLUhoPRIJeHiVSlo1N' + 'tI2/++UsXVg3ow6ItqCJGgdNuGG5JB+bslDHWPxROpesEIHdczk46HCpHQN8f1sk' + 'Hi/fmZZNQQqj1Ijq0caOIw=='}) def delete_servers_1234_os_server_password(self, **kw): return (202, {}, None) @@ -488,12 +520,12 @@ _body = None resp = 202 assert len(body.keys()) == 1 - action = body.keys()[0] + action = list(body)[0] if action == 'reboot': - assert body[action].keys() == ['type'] + assert list(body[action]) == ['type'] assert body[action]['type'] in ['HARD', 'SOFT'] elif action == 'rebuild': - keys = body[action].keys() + keys = list(body[action]) if 'adminPass' in keys: keys.remove('adminPass') assert 'imageRef' in keys @@ -538,46 +570,54 @@ assert body[action] is None elif action == 'unlock': assert body[action] is None + elif action == 'shelve': + assert body[action] is None + elif action == 'shelveOffload': + assert body[action] is None + elif action == 'unshelve': + assert body[action] is None elif action == 'addFixedIp': - assert body[action].keys() == ['networkId'] + assert list(body[action]) == ['networkId'] elif action == 'removeFixedIp': - assert body[action].keys() == ['address'] + assert list(body[action]) == ['address'] elif action == 'addFloatingIp': - assert (body[action].keys() == ['address'] or - body[action].keys() == ['fixed_address', - 'address']) + assert (list(body[action]) == ['address'] or + sorted(list(body[action])) == ['address', + 'fixed_address']) elif action == 'removeFloatingIp': - assert body[action].keys() == ['address'] + assert list(body[action]) == ['address'] elif action == 'createImage': assert set(body[action].keys()) == set(['name', 'metadata']) _headers = dict(location="http://blah/images/456") elif action == 'changePassword': - assert body[action].keys() == ['adminPass'] + assert list(body[action]) == ['adminPass'] elif action == 'os-getConsoleOutput': - assert body[action].keys() == ['length'] + assert list(body[action]) == ['length'] return (202, {}, {'output': 'foo'}) elif action == 'os-getVNCConsole': - assert body[action].keys() == ['type'] + assert list(body[action]) == ['type'] elif action == 'os-getSPICEConsole': - assert body[action].keys() == ['type'] + assert list(body[action]) == ['type'] + elif action == 'os-getRDPConsole': + assert list(body[action]) == ['type'] elif action == 'os-migrateLive': assert set(body[action].keys()) == set(['host', 'block_migration', 'disk_over_commit']) elif action == 'os-resetState': - assert body[action].keys() == ['state'] + assert list(body[action]) == ['state'] elif action == 'resetNetwork': assert body[action] is None elif action == 'addSecurityGroup': - assert body[action].keys() == ['name'] + assert list(body[action]) == ['name'] elif action == 'removeSecurityGroup': - assert body[action].keys() == ['name'] + assert list(body[action]) == ['name'] elif action == 'createBackup': - assert set(body[action].keys()) == set(['name', - 'backup_type', - 'rotation']) + assert set(body[action]) == set(['name', + 'backup_type', + 'rotation']) elif action == 'evacuate': - keys = body[action].keys() + keys = list(body[action]) if 'adminPass' in keys: keys.remove('adminPass') assert set(keys) == set(['host', 'onSharedStorage']) @@ -613,7 +653,7 @@ def get_flavors(self, **kw): status, header, flavors = self.get_flavors_detail(**kw) for flavor in flavors['flavors']: - for k in flavor.keys(): + for k in list(flavor): if k not in ['id', 'name']: del flavor[k] @@ -629,6 +669,10 @@ 'OS-FLV-EXT-DATA:ephemeral': 20, 'os-flavor-access:is_public': False, 'links': {}}, + {'id': 4, 'name': '1024 MB Server', 'ram': 1024, 'disk': 10, + 'OS-FLV-EXT-DATA:ephemeral': 10, + 'os-flavor-access:is_public': True, + 'links': {}}, {'id': 'aa1', 'name': '128 MB Server', 'ram': 128, 'disk': 0, 'OS-FLV-EXT-DATA:ephemeral': 0, 'os-flavor-access:is_public': True, @@ -696,6 +740,14 @@ 200, {}, {'flavor': + self.get_flavors_detail(is_public='None')[2]['flavors'][3]} + ) + + def get_flavors_4(self, **kw): + return ( + 200, + {}, + {'flavor': self.get_flavors_detail(is_public='None')[2]['flavors'][2]} ) @@ -727,14 +779,26 @@ return (200, {}, {'extra_specs': {"k3": "v3"}}) + def get_flavors_4_os_extra_specs(self, **kw): + return (200, + {}, + {'extra_specs': {"k4": "v4"}}) + def post_flavors_1_os_extra_specs(self, body, **kw): - assert body.keys() == ['extra_specs'] + assert list(body) == ['extra_specs'] fakes.assert_has_keys(body['extra_specs'], required=['k1']) return (200, {}, {'extra_specs': {"k1": "v1"}}) + def post_flavors_4_os_extra_specs(self, body, **kw): + assert list(body) == ['extra_specs'] + + return (200, + {}, + body) + def delete_flavors_1_os_extra_specs_k1(self, **kw): return (204, {}, None) @@ -762,7 +826,7 @@ return ( 200, {}, - {'floating_ip_pools': [{'name': 'foo', 'name': 'bar'}]} + {'floating_ip_pools': [{'name': 'foo'}, {'name': 'bar'}]} ) def get_os_floating_ips(self, **kw): @@ -910,13 +974,16 @@ def get_images_2(self, **kw): return (200, {}, {'image': self.get_images_detail()[2]['images'][1]}) + def get_images_456(self, **kw): + return (200, {}, {'image': self.get_images_detail()[2]['images'][1]}) + def post_images(self, body, **kw): - assert body.keys() == ['image'] + assert list(body) == ['image'] fakes.assert_has_keys(body['image'], required=['serverId', 'name']) return (202, {}, self.get_images_1()[2]) def post_images_1_metadata(self, body, **kw): - assert body.keys() == ['metadata'] + assert list(body) == ['metadata'] fakes.assert_has_keys(body['metadata'], required=['test_key']) return (200, @@ -947,7 +1014,7 @@ return (202, {}, None) def post_os_keypairs(self, body, **kw): - assert body.keys() == ['keypair'] + assert list(body) == ['keypair'] fakes.assert_has_keys(body['keypair'], required=['name']) r = {'keypair': self.get_os_keypairs()[2]['keypairs'][0]} @@ -971,8 +1038,6 @@ 'metadata_items': [], 'injected_file_content_bytes': 1, 'injected_file_path_bytes': 1, - 'volumes': 1, - 'gigabytes': 1, 'ram': 1, 'floating_ips': 1, 'instances': 1, @@ -988,8 +1053,6 @@ 'metadata_items': [], 'injected_file_content_bytes': 1, 'injected_file_path_bytes': 1, - 'volumes': 1, - 'gigabytes': 1, 'ram': 1, 'floating_ips': 1, 'instances': 1, @@ -1005,8 +1068,6 @@ 'metadata_items': [], 'injected_file_content_bytes': 1, 'injected_file_path_bytes': 1, - 'volumes': 1, - 'gigabytes': 1, 'ram': 1, 'floating_ips': 1, 'instances': 1, @@ -1022,8 +1083,6 @@ 'metadata_items': [], 'injected_file_content_bytes': 1, 'injected_file_path_bytes': 1, - 'volumes': 1, - 'gigabytes': 1, 'ram': 1, 'floating_ips': 1, 'instances': 1, @@ -1039,8 +1098,6 @@ 'metadata_items': [], 'injected_file_content_bytes': 1, 'injected_file_path_bytes': 1, - 'volumes': 1, - 'gigabytes': 1, 'ram': 1, 'floating_ips': 1, 'instances': 1, @@ -1056,8 +1113,6 @@ 'metadata_items': [], 'injected_file_content_bytes': 1, 'injected_file_path_bytes': 1, - 'volumes': 1, - 'gigabytes': 1, 'ram': 1, 'floating_ips': 1, 'instances': 1, @@ -1073,8 +1128,6 @@ 'metadata_items': [], 'injected_file_content_bytes': 1, 'injected_file_path_bytes': 1, - 'volumes': 1, - 'gigabytes': 1, 'ram': 1, 'floating_ips': 1, 'instances': 1, @@ -1085,7 +1138,7 @@ 'security_group_rules': 1}}) def put_os_quota_sets_97f4c221bff44578b0300df4ef119353(self, body, **kw): - assert body.keys() == ['quota_set'] + assert list(body) == ['quota_set'] fakes.assert_has_keys(body['quota_set'], required=['tenant_id']) return (200, {}, {'quota_set': { @@ -1093,8 +1146,6 @@ 'metadata_items': [], 'injected_file_content_bytes': 1, 'injected_file_path_bytes': 1, - 'volumes': 2, - 'gigabytes': 1, 'ram': 1, 'floating_ips': 1, 'instances': 1, @@ -1116,59 +1167,47 @@ def get_os_quota_class_sets_test(self, **kw): return (200, {}, {'quota_class_set': { - 'class_name': 'test', - 'metadata_items': [], + 'id': 'test', + 'metadata_items': 1, 'injected_file_content_bytes': 1, 'injected_file_path_bytes': 1, - 'volumes': 1, - 'gigabytes': 1, 'ram': 1, 'floating_ips': 1, 'instances': 1, 'injected_files': 1, 'cores': 1, - 'keypairs': 1, + 'key_pairs': 1, 'security_groups': 1, 'security_group_rules': 1}}) def put_os_quota_class_sets_test(self, body, **kw): - assert body.keys() == ['quota_class_set'] - fakes.assert_has_keys(body['quota_class_set'], - required=['class_name']) + assert list(body) == ['quota_class_set'] return (200, {}, {'quota_class_set': { - 'class_name': 'test', - 'metadata_items': [], + 'metadata_items': 1, 'injected_file_content_bytes': 1, 'injected_file_path_bytes': 1, - 'volumes': 2, - 'gigabytes': 1, 'ram': 1, 'floating_ips': 1, 'instances': 1, 'injected_files': 1, 'cores': 1, - 'keypairs': 1, + 'key_pairs': 1, 'security_groups': 1, 'security_group_rules': 1}}) def put_os_quota_class_sets_97f4c221bff44578b0300df4ef119353(self, body, **kw): - assert body.keys() == ['quota_class_set'] - fakes.assert_has_keys(body['quota_class_set'], - required=['class_name']) + assert list(body) == ['quota_class_set'] return (200, {}, {'quota_class_set': { - 'class_name': '97f4c221bff44578b0300df4ef119353', - 'metadata_items': [], + 'metadata_items': 1, 'injected_file_content_bytes': 1, 'injected_file_path_bytes': 1, - 'volumes': 2, - 'gigabytes': 1, 'ram': 1, 'floating_ips': 1, 'instances': 1, 'injected_files': 1, 'cores': 1, - 'keypairs': 1, + 'key_pairs': 1, 'security_groups': 1, 'security_group_rules': 1}}) @@ -1219,7 +1258,7 @@ return (202, {}, None) def post_os_security_groups(self, body, **kw): - assert body.keys() == ['security_group'] + assert list(body) == ['security_group'] fakes.assert_has_keys(body['security_group'], required=['name', 'description']) r = {'security_group': @@ -1227,7 +1266,7 @@ return (202, {}, r) def put_os_security_groups_1(self, body, **kw): - assert body.keys() == ['security_group'] + assert list(body) == ['security_group'] fakes.assert_has_keys(body['security_group'], required=['name', 'description']) return (205, {}, body) @@ -1252,7 +1291,7 @@ return (202, {}, None) def post_os_security_group_rules(self, body, **kw): - assert body.keys() == ['security_group_rule'] + assert list(body) == ['security_group_rule'] fakes.assert_has_keys(body['security_group_rule'], required=['parent_group_id'], optional=['group_id', 'ip_protocol', 'from_port', @@ -1678,14 +1717,6 @@ } ) - def post_os_coverage_action(self, body, **kw): - if 'report' not in body: - return (200, {}, None) - else: - return (200, {}, { - 'path': '/tmp/tmpdir/' + body['report']['file'] - }) - def post_os_networks_1_action(self, **kw): return (202, {}, None) @@ -1695,16 +1726,6 @@ def post_os_networks_2_action(self, **kw): return (202, {}, None) - def post_os_coverage_action(self, body, **kw): - if 'start' in body or 'reset' in body: - return (200, {}, None) - elif 'stop' in body: - return (200, {}, {'path': '/tmp/tmpdir/'}) - else: - return (200, {}, { - 'path': '/tmp/tmpdir/' + body['report']['file'] - }) - def get_os_availability_zone(self, **kw): return (200, {}, {"availabilityZoneInfo": [ {"zoneName": "zone-1", @@ -1773,45 +1794,65 @@ def get_volumes_detail(self, **kw): return (200, {}, {"volumes": [ - {"display_name": "Work", - "display_description": "volume for work", - "status": "ATTACHED", - "id": "15e59938-07d5-11e1-90e3-e3dffe0c5983", - "created_at": "2011-09-09T00:00:00Z", - "attached": "2011-11-11T00:00:00Z", - "size": 1024, - "attachments": [ - {"id": "3333", - "links": ''}], - "metadata": {}}]}) + { + "display_name": "Work", + "display_description": "volume for work", + "status": "ATTACHED", + "id": "15e59938-07d5-11e1-90e3-e3dffe0c5983", + "created_at": "2011-09-09T00:00:00Z", + "attached": "2011-11-11T00:00:00Z", + "size": 1024, + "attachments": [ + {"id": "3333", + "links": ''}], + "metadata": {}}, + { + "display_name": "Work2", + "display_description": "volume for work2", + "status": "ATTACHED", + "id": "15e59938-07d5-11e1-90e3-ee32ba30feaa", + "created_at": "2011-09-09T00:00:00Z", + "attached": "2011-11-11T00:00:00Z", + "size": 1024, + "attachments": [ + {"id": "2222", + "links": ''}], + "metadata": {}}]}) def get_volumes(self, **kw): return (200, {}, {"volumes": [ - {"display_name": "Work", - "display_description": "volume for work", - "status": "ATTACHED", - "id": "15e59938-07d5-11e1-90e3-e3dffe0c5983", - "created_at": "2011-09-09T00:00:00Z", - "attached": "2011-11-11T00:00:00Z", - "size": 1024, - "attachments": [ - {"id": "3333", - "links": ''}], - "metadata": {}}]}) + { + "display_name": "Work", + "display_description": "volume for work", + "status": "ATTACHED", + "id": "15e59938-07d5-11e1-90e3-e3dffe0c5983", + "created_at": "2011-09-09T00:00:00Z", + "attached": "2011-11-11T00:00:00Z", + "size": 1024, + "attachments": [ + {"id": "3333", + "links": ''}], + "metadata": {}}, + { + "display_name": "Work2", + "display_description": "volume for work2", + "status": "ATTACHED", + "id": "15e59938-07d5-11e1-90e3-ee32ba30feaa", + "created_at": "2011-09-09T00:00:00Z", + "attached": "2011-11-11T00:00:00Z", + "size": 1024, + "attachments": [ + {"id": "2222", + "links": ''}], + "metadata": {}}]}) def get_volumes_15e59938_07d5_11e1_90e3_e3dffe0c5983(self, **kw): - return (200, {}, {"volume": - {"display_name": "Work", - "display_description": "volume for work", - "status": "ATTACHED", - "id": "15e59938-07d5-11e1-90e3-e3dffe0c5983", - "created_at": "2011-09-09T00:00:00Z", - "attached": "2011-11-11T00:00:00Z", - "size": 1024, - "attachments": [ - {"id": "3333", - "links": ''}], - "metadata": {}}}) + return (200, {}, { + "volume": self.get_volumes_detail()[2]['volumes'][0]}) + + def get_volumes_15e59938_07d5_11e1_90e3_ee32ba30feaa(self, **kw): + return (200, {}, { + "volume": self.get_volumes_detail()[2]['volumes'][1]}) def post_volumes(self, **kw): return (200, {}, {"volume": @@ -1830,6 +1871,9 @@ def delete_volumes_15e59938_07d5_11e1_90e3_e3dffe0c5983(self, **kw): return (200, {}, {}) + def delete_volumes_15e59938_07d5_11e1_90e3_ee32ba30feaa(self, **kw): + return (200, {}, {}) + def post_servers_1234_os_volume_attachments(self, **kw): return (200, {}, {"volumeAttachment": {"device": "/dev/vdb", @@ -1906,7 +1950,7 @@ 'username': 'cell1_user', 'name': 'cell1', 'rpc_host': '10.0.1.10', - '_info': { + 'info': { 'username': 'cell1_user', 'rpc_host': '10.0.1.10', 'type': 'child', @@ -1915,7 +1959,7 @@ }, 'type': 'child', 'rpc_port': 5673, - '_loaded': True + 'loaded': True }} return (200, {}, cell) diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/test_agents.py python-novaclient-2.16.0/novaclient/tests/v1_1/test_agents.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/test_agents.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/test_agents.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,5 +1,3 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - # Copyright 2012 IBM Corp. # All Rights Reserved. # @@ -15,30 +13,39 @@ # License for the specific language governing permissions and limitations # under the License. -from novaclient.v1_1 import agents -from novaclient.tests.v1_1 import fakes from novaclient.tests import utils +from novaclient.tests.v1_1 import fakes +from novaclient.v1_1 import agents -cs = fakes.FakeClient() +class AgentsTest(utils.TestCase): + def setUp(self): + super(AgentsTest, self).setUp() + self.cs = self._get_fake_client() + self.agent_type = self._get_agent_type() + def _get_fake_client(self): + return fakes.FakeClient() -class AgentsTest(utils.TestCase): + def _get_agent_type(self): + return agents.Agent def test_list_agents(self): - ags = cs.agents.list() - cs.assert_called('GET', '/os-agents') - [self.assertTrue(isinstance(a, agents.Agent)) for a in ags] - [self.assertEqual(a.hypervisor, 'kvm') for a in ags] + ags = self.cs.agents.list() + self.cs.assert_called('GET', '/os-agents') + for a in ags: + self.assertIsInstance(a, self.agent_type) + self.assertEqual(a.hypervisor, 'kvm') def test_list_agents_with_hypervisor(self): - ags = cs.agents.list('xen') - cs.assert_called('GET', '/os-agents?hypervisor=xen') - [self.assertTrue(isinstance(a, agents.Agent)) for a in ags] - [self.assertEqual(a.hypervisor, 'xen') for a in ags] + ags = self.cs.agents.list('xen') + self.cs.assert_called('GET', '/os-agents?hypervisor=xen') + for a in ags: + self.assertIsInstance(a, self.agent_type) + self.assertEqual(a.hypervisor, 'xen') def test_agents_create(self): - ag = cs.agents.create('win', 'x86', '7.0', + ag = self.cs.agents.create('win', 'x86', '7.0', '/xxx/xxx/xxx', 'add6bb58e139be103324d04d82d8f546', 'xen') @@ -49,20 +56,23 @@ 'version': '7.0', 'architecture': 'x86', 'os': 'win'}} - cs.assert_called('POST', '/os-agents', body) + self.cs.assert_called('POST', '/os-agents', body) self.assertEqual(1, ag._info.copy()['id']) def test_agents_delete(self): - cs.agents.delete('1') - cs.assert_called('DELETE', '/os-agents/1') + self.cs.agents.delete('1') + self.cs.assert_called('DELETE', '/os-agents/1') + + def _build_example_update_body(self): + return {"para": { + "url": "/yyy/yyyy/yyyy", + "version": "8.0", + "md5hash": "add6bb58e139be103324d04d82d8f546"}} def test_agents_modify(self): - ag = cs.agents.update('1', '8.0', + ag = self.cs.agents.update('1', '8.0', '/yyy/yyyy/yyyy', 'add6bb58e139be103324d04d82d8f546') - body = {"para": { - "url": "/yyy/yyyy/yyyy", - "version": "8.0", - "md5hash": "add6bb58e139be103324d04d82d8f546"}} - cs.assert_called('PUT', '/os-agents/1', body) + body = self._build_example_update_body() + self.cs.assert_called('PUT', '/os-agents/1', body) self.assertEqual(1, ag.id) diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/test_aggregates.py python-novaclient-2.16.0/novaclient/tests/v1_1/test_aggregates.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/test_aggregates.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/test_aggregates.py 2014-02-26 16:28:51.000000000 +0000 @@ -13,126 +13,133 @@ # License for the specific language governing permissions and limitations # under the License. -from novaclient.v1_1 import aggregates from novaclient.tests import utils from novaclient.tests.v1_1 import fakes +from novaclient.v1_1 import aggregates -cs = fakes.FakeClient() +class AggregatesTest(utils.TestCase): + def setUp(self): + super(AggregatesTest, self).setUp() + self.cs = self._get_fake_client() + self.aggregate_type = self._get_aggregate_type() + def _get_fake_client(self): + return fakes.FakeClient() -class AggregatesTest(utils.TestCase): + def _get_aggregate_type(self): + return aggregates.Aggregate def test_list_aggregates(self): - result = cs.aggregates.list() - cs.assert_called('GET', '/os-aggregates') + result = self.cs.aggregates.list() + self.cs.assert_called('GET', '/os-aggregates') for aggregate in result: - self.assertTrue(isinstance(aggregate, aggregates.Aggregate)) + self.assertIsInstance(aggregate, aggregates.Aggregate) def test_create_aggregate(self): body = {"aggregate": {"name": "test", "availability_zone": "nova1"}} - aggregate = cs.aggregates.create("test", "nova1") - cs.assert_called('POST', '/os-aggregates', body) - self.assertTrue(isinstance(aggregate, aggregates.Aggregate)) + aggregate = self.cs.aggregates.create("test", "nova1") + self.cs.assert_called('POST', '/os-aggregates', body) + self.assertIsInstance(aggregate, aggregates.Aggregate) def test_get(self): - aggregate = cs.aggregates.get("1") - cs.assert_called('GET', '/os-aggregates/1') - self.assertTrue(isinstance(aggregate, aggregates.Aggregate)) - - aggregate2 = cs.aggregates.get(aggregate) - cs.assert_called('GET', '/os-aggregates/1') - self.assertTrue(isinstance(aggregate2, aggregates.Aggregate)) + aggregate = self.cs.aggregates.get("1") + self.cs.assert_called('GET', '/os-aggregates/1') + self.assertIsInstance(aggregate, aggregates.Aggregate) + + aggregate2 = self.cs.aggregates.get(aggregate) + self.cs.assert_called('GET', '/os-aggregates/1') + self.assertIsInstance(aggregate2, aggregates.Aggregate) def test_get_details(self): - aggregate = cs.aggregates.get_details("1") - cs.assert_called('GET', '/os-aggregates/1') - self.assertTrue(isinstance(aggregate, aggregates.Aggregate)) - - aggregate2 = cs.aggregates.get_details(aggregate) - cs.assert_called('GET', '/os-aggregates/1') - self.assertTrue(isinstance(aggregate2, aggregates.Aggregate)) + aggregate = self.cs.aggregates.get_details("1") + self.cs.assert_called('GET', '/os-aggregates/1') + self.assertIsInstance(aggregate, aggregates.Aggregate) + + aggregate2 = self.cs.aggregates.get_details(aggregate) + self.cs.assert_called('GET', '/os-aggregates/1') + self.assertIsInstance(aggregate2, aggregates.Aggregate) def test_update(self): - aggregate = cs.aggregates.get("1") + aggregate = self.cs.aggregates.get("1") values = {"name": "foo"} body = {"aggregate": values} result1 = aggregate.update(values) - cs.assert_called('PUT', '/os-aggregates/1', body) - self.assertTrue(isinstance(result1, aggregates.Aggregate)) + self.cs.assert_called('PUT', '/os-aggregates/1', body) + self.assertIsInstance(result1, aggregates.Aggregate) - result2 = cs.aggregates.update(2, values) - cs.assert_called('PUT', '/os-aggregates/2', body) - self.assertTrue(isinstance(result2, aggregates.Aggregate)) + result2 = self.cs.aggregates.update(2, values) + self.cs.assert_called('PUT', '/os-aggregates/2', body) + self.assertIsInstance(result2, aggregates.Aggregate) def test_update_with_availability_zone(self): - aggregate = cs.aggregates.get("1") + aggregate = self.cs.aggregates.get("1") values = {"name": "foo", "availability_zone": "new_zone"} body = {"aggregate": values} - result3 = cs.aggregates.update(aggregate, values) - cs.assert_called('PUT', '/os-aggregates/1', body) - self.assertTrue(isinstance(result3, aggregates.Aggregate)) + result3 = self.cs.aggregates.update(aggregate, values) + self.cs.assert_called('PUT', '/os-aggregates/1', body) + self.assertIsInstance(result3, aggregates.Aggregate) def test_add_host(self): - aggregate = cs.aggregates.get("1") + aggregate = self.cs.aggregates.get("1") host = "host1" body = {"add_host": {"host": "host1"}} result1 = aggregate.add_host(host) - cs.assert_called('POST', '/os-aggregates/1/action', body) - self.assertTrue(isinstance(result1, aggregates.Aggregate)) + self.cs.assert_called('POST', '/os-aggregates/1/action', body) + self.assertIsInstance(result1, aggregates.Aggregate) - result2 = cs.aggregates.add_host("2", host) - cs.assert_called('POST', '/os-aggregates/2/action', body) - self.assertTrue(isinstance(result2, aggregates.Aggregate)) - - result3 = cs.aggregates.add_host(aggregate, host) - cs.assert_called('POST', '/os-aggregates/1/action', body) - self.assertTrue(isinstance(result3, aggregates.Aggregate)) + result2 = self.cs.aggregates.add_host("2", host) + self.cs.assert_called('POST', '/os-aggregates/2/action', body) + self.assertIsInstance(result2, aggregates.Aggregate) + + result3 = self.cs.aggregates.add_host(aggregate, host) + self.cs.assert_called('POST', '/os-aggregates/1/action', body) + self.assertIsInstance(result3, aggregates.Aggregate) def test_remove_host(self): - aggregate = cs.aggregates.get("1") + aggregate = self.cs.aggregates.get("1") host = "host1" body = {"remove_host": {"host": "host1"}} result1 = aggregate.remove_host(host) - cs.assert_called('POST', '/os-aggregates/1/action', body) - self.assertTrue(isinstance(result1, aggregates.Aggregate)) + self.cs.assert_called('POST', '/os-aggregates/1/action', body) + self.assertIsInstance(result1, aggregates.Aggregate) - result2 = cs.aggregates.remove_host("2", host) - cs.assert_called('POST', '/os-aggregates/2/action', body) - self.assertTrue(isinstance(result2, aggregates.Aggregate)) - - result3 = cs.aggregates.remove_host(aggregate, host) - cs.assert_called('POST', '/os-aggregates/1/action', body) - self.assertTrue(isinstance(result3, aggregates.Aggregate)) + result2 = self.cs.aggregates.remove_host("2", host) + self.cs.assert_called('POST', '/os-aggregates/2/action', body) + self.assertIsInstance(result2, aggregates.Aggregate) + + result3 = self.cs.aggregates.remove_host(aggregate, host) + self.cs.assert_called('POST', '/os-aggregates/1/action', body) + self.assertIsInstance(result3, aggregates.Aggregate) def test_set_metadata(self): - aggregate = cs.aggregates.get("1") + aggregate = self.cs.aggregates.get("1") metadata = {"foo": "bar"} body = {"set_metadata": {"metadata": metadata}} result1 = aggregate.set_metadata(metadata) - cs.assert_called('POST', '/os-aggregates/1/action', body) - self.assertTrue(isinstance(result1, aggregates.Aggregate)) + self.cs.assert_called('POST', '/os-aggregates/1/action', body) + self.assertIsInstance(result1, aggregates.Aggregate) - result2 = cs.aggregates.set_metadata(2, metadata) - cs.assert_called('POST', '/os-aggregates/2/action', body) - self.assertTrue(isinstance(result2, aggregates.Aggregate)) - - result3 = cs.aggregates.set_metadata(aggregate, metadata) - cs.assert_called('POST', '/os-aggregates/1/action', body) - self.assertTrue(isinstance(result3, aggregates.Aggregate)) + result2 = self.cs.aggregates.set_metadata(2, metadata) + self.cs.assert_called('POST', '/os-aggregates/2/action', body) + self.assertIsInstance(result2, aggregates.Aggregate) + + result3 = self.cs.aggregates.set_metadata(aggregate, metadata) + self.cs.assert_called('POST', '/os-aggregates/1/action', body) + self.assertIsInstance(result3, aggregates.Aggregate) def test_delete_aggregate(self): - aggregate = cs.aggregates.list()[0] + aggregate = self.cs.aggregates.list()[0] aggregate.delete() - cs.assert_called('DELETE', '/os-aggregates/1') + self.cs.assert_called('DELETE', '/os-aggregates/1') - cs.aggregates.delete('1') - cs.assert_called('DELETE', '/os-aggregates/1') + self.cs.aggregates.delete('1') + self.cs.assert_called('DELETE', '/os-aggregates/1') - cs.aggregates.delete(aggregate) - cs.assert_called('DELETE', '/os-aggregates/1') + self.cs.aggregates.delete(aggregate) + self.cs.assert_called('DELETE', '/os-aggregates/1') diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/test_auth.py python-novaclient-2.16.0/novaclient/tests/v1_1/test_auth.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/test_auth.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/test_auth.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,12 +1,25 @@ +# +# 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 copy import json -import mock +import mock import requests -from novaclient.v1_1 import client from novaclient import exceptions from novaclient.tests import utils +from novaclient.v1_1 import client class AuthenticateAgainstKeystoneTests(utils.TestCase): @@ -325,6 +338,86 @@ test_auth_call() + def test_authenticate_with_token_success(self): + cs = client.Client("username", None, "project_id", + "auth_url/v2.0", service_type='compute') + cs.client.auth_token = "FAKE_ID" + resp = { + "access": { + "token": { + "expires": "12345", + "id": "FAKE_ID", + "tenant": { + "id": "FAKE_TENANT_ID", + } + }, + "serviceCatalog": [ + { + "type": "compute", + "endpoints": [ + { + "region": "RegionOne", + "adminURL": "http://localhost:8774/v1.1", + "internalURL": "http://localhost:8774/v1.1", + "publicURL": "http://localhost:8774/v1.1/", + }, + ], + }, + ], + }, + } + auth_response = utils.TestResponse({ + "status_code": 200, + "text": json.dumps(resp), + }) + + mock_request = mock.Mock(return_value=(auth_response)) + + with mock.patch.object(requests.Session, "request", mock_request): + cs.client.authenticate() + headers = { + 'User-Agent': cs.client.USER_AGENT, + 'Content-Type': 'application/json', + 'Accept': 'application/json', + } + body = { + 'auth': { + 'token': { + 'id': cs.client.auth_token, + }, + 'tenantName': cs.client.projectid, + }, + } + + token_url = cs.client.auth_url + "/tokens" + mock_request.assert_called_with( + "POST", + token_url, + headers=headers, + data=json.dumps(body), + allow_redirects=True, + **self.TEST_REQUEST_BASE) + + endpoints = resp["access"]["serviceCatalog"][0]['endpoints'] + public_url = endpoints[0]["publicURL"].rstrip('/') + self.assertEqual(cs.client.management_url, public_url) + token_id = resp["access"]["token"]["id"] + self.assertEqual(cs.client.auth_token, token_id) + + def test_authenticate_with_token_failure(self): + cs = client.Client("username", None, "project_id", "auth_url/v2.0") + cs.client.auth_token = "FAKE_ID" + resp = {"unauthorized": {"message": "Unauthorized", "code": "401"}} + auth_response = utils.TestResponse({ + "status_code": 401, + "text": json.dumps(resp), + }) + + mock_request = mock.Mock(return_value=(auth_response)) + + with mock.patch.object(requests.Session, "request", mock_request): + self.assertRaises(exceptions.Unauthorized, cs.client.authenticate) + class AuthenticationTests(utils.TestCase): def test_authenticate_success(self): diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/test_availability_zone.py python-novaclient-2.16.0/novaclient/tests/v1_1/test_availability_zone.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/test_availability_zone.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/test_availability_zone.py 2014-02-26 16:28:51.000000000 +0000 @@ -16,36 +16,45 @@ import six -from novaclient.v1_1 import availability_zones -from novaclient.v1_1 import shell -from novaclient.tests.v1_1 import fakes from novaclient.tests import utils +from novaclient.tests.v1_1 import fakes +from novaclient.v1_1 import availability_zones -cs = fakes.FakeClient() +class AvailabilityZoneTest(utils.TestCase): + # NOTE(cyeoh): import shell here so the V3 version of + # this class can inherit off the v3 version of shell + from novaclient.v1_1 import shell # noqa + + def setUp(self): + super(AvailabilityZoneTest, self).setUp() + self.cs = self._get_fake_client() + self.availability_zone_type = self._get_availability_zone_type() + def _get_fake_client(self): + return fakes.FakeClient() -class AvailabilityZoneTest(utils.TestCase): + def _get_availability_zone_type(self): + return availability_zones.AvailabilityZone def _assertZone(self, zone, name, status): self.assertEqual(zone.zoneName, name) self.assertEqual(zone.zoneState, status) def test_list_availability_zone(self): - zones = cs.availability_zones.list(detailed=False) - cs.assert_called('GET', '/os-availability-zone') + zones = self.cs.availability_zones.list(detailed=False) + self.cs.assert_called('GET', '/os-availability-zone') for zone in zones: - self.assertTrue(isinstance(zone, - availability_zones.AvailabilityZone)) + self.assertIsInstance(zone, self.availability_zone_type) self.assertEqual(2, len(zones)) l0 = [six.u('zone-1'), six.u('available')] l1 = [six.u('zone-2'), six.u('not available')] - z0 = shell._treeizeAvailabilityZone(zones[0]) - z1 = shell._treeizeAvailabilityZone(zones[1]) + z0 = self.shell._treeizeAvailabilityZone(zones[0]) + z1 = self.shell._treeizeAvailabilityZone(zones[1]) self.assertEqual((len(z0), len(z1)), (1, 1)) @@ -53,12 +62,11 @@ self._assertZone(z1[0], l1[0], l1[1]) def test_detail_availability_zone(self): - zones = cs.availability_zones.list(detailed=True) - cs.assert_called('GET', '/os-availability-zone/detail') + zones = self.cs.availability_zones.list(detailed=True) + self.cs.assert_called('GET', '/os-availability-zone/detail') for zone in zones: - self.assertTrue(isinstance(zone, - availability_zones.AvailabilityZone)) + self.assertIsInstance(zone, self.availability_zone_type) self.assertEqual(3, len(zones)) @@ -75,9 +83,9 @@ six.u('enabled XXX 2012-12-26 14:45:24')] l8 = [six.u('zone-2'), six.u('not available')] - z0 = shell._treeizeAvailabilityZone(zones[0]) - z1 = shell._treeizeAvailabilityZone(zones[1]) - z2 = shell._treeizeAvailabilityZone(zones[2]) + z0 = self.shell._treeizeAvailabilityZone(zones[0]) + z1 = self.shell._treeizeAvailabilityZone(zones[1]) + z2 = self.shell._treeizeAvailabilityZone(zones[2]) self.assertEqual((len(z0), len(z1), len(z2)), (3, 5, 1)) diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/test_certs.py python-novaclient-2.16.0/novaclient/tests/v1_1/test_certs.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/test_certs.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/test_certs.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,19 +1,39 @@ -from novaclient.v1_1 import certs +# +# 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 novaclient.tests import utils from novaclient.tests.v1_1 import fakes +from novaclient.v1_1 import certs -cs = fakes.FakeClient() +class CertsTest(utils.TestCase): + def setUp(self): + super(CertsTest, self).setUp() + self.cs = self._get_fake_client() + self.cert_type = self._get_cert_type() + def _get_fake_client(self): + return fakes.FakeClient() -class FlavorsTest(utils.TestCase): + def _get_cert_type(self): + return certs.Certificate def test_create_cert(self): - cert = cs.certs.create() - cs.assert_called('POST', '/os-certificates') - self.assertTrue(isinstance(cert, certs.Certificate)) + cert = self.cs.certs.create() + self.cs.assert_called('POST', '/os-certificates') + self.assertIsInstance(cert, certs.Certificate) def test_get_root_cert(self): - cert = cs.certs.get() - cs.assert_called('GET', '/os-certificates/root') - self.assertTrue(isinstance(cert, certs.Certificate)) + cert = self.cs.certs.get() + self.cs.assert_called('GET', '/os-certificates/root') + self.assertIsInstance(cert, certs.Certificate) diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/test_cloudpipe.py python-novaclient-2.16.0/novaclient/tests/v1_1/test_cloudpipe.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/test_cloudpipe.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/test_cloudpipe.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,6 +1,19 @@ -from novaclient.v1_1 import cloudpipe +# +# 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 novaclient.tests import utils from novaclient.tests.v1_1 import fakes +from novaclient.v1_1 import cloudpipe cs = fakes.FakeClient() @@ -11,14 +24,14 @@ def test_list_cloudpipes(self): cp = cs.cloudpipe.list() cs.assert_called('GET', '/os-cloudpipe') - [self.assertTrue(isinstance(c, cloudpipe.Cloudpipe)) for c in cp] + [self.assertIsInstance(c, cloudpipe.Cloudpipe) for c in cp] def test_create(self): project = "test" cp = cs.cloudpipe.create(project) body = {'cloudpipe': {'project_id': project}} cs.assert_called('POST', '/os-cloudpipe', body) - self.assertTrue(isinstance(cp, str)) + self.assertIsInstance(cp, str) def test_update(self): cs.cloudpipe.update("192.168.1.1", 2345) diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/test_coverage_ext.py python-novaclient-2.16.0/novaclient/tests/v1_1/test_coverage_ext.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/test_coverage_ext.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/test_coverage_ext.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2012 IBM Corp. -# -# 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. - -# See: http://wiki.openstack.org/Nova/CoverageExtension for more information -# and usage explanation for this API extension - -from novaclient.tests import utils -from novaclient.tests.v1_1 import fakes - - -cs = fakes.FakeClient() - - -class CoverageTest(utils.TestCase): - - def test_start_coverage(self): - c = cs.coverage.start() - cs.assert_called('POST', '/os-coverage/action') - - def test_stop_coverage(self): - c = cs.coverage.stop() - return_dict = {'path': '/tmp/tmpdir/report'} - cs.assert_called_anytime('POST', '/os-coverage/action') - - def test_report_coverage(self): - c = cs.coverage.report('report') - return_dict = {'path': '/tmp/tmpdir/report'} - cs.assert_called_anytime('POST', '/os-coverage/action') - - def test_reset_coverage(self): - c = cs.coverage.reset() - cs.assert_called_anytime('POST', '/os-coverage/action') diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/test_fixed_ips.py python-novaclient-2.16.0/novaclient/tests/v1_1/test_fixed_ips.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/test_fixed_ips.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/test_fixed_ips.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,5 +1,3 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - # Copyright 2012 IBM Corp. # All Rights Reserved. # @@ -15,8 +13,8 @@ # License for the specific language governing permissions and limitations # under the License. -from novaclient.tests.v1_1 import fakes from novaclient.tests import utils +from novaclient.tests.v1_1 import fakes cs = fakes.FakeClient() diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/test_flavor_access.py python-novaclient-2.16.0/novaclient/tests/v1_1/test_flavor_access.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/test_flavor_access.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/test_flavor_access.py 2014-02-26 16:28:51.000000000 +0000 @@ -13,9 +13,9 @@ # License for the specific language governing permissions and limitations # under the License. -from novaclient.v1_1 import flavor_access from novaclient.tests import utils from novaclient.tests.v1_1 import fakes +from novaclient.v1_1 import flavor_access cs = fakes.FakeClient() @@ -27,7 +27,7 @@ kwargs = {'flavor': cs.flavors.get(2)} r = cs.flavor_access.list(**kwargs) cs.assert_called('GET', '/flavors/2/os-flavor-access') - [self.assertTrue(isinstance(a, flavor_access.FlavorAccess)) for a in r] + [self.assertIsInstance(a, flavor_access.FlavorAccess) for a in r] def test_add_tenant_access(self): flavor = cs.flavors.get(2) @@ -41,7 +41,7 @@ } cs.assert_called('POST', '/flavors/2/action', body) - [self.assertTrue(isinstance(a, flavor_access.FlavorAccess)) for a in r] + [self.assertIsInstance(a, flavor_access.FlavorAccess) for a in r] def test_remove_tenant_access(self): flavor = cs.flavors.get(2) @@ -55,4 +55,4 @@ } cs.assert_called('POST', '/flavors/2/action', body) - [self.assertTrue(isinstance(a, flavor_access.FlavorAccess)) for a in r] + [self.assertIsInstance(a, flavor_access.FlavorAccess) for a in r] diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/test_flavors.py python-novaclient-2.16.0/novaclient/tests/v1_1/test_flavors.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/test_flavors.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/test_flavors.py 2014-02-26 16:28:51.000000000 +0000 @@ -14,191 +14,199 @@ # under the License. from novaclient import exceptions -from novaclient.v1_1 import flavors from novaclient.tests import utils from novaclient.tests.v1_1 import fakes +from novaclient.v1_1 import flavors -cs = fakes.FakeClient() +class FlavorsTest(utils.TestCase): + def setUp(self): + super(FlavorsTest, self).setUp() + self.cs = self._get_fake_client() + self.flavor_type = self._get_flavor_type() + def _get_fake_client(self): + return fakes.FakeClient() -class FlavorsTest(utils.TestCase): + def _get_flavor_type(self): + return flavors.Flavor def test_list_flavors(self): - fl = cs.flavors.list() - cs.assert_called('GET', '/flavors/detail') + fl = self.cs.flavors.list() + self.cs.assert_called('GET', '/flavors/detail') for flavor in fl: - self.assertTrue(isinstance(flavor, flavors.Flavor)) + self.assertIsInstance(flavor, self.flavor_type) def test_list_flavors_undetailed(self): - fl = cs.flavors.list(detailed=False) - cs.assert_called('GET', '/flavors') + fl = self.cs.flavors.list(detailed=False) + self.cs.assert_called('GET', '/flavors') for flavor in fl: - self.assertTrue(isinstance(flavor, flavors.Flavor)) + self.assertIsInstance(flavor, self.flavor_type) def test_list_flavors_is_public_none(self): - fl = cs.flavors.list(is_public=None) - cs.assert_called('GET', '/flavors/detail?is_public=None') + fl = self.cs.flavors.list(is_public=None) + self.cs.assert_called('GET', '/flavors/detail?is_public=None') for flavor in fl: - self.assertTrue(isinstance(flavor, flavors.Flavor)) + self.assertIsInstance(flavor, self.flavor_type) def test_list_flavors_is_public_false(self): - fl = cs.flavors.list(is_public=False) - cs.assert_called('GET', '/flavors/detail?is_public=False') + fl = self.cs.flavors.list(is_public=False) + self.cs.assert_called('GET', '/flavors/detail?is_public=False') for flavor in fl: - self.assertTrue(isinstance(flavor, flavors.Flavor)) + self.assertIsInstance(flavor, self.flavor_type) def test_list_flavors_is_public_true(self): - fl = cs.flavors.list(is_public=True) - cs.assert_called('GET', '/flavors/detail') + fl = self.cs.flavors.list(is_public=True) + self.cs.assert_called('GET', '/flavors/detail') for flavor in fl: - self.assertTrue(isinstance(flavor, flavors.Flavor)) + self.assertIsInstance(flavor, self.flavor_type) def test_get_flavor_details(self): - f = cs.flavors.get(1) - cs.assert_called('GET', '/flavors/1') - self.assertTrue(isinstance(f, flavors.Flavor)) + f = self.cs.flavors.get(1) + self.cs.assert_called('GET', '/flavors/1') + self.assertIsInstance(f, self.flavor_type) self.assertEqual(f.ram, 256) self.assertEqual(f.disk, 10) self.assertEqual(f.ephemeral, 10) self.assertEqual(f.is_public, True) def test_get_flavor_details_alphanum_id(self): - f = cs.flavors.get('aa1') - cs.assert_called('GET', '/flavors/aa1') - self.assertTrue(isinstance(f, flavors.Flavor)) + f = self.cs.flavors.get('aa1') + self.cs.assert_called('GET', '/flavors/aa1') + self.assertIsInstance(f, self.flavor_type) self.assertEqual(f.ram, 128) self.assertEqual(f.disk, 0) self.assertEqual(f.ephemeral, 0) self.assertEqual(f.is_public, True) def test_get_flavor_details_diablo(self): - f = cs.flavors.get(3) - cs.assert_called('GET', '/flavors/3') - self.assertTrue(isinstance(f, flavors.Flavor)) + f = self.cs.flavors.get(3) + self.cs.assert_called('GET', '/flavors/3') + self.assertIsInstance(f, self.flavor_type) self.assertEqual(f.ram, 256) self.assertEqual(f.disk, 10) self.assertEqual(f.ephemeral, 'N/A') self.assertEqual(f.is_public, 'N/A') def test_find(self): - f = cs.flavors.find(ram=256) - cs.assert_called('GET', '/flavors/detail') + f = self.cs.flavors.find(ram=256) + self.cs.assert_called('GET', '/flavors/detail') self.assertEqual(f.name, '256 MB Server') - f = cs.flavors.find(disk=0) + f = self.cs.flavors.find(disk=0) self.assertEqual(f.name, '128 MB Server') - self.assertRaises(exceptions.NotFound, cs.flavors.find, disk=12345) + self.assertRaises(exceptions.NotFound, self.cs.flavors.find, + disk=12345) - def test_create(self): - f = cs.flavors.create("flavorcreate", 512, 1, 10, 1234, ephemeral=10, - is_public=False) - - body = { + def _create_body(self, name, ram, vcpus, disk, ephemeral, id, swap, + rxtx_factor, is_public): + return { "flavor": { - "name": "flavorcreate", - "ram": 512, - "vcpus": 1, - "disk": 10, - "OS-FLV-EXT-DATA:ephemeral": 10, - "id": 1234, - "swap": 0, - "rxtx_factor": 1.0, - "os-flavor-access:is_public": False, + "name": name, + "ram": ram, + "vcpus": vcpus, + "disk": disk, + "OS-FLV-EXT-DATA:ephemeral": ephemeral, + "id": id, + "swap": swap, + "rxtx_factor": rxtx_factor, + "os-flavor-access:is_public": is_public, } } - cs.assert_called('POST', '/flavors', body) - self.assertTrue(isinstance(f, flavors.Flavor)) + def test_create(self): + f = self.cs.flavors.create("flavorcreate", 512, 1, 10, 1234, + ephemeral=10, is_public=False) + + body = self._create_body("flavorcreate", 512, 1, 10, 10, 1234, 0, 1.0, + False) + + self.cs.assert_called('POST', '/flavors', body) + self.assertIsInstance(f, self.flavor_type) def test_create_with_id_as_string(self): flavor_id = 'foobar' - f = cs.flavors.create("flavorcreate", 512, + f = self.cs.flavors.create("flavorcreate", 512, 1, 10, flavor_id, ephemeral=10, is_public=False) - body = { - "flavor": { - "name": "flavorcreate", - "ram": 512, - "vcpus": 1, - "disk": 10, - "OS-FLV-EXT-DATA:ephemeral": 10, - "id": flavor_id, - "swap": 0, - "rxtx_factor": 1.0, - "os-flavor-access:is_public": False, - } - } + body = self._create_body("flavorcreate", 512, 1, 10, 10, flavor_id, 0, + 1.0, False) - cs.assert_called('POST', '/flavors', body) - self.assertTrue(isinstance(f, flavors.Flavor)) + self.cs.assert_called('POST', '/flavors', body) + self.assertIsInstance(f, self.flavor_type) def test_create_ephemeral_ispublic_defaults(self): - f = cs.flavors.create("flavorcreate", 512, 1, 10, 1234) + f = self.cs.flavors.create("flavorcreate", 512, 1, 10, 1234) - body = { - "flavor": { - "name": "flavorcreate", - "ram": 512, - "vcpus": 1, - "disk": 10, - "OS-FLV-EXT-DATA:ephemeral": 0, - "id": 1234, - "swap": 0, - "rxtx_factor": 1.0, - "os-flavor-access:is_public": True, - } - } + body = self._create_body("flavorcreate", 512, 1, 10, 0, 1234, 0, + 1.0, True) - cs.assert_called('POST', '/flavors', body) - self.assertTrue(isinstance(f, flavors.Flavor)) + self.cs.assert_called('POST', '/flavors', body) + self.assertIsInstance(f, self.flavor_type) def test_invalid_parameters_create(self): - self.assertRaises(exceptions.CommandError, cs.flavors.create, + self.assertRaises(exceptions.CommandError, self.cs.flavors.create, "flavorcreate", "invalid", 1, 10, 1234, swap=0, ephemeral=0, rxtx_factor=1.0, is_public=True) - self.assertRaises(exceptions.CommandError, cs.flavors.create, + self.assertRaises(exceptions.CommandError, self.cs.flavors.create, "flavorcreate", 512, "invalid", 10, 1234, swap=0, ephemeral=0, rxtx_factor=1.0, is_public=True) - self.assertRaises(exceptions.CommandError, cs.flavors.create, + self.assertRaises(exceptions.CommandError, self.cs.flavors.create, "flavorcreate", 512, 1, "invalid", 1234, swap=0, ephemeral=0, rxtx_factor=1.0, is_public=True) - self.assertRaises(exceptions.CommandError, cs.flavors.create, + self.assertRaises(exceptions.CommandError, self.cs.flavors.create, "flavorcreate", 512, 1, 10, 1234, swap="invalid", ephemeral=0, rxtx_factor=1.0, is_public=True) - self.assertRaises(exceptions.CommandError, cs.flavors.create, + self.assertRaises(exceptions.CommandError, self.cs.flavors.create, "flavorcreate", 512, 1, 10, 1234, swap=0, ephemeral="invalid", rxtx_factor=1.0, is_public=True) - self.assertRaises(exceptions.CommandError, cs.flavors.create, + self.assertRaises(exceptions.CommandError, self.cs.flavors.create, "flavorcreate", 512, 1, 10, 1234, swap=0, ephemeral=0, rxtx_factor="invalid", is_public=True) - self.assertRaises(exceptions.CommandError, cs.flavors.create, + self.assertRaises(exceptions.CommandError, self.cs.flavors.create, "flavorcreate", 512, 1, 10, 1234, swap=0, ephemeral=0, rxtx_factor=1.0, is_public='invalid') def test_delete(self): - cs.flavors.delete("flavordelete") - cs.assert_called('DELETE', '/flavors/flavordelete') + self.cs.flavors.delete("flavordelete") + self.cs.assert_called('DELETE', '/flavors/flavordelete') def test_delete_with_flavor_instance(self): - f = cs.flavors.get(2) - cs.flavors.delete(f) - cs.assert_called('DELETE', '/flavors/2') + f = self.cs.flavors.get(2) + self.cs.flavors.delete(f) + self.cs.assert_called('DELETE', '/flavors/2') def test_delete_with_flavor_instance_method(self): - f = cs.flavors.get(2) + f = self.cs.flavors.get(2) f.delete() - cs.assert_called('DELETE', '/flavors/2') + self.cs.assert_called('DELETE', '/flavors/2') def test_set_keys(self): - f = cs.flavors.get(1) + f = self.cs.flavors.get(1) f.set_keys({'k1': 'v1'}) - cs.assert_called('POST', '/flavors/1/os-extra_specs', + self.cs.assert_called('POST', '/flavors/1/os-extra_specs', {"extra_specs": {'k1': 'v1'}}) + def test_set_with_valid_keys(self): + valid_keys = ['key4', 'month.price', 'I-Am:AK-ey.44-', + 'key with spaces and _'] + + f = self.cs.flavors.get(4) + for key in valid_keys: + f.set_keys({key: 'v4'}) + self.cs.assert_called('POST', '/flavors/4/os-extra_specs', + {"extra_specs": {key: 'v4'}}) + + def test_set_with_invalid_keys(self): + invalid_keys = ['/1', '?1', '%1', '<', '>'] + + f = self.cs.flavors.get(1) + for key in invalid_keys: + self.assertRaises(exceptions.CommandError, f.set_keys, {key: 'v1'}) + def test_unset_keys(self): - f = cs.flavors.get(1) + f = self.cs.flavors.get(1) f.unset_keys(['k1']) - cs.assert_called('DELETE', '/flavors/1/os-extra_specs/k1') + self.cs.assert_called('DELETE', '/flavors/1/os-extra_specs/k1') diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/test_floating_ip_dns.py python-novaclient-2.16.0/novaclient/tests/v1_1/test_floating_ip_dns.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/test_floating_ip_dns.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/test_floating_ip_dns.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,6 +1,19 @@ -from novaclient.v1_1 import floating_ip_dns -from novaclient.tests.v1_1 import fakes +# +# 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 novaclient.tests import utils +from novaclient.tests.v1_1 import fakes +from novaclient.v1_1 import floating_ip_dns cs = fakes.FakeClient() @@ -15,8 +28,8 @@ self.assertEqual(len(domainlist), 2) for entry in domainlist: - self.assertTrue(isinstance(entry, - floating_ip_dns.FloatingIPDNSDomain)) + self.assertIsInstance(entry, + floating_ip_dns.FloatingIPDNSDomain) self.assertEqual(domainlist[1].domain, 'example.com') @@ -48,8 +61,8 @@ self.assertEqual(len(entries), 2) for entry in entries: - self.assertTrue(isinstance(entry, - floating_ip_dns.FloatingIPDNSEntry)) + self.assertIsInstance(entry, + floating_ip_dns.FloatingIPDNSEntry) self.assertEqual(entries[1].dns_entry['name'], 'host2') self.assertEqual(entries[1].dns_entry['ip'], self.testip) @@ -57,7 +70,7 @@ def test_get_dns_entry_by_name(self): entry = cs.dns_entries.get(self.testdomain, self.testname) - self.assertTrue(isinstance(entry, floating_ip_dns.FloatingIPDNSEntry)) + self.assertIsInstance(entry, floating_ip_dns.FloatingIPDNSEntry) self.assertEqual(entry.name, self.testname) def test_create_entry(self): diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/test_floating_ip_pools.py python-novaclient-2.16.0/novaclient/tests/v1_1/test_floating_ip_pools.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/test_floating_ip_pools.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/test_floating_ip_pools.py 2014-02-26 16:28:51.000000000 +0000 @@ -14,9 +14,9 @@ # License for the specific language governing permissions and limitations # under the License. -from novaclient.v1_1 import floating_ip_pools from novaclient.tests import utils from novaclient.tests.v1_1 import fakes +from novaclient.v1_1 import floating_ip_pools cs = fakes.FakeClient() @@ -27,5 +27,5 @@ def test_list_floating_ips(self): fl = cs.floating_ip_pools.list() cs.assert_called('GET', '/os-floating-ip-pools') - [self.assertTrue(isinstance(f, floating_ip_pools.FloatingIPPool)) + [self.assertIsInstance(f, floating_ip_pools.FloatingIPPool) for f in fl] diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/test_floating_ips_bulk.py python-novaclient-2.16.0/novaclient/tests/v1_1/test_floating_ips_bulk.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/test_floating_ips_bulk.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/test_floating_ips_bulk.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,5 +1,3 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - # Copyright 2012 IBM Corp. # All Rights Reserved. # @@ -14,9 +12,10 @@ # 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 novaclient.v1_1 import floating_ips_bulk + from novaclient.tests import utils from novaclient.tests.v1_1 import fakes +from novaclient.v1_1 import floating_ips_bulk cs = fakes.FakeClient() @@ -27,13 +26,13 @@ def test_list_floating_ips_bulk(self): fl = cs.floating_ips_bulk.list() cs.assert_called('GET', '/os-floating-ips-bulk') - [self.assertTrue(isinstance(f, floating_ips_bulk.FloatingIP)) + [self.assertIsInstance(f, floating_ips_bulk.FloatingIP) for f in fl] def test_list_floating_ips_bulk_host_filter(self): fl = cs.floating_ips_bulk.list('testHost') cs.assert_called('GET', '/os-floating-ips-bulk/testHost') - [self.assertTrue(isinstance(f, floating_ips_bulk.FloatingIP)) + [self.assertIsInstance(f, floating_ips_bulk.FloatingIP) for f in fl] def test_create_floating_ips_bulk(self): diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/test_floating_ips.py python-novaclient-2.16.0/novaclient/tests/v1_1/test_floating_ips.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/test_floating_ips.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/test_floating_ips.py 2014-02-26 16:28:51.000000000 +0000 @@ -14,9 +14,9 @@ # License for the specific language governing permissions and limitations # under the License. -from novaclient.v1_1 import floating_ips from novaclient.tests import utils from novaclient.tests.v1_1 import fakes +from novaclient.v1_1 import floating_ips cs = fakes.FakeClient() @@ -27,7 +27,7 @@ def test_list_floating_ips(self): fl = cs.floating_ips.list() cs.assert_called('GET', '/os-floating-ips') - [self.assertTrue(isinstance(f, floating_ips.FloatingIP)) for f in fl] + [self.assertIsInstance(f, floating_ips.FloatingIP) for f in fl] def test_delete_floating_ip(self): fl = cs.floating_ips.list()[0] @@ -41,11 +41,11 @@ def test_create_floating_ip(self): fl = cs.floating_ips.create() cs.assert_called('POST', '/os-floating-ips') - self.assertEqual(fl.pool, None) - self.assertTrue(isinstance(fl, floating_ips.FloatingIP)) + self.assertIsNone(fl.pool) + self.assertIsInstance(fl, floating_ips.FloatingIP) def test_create_floating_ip_with_pool(self): fl = cs.floating_ips.create('foo') cs.assert_called('POST', '/os-floating-ips') self.assertEqual(fl.pool, 'nova') - self.assertTrue(isinstance(fl, floating_ips.FloatingIP)) + self.assertIsInstance(fl, floating_ips.FloatingIP) diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/test_fping.py python-novaclient-2.16.0/novaclient/tests/v1_1/test_fping.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/test_fping.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/test_fping.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,5 +1,3 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - # Copyright 2012 OpenStack Foundation # All Rights Reserved. # @@ -15,9 +13,9 @@ # License for the specific language governing permissions and limitations # under the License. -from novaclient.v1_1 import fping from novaclient.tests import utils from novaclient.tests.v1_1 import fakes +from novaclient.v1_1 import fping cs = fakes.FakeClient() @@ -33,31 +31,31 @@ fl = cs.fping.list() cs.assert_called('GET', '/os-fping') for f in fl: - self.assertTrue(isinstance(f, fping.Fping)) + self.assertIsInstance(f, fping.Fping) self.assertEqual(f.project_id, "fake-project") self.assertEqual(f.alive, True) def test_list_fpings_all_tenants(self): fl = cs.fping.list(all_tenants=True) for f in fl: - self.assertTrue(isinstance(f, fping.Fping)) + self.assertIsInstance(f, fping.Fping) cs.assert_called('GET', '/os-fping?all_tenants=1') def test_list_fpings_exclude(self): fl = cs.fping.list(exclude=['1']) for f in fl: - self.assertTrue(isinstance(f, fping.Fping)) + self.assertIsInstance(f, fping.Fping) cs.assert_called('GET', '/os-fping?exclude=1') def test_list_fpings_include(self): fl = cs.fping.list(include=['1']) for f in fl: - self.assertTrue(isinstance(f, fping.Fping)) + self.assertIsInstance(f, fping.Fping) cs.assert_called('GET', '/os-fping?include=1') def test_get_fping(self): f = cs.fping.get(1) cs.assert_called('GET', '/os-fping/1') - self.assertTrue(isinstance(f, fping.Fping)) + self.assertIsInstance(f, fping.Fping) self.assertEqual(f.project_id, "fake-project") self.assertEqual(f.alive, True) diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/test_hosts.py python-novaclient-2.16.0/novaclient/tests/v1_1/test_hosts.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/test_hosts.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/test_hosts.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,6 +1,19 @@ -from novaclient.v1_1 import hosts -from novaclient.tests.v1_1 import fakes +# +# 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 novaclient.tests import utils +from novaclient.tests.v1_1 import fakes +from novaclient.v1_1 import hosts cs = fakes.FakeClient() @@ -11,18 +24,18 @@ def test_describe_resource(self): hs = cs.hosts.get('host') cs.assert_called('GET', '/os-hosts/host') - [self.assertTrue(isinstance(h, hosts.Host)) for h in hs] + [self.assertIsInstance(h, hosts.Host) for h in hs] def test_list_host(self): hs = cs.hosts.list() cs.assert_called('GET', '/os-hosts') - [self.assertTrue(isinstance(h, hosts.Host)) for h in hs] + [self.assertIsInstance(h, hosts.Host) for h in hs] [self.assertEqual(h.zone, 'nova1') for h in hs] def test_list_host_with_zone(self): hs = cs.hosts.list('nova') cs.assert_called('GET', '/os-hosts?zone=nova') - [self.assertTrue(isinstance(h, hosts.Host)) for h in hs] + [self.assertIsInstance(h, hosts.Host) for h in hs] [self.assertEqual(h.zone, 'nova') for h in hs] def test_update_enable(self): @@ -30,14 +43,14 @@ values = {"status": "enabled"} result = host.update(values) cs.assert_called('PUT', '/os-hosts/sample_host', values) - self.assertTrue(isinstance(result, hosts.Host)) + self.assertIsInstance(result, hosts.Host) def test_update_maintenance(self): host = cs.hosts.get('sample_host')[0] values = {"maintenance_mode": "enable"} result = host.update(values) cs.assert_called('PUT', '/os-hosts/sample_host', values) - self.assertTrue(isinstance(result, hosts.Host)) + self.assertIsInstance(result, hosts.Host) def test_update_both(self): host = cs.hosts.get('sample_host')[0] @@ -45,7 +58,7 @@ "maintenance_mode": "enable"} result = host.update(values) cs.assert_called('PUT', '/os-hosts/sample_host', values) - self.assertTrue(isinstance(result, hosts.Host)) + self.assertIsInstance(result, hosts.Host) def test_host_startup(self): host = cs.hosts.get('sample_host')[0] diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/test_hypervisors.py python-novaclient-2.16.0/novaclient/tests/v1_1/test_hypervisors.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/test_hypervisors.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/test_hypervisors.py 2014-02-26 16:28:51.000000000 +0000 @@ -17,10 +17,14 @@ from novaclient.tests.v1_1 import fakes -cs = fakes.FakeClient() +class HypervisorsTest(utils.TestCase): + def setUp(self): + super(HypervisorsTest, self).setUp() + self.cs = self._get_fake_client() + def _get_fake_client(self): + return fakes.FakeClient() -class HypervisorsTest(utils.TestCase): def compare_to_expected(self, expected, hyper): for key, value in expected.items(): self.assertEqual(getattr(hyper, key), value) @@ -31,8 +35,8 @@ dict(id=5678, hypervisor_hostname='hyper2'), ] - result = cs.hypervisors.list(False) - cs.assert_called('GET', '/os-hypervisors') + result = self.cs.hypervisors.list(False) + self.cs.assert_called('GET', '/os-hypervisors') for idx, hyper in enumerate(result): self.compare_to_expected(expected[idx], hyper) @@ -74,8 +78,8 @@ cpu_info='cpu_info', disk_available_least=100)] - result = cs.hypervisors.list() - cs.assert_called('GET', '/os-hypervisors/detail') + result = self.cs.hypervisors.list() + self.cs.assert_called('GET', '/os-hypervisors/detail') for idx, hyper in enumerate(result): self.compare_to_expected(expected[idx], hyper) @@ -86,8 +90,8 @@ dict(id=5678, hypervisor_hostname='hyper2'), ] - result = cs.hypervisors.search('hyper') - cs.assert_called('GET', '/os-hypervisors/hyper/search') + result = self.cs.hypervisors.search('hyper') + self.cs.assert_called('GET', '/os-hypervisors/hyper/search') for idx, hyper in enumerate(result): self.compare_to_expected(expected[idx], hyper) @@ -106,8 +110,8 @@ dict(name='inst4', uuid='uuid4')]), ] - result = cs.hypervisors.search('hyper', True) - cs.assert_called('GET', '/os-hypervisors/hyper/servers') + result = self.cs.hypervisors.search('hyper', True) + self.cs.assert_called('GET', '/os-hypervisors/hyper/servers') for idx, hyper in enumerate(result): self.compare_to_expected(expected[idx], hyper) @@ -132,8 +136,8 @@ cpu_info='cpu_info', disk_available_least=100) - result = cs.hypervisors.get(1234) - cs.assert_called('GET', '/os-hypervisors/1234') + result = self.cs.hypervisors.get(1234) + self.cs.assert_called('GET', '/os-hypervisors/1234') self.compare_to_expected(expected, result) @@ -143,8 +147,8 @@ hypervisor_hostname="hyper1", uptime="fake uptime") - result = cs.hypervisors.uptime(1234) - cs.assert_called('GET', '/os-hypervisors/1234/uptime') + result = self.cs.hypervisors.uptime(1234) + self.cs.assert_called('GET', '/os-hypervisors/1234/uptime') self.compare_to_expected(expected, result) @@ -164,7 +168,7 @@ disk_available_least=200, ) - result = cs.hypervisors.statistics() - cs.assert_called('GET', '/os-hypervisors/statistics') + result = self.cs.hypervisors.statistics() + self.cs.assert_called('GET', '/os-hypervisors/statistics') self.compare_to_expected(expected, result) diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/test_images.py python-novaclient-2.16.0/novaclient/tests/v1_1/test_images.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/test_images.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/test_images.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,6 +1,19 @@ -from novaclient.v1_1 import images +# +# 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 novaclient.tests import utils from novaclient.tests.v1_1 import fakes +from novaclient.v1_1 import images cs = fakes.FakeClient() @@ -11,12 +24,12 @@ def test_list_images(self): il = cs.images.list() cs.assert_called('GET', '/images/detail') - [self.assertTrue(isinstance(i, images.Image)) for i in il] + [self.assertIsInstance(i, images.Image) for i in il] def test_list_images_undetailed(self): il = cs.images.list(detailed=False) cs.assert_called('GET', '/images') - [self.assertTrue(isinstance(i, images.Image)) for i in il] + [self.assertIsInstance(i, images.Image) for i in il] def test_list_images_with_limit(self): il = cs.images.list(limit=4) @@ -25,7 +38,7 @@ def test_get_image_details(self): i = cs.images.get(1) cs.assert_called('GET', '/images/1') - self.assertTrue(isinstance(i, images.Image)) + self.assertIsInstance(i, images.Image) self.assertEqual(i.id, 1) self.assertEqual(i.name, 'CentOS 5.2') diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/test_keypairs.py python-novaclient-2.16.0/novaclient/tests/v1_1/test_keypairs.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/test_keypairs.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/test_keypairs.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,39 +1,60 @@ -from novaclient.v1_1 import keypairs +# +# 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 novaclient.tests import utils from novaclient.tests.v1_1 import fakes +from novaclient.v1_1 import keypairs -cs = fakes.FakeClient() +class KeypairsTest(utils.TestCase): + def setUp(self): + super(KeypairsTest, self).setUp() + self.cs = self._get_fake_client() + self.keypair_type = self._get_keypair_type() + self.keypair_prefix = keypairs.KeypairManager.keypair_prefix + def _get_fake_client(self): + return fakes.FakeClient() -class KeypairsTest(utils.TestCase): + def _get_keypair_type(self): + return keypairs.Keypair def test_get_keypair(self): - kp = cs.keypairs.get('test') - cs.assert_called('GET', '/os-keypairs/test') - self.assertTrue(isinstance(kp, keypairs.Keypair)) + kp = self.cs.keypairs.get('test') + self.cs.assert_called('GET', '/%s/test' % self.keypair_prefix) + self.assertIsInstance(kp, keypairs.Keypair) self.assertEqual(kp.name, 'test') def test_list_keypairs(self): - kps = cs.keypairs.list() - cs.assert_called('GET', '/os-keypairs') - [self.assertTrue(isinstance(kp, keypairs.Keypair)) for kp in kps] + kps = self.cs.keypairs.list() + self.cs.assert_called('GET', '/%s' % self.keypair_prefix) + [self.assertIsInstance(kp, keypairs.Keypair) for kp in kps] def test_delete_keypair(self): - kp = cs.keypairs.list()[0] + kp = self.cs.keypairs.list()[0] kp.delete() - cs.assert_called('DELETE', '/os-keypairs/test') - cs.keypairs.delete('test') - cs.assert_called('DELETE', '/os-keypairs/test') - cs.keypairs.delete(kp) - cs.assert_called('DELETE', '/os-keypairs/test') + self.cs.assert_called('DELETE', '/%s/test' % self.keypair_prefix) + self.cs.keypairs.delete('test') + self.cs.assert_called('DELETE', '/%s/test' % self.keypair_prefix) + self.cs.keypairs.delete(kp) + self.cs.assert_called('DELETE', '/%s/test' % self.keypair_prefix) def test_create_keypair(self): - kp = cs.keypairs.create("foo") - cs.assert_called('POST', '/os-keypairs') - self.assertTrue(isinstance(kp, keypairs.Keypair)) + kp = self.cs.keypairs.create("foo") + self.cs.assert_called('POST', '/%s' % self.keypair_prefix) + self.assertIsInstance(kp, keypairs.Keypair) def test_import_keypair(self): - kp = cs.keypairs.create("foo", "fake-public-key") - cs.assert_called('POST', '/os-keypairs') - self.assertTrue(isinstance(kp, keypairs.Keypair)) + kp = self.cs.keypairs.create("foo", "fake-public-key") + self.cs.assert_called('POST', '/%s' % self.keypair_prefix) + self.assertIsInstance(kp, keypairs.Keypair) diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/test_limits.py python-novaclient-2.16.0/novaclient/tests/v1_1/test_limits.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/test_limits.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/test_limits.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,7 +1,19 @@ +# +# 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 novaclient.v1_1 import limits from novaclient.tests import utils from novaclient.tests.v1_1 import fakes +from novaclient.v1_1 import limits cs = fakes.FakeClient() @@ -12,12 +24,12 @@ def test_get_limits(self): obj = cs.limits.get() cs.assert_called('GET', '/limits') - self.assertTrue(isinstance(obj, limits.Limits)) + self.assertIsInstance(obj, limits.Limits) def test_get_limits_for_a_tenant(self): obj = cs.limits.get(tenant_id=1234) cs.assert_called('GET', '/limits?tenant_id=1234') - self.assertTrue(isinstance(obj, limits.Limits)) + self.assertIsInstance(obj, limits.Limits) def test_absolute_limits(self): obj = cs.limits.get() diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/test_networks.py python-novaclient-2.16.0/novaclient/tests/v1_1/test_networks.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/test_networks.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/test_networks.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,6 +1,19 @@ -from novaclient.v1_1 import networks +# +# 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 novaclient.tests import utils from novaclient.tests.v1_1 import fakes +from novaclient.v1_1 import networks cs = fakes.FakeClient() @@ -11,12 +24,12 @@ def test_list_networks(self): fl = cs.networks.list() cs.assert_called('GET', '/os-networks') - [self.assertTrue(isinstance(f, networks.Network)) for f in fl] + [self.assertIsInstance(f, networks.Network) for f in fl] def test_get_network(self): f = cs.networks.get(1) cs.assert_called('GET', '/os-networks/1') - self.assertTrue(isinstance(f, networks.Network)) + self.assertIsInstance(f, networks.Network) def test_delete(self): cs.networks.delete('networkdelete') @@ -26,7 +39,7 @@ f = cs.networks.create(label='foo') cs.assert_called('POST', '/os-networks', {'network': {'label': 'foo'}}) - self.assertTrue(isinstance(f, networks.Network)) + self.assertIsInstance(f, networks.Network) def test_create_allparams(self): params = { @@ -49,7 +62,7 @@ f = cs.networks.create(**params) cs.assert_called('POST', '/os-networks', {'network': params}) - self.assertTrue(isinstance(f, networks.Network)) + self.assertIsInstance(f, networks.Network) def test_associate_project(self): cs.networks.associate_project('networktest') diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/test_quota_classes.py python-novaclient-2.16.0/novaclient/tests/v1_1/test_quota_classes.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/test_quota_classes.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/test_quota_classes.py 2014-02-26 16:28:51.000000000 +0000 @@ -29,14 +29,14 @@ def test_update_quota(self): q = cs.quota_classes.get('test') - q.update(volumes=2) + q.update(cores=2) cs.assert_called('PUT', '/os-quota-class-sets/test') def test_refresh_quota(self): q = cs.quota_classes.get('test') q2 = cs.quota_classes.get('test') - self.assertEqual(q.volumes, q2.volumes) - q2.volumes = 0 - self.assertNotEqual(q.volumes, q2.volumes) + self.assertEqual(q.cores, q2.cores) + q2.cores = 0 + self.assertNotEqual(q.cores, q2.cores) q2.get() - self.assertEqual(q.volumes, q2.volumes) + self.assertEqual(q.cores, q2.cores) diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/test_quotas.py python-novaclient-2.16.0/novaclient/tests/v1_1/test_quotas.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/test_quotas.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/test_quotas.py 2014-02-26 16:28:51.000000000 +0000 @@ -16,68 +16,49 @@ from novaclient.tests import utils from novaclient.tests.v1_1 import fakes -cs = fakes.FakeClient() - class QuotaSetsTest(utils.TestCase): + def setUp(self): + super(QuotaSetsTest, self).setUp() + self.cs = self._get_fake_client() + + def _get_fake_client(self): + return fakes.FakeClient() def test_tenant_quotas_get(self): tenant_id = 'test' - cs.quotas.get(tenant_id) - cs.assert_called('GET', '/os-quota-sets/%s' % tenant_id) + self.cs.quotas.get(tenant_id) + self.cs.assert_called('GET', '/os-quota-sets/%s' % tenant_id) def test_user_quotas_get(self): tenant_id = 'test' user_id = 'fake_user' - cs.quotas.get(tenant_id, user_id=user_id) + self.cs.quotas.get(tenant_id, user_id=user_id) url = '/os-quota-sets/%s?user_id=%s' % (tenant_id, user_id) - cs.assert_called('GET', url) + self.cs.assert_called('GET', url) def test_tenant_quotas_defaults(self): tenant_id = '97f4c221bff44578b0300df4ef119353' - cs.quotas.defaults(tenant_id) - cs.assert_called('GET', '/os-quota-sets/%s/defaults' % tenant_id) - - def test_update_quota(self): - q = cs.quotas.get('97f4c221bff44578b0300df4ef119353') - q.update(volumes=2) - cs.assert_called('PUT', - '/os-quota-sets/97f4c221bff44578b0300df4ef119353') - - def test_update_user_quota(self): - tenant_id = '97f4c221bff44578b0300df4ef119353' - user_id = 'fake_user' - q = cs.quotas.get(tenant_id) - q.update(volumes=2, user_id=user_id) - url = '/os-quota-sets/%s?user_id=%s' % (tenant_id, user_id) - cs.assert_called('PUT', url) + self.cs.quotas.defaults(tenant_id) + self.cs.assert_called('GET', '/os-quota-sets/%s/defaults' % tenant_id) def test_force_update_quota(self): - q = cs.quotas.get('97f4c221bff44578b0300df4ef119353') + q = self.cs.quotas.get('97f4c221bff44578b0300df4ef119353') q.update(cores=2, force=True) - cs.assert_called( + self.cs.assert_called( 'PUT', '/os-quota-sets/97f4c221bff44578b0300df4ef119353', {'quota_set': {'force': True, 'cores': 2, 'tenant_id': '97f4c221bff44578b0300df4ef119353'}}) - def test_refresh_quota(self): - q = cs.quotas.get('test') - q2 = cs.quotas.get('test') - self.assertEqual(q.volumes, q2.volumes) - q2.volumes = 0 - self.assertNotEqual(q.volumes, q2.volumes) - q2.get() - self.assertEqual(q.volumes, q2.volumes) - def test_quotas_delete(self): tenant_id = 'test' - cs.quotas.delete(tenant_id) - cs.assert_called('DELETE', '/os-quota-sets/%s' % tenant_id) + self.cs.quotas.delete(tenant_id) + self.cs.assert_called('DELETE', '/os-quota-sets/%s' % tenant_id) def test_user_quotas_delete(self): tenant_id = 'test' user_id = 'fake_user' - cs.quotas.delete(tenant_id, user_id=user_id) + self.cs.quotas.delete(tenant_id, user_id=user_id) url = '/os-quota-sets/%s?user_id=%s' % (tenant_id, user_id) - cs.assert_called('DELETE', url) + self.cs.assert_called('DELETE', url) diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/test_security_group_rules.py python-novaclient-2.16.0/novaclient/tests/v1_1/test_security_group_rules.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/test_security_group_rules.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/test_security_group_rules.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,7 +1,20 @@ +# +# 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 novaclient import exceptions -from novaclient.v1_1 import security_group_rules from novaclient.tests import utils from novaclient.tests.v1_1 import fakes +from novaclient.v1_1 import security_group_rules cs = fakes.FakeClient() diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/test_security_groups.py python-novaclient-2.16.0/novaclient/tests/v1_1/test_security_groups.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/test_security_groups.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/test_security_groups.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,6 +1,19 @@ -from novaclient.v1_1 import security_groups +# +# 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 novaclient.tests import utils from novaclient.tests.v1_1 import fakes +from novaclient.v1_1 import security_groups cs = fakes.FakeClient() @@ -11,7 +24,7 @@ sgs = cs.security_groups.list(search_opts=search_opts) cs.assert_called('GET', path) for sg in sgs: - self.assertTrue(isinstance(sg, security_groups.SecurityGroup)) + self.assertIsInstance(sg, security_groups.SecurityGroup) def test_list_security_groups_all_tenants_on(self): self._do_test_list_security_groups( @@ -28,7 +41,7 @@ def test_get_security_groups(self): sg = cs.security_groups.get(1) cs.assert_called('GET', '/os-security-groups/1') - self.assertTrue(isinstance(sg, security_groups.SecurityGroup)) + self.assertIsInstance(sg, security_groups.SecurityGroup) self.assertEqual('1', str(sg)) def test_delete_security_group(self): @@ -43,13 +56,13 @@ def test_create_security_group(self): sg = cs.security_groups.create("foo", "foo barr") cs.assert_called('POST', '/os-security-groups') - self.assertTrue(isinstance(sg, security_groups.SecurityGroup)) + self.assertIsInstance(sg, security_groups.SecurityGroup) def test_update_security_group(self): sg = cs.security_groups.list()[0] secgroup = cs.security_groups.update(sg, "update", "update") cs.assert_called('PUT', '/os-security-groups/1') - self.assertTrue(isinstance(secgroup, security_groups.SecurityGroup)) + self.assertIsInstance(secgroup, security_groups.SecurityGroup) def test_refresh_security_group(self): sg = cs.security_groups.get(1) diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/test_servers.py python-novaclient-2.16.0/novaclient/tests/v1_1/test_servers.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/test_servers.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/test_servers.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,12 +1,24 @@ # -*- coding: utf-8 -*- +# +# 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 mock import six from novaclient import exceptions -from novaclient.v1_1 import servers from novaclient.tests import utils from novaclient.tests.v1_1 import fakes +from novaclient.v1_1 import servers cs = fakes.FakeClient() @@ -17,30 +29,30 @@ def test_list_servers(self): sl = cs.servers.list() cs.assert_called('GET', '/servers/detail') - [self.assertTrue(isinstance(s, servers.Server)) for s in sl] + [self.assertIsInstance(s, servers.Server) for s in sl] def test_list_servers_undetailed(self): sl = cs.servers.list(detailed=False) cs.assert_called('GET', '/servers') - [self.assertTrue(isinstance(s, servers.Server)) for s in sl] + [self.assertIsInstance(s, servers.Server) for s in sl] def test_list_servers_with_marker_limit(self): sl = cs.servers.list(marker=1234, limit=2) - cs.assert_called('GET', '/servers/detail?marker=1234&limit=2') + cs.assert_called('GET', '/servers/detail?limit=2&marker=1234') for s in sl: - self.assertTrue(isinstance(s, servers.Server)) + self.assertIsInstance(s, servers.Server) def test_get_server_details(self): s = cs.servers.get(1234) cs.assert_called('GET', '/servers/1234') - self.assertTrue(isinstance(s, servers.Server)) + self.assertIsInstance(s, servers.Server) self.assertEqual(s.id, 1234) self.assertEqual(s.status, 'BUILD') def test_get_server_promote_details(self): s1 = cs.servers.list(detailed=False)[0] s2 = cs.servers.list(detailed=True)[0] - self.assertNotEquals(s1._info, s2._info) + self.assertNotEqual(s1._info, s2._info) s1.get() self.assertEqual(s1._info, s2._info) @@ -58,7 +70,7 @@ } ) cs.assert_called('POST', '/servers') - self.assertTrue(isinstance(s, servers.Server)) + self.assertIsInstance(s, servers.Server) def test_create_server_boot_from_volume_with_nics(self): old_boot = cs.servers._boot @@ -88,7 +100,7 @@ nics=nics ) cs.assert_called('POST', '/os-volumes_boot') - self.assertTrue(isinstance(s, servers.Server)) + self.assertIsInstance(s, servers.Server) test_create_server_from_volume() @@ -105,7 +117,7 @@ }, ) cs.assert_called('POST', '/servers') - self.assertTrue(isinstance(s, servers.Server)) + self.assertIsInstance(s, servers.Server) def test_create_server_userdata_unicode(self): s = cs.servers.create( @@ -121,7 +133,7 @@ }, ) cs.assert_called('POST', '/servers') - self.assertTrue(isinstance(s, servers.Server)) + self.assertIsInstance(s, servers.Server) def test_create_server_userdata_utf8(self): s = cs.servers.create( @@ -137,7 +149,7 @@ }, ) cs.assert_called('POST', '/servers') - self.assertTrue(isinstance(s, servers.Server)) + self.assertIsInstance(s, servers.Server) def _create_disk_config(self, disk_config): s = cs.servers.create( @@ -147,7 +159,7 @@ disk_config=disk_config ) cs.assert_called('POST', '/servers') - self.assertTrue(isinstance(s, servers.Server)) + self.assertIsInstance(s, servers.Server) # verify disk config param was used in the request: last_request = cs.client.callstack[-1] @@ -196,6 +208,11 @@ reval = cs.assert_called('POST', '/servers/1234/metadata', {'metadata': {'test_key': 'test_value'}}) + def test_set_server_meta_item(self): + s = cs.servers.set_meta_item(1234, 'test_key', 'test_value') + reval = cs.assert_called('PUT', '/servers/1234/metadata/test_key', + {'meta': {'test_key': 'test_value'}}) + def test_find(self): server = cs.servers.find(name='sample-server') cs.assert_called('GET', '/servers', pos=-2) @@ -249,6 +266,15 @@ def test_rebuild_server_disk_config_manual(self): self._rebuild_resize_disk_config('MANUAL') + def test_rebuild_server_preserve_ephemeral(self): + s = cs.servers.get(1234) + s.rebuild(image=1, preserve_ephemeral=True) + cs.assert_called('POST', '/servers/1234/action') + body = cs.client.callstack[-1][-1] + d = body['rebuild'] + self.assertIn('preserve_ephemeral', d) + self.assertEqual(d['preserve_ephemeral'], True) + def test_resize_server(self): s = cs.servers.get(1234) s.resize(flavor=1) @@ -420,9 +446,35 @@ self.assertEqual(cs.servers.get_console_output(s, length=50), success) cs.assert_called('POST', '/servers/1234/action') + # Testing password methods with the following password and key + # + # Clear password: FooBar123 + # + # RSA Private Key: novaclient/tests/idfake.pem + # + # Encrypted password + # OIuEuQttO8Rk93BcKlwHQsziDAnkAm/V6V8VPToA8ZeUaUBWwS0gwo2K6Y61Z96r + # qG447iRz0uTEEYq3RAYJk1mh3mMIRVl27t8MtIecR5ggVVbz1S9AwXJQypDKl0ho + # QFvhCBcMWPohyGewDJOhDbtuN1IoFI9G55ZvFwCm5y7m7B2aVcoLeIsJZE4PLsIw + # /y5a6Z3/AoJZYGG7IH5WN88UROU3B9JZGFB2qtPLQTOvDMZLUhoPRIJeHiVSlo1N + # tI2/++UsXVg3ow6ItqCJGgdNuGG5JB+bslDHWPxROpesEIHdczk46HCpHQN8f1sk + # Hi/fmZZNQQqj1Ijq0caOIw== + def test_get_password(self): s = cs.servers.get(1234) - self.assertEqual(s.get_password('/foo/id_rsa'), '') + self.assertEqual(s.get_password('novaclient/tests/idfake.pem'), + b'FooBar123') + cs.assert_called('GET', '/servers/1234/os-server-password') + + def test_get_password_without_key(self): + s = cs.servers.get(1234) + self.assertEqual(s.get_password(), + 'OIuEuQttO8Rk93BcKlwHQsziDAnkAm/V6V8VPToA8ZeUaUBWwS0gwo2K6Y61Z96r' + 'qG447iRz0uTEEYq3RAYJk1mh3mMIRVl27t8MtIecR5ggVVbz1S9AwXJQypDKl0ho' + 'QFvhCBcMWPohyGewDJOhDbtuN1IoFI9G55ZvFwCm5y7m7B2aVcoLeIsJZE4PLsIw' + '/y5a6Z3/AoJZYGG7IH5WN88UROU3B9JZGFB2qtPLQTOvDMZLUhoPRIJeHiVSlo1N' + 'tI2/++UsXVg3ow6ItqCJGgdNuGG5JB+bslDHWPxROpesEIHdczk46HCpHQN8f1sk' + 'Hi/fmZZNQQqj1Ijq0caOIw==') cs.assert_called('GET', '/servers/1234/os-server-password') def test_clear_password(self): @@ -458,6 +510,14 @@ cs.servers.get_spice_console(s, 'fake') cs.assert_called('POST', '/servers/1234/action') + def test_get_rdp_console(self): + s = cs.servers.get(1234) + s.get_rdp_console('fake') + cs.assert_called('POST', '/servers/1234/action') + + cs.servers.get_rdp_console(s, 'fake') + cs.assert_called('POST', '/servers/1234/action') + def test_create_image(self): s = cs.servers.get(1234) s.create_image('123') diff -Nru python-novaclient-2.15.0/novaclient/tests/v1_1/test_services.py python-novaclient-2.16.0/novaclient/tests/v1_1/test_services.py --- python-novaclient-2.15.0/novaclient/tests/v1_1/test_services.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/tests/v1_1/test_services.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,5 +1,3 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - # Copyright 2012 IBM Corp. # All Rights Reserved. # @@ -15,63 +13,83 @@ # License for the specific language governing permissions and limitations # under the License. -from novaclient.v1_1 import services -from novaclient.tests.v1_1 import fakes from novaclient.tests import utils +from novaclient.tests.v1_1 import fakes +from novaclient.v1_1 import services -cs = fakes.FakeClient() +class ServicesTest(utils.TestCase): + def setUp(self): + super(ServicesTest, self).setUp() + self.cs = self._get_fake_client() + self.service_type = self._get_service_type() + def _get_fake_client(self): + return fakes.FakeClient() -class ServicesTest(utils.TestCase): + def _get_service_type(self): + return services.Service def test_list_services(self): - svs = cs.services.list() - cs.assert_called('GET', '/os-services') - [self.assertTrue(isinstance(s, services.Service)) for s in svs] - [self.assertEqual(s.binary, 'nova-compute') for s in svs] - [self.assertEqual(s.host, 'host1') for s in svs] + svs = self.cs.services.list() + self.cs.assert_called('GET', '/os-services') + for s in svs: + self.assertIsInstance(s, self._get_service_type()) + self.assertEqual(s.binary, 'nova-compute') + self.assertEqual(s.host, 'host1') + self.assertTrue(str(s).startswith('>> _flatten('cpu_info', {'arch':'x86_64'}) + [('cpu_info_arch': 'x86_64')] + + """ + if isinstance(data, dict): + for key, value in six.iteritems(data): + new_key = '%s_%s' % (prefix, key) if prefix else key + if isinstance(value, (dict, list)): + for item in _flatten(value, new_key): + yield item + else: + yield new_key, value + else: + yield prefix, data + + +def flatten_dict(data): + """Return a new dict whose sub-dicts have been merged into the + original. Each of the parents keys are prepended to the child's + to prevent collisions. Any string elements will be JSON parsed + before flattening. + + >>> flatten_dict({'service': {'host':'cloud9@compute-068', 'id': 143}}) + {'service_host': colud9@compute-068', 'service_id': 143} + + """ + data = data.copy() + # Try and decode any nested JSON structures. + for key, value in six.iteritems(data): + if isinstance(value, six.string_types): + try: + data[key] = json.loads(value) + except ValueError: + pass + + return dict(_flatten(data)) def print_dict(d, dict_property="Property", dict_value="Value", wrap=0): pt = prettytable.PrettyTable([dict_property, dict_value], caching=False) pt.align = 'l' - for k, v in six.iteritems(d): + for k, v in sorted(d.items()): # convert dict to str to check length - if isinstance(v, dict): - v = str(v) + if isinstance(v, (dict, list)): + v = jsonutils.dumps(v) if wrap > 0: v = textwrap.fill(str(v), wrap) # if value has a newline, add in multiple rows @@ -190,13 +192,25 @@ pt.add_row([col1, line]) col1 = '' else: + if v is None: + v = '-' pt.add_row([k, v]) - print(strutils.safe_encode(pt.get_string())) + + result = strutils.safe_encode(pt.get_string()) + + print(result) def find_resource(manager, name_or_id, **find_args): """Helper for the _find_* methods.""" - # first try to get entity as integer id + # for str id which is not uuid (for Flavor search currently) + if getattr(manager, 'is_alphanum_id_allowed', False): + try: + return manager.get(name_or_id) + except exceptions.NotFound: + pass + + # try to get entity as integer id try: return manager.get(int(name_or_id)) except (TypeError, ValueError, exceptions.NotFound): @@ -204,18 +218,12 @@ # now try to get entity as uuid try: - uuid.UUID(strutils.safe_encode(name_or_id)) - return manager.get(name_or_id) + tmp_id = strutils.safe_encode(name_or_id) + uuid.UUID(tmp_id) + return manager.get(tmp_id) except (TypeError, ValueError, exceptions.NotFound): pass - # for str id which is not uuid (for Flavor search currently) - if getattr(manager, 'is_alphanum_id_allowed', False): - try: - return manager.get(name_or_id) - except exceptions.NotFound: - pass - try: try: return manager.find(human_id=name_or_id, **find_args) @@ -230,13 +238,15 @@ kwargs.update(find_args) return manager.find(**kwargs) except exceptions.NotFound: - msg = "No %s with a name or ID of '%s' exists." % \ - (manager.resource_class.__name__.lower(), name_or_id) + msg = _("No %(class)s with a name or ID of '%(name)s' exists.") % \ + {'class': manager.resource_class.__name__.lower(), + 'name': name_or_id} raise exceptions.CommandError(msg) except exceptions.NoUniqueMatch: - msg = ("Multiple %s matches found for '%s', use an ID to be more" - " specific." % (manager.resource_class.__name__.lower(), - name_or_id)) + msg = (_("Multiple %(class)s matches found for '%(name)s', use an ID " + "to be more specific.") % + {'class': manager.resource_class.__name__.lower(), + 'name': name_or_id}) raise exceptions.CommandError(msg) @@ -328,27 +338,6 @@ __import__(mod_str) return getattr(sys.modules[mod_str], class_str) -_slugify_strip_re = re.compile(r'[^\w\s-]') -_slugify_hyphenate_re = re.compile(r'[-\s]+') - - -# http://code.activestate.com/recipes/ -# 577257-slugify-make-a-string-usable-in-a-url-or-filename/ -def slugify(value): - """ - Normalizes string, converts to lowercase, removes non-alpha characters, - and converts spaces to hyphens. - - From Django's "django/template/defaultfilters.py". - """ - import unicodedata - if not isinstance(value, six.text_type): - value = six.text_type(value) - value = unicodedata.normalize('NFKD', value).encode('ascii', - 'ignore').decode("ascii") - value = six.text_type(_slugify_strip_re.sub('', value).strip().lower()) - return _slugify_hyphenate_re.sub('-', value) - def _load_entry_point(ep_name, name=None): """Try to load the entry point ep_name that matches name.""" @@ -366,3 +355,13 @@ return True except (TypeError, ValueError, AttributeError): return False + + +def validate_flavor_metadata_keys(keys): + for key in keys: + valid_name = VALID_KEY_REGEX.match(key) + if not valid_name: + msg = _('Invalid key: "%s". Keys may only contain letters, ' + 'numbers, spaces, underscores, periods, colons and ' + 'hyphens.') + raise exceptions.CommandError(msg % key) diff -Nru python-novaclient-2.15.0/novaclient/v1_1/agents.py python-novaclient-2.16.0/novaclient/v1_1/agents.py --- python-novaclient-2.15.0/novaclient/v1_1/agents.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v1_1/agents.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,5 +1,3 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - # Copyright 2012 IBM Corp. # All Rights Reserved. # @@ -42,13 +40,16 @@ url = "/os-agents?hypervisor=%s" % hypervisor return self._list(url, "agents") - def update(self, id, version, - url, md5hash): - """Update an existing agent build.""" - body = {'para': { + def _build_update_body(self, version, url, md5hash): + return {'para': { 'version': version, 'url': url, 'md5hash': md5hash}} + + def update(self, id, version, + url, md5hash): + """Update an existing agent build.""" + body = self._build_update_body(version, url, md5hash) return self._update('/os-agents/%s' % id, body, 'agent') def create(self, os, architecture, version, diff -Nru python-novaclient-2.15.0/novaclient/v1_1/availability_zones.py python-novaclient-2.16.0/novaclient/v1_1/availability_zones.py --- python-novaclient-2.15.0/novaclient/v1_1/availability_zones.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v1_1/availability_zones.py 2014-02-26 16:28:51.000000000 +0000 @@ -36,6 +36,7 @@ Manage :class:`AvailabilityZone` resources. """ resource_class = AvailabilityZone + return_parameter_name = "availabilityZoneInfo" def list(self, detailed=True): """ @@ -45,6 +46,7 @@ """ if detailed is True: return self._list("/os-availability-zone/detail", - "availabilityZoneInfo") + self.return_parameter_name) else: - return self._list("/os-availability-zone", "availabilityZoneInfo") + return self._list("/os-availability-zone", + self.return_parameter_name) diff -Nru python-novaclient-2.15.0/novaclient/v1_1/client.py python-novaclient-2.16.0/novaclient/v1_1/client.py --- python-novaclient-2.15.0/novaclient/v1_1/client.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v1_1/client.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,4 +1,3 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 # Copyright 2012 OpenStack Foundation # Copyright 2013 IBM Corp. # @@ -16,16 +15,17 @@ from novaclient import client from novaclient.v1_1 import agents -from novaclient.v1_1 import certs -from novaclient.v1_1 import cloudpipe from novaclient.v1_1 import aggregates from novaclient.v1_1 import availability_zones -from novaclient.v1_1 import coverage_ext -from novaclient.v1_1 import flavors +from novaclient.v1_1 import certs +from novaclient.v1_1 import cloudpipe +from novaclient.v1_1 import fixed_ips from novaclient.v1_1 import flavor_access +from novaclient.v1_1 import flavors from novaclient.v1_1 import floating_ip_dns -from novaclient.v1_1 import floating_ips from novaclient.v1_1 import floating_ip_pools +from novaclient.v1_1 import floating_ips +from novaclient.v1_1 import floating_ips_bulk from novaclient.v1_1 import fping from novaclient.v1_1 import hosts from novaclient.v1_1 import hypervisors @@ -38,14 +38,12 @@ from novaclient.v1_1 import security_group_rules from novaclient.v1_1 import security_groups from novaclient.v1_1 import servers +from novaclient.v1_1 import services from novaclient.v1_1 import usage from novaclient.v1_1 import virtual_interfaces -from novaclient.v1_1 import volumes from novaclient.v1_1 import volume_snapshots from novaclient.v1_1 import volume_types -from novaclient.v1_1 import services -from novaclient.v1_1 import fixed_ips -from novaclient.v1_1 import floating_ips_bulk +from novaclient.v1_1 import volumes class Client(object): @@ -74,7 +72,7 @@ volume_service_name=None, timings=False, bypass_url=None, os_cache=False, no_cache=True, http_log_debug=False, auth_system='keystone', - auth_plugin=None, + auth_plugin=None, auth_token=None, cacert=None, tenant_id=None): # FIXME(comstud): Rename the api_key argument above when we # know it's not being used as keyword argument @@ -116,7 +114,6 @@ self.fixed_ips = fixed_ips.FixedIPsManager(self) self.floating_ips_bulk = floating_ips_bulk.FloatingIPBulkManager(self) self.os_cache = os_cache or not no_cache - self.coverage = coverage_ext.CoverageManager(self) self.availability_zones = \ availability_zones.AvailabilityZoneManager(self) @@ -132,6 +129,7 @@ projectid=project_id, tenant_id=tenant_id, auth_url=auth_url, + auth_token=auth_token, insecure=insecure, timeout=timeout, auth_system=auth_system, diff -Nru python-novaclient-2.15.0/novaclient/v1_1/cloudpipe.py python-novaclient-2.16.0/novaclient/v1_1/cloudpipe.py --- python-novaclient-2.15.0/novaclient/v1_1/cloudpipe.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v1_1/cloudpipe.py 2014-02-26 16:28:51.000000000 +0000 @@ -35,7 +35,7 @@ """ Launch a cloudpipe instance. - :param project: name of the project for the cloudpipe + :param project: UUID of the project (tenant) for the cloudpipe """ body = {'cloudpipe': {'project_id': project}} return self._create('/os-cloudpipe', body, 'instance_id', diff -Nru python-novaclient-2.15.0/novaclient/v1_1/contrib/baremetal.py python-novaclient-2.16.0/novaclient/v1_1/contrib/baremetal.py --- python-novaclient-2.15.0/novaclient/v1_1/contrib/baremetal.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v1_1/contrib/baremetal.py 2014-02-26 16:28:51.000000000 +0000 @@ -17,6 +17,7 @@ Baremetal interface (v2 extension). """ from novaclient import base +from novaclient.openstack.common.gettextutils import _ from novaclient import utils @@ -151,35 +152,36 @@ @utils.arg('service_host', metavar='', - help='Name of nova compute host which will control this baremetal node') + help=_('Name of nova compute host which will control this baremetal ' + 'node')) @utils.arg('cpus', metavar='', type=int, - help='Number of CPUs in the node') + help=_('Number of CPUs in the node')) @utils.arg('memory_mb', metavar='', type=int, - help='Megabytes of RAM in the node') + help=_('Megabytes of RAM in the node')) @utils.arg('local_gb', metavar='', type=int, - help='Gigabytes of local storage in the node') + help=_('Gigabytes of local storage in the node')) @utils.arg('prov_mac_address', metavar='', - help='MAC address to provision the node') + help=_('MAC address to provision the node')) @utils.arg('--pm_address', default=None, metavar='', - help='Power management IP for the node') + help=_('Power management IP for the node')) @utils.arg('--pm_user', default=None, metavar='', - help='Username for the node\'s power management') + help=_('Username for the node\'s power management')) @utils.arg('--pm_password', default=None, metavar='', - help='Password for the node\'s power management') + help=_('Password for the node\'s power management')) @utils.arg('--terminal_port', default=None, metavar='', type=int, - help='ShellInABox port?') + help=_('ShellInABox port?')) def do_baremetal_node_create(cs, args): """Create a baremetal node.""" node = cs.baremetal.create(args.service_host, args.cpus, @@ -270,18 +272,18 @@ @utils.arg('node', metavar='', - help="ID of node") + help=_("ID of node")) @utils.arg('address', metavar='
', - help="MAC address of interface") + help=_("MAC address of interface")) @utils.arg('--datapath_id', default=0, metavar='', - help="OpenFlow Datapath ID of interface") + help=_("OpenFlow Datapath ID of interface")) @utils.arg('--port_no', default=0, metavar='', - help="OpenFlow port number of interface") + help=_("OpenFlow port number of interface")) def do_baremetal_interface_add(cs, args): """Add a network interface to a baremetal node.""" bmif = cs.baremetal.add_interface(args.node, args.address, @@ -289,8 +291,8 @@ _print_baremetal_resource(bmif) -@utils.arg('node', metavar='', help="ID of node") -@utils.arg('address', metavar='
', help="MAC address of interface") +@utils.arg('node', metavar='', help=_("ID of node")) +@utils.arg('address', metavar='
', help=_("MAC address of interface")) def do_baremetal_interface_remove(cs, args): """Remove a network interface from a baremetal node.""" cs.baremetal.remove_interface(args.node, args.address) diff -Nru python-novaclient-2.15.0/novaclient/v1_1/contrib/cells.py python-novaclient-2.16.0/novaclient/v1_1/contrib/cells.py --- python-novaclient-2.15.0/novaclient/v1_1/contrib/cells.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v1_1/contrib/cells.py 2014-02-26 16:28:51.000000000 +0000 @@ -14,6 +14,7 @@ # under the License. from novaclient import base +from novaclient.openstack.common.gettextutils import _ from novaclient import utils @@ -47,7 +48,7 @@ @utils.arg('cell', metavar='', - help='Name of the cell.') + help=_('Name of the cell.')) def do_cell_show(cs, args): """Show details of a given cell.""" cell = cs.cells.get(args.cell) @@ -56,14 +57,15 @@ @utils.arg('--cell', metavar='', - help="Name of the cell to get the capacities.", + help=_("Name of the cell to get the capacities."), default=None) def do_cell_capacities(cs, args): """Get cell capacities for all cells or a given cell.""" cell = cs.cells.capacities(args.cell) - print("Ram Available: %s MB" % cell.capacities['ram_free']['total_mb']) + print(_("Ram Available: %s MB") % cell.capacities['ram_free']['total_mb']) utils.print_dict(cell.capacities['ram_free']['units_by_mb'], dict_property='Ram(MB)', dict_value="Units") - print("\nDisk Available: %s MB" % cell.capacities['disk_free']['total_mb']) + print(_("\nDisk Available: %s MB") % + cell.capacities['disk_free']['total_mb']) utils.print_dict(cell.capacities['disk_free']['units_by_mb'], dict_property='Disk(MB)', dict_value="Units") diff -Nru python-novaclient-2.15.0/novaclient/v1_1/contrib/host_evacuate.py python-novaclient-2.16.0/novaclient/v1_1/contrib/host_evacuate.py --- python-novaclient-2.15.0/novaclient/v1_1/contrib/host_evacuate.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v1_1/contrib/host_evacuate.py 2014-02-26 16:28:51.000000000 +0000 @@ -14,6 +14,7 @@ # under the License. from novaclient import base +from novaclient.openstack.common.gettextutils import _ from novaclient import utils @@ -29,7 +30,7 @@ args.on_shared_storage) except Exception as e: success = False - error_message = "Error while evacuating instance: %s" % e + error_message = _("Error while evacuating instance: %s") % e return EvacuateHostResponse(base.Manager, {"server_uuid": server['uuid'], "evacuate_accepted": success, @@ -40,12 +41,13 @@ @utils.arg('--target_host', metavar='', default=None, - help='Name of target host.') + help=_('Name of target host.')) @utils.arg('--on-shared-storage', dest='on_shared_storage', action="store_true", default=False, - help='Specifies whether all instances files are on shared storage') + help=_('Specifies whether all instances files are on shared ' + ' storage')) def do_host_evacuate(cs, args): """Evacuate all instances from failed host to specified one.""" hypervisors = cs.hypervisors.search(args.host, servers=True) diff -Nru python-novaclient-2.15.0/novaclient/v1_1/contrib/host_servers_migrate.py python-novaclient-2.16.0/novaclient/v1_1/contrib/host_servers_migrate.py --- python-novaclient-2.15.0/novaclient/v1_1/contrib/host_servers_migrate.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v1_1/contrib/host_servers_migrate.py 2014-02-26 16:28:51.000000000 +0000 @@ -14,6 +14,7 @@ # under the License. from novaclient import base +from novaclient.openstack.common.gettextutils import _ from novaclient import utils @@ -28,7 +29,7 @@ cs.servers.migrate(server['uuid']) except Exception as e: success = False - error_message = "Error while migrating instance: %s" % e + error_message = _("Error while migrating instance: %s") % e return HostServersMigrateResponse(base.Manager, {"server_uuid": server['uuid'], "migration_accepted": success, diff -Nru python-novaclient-2.15.0/novaclient/v1_1/contrib/instance_action.py python-novaclient-2.16.0/novaclient/v1_1/contrib/instance_action.py --- python-novaclient-2.15.0/novaclient/v1_1/contrib/instance_action.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v1_1/contrib/instance_action.py 2014-02-26 16:28:51.000000000 +0000 @@ -16,6 +16,7 @@ import pprint from novaclient import base +from novaclient.openstack.common.gettextutils import _ from novaclient import utils @@ -41,10 +42,10 @@ @utils.arg('server', metavar='', - help='Name or UUID of the server to show an action for.') + help=_('Name or UUID of the server to show an action for.')) @utils.arg('request_id', metavar='', - help='Request ID of the action to get.') + help=_('Request ID of the action to get.')) def do_instance_action(cs, args): """Show an action.""" server = utils.find_resource(cs.servers, args.server) @@ -57,7 +58,7 @@ @utils.arg('server', metavar='', - help='Name or UUID of the server to list actions for.') + help=_('Name or UUID of the server to list actions for.')) def do_instance_action_list(cs, args): """List actions on a server.""" server = utils.find_resource(cs.servers, args.server) diff -Nru python-novaclient-2.15.0/novaclient/v1_1/contrib/metadata_extensions.py python-novaclient-2.16.0/novaclient/v1_1/contrib/metadata_extensions.py --- python-novaclient-2.15.0/novaclient/v1_1/contrib/metadata_extensions.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v1_1/contrib/metadata_extensions.py 2014-02-26 16:28:51.000000000 +0000 @@ -13,23 +13,25 @@ # License for the specific language governing permissions and limitations # under the License. +from novaclient.openstack.common.gettextutils import _ from novaclient import utils from novaclient.v1_1 import shell @utils.arg('host', metavar='', - help='Name of host.') + help=_('Name of host.')) @utils.arg('action', metavar='', choices=['set', 'delete'], - help="Actions: 'set' or 'delete'") + help=_("Actions: 'set' or 'delete'")) @utils.arg('metadata', metavar='', nargs='+', action='append', default=[], - help='Metadata to set or delete (only key is necessary on delete)') + help=_('Metadata to set or delete (only key is necessary on ' + 'delete)')) def do_host_meta(cs, args): """Set or Delete metadata on all instances of a host.""" hypervisors = cs.hypervisors.search(args.host, servers=True) diff -Nru python-novaclient-2.15.0/novaclient/v1_1/contrib/migrations.py python-novaclient-2.16.0/novaclient/v1_1/contrib/migrations.py --- python-novaclient-2.15.0/novaclient/v1_1/contrib/migrations.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v1_1/contrib/migrations.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,5 +1,3 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - # 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 @@ -16,9 +14,9 @@ migration interface """ -import urllib - from novaclient import base +from novaclient.openstack.common.gettextutils import _ +from novaclient.openstack.common.py3kcompat import urlutils from novaclient import utils @@ -45,7 +43,11 @@ if cell_name: opts['cell_name'] = cell_name - query_string = "?%s" % urllib.urlencode(opts) if opts else "" + # Transform the dict to a sequence of two-element tuples in fixed + # order, then the encoded string will be consistent in Python 2&3. + new_opts = sorted(opts.items(), key=lambda x: x[0]) + + query_string = "?%s" % urlutils.urlencode(new_opts) if new_opts else "" return self._list("/os-migrations%s" % query_string, "migrations") @@ -53,15 +55,15 @@ @utils.arg('--host', dest='host', metavar='', - help='Fetch migrations for the given host.') + help=_('Fetch migrations for the given host.')) @utils.arg('--status', dest='status', metavar='', - help='Fetch migrations for the given status.') + help=_('Fetch migrations for the given status.')) @utils.arg('--cell_name', dest='cell_name', metavar='', - help='Fetch migrations for the given cell_name.') + help=_('Fetch migrations for the given cell_name.')) def do_migration_list(cs, args): """Print a list of migrations.""" _print_migrations(cs.migrations.list(args.host, args.status, diff -Nru python-novaclient-2.15.0/novaclient/v1_1/contrib/tenant_networks.py python-novaclient-2.16.0/novaclient/v1_1/contrib/tenant_networks.py --- python-novaclient-2.15.0/novaclient/v1_1/contrib/tenant_networks.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v1_1/contrib/tenant_networks.py 2014-02-26 16:28:51.000000000 +0000 @@ -13,6 +13,7 @@ # limitations under the License. from novaclient import base +from novaclient.openstack.common.gettextutils import _ from novaclient import utils @@ -57,10 +58,10 @@ @utils.arg('label', metavar='', - help='Network label (ex. my_new_network)') + help=_('Network label (ex. my_new_network)')) @utils.arg('cidr', metavar='', - help='IP block to allocate from (ex. 172.16.0.0/24 or ' - '2001:DB8::/64)') + help=_('IP block to allocate from (ex. 172.16.0.0/24 or ' + '2001:DB8::/64)')) def do_net_create(cs, args): """ Create a network diff -Nru python-novaclient-2.15.0/novaclient/v1_1/coverage_ext.py python-novaclient-2.16.0/novaclient/v1_1/coverage_ext.py --- python-novaclient-2.15.0/novaclient/v1_1/coverage_ext.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v1_1/coverage_ext.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,60 +0,0 @@ -# Copyright 2012 IBM Corp. -# 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 novaclient import base - - -class Coverage(base.Resource): - def __repr__(self): - return "" % self.name - - -class CoverageManager(base.Manager): - - resource_class = Coverage - - def start(self, combine=False, **kwargs): - body = {'start': {}} - if combine: - body['start'] = {'combine': True} - self.run_hooks('modify_body_for_action', body) - url = '/os-coverage/action' - return self.api.client.post(url, body=body) - - def stop(self): - body = {'stop': {}} - self.run_hooks('modify_body_for_action', body) - url = '/os-coverage/action' - return self.api.client.post(url, body=body) - - def report(self, filename, xml=False, html=False): - body = { - 'report': { - 'file': filename, - } - } - if xml: - body['report']['xml'] = True - elif html: - body['report']['html'] = True - self.run_hooks('modify_body_for_action', body) - url = '/os-coverage/action' - return self.api.client.post(url, body=body) - - def reset(self): - body = {'reset': {}} - self.run_hooks('modify_body_for_action', body) - url = '/os-coverage/action' - return self.api.client.post(url, body=body) diff -Nru python-novaclient-2.15.0/novaclient/v1_1/fixed_ips.py python-novaclient-2.16.0/novaclient/v1_1/fixed_ips.py --- python-novaclient-2.15.0/novaclient/v1_1/fixed_ips.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v1_1/fixed_ips.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,5 +1,3 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - # Copyright 2012 IBM Corp. # All Rights Reserved. # diff -Nru python-novaclient-2.15.0/novaclient/v1_1/flavor_access.py python-novaclient-2.16.0/novaclient/v1_1/flavor_access.py --- python-novaclient-2.15.0/novaclient/v1_1/flavor_access.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v1_1/flavor_access.py 2014-02-26 16:28:51.000000000 +0000 @@ -16,6 +16,7 @@ """Flavor access interface.""" from novaclient import base +from novaclient.openstack.common.gettextutils import _ class FlavorAccess(base.Resource): @@ -30,12 +31,12 @@ resource_class = FlavorAccess def list(self, **kwargs): - if kwargs.get('flavor', None): + if kwargs.get('flavor'): return self._list_by_flavor(kwargs['flavor']) - elif kwargs.get('tenant', None): + elif kwargs.get('tenant'): return self._list_by_tenant(kwargs['tenant']) else: - raise NotImplementedError('Unknown list options.') + raise NotImplementedError(_('Unknown list options.')) def _list_by_flavor(self, flavor): return self._list('/flavors/%s/os-flavor-access' % base.getid(flavor), @@ -45,7 +46,7 @@ """Print flavor list shared with the given tenant.""" # TODO(uni): need to figure out a proper URI for list_by_tenant # since current API already provided current tenant_id information - raise NotImplementedError('Sorry, query by tenant not supported.') + raise NotImplementedError(_('Sorry, query by tenant not supported.')) def add_tenant_access(self, flavor, tenant): """Add a tenant to the given flavor access list.""" diff -Nru python-novaclient-2.15.0/novaclient/v1_1/flavors.py python-novaclient-2.16.0/novaclient/v1_1/flavors.py --- python-novaclient-2.15.0/novaclient/v1_1/flavors.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v1_1/flavors.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,11 +1,27 @@ # Copyright 2010 Jacob Kaplan-Moss +# +# 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. + """ Flavor interface. """ + from novaclient import base from novaclient import exceptions -from novaclient import utils +from novaclient.openstack.common.gettextutils import _ from novaclient.openstack.common.py3kcompat import urlutils +from novaclient.openstack.common import strutils +from novaclient import utils class Flavor(base.Resource): @@ -49,6 +65,8 @@ :param flavor: The :class:`Flavor` to set extra spec on :param metadata: A dict of key/value pairs to be set """ + utils.validate_flavor_metadata_keys(metadata.keys()) + body = {'extra_specs': metadata} return self.manager._create( "/flavors/%s/os-extra_specs" % base.getid(self), @@ -116,18 +134,33 @@ Delete a specific flavor. :param flavor: The ID of the :class:`Flavor` to get. - :param purge: Whether to purge record from the database """ self._delete("/flavors/%s" % base.getid(flavor)) + def _build_body(self, name, ram, vcpus, disk, id, swap, + ephemeral, rxtx_factor, is_public): + return { + "flavor": { + "name": name, + "ram": ram, + "vcpus": vcpus, + "disk": disk, + "id": id, + "swap": swap, + "OS-FLV-EXT-DATA:ephemeral": ephemeral, + "rxtx_factor": rxtx_factor, + "os-flavor-access:is_public": is_public, + } + } + def create(self, name, ram, vcpus, disk, flavorid="auto", ephemeral=0, swap=0, rxtx_factor=1.0, is_public=True): """ - Create (allocate) a floating ip for a tenant + Create a flavor. :param name: Descriptive name of the flavor :param ram: Memory in MB for the flavor - :param vcpu: Number of VCPUs for the flavor + :param vcpus: Number of VCPUs for the flavor :param disk: Size of local disk in GB :param flavorid: ID for the flavor (optional). You can use the reserved value ``"auto"`` to have Nova generate a UUID for the @@ -140,15 +173,15 @@ try: ram = int(ram) except (TypeError, ValueError): - raise exceptions.CommandError("Ram must be an integer.") + raise exceptions.CommandError(_("Ram must be an integer.")) try: vcpus = int(vcpus) except (TypeError, ValueError): - raise exceptions.CommandError("VCPUs must be an integer.") + raise exceptions.CommandError(_("VCPUs must be an integer.")) try: disk = int(disk) except (TypeError, ValueError): - raise exceptions.CommandError("Disk must be an integer.") + raise exceptions.CommandError(_("Disk must be an integer.")) if flavorid == "auto": flavorid = None @@ -156,33 +189,22 @@ try: swap = int(swap) except (TypeError, ValueError): - raise exceptions.CommandError("Swap must be an integer.") + raise exceptions.CommandError(_("Swap must be an integer.")) try: ephemeral = int(ephemeral) except (TypeError, ValueError): - raise exceptions.CommandError("Ephemeral must be an integer.") + raise exceptions.CommandError(_("Ephemeral must be an integer.")) try: rxtx_factor = float(rxtx_factor) except (TypeError, ValueError): - raise exceptions.CommandError("rxtx_factor must be a float.") + raise exceptions.CommandError(_("rxtx_factor must be a float.")) try: - is_public = utils.bool_from_str(is_public) + is_public = strutils.bool_from_string(is_public, True) except Exception: - raise exceptions.CommandError("is_public must be a boolean.") + raise exceptions.CommandError(_("is_public must be a boolean.")) - body = { - "flavor": { - "name": name, - "ram": ram, - "vcpus": vcpus, - "disk": disk, - "id": flavorid, - "swap": swap, - "OS-FLV-EXT-DATA:ephemeral": ephemeral, - "rxtx_factor": rxtx_factor, - "os-flavor-access:is_public": is_public, - } - } + body = self._build_body(name, ram, vcpus, disk, flavorid, swap, + ephemeral, rxtx_factor, is_public) return self._create("/flavors", body, "flavor") diff -Nru python-novaclient-2.15.0/novaclient/v1_1/floating_ips_bulk.py python-novaclient-2.16.0/novaclient/v1_1/floating_ips_bulk.py --- python-novaclient-2.15.0/novaclient/v1_1/floating_ips_bulk.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v1_1/floating_ips_bulk.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,5 +1,3 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - # Copyright 2012 IBM Corp. # All Rights Reserved. # diff -Nru python-novaclient-2.15.0/novaclient/v1_1/floating_ips.py python-novaclient-2.16.0/novaclient/v1_1/floating_ips.py --- python-novaclient-2.15.0/novaclient/v1_1/floating_ips.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v1_1/floating_ips.py 2014-02-26 16:28:51.000000000 +0000 @@ -44,7 +44,7 @@ """ Delete (deallocate) a floating ip for a tenant - :param key: The :class:`Keypair` (or its ID) to delete. + :param floating_ip: The floating ip address to delete. """ self._delete("/os-floating-ips/%s" % base.getid(floating_ip)) diff -Nru python-novaclient-2.15.0/novaclient/v1_1/fping.py python-novaclient-2.16.0/novaclient/v1_1/fping.py --- python-novaclient-2.15.0/novaclient/v1_1/fping.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v1_1/fping.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,5 +1,3 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - # Copyright 2012 OpenStack Foundation # All Rights Reserved. # diff -Nru python-novaclient-2.15.0/novaclient/v1_1/images.py python-novaclient-2.16.0/novaclient/v1_1/images.py --- python-novaclient-2.15.0/novaclient/v1_1/images.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v1_1/images.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,4 +1,17 @@ # Copyright 2010 Jacob Kaplan-Moss +# +# 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. + """ Image interface. """ @@ -79,7 +92,7 @@ """ Delete metadata from an image - :param image: The :class:`Image` to add metadata to + :param image: The :class:`Image` to delete metadata :param keys: A list of metadata keys to delete from the image """ for k in keys: diff -Nru python-novaclient-2.15.0/novaclient/v1_1/keypairs.py python-novaclient-2.16.0/novaclient/v1_1/keypairs.py --- python-novaclient-2.15.0/novaclient/v1_1/keypairs.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v1_1/keypairs.py 2014-02-26 16:28:51.000000000 +0000 @@ -32,7 +32,15 @@ dico = 'keypair' in info and \ info['keypair'] or info for (k, v) in dico.items(): - setattr(self, k, v) + # NOTE(rpodolyaka): keypair name allows us to uniquely identify + # a specific keypair, while its id attribute + # is nothing more than an implementation + # detail. We can safely omit the id attribute + # here to ensure setattr() won't raise + # AttributeError trying to set read-only + # property id + if k != 'id': + setattr(self, k, v) @property def id(self): @@ -44,6 +52,7 @@ class KeypairManager(base.ManagerWithFind): resource_class = Keypair + keypair_prefix = "os-keypairs" def get(self, keypair): """ @@ -52,7 +61,8 @@ :param keypair: The ID of the keypair to get. :rtype: :class:`Keypair` """ - return self._get("/os-keypairs/%s" % base.getid(keypair), "keypair") + return self._get("/%s/%s" % (self.keypair_prefix, base.getid(keypair)), + "keypair") def create(self, name, public_key=None): """ @@ -64,7 +74,7 @@ body = {'keypair': {'name': name}} if public_key: body['keypair']['public_key'] = public_key - return self._create('/os-keypairs', body, 'keypair') + return self._create('/%s' % self.keypair_prefix, body, 'keypair') def delete(self, key): """ @@ -72,10 +82,10 @@ :param key: The :class:`Keypair` (or its ID) to delete. """ - self._delete('/os-keypairs/%s' % (base.getid(key))) + self._delete('/%s/%s' % (self.keypair_prefix, base.getid(key))) def list(self): """ Get a list of keypairs. """ - return self._list('/os-keypairs', 'keypairs') + return self._list('/%s' % self.keypair_prefix, 'keypairs') diff -Nru python-novaclient-2.15.0/novaclient/v1_1/limits.py python-novaclient-2.16.0/novaclient/v1_1/limits.py --- python-novaclient-2.15.0/novaclient/v1_1/limits.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v1_1/limits.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,4 +1,16 @@ # Copyright 2011 OpenStack Foundation +# +# 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 novaclient import base from novaclient.openstack.common.py3kcompat import urlutils diff -Nru python-novaclient-2.15.0/novaclient/v1_1/networks.py python-novaclient-2.16.0/novaclient/v1_1/networks.py --- python-novaclient-2.15.0/novaclient/v1_1/networks.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v1_1/networks.py 2014-02-26 16:28:51.000000000 +0000 @@ -19,6 +19,7 @@ from novaclient import base from novaclient import exceptions +from novaclient.openstack.common.gettextutils import _ class Network(base.Resource): @@ -110,7 +111,7 @@ body = {"disassociate_host": None} else: raise exceptions.CommandError( - "Must disassociate either host or project or both") + _("Must disassociate either host or project or both")) self.api.client.post("/os-networks/%s/action" % base.getid(network), body=body) diff -Nru python-novaclient-2.15.0/novaclient/v1_1/quota_classes.py python-novaclient-2.16.0/novaclient/v1_1/quota_classes.py --- python-novaclient-2.15.0/novaclient/v1_1/quota_classes.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v1_1/quota_classes.py 2014-02-26 16:28:51.000000000 +0000 @@ -18,14 +18,8 @@ class QuotaClassSet(base.Resource): - @property - def id(self): - """QuotaClassSet does not have a 'id' attribute but base.Resource - needs it to self-refresh and QuotaSet is indexed by class_name""" - return self.class_name - def update(self, *args, **kwargs): - return self.manager.update(self.class_name, *args, **kwargs) + return self.manager.update(self.id, *args, **kwargs) class QuotaClassSetManager(base.Manager): @@ -35,30 +29,13 @@ return self._get("/os-quota-class-sets/%s" % (class_name), "quota_class_set") - def update(self, class_name, metadata_items=None, - injected_file_content_bytes=None, injected_file_path_bytes=None, - volumes=None, gigabytes=None, - ram=None, floating_ips=None, instances=None, - injected_files=None, cores=None, key_pairs=None, - security_groups=None, security_group_rules=None): - - body = {'quota_class_set': { - 'class_name': class_name, - 'metadata_items': metadata_items, - 'key_pairs': key_pairs, - 'injected_file_content_bytes': injected_file_content_bytes, - 'injected_file_path_bytes': injected_file_path_bytes, - 'volumes': volumes, - 'gigabytes': gigabytes, - 'ram': ram, - 'floating_ips': floating_ips, - 'instances': instances, - 'injected_files': injected_files, - 'cores': cores, - 'security_groups': security_groups, - 'security_group_rules': security_group_rules}} + def _update_body(self, **kwargs): + return {'quota_class_set': kwargs} + + def update(self, class_name, **kwargs): + body = self._update_body(**kwargs) - for key in body['quota_class_set'].keys(): + for key in list(body['quota_class_set']): if body['quota_class_set'][key] is None: body['quota_class_set'].pop(key) diff -Nru python-novaclient-2.15.0/novaclient/v1_1/quotas.py python-novaclient-2.16.0/novaclient/v1_1/quotas.py --- python-novaclient-2.15.0/novaclient/v1_1/quotas.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v1_1/quotas.py 2014-02-26 16:28:51.000000000 +0000 @@ -21,7 +21,8 @@ @property def id(self): """QuotaSet does not have a 'id' attribute but base.Resource needs it - to self-refresh and QuotaSet is indexed by tenant_id""" + to self-refresh and QuotaSet is indexed by tenant_id. + """ return self.tenant_id def update(self, *args, **kwargs): @@ -40,33 +41,16 @@ url = '/os-quota-sets/%s' % tenant_id return self._get(url, "quota_set") - def update(self, tenant_id, metadata_items=None, - injected_file_content_bytes=None, injected_file_path_bytes=None, - volumes=None, gigabytes=None, - ram=None, floating_ips=None, fixed_ips=None, instances=None, - injected_files=None, cores=None, key_pairs=None, - security_groups=None, security_group_rules=None, force=None, - user_id=None): - - body = {'quota_set': { - 'tenant_id': tenant_id, - 'metadata_items': metadata_items, - 'key_pairs': key_pairs, - 'injected_file_content_bytes': injected_file_content_bytes, - 'injected_file_path_bytes': injected_file_path_bytes, - 'volumes': volumes, - 'gigabytes': gigabytes, - 'ram': ram, - 'floating_ips': floating_ips, - 'fixed_ips': fixed_ips, - 'instances': instances, - 'injected_files': injected_files, - 'cores': cores, - 'security_groups': security_groups, - 'security_group_rules': security_group_rules, - 'force': force}} + def _update_body(self, tenant_id, **kwargs): + kwargs['tenant_id'] = tenant_id + return {'quota_set': kwargs} - for key in body['quota_set'].keys(): + def update(self, tenant_id, **kwargs): + + user_id = kwargs.pop('user_id', None) + body = self._update_body(tenant_id, **kwargs) + + for key in list(body['quota_set']): if body['quota_set'][key] is None: body['quota_set'].pop(key) diff -Nru python-novaclient-2.15.0/novaclient/v1_1/security_group_rules.py python-novaclient-2.16.0/novaclient/v1_1/security_group_rules.py --- python-novaclient-2.15.0/novaclient/v1_1/security_group_rules.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v1_1/security_group_rules.py 2014-02-26 16:28:51.000000000 +0000 @@ -19,6 +19,7 @@ from novaclient import base from novaclient import exceptions +from novaclient.openstack.common.gettextutils import _ class SecurityGroupRule(base.Resource): @@ -48,14 +49,14 @@ try: from_port = int(from_port) except (TypeError, ValueError): - raise exceptions.CommandError("From port must be an integer.") + raise exceptions.CommandError(_("From port must be an integer.")) try: to_port = int(to_port) except (TypeError, ValueError): - raise exceptions.CommandError("To port must be an integer.") + raise exceptions.CommandError(_("To port must be an integer.")) if ip_protocol.upper() not in ['TCP', 'UDP', 'ICMP']: - raise exceptions.CommandError("Ip protocol must be 'tcp', 'udp', " - "or 'icmp'.") + raise exceptions.CommandError(_("Ip protocol must be 'tcp', 'udp'" + ", or 'icmp'.")) body = {"security_group_rule": { "ip_protocol": ip_protocol, diff -Nru python-novaclient-2.15.0/novaclient/v1_1/security_groups.py python-novaclient-2.16.0/novaclient/v1_1/security_groups.py --- python-novaclient-2.15.0/novaclient/v1_1/security_groups.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v1_1/security_groups.py 2014-02-26 16:28:51.000000000 +0000 @@ -52,7 +52,7 @@ """ Update a security group - :param group: The security group to delete (group or ID) + :param group: The security group to update (group or ID) :param name: name for the security group to update :param description: description for the security group to update :rtype: the security group object diff -Nru python-novaclient-2.15.0/novaclient/v1_1/servers.py python-novaclient-2.16.0/novaclient/v1_1/servers.py --- python-novaclient-2.15.0/novaclient/v1_1/servers.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v1_1/servers.py 2014-02-26 16:28:51.000000000 +0000 @@ -19,11 +19,14 @@ Server interface. """ +import base64 + import six from novaclient import base from novaclient import crypto from novaclient.openstack.common.py3kcompat import urlutils +from novaclient.openstack.common import strutils from novaclient.v1_1.security_groups import SecurityGroup REBOOT_SOFT, REBOOT_HARD = 'SOFT', 'HARD' @@ -43,10 +46,9 @@ def update(self, name=None): """ - Update the name or the password for this server. + Update the name for this server. :param name: Update the server's name. - :param password: Update the root password. """ self.manager.update(self, name=name) @@ -74,11 +76,23 @@ """ return self.manager.get_spice_console(self, console_type) - def get_password(self, private_key): + def get_rdp_console(self, console_type): + """ + Get rdp console for a Server. + + :param console_type: Type of console ('rdp-html5') + """ + return self.manager.get_rdp_console(self, console_type) + + def get_password(self, private_key=None): """ Get password for a Server. + Returns the clear password of an instance if private_key is + provided, returns the ciphered password otherwise. + :param private_key: Path to private key file for decryption + (optional) """ return self.manager.get_password(self, private_key) @@ -187,6 +201,24 @@ """ self.manager.unrescue(self) + def shelve(self): + """ + Shelve -- Shelve the server. + """ + self.manager.shelve(self) + + def shelve_offload(self): + """ + Shelve_offload -- Remove a shelved server from the compute node. + """ + self.manager.shelve_offload(self) + + def unshelve(self): + """ + Unshelve -- Unshelve the server. + """ + self.manager.unshelve(self) + def diagnostics(self): """Diagnostics -- Retrieve server diagnostics.""" return self.manager.diagnostics(self) @@ -220,14 +252,18 @@ """ self.manager.reboot(self, reboot_type) - def rebuild(self, image, password=None, **kwargs): + def rebuild(self, image, password=None, preserve_ephemeral=False, + **kwargs): """ Rebuild -- shut down and then re-image -- this server. :param image: the :class:`Image` (or its ID) to re-image with. :param password: string to set as password on the rebuilt server. + :param preserve_ephemeral: If True, request that any ephemeral device + be preserved when rebuilding the instance. Defaults to False. """ - return self.manager.rebuild(self, image, password=password, **kwargs) + return self.manager.rebuild(self, image, password=password, + preserve_ephemeral=preserve_ephemeral, **kwargs) def resize(self, flavor, **kwargs): """ @@ -360,6 +396,143 @@ class ServerManager(base.BootingManagerWithFind): resource_class = Server + def _boot(self, resource_url, response_key, name, image, flavor, + meta=None, files=None, userdata=None, + reservation_id=None, return_raw=False, min_count=None, + max_count=None, security_groups=None, key_name=None, + availability_zone=None, block_device_mapping=None, + block_device_mapping_v2=None, nics=None, scheduler_hints=None, + config_drive=None, admin_pass=None, disk_config=None, **kwargs): + """ + Create (boot) a new server. + + :param name: Something to name the server. + :param image: The :class:`Image` to boot with. + :param flavor: The :class:`Flavor` to boot onto. + :param meta: A dict of arbitrary key/value metadata to store for this + server. A maximum of five entries is allowed, and both + keys and values must be 255 characters or less. + :param files: A dict of files to overwrite on the server upon boot. + Keys are file names (i.e. ``/etc/passwd``) and values + are the file contents (either as a string or as a + file-like object). A maximum of five entries is allowed, + and each file must be 10k or less. + :param reservation_id: a UUID for the set of servers being requested. + :param return_raw: If True, don't try to coearse the result into + a Resource object. + :param security_groups: list of security group names + :param key_name: (optional extension) name of keypair to inject into + the instance + :param availability_zone: Name of the availability zone for instance + placement. + :param block_device_mapping: A dict of block device mappings for this + server. + :param block_device_mapping_v2: A dict of block device mappings V2 for + this server. + :param nics: (optional extension) an ordered list of nics to be + added to this server, with information about + connected networks, fixed ips, etc. + :param scheduler_hints: (optional extension) arbitrary key-value pairs + specified by the client to help boot an instance. + :param config_drive: (optional extension) value for config drive + either boolean, or volume-id + :param admin_pass: admin password for the server. + :param disk_config: (optional extension) control how the disk is + partitioned when the server is created. + """ + body = {"server": { + "name": name, + "imageRef": str(base.getid(image)) if image else '', + "flavorRef": str(base.getid(flavor)), + }} + if userdata: + if hasattr(userdata, 'read'): + userdata = userdata.read() + + if six.PY3: + userdata = userdata.encode("utf-8") + else: + userdata = strutils.safe_encode(userdata) + + body["server"]["user_data"] = base64.b64encode(userdata) + if meta: + body["server"]["metadata"] = meta + if reservation_id: + body["server"]["reservation_id"] = reservation_id + if key_name: + body["server"]["key_name"] = key_name + if scheduler_hints: + body['os:scheduler_hints'] = scheduler_hints + if config_drive: + body["server"]["config_drive"] = config_drive + if admin_pass: + body["server"]["adminPass"] = admin_pass + if not min_count: + min_count = 1 + if not max_count: + max_count = min_count + body["server"]["min_count"] = min_count + body["server"]["max_count"] = max_count + + if security_groups: + body["server"]["security_groups"] =\ + [{'name': sg} for sg in security_groups] + + # Files are a slight bit tricky. They're passed in a "personality" + # list to the POST. Each item is a dict giving a file name and the + # base64-encoded contents of the file. We want to allow passing + # either an open file *or* some contents as files here. + if files: + personality = body['server']['personality'] = [] + for filepath, file_or_string in sorted(files.items(), + key=lambda x: x[0]): + if hasattr(file_or_string, 'read'): + data = file_or_string.read() + else: + data = file_or_string + personality.append({ + 'path': filepath, + 'contents': base64.b64encode(data.encode('utf-8')), + }) + + if availability_zone: + body["server"]["availability_zone"] = availability_zone + + # Block device mappings are passed as a list of dictionaries + if block_device_mapping: + body['server']['block_device_mapping'] = \ + self._parse_block_device_mapping(block_device_mapping) + elif block_device_mapping_v2: + # Append the image to the list only if we have new style BDMs + if image: + bdm_dict = {'uuid': image.id, 'source_type': 'image', + 'destination_type': 'local', 'boot_index': 0, + 'delete_on_termination': True} + block_device_mapping_v2.insert(0, bdm_dict) + + body['server']['block_device_mapping_v2'] = block_device_mapping_v2 + + if nics is not None: + # NOTE(tr3buchet): nics can be an empty list + all_net_data = [] + for nic_info in nics: + net_data = {} + # if value is empty string, do not send value in body + if nic_info.get('net-id'): + net_data['uuid'] = nic_info['net-id'] + if nic_info.get('v4-fixed-ip'): + net_data['fixed_ip'] = nic_info['v4-fixed-ip'] + if nic_info.get('port-id'): + net_data['port'] = nic_info['port-id'] + all_net_data.append(net_data) + body['server']['networks'] = all_net_data + + if disk_config is not None: + body['server']['OS-DCF:diskConfig'] = disk_config + + return self._create(resource_url, body, response_key, + return_raw=return_raw, **kwargs) + def get(self, server): """ Get a server. @@ -396,7 +569,13 @@ if limit: qparams['limit'] = limit - query_string = "?%s" % urlutils.urlencode(qparams) if qparams else "" + # Transform the dict to a sequence of two-element tuples in fixed + # order, then the encoded string will be consistent in Python 2&3. + if qparams: + new_qparams = sorted(qparams.items(), key=lambda x: x[0]) + query_string = "?%s" % urlutils.urlencode(new_qparams) + else: + query_string = "" detail = "" if detailed: @@ -473,24 +652,40 @@ return self._action('os-getSPICEConsole', server, {'type': console_type})[1] - def get_password(self, server, private_key): + def get_rdp_console(self, server, console_type): + """ + Get a rdp console for an instance + + :param server: The :class:`Server` (or its ID) to add an IP to. + :param console_type: Type of rdp console to get ('rdp-html5') + """ + + return self._action('os-getRDPConsole', server, + {'type': console_type})[1] + + def get_password(self, server, private_key=None): """ Get password for an instance + Returns the clear password of an instance if private_key is + provided, returns the ciphered password otherwise. + Requires that openssl is installed and in the path :param server: The :class:`Server` (or its ID) to add an IP to. :param private_key: The private key to decrypt password + (optional) """ _resp, body = self.api.client.get("/servers/%s/os-server-password" % base.getid(server)) - if body and body.get('password'): + ciphered_pw = body.get('password', '') if body else '' + if private_key and ciphered_pw: try: - return crypto.decrypt_password(private_key, body['password']) + return crypto.decrypt_password(private_key, ciphered_pw) except Exception as exc: - return '%sFailed to decrypt:\n%s' % (exc, body['password']) - return '' + return '%sFailed to decrypt:\n%s' % (exc, ciphered_pw) + return ciphered_pw def clear_password(self, server): """ @@ -574,6 +769,24 @@ """ self._action('unrescue', server, None) + def shelve(self, server): + """ + Shelve the server. + """ + self._action('shelve', server, None) + + def shelve_offload(self, server): + """ + Remove a shelved instance from the compute node. + """ + self._action('shelveOffload', server, None) + + def unshelve(self, server): + """ + Unshelve the server. + """ + self._action('unshelve', server, None) + def diagnostics(self, server): """Retrieve server diagnostics.""" return self.api.client.get("/servers/%s/diagnostics" % @@ -698,7 +911,7 @@ self._action('reboot', server, {'type': reboot_type}) def rebuild(self, server, image, password=None, disk_config=None, - **kwargs): + preserve_ephemeral=False, **kwargs): """ Rebuild -- shut down and then re-image -- a server. @@ -707,12 +920,16 @@ :param password: string to set as password on the rebuilt server. :param disk_config: partitioning mode to use on the rebuilt server. Valid values are 'AUTO' or 'MANUAL' + :param preserve_ephemeral: If True, request that any ephemeral device + be preserved when rebuilding the instance. Defaults to False. """ body = {'imageRef': base.getid(image)} if password is not None: body['adminPass'] = password if disk_config is not None: body['OS-DCF:diskConfig'] = disk_config + if preserve_ephemeral is not False: + body['preserve_ephemeral'] = True _resp, body = self._action('rebuild', server, body, **kwargs) return Server(self, body['server']) @@ -800,6 +1017,17 @@ return self._create("/servers/%s/metadata" % base.getid(server), body, "metadata") + def set_meta_item(self, server, key, value): + """ + Updates an item of server metadata + :param server: The :class:`Server` to add metadata to + :param key: metadata key to update + :param value: string value + """ + body = {'meta': {key: value}} + return self._update("/servers/%s/metadata/%s" % + (base.getid(server), key), body) + def get_console_output(self, server, length=None): """ Get text console log output from Server. diff -Nru python-novaclient-2.15.0/novaclient/v1_1/services.py python-novaclient-2.16.0/novaclient/v1_1/services.py --- python-novaclient-2.15.0/novaclient/v1_1/services.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v1_1/services.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,5 +1,3 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - # Copyright 2012 IBM Corp. # All Rights Reserved. # @@ -23,7 +21,7 @@ class Service(base.Resource): def __repr__(self): - return "" % self.service + return "" % self.binary def _add_details(self, info): dico = 'resource' in info and info['resource'] or info @@ -50,17 +48,24 @@ url = "%s?%s" % (url, "&".join(filters)) return self._list(url, "services") + def _update_body(self, host, binary, disabled_reason=None): + body = {"host": host, + "binary": binary} + if disabled_reason is not None: + body["disabled_reason"] = disabled_reason + return body + def enable(self, host, binary): """Enable the service specified by hostname and binary.""" - body = {"host": host, "binary": binary} + body = self._update_body(host, binary) return self._update("/os-services/enable", body, "service") def disable(self, host, binary): """Disable the service specified by hostname and binary.""" - body = {"host": host, "binary": binary} + body = self._update_body(host, binary) return self._update("/os-services/disable", body, "service") def disable_log_reason(self, host, binary, reason): """Disable the service with reason.""" - body = {"host": host, "binary": binary, "disabled_reason": reason} + body = self._update_body(host, binary, reason) return self._update("/os-services/disable-log-reason", body, "service") diff -Nru python-novaclient-2.15.0/novaclient/v1_1/shell.py python-novaclient-2.16.0/novaclient/v1_1/shell.py --- python-novaclient-2.15.0/novaclient/v1_1/shell.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v1_1/shell.py 2014-02-26 16:28:52.000000000 +0000 @@ -30,8 +30,10 @@ import six from novaclient import exceptions +from novaclient.openstack.common.gettextutils import _ from novaclient.openstack.common import strutils from novaclient.openstack.common import timeutils +from novaclient.openstack.common import uuidutils from novaclient import utils from novaclient.v1_1 import availability_zones from novaclient.v1_1 import quotas @@ -134,11 +136,11 @@ if max_count is None: max_count = min_count if min_count > max_count: - raise exceptions.CommandError("min_instances should be <= " - "max_instances") + raise exceptions.CommandError(_("min_instances should be <= " + "max_instances")) if not min_count or not max_count: - raise exceptions.CommandError("min_instances nor max_instances should" - "be 0") + raise exceptions.CommandError(_("min_instances nor max_instances " + "should be 0")) if args.image: image = _find_image(cs, args.image) @@ -153,11 +155,11 @@ image = images[0] if not args.flavor: - raise exceptions.CommandError("you need to specify a Flavor ID ") + raise exceptions.CommandError(_("you need to specify a Flavor ID ")) if args.num_instances is not None: if args.num_instances <= 1: - raise exceptions.CommandError("num_instances should be > 1") + raise exceptions.CommandError(_("num_instances should be > 1")) max_count = args.num_instances flavor = _find_flavor(cs, args.flavor) @@ -170,10 +172,13 @@ dst, src = f.split('=', 1) files[dst] = open(src) except IOError as e: - raise exceptions.CommandError("Can't open '%s': %s" % (src, e)) + raise exceptions.CommandError(_("Can't open '%(src)s': %(exc)s") % + {'src': src, 'exc': e}) except ValueError as e: - raise exceptions.CommandError("Invalid file argument '%s'. File " - "arguments must be of the form '--file '" % f) + raise exceptions.CommandError(_("Invalid file argument '%s'. " + "File arguments must be of the " + "form '--file " + "'") % f) # use the os-keypair extension key_name = None @@ -184,8 +189,10 @@ try: userdata = open(args.user_data) except IOError as e: - raise exceptions.CommandError("Can't open '%s': %s" % - (args.user_data, e)) + raise exceptions.CommandError(_("Can't open '%(user_data)s': " + "%(exc)s") % + {'user_data': args.user_data, + 'exc': e}) else: userdata = None @@ -206,29 +213,30 @@ block_device_mapping_v2 = _parse_block_device_mapping_v2(args, image) - n_boot_args = len(filter(None, (image, args.boot_volume, args.snapshot))) + n_boot_args = len(list(filter( + bool, (image, args.boot_volume, args.snapshot)))) have_bdm = block_device_mapping_v2 or block_device_mapping # Fail if more than one boot devices are present # or if there is no device to boot from. if n_boot_args > 1 or n_boot_args == 0 and not have_bdm: raise exceptions.CommandError( - "you need to specify at least one source ID (Image, Snapshot or " - "Volume), a block device mapping or provide a set of properties " - "to match against an image") + _("you need to specify at least one source ID (Image, Snapshot, " + "or Volume), a block device mapping or provide a set of " + "properties to match against an image")) if block_device_mapping and block_device_mapping_v2: raise exceptions.CommandError( - "you can't mix old block devices (--block-device-mapping) " + _("you can't mix old block devices (--block-device-mapping) " "with the new ones (--block-device, --boot-volume, --snapshot, " - "--ephemeral, --swap)") + "--ephemeral, --swap)")) nics = [] for nic_str in args.nics: - err_msg = ("Invalid nic argument '%s'. Nic arguments must be of the " - "form --nic , with at minimum net-id or port-id " - "specified." % nic_str) + "specified.") % nic_str) nic_info = {"net-id": "", "v4-fixed-ip": "", "port-id": ""} for kv_str in nic_str.split(","): @@ -254,7 +262,7 @@ # NOTE(vish): multiple copies of the same hint will # result in a list of values if key in hints: - if isinstance(hints[key], basestring): + if isinstance(hints[key], six.string_types): hints[key] = [hints[key]] hints[key] += [value] else: @@ -290,74 +298,74 @@ @utils.arg('--flavor', default=None, metavar='', - help="Name or ID of flavor (see 'nova flavor-list').") + help=_("Name or ID of flavor (see 'nova flavor-list').")) @utils.arg('--image', default=None, metavar='', - help="Name or ID of image (see 'nova image-list'). ") + help=_("Name or ID of image (see 'nova image-list'). ")) @utils.arg('--image-with', default=[], type=_key_value_pairing, action='append', metavar='', - help="Image metadata property (see 'nova image-show'). ") + help=_("Image metadata property (see 'nova image-show'). ")) @utils.arg('--boot-volume', default=None, metavar="", - help="Volume ID to boot from.") + help=_("Volume ID to boot from.")) @utils.arg('--snapshot', default=None, metavar="", - help="Sapshot ID to boot from (will create a volume).") + help=_("Snapshot ID to boot from (will create a volume).")) @utils.arg('--num-instances', default=None, type=int, metavar='', - help="boot multi instances at a time (limited by quota).") + help=_("boot multiple servers at a time (limited by quota).")) @utils.arg('--meta', metavar="", action='append', default=[], - help="Record arbitrary key/value metadata to /meta.js " - "on the new server. Can be specified multiple times.") + help=_("Record arbitrary key/value metadata to /meta.js " + "on the new server. Can be specified multiple times.")) @utils.arg('--file', metavar="", action='append', dest='files', default=[], - help="Store arbitrary files from locally to " - "on the new server. You may store up to 5 files.") + help=_("Store arbitrary files from locally to " + "on the new server. You may store up to 5 files.")) @utils.arg('--key-name', metavar='', - help="Key name of keypair that should be created earlier with \ - the command keypair-add") + help=_("Key name of keypair that should be created earlier with \ + the command keypair-add")) @utils.arg('--key_name', help=argparse.SUPPRESS) -@utils.arg('name', metavar='', help='Name for the new server') +@utils.arg('name', metavar='', help=_('Name for the new server')) @utils.arg('--user-data', default=None, metavar='', - help="user data file to pass to be exposed by the metadata server.") + help=_("user data file to pass to be exposed by the metadata server.")) @utils.arg('--user_data', help=argparse.SUPPRESS) @utils.arg('--availability-zone', default=None, metavar='', - help="The availability zone for instance placement.") + help=_("The availability zone for server placement.")) @utils.arg('--availability_zone', help=argparse.SUPPRESS) @utils.arg('--security-groups', default=None, metavar='', - help="Comma separated list of security group names.") + help=_("Comma separated list of security group names.")) @utils.arg('--security_groups', help=argparse.SUPPRESS) @utils.arg('--block-device-mapping', metavar="", action='append', default=[], - help="Block device mapping in the format " - "=:::.") + help=_("Block device mapping in the format " + "=:::.")) @utils.arg('--block_device_mapping', action='append', help=argparse.SUPPRESS) @@ -365,7 +373,7 @@ metavar="key1=value1[,key2=value2...]", action='append', default=[], - help="Block device mapping with the keys: " + help=_("Block device mapping with the keys: " "id=image_id, snapshot_id or volume_id, " "source=source type (image, snapshot, volume or blank), " "dest=destination type of the block device (volume or local), " @@ -375,45 +383,46 @@ "format=device will be formatted (e.g. swap, ext3, ntfs, ...), " "bootindex=integer used for ordering the boot disks, " "type=device type (e.g. disk, cdrom, ...) and " - "shutdown=shutdown behaviour (either preserve or remove).") + "shutdown=shutdown behaviour (either preserve or remove).")) @utils.arg('--swap', metavar="", default=None, - help="Create and attach a local swap block device of MB.") + help=_("Create and attach a local swap block device of MB.")) @utils.arg('--ephemeral', metavar="size=[,format=]", action='append', default=[], - help="Create and attach a local ephemeral block device of GB " - "and format it to .") + help=_("Create and attach a local ephemeral block device of GB " + "and format it to .")) @utils.arg('--hint', action='append', dest='scheduler_hints', default=[], metavar='', - help="Send arbitrary key/value pairs to the scheduler for custom use.") + help=_("Send arbitrary key/value pairs to the scheduler for custom " + "use.")) @utils.arg('--nic', metavar="", action='append', dest='nics', default=[], - help="Create a NIC on the server. " + help=_("Create a NIC on the server. " "Specify option multiple times to create multiple NICs. " "net-id: attach NIC to network with this UUID " "(required if no port-id), " "v4-fixed-ip: IPv4 fixed address for NIC (optional), " "port-id: attach NIC to port with this UUID " - "(required if no net-id)") + "(required if no net-id)")) @utils.arg('--config-drive', metavar="", dest='config_drive', default=False, - help="Enable config drive") + help=_("Enable config drive")) @utils.arg('--poll', dest='poll', action="store_true", default=False, - help='Blocks while instance builds so progress can be reported.') + help=_('Blocks while server builds so progress can be reported.')) def do_boot(cs, args): """Boot a new server.""" boot_args, boot_kwargs = _boot(cs, args) @@ -422,30 +431,10 @@ boot_kwargs.update(extra_boot_kwargs) server = cs.servers.create(*boot_args, **boot_kwargs) - - # Keep any information (like adminPass) returned by create - info = server._info - server = cs.servers.get(info['id']) - info.update(server._info) - - flavor = info.get('flavor', {}) - flavor_id = flavor.get('id', '') - info['flavor'] = _find_flavor(cs, flavor_id).name - - image = info.get('image', {}) - if image: - image_id = image.get('id', '') - info['image'] = _find_image(cs, image_id).name - else: # Booting from volume - info['image'] = "Attempt to boot from volume - no image supplied" - - info.pop('links', None) - info.pop('addresses', None) - - utils.print_dict(info) + _print_server(cs, args, server) if args.poll: - _poll_for_status(cs.servers.get, info['id'], 'building', ['active']) + _poll_for_status(cs.servers.get, server.id, 'building', ['active']) def do_cloudpipe_list(cs, _args): @@ -455,13 +444,14 @@ utils.print_list(cloudpipes, columns) -@utils.arg('project', metavar='', help='Name of the project.') +@utils.arg('project', metavar='', + help=_('UUID of the project to create the cloudpipe for.')) def do_cloudpipe_create(cs, args): """Create a cloudpipe instance for the given project.""" cs.cloudpipe.create(args.project) -@utils.arg('address', metavar='', help='New IP Address.') +@utils.arg('address', metavar='', help=_('New IP Address.')) @utils.arg('port', metavar='', help='New Port.') def do_cloudpipe_configure(cs, args): """Update the VPN IP/port of a cloudpipe instance.""" @@ -476,10 +466,10 @@ """ def print_progress(progress): if show_progress: - msg = ('\rInstance %(action)s... %(progress)s%% complete' + msg = (_('\rServer %(action)s... %(progress)s%% complete') % dict(action=action, progress=progress)) else: - msg = '\rInstance %(action)s...' % dict(action=action) + msg = _('\rServer %(action)s...') % dict(action=action) sys.stdout.write(msg) sys.stdout.flush() @@ -499,11 +489,11 @@ if status in final_ok_states: if not silent: print_progress(100) - print("\nFinished") + print(_("\nFinished")) break elif status == "error": if not silent: - print("\nError %s instance" % action) + print(_("\nError %s server") % action) break if not silent: @@ -584,12 +574,12 @@ dest='extra_specs', action='store_true', default=False, - help='Get extra-specs of each flavor.') + help=_('Get extra-specs of each flavor.')) @utils.arg('--all', dest='all', action='store_true', default=False, - help='Display all flavors (Admin only).') + help=_('Display all flavors (Admin only).')) def do_flavor_list(cs, args): """Print a list of available 'flavors' (sizes of servers).""" if args.all: @@ -601,7 +591,7 @@ @utils.arg('flavor', metavar='', - help="Name or ID of the flavor to delete") + help=_("Name or ID of the flavor to delete")) def do_flavor_delete(cs, args): """Delete a specific flavor""" flavorid = _find_flavor(cs, args.flavor) @@ -611,7 +601,7 @@ @utils.arg('flavor', metavar='', - help="Name or ID of flavor") + help=_("Name or ID of flavor")) def do_flavor_show(cs, args): """Show details about the given flavor.""" flavor = _find_flavor(cs, args.flavor) @@ -620,36 +610,36 @@ @utils.arg('name', metavar='', - help="Name of the new flavor") + help=_("Name of the new flavor")) @utils.arg('id', metavar='', - help="Unique ID (integer or UUID) for the new flavor." - " If specifying 'auto', a UUID will be generated as id") + help=_("Unique ID (integer or UUID) for the new flavor." + " If specifying 'auto', a UUID will be generated as id")) @utils.arg('ram', metavar='', - help="Memory size in MB") + help=_("Memory size in MB")) @utils.arg('disk', metavar='', - help="Disk size in GB") + help=_("Disk size in GB")) @utils.arg('--ephemeral', metavar='', - help="Ephemeral space size in GB (default 0)", + help=_("Ephemeral space size in GB (default 0)"), default=0) @utils.arg('vcpus', metavar='', - help="Number of vcpus") + help=_("Number of vcpus")) @utils.arg('--swap', metavar='', - help="Swap space size in MB (default 0)", + help=_("Swap space size in MB (default 0)"), default=0) @utils.arg('--rxtx-factor', metavar='', - help="RX/TX factor (default 1)", + help=_("RX/TX factor (default 1)"), default=1.0) @utils.arg('--is-public', metavar='', - help="Make flavor accessible to the public (default true)", - type=utils.bool_from_str, + help=_("Make flavor accessible to the public (default true)"), + type=lambda v: strutils.bool_from_string(v, True), default=True) def do_flavor_create(cs, args): """Create a new flavor""" @@ -661,17 +651,17 @@ @utils.arg('flavor', metavar='', - help="Name or ID of flavor") + help=_("Name or ID of flavor")) @utils.arg('action', metavar='', choices=['set', 'unset'], - help="Actions: 'set' or 'unset'") + help=_("Actions: 'set' or 'unset'")) @utils.arg('metadata', metavar='', nargs='+', action='append', default=[], - help='Extra_specs to set/unset (only key is necessary on unset)') + help=_('Extra_specs to set/unset (only key is necessary on unset)')) def do_flavor_key(cs, args): """Set or unset extra_spec for a flavor.""" flavor = _find_flavor(cs, args.flavor) @@ -685,25 +675,25 @@ @utils.arg('--flavor', metavar='', - help="Filter results by flavor name or ID.") + help=_("Filter results by flavor name or ID.")) @utils.arg('--tenant', metavar='', - help='Filter results by tenant ID.') + help=_('Filter results by tenant ID.')) def do_flavor_access_list(cs, args): """Print access information about the given flavor.""" if args.flavor and args.tenant: - raise exceptions.CommandError("Unable to filter results by " - "both --flavor and --tenant.") + raise exceptions.CommandError(_("Unable to filter results by " + "both --flavor and --tenant.")) elif args.flavor: flavor = _find_flavor(cs, args.flavor) if flavor.is_public: - raise exceptions.CommandError("Failed to get access list " - "for public flavor type.") + raise exceptions.CommandError(_("Failed to get access list " + "for public flavor type.")) kwargs = {'flavor': flavor} elif args.tenant: kwargs = {'tenant': args.tenant} else: - raise exceptions.CommandError("Unable to get all access lists. " - "Specify --flavor or --tenant") + raise exceptions.CommandError(_("Unable to get all access lists. " + "Specify --flavor or --tenant")) try: access_list = cs.flavor_access.list(**kwargs) @@ -716,9 +706,9 @@ @utils.arg('flavor', metavar='', - help="Filter results by flavor name or ID.") + help=_("Flavor name or ID to add access for the given tenant.")) @utils.arg('tenant', metavar='', - help='Filter results by tenant ID.') + help=_('Tenant ID to add flavor access for.')) def do_flavor_access_add(cs, args): """Add flavor access for the given tenant.""" flavor = _find_flavor_for_admin(cs, args.flavor) @@ -729,9 +719,9 @@ @utils.arg('flavor', metavar='', - help="Filter results by flavor name or ID.") + help=_("Flavor name or ID to remove access for the given tenant.")) @utils.arg('tenant', metavar='', - help='Filter results by tenant ID.') + help=_('Tenant ID to remove flavor access for.')) def do_flavor_access_remove(cs, args): """Remove flavor access for the given tenant.""" flavor = _find_flavor_for_admin(cs, args.flavor) @@ -741,7 +731,7 @@ @utils.arg('project_id', metavar='', - help='The ID of the project.') + help=_('The ID of the project.')) def do_scrub(cs, args): """Delete data associated with the project.""" networks_list = cs.networks.list() @@ -766,7 +756,7 @@ @utils.arg('network', metavar='', - help="uuid or label of network") + help=_("uuid or label of network")) def do_network_show(cs, args): """Show details about the given network.""" network = utils.find_resource(cs.networks, args.network) @@ -834,69 +824,69 @@ @utils.arg('label', metavar='', - help="Label for network") + help=_("Label for network")) @utils.arg('--fixed-range-v4', dest='cidr', metavar='', - help="IPv4 subnet (ex: 10.0.0.0/8)") + help=_("IPv4 subnet (ex: 10.0.0.0/8)")) @utils.arg('--fixed-range-v6', dest="cidr_v6", - help='IPv6 subnet (ex: fe80::/64') + help=_('IPv6 subnet (ex: fe80::/64')) @utils.arg('--vlan', dest='vlan_start', metavar='', - help="vlan id") + help=_("vlan id")) @utils.arg('--vpn', dest='vpn_start', metavar='', - help="vpn start") + help=_("vpn start")) @utils.arg('--gateway', dest="gateway", - help='gateway') + help=_('gateway')) @utils.arg('--gateway-v6', dest="gateway_v6", - help='ipv6 gateway') + help=_('ipv6 gateway')) @utils.arg('--bridge', dest="bridge", metavar='', - help='VIFs on this network are connected to this bridge') + help=_('VIFs on this network are connected to this bridge')) @utils.arg('--bridge-interface', dest="bridge_interface", metavar='', - help='the bridge is connected to this interface') + help=_('the bridge is connected to this interface')) @utils.arg('--multi-host', dest="multi_host", metavar="<'T'|'F'>", - help='Multi host') + help=_('Multi host')) @utils.arg('--dns1', dest="dns1", metavar="", help='First DNS') @utils.arg('--dns2', dest="dns2", metavar="", - help='Second DNS') + help=_('Second DNS')) @utils.arg('--uuid', dest="uuid", metavar="", - help='Network UUID') + help=_('Network UUID')) @utils.arg('--fixed-cidr', dest="fixed_cidr", metavar='', - help='IPv4 subnet for fixed IPS (ex: 10.20.0.0/16)') + help=_('IPv4 subnet for fixed IPS (ex: 10.20.0.0/16)')) @utils.arg('--project-id', dest="project_id", metavar="", - help='Project id') + help=_('Project id')) @utils.arg('--priority', dest="priority", metavar="", - help='Network interface priority') + help=_('Network interface priority')) def do_network_create(cs, args): """Create a network.""" if not (args.cidr or args.cidr_v6): raise exceptions.CommandError( - "Must specify eith fixed_range_v4 or fixed_range_v6") + _("Must specify eith fixed_range_v4 or fixed_range_v6")) kwargs = _filter_network_create_options(args) if args.multi_host is not None: kwargs['multi_host'] = bool(args.multi_host == 'T' or @@ -908,7 +898,7 @@ @utils.arg('--limit', dest="limit", metavar="", - help='number of images to return per request') + help=_('number of images to return per request')) def do_image_list(cs, _args): """Print a list of available images to boot from.""" limit = _args.limit @@ -927,17 +917,18 @@ @utils.arg('image', metavar='', - help="Name or ID of image") + help=_("Name or ID of image")) @utils.arg('action', metavar='', choices=['set', 'delete'], - help="Actions: 'set' or 'delete'") + help=_("Actions: 'set' or 'delete'")) @utils.arg('metadata', metavar='', nargs='+', action='append', default=[], - help='Metadata to add/update or delete (only key is necessary on delete)') + help=_('Metadata to add/update or delete (only key is necessary on ' + 'delete)')) def do_image_meta(cs, args): """Set or Delete metadata on an image.""" image = _find_image(cs, args.image) @@ -999,7 +990,7 @@ @utils.arg('image', metavar='', - help="Name or ID of image") + help=_("Name or ID of image")) def do_image_show(cs, args): """Show details about the given image.""" image = _find_image(cs, args.image) @@ -1007,74 +998,78 @@ @utils.arg('image', metavar='', nargs='+', - help='Name or ID of image(s).') + help=_('Name or ID of image(s).')) def do_image_delete(cs, args): """Delete specified image(s).""" for image in args.image: try: _find_image(cs, image).delete() except Exception as e: - print("Delete for image %s failed: %s" % (image, e)) + print(_("Delete for image %(image)s failed: %(e)s") % + {'image': image, 'e': e}) @utils.arg('--reservation-id', dest='reservation_id', metavar='', default=None, - help='Only return instances that match reservation-id.') + help=_('Only return servers that match reservation-id.')) @utils.arg('--reservation_id', help=argparse.SUPPRESS) @utils.arg('--ip', dest='ip', metavar='', default=None, - help='Search with regular expression match by IP address (Admin only).') + help=_('Search with regular expression match by IP address (Admin only).')) @utils.arg('--ip6', dest='ip6', metavar='', default=None, - help='Search with regular expression match by IPv6 address (Admin only).') + help=_('Search with regular expression match by IPv6 address ' + '(Admin only).')) @utils.arg('--name', dest='name', metavar='', default=None, - help='Search with regular expression match by name') + help=_('Search with regular expression match by name')) @utils.arg('--instance-name', dest='instance_name', metavar='', default=None, - help='Search with regular expression match by instance name (Admin only).') + help=_('Search with regular expression match by server name ' + '(Admin only).')) @utils.arg('--instance_name', help=argparse.SUPPRESS) @utils.arg('--status', dest='status', metavar='', default=None, - help='Search by server status') + help=_('Search by server status')) @utils.arg('--flavor', dest='flavor', metavar='', default=None, - help='Search by flavor name or ID') + help=_('Search by flavor name or ID')) @utils.arg('--image', dest='image', metavar='', default=None, - help='Search by image name or ID') + help=_('Search by image name or ID')) @utils.arg('--host', dest='host', metavar='', default=None, - help='Search instances by hostname to which they are assigned ' - '(Admin only).') + help=_('Search servers by hostname to which they are assigned (Admin ' + 'only).')) @utils.arg('--all-tenants', dest='all_tenants', metavar='<0|1>', nargs='?', type=int, const=1, - default=int(utils.bool_from_str(os.environ.get("ALL_TENANTS", 'false'))), - help='Display information from all tenants (Admin only).') + default=int(strutils.bool_from_string( + os.environ.get("ALL_TENANTS", 'false'), True)), + help=_('Display information from all tenants (Admin only).')) @utils.arg('--all_tenants', nargs='?', type=int, @@ -1085,12 +1080,22 @@ dest='tenant', metavar='', nargs='?', - help='Display information from single tenant (Admin only).') + help=_('Display information from single tenant (Admin only).')) +@utils.arg('--deleted', + dest='deleted', + action="store_true", + default=False, + help='Only display deleted servers (Admin only).') @utils.arg('--fields', default=None, metavar='', - help='Comma-separated list of fields to display. ' - 'Use the show command to see which fields are available.') + help=_('Comma-separated list of fields to display. ' + 'Use the show command to see which fields are available.')) +@utils.arg('--minimal', + dest='minimal', + action="store_true", + default=False, + help=_('Get only uuid and name.')) def do_list(cs, args): """List active servers.""" imageid = None @@ -1110,6 +1115,7 @@ 'status': args.status, 'tenant_id': args.tenant, 'host': args.host, + 'deleted': args.deleted, 'instance_name': args.instance_name} filters = {'flavor': lambda f: f['id'], @@ -1126,7 +1132,10 @@ id_col = 'ID' - servers = cs.servers.list(search_opts=search_opts) + detailed = not args.minimal + + servers = cs.servers.list(detailed=detailed, + search_opts=search_opts) convert = [('OS-EXT-SRV-ATTR:host', 'host'), ('OS-EXT-STS:task_state', 'task_state'), ('OS-EXT-SRV-ATTR:instance_name', 'instance_name'), @@ -1134,7 +1143,11 @@ ('hostId', 'host_id')] _translate_keys(servers, convert) _translate_extended_states(servers) - if field_titles: + if args.minimal: + columns = [ + id_col, + 'Name'] + elif field_titles: columns = [id_col] + field_titles else: columns = [ @@ -1155,13 +1168,13 @@ action='store_const', const=servers.REBOOT_HARD, default=servers.REBOOT_SOFT, - help='Perform a hard reboot (instead of a soft one).') -@utils.arg('server', metavar='', help='Name or ID of server.') + help=_('Perform a hard reboot (instead of a soft one).')) +@utils.arg('server', metavar='', help=_('Name or ID of server.')) @utils.arg('--poll', dest='poll', action="store_true", default=False, - help='Blocks while instance is rebooting.') + help=_('Blocks while server is rebooting.')) def do_reboot(cs, args): """Reboot a server.""" server = _find_server(cs, args.server) @@ -1172,25 +1185,29 @@ show_progress=False) -@utils.arg('server', metavar='', help='Name or ID of server.') -@utils.arg('image', metavar='', help="Name or ID of new image.") +@utils.arg('server', metavar='', help=_('Name or ID of server.')) +@utils.arg('image', metavar='', help=_("Name or ID of new image.")) @utils.arg('--rebuild-password', dest='rebuild_password', metavar='', default=False, - help="Set the provided password on the rebuild instance.") + help=_("Set the provided password on the rebuild server.")) @utils.arg('--rebuild_password', help=argparse.SUPPRESS) @utils.arg('--poll', dest='poll', action="store_true", default=False, - help='Blocks while instance rebuilds so progress can be reported.') + help=_('Blocks while server rebuilds so progress can be reported.')) @utils.arg('--minimal', dest='minimal', action="store_true", default=False, - help='Skips flavor/image lookups when showing instances') + help=_('Skips flavor/image lookups when showing servers')) +@utils.arg('--preserve-ephemeral', + action="store_true", + default=False, + help='Preserve the default ephemeral storage partition on rebuild.') def do_rebuild(cs, args): """Shutdown, re-image, and re-boot a server.""" server = _find_server(cs, args.server) @@ -1202,6 +1219,7 @@ _password = None kwargs = utils.get_resource_manager_extra_kwargs(do_rebuild, args) + kwargs['preserve_ephemeral'] = args.preserve_ephemeral server.rebuild(image, _password, **kwargs) _print_server(cs, args) @@ -1210,20 +1228,20 @@ @utils.arg('server', metavar='', - help='Name (old name) or ID of server.') -@utils.arg('name', metavar='', help='New name for the server.') + help=_('Name (old name) or ID of server.')) +@utils.arg('name', metavar='', help=_('New name for the server.')) def do_rename(cs, args): """Rename a server.""" _find_server(cs, args.server).update(name=args.name) -@utils.arg('server', metavar='', help='Name or ID of server.') -@utils.arg('flavor', metavar='', help="Name or ID of new flavor.") +@utils.arg('server', metavar='', help=_('Name or ID of server.')) +@utils.arg('flavor', metavar='', help=_("Name or ID of new flavor.")) @utils.arg('--poll', dest='poll', action="store_true", default=False, - help='Blocks while instance resizes so progress can be reported.') + help=_('Blocks while servers resizes so progress can be reported.')) def do_resize(cs, args): """Resize a server.""" server = _find_server(cs, args.server) @@ -1235,24 +1253,24 @@ ['active', 'verify_resize']) -@utils.arg('server', metavar='', help='Name or ID of server.') +@utils.arg('server', metavar='', help=_('Name or ID of server.')) def do_resize_confirm(cs, args): """Confirm a previous resize.""" _find_server(cs, args.server).confirm_resize() -@utils.arg('server', metavar='', help='Name or ID of server.') +@utils.arg('server', metavar='', help=_('Name or ID of server.')) def do_resize_revert(cs, args): """Revert a previous resize (and return to the previous VM).""" _find_server(cs, args.server).revert_resize() -@utils.arg('server', metavar='', help='Name or ID of server.') +@utils.arg('server', metavar='', help=_('Name or ID of server.')) @utils.arg('--poll', dest='poll', action="store_true", default=False, - help='Blocks while instance migrates so progress can be reported.') + help=_('Blocks while server migrates so progress can be reported.')) def do_migrate(cs, args): """Migrate a server. The new host will be selected by the scheduler.""" server = _find_server(cs, args.server) @@ -1263,74 +1281,92 @@ ['active', 'verify_resize']) -@utils.arg('server', metavar='', help='Name or ID of server.') +@utils.arg('server', metavar='', help=_('Name or ID of server.')) def do_pause(cs, args): """Pause a server.""" _find_server(cs, args.server).pause() -@utils.arg('server', metavar='', help='Name or ID of server.') +@utils.arg('server', metavar='', help=_('Name or ID of server.')) def do_unpause(cs, args): """Unpause a server.""" _find_server(cs, args.server).unpause() -@utils.arg('server', metavar='', help='Name or ID of server.') +@utils.arg('server', metavar='', help=_('Name or ID of server.')) def do_stop(cs, args): """Stop a server.""" _find_server(cs, args.server).stop() -@utils.arg('server', metavar='', help='Name or ID of server.') +@utils.arg('server', metavar='', help=_('Name or ID of server.')) def do_start(cs, args): """Start a server.""" _find_server(cs, args.server).start() -@utils.arg('server', metavar='', help='Name or ID of server.') +@utils.arg('server', metavar='', help=_('Name or ID of server.')) def do_lock(cs, args): """Lock a server.""" _find_server(cs, args.server).lock() -@utils.arg('server', metavar='', help='Name or ID of server.') +@utils.arg('server', metavar='', help=_('Name or ID of server.')) def do_unlock(cs, args): """Unlock a server.""" _find_server(cs, args.server).unlock() -@utils.arg('server', metavar='', help='Name or ID of server.') +@utils.arg('server', metavar='', help=_('Name or ID of server.')) def do_suspend(cs, args): """Suspend a server.""" _find_server(cs, args.server).suspend() -@utils.arg('server', metavar='', help='Name or ID of server.') +@utils.arg('server', metavar='', help=_('Name or ID of server.')) def do_resume(cs, args): """Resume a server.""" _find_server(cs, args.server).resume() -@utils.arg('server', metavar='', help='Name or ID of server.') +@utils.arg('server', metavar='', help=_('Name or ID of server.')) def do_rescue(cs, args): """Rescue a server.""" utils.print_dict(_find_server(cs, args.server).rescue()[1]) -@utils.arg('server', metavar='', help='Name or ID of server.') +@utils.arg('server', metavar='', help=_('Name or ID of server.')) def do_unrescue(cs, args): """Unrescue a server.""" _find_server(cs, args.server).unrescue() -@utils.arg('server', metavar='', help='Name or ID of server.') +@utils.arg('server', metavar='', help=_('Name or ID of server.')) +def do_shelve(cs, args): + """Shelve a server.""" + _find_server(cs, args.server).shelve() + + +@utils.arg('server', metavar='', help=_('Name or ID of server.')) +def do_shelve_offload(cs, args): + """Remove a shelved server from the compute node.""" + _find_server(cs, args.server).shelve_offload() + + +@utils.arg('server', metavar='', help=_('Name or ID of server.')) +def do_unshelve(cs, args): + """Unshelve a server.""" + _find_server(cs, args.server).unshelve() + + +@utils.arg('server', metavar='', help=_('Name or ID of server.')) def do_diagnostics(cs, args): """Retrieve server diagnostics.""" server = _find_server(cs, args.server) - utils.print_dict(cs.servers.diagnostics(server)[1]) + utils.print_dict(cs.servers.diagnostics(server)[1], wrap=80) -@utils.arg('server', metavar='', help='Name or ID of server.') +@utils.arg('server', metavar='', help=_('Name or ID of server.')) def do_root_password(cs, args): """ Change the root password for a server. @@ -1339,17 +1375,22 @@ p1 = getpass.getpass('New password: ') p2 = getpass.getpass('Again: ') if p1 != p2: - raise exceptions.CommandError("Passwords do not match.") + raise exceptions.CommandError(_("Passwords do not match.")) server.change_password(p1) -@utils.arg('server', metavar='', help='Name or ID of server.') -@utils.arg('name', metavar='', help='Name of snapshot.') +@utils.arg('server', metavar='', help=_('Name or ID of server.')) +@utils.arg('name', metavar='', help=_('Name of snapshot.')) +@utils.arg('--show', + dest='show', + action="store_true", + default=False, + help=_('Print image info.')) @utils.arg('--poll', dest='poll', action="store_true", default=False, - help='Blocks while instance snapshots so progress can be reported.') + help=_('Blocks while server snapshots so progress can be reported.')) def do_image_create(cs, args): """Create a new image by taking a snapshot of a running server.""" server = _find_server(cs, args.server) @@ -1374,15 +1415,19 @@ [None], status_field=task_state_field, show_progress=False, silent=True) + if args.show: + _print_image(cs.images.get(image_uuid)) -@utils.arg('server', metavar='', help='Name or ID of server.') -@utils.arg('name', metavar='', help='Name of the backup image.') + +@utils.arg('server', metavar='', help=_('Name or ID of server.')) +@utils.arg('name', metavar='', help=_('Name of the backup image.')) @utils.arg('backup_type', metavar='', - help='The backup type, like "daily" or "weekly".') + help=_('The backup type, like "daily" or "weekly".')) @utils.arg('rotation', metavar='', - help='Int parameter representing how many backups to keep around.') + help=_('Int parameter representing how many backups to keep ' + 'around.')) def do_backup(cs, args): - """Backup a instance by create a 'backup' type snapshot.""" + """Backup a server by creating a 'backup' type snapshot.""" _find_server(cs, args.server).backup(args.name, args.backup_type, args.rotation) @@ -1390,17 +1435,17 @@ @utils.arg('server', metavar='', - help="Name or ID of server") + help=_("Name or ID of server")) @utils.arg('action', metavar='', choices=['set', 'delete'], - help="Actions: 'set' or 'delete'") + help=_("Actions: 'set' or 'delete'")) @utils.arg('metadata', metavar='', nargs='+', action='append', default=[], - help='Metadata to set or delete (only key is necessary on delete)') + help=_('Metadata to set or delete (only key is necessary on delete)')) def do_meta(cs, args): """Set or Delete metadata on a server.""" server = _find_server(cs, args.server) @@ -1409,16 +1454,19 @@ if args.action == 'set': cs.servers.set_meta(server, metadata) elif args.action == 'delete': - cs.servers.delete_meta(server, metadata.keys()) + cs.servers.delete_meta(server, sorted(metadata.keys(), reverse=True)) -def _print_server(cs, args): +def _print_server(cs, args, server=None): # By default when searching via name we will do a # findall(name=blah) and due a REST /details which is not the same # as a .get() and doesn't get the information about flavors and # images. This fix it as we redo the call with the id which does a # .get() to get all informations. - server = _find_server(cs, args.server) + if not server: + server = _find_server(cs, args.server) + + minimal = getattr(args, "minimal", False) networks = server.networks info = server._info.copy() @@ -1427,25 +1475,29 @@ flavor = info.get('flavor', {}) flavor_id = flavor.get('id', '') - if args.minimal: + if minimal: info['flavor'] = flavor_id else: info['flavor'] = '%s (%s)' % (_find_flavor(cs, flavor_id).name, flavor_id) + if 'security_groups' in info: + info['security_groups'] = \ + ', '.join(group['name'] for group in info['security_groups']) + image = info.get('image', {}) if image: image_id = image.get('id', '') - if args.minimal: + if minimal: info['image'] = image_id else: try: info['image'] = '%s (%s)' % (_find_image(cs, image_id).name, image_id) except Exception: - info['image'] = '%s (%s)' % ("Image not found", image_id) + info['image'] = '%s (%s)' % (_("Image not found"), image_id) else: # Booted from volume - info['image'] = "Attempt to boot from volume - no image supplied" + info['image'] = _("Attempt to boot from volume - no image supplied") info.pop('links', None) info.pop('addresses', None) @@ -1457,15 +1509,15 @@ dest='minimal', action="store_true", default=False, - help='Skips flavor/image lookups when showing instances') -@utils.arg('server', metavar='', help='Name or ID of server.') + help=_('Skips flavor/image lookups when showing servers')) +@utils.arg('server', metavar='', help=_('Name or ID of server.')) def do_show(cs, args): """Show details about the given server.""" _print_server(cs, args) @utils.arg('server', metavar='', nargs='+', - help='Name or ID of server(s).') + help=_('Name or ID of server(s).')) def do_delete(cs, args): """Immediately shut down and delete specified server(s).""" failure_count = 0 @@ -1478,8 +1530,8 @@ print(e) if failure_count == len(args.server): - raise exceptions.CommandError("Unable to delete any of the specified " - "servers.") + raise exceptions.CommandError(_("Unable to delete any of the " + "specified servers.")) def _find_server(cs, server): @@ -1508,7 +1560,7 @@ return cs.flavors.find(ram=flavor) -@utils.arg('server', metavar='', help='Name or ID of server.') +@utils.arg('server', metavar='', help=_('Name or ID of server.')) @utils.arg('network_id', metavar='', help='Network ID.') @@ -1518,8 +1570,8 @@ server.add_fixed_ip(args.network_id) -@utils.arg('server', metavar='', help='Name or ID of server.') -@utils.arg('address', metavar='
', help='IP Address.') +@utils.arg('server', metavar='', help=_('Name or ID of server.')) +@utils.arg('address', metavar='
', help=_('IP Address.')) def do_remove_fixed_ip(cs, args): """Remove an IP address from a server.""" server = _find_server(cs, args.server) @@ -1567,8 +1619,9 @@ nargs='?', type=int, const=1, - default=int(utils.bool_from_str(os.environ.get("ALL_TENANTS", 'false'))), - help='Display information from all tenants (Admin only).') + default=int(strutils.bool_from_string( + os.environ.get("ALL_TENANTS", 'false'), True)), + help=_('Display information from all tenants (Admin only).')) @utils.arg('--all_tenants', nargs='?', type=int, @@ -1589,7 +1642,7 @@ 'Size', 'Volume Type', 'Attached to']) -@utils.arg('volume', metavar='', help='Name or ID of the volume.') +@utils.arg('volume', metavar='', help=_('Name or ID of the volume.')) @utils.service_type('volume') def do_volume_show(cs, args): """Show details about a volume.""" @@ -1600,37 +1653,37 @@ @utils.arg('size', metavar='', type=int, - help='Size of volume in GB') + help=_('Size of volume in GB')) @utils.arg('--snapshot-id', metavar='', default=None, - help='Optional snapshot id to create the volume from. (Default=None)') + help=_('Optional snapshot id to create the volume from. (Default=None)')) @utils.arg('--snapshot_id', help=argparse.SUPPRESS) @utils.arg('--image-id', metavar='', - help='Optional image id to create the volume from. (Default=None)', + help=_('Optional image id to create the volume from. (Default=None)'), default=None) @utils.arg('--display-name', metavar='', default=None, - help='Optional volume name. (Default=None)') + help=_('Optional volume name. (Default=None)')) @utils.arg('--display_name', help=argparse.SUPPRESS) @utils.arg('--display-description', metavar='', default=None, - help='Optional volume description. (Default=None)') + help=_('Optional volume description. (Default=None)')) @utils.arg('--display_description', help=argparse.SUPPRESS) @utils.arg('--volume-type', metavar='', default=None, - help='Optional volume type. (Default=None)') + help=_('Optional volume type. (Default=None)')) @utils.arg('--volume_type', help=argparse.SUPPRESS) @utils.arg('--availability-zone', metavar='', - help='Optional Availability Zone for volume. (Default=None)', + help=_('Optional Availability Zone for volume. (Default=None)'), default=None) @utils.service_type('volume') def do_volume_create(cs, args): @@ -1646,24 +1699,28 @@ @utils.arg('volume', - metavar='', - help='Name or ID of the volume to delete.') + metavar='', nargs='+', + help=_('Name or ID of the volume(s) to delete.')) @utils.service_type('volume') def do_volume_delete(cs, args): - """Remove a volume.""" - volume = _find_volume(cs, args.volume) - volume.delete() + """Remove volume(s).""" + for volume in args.volume: + try: + _find_volume(cs, volume).delete() + except Exception as e: + print(_("Delete for volume %(volume)s failed: %(e)s") % + {'volume': volume, 'e': e}) @utils.arg('server', metavar='', - help='Name or ID of server.') + help=_('Name or ID of server.')) @utils.arg('volume', metavar='', - help='ID of the volume to attach.') -@utils.arg('device', metavar='', - help='Name of the device e.g. /dev/vdb. ' - 'Use "auto" for autoassign (if supported)') + help=_('ID of the volume to attach.')) +@utils.arg('device', metavar='', default=None, nargs='?', + help=_('Name of the device e.g. /dev/vdb. ' + 'Use "auto" for autoassign (if supported)')) def do_volume_attach(cs, args): """Attach a volume to a server.""" if args.device == 'auto': @@ -1677,13 +1734,13 @@ @utils.arg('server', metavar='', - help='Name or ID of server.') + help=_('Name or ID of server.')) @utils.arg('attachment_id', metavar='', - help='Attachment ID of the volume.') + help=_('Attachment ID of the volume.')) @utils.arg('new_volume', metavar='', - help='ID of the volume to attach.') + help=_('ID of the volume to attach.')) def do_volume_update(cs, args): """Update volume attachment.""" volume = cs.volumes.update_server_volume(_find_server(cs, args.server).id, @@ -1694,10 +1751,10 @@ @utils.arg('server', metavar='', - help='Name or ID of server.') + help=_('Name or ID of server.')) @utils.arg('attachment_id', metavar='', - help='Attachment ID of the volume.') + help=_('Attachment ID of the volume.')) def do_volume_detach(cs, args): """Detach a volume from a server.""" cs.volumes.delete_server_volume(_find_server(cs, args.server).id, @@ -1715,7 +1772,7 @@ @utils.arg('snapshot', metavar='', - help='Name or ID of the snapshot.') + help=_('Name or ID of the snapshot.')) @utils.service_type('volume') def do_volume_snapshot_show(cs, args): """Show details about a snapshot.""" @@ -1725,22 +1782,22 @@ @utils.arg('volume_id', metavar='', - help='ID of the volume to snapshot') + help=_('ID of the volume to snapshot')) @utils.arg('--force', metavar='', - help='Optional flag to indicate whether to snapshot a volume even if its ' - 'attached to an instance. (Default=False)', + help=_('Optional flag to indicate whether to snapshot a volume even if ' + 'its attached to a server. (Default=False)'), default=False) @utils.arg('--display-name', metavar='', default=None, - help='Optional snapshot name. (Default=None)') + help=_('Optional snapshot name. (Default=None)')) @utils.arg('--display_name', help=argparse.SUPPRESS) @utils.arg('--display-description', metavar='', default=None, - help='Optional snapshot description. (Default=None)') + help=_('Optional snapshot description. (Default=None)')) @utils.arg('--display_description', help=argparse.SUPPRESS) @utils.service_type('volume') @@ -1755,7 +1812,7 @@ @utils.arg('snapshot', metavar='', - help='Name or ID of the snapshot to delete.') + help=_('Name or ID of the snapshot to delete.')) @utils.service_type('volume') def do_volume_snapshot_delete(cs, args): """Remove a snapshot.""" @@ -1776,7 +1833,7 @@ @utils.arg('name', metavar='', - help="Name of the new flavor") + help=_("Name of the new flavor")) @utils.service_type('volume') def do_volume_type_create(cs, args): """Create a new volume type.""" @@ -1786,17 +1843,17 @@ @utils.arg('id', metavar='', - help="Unique ID of the volume type to delete") + help=_("Unique ID of the volume type to delete")) @utils.service_type('volume') def do_volume_type_delete(cs, args): """Delete a specific flavor""" cs.volume_types.delete(args.id) -@utils.arg('server', metavar='', help='Name or ID of server.') +@utils.arg('server', metavar='', help=_('Name or ID of server.')) @utils.arg('console_type', metavar='', - help='Type of vnc console ("novnc" or "xvpvnc").') + help=_('Type of vnc console ("novnc" or "xvpvnc").')) def do_get_vnc_console(cs, args): """Get a vnc console to a server.""" server = _find_server(cs, args.server) @@ -1810,10 +1867,10 @@ utils.print_list([VNCConsole(data['console'])], ['Type', 'Url']) -@utils.arg('server', metavar='', help='Name or ID of server.') +@utils.arg('server', metavar='', help=_('Name or ID of server.')) @utils.arg('console_type', metavar='', - help='Type of spice console ("spice-html5").') + help=_('Type of spice console ("spice-html5").')) def do_get_spice_console(cs, args): """Get a spice console to a server.""" server = _find_server(cs, args.server) @@ -1827,10 +1884,32 @@ utils.print_list([SPICEConsole(data['console'])], ['Type', 'Url']) +@utils.arg('server', metavar='', help=_('Name or ID of server.')) +@utils.arg('console_type', + metavar='', + help='Type of rdp console ("rdp-html5").') +def do_get_rdp_console(cs, args): + """Get a rdp console to a server.""" + server = _find_server(cs, args.server) + data = server.get_rdp_console(args.console_type) + + class RDPConsole: + def __init__(self, console_dict): + self.type = console_dict['type'] + self.url = console_dict['url'] + + utils.print_list([RDPConsole(data['console'])], ['Type', 'Url']) + + @utils.arg('server', metavar='', help='Name or ID of server.') @utils.arg('private_key', metavar='', - help='Private key (used locally to decrypt password).') + help=_('Private key (used locally to decrypt password) (Optional). ' + 'When specified, the command displays the clear (decrypted) VM ' + 'password. When not specified, the ciphered VM password is ' + 'displayed.'), + nargs='?', + default=None) def do_get_password(cs, args): """Get password for a server.""" server = _find_server(cs, args.server) @@ -1838,7 +1917,7 @@ print(data) -@utils.arg('server', metavar='', help='Name or ID of server.') +@utils.arg('server', metavar='', help=_('Name or ID of server.')) def do_clear_password(cs, args): """Clear password for a server.""" server = _find_server(cs, args.server) @@ -1846,14 +1925,14 @@ def _print_floating_ip_list(floating_ips): - utils.print_list(floating_ips, ['Ip', 'Instance Id', 'Fixed Ip', 'Pool']) + utils.print_list(floating_ips, ['Ip', 'Server Id', 'Fixed Ip', 'Pool']) -@utils.arg('server', metavar='', help='Name or ID of server.') +@utils.arg('server', metavar='', help=_('Name or ID of server.')) @utils.arg('--length', metavar='', default=None, - help='Length in lines to tail.') + help=_('Length in lines to tail.')) def do_console_log(cs, args): """Get console log output of a server.""" server = _find_server(cs, args.server) @@ -1861,43 +1940,69 @@ print(data) +@utils.arg('server', metavar='', help=_('Name or ID of server.')) +@utils.arg('address', metavar='
', help=_('IP Address.')) +@utils.arg('--fixed-address', + metavar='', + default=None, + help=_('Fixed IP Address to associate with.')) +def do_add_floating_ip(cs, args): + """DEPRECATED, use floating-ip-associate instead.""" + _associate_floating_ip(cs, args) + + @utils.arg('server', metavar='', help='Name or ID of server.') @utils.arg('address', metavar='
', help='IP Address.') @utils.arg('--fixed-address', metavar='', default=None, help='Fixed IP Address to associate with.') -def do_add_floating_ip(cs, args): - """Add a floating IP address to a server.""" +def do_floating_ip_associate(cs, args): + """Associate a floating IP address to a server.""" + _associate_floating_ip(cs, args) + + +def _associate_floating_ip(cs, args): server = _find_server(cs, args.server) server.add_floating_ip(args.address, args.fixed_address) +@utils.arg('server', metavar='', help=_('Name or ID of server.')) +@utils.arg('address', metavar='
', help=_('IP Address.')) +def do_remove_floating_ip(cs, args): + """DEPRECATED, use floating-ip-disassociate instead.""" + _disassociate_floating_ip(cs, args) + + @utils.arg('server', metavar='', help='Name or ID of server.') @utils.arg('address', metavar='
', help='IP Address.') -def do_remove_floating_ip(cs, args): - """Remove a floating IP address from a server.""" +def do_floating_ip_disassociate(cs, args): + """Disassociate a floating IP address from a server.""" + _disassociate_floating_ip(cs, args) + + +def _disassociate_floating_ip(cs, args): server = _find_server(cs, args.server) server.remove_floating_ip(args.address) -@utils.arg('server', metavar='', help='Name or ID of server.') -@utils.arg('secgroup', metavar='', help='Name of Security Group.') +@utils.arg('server', metavar='', help=_('Name or ID of server.')) +@utils.arg('secgroup', metavar='', help=_('Name of Security Group.')) def do_add_secgroup(cs, args): """Add a Security Group to a server.""" server = _find_server(cs, args.server) server.add_security_group(args.secgroup) -@utils.arg('server', metavar='', help='Name or ID of server.') -@utils.arg('secgroup', metavar='', help='Name of Security Group.') +@utils.arg('server', metavar='', help=_('Name or ID of server.')) +@utils.arg('secgroup', metavar='', help=_('Name of Security Group.')) def do_remove_secgroup(cs, args): """Remove a Security Group from a server.""" server = _find_server(cs, args.server) server.remove_security_group(args.secgroup) -@utils.arg('server', metavar='', help='Name or ID of server.') +@utils.arg('server', metavar='', help=_('Name or ID of server.')) def do_list_secgroup(cs, args): """List Security Group(s) of a server.""" server = _find_server(cs, args.server) @@ -1907,7 +2012,7 @@ @utils.arg('pool', metavar='', - help='Name of Floating IP Pool. (Optional)', + help=_('Name of Floating IP Pool. (Optional)'), nargs='?', default=None) def do_floating_ip_create(cs, args): @@ -1915,14 +2020,15 @@ _print_floating_ip_list([cs.floating_ips.create(pool=args.pool)]) -@utils.arg('address', metavar='
', help='IP of Floating Ip.') +@utils.arg('address', metavar='
', help=_('IP of Floating Ip.')) def do_floating_ip_delete(cs, args): """De-allocate a floating IP.""" floating_ips = cs.floating_ips.list() for floating_ip in floating_ips: if floating_ip.ip == args.address: return cs.floating_ips.delete(floating_ip.id) - raise exceptions.CommandError("Floating ip %s not found." % args.address) + raise exceptions.CommandError(_("Floating ip %s not found.") % + args.address) def do_floating_ip_list(cs, _args): @@ -1936,7 +2042,7 @@ @utils.arg('--host', dest='host', metavar='', default=None, - help='Filter by host') + help=_('Filter by host')) def do_floating_ip_bulk_list(cs, args): """List all floating ips.""" utils.print_list(cs.floating_ips_bulk.list(args.host), ['project_id', @@ -1946,17 +2052,17 @@ 'interface']) -@utils.arg('ip_range', metavar='', help='Address range to create') +@utils.arg('ip_range', metavar='', help=_('Address range to create')) @utils.arg('--pool', dest='pool', metavar='', default=None, - help='Pool for new Floating IPs') + help=_('Pool for new Floating IPs')) @utils.arg('--interface', metavar='', default=None, - help='Interface for new Floating IPs') + help=_('Interface for new Floating IPs')) def do_floating_ip_bulk_create(cs, args): """Bulk create floating ips by range.""" cs.floating_ips_bulk.create(args.ip_range, args.pool, args.interface) -@utils.arg('ip_range', metavar='', help='Address range to delete') +@utils.arg('ip_range', metavar='', help=_('Address range to delete')) def do_floating_ip_bulk_delete(cs, args): """Bulk delete floating ips by range.""" cs.floating_ips_bulk.delete(args.ip_range) @@ -1977,14 +2083,14 @@ _print_domain_list(domains) -@utils.arg('domain', metavar='', help='DNS domain') -@utils.arg('--ip', metavar='', help='ip address', default=None) -@utils.arg('--name', metavar='', help='DNS name', default=None) +@utils.arg('domain', metavar='', help=_('DNS domain')) +@utils.arg('--ip', metavar='', help=_('ip address'), default=None) +@utils.arg('--name', metavar='', help=_('DNS name'), default=None) def do_dns_list(cs, args): """List current DNS entries for domain and ip or domain and name.""" if not (args.ip or args.name): raise exceptions.CommandError( - "You must specify either --ip or --name") + _("You must specify either --ip or --name")) if args.name: entry = cs.dns_entries.get(args.domain, args.name) _print_dns_list([entry]) @@ -1994,34 +2100,35 @@ _print_dns_list(entries) -@utils.arg('ip', metavar='', help='ip address') -@utils.arg('name', metavar='', help='DNS name') -@utils.arg('domain', metavar='', help='DNS domain') -@utils.arg('--type', metavar='', help='dns type (e.g. "A")', default='A') +@utils.arg('ip', metavar='', help=_('ip address')) +@utils.arg('name', metavar='', help=_('DNS name')) +@utils.arg('domain', metavar='', help=_('DNS domain')) +@utils.arg('--type', metavar='', help=_('dns type (e.g. "A")'), + default='A') def do_dns_create(cs, args): """Create a DNS entry for domain, name and ip.""" cs.dns_entries.create(args.domain, args.name, args.ip, args.type) -@utils.arg('domain', metavar='', help='DNS domain') -@utils.arg('name', metavar='', help='DNS name') +@utils.arg('domain', metavar='', help=_('DNS domain')) +@utils.arg('name', metavar='', help=_('DNS name')) def do_dns_delete(cs, args): """Delete the specified DNS entry.""" cs.dns_entries.delete(args.domain, args.name) -@utils.arg('domain', metavar='', help='DNS domain') +@utils.arg('domain', metavar='', help=_('DNS domain')) def do_dns_delete_domain(cs, args): """Delete the specified DNS domain.""" cs.dns_domains.delete(args.domain) -@utils.arg('domain', metavar='', help='DNS domain') +@utils.arg('domain', metavar='', help=_('DNS domain')) @utils.arg('--availability-zone', metavar='', default=None, - help='Limit access to this domain to instances ' - 'in the specified availability zone.') + help=_('Limit access to this domain to servers ' + 'in the specified availability zone.')) @utils.arg('--availability_zone', help=argparse.SUPPRESS) def do_dns_create_private_domain(cs, args): @@ -2030,10 +2137,10 @@ args.availability_zone) -@utils.arg('domain', metavar='', help='DNS domain') +@utils.arg('domain', metavar='', help=_('DNS domain')) @utils.arg('--project', metavar='', - help='Limit access to this domain to users ' - 'of the specified project.', + help=_('Limit access to this domain to users ' + 'of the specified project.'), default=None) def do_dns_create_public_domain(cs, args): """Create the specified DNS domain.""" @@ -2066,8 +2173,9 @@ def _get_secgroup(cs, secgroup): - # Check secgroup is an ID - if utils.is_integer_like(strutils.safe_encode(secgroup)): + # Check secgroup is an ID (nova-network) or UUID (neutron) + if (utils.is_integer_like(strutils.safe_encode(secgroup)) + or uuidutils.is_uuid_like(secgroup)): try: return cs.security_groups.get(secgroup) except exceptions.NotFound: @@ -2079,32 +2187,33 @@ encoding = (locale.getpreferredencoding() or sys.stdin.encoding or 'UTF-8') - s.name = s.name.encode(encoding) + if not six.PY3: + s.name = s.name.encode(encoding) if secgroup == s.name: - if match_found != False: - msg = ("Multiple security group matches found for name" - " '%s', use an ID to be more specific." % secgroup) + if match_found is not False: + msg = (_("Multiple security group matches found for name '%s'" + ", use an ID to be more specific.") % secgroup) raise exceptions.NoUniqueMatch(msg) match_found = s if match_found is False: - raise exceptions.CommandError("Secgroup ID or name '%s' not found." + raise exceptions.CommandError(_("Secgroup ID or name '%s' not found.") % secgroup) return match_found @utils.arg('secgroup', metavar='', - help='ID or name of security group.') + help=_('ID or name of security group.')) @utils.arg('ip_proto', metavar='', - help='IP protocol (icmp, tcp, udp).') + help=_('IP protocol (icmp, tcp, udp).')) @utils.arg('from_port', metavar='', - help='Port at start of range.') + help=_('Port at start of range.')) @utils.arg('to_port', metavar='', - help='Port at end of range.') -@utils.arg('cidr', metavar='', help='CIDR for address range.') + help=_('Port at end of range.')) +@utils.arg('cidr', metavar='', help=_('CIDR for address range.')) def do_secgroup_add_rule(cs, args): """Add a rule to a security group.""" secgroup = _get_secgroup(cs, args.secgroup) @@ -2118,17 +2227,17 @@ @utils.arg('secgroup', metavar='', - help='ID or name of security group.') + help=_('ID or name of security group.')) @utils.arg('ip_proto', metavar='', - help='IP protocol (icmp, tcp, udp).') + help=_('IP protocol (icmp, tcp, udp).')) @utils.arg('from_port', metavar='', - help='Port at start of range.') + help=_('Port at start of range.')) @utils.arg('to_port', metavar='', - help='Port at end of range.') -@utils.arg('cidr', metavar='', help='CIDR for address range.') + help=_('Port at end of range.')) +@utils.arg('cidr', metavar='', help=_('CIDR for address range.')) def do_secgroup_delete_rule(cs, args): """Delete a rule from a security group.""" secgroup = _get_secgroup(cs, args.secgroup) @@ -2141,12 +2250,12 @@ _print_secgroup_rules([rule]) return cs.security_group_rules.delete(rule['id']) - raise exceptions.CommandError("Rule not found") + raise exceptions.CommandError(_("Rule not found")) -@utils.arg('name', metavar='', help='Name of security group.') +@utils.arg('name', metavar='', help=_('Name of security group.')) @utils.arg('description', metavar='', - help='Description of security group.') + help=_('Description of security group.')) def do_secgroup_create(cs, args): """Create a security group.""" secgroup = cs.security_groups.create(args.name, args.description) @@ -2155,10 +2264,10 @@ @utils.arg('secgroup', metavar='', - help='ID or name of security group.') -@utils.arg('name', metavar='', help='Name of security group.') + help=_('ID or name of security group.')) +@utils.arg('name', metavar='', help=_('Name of security group.')) @utils.arg('description', metavar='', - help='Description of security group.') + help=_('Description of security group.')) def do_secgroup_update(cs, args): """Update a security group.""" sg = _get_secgroup(cs, args.secgroup) @@ -2168,7 +2277,7 @@ @utils.arg('secgroup', metavar='', - help='ID or name of security group.') + help=_('ID or name of security group.')) def do_secgroup_delete(cs, args): """Delete a security group.""" secgroup = _get_secgroup(cs, args.secgroup) @@ -2182,8 +2291,9 @@ nargs='?', type=int, const=1, - default=int(utils.bool_from_str(os.environ.get("ALL_TENANTS", 'false'))), - help='Display information from all tenants (Admin only).') + default=int(strutils.bool_from_string( + os.environ.get("ALL_TENANTS", 'false'), True)), + help=_('Display information from all tenants (Admin only).')) @utils.arg('--all_tenants', nargs='?', type=int, @@ -2201,7 +2311,7 @@ @utils.arg('secgroup', metavar='', - help='ID or name of security group.') + help=_('ID or name of security group.')) def do_secgroup_list_rules(cs, args): """List rules for a security group.""" secgroup = _get_secgroup(cs, args.secgroup) @@ -2210,19 +2320,19 @@ @utils.arg('secgroup', metavar='', - help='ID or name of security group.') + help=_('ID or name of security group.')) @utils.arg('source_group', metavar='', - help='ID or name of source group.') + help=_('ID or name of source group.')) @utils.arg('ip_proto', metavar='', - help='IP protocol (icmp, tcp, udp).') + help=_('IP protocol (icmp, tcp, udp).')) @utils.arg('from_port', metavar='', - help='Port at start of range.') + help=_('Port at start of range.')) @utils.arg('to_port', metavar='', - help='Port at end of range.') + help=_('Port at end of range.')) def do_secgroup_add_group_rule(cs, args): """Add a source group rule to a security group.""" secgroup = _get_secgroup(cs, args.secgroup) @@ -2232,8 +2342,8 @@ if args.ip_proto or args.from_port or args.to_port: if not (args.ip_proto and args.from_port and args.to_port): - raise exceptions.CommandError("ip_proto, from_port, and to_port" - " must be specified together") + raise exceptions.CommandError(_("ip_proto, from_port, and to_port" + " must be specified together")) params['ip_protocol'] = args.ip_proto.upper() params['from_port'] = args.from_port params['to_port'] = args.to_port @@ -2244,19 +2354,19 @@ @utils.arg('secgroup', metavar='', - help='ID or name of security group.') + help=_('ID or name of security group.')) @utils.arg('source_group', metavar='', - help='ID or name of source group.') + help=_('ID or name of source group.')) @utils.arg('ip_proto', metavar='', - help='IP protocol (icmp, tcp, udp).') + help=_('IP protocol (icmp, tcp, udp).')) @utils.arg('from_port', metavar='', - help='Port at start of range.') + help=_('Port at start of range.')) @utils.arg('to_port', metavar='', - help='Port at end of range.') + help=_('Port at end of range.')) def do_secgroup_delete_group_rule(cs, args): """Delete a source group rule from a security group.""" secgroup = _get_secgroup(cs, args.secgroup) @@ -2266,8 +2376,8 @@ if args.ip_proto or args.from_port or args.to_port: if not (args.ip_proto and args.from_port and args.to_port): - raise exceptions.CommandError("ip_proto, from_port, and to_port" - " must be specified together") + raise exceptions.CommandError(_("ip_proto, from_port, and to_port" + " must be specified together")) params['ip_protocol'] = args.ip_proto.upper() params['from_port'] = int(args.from_port) params['to_port'] = int(args.to_port) @@ -2281,18 +2391,18 @@ params.get('group_name')): return cs.security_group_rules.delete(rule['id']) - raise exceptions.CommandError("Rule not found") + raise exceptions.CommandError(_("Rule not found")) -@utils.arg('name', metavar='', help='Name of key.') +@utils.arg('name', metavar='', help=_('Name of key.')) @utils.arg('--pub-key', metavar='', default=None, - help='Path to a public ssh key.') + help=_('Path to a public ssh key.')) @utils.arg('--pub_key', help=argparse.SUPPRESS) def do_keypair_add(cs, args): - """Create a new key pair for use with instances.""" + """Create a new key pair for use with servers.""" name = args.name pub_key = args.pub_key @@ -2301,8 +2411,9 @@ with open(os.path.expanduser(pub_key)) as f: pub_key = f.read() except IOError as e: - raise exceptions.CommandError("Can't open or read '%s': %s" % - (pub_key, e)) + raise exceptions.CommandError(_("Can't open or read '%(key)s': " + "%(exc)s") % {'key': pub_key, + 'exc': e}) keypair = cs.keypairs.create(name, pub_key) @@ -2311,7 +2422,7 @@ print(private_key) -@utils.arg('name', metavar='', help='Keypair name to delete.') +@utils.arg('name', metavar='', help=_('Keypair name to delete.')) def do_keypair_delete(cs, args): """Delete keypair given by its name.""" name = args.name @@ -2329,12 +2440,12 @@ kp = keypair._info.copy() pk = kp.pop('public_key') utils.print_dict(kp) - print("Public key: %s" % pk) + print(_("Public key: %s") % pk) @utils.arg('keypair', metavar='', - help="Name or ID of keypair") + help=_("Name or ID of keypair")) def do_keypair_show(cs, args): """Show details about the given keypair.""" keypair = cs.keypairs.get(args.keypair) @@ -2346,12 +2457,12 @@ dest='tenant', metavar='', nargs='?', - help='Display information from single tenant (Admin only).') + help=_('Display information from single tenant (Admin only).')) @utils.arg('--reserved', dest='reserved', action='store_true', default=False, - help='Include reservations count.') + help=_('Include reservations count.')) def do_absolute_limits(cs, args): """Print a list of absolute limits for a user""" limits = cs.limits.get(args.reserved, args.tenant).absolute @@ -2367,15 +2478,16 @@ @utils.arg('--start', metavar='', - help='Usage range start date ex 2012-01-20 (default: 4 weeks ago)', + help=_('Usage range start date ex 2012-01-20 (default: 4 weeks ' + 'ago)'), default=None) @utils.arg('--end', metavar='', - help='Usage range end date, ex 2012-01-20 (default: tomorrow) ', + help=_('Usage range end date, ex 2012-01-20 (default: tomorrow)'), default=None) def do_usage_list(cs, args): """List usage data for all tenants.""" dateformat = "%Y-%m-%d" - rows = ["Tenant ID", "Instances", "RAM MB-Hours", "CPU Hours", + rows = ["Tenant ID", "Servers", "RAM MB-Hours", "CPU Hours", "Disk GB-Hours"] now = timeutils.utcnow() @@ -2401,8 +2513,9 @@ usage_list = cs.usage.list(start, end, detailed=True) - print("Usage from %s to %s:" % (start.strftime(dateformat), - end.strftime(dateformat))) + print(_("Usage from %(start)s to %(end)s:") % + {'start': start.strftime(dateformat), + 'end': end.strftime(dateformat)}) for usage in usage_list: simplify_usage(usage) @@ -2411,18 +2524,19 @@ @utils.arg('--start', metavar='', - help='Usage range start date ex 2012-01-20 (default: 4 weeks ago)', + help=_('Usage range start date ex 2012-01-20 (default: 4 weeks ' + 'ago)'), default=None) @utils.arg('--end', metavar='', - help='Usage range end date, ex 2012-01-20 (default: tomorrow) ', + help=_('Usage range end date, ex 2012-01-20 (default: tomorrow)'), default=None) @utils.arg('--tenant', metavar='', default=None, - help='UUID or name of tenant to get usage for.') + help=_('UUID or name of tenant to get usage for.')) def do_usage(cs, args): """Show usage data for a single tenant.""" dateformat = "%Y-%m-%d" - rows = ["Instances", "RAM MB-Hours", "CPU Hours", "Disk GB-Hours"] + rows = ["Servers", "RAM MB-Hours", "CPU Hours", "Disk GB-Hours"] now = timeutils.utcnow() @@ -2449,35 +2563,36 @@ else: usage = cs.usage.get(cs.client.tenant_id, start, end) - print("Usage from %s to %s:" % (start.strftime(dateformat), - end.strftime(dateformat))) + print(_("Usage from %(start)s to %(end)s:") % + {'start': start.strftime(dateformat), + 'end': end.strftime(dateformat)}) if getattr(usage, 'total_vcpus_usage', None): simplify_usage(usage) utils.print_list([usage], rows) else: - print('None') + print(_('None')) @utils.arg('pk_filename', metavar='', nargs='?', default='pk.pem', - help='Filename for the private key [Default: pk.pem]') + help=_('Filename for the private key [Default: pk.pem]')) @utils.arg('cert_filename', metavar='', nargs='?', default='cert.pem', - help='Filename for the X.509 certificate [Default: cert.pem]') + help=_('Filename for the X.509 certificate [Default: cert.pem]')) def do_x509_create_cert(cs, args): """Create x509 cert for a user in tenant.""" if os.path.exists(args.pk_filename): - raise exceptions.CommandError("Unable to write privatekey - %s exists." - % args.pk_filename) + raise exceptions.CommandError(_("Unable to write privatekey - %s " + "exists.") % args.pk_filename) if os.path.exists(args.cert_filename): - raise exceptions.CommandError("Unable to write x509 cert - %s exists." - % args.cert_filename) + raise exceptions.CommandError(_("Unable to write x509 cert - %s " + "exists.") % args.cert_filename) certs = cs.certs.create() @@ -2485,34 +2600,34 @@ old_umask = os.umask(0o377) with open(args.pk_filename, 'w') as private_key: private_key.write(certs.private_key) - print("Wrote private key to %s" % args.pk_filename) + print(_("Wrote private key to %s") % args.pk_filename) finally: os.umask(old_umask) with open(args.cert_filename, 'w') as cert: cert.write(certs.data) - print("Wrote x509 certificate to %s" % args.cert_filename) + print(_("Wrote x509 certificate to %s") % args.cert_filename) @utils.arg('filename', metavar='', nargs='?', default='cacert.pem', - help='Filename to write the x509 root cert.') + help=_('Filename to write the x509 root cert.')) def do_x509_get_root_cert(cs, args): """Fetch the x509 root cert.""" if os.path.exists(args.filename): - raise exceptions.CommandError("Unable to write x509 root cert - \ - %s exists." % args.filename) + raise exceptions.CommandError(_("Unable to write x509 root cert - \ + %s exists.") % args.filename) with open(args.filename, 'w') as cert: cacert = cs.certs.get() cert.write(cacert.data) - print("Wrote x509 root cert to %s" % args.filename) + print(_("Wrote x509 root cert to %s") % args.filename) @utils.arg('--hypervisor', metavar='', default=None, - help='type of hypervisor.') + help=_('type of hypervisor.')) def do_agent_list(cs, args): """List all builds.""" result = cs.agents.list(args.hypervisor) @@ -2521,14 +2636,14 @@ utils.print_list(result, columns) -@utils.arg('os', metavar='', help='type of os.') +@utils.arg('os', metavar='', help=_('type of os.')) @utils.arg('architecture', metavar='', - help='type of architecture') -@utils.arg('version', metavar='', help='version') -@utils.arg('url', metavar='', help='url') -@utils.arg('md5hash', metavar='', help='md5 hash') + help=_('type of architecture')) +@utils.arg('version', metavar='', help=_('version')) +@utils.arg('url', metavar='', help=_('url')) +@utils.arg('md5hash', metavar='', help=_('md5 hash')) @utils.arg('hypervisor', metavar='', default='xen', - help='type of hypervisor.') + help=_('type of hypervisor.')) def do_agent_create(cs, args): """Create new agent build.""" result = cs.agents.create(args.os, args.architecture, @@ -2537,16 +2652,16 @@ utils.print_dict(result._info.copy()) -@utils.arg('id', metavar='', help='id of the agent-build') +@utils.arg('id', metavar='', help=_('id of the agent-build')) def do_agent_delete(cs, args): """Delete existing agent build.""" cs.agents.delete(args.id) -@utils.arg('id', metavar='', help='id of the agent-build') -@utils.arg('version', metavar='', help='version') -@utils.arg('url', metavar='', help='url') -@utils.arg('md5hash', metavar='', help='md5hash') +@utils.arg('id', metavar='', help=_('id of the agent-build')) +@utils.arg('version', metavar='', help=_('version')) +@utils.arg('url', metavar='', help=_('url')) +@utils.arg('md5hash', metavar='', help=_('md5hash')) def do_agent_modify(cs, args): """Modify existing agent build.""" result = cs.agents.update(args.id, args.version, @@ -2566,12 +2681,12 @@ utils.print_list(aggregates, columns) -@utils.arg('name', metavar='', help='Name of aggregate.') +@utils.arg('name', metavar='', help=_('Name of aggregate.')) @utils.arg('availability_zone', metavar='', default=None, nargs='?', - help='The availability zone of the aggregate (optional).') + help=_('The availability zone of the aggregate (optional).')) def do_aggregate_create(cs, args): """Create a new aggregate with the specified details.""" aggregate = cs.aggregates.create(args.name, args.availability_zone) @@ -2579,22 +2694,22 @@ @utils.arg('aggregate', metavar='', - help='Name or ID of aggregate to delete.') + help=_('Name or ID of aggregate to delete.')) def do_aggregate_delete(cs, args): """Delete the aggregate.""" aggregate = _find_aggregate(cs, args.aggregate) cs.aggregates.delete(aggregate) - print("Aggregate %s has been successfully deleted." % aggregate.id) + print(_("Aggregate %s has been successfully deleted.") % aggregate.id) @utils.arg('aggregate', metavar='', - help='Name or ID of aggregate to update.') -@utils.arg('name', metavar='', help='Name of aggregate.') + help=_('Name or ID of aggregate to update.')) +@utils.arg('name', metavar='', help=_('Name of aggregate.')) @utils.arg('availability_zone', metavar='', nargs='?', default=None, - help='The availability zone of the aggregate.') + help=_('The availability zone of the aggregate.')) def do_aggregate_update(cs, args): """Update the aggregate's name and optionally availability zone.""" aggregate = _find_aggregate(cs, args.aggregate) @@ -2603,49 +2718,58 @@ updates["availability_zone"] = args.availability_zone aggregate = cs.aggregates.update(aggregate.id, updates) - print("Aggregate %s has been successfully updated." % aggregate.id) + print(_("Aggregate %s has been successfully updated.") % aggregate.id) _print_aggregate_details(aggregate) @utils.arg('aggregate', metavar='', - help='Name or ID of aggregate to update.') + help=_('Name or ID of aggregate to update.')) @utils.arg('metadata', metavar='', nargs='+', action='append', default=[], - help='Metadata to add/update to aggregate') + help=_('Metadata to add/update to aggregate')) def do_aggregate_set_metadata(cs, args): """Update the metadata associated with the aggregate.""" aggregate = _find_aggregate(cs, args.aggregate) metadata = _extract_metadata(args) aggregate = cs.aggregates.set_metadata(aggregate.id, metadata) - print("Aggregate %s has been successfully updated." % aggregate.id) + print(_("Metadata has been successfully updated for aggregate %s.") % + aggregate.id) _print_aggregate_details(aggregate) -@utils.arg('aggregate', metavar='', help='Name or ID of aggregate.') -@utils.arg('host', metavar='', help='The host to add to the aggregate.') +@utils.arg('aggregate', metavar='', + help=_('Name or ID of aggregate.')) +@utils.arg('host', metavar='', + help=_('The host to add to the aggregate.')) def do_aggregate_add_host(cs, args): """Add the host to the specified aggregate.""" aggregate = _find_aggregate(cs, args.aggregate) aggregate = cs.aggregates.add_host(aggregate.id, args.host) - print("Aggregate %s has been successfully updated." % aggregate.id) + print(_("Host %(host)s has been successfully added for aggregate " + "%(aggregate_id)s ") % {'host': args.host, + 'aggregate_id': aggregate.id}) _print_aggregate_details(aggregate) -@utils.arg('aggregate', metavar='', help='Name or ID of aggregate.') +@utils.arg('aggregate', metavar='', + help=_('Name or ID of aggregate.')) @utils.arg('host', metavar='', - help='The host to remove from the aggregate.') + help=_('The host to remove from the aggregate.')) def do_aggregate_remove_host(cs, args): """Remove the specified host from the specified aggregate.""" aggregate = _find_aggregate(cs, args.aggregate) aggregate = cs.aggregates.remove_host(aggregate.id, args.host) - print("Aggregate %s has been successfully updated." % aggregate.id) + print(_("Host %(host)s has been successfully removed from aggregate " + "%(aggregate_id)s ") % {'host': args.host, + 'aggregate_id': aggregate.id}) _print_aggregate_details(aggregate) -@utils.arg('aggregate', metavar='', help='Name or ID of aggregate.') +@utils.arg('aggregate', metavar='', + help=_('Name or ID of aggregate.')) def do_aggregate_details(cs, args): """Show details of the specified aggregate.""" aggregate = _find_aggregate(cs, args.aggregate) @@ -2654,18 +2778,28 @@ def _print_aggregate_details(aggregate): columns = ['Id', 'Name', 'Availability Zone', 'Hosts', 'Metadata'] - utils.print_list([aggregate], columns) + def parser_metadata(fields): + return utils.pretty_choice_dict(getattr(fields, 'metadata', {}) or {}) -@utils.arg('server', metavar='', help='Name or ID of server.') + def parser_hosts(fields): + return utils.pretty_choice_list(getattr(fields, 'hosts', [])) + + formatters = { + 'Metadata': parser_metadata, + 'Hosts': parser_hosts, + } + utils.print_list([aggregate], columns, formatters=formatters) + + +@utils.arg('server', metavar='', help=_('Name or ID of server.')) @utils.arg('host', metavar='', default=None, nargs='?', - help='destination host name.') + help=_('destination host name.')) @utils.arg('--block-migrate', action='store_true', dest='block_migrate', default=False, - help='True in case of block_migration.\ - (Default=False:live_migration)') + help=_('True in case of block_migration. (Default=False:live_migration)')) @utils.arg('--block_migrate', action='store_true', help=argparse.SUPPRESS) @@ -2673,60 +2807,60 @@ action='store_true', dest='disk_over_commit', default=False, - help='Allow overcommit.(Default=False)') + help=_('Allow overcommit.(Default=False)')) @utils.arg('--disk_over_commit', action='store_true', help=argparse.SUPPRESS) def do_live_migration(cs, args): - """Migrate running instance to a new machine.""" + """Migrate running server to a new machine.""" _find_server(cs, args.server).live_migrate(args.host, args.block_migrate, args.disk_over_commit) -@utils.arg('server', metavar='', help='Name or ID of server.') +@utils.arg('server', metavar='', help=_('Name or ID of server.')) @utils.arg('--active', action='store_const', dest='state', default='error', const='active', - help='Request the instance be reset to "active" state instead ' - 'of "error" state (the default).') + help=_('Request the server be reset to "active" state instead ' + 'of "error" state (the default).')) def do_reset_state(cs, args): - """Reset the state of an instance.""" + """Reset the state of a server.""" _find_server(cs, args.server).reset_state(args.state) -@utils.arg('server', metavar='', help='Name or ID of server.') +@utils.arg('server', metavar='', help=_('Name or ID of server.')) def do_reset_network(cs, args): - """Reset network of an instance.""" + """Reset network of a server.""" _find_server(cs, args.server).reset_network() @utils.arg('--host', metavar='', default=None, - help='Name of host.') + help=_('Name of host.')) @utils.arg('--binary', metavar='', default=None, - help='Service binary.') + help=_('Service binary.')) def do_service_list(cs, args): """Show a list of all running services. Filter by host & binary.""" result = cs.services.list(host=args.host, binary=args.binary) columns = ["Binary", "Host", "Zone", "Status", "State", "Updated_at"] # NOTE(sulo): we check if the response has disabled_reason # so as not to add the column when the extended ext is not enabled. - if hasattr(result[0], 'disabled_reason'): + if result and hasattr(result[0], 'disabled_reason'): columns.append("Disabled Reason") utils.print_list(result, columns) -@utils.arg('host', metavar='', help='Name of host.') -@utils.arg('binary', metavar='', help='Service binary.') +@utils.arg('host', metavar='', help=_('Name of host.')) +@utils.arg('binary', metavar='', help=_('Service binary.')) def do_service_enable(cs, args): """Enable the service.""" result = cs.services.enable(args.host, args.binary) utils.print_list([result], ['Host', 'Binary', 'Status']) -@utils.arg('host', metavar='', help='Name of host.') -@utils.arg('binary', metavar='', help='Service binary.') +@utils.arg('host', metavar='', help=_('Name of host.')) +@utils.arg('binary', metavar='', help=_('Service binary.')) @utils.arg('--reason', metavar='', - help='Reason for disabling service.') + help=_('Reason for disabling service.')) def do_service_disable(cs, args): """Disable the service.""" if args.reason: @@ -2739,26 +2873,26 @@ utils.print_list([result], ['Host', 'Binary', 'Status']) -@utils.arg('fixed_ip', metavar='', help='Fixed IP Address.') +@utils.arg('fixed_ip', metavar='', help=_('Fixed IP Address.')) def do_fixed_ip_get(cs, args): """Retrieve info on a fixed ip.""" result = cs.fixed_ips.get(args.fixed_ip) utils.print_list([result], ['address', 'cidr', 'hostname', 'host']) -@utils.arg('fixed_ip', metavar='', help='Fixed IP Address.') +@utils.arg('fixed_ip', metavar='', help=_('Fixed IP Address.')) def do_fixed_ip_reserve(cs, args): """Reserve a fixed IP.""" cs.fixed_ips.reserve(args.fixed_ip) -@utils.arg('fixed_ip', metavar='', help='Fixed IP Address.') +@utils.arg('fixed_ip', metavar='', help=_('Fixed IP Address.')) def do_fixed_ip_unreserve(cs, args): """Unreserve a fixed IP.""" cs.fixed_ips.unreserve(args.fixed_ip) -@utils.arg('host', metavar='', help='Name of host.') +@utils.arg('host', metavar='', help=_('Name of host.')) def do_host_describe(cs, args): """Describe a specific host.""" result = cs.hosts.get(args.host) @@ -2767,8 +2901,8 @@ @utils.arg('--zone', metavar='', default=None, - help='Filters the list, returning only those ' - 'hosts in the availability zone .') + help=_('Filters the list, returning only those ' + 'hosts in the availability zone .')) def do_host_list(cs, args): """List all hosts by service.""" columns = ["host_name", "service", "zone"] @@ -2778,12 +2912,12 @@ @utils.arg('host', metavar='', help='Name of host.') @utils.arg('--status', metavar='', default=None, dest='status', - help='Either enable or disable a host.') + help=_('Either enable or disable a host.')) @utils.arg('--maintenance', metavar='', default=None, dest='maintenance', - help='Either put or resume host to/from maintenance.') + help=_('Either put or resume host to/from maintenance.')) def do_host_update(cs, args): """Update host settings.""" updates = {} @@ -2801,63 +2935,20 @@ @utils.arg('host', metavar='', help='Name of host.') @utils.arg('--action', metavar='', dest='action', choices=['startup', 'shutdown', 'reboot'], - help='A power action: startup, reboot, or shutdown.') + help=_('A power action: startup, reboot, or shutdown.')) def do_host_action(cs, args): """Perform a power action on a host.""" result = cs.hosts.host_action(args.host, args.action) utils.print_list([result], ['HOST', 'power_action']) -@utils.arg('--combine', - dest='combine', - action="store_true", - default=False, - help='Generate a single report for all services.') -def do_coverage_start(cs, args): - """Start Nova coverage reporting.""" - cs.coverage.start(combine=args.combine) - print("Coverage collection started") - - -def do_coverage_stop(cs, args): - """Stop Nova coverage reporting.""" - out = cs.coverage.stop() - print("Coverage data file path: %s" % out[-1]['path']) - - -@utils.arg('filename', metavar='', help='report filename') -@utils.arg('--html', - dest='html', - action="store_true", - default=False, - help='Generate HTML reports instead of text ones.') -@utils.arg('--xml', - dest='xml', - action="store_true", - default=False, - help='Generate XML reports instead of text ones.') -def do_coverage_report(cs, args): - """Generate coverage report.""" - if args.html == True and args.xml == True: - raise exceptions.CommandError("--html and --xml must not be " - "specified together.") - cov = cs.coverage.report(args.filename, xml=args.xml, html=args.html) - print("Report path: %s" % cov[-1]['path']) - - -def do_coverage_reset(cs, args): - """Reset coverage data.""" - cs.coverage.reset() - print("Coverage data reset") - - def _find_hypervisor(cs, hypervisor): """Get a hypervisor by name or ID.""" return utils.find_resource(cs.hypervisors, hypervisor) @utils.arg('--matching', metavar='', default=None, - help='List hypervisors matching the given .') + help=_('List hypervisors matching the given .')) def do_hypervisor_list(cs, args): """List hypervisors.""" columns = ['ID', 'Hypervisor hostname'] @@ -2870,9 +2961,9 @@ @utils.arg('hostname', metavar='', - help='The hypervisor hostname (or pattern) to search for.') + help=_('The hypervisor hostname (or pattern) to search for.')) def do_hypervisor_servers(cs, args): - """List instances belonging to specific hypervisors.""" + """List servers belonging to specific hypervisors.""" hypers = cs.hypervisors.search(args.hostname, servers=True) class InstanceOnHyper(object): @@ -2898,23 +2989,16 @@ @utils.arg('hypervisor', metavar='', - help='Name or ID of the hypervisor to show the details of.') + help=_('Name or ID of the hypervisor to show the details of.')) def do_hypervisor_show(cs, args): """Display the details of the specified hypervisor.""" hyper = _find_hypervisor(cs, args.hypervisor) - - # Build up the dict - info = hyper._info.copy() - info['service_id'] = info['service']['id'] - info['service_host'] = info['service']['host'] - del info['service'] - - utils.print_dict(info) + utils.print_dict(utils.flatten_dict(hyper._info)) @utils.arg('hypervisor', metavar='', - help='Name or ID of the hypervisor to show the uptime of.') + help=_('Name or ID of the hypervisor to show the uptime of.')) def do_hypervisor_uptime(cs, args): """Display the uptime of the specified hypervisor.""" hyper = _find_hypervisor(cs, args.hypervisor) @@ -2947,7 +3031,7 @@ @utils.arg('--wrap', dest='wrap', metavar='', default=64, - help='wrap PKI tokens to a specified length, or 0 to disable') + help=_('wrap PKI tokens to a specified length, or 0 to disable')) def do_credentials(cs, _args): """Show user credentials returned from auth.""" ensure_service_catalog_present(cs) @@ -2957,44 +3041,55 @@ utils.print_dict(catalog['access']['token'], "Token", wrap=int(_args.wrap)) -@utils.arg('server', metavar='', help='Name or ID of server.') +@utils.arg('server', metavar='', help=_('Name or ID of server.')) @utils.arg('--port', dest='port', action='store', type=int, default=22, - help='Optional flag to indicate which port to use for ssh. ' - '(Default=22)') + help=_('Optional flag to indicate which port to use for ssh. ' + '(Default=22)')) @utils.arg('--private', dest='private', action='store_true', default=False, - help='Optional flag to indicate whether to use private address ' - 'attached to an instance. (Default=False)') + help=_('Optional flag to indicate whether to only use private address ' + 'attached to an instance. (Default=False). If no public address is ' + 'found try private address')) @utils.arg('--ipv6', dest='ipv6', action='store_true', default=False, - help='Optional flag to indicate whether to use an IPv6 address ' - 'attached to an instance. (Defaults to IPv4 address)') -@utils.arg('--login', metavar='', help='Login to use.', default="root") + help=_('Optional flag to indicate whether to use an IPv6 address ' + 'attached to a server. (Defaults to IPv4 address)')) +@utils.arg('--login', metavar='', help=_('Login to use.'), + default="root") @utils.arg('-i', '--identity', dest='identity', - help='Private key file, same as the -i option to the ssh command.', + help=_('Private key file, same as the -i option to the ssh command.'), default='') @utils.arg('--extra-opts', dest='extra', - help='Extra options to pass to ssh. see: man ssh', + help=_('Extra options to pass to ssh. see: man ssh'), default='') def do_ssh(cs, args): """SSH into a server.""" + if '@' in args.server: + user, server = args.server.split('@', 1) + args.login = user + args.server = server + addresses = _find_server(cs, args.server).addresses address_type = "private" if args.private else "public" version = 6 if args.ipv6 else 4 + if (address_type == "public" and address_type not in addresses and + "private" in addresses): + address_type = "private" + if address_type not in addresses: - print("ERROR: No %s addresses found for '%s'." % (address_type, - args.server)) + print(_("ERROR: No %(addr_type)s addresses found for '%(server)s'.") % + {'addr_type': address_type, 'server': args.server}) return ip_address = None @@ -3011,12 +3106,12 @@ args.extra)) else: pretty_version = "IPv%d" % version - print("ERROR: No %s %s address found." % (address_type, - pretty_version)) + print(_("ERROR: No %(addr_type)s %(pretty_version)s address found.") % + {'addr_type': address_type, 'pretty_version': pretty_version}) return -_quota_resources = ['instances', 'cores', 'ram', 'volumes', 'gigabytes', +_quota_resources = ['instances', 'cores', 'ram', 'floating_ips', 'fixed_ips', 'metadata_items', 'injected_files', 'injected_file_content_bytes', 'injected_file_path_bytes', 'key_pairs', @@ -3062,11 +3157,11 @@ @utils.arg('--tenant', metavar='', default=None, - help='ID of tenant to list the quotas for.') + help=_('ID of tenant to list the quotas for.')) @utils.arg('--user', metavar='', default=None, - help='ID of user to list the quotas for.') + help=_('ID of user to list the quotas for.')) def do_quota_show(cs, args): """List the quotas for a tenant/user.""" @@ -3079,7 +3174,7 @@ @utils.arg('--tenant', metavar='', default=None, - help='ID of tenant to list the default quotas for.') + help=_('ID of tenant to list the default quotas for.')) def do_quota_defaults(cs, args): """List the default quotas for a tenant.""" @@ -3091,36 +3186,28 @@ @utils.arg('tenant', metavar='', - help='ID of tenant to set the quotas for.') + help=_('ID of tenant to set the quotas for.')) @utils.arg('--user', metavar='', default=None, - help='ID of user to set the quotas for.') + help=_('ID of user to set the quotas for.')) @utils.arg('--instances', metavar='', type=int, default=None, - help='New value for the "instances" quota.') + help=_('New value for the "instances" quota.')) @utils.arg('--cores', metavar='', type=int, default=None, - help='New value for the "cores" quota.') + help=_('New value for the "cores" quota.')) @utils.arg('--ram', metavar='', type=int, default=None, - help='New value for the "ram" quota.') -@utils.arg('--volumes', - metavar='', - type=int, default=None, - help='New value for the "volumes" quota.') -@utils.arg('--gigabytes', - metavar='', - type=int, default=None, - help='New value for the "gigabytes" quota.') + help=_('New value for the "ram" quota.')) @utils.arg('--floating-ips', metavar='', type=int, default=None, - help='New value for the "floating-ips" quota.') + help=_('New value for the "floating-ips" quota.')) @utils.arg('--floating_ips', type=int, help=argparse.SUPPRESS) @@ -3128,12 +3215,12 @@ metavar='', type=int, default=None, - help='New value for the "fixed-ips" quota.') + help=_('New value for the "fixed-ips" quota.')) @utils.arg('--metadata-items', metavar='', type=int, default=None, - help='New value for the "metadata-items" quota.') + help=_('New value for the "metadata-items" quota.')) @utils.arg('--metadata_items', type=int, help=argparse.SUPPRESS) @@ -3141,7 +3228,7 @@ metavar='', type=int, default=None, - help='New value for the "injected-files" quota.') + help=_('New value for the "injected-files" quota.')) @utils.arg('--injected_files', type=int, help=argparse.SUPPRESS) @@ -3149,7 +3236,7 @@ metavar='', type=int, default=None, - help='New value for the "injected-file-content-bytes" quota.') + help=_('New value for the "injected-file-content-bytes" quota.')) @utils.arg('--injected_file_content_bytes', type=int, help=argparse.SUPPRESS) @@ -3157,28 +3244,28 @@ metavar='', type=int, default=None, - help='New value for the "injected-file-path-bytes" quota.') + help=_('New value for the "injected-file-path-bytes" quota.')) @utils.arg('--key-pairs', metavar='', type=int, default=None, - help='New value for the "key-pairs" quota.') + help=_('New value for the "key-pairs" quota.')) @utils.arg('--security-groups', metavar='', type=int, default=None, - help='New value for the "security-groups" quota.') + help=_('New value for the "security-groups" quota.')) @utils.arg('--security-group-rules', metavar='', type=int, default=None, - help='New value for the "security-group-rules" quota.') + help=_('New value for the "security-group-rules" quota.')) @utils.arg('--force', dest='force', action="store_true", default=None, - help='Whether force update the quota even if the already used' - ' and reserved exceeds the new quota') + help=_('Whether force update the quota even if the already used' + ' and reserved exceeds the new quota')) def do_quota_update(cs, args): """Update the quotas for a tenant/user.""" @@ -3187,10 +3274,10 @@ @utils.arg('--tenant', metavar='', - help='ID of tenant to delete quota for.') + help=_('ID of tenant to delete quota for.')) @utils.arg('--user', metavar='', - help='ID of user to delete quota for.') + help=_('ID of user to delete quota for.')) def do_quota_delete(cs, args): """Delete quota for a tenant/user so their quota will Revert back to default. @@ -3201,7 +3288,7 @@ @utils.arg('class_name', metavar='', - help='Name of quota class to list the quotas for.') + help=_('Name of quota class to list the quotas for.')) def do_quota_class_show(cs, args): """List the quotas for a quota class.""" @@ -3210,32 +3297,24 @@ @utils.arg('class_name', metavar='', - help='Name of quota class to set the quotas for.') + help=_('Name of quota class to set the quotas for.')) @utils.arg('--instances', metavar='', type=int, default=None, - help='New value for the "instances" quota.') + help=_('New value for the "instances" quota.')) @utils.arg('--cores', metavar='', type=int, default=None, - help='New value for the "cores" quota.') + help=_('New value for the "cores" quota.')) @utils.arg('--ram', metavar='', type=int, default=None, - help='New value for the "ram" quota.') -@utils.arg('--volumes', - metavar='', - type=int, default=None, - help='New value for the "volumes" quota.') -@utils.arg('--gigabytes', - metavar='', - type=int, default=None, - help='New value for the "gigabytes" quota.') + help=_('New value for the "ram" quota.')) @utils.arg('--floating-ips', metavar='', type=int, default=None, - help='New value for the "floating-ips" quota.') + help=_('New value for the "floating-ips" quota.')) @utils.arg('--floating_ips', type=int, help=argparse.SUPPRESS) @@ -3243,7 +3322,7 @@ metavar='', type=int, default=None, - help='New value for the "metadata-items" quota.') + help=_('New value for the "metadata-items" quota.')) @utils.arg('--metadata_items', type=int, help=argparse.SUPPRESS) @@ -3251,7 +3330,7 @@ metavar='', type=int, default=None, - help='New value for the "injected-files" quota.') + help=_('New value for the "injected-files" quota.')) @utils.arg('--injected_files', type=int, help=argparse.SUPPRESS) @@ -3259,7 +3338,7 @@ metavar='', type=int, default=None, - help='New value for the "injected-file-content-bytes" quota.') + help=_('New value for the "injected-file-content-bytes" quota.')) @utils.arg('--injected_file_content_bytes', type=int, help=argparse.SUPPRESS) @@ -3267,41 +3346,41 @@ metavar='', type=int, default=None, - help='New value for the "injected-file-path-bytes" quota.') + help=_('New value for the "injected-file-path-bytes" quota.')) @utils.arg('--key-pairs', metavar='', type=int, default=None, - help='New value for the "key-pairs" quota.') + help=_('New value for the "key-pairs" quota.')) @utils.arg('--security-groups', metavar='', type=int, default=None, - help='New value for the "security-groups" quota.') + help=_('New value for the "security-groups" quota.')) @utils.arg('--security-group-rules', metavar='', type=int, default=None, - help='New value for the "security-group-rules" quota.') + help=_('New value for the "security-group-rules" quota.')) def do_quota_class_update(cs, args): """Update the quotas for a quota class.""" _quota_update(cs.quota_classes, args.class_name, args) -@utils.arg('server', metavar='', help='Name or ID of server.') -@utils.arg('host', metavar='', help='Name or ID of target host.') +@utils.arg('server', metavar='', help=_('Name or ID of server.')) +@utils.arg('host', metavar='', help=_('Name or ID of target host.')) @utils.arg('--password', dest='password', metavar='', default=None, - help="Set the provided password on the evacuated instance. Not applicable " - "with on-shared-storage flag") + help=_("Set the provided password on the evacuated server. Not applicable " + "with on-shared-storage flag")) @utils.arg('--on-shared-storage', dest='on_shared_storage', action="store_true", default=False, - help='Specifies whether instance files located on shared storage') + help=_('Specifies whether server files are located on shared storage')) def do_evacuate(cs, args): """Evacuate server from failed host to specified one.""" server = _find_server(cs, args.server) @@ -3326,9 +3405,9 @@ utils.print_list([FormattedInterface(i) for i in interfaces], columns) -@utils.arg('server', metavar='', help='Name or ID of server.') +@utils.arg('server', metavar='', help=_('Name or ID of server.')) def do_interface_list(cs, args): - """List interfaces attached to an instance.""" + """List interfaces attached to a server.""" server = _find_server(cs, args.server) res = server.interface_list() @@ -3336,14 +3415,15 @@ _print_interfaces(res) -@utils.arg('server', metavar='', help='Name or ID of server.') -@utils.arg('--port-id', metavar='', help='Port ID.', dest="port_id") -@utils.arg('--net-id', metavar='', help='Network ID', +@utils.arg('server', metavar='', help=_('Name or ID of server.')) +@utils.arg('--port-id', metavar='', help=_('Port ID.'), + dest="port_id") +@utils.arg('--net-id', metavar='', help=_('Network ID'), default=None, dest="net_id") -@utils.arg('--fixed-ip', metavar='', help='Requested fixed IP.', +@utils.arg('--fixed-ip', metavar='', help=_('Requested fixed IP.'), default=None, dest="fixed_ip") def do_interface_attach(cs, args): - """Attach a network interface to an instance.""" + """Attach a network interface to a server.""" server = _find_server(cs, args.server) res = server.interface_attach(args.port_id, args.net_id, args.fixed_ip) @@ -3351,10 +3431,10 @@ utils.print_dict(res) -@utils.arg('server', metavar='', help='Name or ID of server.') -@utils.arg('port_id', metavar='', help='Port ID.') +@utils.arg('server', metavar='', help=_('Name or ID of server.')) +@utils.arg('port_id', metavar='', help=_('Port ID.')) def do_interface_detach(cs, args): - """Detach a network interface from an instance.""" + """Detach a network interface from a server.""" server = _find_server(cs, args.server) res = server.interface_detach(args.port_id) @@ -3379,7 +3459,8 @@ result.append(az) if zone.hosts is not None: - for (host, services) in zone.hosts.items(): + zone_hosts = sorted(zone.hosts.items(), key=lambda x: x[0]) + for (host, services) in zone_hosts: # Host tree view item az = AvailabilityZone(zone.manager, copy.deepcopy(zone._info), zone._loaded) diff -Nru python-novaclient-2.15.0/novaclient/v1_1/usage.py python-novaclient-2.16.0/novaclient/v1_1/usage.py --- python-novaclient-2.15.0/novaclient/v1_1/usage.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v1_1/usage.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,3 +1,16 @@ +# +# 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. + """ Usage interface. """ diff -Nru python-novaclient-2.15.0/novaclient/v3/agents.py python-novaclient-2.16.0/novaclient/v3/agents.py --- python-novaclient-2.15.0/novaclient/v3/agents.py 1970-01-01 00:00:00.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v3/agents.py 2014-02-26 16:28:51.000000000 +0000 @@ -0,0 +1,34 @@ +# Copyright 2012 IBM Corp. +# 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. + +""" +agent interface +""" + +from novaclient.v1_1 import agents + + +class Agent(agents.Agent): + pass + + +class AgentsManager(agents.AgentsManager): + resource_class = Agent + + def _build_update_body(self, version, url, md5hash): + return {'agent': { + 'version': version, + 'url': url, + 'md5hash': md5hash}} diff -Nru python-novaclient-2.15.0/novaclient/v3/aggregates.py python-novaclient-2.16.0/novaclient/v3/aggregates.py --- python-novaclient-2.15.0/novaclient/v3/aggregates.py 1970-01-01 00:00:00.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v3/aggregates.py 2014-02-26 16:28:51.000000000 +0000 @@ -0,0 +1,26 @@ +# Copyright 2012 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. + +"""Aggregate interface.""" + +from novaclient.v1_1 import aggregates + + +class Aggregate(aggregates.Aggregate): + pass + + +class AggregateManager(aggregates.AggregateManager): + resource_class = Aggregate diff -Nru python-novaclient-2.15.0/novaclient/v3/availability_zones.py python-novaclient-2.16.0/novaclient/v3/availability_zones.py --- python-novaclient-2.15.0/novaclient/v3/availability_zones.py 1970-01-01 00:00:00.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v3/availability_zones.py 2014-02-26 16:28:51.000000000 +0000 @@ -0,0 +1,33 @@ +# Copyright 2011 OpenStack Foundation +# Copyright 2013 IBM Corp. +# 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. + +""" +Availability Zone interface. +""" + +from novaclient.v1_1 import availability_zones + + +class AvailabilityZone(availability_zones.AvailabilityZone): + pass + + +class AvailabilityZoneManager(availability_zones.AvailabilityZoneManager): + """ + Manage :class:`AvailabilityZone` resources. + """ + resource_class = AvailabilityZone + return_parameter_name = 'availability_zone_info' diff -Nru python-novaclient-2.15.0/novaclient/v3/certs.py python-novaclient-2.16.0/novaclient/v3/certs.py --- python-novaclient-2.15.0/novaclient/v3/certs.py 1970-01-01 00:00:00.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v3/certs.py 2014-02-26 16:28:51.000000000 +0000 @@ -0,0 +1,30 @@ +# Copyright 2010 Jacob Kaplan-Moss + +# 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. + +""" +Certificate interface. +""" + +from novaclient.v1_1 import certs + + +class Certificate(certs.Certificate): + pass + + +class CertificateManager(certs.CertificateManager): + pass diff -Nru python-novaclient-2.15.0/novaclient/v3/client.py python-novaclient-2.16.0/novaclient/v3/client.py --- python-novaclient-2.15.0/novaclient/v3/client.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v3/client.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,4 +1,3 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 # Copyright 2012 OpenStack Foundation # Copyright 2013 IBM Corp. # @@ -15,6 +14,22 @@ # under the License. from novaclient import client +from novaclient.v3 import agents +from novaclient.v3 import aggregates +from novaclient.v3 import availability_zones +from novaclient.v3 import certs +from novaclient.v3 import flavor_access +from novaclient.v3 import flavors +from novaclient.v3 import hosts +from novaclient.v3 import hypervisors +from novaclient.v3 import images +from novaclient.v3 import keypairs +from novaclient.v3 import quota_classes +from novaclient.v3 import quotas +from novaclient.v3 import servers +from novaclient.v3 import services +from novaclient.v3 import usage +from novaclient.v3 import volumes class Client(object): @@ -39,13 +54,33 @@ insecure=False, timeout=None, proxy_tenant_id=None, proxy_token=None, region_name=None, endpoint_type='publicURL', extensions=None, - service_type='compute', service_name=None, + service_type='computev3', service_name=None, volume_service_name=None, timings=False, bypass_url=None, os_cache=False, no_cache=True, http_log_debug=False, auth_system='keystone', - auth_plugin=None, + auth_plugin=None, auth_token=None, cacert=None, tenant_id=None): + self.projectid = project_id + self.tenant_id = tenant_id + self.os_cache = os_cache or not no_cache #TODO(bnemec): Add back in v3 extensions + self.agents = agents.AgentsManager(self) + self.aggregates = aggregates.AggregateManager(self) + self.availability_zones = \ + availability_zones.AvailabilityZoneManager(self) + self.certs = certs.CertificateManager(self) + self.hosts = hosts.HostManager(self) + self.flavors = flavors.FlavorManager(self) + self.flavor_access = flavor_access.FlavorAccessManager(self) + self.hypervisors = hypervisors.HypervisorManager(self) + self.images = images.ImageManager(self) + self.keypairs = keypairs.KeypairManager(self) + self.quotas = quotas.QuotaSetManager(self) + self.quota_classes = quota_classes.QuotaClassSetManager(self) + self.servers = servers.ServerManager(self) + self.services = services.ServiceManager(self) + self.usage = usage.UsageManager(self) + self.volumes = volumes.VolumeManager(self) # Add in any extensions... if extensions: @@ -63,6 +98,7 @@ timeout=timeout, auth_system=auth_system, auth_plugin=auth_plugin, + auth_token=auth_token, proxy_token=proxy_token, proxy_tenant_id=proxy_tenant_id, region_name=region_name, diff -Nru python-novaclient-2.15.0/novaclient/v3/flavor_access.py python-novaclient-2.16.0/novaclient/v3/flavor_access.py --- python-novaclient-2.15.0/novaclient/v3/flavor_access.py 1970-01-01 00:00:00.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v3/flavor_access.py 2014-02-26 16:28:51.000000000 +0000 @@ -0,0 +1,45 @@ +# Copyright 2012 OpenStack Foundation +# Copyright 2013 IBM Corp. +# 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. + +"""Flavor access interface.""" + +from novaclient import base +from novaclient.v1_1 import flavor_access + + +class FlavorAccess(flavor_access.FlavorAccess): + pass + + +class FlavorAccessManager(flavor_access.FlavorAccessManager): + """ + Manage :class:`FlavorAccess` resources. + """ + resource_class = FlavorAccess + + def _list_by_flavor(self, flavor): + return self._list('/flavors/%s/flavor-access' % base.getid(flavor), + 'flavor_access') + + def add_tenant_access(self, flavor, tenant): + """Add a tenant to the given flavor access list.""" + info = {'tenant_id': tenant} + return self._action('add_tenant_access', flavor, info) + + def remove_tenant_access(self, flavor, tenant): + """Remove a tenant from the given flavor access list.""" + info = {'tenant_id': tenant} + return self._action('remove_tenant_access', flavor, info) diff -Nru python-novaclient-2.15.0/novaclient/v3/flavors.py python-novaclient-2.16.0/novaclient/v3/flavors.py --- python-novaclient-2.15.0/novaclient/v3/flavors.py 1970-01-01 00:00:00.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v3/flavors.py 2014-02-26 16:28:51.000000000 +0000 @@ -0,0 +1,103 @@ +# Copyright 2010 Jacob Kaplan-Moss +# Copyright 2013 IBM Corp. +# +# 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. + +""" +Flavor interface. +""" + +from novaclient import base +from novaclient import utils +from novaclient.v1_1 import flavors + + +class Flavor(base.Resource): + """ + A flavor is an available hardware configuration for a server. + """ + HUMAN_ID = True + + def __repr__(self): + return "" % self.name + + @property + def is_public(self): + """ + Provide a user-friendly accessor to flavor-access:is_public + """ + return self._info.get("flavor-access:is_public", 'N/A') + + def get_keys(self): + """ + Get extra specs from a flavor. + + :param flavor: The :class:`Flavor` to get extra specs from + """ + _resp, body = self.manager.api.client.get( + "/flavors/%s/flavor-extra-specs" % + base.getid(self)) + return body["extra_specs"] + + def set_keys(self, metadata): + """ + Set extra specs on a flavor. + + :param flavor: The :class:`Flavor` to set extra spec on + :param metadata: A dict of key/value pairs to be set + """ + utils.validate_flavor_metadata_keys(metadata.keys()) + + body = {'extra_specs': metadata} + return self.manager._create( + "/flavors/%s/flavor-extra-specs" % + base.getid(self), body, "extra_specs", + return_raw=True) + + def unset_keys(self, keys): + """ + Unset extra specs on a flavor. + + :param flavor: The :class:`Flavor` to unset extra spec on + :param keys: A list of keys to be unset + """ + for k in keys: + return self.manager._delete( + "/flavors/%s/flavor-extra-specs/%s" % ( + base.getid(self), k)) + + def delete(self): + """ + Delete this flavor. + """ + self.manager.delete(self) + + +class FlavorManager(flavors.FlavorManager): + resource_class = Flavor + + def _build_body(self, name, ram, vcpus, disk, id, swap, + ephemeral, rxtx_factor, is_public): + return { + "flavor": { + "name": name, + "ram": ram, + "vcpus": vcpus, + "disk": disk, + "id": id, + "swap": swap, + "ephemeral": ephemeral, + "rxtx_factor": rxtx_factor, + "flavor-access:is_public": is_public, + } + } diff -Nru python-novaclient-2.15.0/novaclient/v3/hosts.py python-novaclient-2.16.0/novaclient/v3/hosts.py --- python-novaclient-2.15.0/novaclient/v3/hosts.py 1970-01-01 00:00:00.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v3/hosts.py 2014-02-26 16:28:51.000000000 +0000 @@ -0,0 +1,35 @@ +# Copyright 2013 OpenStack Foundation +# +# 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. + +""" V3 API versions of the Hosts interface. + +Inherits from the 1.1 code because a lot of the functionality is shared. +""" + +from novaclient.v1_1 import hosts + + +Host = hosts.Host + + +class HostManager(hosts.HostManager): + def update(self, host, values): + """Update status or maintenance mode for the host.""" + body = dict(host=values) + return self._update("/os-hosts/%s" % host, body, response_key='host') + + def host_action(self, host, action): + """Perform an action on a host.""" + url = '/os-hosts/{0}/{1}'.format(host, action) + return self._get(url, response_key='host') diff -Nru python-novaclient-2.15.0/novaclient/v3/hypervisors.py python-novaclient-2.16.0/novaclient/v3/hypervisors.py --- python-novaclient-2.15.0/novaclient/v3/hypervisors.py 1970-01-01 00:00:00.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v3/hypervisors.py 2014-02-26 16:28:51.000000000 +0000 @@ -0,0 +1,48 @@ +# Copyright 2013 IBM Corp +# 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. + +""" +Hypervisors interface +""" + +from novaclient.openstack.common.py3kcompat import urlutils +from novaclient.v1_1 import hypervisors + + +class Hypervisor(hypervisors.Hypervisor): + pass + + +class HypervisorManager(hypervisors.HypervisorManager): + resource_class = Hypervisor + + def search(self, hypervisor_match): + """ + Get a list of matching hypervisors. + + :param servers: If True, server information is also retrieved. + """ + url = ('/os-hypervisors/search?query=%s' % + urlutils.quote(hypervisor_match, safe='')) + return self._list(url, 'hypervisors') + + def servers(self, hypervisor): + """ + Get servers for a specific hypervisor + + :param hypervisor: ID of hypervisor to get list of servers for. + """ + return self._get('/os-hypervisors/%s/servers' % hypervisor, + 'hypervisor') diff -Nru python-novaclient-2.15.0/novaclient/v3/images.py python-novaclient-2.16.0/novaclient/v3/images.py --- python-novaclient-2.15.0/novaclient/v3/images.py 1970-01-01 00:00:00.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v3/images.py 2014-02-26 16:28:51.000000000 +0000 @@ -0,0 +1,104 @@ +# Copyright 2010 Jacob Kaplan-Moss +# Copyright 2013 IBM Corp. +# +# 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. + +""" +Image interface. +""" +from novaclient import base +from novaclient.openstack.common.py3kcompat import urlutils +from novaclient.openstack.common import strutils + + +class Image(base.Resource): + """ + An image is a collection of files used to create or rebuild a server. + """ + HUMAN_ID = True + + def __repr__(self): + return "" % self.name + + def delete(self): + """ + Delete this image. + """ + self.manager.delete(self) + + +class ImageManager(base.ManagerWithFind): + """ + Manage :class:`Image` resources. + """ + resource_class = Image + # NOTE(cyeoh): Eventually we'll want novaclient to be smart + # enough to do version discovery, but for now we just request + # the v1 image API + image_api_prefix = '/v1' + + def _image_meta_from_headers(self, headers): + meta = {'properties': {}} + safe_decode = strutils.safe_decode + for key, value in headers.items(): + value = safe_decode(value, incoming='utf-8') + if key.startswith('x-image-meta-property-'): + _key = safe_decode(key[22:], incoming='utf-8') + meta['properties'][_key] = value + elif key.startswith('x-image-meta-'): + _key = safe_decode(key[13:], incoming='utf-8') + meta[_key] = value + + for key in ['is_public', 'protected', 'deleted']: + if key in meta: + meta[key] = strutils.bool_from_string(meta[key]) + + return self._format_image_meta_for_user(meta) + + @staticmethod + def _format_image_meta_for_user(meta): + for key in ['size', 'min_ram', 'min_disk']: + if key in meta: + try: + meta[key] = int(meta[key]) + except ValueError: + pass + return meta + + def get(self, image): + """ + Get an image. + + :param image: The ID of the image to get. + :rtype: :class:`Image` + """ + url = "%s/images/%s" % (self.image_api_prefix, base.getid(image)) + resp, _ = self.api.client._cs_request(url, 'HEAD') + foo = self._image_meta_from_headers(resp.headers) + return Image(self, foo) + + def list(self, detailed=True, limit=None): + """ + Get a list of all images. + + :rtype: list of :class:`Image` + :param limit: maximum number of images to return. + """ + params = {} + detail = '' + if detailed: + detail = '/detail' + if limit: + params['limit'] = int(limit) + query = '?%s' % urlutils.urlencode(params) if params else '' + return self._list('/v1/images%s%s' % (detail, query), 'images') diff -Nru python-novaclient-2.15.0/novaclient/v3/keypairs.py python-novaclient-2.16.0/novaclient/v3/keypairs.py --- python-novaclient-2.15.0/novaclient/v3/keypairs.py 1970-01-01 00:00:00.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v3/keypairs.py 2014-02-26 16:28:51.000000000 +0000 @@ -0,0 +1,28 @@ +# Copyright 2013 IBM Corp. +# +# 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. + +""" +Keypair interface +""" + +from novaclient.v1_1 import keypairs + + +class Keypair(keypairs.Keypair): + pass + + +class KeypairManager(keypairs.KeypairManager): + resource_class = Keypair + keypair_prefix = "keypairs" diff -Nru python-novaclient-2.15.0/novaclient/v3/quota_classes.py python-novaclient-2.16.0/novaclient/v3/quota_classes.py --- python-novaclient-2.15.0/novaclient/v3/quota_classes.py 1970-01-01 00:00:00.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v3/quota_classes.py 2014-02-26 16:28:51.000000000 +0000 @@ -0,0 +1,23 @@ +# Copyright IBM Corp. 2013 +# +# 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 novaclient.v1_1 import quota_classes + + +class QuotaClassSet(quota_classes.QuotaClassSet): + pass + + +class QuotaClassSetManager(quota_classes.QuotaClassSetManager): + resource_class = QuotaClassSet diff -Nru python-novaclient-2.15.0/novaclient/v3/quotas.py python-novaclient-2.16.0/novaclient/v3/quotas.py --- python-novaclient-2.15.0/novaclient/v3/quotas.py 1970-01-01 00:00:00.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v3/quotas.py 2014-02-26 16:28:51.000000000 +0000 @@ -0,0 +1,42 @@ +# 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. + +from novaclient.v1_1 import quotas + + +class QuotaSet(quotas.QuotaSet): + pass + + +class QuotaSetManager(quotas.QuotaSetManager): + resource_class = QuotaSet + + def get(self, tenant_id, user_id=None, detail=False): + if detail: + detail_string = '/detail' + else: + detail_string = '' + + if hasattr(tenant_id, 'tenant_id'): + tenant_id = tenant_id.tenant_id + if user_id: + url = '/os-quota-sets/%s%s?user_id=%s' % (tenant_id, detail_string, + user_id) + else: + url = '/os-quota-sets/%s%s' % (tenant_id, detail_string) + return self._get(url, "quota_set") + + def _update_body(self, tenant_id, **kwargs): + return {'quota_set': kwargs} diff -Nru python-novaclient-2.15.0/novaclient/v3/servers.py python-novaclient-2.16.0/novaclient/v3/servers.py --- python-novaclient-2.15.0/novaclient/v3/servers.py 1970-01-01 00:00:00.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v3/servers.py 2014-02-26 16:28:51.000000000 +0000 @@ -0,0 +1,1007 @@ +# Copyright 2010 Jacob Kaplan-Moss + +# 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. + +""" +Server interface. +""" + +import base64 + +import six + +from novaclient import base +from novaclient import crypto +from novaclient.openstack.common.py3kcompat import urlutils +from novaclient.openstack.common import strutils + +REBOOT_SOFT, REBOOT_HARD = 'SOFT', 'HARD' + + +class Server(base.Resource): + HUMAN_ID = True + + def __repr__(self): + return "" % self.name + + def delete(self): + """ + Delete (i.e. shut down and delete the image) this server. + """ + self.manager.delete(self) + + def update(self, name=None): + """ + Update the name or the password for this server. + + :param name: Update the server's name. + :param password: Update the root password. + """ + self.manager.update(self, name=name) + + def get_console_output(self, length=None): + """ + Get text console log output from Server. + + :param length: The number of lines you would like to retrieve (as int) + """ + return self.manager.get_console_output(self, length) + + def get_vnc_console(self, console_type): + """ + Get vnc console for a Server. + + :param console_type: Type of console ('novnc' or 'xvpvnc') + """ + return self.manager.get_vnc_console(self, console_type) + + def get_spice_console(self, console_type): + """ + Get spice console for a Server. + + :param console_type: Type of console ('spice-html5') + """ + return self.manager.get_spice_console(self, console_type) + + def get_password(self, private_key): + """ + Get password for a Server. + + :param private_key: Path to private key file for decryption + """ + return self.manager.get_password(self, private_key) + + def clear_password(self): + """ + Get password for a Server. + + """ + return self.manager.clear_password(self) + + def add_fixed_ip(self, network_id): + """ + Add an IP address on a network. + + :param network_id: The ID of the network the IP should be on. + """ + self.manager.add_fixed_ip(self, network_id) + + def remove_floating_ip(self, address): + """ + Remove floating IP from an instance + + :param address: The ip address or FloatingIP to remove + """ + self.manager.remove_floating_ip(self, address) + + def stop(self): + """ + Stop -- Stop the running server. + """ + self.manager.stop(self) + + def force_delete(self): + """ + Force delete -- Force delete a server. + """ + self.manager.force_delete(self) + + def restore(self): + """ + Restore -- Restore a server in 'soft-deleted' state. + """ + self.manager.restore(self) + + def start(self): + """ + Start -- Start the paused server. + """ + self.manager.start(self) + + def pause(self): + """ + Pause -- Pause the running server. + """ + self.manager.pause(self) + + def unpause(self): + """ + Unpause -- Unpause the paused server. + """ + self.manager.unpause(self) + + def lock(self): + """ + Lock -- Lock the instance from certain operations. + """ + self.manager.lock(self) + + def unlock(self): + """ + Unlock -- Remove instance lock. + """ + self.manager.unlock(self) + + def suspend(self): + """ + Suspend -- Suspend the running server. + """ + self.manager.suspend(self) + + def resume(self): + """ + Resume -- Resume the suspended server. + """ + self.manager.resume(self) + + def rescue(self): + """ + Rescue -- Rescue the problematic server. + """ + return self.manager.rescue(self) + + def unrescue(self): + """ + Unrescue -- Unrescue the rescued server. + """ + self.manager.unrescue(self) + + def shelve(self): + """ + Shelve -- Shelve the server. + """ + self.manager.shelve(self) + + def shelve_offload(self): + """ + Shelve_offload -- Remove a shelved server from the compute node. + """ + self.manager.shelve_offload(self) + + def unshelve(self): + """ + Unshelve -- Unshelve the server. + """ + self.manager.unshelve(self) + + def diagnostics(self): + """Diagnostics -- Retrieve server diagnostics.""" + return self.manager.diagnostics(self) + + def migrate(self): + """ + Migrate a server to a new host. + """ + self.manager.migrate(self) + + def remove_fixed_ip(self, address): + """ + Remove an IP address. + + :param address: The IP address to remove. + """ + self.manager.remove_fixed_ip(self, address) + + def change_password(self, password): + """ + Update the password for a server. + """ + self.manager.change_password(self, password) + + def reboot(self, reboot_type=REBOOT_SOFT): + """ + Reboot the server. + + :param reboot_type: either :data:`REBOOT_SOFT` for a software-level + reboot, or `REBOOT_HARD` for a virtual power cycle hard reboot. + """ + self.manager.reboot(self, reboot_type) + + def rebuild(self, image, password=None, **kwargs): + """ + Rebuild -- shut down and then re-image -- this server. + + :param image: the :class:`Image` (or its ID) to re-image with. + :param password: string to set as password on the rebuilt server. + """ + return self.manager.rebuild(self, image, password=password, **kwargs) + + def resize(self, flavor, **kwargs): + """ + Resize the server's resources. + + :param flavor: the :class:`Flavor` (or its ID) to resize to. + + Until a resize event is confirmed with :meth:`confirm_resize`, the old + server will be kept around and you'll be able to roll back to the old + flavor quickly with :meth:`revert_resize`. All resizes are + automatically confirmed after 24 hours. + """ + self.manager.resize(self, flavor, **kwargs) + + def create_image(self, image_name, metadata=None): + """ + Create an image based on this server. + + :param image_name: The name to assign the newly create image. + :param metadata: Metadata to assign to the image. + """ + return self.manager.create_image(self, image_name, metadata) + + def backup(self, backup_name, backup_type, rotation): + """ + Backup a server instance. + + :param backup_name: Name of the backup image + :param backup_type: The backup type, like 'daily' or 'weekly' + :param rotation: Int parameter representing how many backups to + keep around. + """ + self.manager.backup(self, backup_name, backup_type, rotation) + + def confirm_resize(self): + """ + Confirm that the resize worked, thus removing the original server. + """ + self.manager.confirm_resize(self) + + def revert_resize(self): + """ + Revert a previous resize, switching back to the old server. + """ + self.manager.revert_resize(self) + + @property + def networks(self): + """ + Generate a simplified list of addresses + """ + networks = {} + try: + for network_label, address_list in self.addresses.items(): + networks[network_label] = [a['addr'] for a in address_list] + return networks + except Exception: + return {} + + def live_migrate(self, host=None, + block_migration=False, + disk_over_commit=False): + """ + Migrates a running instance to a new machine. + """ + self.manager.live_migrate(self, host, + block_migration, + disk_over_commit) + + def reset_state(self, state='error'): + """ + Reset the state of an instance to active or error. + """ + self.manager.reset_state(self, state) + + def reset_network(self): + """ + Reset network of an instance. + """ + self.manager.reset_network(self) + + def evacuate(self, host, on_shared_storage, password=None): + """ + Evacuate an instance from failed host to specified host. + + :param host: Name of the target host + :param on_shared_storage: Specifies whether instance files located + on shared storage + :param password: string to set as password on the evacuated server. + """ + return self.manager.evacuate(self, host, on_shared_storage, password) + + def interface_list(self): + """ + List interfaces attached to an instance. + """ + return self.manager.interface_list(self) + + def interface_attach(self, port_id, net_id, fixed_ip): + """ + Attach a network interface to an instance. + """ + return self.manager.interface_attach(self, port_id, net_id, fixed_ip) + + def interface_detach(self, port_id): + """ + Detach a network interface from an instance. + """ + return self.manager.interface_detach(self, port_id) + + +class ServerManager(base.BootingManagerWithFind): + resource_class = Server + + def _boot(self, resource_url, response_key, name, image, flavor, + meta=None, userdata=None, + reservation_id=None, return_raw=False, min_count=None, + max_count=None, security_groups=None, key_name=None, + availability_zone=None, block_device_mapping=None, + block_device_mapping_v2=None, nics=None, scheduler_hints=None, + config_drive=None, admin_pass=None, **kwargs): + """ + Create (boot) a new server. + + :param name: Something to name the server. + :param image: The :class:`Image` to boot with. + :param flavor: The :class:`Flavor` to boot onto. + :param meta: A dict of arbitrary key/value metadata to store for this + server. A maximum of five entries is allowed, and both + keys and values must be 255 characters or less. + :param reservation_id: a UUID for the set of servers being requested. + :param return_raw: If True, don't try to coearse the result into + a Resource object. + :param security_groups: list of security group names + :param key_name: (optional extension) name of keypair to inject into + the instance + :param availability_zone: Name of the availability zone for instance + placement. + :param block_device_mapping: A dict of block device mappings for this + server. + :param block_device_mapping_v2: A dict of block device mappings V2 for + this server. + :param nics: (optional extension) an ordered list of nics to be + added to this server, with information about + connected networks, fixed ips, etc. + :param scheduler_hints: (optional extension) arbitrary key-value pairs + specified by the client to help boot an instance. + :param config_drive: (optional extension) value for config drive + either boolean, or volume-id + :param admin_pass: admin password for the server. + """ + body = {"server": { + "name": name, + "image_ref": str(base.getid(image)) if image else '', + "flavor_ref": str(base.getid(flavor)), + }} + if userdata: + if hasattr(userdata, 'read'): + userdata = userdata.read() + + if six.PY3: + userdata = userdata.encode("utf-8") + else: + userdata = strutils.safe_encode(userdata) + + body["server"][ + "os-user-data:user_data"] = base64.b64encode(userdata) + if meta: + body["server"]["metadata"] = meta + if reservation_id: + body["server"][ + "os-multiple-create:reservation_id"] = reservation_id + if key_name: + body["server"]["key_name"] = key_name + if scheduler_hints: + body["server"][ + "os-scheduler-hints:scheduler_hints"] = scheduler_hints + if config_drive: + body["server"]["os-config-drive:config_drive"] = config_drive + if admin_pass: + body["server"]["admin_password"] = admin_pass + if not min_count: + min_count = 1 + if not max_count: + max_count = min_count + body["server"]["os-multiple-create:min_count"] = min_count + body["server"]["os-multiple-create:max_count"] = max_count + + if security_groups: + body["server"]["os-security-groups:security_groups"] = \ + [{'name': sg} for sg in security_groups] + + if availability_zone: + body["server"][ + "os-availability-zone:availability_zone"] = availability_zone + + # Block device mappings are passed as a list of dictionaries + if block_device_mapping: + bdm_param = 'os-block-device-mapping:block_device_mapping' + body['server'][bdm_param] = \ + self._parse_block_device_mapping(block_device_mapping) + elif block_device_mapping_v2: + # Append the image to the list only if we have new style BDMs + if image: + bdm_dict = {'uuid': image.id, 'source_type': 'image', + 'destination_type': 'local', 'boot_index': 0, + 'delete_on_termination': True} + block_device_mapping_v2.insert(0, bdm_dict) + + body['server'][bdm_param] = block_device_mapping_v2 + + if nics is not None: + # NOTE(tr3buchet): nics can be an empty list + all_net_data = [] + for nic_info in nics: + net_data = {} + # if value is empty string, do not send value in body + if nic_info.get('net-id'): + net_data['uuid'] = nic_info['net-id'] + if nic_info.get('v4-fixed-ip'): + net_data['fixed_ip'] = nic_info['v4-fixed-ip'] + if nic_info.get('port-id'): + net_data['port'] = nic_info['port-id'] + all_net_data.append(net_data) + body['server']['networks'] = all_net_data + + return self._create(resource_url, body, response_key, + return_raw=return_raw, **kwargs) + + def get(self, server): + """ + Get a server. + + :param server: ID of the :class:`Server` to get. + :rtype: :class:`Server` + """ + return self._get("/servers/%s" % base.getid(server), "server") + + def list(self, detailed=True, search_opts=None, marker=None, limit=None): + """ + Get a list of servers. + + :param detailed: Whether to return detailed server info (optional). + :param search_opts: Search options to filter out servers (optional). + :param marker: Begin returning servers that appear later in the server + list than that represented by this server id (optional). + :param limit: Maximum number of servers to return (optional). + + :rtype: list of :class:`Server` + """ + if search_opts is None: + search_opts = {} + + qparams = {} + + for opt, val in six.iteritems(search_opts): + if val: + qparams[opt] = val + + if marker: + qparams['marker'] = marker + + if limit: + qparams['limit'] = limit + + # Transform the dict to a sequence of two-element tuples in fixed + # order, then the encoded string will be consistent in Python 2&3. + if qparams: + new_qparams = sorted(qparams.items(), key=lambda x: x[0]) + query_string = "?%s" % urlutils.urlencode(new_qparams) + else: + query_string = "" + + detail = "" + if detailed: + detail = "/detail" + return self._list("/servers%s%s" % (detail, query_string), "servers") + + def add_fixed_ip(self, server, network_id): + """ + Add an IP address on a network. + + :param server: The :class:`Server` (or its ID) to add an IP to. + :param network_id: The ID of the network the IP should be on. + """ + self._action('add_fixed_ip', server, {'network_id': network_id}) + + def remove_fixed_ip(self, server, address): + """ + Remove an IP address. + + :param server: The :class:`Server` (or its ID) to add an IP to. + :param address: The IP address to remove. + """ + self._action('remove_fixed_ip', server, {'address': address}) + + def get_vnc_console(self, server, console_type): + """ + Get a vnc console for an instance + + :param server: The :class:`Server` (or its ID) to add an IP to. + :param console_type: Type of vnc console to get ('novnc' or 'xvpvnc') + """ + + return self._action('get_vnc_console', server, + {'type': console_type})[1] + + def get_spice_console(self, server, console_type): + """ + Get a spice console for an instance + + :param server: The :class:`Server` (or its ID) to add an IP to. + :param console_type: Type of spice console to get ('spice-html5') + """ + + return self._action('get_spice_console', server, + {'type': console_type})[1] + + def get_password(self, server, private_key): + """ + Get password for an instance + + Requires that openssl is installed and in the path + + :param server: The :class:`Server` (or its ID) to add an IP to. + :param private_key: The private key to decrypt password + """ + + _resp, body = self.api.client.get("/servers/%s/os-server-password" + % base.getid(server)) + if body and body.get('password'): + try: + return crypto.decrypt_password(private_key, body['password']) + except Exception as exc: + return '%sFailed to decrypt:\n%s' % (exc, body['password']) + return '' + + def clear_password(self, server): + """ + Clear password for an instance + + :param server: The :class:`Server` (or its ID) to add an IP to. + """ + + return self._delete("/servers/%s/os-server-password" + % base.getid(server)) + + def stop(self, server): + """ + Stop the server. + """ + return self._action('stop', server, None) + + def force_delete(self, server): + """ + Force delete the server. + """ + return self._action('force_delete', server, None) + + def restore(self, server): + """ + Restore soft-deleted server. + """ + return self._action('restore', server, None) + + def start(self, server): + """ + Start the server. + """ + self._action('start', server, None) + + def pause(self, server): + """ + Pause the server. + """ + self._action('pause', server, None) + + def unpause(self, server): + """ + Unpause the server. + """ + self._action('unpause', server, None) + + def lock(self, server): + """ + Lock the server. + """ + self._action('lock', server, None) + + def unlock(self, server): + """ + Unlock the server. + """ + self._action('unlock', server, None) + + def suspend(self, server): + """ + Suspend the server. + """ + self._action('suspend', server, None) + + def resume(self, server): + """ + Resume the server. + """ + self._action('resume', server, None) + + def rescue(self, server): + """ + Rescue the server. + """ + return self._action('rescue', server, None) + + def unrescue(self, server): + """ + Unrescue the server. + """ + self._action('unrescue', server, None) + + def shelve(self, server): + """ + Shelve the server. + """ + self._action('shelve', server, None) + + def shelve_offload(self, server): + """ + Remove a shelved instance from the compute node. + """ + self._action('shelve_offload', server, None) + + def unshelve(self, server): + """ + Unshelve the server. + """ + self._action('unshelve', server, None) + + def diagnostics(self, server): + """Retrieve server diagnostics.""" + return self.api.client.get("/servers/%s/os-server-diagnostics" % + base.getid(server)) + + def create(self, name, image, flavor, meta=None, files=None, + reservation_id=None, min_count=None, + max_count=None, security_groups=None, userdata=None, + key_name=None, availability_zone=None, + block_device_mapping=None, block_device_mapping_v2=None, + nics=None, scheduler_hints=None, + config_drive=None, **kwargs): + # TODO(anthony): indicate in doc string if param is an extension + # and/or optional + """ + Create (boot) a new server. + + :param name: Something to name the server. + :param image: The :class:`Image` to boot with. + :param flavor: The :class:`Flavor` to boot onto. + :param meta: A dict of arbitrary key/value metadata to store for this + server. A maximum of five entries is allowed, and both + keys and values must be 255 characters or less. + :param files: A dict of files to overrwrite on the server upon boot. + Keys are file names (i.e. ``/etc/passwd``) and values + are the file contents (either as a string or as a + file-like object). A maximum of five entries is allowed, + and each file must be 10k or less. + :param userdata: user data to pass to be exposed by the metadata + server this can be a file type object as well or a + string. + :param reservation_id: a UUID for the set of servers being requested. + :param key_name: (optional extension) name of previously created + keypair to inject into the instance. + :param availability_zone: Name of the availability zone for instance + placement. + :param block_device_mapping: (optional extension) A dict of block + device mappings for this server. + :param block_device_mapping_v2: (optional extension) A dict of block + device mappings for this server. + :param nics: (optional extension) an ordered list of nics to be + added to this server, with information about + connected networks, fixed ips, port etc. + :param scheduler_hints: (optional extension) arbitrary key-value pairs + specified by the client to help boot an instance + :param config_drive: (optional extension) value for config drive + either boolean, or volume-id + """ + if not min_count: + min_count = 1 + if not max_count: + max_count = min_count + if min_count > max_count: + min_count = max_count + + boot_args = [name, image, flavor] + + boot_kwargs = dict( + meta=meta, files=files, userdata=userdata, + reservation_id=reservation_id, min_count=min_count, + max_count=max_count, security_groups=security_groups, + key_name=key_name, availability_zone=availability_zone, + scheduler_hints=scheduler_hints, config_drive=config_drive, + **kwargs) + + if block_device_mapping: + boot_kwargs['block_device_mapping'] = block_device_mapping + elif block_device_mapping_v2: + boot_kwargs['block_device_mapping_v2'] = block_device_mapping_v2 + resource_url = "/servers" + if nics: + boot_kwargs['nics'] = nics + + response_key = "server" + return self._boot(resource_url, response_key, *boot_args, + **boot_kwargs) + + def update(self, server, name=None): + """ + Update the name or the password for a server. + + :param server: The :class:`Server` (or its ID) to update. + :param name: Update the server's name. + """ + if name is None: + return + + body = { + "server": { + "name": name, + }, + } + + return self._update("/servers/%s" % base.getid(server), body, "server") + + def change_password(self, server, password): + """ + Update the password for a server. + """ + self._action("change_password", server, {"admin_password": password}) + + def delete(self, server): + """ + Delete (i.e. shut down and delete the image) this server. + """ + self._delete("/servers/%s" % base.getid(server)) + + def reboot(self, server, reboot_type=REBOOT_SOFT): + """ + Reboot a server. + + :param server: The :class:`Server` (or its ID) to share onto. + :param reboot_type: either :data:`REBOOT_SOFT` for a software-level + reboot, or `REBOOT_HARD` for a virtual power cycle hard reboot. + """ + self._action('reboot', server, {'type': reboot_type}) + + def rebuild(self, server, image, password=None, **kwargs): + """ + Rebuild -- shut down and then re-image -- a server. + + :param server: The :class:`Server` (or its ID) to share onto. + :param image: the :class:`Image` (or its ID) to re-image with. + :param password: string to set as password on the rebuilt server. + """ + body = {'image_ref': base.getid(image)} + if password is not None: + body['admin_password'] = password + + _resp, body = self._action('rebuild', server, body, **kwargs) + return Server(self, body['server']) + + def migrate(self, server): + """ + Migrate a server to a new host. + + :param server: The :class:`Server` (or its ID). + """ + self._action('migrate', server) + + def resize(self, server, flavor, **kwargs): + """ + Resize a server's resources. + + :param server: The :class:`Server` (or its ID) to share onto. + :param flavor: the :class:`Flavor` (or its ID) to resize to. + + Until a resize event is confirmed with :meth:`confirm_resize`, the old + server will be kept around and you'll be able to roll back to the old + flavor quickly with :meth:`revert_resize`. All resizes are + automatically confirmed after 24 hours. + """ + info = {'flavor_ref': base.getid(flavor)} + + self._action('resize', server, info=info, **kwargs) + + def confirm_resize(self, server): + """ + Confirm that the resize worked, thus removing the original server. + + :param server: The :class:`Server` (or its ID) to share onto. + """ + self._action('confirm_resize', server) + + def revert_resize(self, server): + """ + Revert a previous resize, switching back to the old server. + + :param server: The :class:`Server` (or its ID) to share onto. + """ + self._action('revert_resize', server) + + def create_image(self, server, image_name, metadata=None): + """ + Snapshot a server. + + :param server: The :class:`Server` (or its ID) to share onto. + :param image_name: Name to give the snapshot image + :param meta: Metadata to give newly-created image entity + """ + body = {'name': image_name, 'metadata': metadata or {}} + resp = self._action('create_image', server, body)[0] + location = resp.headers['location'] + image_uuid = location.split('/')[-1] + return image_uuid + + def backup(self, server, backup_name, backup_type, rotation): + """ + Backup a server instance. + + :param server: The :class:`Server` (or its ID) to share onto. + :param backup_name: Name of the backup image + :param backup_type: The backup type, like 'daily' or 'weekly' + :param rotation: Int parameter representing how many backups to + keep around. + """ + body = {'name': backup_name, + 'backup_type': backup_type, + 'rotation': rotation} + self._action('create_backup', server, body) + + def set_meta(self, server, metadata): + """ + Set a servers metadata + :param server: The :class:`Server` to add metadata to + :param metadata: A dict of metadata to add to the server + """ + body = {'metadata': metadata} + return self._create("/servers/%s/metadata" % base.getid(server), + body, "metadata") + + def get_console_output(self, server, length=None): + """ + Get text console log output from Server. + + :param server: The :class:`Server` (or its ID) whose console output + you would like to retrieve. + :param length: The number of tail loglines you would like to retrieve. + """ + return self._action('get_console_output', + server, {'length': length})[1]['output'] + + def delete_meta(self, server, keys): + """ + Delete metadata from an server + :param server: The :class:`Server` to add metadata to + :param keys: A list of metadata keys to delete from the server + """ + for k in keys: + self._delete("/servers/%s/metadata/%s" % (base.getid(server), k)) + + def live_migrate(self, server, host, block_migration, disk_over_commit): + """ + Migrates a running instance to a new machine. + + :param server: instance id which comes from nova list. + :param host: destination host name. + :param block_migration: if True, do block_migration. + :param disk_over_commit: if True, Allow overcommit. + + """ + self._action('migrate_live', server, + {'host': host, + 'block_migration': block_migration, + 'disk_over_commit': disk_over_commit}) + + def reset_state(self, server, state='error'): + """ + Reset the state of an instance to active or error. + + :param server: ID of the instance to reset the state of. + :param state: Desired state; either 'active' or 'error'. + Defaults to 'error'. + """ + self._action('reset_state', server, dict(state=state)) + + def reset_network(self, server): + """ + Reset network of an instance. + """ + self._action('reset_network', server) + + def evacuate(self, server, host, on_shared_storage, password=None): + """ + Evacuate a server instance. + + :param server: The :class:`Server` (or its ID) to share onto. + :param host: Name of the target host. + :param on_shared_storage: Specifies whether instance files located + on shared storage + :param password: string to set as password on the evacuated server. + """ + body = { + 'host': host, + 'on_shared_storage': on_shared_storage, + } + + if password is not None: + body['admin_password'] = password + + return self._action('evacuate', server, body) + + def interface_list(self, server): + """ + List attached network interfaces + + :param server: The :class:`Server` (or its ID) to query. + """ + return self._list('/servers/%s/os-attach-interfaces' + % base.getid(server), 'interface_attachments') + + def interface_attach(self, server, port_id, net_id, fixed_ip): + """ + Attach a network_interface to an instance. + + :param server: The :class:`Server` (or its ID) to attach to. + :param port_id: The port to attach. + """ + + body = {'interface_attachment': {}} + if port_id: + body['interface_attachment']['port_id'] = port_id + if net_id: + body['interface_attachment']['net_id'] = net_id + if fixed_ip: + body['interface_attachment']['fixed_ips'] = [ + {'ip_address': fixed_ip}] + + return self._create('/servers/%s/os-attach-interfaces' + % base.getid(server), + body, 'interface_attachment') + + def interface_detach(self, server, port_id): + """ + Detach a network_interface from an instance. + + :param server: The :class:`Server` (or its ID) to detach from. + :param port_id: The port to detach. + """ + self._delete('/servers/%s/os-attach-interfaces/%s' + % (base.getid(server), port_id)) + + def _action(self, action, server, info=None, **kwargs): + """ + Perform a server "action" -- reboot/rebuild/resize/etc. + """ + body = {action: info} + self.run_hooks('modify_body_for_action', body, **kwargs) + url = '/servers/%s/action' % base.getid(server) + return self.api.client.post(url, body=body) diff -Nru python-novaclient-2.15.0/novaclient/v3/services.py python-novaclient-2.16.0/novaclient/v3/services.py --- python-novaclient-2.15.0/novaclient/v3/services.py 1970-01-01 00:00:00.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v3/services.py 2014-02-26 16:28:51.000000000 +0000 @@ -0,0 +1,34 @@ +# Copyright 2013 IBM Corp. +# +# 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. + +""" +service interface +""" +from novaclient.v1_1 import services + + +class Service(services.Service): + pass + + +class ServiceManager(services.ServiceManager): + resource_class = Service + + def _update_body(self, host, binary, disabled_reason=None): + body = {"service": + {"host": host, + "binary": binary}} + if disabled_reason is not None: + body["service"]["disabled_reason"] = disabled_reason + return body diff -Nru python-novaclient-2.15.0/novaclient/v3/shell.py python-novaclient-2.16.0/novaclient/v3/shell.py --- python-novaclient-2.15.0/novaclient/v3/shell.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v3/shell.py 2014-02-26 16:28:51.000000000 +0000 @@ -27,14 +27,15 @@ import sys import time +import six + from novaclient import exceptions from novaclient.openstack.common import strutils from novaclient.openstack.common import timeutils from novaclient.openstack.common import uuidutils from novaclient import utils -from novaclient.v1_1 import availability_zones -from novaclient.v1_1 import quotas -from novaclient.v1_1 import servers +from novaclient.v3 import availability_zones +from novaclient.v3 import servers def _key_value_pairing(text): @@ -73,12 +74,12 @@ "be 0") if args.image: - image = _find_image(cs, args.image) + image = _find_image(cs.image_cs, args.image) else: image = None if not image and args.image_with: - images = _match_image(cs, args.image_with) + images = _match_image(cs.image_cs, args.image_with) if images: # TODO(harlowja): log a warning that we # are selecting the first of many? @@ -172,7 +173,7 @@ # NOTE(vish): multiple copies of the same hint will # result in a list of values if key in hints: - if isinstance(hints[key], basestring): + if isinstance(hints[key], six.string_types): hints[key] = [hints[key]] hints[key] += [value] else: @@ -222,7 +223,7 @@ default=None, type=int, metavar='', - help="boot multi instances at a time (limited by quota).") + help="boot multiple servers at a time (limited by quota).") @utils.arg('--meta', metavar="", action='append', @@ -252,7 +253,7 @@ @utils.arg('--availability-zone', default=None, metavar='', - help="The availability zone for instance placement.") + help="The availability zone for server placement.") @utils.arg('--availability_zone', help=argparse.SUPPRESS) @utils.arg('--security-groups', @@ -297,7 +298,7 @@ dest='poll', action="store_true", default=False, - help='Blocks while instance builds so progress can be reported.') + help='Blocks while server builds so progress can be reported.') def do_boot(cs, args): """Boot a new server.""" boot_args, boot_kwargs = _boot(cs, args) @@ -306,50 +307,10 @@ boot_kwargs.update(extra_boot_kwargs) server = cs.servers.create(*boot_args, **boot_kwargs) - - # Keep any information (like adminPass) returned by create - info = server._info - server = cs.servers.get(info['id']) - info.update(server._info) - - flavor = info.get('flavor', {}) - flavor_id = flavor.get('id', '') - info['flavor'] = _find_flavor(cs, flavor_id).name - - image = info.get('image', {}) - if image: - image_id = image.get('id', '') - info['image'] = _find_image(cs, image_id).name - else: # Booting from volume - info['image'] = "Attempt to boot from volume - no image supplied" - - info.pop('links', None) - info.pop('addresses', None) - - utils.print_dict(info) + _print_server(cs, args, server) if args.poll: - _poll_for_status(cs.servers.get, info['id'], 'building', ['active']) - - -def do_cloudpipe_list(cs, _args): - """Print a list of all cloudpipe instances.""" - cloudpipes = cs.cloudpipe.list() - columns = ['Project Id', "Public IP", "Public Port", "Internal IP"] - utils.print_list(cloudpipes, columns) - - -@utils.arg('project', metavar='', help='Name of the project.') -def do_cloudpipe_create(cs, args): - """Create a cloudpipe instance for the given project.""" - cs.cloudpipe.create(args.project) - - -@utils.arg('address', metavar='', help='New IP Address.') -@utils.arg('port', metavar='', help='New Port.') -def do_cloudpipe_configure(cs, args): - """Update the VPN IP/port of a cloudpipe instance.""" - cs.cloudpipe.update(args.address, args.port) + _poll_for_status(cs.servers.get, server.id, 'building', ['active']) def _poll_for_status(poll_fn, obj_id, action, final_ok_states, @@ -360,10 +321,10 @@ """ def print_progress(progress): if show_progress: - msg = ('\rInstance %(action)s... %(progress)s%% complete' + msg = ('\rServer %(action)s... %(progress)s%% complete' % dict(action=action, progress=progress)) else: - msg = '\rInstance %(action)s...' % dict(action=action) + msg = '\rServer %(action)s...' % dict(action=action) sys.stdout.write(msg) sys.stdout.flush() @@ -387,7 +348,7 @@ break elif status == "error": if not silent: - print("\nError %s instance" % action) + print("\nError %s server" % action) break if not silent: @@ -533,7 +494,7 @@ @utils.arg('--is-public', metavar='', help="Make flavor accessible to the public (default true)", - type=utils.bool_from_str, + type=lambda v: strutils.bool_from_string(v, True), default=True) def do_flavor_create(cs, args): """Create a new flavor""" @@ -600,9 +561,9 @@ @utils.arg('flavor', metavar='', - help="Filter results by flavor name or ID.") + help="Flavor name or ID to add access for the given tenant.") @utils.arg('tenant', metavar='', - help='Filter results by tenant ID.') + help='Tenant ID to add flavor access for.') def do_flavor_access_add(cs, args): """Add flavor access for the given tenant.""" flavor = _find_flavor(cs, args.flavor) @@ -613,9 +574,9 @@ @utils.arg('flavor', metavar='', - help="Filter results by flavor name or ID.") + help="Flavor name or ID to remove access for the given tenant.") @utils.arg('tenant', metavar='', - help='Filter results by tenant ID.') + help='Tenant ID to remove flavor access for.') def do_flavor_access_remove(cs, args): """Remove flavor access for the given tenant.""" flavor = _find_flavor(cs, args.flavor) @@ -793,6 +754,7 @@ dest="limit", metavar="", help='number of images to return per request') +@utils.service_type('image') def do_image_list(cs, _args): """Print a list of available images to boot from.""" limit = _args.limit @@ -851,9 +813,6 @@ def _print_image(image): info = image._info.copy() - # ignore links, we don't need to present those - info.pop('links') - # try to replace a server entity to just an id server = info.pop('server', None) try: @@ -862,10 +821,10 @@ pass # break up metadata and display each on its own row - metadata = info.pop('metadata', {}) + properties = info.pop('properties', {}) try: - for key, value in metadata.items(): - _key = 'metadata %s' % key + for key, value in properties.items(): + _key = 'Property %s' % key info[_key] = value except AttributeError: pass @@ -884,6 +843,7 @@ @utils.arg('image', metavar='', help="Name or ID of image") +@utils.service_type('image') def do_image_show(cs, args): """Show details about the given image.""" image = _find_image(cs, args.image) @@ -905,7 +865,7 @@ dest='reservation_id', metavar='', default=None, - help='Only return instances that match reservation-id.') + help='Only return servers that match reservation-id.') @utils.arg('--reservation_id', help=argparse.SUPPRESS) @utils.arg('--ip', @@ -927,7 +887,7 @@ dest='instance_name', metavar='', default=None, - help='Search with regular expression match by instance name (Admin only).') + help='Search with regular expression match by server name (Admin only).') @utils.arg('--instance_name', help=argparse.SUPPRESS) @utils.arg('--status', @@ -949,7 +909,7 @@ dest='host', metavar='', default=None, - help='Search instances by hostname to which they are assigned ' + help='Search servers by hostname to which they are assigned ' '(Admin only).') @utils.arg('--all-tenants', dest='all_tenants', @@ -957,7 +917,8 @@ nargs='?', type=int, const=1, - default=int(utils.bool_from_str(os.environ.get("ALL_TENANTS", 'false'))), + default=int(strutils.bool_from_string( + os.environ.get("ALL_TENANTS", 'false'), True)), help='Display information from all tenants (Admin only).') @utils.arg('--all_tenants', nargs='?', @@ -975,6 +936,16 @@ metavar='', help='Comma-separated list of fields to display. ' 'Use the show command to see which fields are available.') +@utils.arg('--deleted', + dest='deleted', + action="store_true", + default=False, + help='Only display deleted servers (Admin only).') +@utils.arg('--minimal', + dest='minimal', + action="store_true", + default=False, + help='Get only uuid and name.') def do_list(cs, args): """List active servers.""" imageid = None @@ -994,6 +965,7 @@ 'status': args.status, 'tenant_id': args.tenant, 'host': args.host, + 'deleted': args.deleted, 'instance_name': args.instance_name} filters = {'flavor': lambda f: f['id'], @@ -1010,15 +982,22 @@ id_col = 'ID' - servers = cs.servers.list(search_opts=search_opts) - convert = [('OS-EXT-SRV-ATTR:host', 'host'), - ('OS-EXT-STS:task_state', 'task_state'), - ('OS-EXT-SRV-ATTR:instance_name', 'instance_name'), - ('OS-EXT-STS:power_state', 'power_state'), - ('hostId', 'host_id')] + detailed = not args.minimal + + servers = cs.servers.list(detailed=detailed, + search_opts=search_opts) + convert = [('os-extended-server-attributes:hypervisor_hostname', 'host'), + ('os-extended-status:task_state', 'task_state'), + ('os-extended-server-attributes:instance_name', + 'instance_name'), + ('os-extended-status:power_state', 'power_state')] _translate_keys(servers, convert) _translate_extended_states(servers) - if field_titles: + if args.minimal: + columns = [ + id_col, + 'Name'] + elif field_titles: columns = [id_col] + field_titles else: columns = [ @@ -1045,7 +1024,7 @@ dest='poll', action="store_true", default=False, - help='Blocks while instance is rebooting.') + help='Blocks while server is rebooting.') def do_reboot(cs, args): """Reboot a server.""" server = _find_server(cs, args.server) @@ -1062,19 +1041,19 @@ dest='rebuild_password', metavar='', default=False, - help="Set the provided password on the rebuild instance.") + help="Set the provided password on the rebuild server.") @utils.arg('--rebuild_password', help=argparse.SUPPRESS) @utils.arg('--poll', dest='poll', action="store_true", default=False, - help='Blocks while instance rebuilds so progress can be reported.') + help='Blocks while server rebuilds so progress can be reported.') @utils.arg('--minimal', dest='minimal', action="store_true", default=False, - help='Skips flavor/image lookups when showing instances') + help='Skips flavor/image lookups when showing servers') def do_rebuild(cs, args): """Shutdown, re-image, and re-boot a server.""" server = _find_server(cs, args.server) @@ -1107,7 +1086,7 @@ dest='poll', action="store_true", default=False, - help='Blocks while instance resizes so progress can be reported.') + help='Blocks while server resizes so progress can be reported.') def do_resize(cs, args): """Resize a server.""" server = _find_server(cs, args.server) @@ -1136,7 +1115,7 @@ dest='poll', action="store_true", default=False, - help='Blocks while instance migrates so progress can be reported.') + help='Blocks while server migrates so progress can be reported.') def do_migrate(cs, args): """Migrate a server. The new host will be selected by the scheduler.""" server = _find_server(cs, args.server) @@ -1211,7 +1190,7 @@ def do_diagnostics(cs, args): """Retrieve server diagnostics.""" server = _find_server(cs, args.server) - utils.print_dict(cs.servers.diagnostics(server)[1]) + utils.print_dict(cs.servers.diagnostics(server)[1], wrap=80) @utils.arg('server', metavar='', help='Name or ID of server.') @@ -1229,11 +1208,16 @@ @utils.arg('server', metavar='', help='Name or ID of server.') @utils.arg('name', metavar='', help='Name of snapshot.') +@utils.arg('--show', + dest='show', + action="store_true", + default=False, + help='Print image info.') @utils.arg('--poll', dest='poll', action="store_true", default=False, - help='Blocks while instance snapshots so progress can be reported.') + help='Blocks while server snapshots so progress can be reported.') def do_image_create(cs, args): """Create a new image by taking a snapshot of a running server.""" server = _find_server(cs, args.server) @@ -1258,6 +1242,9 @@ [None], status_field=task_state_field, show_progress=False, silent=True) + if args.show: + _print_image(cs.images.get(image_uuid)) + @utils.arg('server', metavar='', help='Name or ID of server.') @utils.arg('name', metavar='', help='Name of the backup image.') @@ -1266,7 +1253,7 @@ @utils.arg('rotation', metavar='', help='Int parameter representing how many backups to keep around.') def do_backup(cs, args): - """Backup a instance by create a 'backup' type snapshot.""" + """Backup a server by creating a 'backup' type snapshot.""" _find_server(cs, args.server).backup(args.name, args.backup_type, args.rotation) @@ -1296,13 +1283,16 @@ cs.servers.delete_meta(server, metadata.keys()) -def _print_server(cs, args): +def _print_server(cs, args, server=None): # By default when searching via name we will do a # findall(name=blah) and due a REST /details which is not the same # as a .get() and doesn't get the information about flavors and # images. This fix it as we redo the call with the id which does a # .get() to get all informations. - server = _find_server(cs, args.server) + if not server: + server = _find_server(cs, args.server) + + minimal = getattr(args, "minimal", False) networks = server.networks info = server._info.copy() @@ -1311,7 +1301,7 @@ flavor = info.get('flavor', {}) flavor_id = flavor.get('id', '') - if args.minimal: + if minimal: info['flavor'] = flavor_id else: info['flavor'] = '%s (%s)' % (_find_flavor(cs, flavor_id).name, @@ -1320,7 +1310,7 @@ image = info.get('image', {}) if image: image_id = image.get('id', '') - if args.minimal: + if minimal: info['image'] = image_id else: try: @@ -1341,7 +1331,7 @@ dest='minimal', action="store_true", default=False, - help='Skips flavor/image lookups when showing instances') + help='Skips flavor/image lookups when showing servers') @utils.arg('server', metavar='', help='Name or ID of server.') def do_show(cs, args): """Show details about the given server.""" @@ -1402,133 +1392,9 @@ server.remove_fixed_ip(args.address) -def _find_volume(cs, volume): - """Get a volume by name or ID.""" - return utils.find_resource(cs.volumes, volume) - - -def _find_volume_snapshot(cs, snapshot): - """Get a volume snapshot by name or ID.""" - return utils.find_resource(cs.volume_snapshots, snapshot) - - -def _print_volume(volume): - utils.print_dict(volume._info) - - -def _print_volume_snapshot(snapshot): - utils.print_dict(snapshot._info) - - -def _translate_volume_keys(collection): - _translate_keys(collection, - [('displayName', 'display_name'), - ('volumeType', 'volume_type')]) - - -def _translate_volume_snapshot_keys(collection): - _translate_keys(collection, - [('displayName', 'display_name'), - ('volumeId', 'volume_id')]) - - def _translate_availability_zone_keys(collection): _translate_keys(collection, - [('zoneName', 'name'), ('zoneState', 'status')]) - - -@utils.arg('--all-tenants', - dest='all_tenants', - metavar='<0|1>', - nargs='?', - type=int, - const=1, - default=int(utils.bool_from_str(os.environ.get("ALL_TENANTS", 'false'))), - help='Display information from all tenants (Admin only).') -@utils.arg('--all_tenants', - nargs='?', - type=int, - const=1, - help=argparse.SUPPRESS) -@utils.service_type('volume') -def do_volume_list(cs, args): - """List all the volumes.""" - search_opts = {'all_tenants': args.all_tenants} - volumes = cs.volumes.list(search_opts=search_opts) - _translate_volume_keys(volumes) - - # Create a list of servers to which the volume is attached - for vol in volumes: - servers = [s.get('server_id') for s in vol.attachments] - setattr(vol, 'attached_to', ','.join(map(str, servers))) - utils.print_list(volumes, ['ID', 'Status', 'Display Name', - 'Size', 'Volume Type', 'Attached to']) - - -@utils.arg('volume', metavar='', help='Name or ID of the volume.') -@utils.service_type('volume') -def do_volume_show(cs, args): - """Show details about a volume.""" - volume = _find_volume(cs, args.volume) - _print_volume(volume) - - -@utils.arg('size', - metavar='', - type=int, - help='Size of volume in GB') -@utils.arg('--snapshot-id', - metavar='', - default=None, - help='Optional snapshot id to create the volume from. (Default=None)') -@utils.arg('--snapshot_id', - help=argparse.SUPPRESS) -@utils.arg('--image-id', - metavar='', - help='Optional image id to create the volume from. (Default=None)', - default=None) -@utils.arg('--display-name', - metavar='', - default=None, - help='Optional volume name. (Default=None)') -@utils.arg('--display_name', - help=argparse.SUPPRESS) -@utils.arg('--display-description', - metavar='', - default=None, - help='Optional volume description. (Default=None)') -@utils.arg('--display_description', - help=argparse.SUPPRESS) -@utils.arg('--volume-type', - metavar='', - default=None, - help='Optional volume type. (Default=None)') -@utils.arg('--volume_type', - help=argparse.SUPPRESS) -@utils.arg('--availability-zone', metavar='', - help='Optional Availability Zone for volume. (Default=None)', - default=None) -@utils.service_type('volume') -def do_volume_create(cs, args): - """Add a new volume.""" - volume = cs.volumes.create(args.size, - args.snapshot_id, - args.display_name, - args.display_description, - args.volume_type, - args.availability_zone, - imageRef=args.image_id) - _print_volume(volume) - - -@utils.arg('volume', - metavar='', - help='Name or ID of the volume to delete.') -@utils.service_type('volume') -def do_volume_delete(cs, args): - """Remove a volume.""" - volume = _find_volume(cs, args.volume) - volume.delete() + [('zone_name', 'name'), ('zone_state', 'status')]) @utils.arg('server', @@ -1537,7 +1403,7 @@ @utils.arg('volume', metavar='', help='ID of the volume to attach.') -@utils.arg('device', metavar='', +@utils.arg('device', metavar='', default=None, nargs='?', help='Name of the device e.g. /dev/vdb. ' 'Use "auto" for autoassign (if supported)') def do_volume_attach(cs, args): @@ -1545,10 +1411,25 @@ if args.device == 'auto': args.device = None - volume = cs.volumes.create_server_volume(_find_server(cs, args.server).id, + volume = cs.volumes.attach_server_volume(_find_server(cs, args.server).id, args.volume, args.device) - _print_volume(volume) + + +@utils.arg('server', + metavar='', + help='Name or ID of server.') +@utils.arg('attachment_id', + metavar='', + help='Attachment ID of the volume.') +@utils.arg('new_volume', + metavar='', + help='ID of the volume to attach.') +def do_volume_update(cs, args): + """Update volume attachment.""" + volume = cs.volumes.update_server_volume(_find_server(cs, args.server).id, + args.attachment_id, + args.new_volume) @utils.arg('server', @@ -1563,95 +1444,6 @@ args.attachment_id) -@utils.service_type('volume') -def do_volume_snapshot_list(cs, _args): - """List all the snapshots.""" - snapshots = cs.volume_snapshots.list() - _translate_volume_snapshot_keys(snapshots) - utils.print_list(snapshots, ['ID', 'Volume ID', 'Status', 'Display Name', - 'Size']) - - -@utils.arg('snapshot', - metavar='', - help='Name or ID of the snapshot.') -@utils.service_type('volume') -def do_volume_snapshot_show(cs, args): - """Show details about a snapshot.""" - snapshot = _find_volume_snapshot(cs, args.snapshot) - _print_volume_snapshot(snapshot) - - -@utils.arg('volume_id', - metavar='', - help='ID of the volume to snapshot') -@utils.arg('--force', - metavar='', - help='Optional flag to indicate whether to snapshot a volume even if its ' - 'attached to an instance. (Default=False)', - default=False) -@utils.arg('--display-name', - metavar='', - default=None, - help='Optional snapshot name. (Default=None)') -@utils.arg('--display_name', - help=argparse.SUPPRESS) -@utils.arg('--display-description', - metavar='', - default=None, - help='Optional snapshot description. (Default=None)') -@utils.arg('--display_description', - help=argparse.SUPPRESS) -@utils.service_type('volume') -def do_volume_snapshot_create(cs, args): - """Add a new snapshot.""" - snapshot = cs.volume_snapshots.create(args.volume_id, - args.force, - args.display_name, - args.display_description) - _print_volume_snapshot(snapshot) - - -@utils.arg('snapshot', - metavar='', - help='Name or ID of the snapshot to delete.') -@utils.service_type('volume') -def do_volume_snapshot_delete(cs, args): - """Remove a snapshot.""" - snapshot = _find_volume_snapshot(cs, args.snapshot) - snapshot.delete() - - -def _print_volume_type_list(vtypes): - utils.print_list(vtypes, ['ID', 'Name']) - - -@utils.service_type('volume') -def do_volume_type_list(cs, args): - """Print a list of available 'volume types'.""" - vtypes = cs.volume_types.list() - _print_volume_type_list(vtypes) - - -@utils.arg('name', - metavar='', - help="Name of the new flavor") -@utils.service_type('volume') -def do_volume_type_create(cs, args): - """Create a new volume type.""" - vtype = cs.volume_types.create(args.name) - _print_volume_type_list([vtype]) - - -@utils.arg('id', - metavar='', - help="Unique ID of the volume type to delete") -@utils.service_type('volume') -def do_volume_type_delete(cs, args): - """Delete a specific flavor""" - cs.volume_types.delete(args.id) - - @utils.arg('server', metavar='', help='Name or ID of server.') @utils.arg('console_type', metavar='', @@ -1687,9 +1479,31 @@ @utils.arg('server', metavar='', help='Name or ID of server.') +@utils.arg('console_type', + metavar='', + help='Type of rdp console ("rdp-html5").') +def do_get_rdp_console(cs, args): + """Get a rdp console to a server.""" + server = _find_server(cs, args.server) + data = server.get_rdp_console(args.console_type) + + class RDPConsole: + def __init__(self, console_dict): + self.type = console_dict['type'] + self.url = console_dict['url'] + + utils.print_list([RDPConsole(data['console'])], ['Type', 'Url']) + + +@utils.arg('server', metavar='', help='Name or ID of server.') @utils.arg('private_key', metavar='', - help='Private key (used locally to decrypt password).') + help='Private key (used locally to decrypt password) (Optional). ' + 'When specified, the command displays the clear (decrypted) VM ' + 'password. When not specified, the ciphered VM password is ' + 'displayed.', + nargs='?', + default=None) def do_get_password(cs, args): """Get password for a server.""" server = _find_server(cs, args.server) @@ -1705,7 +1519,7 @@ def _print_floating_ip_list(floating_ips): - utils.print_list(floating_ips, ['Ip', 'Instance Id', 'Fixed Ip', 'Pool']) + utils.print_list(floating_ips, ['Ip', 'Server Id', 'Fixed Ip', 'Pool']) @utils.arg('server', metavar='', help='Name or ID of server.') @@ -1871,7 +1685,7 @@ @utils.arg('--availability-zone', metavar='', default=None, - help='Limit access to this domain to instances ' + help='Limit access to this domain to servers ' 'in the specified availability zone.') @utils.arg('--availability_zone', help=argparse.SUPPRESS) @@ -1932,7 +1746,7 @@ 'UTF-8') s.name = s.name.encode(encoding) if secgroup == s.name: - if match_found != False: + if match_found is not False: msg = ("Multiple security group matches found for name" " '%s', use an ID to be more specific." % secgroup) raise exceptions.NoUniqueMatch(msg) @@ -2033,7 +1847,8 @@ nargs='?', type=int, const=1, - default=int(utils.bool_from_str(os.environ.get("ALL_TENANTS", 'false'))), + default=int(strutils.bool_from_string( + os.environ.get("ALL_TENANTS", 'false'), True)), help='Display information from all tenants (Admin only).') @utils.arg('--all_tenants', nargs='?', @@ -2143,7 +1958,7 @@ @utils.arg('--pub_key', help=argparse.SUPPRESS) def do_keypair_add(cs, args): - """Create a new key pair for use with instances.""" + """Create a new key pair for use with servers.""" name = args.name pub_key = args.pub_key @@ -2192,31 +2007,6 @@ _print_keypair(keypair) -@utils.arg('--tenant', - #nova db searches by project_id - dest='tenant', - metavar='', - nargs='?', - help='Display information from single tenant (Admin only).') -@utils.arg('--reserved', - dest='reserved', - action='store_true', - default=False, - help='Include reservations count.') -def do_absolute_limits(cs, args): - """Print a list of absolute limits for a user""" - limits = cs.limits.get(args.reserved, args.tenant).absolute - columns = ['Name', 'Value'] - utils.print_list(limits, columns) - - -def do_rate_limits(cs, args): - """Print a list of rate limits for a user""" - limits = cs.limits.get().rate - columns = ['Verb', 'URI', 'Value', 'Remain', 'Unit', 'Next_Available'] - utils.print_list(limits, columns) - - @utils.arg('--start', metavar='', help='Usage range start date ex 2012-01-20 (default: 4 weeks ago)', default=None) @@ -2226,7 +2016,7 @@ def do_usage_list(cs, args): """List usage data for all tenants.""" dateformat = "%Y-%m-%d" - rows = ["Tenant ID", "Instances", "RAM MB-Hours", "CPU Hours", + rows = ["Tenant ID", "Servers", "RAM MB-Hours", "CPU Hours", "Disk GB-Hours"] now = timeutils.utcnow() @@ -2273,7 +2063,7 @@ def do_usage(cs, args): """Show usage data for a single tenant.""" dateformat = "%Y-%m-%d" - rows = ["Instances", "RAM MB-Hours", "CPU Hours", "Disk GB-Hours"] + rows = ["Servers", "RAM MB-Hours", "CPU Hours", "Disk GB-Hours"] now = timeutils.utcnow() @@ -2471,7 +2261,8 @@ aggregate = _find_aggregate(cs, args.aggregate) metadata = _extract_metadata(args) aggregate = cs.aggregates.set_metadata(aggregate.id, metadata) - print("Aggregate %s has been successfully updated." % aggregate.id) + print("Metadata has been successfully updated for aggregate %s." % + aggregate.id) _print_aggregate_details(aggregate) @@ -2481,7 +2272,8 @@ """Add the host to the specified aggregate.""" aggregate = _find_aggregate(cs, args.aggregate) aggregate = cs.aggregates.add_host(aggregate.id, args.host) - print("Aggregate %s has been successfully updated." % aggregate.id) + print("Host %s has been successfully added for aggregate %s " % + (args.host, aggregate.id)) _print_aggregate_details(aggregate) @@ -2492,7 +2284,8 @@ """Remove the specified host from the specified aggregate.""" aggregate = _find_aggregate(cs, args.aggregate) aggregate = cs.aggregates.remove_host(aggregate.id, args.host) - print("Aggregate %s has been successfully updated." % aggregate.id) + print("Host %s has been successfully removed from aggregate %s " % + (args.host, aggregate.id)) _print_aggregate_details(aggregate) @@ -2505,7 +2298,18 @@ def _print_aggregate_details(aggregate): columns = ['Id', 'Name', 'Availability Zone', 'Hosts', 'Metadata'] - utils.print_list([aggregate], columns) + + def parser_metadata(fields): + return utils.pretty_choice_dict(getattr(fields, 'metadata', {}) or {}) + + def parser_hosts(fields): + return utils.pretty_choice_list(getattr(fields, 'hosts', [])) + + formatters = { + 'Metadata': parser_metadata, + 'Hosts': parser_hosts, + } + utils.print_list([aggregate], columns, formatters=formatters) @utils.arg('server', metavar='', help='Name or ID of server.') @@ -2529,7 +2333,7 @@ action='store_true', help=argparse.SUPPRESS) def do_live_migration(cs, args): - """Migrate running instance to a new machine.""" + """Migrate running server to a new machine.""" _find_server(cs, args.server).live_migrate(args.host, args.block_migrate, args.disk_over_commit) @@ -2538,16 +2342,16 @@ @utils.arg('server', metavar='', help='Name or ID of server.') @utils.arg('--active', action='store_const', dest='state', default='error', const='active', - help='Request the instance be reset to "active" state instead ' + help='Request the server be reset to "active" state instead ' 'of "error" state (the default).') def do_reset_state(cs, args): - """Reset the state of an instance.""" + """Reset the state of a server.""" _find_server(cs, args.server).reset_state(args.state) @utils.arg('server', metavar='', help='Name or ID of server.') def do_reset_network(cs, args): - """Reset network of an instance.""" + """Reset network of a server.""" _find_server(cs, args.server).reset_network() @@ -2659,49 +2463,6 @@ utils.print_list([result], ['HOST', 'power_action']) -@utils.arg('--combine', - dest='combine', - action="store_true", - default=False, - help='Generate a single report for all services.') -def do_coverage_start(cs, args): - """Start Nova coverage reporting.""" - cs.coverage.start(combine=args.combine) - print("Coverage collection started") - - -def do_coverage_stop(cs, args): - """Stop Nova coverage reporting.""" - out = cs.coverage.stop() - print("Coverage data file path: %s" % out[-1]['path']) - - -@utils.arg('filename', metavar='', help='report filename') -@utils.arg('--html', - dest='html', - action="store_true", - default=False, - help='Generate HTML reports instead of text ones.') -@utils.arg('--xml', - dest='xml', - action="store_true", - default=False, - help='Generate XML reports instead of text ones.') -def do_coverage_report(cs, args): - """Generate coverage report.""" - if args.html == True and args.xml == True: - raise exceptions.CommandError("--html and --xml must not be " - "specified together.") - cov = cs.coverage.report(args.filename, xml=args.xml, html=args.html) - print("Report path: %s" % cov[-1]['path']) - - -def do_coverage_reset(cs, args): - """Reset coverage data.""" - cs.coverage.reset() - print("Coverage data reset") - - def _find_hypervisor(cs, hypervisor): """Get a hypervisor by name or ID.""" return utils.find_resource(cs.hypervisors, hypervisor) @@ -2723,28 +2484,33 @@ @utils.arg('hostname', metavar='', help='The hypervisor hostname (or pattern) to search for.') def do_hypervisor_servers(cs, args): - """List instances belonging to specific hypervisors.""" - hypers = cs.hypervisors.search(args.hostname, servers=True) + """List servers belonging to specific hypervisors.""" + # Get a list of hypervisors first + hypers = cs.hypervisors.search(args.hostname) class InstanceOnHyper(object): def __init__(self, **kwargs): self.__dict__.update(kwargs) # Massage the result into a list to be displayed - instances = [] + servers = [] for hyper in hypers: + # Get a list of servers for each hypervisor hyper_host = hyper.hypervisor_hostname hyper_id = hyper.id - if hasattr(hyper, 'servers'): - instances.extend([InstanceOnHyper(id=serv['uuid'], + + hyper_servers = cs.hypervisors.servers(hyper_id) + if hasattr(hyper_servers, 'servers'): + print(hyper_servers.servers) + servers.extend([InstanceOnHyper(id=serv['id'], name=serv['name'], hypervisor_hostname=hyper_host, hypervisor_id=hyper_id) - for serv in hyper.servers]) + for serv in hyper_servers.servers]) # Output the data - utils.print_list(instances, ['ID', 'Name', 'Hypervisor ID', - 'Hypervisor Hostname']) + utils.print_list(servers, ['ID', 'Name', 'Hypervisor ID', + 'Hypervisor Hostname']) @utils.arg('hypervisor', @@ -2821,13 +2587,13 @@ action='store_true', default=False, help='Optional flag to indicate whether to use private address ' - 'attached to an instance. (Default=False)') + 'attached to a server. (Default=False)') @utils.arg('--ipv6', dest='ipv6', action='store_true', default=False, help='Optional flag to indicate whether to use an IPv6 address ' - 'attached to an instance. (Defaults to IPv4 address)') + 'attached to a server. (Defaults to IPv4 address)') @utils.arg('--login', metavar='', help='Login to use.', default="root") @utils.arg('-i', '--identity', dest='identity', @@ -2839,6 +2605,11 @@ default='') def do_ssh(cs, args): """SSH into a server.""" + if '@' in args.server: + user, server = args.server.split('@', 1) + args.login = user + args.server = server + addresses = _find_server(cs, args.server).addresses address_type = "private" if args.private else "public" version = 6 if args.ipv6 else 4 @@ -2867,11 +2638,8 @@ return -_quota_resources = ['instances', 'cores', 'ram', 'volumes', 'gigabytes', - 'floating_ips', 'fixed_ips', 'metadata_items', - 'injected_files', 'key_pairs', - 'injected_file_content_bytes', 'injected_file_path_bytes', - 'security_groups', 'security_group_rules'] +_quota_resources = ['instances', 'cores', 'ram', + 'fixed_ips', 'metadata_items', 'key_pairs'] def _quota_show(quotas): @@ -2884,6 +2652,23 @@ utils.print_dict(quota_dict) +def _quota_usage(quotas): + class QuotaObj(object): + def __init__(self, resource, quota_dict): + setattr(self, 'resource', resource) + for (k, v) in six.iteritems(quota_dict): + setattr(self, k, v) + + quota_list = [] + for resource in _quota_resources: + try: + quota_list.append(QuotaObj(resource, getattr(quotas, resource))) + except AttributeError: + pass + utils.print_list(quota_list, ['resource', 'in use', 'limit'], + sortby_index=0) + + def _quota_update(manager, identifier, args): updates = {} for resource in _quota_resources: @@ -2894,11 +2679,7 @@ if updates: # default value of force is None to make sure this client # will be compatibile with old nova server - force_update = getattr(args, 'force', None) - if isinstance(manager, quotas.QuotaSetManager): - manager.update(identifier, force=force_update, **updates) - else: - manager.update(identifier, **updates) + manager.update(identifier, **updates) @utils.arg('--tenant', @@ -2917,6 +2698,21 @@ @utils.arg('--tenant', metavar='', default=None, + help='ID of tenant to list the quotas for.') +@utils.arg('--user', + metavar='', + default=None, + help='ID of user to list the quotas for.') +def do_quota_usage(cs, args): + """List the quotas for a tenant.""" + + tenant = args.tenant or cs.client.tenant_id + _quota_usage(cs.quotas.get(tenant, user_id=args.user, detail=True)) + + +@utils.arg('--tenant', + metavar='', + default=None, help='ID of tenant to list the default quotas for.') def do_quota_defaults(cs, args): """List the default quotas for a tenant.""" @@ -2942,22 +2738,6 @@ metavar='', type=int, default=None, help='New value for the "ram" quota.') -@utils.arg('--volumes', - metavar='', - type=int, default=None, - help='New value for the "volumes" quota.') -@utils.arg('--gigabytes', - metavar='', - type=int, default=None, - help='New value for the "gigabytes" quota.') -@utils.arg('--floating-ips', - metavar='', - type=int, - default=None, - help='New value for the "floating-ips" quota.') -@utils.arg('--floating_ips', - type=int, - help=argparse.SUPPRESS) @utils.arg('--fixed-ips', metavar='', type=int, @@ -2971,42 +2751,11 @@ @utils.arg('--metadata_items', type=int, help=argparse.SUPPRESS) -@utils.arg('--injected-files', - metavar='', - type=int, - default=None, - help='New value for the "injected-files" quota.') -@utils.arg('--injected_files', - type=int, - help=argparse.SUPPRESS) -@utils.arg('--injected-file-content-bytes', - metavar='', - type=int, - default=None, - help='New value for the "injected-file-content-bytes" quota.') -@utils.arg('--injected_file_content_bytes', - type=int, - help=argparse.SUPPRESS) -@utils.arg('--injected-file-path-bytes', - metavar='', - type=int, - default=None, - help='New value for the "injected-file-path-bytes" quota.') @utils.arg('--key-pairs', metavar='', type=int, default=None, help='New value for the "key-pairs" quota.') -@utils.arg('--security-groups', - metavar='', - type=int, - default=None, - help='New value for the "security-groups" quota.') -@utils.arg('--security-group-rules', - metavar='', - type=int, - default=None, - help='New value for the "security-group-rules" quota.') @utils.arg('--force', dest='force', action="store_true", @@ -3052,22 +2801,6 @@ metavar='', type=int, default=None, help='New value for the "ram" quota.') -@utils.arg('--volumes', - metavar='', - type=int, default=None, - help='New value for the "volumes" quota.') -@utils.arg('--gigabytes', - metavar='', - type=int, default=None, - help='New value for the "gigabytes" quota.') -@utils.arg('--floating-ips', - metavar='', - type=int, - default=None, - help='New value for the "floating-ips" quota.') -@utils.arg('--floating_ips', - type=int, - help=argparse.SUPPRESS) @utils.arg('--metadata-items', metavar='', type=int, @@ -3076,42 +2809,11 @@ @utils.arg('--metadata_items', type=int, help=argparse.SUPPRESS) -@utils.arg('--injected-files', - metavar='', - type=int, - default=None, - help='New value for the "injected-files" quota.') -@utils.arg('--injected_files', - type=int, - help=argparse.SUPPRESS) -@utils.arg('--injected-file-content-bytes', - metavar='', - type=int, - default=None, - help='New value for the "injected-file-content-bytes" quota.') -@utils.arg('--injected_file_content_bytes', - type=int, - help=argparse.SUPPRESS) -@utils.arg('--injected-file-path-bytes', - metavar='', - type=int, - default=None, - help='New value for the "injected-file-path-bytes" quota.') @utils.arg('--key-pairs', metavar='', type=int, default=None, help='New value for the "key-pairs" quota.') -@utils.arg('--security-groups', - metavar='', - type=int, - default=None, - help='New value for the "security-groups" quota.') -@utils.arg('--security-group-rules', - metavar='', - type=int, - default=None, - help='New value for the "security-group-rules" quota.') def do_quota_class_update(cs, args): """Update the quotas for a quota class.""" @@ -3124,13 +2826,13 @@ dest='password', metavar='', default=None, - help="Set the provided password on the evacuated instance. Not applicable " + help="Set the provided password on the evacuated server. Not applicable " "with on-shared-storage flag") @utils.arg('--on-shared-storage', dest='on_shared_storage', action="store_true", default=False, - help='Specifies whether instance files located on shared storage') + help='Specifies whether server files are located on shared storage') def do_evacuate(cs, args): """Evacuate server from failed host to specified one.""" server = _find_server(cs, args.server) @@ -3157,7 +2859,7 @@ @utils.arg('server', metavar='', help='Name or ID of server.') def do_interface_list(cs, args): - """List interfaces attached to an instance.""" + """List interfaces attached to a server.""" server = _find_server(cs, args.server) res = server.interface_list() @@ -3172,7 +2874,7 @@ @utils.arg('--fixed-ip', metavar='', help='Requested fixed IP.', default=None, dest="fixed_ip") def do_interface_attach(cs, args): - """Attach a network interface to an instance.""" + """Attach a network interface to a server.""" server = _find_server(cs, args.server) res = server.interface_attach(args.port_id, args.net_id, args.fixed_ip) @@ -3183,7 +2885,7 @@ @utils.arg('server', metavar='', help='Name or ID of server.') @utils.arg('port_id', metavar='', help='Port ID.') def do_interface_detach(cs, args): - """Detach a network interface from an instance.""" + """Detach a network interface from a server.""" server = _find_server(cs, args.server) res = server.interface_detach(args.port_id) @@ -3200,40 +2902,40 @@ result = [] # Zone tree view item - az.zoneName = zone.zoneName - az.zoneState = ('available' - if zone.zoneState['available'] else 'not available') - az._info['zoneName'] = az.zoneName - az._info['zoneState'] = az.zoneState + az.zone_name = zone.zone_name + az.zone_state = ('available' + if zone.zone_state['available'] else 'not available') + az._info['zone_name'] = az.zone_name + az._info['zone_state'] = az.zone_state result.append(az) if zone.hosts is not None: - for (host, services) in zone.hosts.items(): + zone_hosts = sorted(zone.hosts.items(), key=lambda x: x[0]) + for (host, services) in zone_hosts: # Host tree view item az = AvailabilityZone(zone.manager, copy.deepcopy(zone._info), zone._loaded) - az.zoneName = '|- %s' % host - az.zoneState = '' - az._info['zoneName'] = az.zoneName - az._info['zoneState'] = az.zoneState + az.zone_name = '|- %s' % host + az.zone_state = '' + az._info['zone_name'] = az.zone_name + az._info['zone_state'] = az.zone_state result.append(az) for (svc, state) in services.items(): # Service tree view item az = AvailabilityZone(zone.manager, copy.deepcopy(zone._info), zone._loaded) - az.zoneName = '| |- %s' % svc - az.zoneState = '%s %s %s' % ( + az.zone_name = '| |- %s' % svc + az.zone_state = '%s %s %s' % ( 'enabled' if state['active'] else 'disabled', ':-)' if state['available'] else 'XXX', state['updated_at']) - az._info['zoneName'] = az.zoneName - az._info['zoneState'] = az.zoneState + az._info['zone_name'] = az.zone_name + az._info['zone_state'] = az.zone_state result.append(az) return result -@utils.service_type('compute') def do_availability_zone_list(cs, _args): """List all the availability zones.""" try: diff -Nru python-novaclient-2.15.0/novaclient/v3/usage.py python-novaclient-2.16.0/novaclient/v3/usage.py --- python-novaclient-2.15.0/novaclient/v3/usage.py 1970-01-01 00:00:00.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v3/usage.py 2014-02-26 16:28:51.000000000 +0000 @@ -0,0 +1,27 @@ +# Copyright 2013 IBM Corp. +# +# 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. + +""" +Usage interface. +""" + +from novaclient.v1_1 import usage + + +class Usage(usage.Usage): + pass + + +class UsageManager(usage.UsageManager): + pass diff -Nru python-novaclient-2.15.0/novaclient/v3/volumes.py python-novaclient-2.16.0/novaclient/v3/volumes.py --- python-novaclient-2.15.0/novaclient/v3/volumes.py 1970-01-01 00:00:00.000000000 +0000 +++ python-novaclient-2.16.0/novaclient/v3/volumes.py 2014-02-26 16:28:51.000000000 +0000 @@ -0,0 +1,68 @@ +# Copyright 2013 IBM Corp. +# +# 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. + +""" +Volume interface +""" + +from novaclient import base + + +class VolumeManager(base.Manager): + """ + Manage :class:`Volume` resources. + """ + + def attach_server_volume(self, server, volume_id, device): + """ + Attach a volume identified by the volume ID to the given server ID + + :param server: The server (or it's ID) + :param volume_id: The ID of the volume to attach. + :param device: The device name + :rtype: :class:`Volume` + """ + body = {'volume_id': volume_id, 'device': device} + return self._action('attach', server, body) + + def update_server_volume(self, server, old_volume_id, new_volume_id): + """ + Update the volume identified by the attachment ID, that is attached to + the given server ID + + :param server_id: The server (or it's ID) + :param old_volume_id: The ID of the attachment + :param new_volume_id: The ID of the new volume to attach + :rtype: :class:`Volume` + """ + body = {'new_volume_id': new_volume_id, 'old_volume_id': old_volume_id} + return self._action('swap_volume_attachment', server, body) + + def delete_server_volume(self, server, volume_id): + """ + Detach a volume identified by the attachment ID from the given server + + :param server_id: The ID of the server + :param volume_id: The ID of the attachment + """ + return self._action('detach', server, {'volume_id': volume_id}) + + def _action(self, action, server, info=None, **kwargs): + """ + Perform a server "action" -- reboot/rebuild/resize/etc. + """ + body = {action: info} + self.run_hooks('modify_body_for_action', body, **kwargs) + url = '/servers/%s/action' % base.getid(server) + return self.api.client.post(url, body=body) diff -Nru python-novaclient-2.15.0/openstack-common.conf python-novaclient-2.16.0/openstack-common.conf --- python-novaclient-2.15.0/openstack-common.conf 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/openstack-common.conf 2014-02-26 16:28:51.000000000 +0000 @@ -2,10 +2,14 @@ # The list of modules to copy from openstack-common module=install_venv_common +module=jsonutils module=strutils module=timeutils module=uuidutils module=py3kcompat +module=apiclient +module=importutils +module=cliutils # The base module to hold the copy of openstack.common base=novaclient diff -Nru python-novaclient-2.15.0/PKG-INFO python-novaclient-2.16.0/PKG-INFO --- python-novaclient-2.15.0/PKG-INFO 2013-09-18 12:39:10.000000000 +0000 +++ python-novaclient-2.16.0/PKG-INFO 2014-02-26 16:29:29.000000000 +0000 @@ -1,8 +1,8 @@ Metadata-Version: 1.1 Name: python-novaclient -Version: 2.15.0 +Version: 2.16.0 Summary: Client library for OpenStack Compute API -Home-page: https://github.com/openstack/python-novaclient +Home-page: https://git.openstack.org/cgit/openstack/python-novaclient Author: OpenStack Author-email: openstack-dev@lists.openstack.org License: Apache License, Version 2.0 @@ -50,13 +50,13 @@ export OS_TENANT_NAME=myproject You will also need to define the authentication url with ``--os-auth-url`` - and the version of the API with ``--version``. Or set them as an environment - variables as well:: + and the version of the API with ``--os-compute-api-version``. Or set them as + an environment variables as well:: export OS_AUTH_URL=http://example.com:8774/v1.1/ export OS_COMPUTE_API_VERSION=1.1 - If you are using Keystone, you need to set the NOVA_URL to the keystone + If you are using Keystone, you need to set the OS_AUTH_URL to the keystone endpoint:: export OS_AUTH_URL=http://example.com:5000/v2.0/ diff -Nru python-novaclient-2.15.0/python_novaclient.egg-info/PKG-INFO python-novaclient-2.16.0/python_novaclient.egg-info/PKG-INFO --- python-novaclient-2.15.0/python_novaclient.egg-info/PKG-INFO 2013-09-18 12:39:10.000000000 +0000 +++ python-novaclient-2.16.0/python_novaclient.egg-info/PKG-INFO 2014-02-26 16:29:29.000000000 +0000 @@ -1,8 +1,8 @@ Metadata-Version: 1.1 Name: python-novaclient -Version: 2.15.0 +Version: 2.16.0 Summary: Client library for OpenStack Compute API -Home-page: https://github.com/openstack/python-novaclient +Home-page: https://git.openstack.org/cgit/openstack/python-novaclient Author: OpenStack Author-email: openstack-dev@lists.openstack.org License: Apache License, Version 2.0 @@ -50,13 +50,13 @@ export OS_TENANT_NAME=myproject You will also need to define the authentication url with ``--os-auth-url`` - and the version of the API with ``--version``. Or set them as an environment - variables as well:: + and the version of the API with ``--os-compute-api-version``. Or set them as + an environment variables as well:: export OS_AUTH_URL=http://example.com:8774/v1.1/ export OS_COMPUTE_API_VERSION=1.1 - If you are using Keystone, you need to set the NOVA_URL to the keystone + If you are using Keystone, you need to set the OS_AUTH_URL to the keystone endpoint:: export OS_AUTH_URL=http://example.com:5000/v2.0/ diff -Nru python-novaclient-2.15.0/python_novaclient.egg-info/requires.txt python-novaclient-2.16.0/python_novaclient.egg-info/requires.txt --- python-novaclient-2.15.0/python_novaclient.egg-info/requires.txt 2013-09-18 12:39:10.000000000 +0000 +++ python-novaclient-2.16.0/python_novaclient.egg-info/requires.txt 2014-02-26 16:29:29.000000000 +0000 @@ -1,7 +1,7 @@ -pbr>=0.5.21,<1.0 -iso8601>=0.1.4 -PrettyTable>=0.6,<0.8 +pbr>=0.6,<1.0 +iso8601>=0.1.8 +PrettyTable>=0.7,<0.8 requests>=1.1 simplejson>=2.0.9 -six -Babel>=0.9.6 \ No newline at end of file +six>=1.4.1 +Babel>=1.3 \ No newline at end of file diff -Nru python-novaclient-2.15.0/python_novaclient.egg-info/SOURCES.txt python-novaclient-2.16.0/python_novaclient.egg-info/SOURCES.txt --- python-novaclient-2.15.0/python_novaclient.egg-info/SOURCES.txt 2013-09-18 12:39:10.000000000 +0000 +++ python-novaclient-2.16.0/python_novaclient.egg-info/SOURCES.txt 2014-02-26 16:29:29.000000000 +0000 @@ -20,16 +20,8 @@ doc/source/api.rst doc/source/conf.py doc/source/index.rst -doc/source/releases.rst doc/source/shell.rst doc/source/man/nova.rst -doc/source/ref/backup_schedules.rst -doc/source/ref/exceptions.rst -doc/source/ref/flavors.rst -doc/source/ref/images.rst -doc/source/ref/index.rst -doc/source/ref/ipgroups.rst -doc/source/ref/servers.rst novaclient/__init__.py novaclient/auth_plugin.py novaclient/base.py @@ -42,14 +34,24 @@ novaclient/utils.py novaclient/openstack/__init__.py novaclient/openstack/common/__init__.py +novaclient/openstack/common/cliutils.py novaclient/openstack/common/gettextutils.py +novaclient/openstack/common/importutils.py +novaclient/openstack/common/jsonutils.py novaclient/openstack/common/strutils.py novaclient/openstack/common/timeutils.py novaclient/openstack/common/uuidutils.py +novaclient/openstack/common/apiclient/__init__.py +novaclient/openstack/common/apiclient/auth.py +novaclient/openstack/common/apiclient/base.py +novaclient/openstack/common/apiclient/client.py +novaclient/openstack/common/apiclient/exceptions.py +novaclient/openstack/common/apiclient/fake_client.py novaclient/openstack/common/py3kcompat/__init__.py novaclient/openstack/common/py3kcompat/urlutils.py novaclient/tests/__init__.py novaclient/tests/fakes.py +novaclient/tests/idfake.pem novaclient/tests/test_auth_plugins.py novaclient/tests/test_base.py novaclient/tests/test_client.py @@ -67,7 +69,6 @@ novaclient/tests/v1_1/test_availability_zone.py novaclient/tests/v1_1/test_certs.py novaclient/tests/v1_1/test_cloudpipe.py -novaclient/tests/v1_1/test_coverage_ext.py novaclient/tests/v1_1/test_fixed_ips.py novaclient/tests/v1_1/test_flavor_access.py novaclient/tests/v1_1/test_flavors.py @@ -102,6 +103,25 @@ novaclient/tests/v1_1/contrib/test_list_extensions.py novaclient/tests/v1_1/contrib/test_migrations.py novaclient/tests/v1_1/contrib/test_tenant_networks.py +novaclient/tests/v3/__init__.py +novaclient/tests/v3/fakes.py +novaclient/tests/v3/test_agents.py +novaclient/tests/v3/test_aggregates.py +novaclient/tests/v3/test_availability_zone.py +novaclient/tests/v3/test_certs.py +novaclient/tests/v3/test_flavor_access.py +novaclient/tests/v3/test_flavors.py +novaclient/tests/v3/test_hosts.py +novaclient/tests/v3/test_hypervisors.py +novaclient/tests/v3/test_images.py +novaclient/tests/v3/test_keypairs.py +novaclient/tests/v3/test_quota_classes.py +novaclient/tests/v3/test_quotas.py +novaclient/tests/v3/test_servers.py +novaclient/tests/v3/test_services.py +novaclient/tests/v3/test_shell.py +novaclient/tests/v3/test_usage.py +novaclient/tests/v3/test_volumes.py novaclient/v1_1/__init__.py novaclient/v1_1/agents.py novaclient/v1_1/aggregates.py @@ -109,7 +129,6 @@ novaclient/v1_1/certs.py novaclient/v1_1/client.py novaclient/v1_1/cloudpipe.py -novaclient/v1_1/coverage_ext.py novaclient/v1_1/fixed_ips.py novaclient/v1_1/flavor_access.py novaclient/v1_1/flavors.py @@ -149,8 +168,24 @@ novaclient/v1_1/contrib/migrations.py novaclient/v1_1/contrib/tenant_networks.py novaclient/v3/__init__.py +novaclient/v3/agents.py +novaclient/v3/aggregates.py +novaclient/v3/availability_zones.py +novaclient/v3/certs.py novaclient/v3/client.py +novaclient/v3/flavor_access.py +novaclient/v3/flavors.py +novaclient/v3/hosts.py +novaclient/v3/hypervisors.py +novaclient/v3/images.py +novaclient/v3/keypairs.py +novaclient/v3/quota_classes.py +novaclient/v3/quotas.py +novaclient/v3/servers.py +novaclient/v3/services.py novaclient/v3/shell.py +novaclient/v3/usage.py +novaclient/v3/volumes.py python_novaclient.egg-info/PKG-INFO python_novaclient.egg-info/SOURCES.txt python_novaclient.egg-info/dependency_links.txt diff -Nru python-novaclient-2.15.0/README.rst python-novaclient-2.16.0/README.rst --- python-novaclient-2.15.0/README.rst 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/README.rst 2014-02-26 16:28:51.000000000 +0000 @@ -42,13 +42,13 @@ export OS_TENANT_NAME=myproject You will also need to define the authentication url with ``--os-auth-url`` -and the version of the API with ``--version``. Or set them as an environment -variables as well:: +and the version of the API with ``--os-compute-api-version``. Or set them as +an environment variables as well:: export OS_AUTH_URL=http://example.com:8774/v1.1/ export OS_COMPUTE_API_VERSION=1.1 -If you are using Keystone, you need to set the NOVA_URL to the keystone +If you are using Keystone, you need to set the OS_AUTH_URL to the keystone endpoint:: export OS_AUTH_URL=http://example.com:5000/v2.0/ diff -Nru python-novaclient-2.15.0/requirements.txt python-novaclient-2.16.0/requirements.txt --- python-novaclient-2.15.0/requirements.txt 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/requirements.txt 2014-02-26 16:28:52.000000000 +0000 @@ -1,8 +1,8 @@ -pbr>=0.5.21,<1.0 +pbr>=0.6,<1.0 argparse -iso8601>=0.1.4 -PrettyTable>=0.6,<0.8 +iso8601>=0.1.8 +PrettyTable>=0.7,<0.8 requests>=1.1 simplejson>=2.0.9 -six -Babel>=0.9.6 +six>=1.4.1 +Babel>=1.3 diff -Nru python-novaclient-2.15.0/setup.cfg python-novaclient-2.16.0/setup.cfg --- python-novaclient-2.15.0/setup.cfg 2013-09-18 12:39:10.000000000 +0000 +++ python-novaclient-2.16.0/setup.cfg 2014-02-26 16:29:29.000000000 +0000 @@ -6,7 +6,7 @@ license = Apache License, Version 2.0 author = OpenStack author-email = openstack-dev@lists.openstack.org -home-page = https://github.com/openstack/python-novaclient +home-page = https://git.openstack.org/cgit/openstack/python-novaclient classifier = Development Status :: 5 - Production/Stable Environment :: Console @@ -21,10 +21,6 @@ packages = novaclient -[global] -setup-hooks = - pbr.hooks.setup_hook - [entry_points] console_scripts = nova = novaclient.shell:main diff -Nru python-novaclient-2.15.0/setup.py python-novaclient-2.16.0/setup.py --- python-novaclient-2.15.0/setup.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/setup.py 2014-02-26 16:28:51.000000000 +0000 @@ -18,5 +18,5 @@ import setuptools setuptools.setup( - setup_requires=['pbr>=0.5.21,<1.0'], + setup_requires=['pbr'], pbr=True) diff -Nru python-novaclient-2.15.0/test-requirements.txt python-novaclient-2.16.0/test-requirements.txt --- python-novaclient-2.15.0/test-requirements.txt 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/test-requirements.txt 2014-02-26 16:28:52.000000000 +0000 @@ -1,10 +1,10 @@ -hacking>=0.5.6,<0.8 +hacking>=0.8.0,<0.9 coverage>=3.6 discover -fixtures>=0.3.12 -keyring>=1.6.1 -mock>=0.8.0 -sphinx>=1.1.2 -testrepository>=0.0.17 -testtools>=0.9.32 +fixtures>=0.3.14 +keyring>=1.6.1,<2.0,>=2.1 +mock>=1.0 +sphinx>=1.1.2,<1.2 +testrepository>=0.0.18 +testtools>=0.9.34 diff -Nru python-novaclient-2.15.0/tools/install_venv_common.py python-novaclient-2.16.0/tools/install_venv_common.py --- python-novaclient-2.15.0/tools/install_venv_common.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/tools/install_venv_common.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,5 +1,3 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - # Copyright 2013 OpenStack Foundation # Copyright 2013 IBM Corp. # @@ -119,11 +117,7 @@ self.pip_install('setuptools') self.pip_install('pbr') - self.pip_install('-r', self.requirements) - self.pip_install('-r', self.test_requirements) - - def post_process(self): - self.get_distro().post_process() + self.pip_install('-r', self.requirements, '-r', self.test_requirements) def parse_args(self, argv): """Parses command-line arguments.""" @@ -157,14 +151,6 @@ ' requires virtualenv, please install it using your' ' favorite package management tool' % self.project) - def post_process(self): - """Any distribution-specific post-processing gets done here. - - In particular, this is useful for applying patches to code inside - the venv. - """ - pass - class Fedora(Distro): """This covers all Fedora-based distributions. @@ -176,10 +162,6 @@ return self.run_command_with_code(['rpm', '-q', pkg], check_exit_code=False)[1] == 0 - def apply_patch(self, originalfile, patchfile): - self.run_command(['patch', '-N', originalfile, patchfile], - check_exit_code=False) - def install_virtualenv(self): if self.check_cmd('virtualenv'): return @@ -188,27 +170,3 @@ self.die("Please install 'python-virtualenv'.") super(Fedora, self).install_virtualenv() - - def post_process(self): - """Workaround for a bug in eventlet. - - This currently affects RHEL6.1, but the fix can safely be - applied to all RHEL and Fedora distributions. - - This can be removed when the fix is applied upstream. - - Nova: https://bugs.launchpad.net/nova/+bug/884915 - Upstream: https://bitbucket.org/eventlet/eventlet/issue/89 - RHEL: https://bugzilla.redhat.com/958868 - """ - - if os.path.exists('contrib/redhat-eventlet.patch'): - # Install "patch" program if it's not there - if not self.check_pkg('patch'): - self.die("Please install 'patch'.") - - # Apply the eventlet patch - self.apply_patch(os.path.join(self.venv, 'lib', self.py_version, - 'site-packages', - 'eventlet/green/subprocess.py'), - 'contrib/redhat-eventlet.patch') diff -Nru python-novaclient-2.15.0/tools/install_venv.py python-novaclient-2.16.0/tools/install_venv.py --- python-novaclient-2.15.0/tools/install_venv.py 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/tools/install_venv.py 2014-02-26 16:28:51.000000000 +0000 @@ -1,5 +1,3 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - # Copyright 2010 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. @@ -70,7 +68,6 @@ install.check_dependencies() install.create_virtualenv(no_site_packages=options.no_site_packages) install.install_dependencies() - install.post_process() print_help(project, venv, root) if __name__ == '__main__': diff -Nru python-novaclient-2.15.0/tools/nova.bash_completion python-novaclient-2.16.0/tools/nova.bash_completion --- python-novaclient-2.15.0/tools/nova.bash_completion 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/tools/nova.bash_completion 2014-02-26 16:28:51.000000000 +0000 @@ -9,10 +9,10 @@ prev="${COMP_WORDS[COMP_CWORD-1]}" if [ "x$_nova_opts" == "x" ] ; then - nbc="`nova bash-completion | sed -e "s/[ ]+/ /"`" - _nova_opts="`echo "$nbc" | sed -e "s/--[a-z0-9_-]*//g" -e "s/[ ]+/ /g"`" - _nova_flags="`echo " $nbc" | sed -e "s/ [^-][^-][a-z0-9_-]*//g" -e "s/[ ]+/ /g"`" - _nova_opts_exp="`echo "$_nova_opts" | sed -e "s/[ ]/|/g"`" + nbc="`nova bash-completion | sed -e "s/ *-h */ /" -e "s/ *-i */ /"`" + _nova_opts="`echo "$nbc" | sed -e "s/--[a-z0-9_-]*//g" -e "s/ */ /g"`" + _nova_flags="`echo " $nbc" | sed -e "s/ [^-][^-][a-z0-9_-]*//g" -e "s/ */ /g"`" + _nova_opts_exp="`echo "$_nova_opts" | tr ' ' '|'`" fi if [[ " ${COMP_WORDS[@]} " =~ " "($_nova_opts_exp)" " && "$prev" != "help" ]] ; then diff -Nru python-novaclient-2.15.0/tox.ini python-novaclient-2.16.0/tox.ini --- python-novaclient-2.15.0/tox.ini 2013-09-18 12:38:39.000000000 +0000 +++ python-novaclient-2.16.0/tox.ini 2014-02-26 16:28:51.000000000 +0000 @@ -1,11 +1,12 @@ [tox] envlist = py26,py27,py33,pypy,pep8 +minversion = 1.6 +skipsdist = True [testenv] +usedevelop = True +install_command = pip install -U {opts} {packages} setenv = VIRTUAL_ENV={envdir} - LANG=en_US.UTF-8 - LANGUAGE=en_US:en - LC_ALL=C deps = -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt @@ -24,6 +25,6 @@ downloadcache = ~/cache/pip [flake8] -ignore = E12,E711,E721,E712,F841,F811,F821,H102,H302,H306,H403,H404 +ignore = E12,F841,F811,F821,H302,H404 show-source = True -exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build +exclude=.venv,.git,.tox,dist,*openstack/common*,*lib/python*,*egg,build