Merge lp:~zulcss/ubuntu/precise/python-novaclient/new into lp:~ubuntu-cloud-archive/ubuntu/precise/python-novaclient/trunk

Proposed by Chuck Short
Status: Merged
Merged at revision: 29
Proposed branch: lp:~zulcss/ubuntu/precise/python-novaclient/new
Merge into: lp:~ubuntu-cloud-archive/ubuntu/precise/python-novaclient/trunk
Diff against target: 3937 lines (+2230/-210)
40 files modified
.mailmap (+2/-1)
AUTHORS (+18/-1)
ChangeLog (+898/-66)
PKG-INFO (+2/-1)
debian/changelog (+12/-0)
novaclient/client.py (+3/-1)
novaclient/openstack/common/setup.py (+57/-38)
novaclient/openstack/common/timeutils.py (+16/-5)
novaclient/shell.py (+11/-2)
novaclient/utils.py (+14/-5)
novaclient/v1_1/base.py (+3/-1)
novaclient/v1_1/client.py (+7/-0)
novaclient/v1_1/cloudpipe.py (+14/-0)
novaclient/v1_1/contrib/list_extensions.py (+46/-0)
novaclient/v1_1/fixed_ips.py (+58/-0)
novaclient/v1_1/flavors.py (+52/-11)
novaclient/v1_1/fping.py (+66/-0)
novaclient/v1_1/hosts.py (+5/-2)
novaclient/v1_1/servers.py (+27/-1)
novaclient/v1_1/services.py (+62/-0)
novaclient/v1_1/shell.py (+171/-52)
novaclient/v1_1/volumes.py (+11/-3)
novaclient/versioninfo (+1/-1)
python_novaclient.egg-info/PKG-INFO (+2/-1)
python_novaclient.egg-info/SOURCES.txt (+10/-0)
setup.py (+1/-0)
tests/test_auth_plugins.py (+23/-0)
tests/test_discover.py (+79/-0)
tests/test_shell.py (+6/-12)
tests/test_utils.py (+9/-0)
tests/v1_1/contrib/test_list_extensions.py (+21/-0)
tests/v1_1/fakes.py (+177/-1)
tests/v1_1/test_cloudpipe.py (+6/-0)
tests/v1_1/test_fixed_ips.py (+43/-0)
tests/v1_1/test_flavors.py (+25/-2)
tests/v1_1/test_fping.py (+41/-0)
tests/v1_1/test_hosts.py (+12/-0)
tests/v1_1/test_servers.py (+42/-1)
tests/v1_1/test_services.py (+68/-0)
tests/v1_1/test_shell.py (+109/-2)
To merge this branch: bzr merge lp:~zulcss/ubuntu/precise/python-novaclient/new
Reviewer Review Type Date Requested Status
James Page Approve
Review via email: mp+137201@code.launchpad.net

Description of the change

new release

To post a comment you must log in.
Revision history for this message
James Page (james-page) wrote :

Minor nit:

+python-novaclient (1:2.9.0-0ubuntu1~cloud0) precise-folsom; urgency=low
+
+ * New upstream snapshot for the Ubuntu Cloud Archive.
+
+ -- Chuck Short <email address hidden> Fri, 28 Sep 2012 11:57:15 -0500
+

Its not a snapshot - its a new release.

Other than that LGTM.

review: Approve
Revision history for this message
James Page (james-page) wrote :

Ignore that - I reviewed the existing branch.

Revision history for this message
James Page (james-page) wrote :

OK - reviewed the correct one this time - precise-grizzly target looks just fine.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.mailmap'
2--- .mailmap 2012-08-16 12:41:00 +0000
3+++ .mailmap 2012-11-30 14:02:33 +0000
4@@ -6,7 +6,8 @@
5 <dprince@redhat.com> <dan.prince@rackspace.com>
6 Johannes Erdfelt <johannes.erdfelt@rackspace.com> jerdfelt <johannes@erdfelt.com>
7 <johannes.erdfelt@rackspace.com> <johannes@erdfelt.com>
8-<josh@jk0.org> <jkearney@nova.(none)>
9+<josh.kearney@pistoncloud.com> <josh@jk0.org>
10+<josh.kearney@pistoncloud.com> <jkearney@nova.(none)>
11 <sandy@darksecretsoftware.com> <sandy.walsh@rackspace.com>
12 <sandy@darksecretsoftware.com> <sandy@sandywalsh.com>
13 Andy Smith <github@anarkystic.com> termie <github@anarkystic.com>
14
15=== modified file 'AUTHORS'
16--- AUTHORS 2012-09-27 08:59:05 +0000
17+++ AUTHORS 2012-11-30 14:02:33 +0000
18@@ -18,6 +18,7 @@
19 Chris Behrens <cbehrens+github@codestud.com>
20 Christian Berendt <berendt@b1-systems.de>
21 Christopher MacGown <ignoti+github@gmail.com>
22+Chris Yeoh <cyeoh@au1.ibm.com>
23 Chuck <cthier@gmail.com>
24 Clark Boylan <clark.boylan@gmail.com>
25 Cole Robinson <crobinso@redhat.com>
26@@ -26,6 +27,7 @@
27 Dave Walker (Daviey) <Dave.Walker@canonical.com>
28 Dean Troyer <dtroyer@gmail.com>
29 Dominik Heidler <dheidler@suse.de>
30+Doug Hellmann <doug.hellmann@dreamhost.com>
31 Ed Leafe <ed@leafe.com>
32 Édouard Thuleau <edouard1.thuleau@orange.com>
33 Eldar Nugaev <eldr@ya.ru>
34@@ -37,6 +39,7 @@
35 Ghe Rivero <ghe@debian.org>
36 Hengqing Hu <hudayou@hotmail.com>
37 Ilya Alekseyev <ilyaalekseyev@acm.org>
38+ivan-zhu <bozhu@linux.vnet.ibm.com>
39 jakedahn <jake@ansolabs.com>
40 Jake Dahn <jake@ansolabs.com>
41 James E. Blair <jeblair@hp.com>
42@@ -50,8 +53,10 @@
43 Johannes Erdfelt <johannes.erdfelt@rackspace.com>
44 John Garbutt <john.garbutt@citrix.com>
45 John Tran <jhtran@att.com>
46-Josh Kearney <josh@jk0.org>
47+Josh Kearney <josh.kearney@pistoncloud.com>
48+Joshua Harlow <harlowja@yahoo-inc.com>
49 Julien Danjou <julien.danjou@enovance.com>
50+Julie Pichon <jpichon@redhat.com>
51 Kevin L. Mitchell <kevin.mitchell@rackspace.com>
52 Kiall Mac Innes <kiall@managedit.ie>
53 Kirill Shileev <kshileev@griddynamics.com>
54@@ -64,31 +69,43 @@
55 masumotok <masumotok@nttdata.co.jp>
56 Matt Dietz <matt.dietz@rackspace.com>
57 Matt Stephenson <mattstep@mattstep.net>
58+melwitt <melwitt@yahoo-inc.com>
59 Michael Basnight <mbasnight@gmail.com>
60 Monty Taylor <mordred@inaugust.com>
61 Nachi Ueno <nachi@nttmcl.com>
62 Nicholas Mistry <nmistry@gmail.com>
63+Nick Shobe <nickshobe@gmail.com>
64+Nikola Dipanov <ndipanov@redhat.com>
65 Nikolay Sokolov <nsokolov@griddynamics.com>
66 Ollie Leahy <oliver.leahy@hp.com>
67 Pádraig Brady <pbrady@redhat.com>
68 Paul Voccio <paul@substation9.com>
69+Paul Voccio <paul.voccio@rackspace.com>
70 Pavel Shkitin <pshkitin@griddynamics.com>
71 Peng Yong <ppyy@pubyun.com>
72 Rick Harris <rconradharris@gmail.com>
73 Robie Basak <robie.basak@canonical.com>
74 Russell Bryant <rbryant@redhat.com>
75+Russell Cloran <russell@nimbula.com>
76 Sandy Walsh <sandy@darksecretsoftware.com>
77 SandyWalsh <sandy@darksecretsoftware.com>
78 Sascha Peilicke <saschpe@suse.de>
79+sathish-nagappan <sathish.nagappan@nebula.com>
80+Sathish Nagappan <sathish.nagappan@nebula.com>
81 Scott Moser <smoser@ubuntu.com>
82+Stanislaw Pitucha <stanislaw.pitucha@hp.com>
83+Stef T <stelford@internap.com>
84 Sulochan Acharya <sulochan@gmail.com>
85 Thierry Carrez <thierry@openstack.org>
86 TianTian Gao <gtt116@126.com>
87 Trey Morris <treyemorris@gmail.com>
88 unicell <unicell@gmail.com>
89+Unmesh Gurjar <unmesh.gurjar@nttdata.com>
90 Unmesh Gurjar <unmesh.gurjar@vertex.co.in>
91+Vincent Untz <vuntz@suse.com>
92 Vishvananda Ishaya <vishvananda@gmail.com>
93 William Wolf <throughnothing@gmail.com>
94+Yaguang Tang <heut2008@gmail.com>
95 Your Name <heut2008@gmail.com>
96 Yunhong, Jiang <yunhong.jiang@intel.com>
97 Yuriy Taraday <yorik.sar@gmail.com>
98
99=== modified file 'ChangeLog'
100--- ChangeLog 2012-09-27 08:59:05 +0000
101+++ ChangeLog 2012-11-30 14:02:33 +0000
102@@ -1,3 +1,824 @@
103+commit 18deaf47918e5baa655fabb9776d294571363608
104+Merge: fef3af7 494040d
105+Author: Jenkins <jenkins@review.openstack.org>
106+Date: Thu Nov 29 19:11:11 2012 +0000
107+
108+ Merge "Remove unnecessary casts in flavor create."
109+
110+commit fef3af70725be74763d4ad95c624407dfde25b2a
111+Merge: 926b334 27d7ad9
112+Author: Jenkins <jenkins@review.openstack.org>
113+Date: Thu Nov 29 19:10:38 2012 +0000
114+
115+ Merge "Validate that rxtx_factor is a float."
116+
117+commit 926b334613169d59f91d522218d3418a69952d98
118+Merge: c4f0f50 4f6419b
119+Author: Jenkins <jenkins@review.openstack.org>
120+Date: Thu Nov 29 19:10:19 2012 +0000
121+
122+ Merge "Adds nova client support for nova-manage vpn command"
123+
124+commit c4f0f50a2a8f043f66cb010fbcf1e2ec5b7dcd23
125+Merge: b2338b9 3839d28
126+Author: Jenkins <jenkins@review.openstack.org>
127+Date: Thu Nov 29 18:51:08 2012 +0000
128+
129+ Merge "Adds nova client support for nova-manage fixed command"
130+
131+commit b2338b9a33547f600233b21bc64e74985327ce70
132+Merge: b9d60c1 ff69e4d
133+Author: Jenkins <jenkins@review.openstack.org>
134+Date: Thu Nov 29 18:50:20 2012 +0000
135+
136+ Merge "Implement fping calls in nova client"
137+
138+commit 494040d7fe36ddd00c8813a6e894e53b1abf31be
139+Author: Dan Prince <dprince@redhat.com>
140+Date: Tue Nov 27 11:05:53 2012 -0500
141+
142+ Remove unnecessary casts in flavor create.
143+
144+ We already cast and validate these variables above... no
145+ need to cast them again.
146+
147+ Change-Id: I87b967925ae77c70eb07a42f3ae050703d44a427
148+
149+ novaclient/v1_1/flavors.py | 14 +++++++-------
150+ 1 file changed, 7 insertions(+), 7 deletions(-)
151+
152+commit 27d7ad9d8632bdc67e25757a42a91109e393fbf9
153+Author: Dan Prince <dprince@redhat.com>
154+Date: Tue Nov 27 10:59:43 2012 -0500
155+
156+ Validate that rxtx_factor is a float.
157+
158+ Nova stores rxtx_factor as a float internally and as such
159+ novaclient should validate that a float is specified
160+ when creating a flavor.
161+
162+ Fixes LP Bug #1083651.
163+
164+ Change-Id: I75f9440d3fe2a0e72ea592f2259640623400ae73
165+
166+ novaclient/v1_1/flavors.py | 8 ++++----
167+ novaclient/v1_1/shell.py | 2 +-
168+ tests/v1_1/test_flavors.py | 16 ++++++++--------
169+ 3 files changed, 13 insertions(+), 13 deletions(-)
170+
171+commit 4f6419b5553e853f5720084ba01fc0b4cc1f6220
172+Author: Chris Yeoh <cyeoh@au1.ibm.com>
173+Date: Mon Nov 26 14:21:35 2012 +1030
174+
175+ Adds nova client support for nova-manage vpn command
176+
177+ Adds "nova cloudpipe-configure" command
178+ Adds shell tests for cloudpipe-list and cloudpipe-create commands which
179+ already exist
180+
181+ This patch depends on https://review.openstack.org/#/c/15854/
182+
183+ Change-Id: I784f5bf0f25a2d8cae4b7c2c6ccf345842ffe352
184+ Implements: blueprint apis-for-nova-manage
185+
186+ novaclient/v1_1/cloudpipe.py | 14 ++++++++++++++
187+ novaclient/v1_1/shell.py | 7 +++++++
188+ tests/v1_1/fakes.py | 3 +++
189+ tests/v1_1/test_cloudpipe.py | 6 ++++++
190+ tests/v1_1/test_shell.py | 15 +++++++++++++++
191+ 5 files changed, 45 insertions(+)
192+
193+commit b9d60c1fd2f887992fc1f6c2246b1f0f11efe1a9
194+Author: Joe Gordon <jogo@cloudscaling.com>
195+Date: Mon Nov 26 14:26:53 2012 -0800
196+
197+ Fix aggregate command help messages.
198+
199+ Fixes bug 1083343
200+
201+ Change-Id: I315a0629bb33480952f2280b053b8db8cb83a1ea
202+
203+ novaclient/v1_1/shell.py | 11 ++++++-----
204+ 1 file changed, 6 insertions(+), 5 deletions(-)
205+
206+commit 3839d284da8bb269ca392727f0716ddc2238b880
207+Author: Chris Yeoh <cyeoh@au1.ibm.com>
208+Date: Thu Nov 22 22:43:59 2012 +1030
209+
210+ Adds nova client support for nova-manage fixed command
211+
212+ Adds the following commands:
213+ - "fixed-ip-get <ip_addr>" - displays information about the fixed ip ip_addr
214+ - "fixed-ip-reserve <ip_addr>" - reserves the fixed ip ip_addr
215+ - "fixed-ip-unreserve <ip_addr>" - unreserves the fixed ip ip_addr
216+
217+ Change-Id: I6a5c8b9f7ab359adeb57b86240279649cd421801
218+ Implements: blueprint apis-for-nova-manage
219+
220+ novaclient/v1_1/client.py | 2 ++
221+ novaclient/v1_1/fixed_ips.py | 58 ++++++++++++++++++++++++++++++++++++++++++
222+ novaclient/v1_1/shell.py | 19 ++++++++++++++
223+ tests/v1_1/fakes.py | 13 ++++++++++
224+ tests/v1_1/test_fixed_ips.py | 43 +++++++++++++++++++++++++++++++
225+ tests/v1_1/test_shell.py | 14 ++++++++++
226+ 6 files changed, 149 insertions(+)
227+
228+commit ff69e4d3830f463afa48ca432600224f29a2c238
229+Author: Alessio Ababilov <aababilov@griddynamics.com>
230+Date: Mon Nov 19 11:33:50 2012 +0200
231+
232+ Implement fping calls in nova client
233+
234+ Implements blueprint novaclient-fping
235+
236+ Provide fping API calls in nova client as well as unit tests. API is
237+ accessed by `fping` field of nova client.
238+ Methods:
239+ * list(all_tenants=False|True, include=[VM ids], exclude=[VM ids]) -
240+ perform fping for all VMs in current project (or all projects if
241+ all_tenants==True)
242+ * get(server object or id) - perform fping for single instance
243+
244+ Change-Id: Ic3eda142781d1a14f2cfc83626672a579fc93a7d
245+
246+ novaclient/v1_1/client.py | 2 ++
247+ novaclient/v1_1/fping.py | 66 +++++++++++++++++++++++++++++++++++++++++++++
248+ tests/v1_1/fakes.py | 29 ++++++++++++++++++++
249+ tests/v1_1/test_fping.py | 41 ++++++++++++++++++++++++++++
250+ 4 files changed, 138 insertions(+)
251+
252+commit dc6285c810b696949597dcde6717bb3f3a6c47c9
253+Author: Julie Pichon <jpichon@redhat.com>
254+Date: Wed Nov 21 18:16:17 2012 +0000
255+
256+ Expand help message for 'migrate' to explain how the new host is selected
257+
258+ Fixes bug 1078247
259+
260+ Change-Id: Iedfd6fc957fd1c2e53f7685b02bd33e16d9342e9
261+
262+ novaclient/v1_1/shell.py | 2 +-
263+ 1 file changed, 1 insertion(+), 1 deletion(-)
264+
265+commit 572c8bbf8020c2bcd3d6e529574ee8866ba3cbea
266+Merge: 0173a3c 3fd0c77
267+Author: Jenkins <jenkins@review.openstack.org>
268+Date: Wed Nov 21 17:18:08 2012 +0000
269+
270+ Merge "Boot from volume without image supplied"
271+
272+commit 0173a3cd7085502ac1b9cd39858e5cc9de16bb02
273+Merge: 1558d5d e9b015c
274+Author: Jenkins <jenkins@review.openstack.org>
275+Date: Wed Nov 21 17:18:01 2012 +0000
276+
277+ Merge "Cleans up the flavor creation code. Fixes bug 1080891."
278+
279+commit 1558d5d537d89852339a01a18bb8cbb4198bbb52
280+Merge: 92de98c 3ea4ba9
281+Author: Jenkins <jenkins@review.openstack.org>
282+Date: Wed Nov 21 17:12:04 2012 +0000
283+
284+ Merge "Added --extra-opts to the nova ssh command"
285+
286+commit 92de98c8f68cc22b88dd164ca473eb86dbf1e45a
287+Merge: bc141de 5d5df17
288+Author: Jenkins <jenkins@review.openstack.org>
289+Date: Wed Nov 21 17:12:03 2012 +0000
290+
291+ Merge "fix hypervisor-servers for hypervisors without servers"
292+
293+commit bc141de141e5e9796f4b1c0891e90cda65d726f5
294+Merge: f790ccc aac4fff
295+Author: Jenkins <jenkins@review.openstack.org>
296+Date: Wed Nov 21 17:12:01 2012 +0000
297+
298+ Merge "Make sure create_image returns result"
299+
300+commit f790ccc6bc05a60b378bb7555083d8a8a228fb46
301+Merge: 89c46e6 c819c2f
302+Author: Jenkins <jenkins@review.openstack.org>
303+Date: Wed Nov 21 17:10:15 2012 +0000
304+
305+ Merge "make tenant id optional for quota-defaults and quota-show"
306+
307+commit 89c46e6325f588069e951397fe2522e28d153c36
308+Merge: 47355b7 d037172
309+Author: Jenkins <jenkins@review.openstack.org>
310+Date: Wed Nov 21 17:09:23 2012 +0000
311+
312+ Merge "Add nova client support for nova-manage service command"
313+
314+commit 47355b741b50a63227fb38e6be6b485902efe3e5
315+Author: Nikola Dipanov <ndipanov@redhat.com>
316+Date: Fri Nov 16 10:00:46 2012 +0100
317+
318+ Improved quota output
319+
320+ This patch makes the output of quota show a bit more informative
321+ by not setting a simple None to a non-existing quota, but not showing it
322+ all together.
323+
324+ Kind of fixes bug #1078906
325+ and also bug #1078089
326+
327+ Change-Id: Ic42837d218a80f37e0c6d56625c9804d076f444c
328+
329+ novaclient/v1_1/shell.py | 5 ++++-
330+ 1 file changed, 4 insertions(+), 1 deletion(-)
331+
332+commit 3fd0c77d07419606a81f257b8876394ec5b374de
333+Author: Nikola Dipanov <ndipanov@redhat.com>
334+Date: Wed Nov 7 18:58:58 2012 +0100
335+
336+ Boot from volume without image supplied
337+
338+ Allow for booting instances from volume without the image parameter
339+ supplied. This change is related to the change
340+ I530760cfaa5eb0cae590c7383e0840c6b3f896b9
341+ in opnestack/nova. It allows for boot to work with no image supplied
342+ to accommodate booting from volumes only.
343+
344+ It also makes it possible to interpret show servers that were started
345+ without images, so from volumes only
346+
347+ Change-Id: I5ba9b0f35a5084aa91eca260f46cac83b8b6591e
348+
349+ novaclient/v1_1/base.py | 2 +-
350+ novaclient/v1_1/shell.py | 34 ++++++++++++++++++++++------------
351+ tests/v1_1/fakes.py | 39 +++++++++++++++++++++++++++++++++++++++
352+ tests/v1_1/test_servers.py | 2 +-
353+ tests/v1_1/test_shell.py | 32 ++++++++++++++++++++++++++++++++
354+ 5 files changed, 95 insertions(+), 14 deletions(-)
355+
356+commit 3ea4ba9fc97b05ad93af8f9aa6f6bc2a638b9a36
357+Author: Nick Shobe <nickshobe@gmail.com>
358+Date: Sat Nov 17 04:26:08 2012 -0600
359+
360+ Added --extra-opts to the nova ssh command
361+
362+ This will allow for remote command execution and advanced ssh options
363+ like portforwarding and connection sharing.
364+ The goal is to support ssh commands like
365+ nova ssh fe55adc9-cb1e-44a4-bd36-6a537b238172 --extra-opts='-NfnMS ~/.ssh/master-fe55adc9-cb1e-44a4-bd36-6a537b238172'
366+ and ssh fe55adc9-cb1e-44a4-bd36-6a537b238172 --extra-opts='-t "sudo puppet agent --test"'
367+ This will alow easier scripting of the cli... It is not intended
368+ however to replace using the nova python api. Therefore I kept it simple.
369+
370+ Change-Id: Icce811caf637fc92c6d6374bfb846ea9525a7e05
371+
372+ novaclient/v1_1/shell.py | 9 +++++++--
373+ 1 file changed, 7 insertions(+), 2 deletions(-)
374+
375+commit e9b015c7e14843784debc0d68cfe070c9778f80d
376+Author: Gabriel Hurley <gabriel@strikeawe.com>
377+Date: Sat Nov 17 18:18:48 2012 -0800
378+
379+ Cleans up the flavor creation code. Fixes bug 1080891.
380+
381+ Change-Id: Idc76cd01d1537ab87723a05ab8dd81015284e3c8
382+
383+ novaclient/v1_1/flavors.py | 10 ++++++----
384+ 1 file changed, 6 insertions(+), 4 deletions(-)
385+
386+commit aa8d44c551643bb97e039624d602bd4ad07cbe9c
387+Author: Paul Voccio <paul.voccio@rackspace.com>
388+Date: Fri Nov 16 11:34:12 2012 -0600
389+
390+ Adding support to filter instances by tenant from the admin api
391+
392+ Change-Id: I37a2c5ad7bbe3e005e96416ea974051a82879adc
393+
394+ novaclient/v1_1/shell.py | 7 +++++++
395+ 1 file changed, 7 insertions(+)
396+
397+commit aac4fff1532cc96302cd1566406c6d3b3fe60e47
398+Author: Stanislaw Pitucha <stanislaw.pitucha@hp.com>
399+Date: Fri Nov 9 10:49:02 2012 +0000
400+
401+ Make sure create_image returns result
402+
403+ manager.servers.create_image() returned uuid of the snapshot, but
404+ Server.create_image() didn't. Make them work the same.
405+
406+ Change-Id: I763197ac8ae542e7ce13569d8ce7e98ec92ccc63
407+
408+ novaclient/v1_1/servers.py | 2 +-
409+ 1 file changed, 1 insertion(+), 1 deletion(-)
410+
411+commit c819c2fb50c63554d70f735a6463c911f2f6d8eb
412+Author: Christian Berendt <berendt@b1-systems.de>
413+Date: Fri Nov 9 10:52:23 2012 +0100
414+
415+ make tenant id optional for quota-defaults and quota-show
416+
417+ When using quota-defaults or quota-show without specifing a tenant
418+ the currently used tenant should be used.
419+
420+ Change-Id: I1ef71b68673dd4a95cbf8b5a8dc901fb6eb06865
421+
422+ novaclient/v1_1/client.py | 1 +
423+ novaclient/v1_1/shell.py | 20 ++++++++++++++------
424+ tests/v1_1/test_shell.py | 4 ++--
425+ 3 files changed, 17 insertions(+), 8 deletions(-)
426+
427+commit 5d5df1763d83296464a3c4a9c5c82e9a5057edee
428+Author: Christian Berendt <berendt@b1-systems.de>
429+Date: Thu Nov 8 17:06:24 2012 +0100
430+
431+ fix hypervisor-servers for hypervisors without servers
432+
433+ At the moment hypervisor-servers throws an AttributeError for
434+ hypervisors with no assigned instances. This patch checks first
435+ if there are assigned instances before looping through them to
436+ avoid the exception.
437+
438+ fixes bug 1076435
439+
440+ Change-Id: I504e3f234fd041325b63295fab77f9ed3f704db0
441+
442+ novaclient/v1_1/shell.py | 3 ++-
443+ 1 file changed, 2 insertions(+), 1 deletion(-)
444+
445+commit aa5622147faa0de137f67c6be45dbdb3e11320f6
446+Author: melwitt <melwitt@yahoo-inc.com>
447+Date: Wed Nov 7 22:58:32 2012 +0000
448+
449+ discover extensions via entry points
450+
451+ Currently, nova client can only discover extensions in two ways:
452+
453+ 1. Installing the extension in the novaclient/v1_1/contrib/ directory.
454+ 2. Installing the extension in the top-level python path or modifying
455+ the path to be picked up by pkgutils.iter_modules()
456+
457+ This patch allows a third, more flexible option of discovering
458+ extensions via entry points. This means the extension can be
459+ installed anywhere and entry points can be registered with python
460+ to be picked up by pkg_resources.iter_entry_points().
461+ To register an entry point, simply add the extension module to
462+ the setup() call in setup.py like this:
463+
464+ setuptools.setup(
465+ name='mydistribution',
466+ packages=setuptools.find_packages(),
467+ entry_points={
468+ 'novaclient.extension' : [
469+ 'foo = mydistribution.mynovaclientexts.foo'
470+ ]
471+ },
472+ )
473+
474+ Change-Id: Ic1e223a9173546131e742506897f585f4ac65767
475+
476+ novaclient/shell.py | 11 ++++++-
477+ tests/test_discover.py | 79 ++++++++++++++++++++++++++++++++++++++++++++++++
478+ 2 files changed, 89 insertions(+), 1 deletion(-)
479+
480+commit 4ad512b50e0c2190fbd4ef077256faf808496e2b
481+Author: Christian Berendt <berendt@b1-systems.de>
482+Date: Thu Nov 8 21:03:13 2012 +0100
483+
484+ show help when calling without arguments
485+
486+ When calling nova without arguments you'll receive the following
487+ output:
488+
489+ error: too few arguments
490+ Try 'nova help ' for more information.
491+
492+ Changing 'and' to 'or' the help is also shown when calling nova
493+ without arguments. I think that's the expected behavior.
494+
495+ Change-Id: Id14f0292ad00e6e45ad66dd010f449c3abbf3871
496+
497+ novaclient/shell.py | 2 +-
498+ tests/test_shell.py | 18 ++++++------------
499+ 2 files changed, 7 insertions(+), 13 deletions(-)
500+
501+commit d037172b701afd66d1ac187a3c7e4a76130a8f4f
502+Author: ivan-zhu <bozhu@linux.vnet.ibm.com>
503+Date: Thu Nov 8 17:56:18 2012 +0800
504+
505+ Add nova client support for nova-manage service command
506+
507+ Implements the one workitem of blueprint apis-for-nova-manage
508+
509+ This add three CLI (service-list/sevice-enable/service-diabel) in
510+ nova-client.
511+
512+ So we can use:
513+ "nova service-list" like "nova-manage service list" with two optional
514+ parameters. Show a list of all running services. Filter by host and
515+ service name.
516+
517+ "nova service-enable hostname servicename" like "nova-manage service
518+ enable hostname servicename". It will enable the service specified by
519+ hostname and serviename.
520+
521+ "nova service-disable hostname servicename" like "nova-manage service
522+ diable hostname servicename". It will disable the service specified by
523+ hostname and serviename.
524+
525+ This patch depends on https://review.openstack.org/#/c/15206/
526+
527+ Change-Id: I01d4cee4ef95c1783f6181f8b840244e748387e5
528+
529+ novaclient/v1_1/client.py | 2 ++
530+ novaclient/v1_1/services.py | 62 +++++++++++++++++++++++++++++++++++++++
531+ novaclient/v1_1/shell.py | 27 +++++++++++++++++
532+ tests/v1_1/fakes.py | 30 +++++++++++++++++++
533+ tests/v1_1/test_services.py | 68 +++++++++++++++++++++++++++++++++++++++++++
534+ tests/v1_1/test_shell.py | 26 +++++++++++++++++
535+ 6 files changed, 215 insertions(+)
536+
537+commit a84300f020e79adcaad313aff7f7ee11d9c18d1a
538+Merge: 40ef419 33b2830
539+Author: Jenkins <jenkins@review.openstack.org>
540+Date: Wed Nov 7 22:38:54 2012 +0000
541+
542+ Merge "Allows deletion of multiple servers through CLI"
543+
544+commit 40ef4197e982b840f9c3363bc83bf16600f763c5
545+Merge: a31d285 51faac4
546+Author: Jenkins <jenkins@review.openstack.org>
547+Date: Tue Nov 6 17:45:56 2012 +0000
548+
549+ Merge "Add ability of nova client to display availability zones when listing hosts"
550+
551+commit a31d285f6e7d5516d69319424db06608050107f6
552+Merge: 887f831 e9c16ca
553+Author: Jenkins <jenkins@review.openstack.org>
554+Date: Tue Nov 6 17:13:56 2012 +0000
555+
556+ Merge "Updated the help text for nova list command."
557+
558+commit 887f8314689a71144d4f5c5365d2253e8c662921
559+Merge: 0dea78c 8be01b6
560+Author: Jenkins <jenkins@review.openstack.org>
561+Date: Tue Nov 6 06:48:57 2012 +0000
562+
563+ Merge "Fixes setup compatibility issue on Windows"
564+
565+commit e9c16ca33ad035fda38d42ec3f7e9e40e56cbf6b
566+Author: Unmesh Gurjar <unmesh.gurjar@nttdata.com>
567+Date: Sun Nov 4 23:20:37 2012 -0800
568+
569+ Updated the help text for nova list command.
570+
571+ Few options in the nova list command are admin specific. Updated the help text
572+ to specify the admin only options explitcitly.
573+
574+ Fixes LP: #1055983
575+
576+ Change-Id: Icf8a76e79b9d5399298dacce31b1cc0873f63d71
577+
578+ novaclient/v1_1/shell.py | 9 +++++----
579+ 1 file changed, 5 insertions(+), 4 deletions(-)
580+
581+commit 8be01b650e4669132c0d27481781bdf5688079ec
582+Author: Alessandro Pilotti <ap@pilotti.it>
583+Date: Mon Nov 5 17:47:05 2012 +0200
584+
585+ Fixes setup compatibility issue on Windows
586+
587+ Fixes Bug #1052161
588+
589+ "python setup.py build" fails on Windows due to a hardcoded shell path:
590+ /bin/sh
591+
592+ setup.py updated using openstack-common/update.py
593+
594+ Change-Id: I9c8cf84ada189d8f27448ecda23f51c021d08818
595+
596+ novaclient/openstack/common/setup.py | 16 +++++++++++-----
597+ 1 file changed, 11 insertions(+), 5 deletions(-)
598+
599+commit 0dea78c851a7d43df5ffa9c00bbbc09e857560f0
600+Author: Jesse Andrews <anotherjesse@gmail.com>
601+Date: Sat Nov 3 16:18:53 2012 -0700
602+
603+ include projectid in the cache key
604+
605+ fixes bug #1074771
606+
607+ Change-Id: I0fc1638405c2f4de61255d3efc1b6096ead0742b
608+
609+ novaclient/client.py | 2 +-
610+ 1 file changed, 1 insertion(+), 1 deletion(-)
611+
612+commit 7ddc2fdfcdc0bfa6ada3d150a87ab3d930259538
613+Author: Nikola Dipanov <ndipanov@redhat.com>
614+Date: Fri Nov 2 18:06:51 2012 +0100
615+
616+ Fixes utils.findresource checking for integer
617+
618+ Fixes the novaclient.utils.find_resource function to properly handle
619+ non integer values and not break with an AttributeError.
620+
621+ Adds a test case to test a few more non valid inputs.
622+
623+ Fixes bug #1065367
624+
625+ Change-Id: Iaa2025f4eb580234f754596c3572e2f87872170e
626+
627+ novaclient/utils.py | 11 ++++++++---
628+ tests/test_utils.py | 9 +++++++++
629+ 2 files changed, 17 insertions(+), 3 deletions(-)
630+
631+commit 33b2830e9c81f87fb37e51eca65f6e98143d1e06
632+Author: Sulochan Acharya <sulochan@gmail.com>
633+Date: Thu Nov 1 17:43:39 2012 -0500
634+
635+ Allows deletion of multiple servers through CLI
636+
637+ Adds nargs to argparse for delete command to allow
638+ multiple (optional) positional server argument. This
639+ allows users to delete multiple servers using nova delete.
640+ For example:
641+ nova delete xxx yyy aaa zzz will delete valid servers
642+ xxx, yyy and zzz and print exception msg for invalid
643+ delete of server aaa.
644+
645+ Fixes bug892061
646+
647+ Change-Id: I2abe6329e489bfbd3e5ae699e97ef098b38c4537
648+
649+ novaclient/v1_1/shell.py | 11 ++++++++---
650+ 1 file changed, 8 insertions(+), 3 deletions(-)
651+
652+commit 51faac4a0902ced715c3022985ca4ba7e4aeeaba
653+Author: ivan-zhu <bozhu@linux.vnet.ibm.com>
654+Date: Wed Oct 24 17:31:56 2012 +0800
655+
656+ Add ability of nova client to display availability zones when listing hosts
657+
658+ Implements the one workitem of blueprint apis-for-nova-manage
659+
660+ Add an optional parameter for nova host-list
661+ Now, we can use the command: nova host-list --zone nova
662+ It will return the hosts that availability_zone=nova.
663+ This patch depends on https://review.openstack.org/#/c/14741/
664+
665+ Change-Id: Ide41e75e7d1471e23d19f51e63a8d9951337a411
666+
667+ novaclient/v1_1/hosts.py | 7 +++++--
668+ novaclient/v1_1/shell.py | 7 +++++--
669+ tests/v1_1/fakes.py | 10 ++++++++++
670+ tests/v1_1/test_hosts.py | 12 ++++++++++++
671+ tests/v1_1/test_shell.py | 8 ++++++++
672+ 5 files changed, 40 insertions(+), 4 deletions(-)
673+
674+commit f04a24c6ad397439c7f38e381eac1f3b272eba88
675+Merge: 7bf93a5 67d4d7e
676+Author: Jenkins <jenkins@review.openstack.org>
677+Date: Wed Oct 31 18:07:44 2012 +0000
678+
679+ Merge "Auto-Assign Flavor ID"
680+
681+commit 7bf93a52f8828822c8949fe66bc79e8c035d1330
682+Author: Russell Cloran <russell@nimbula.com>
683+Date: Mon Oct 29 23:09:26 2012 -0700
684+
685+ Validate that boolean parameters are boolean
686+
687+ Ensure that values which are supposed to be boolean look like correct
688+ user input, instead of assuming that any non true-looking input is
689+ False.
690+
691+ Also, update the flavor manager to raise a CommandError if is_public is
692+ not a boolean value.
693+
694+ Fixes bug 1059414
695+
696+ Change-Id: I3275e4bba103b14081becf91f723f1be060391e5
697+
698+ novaclient/utils.py | 8 ++++++--
699+ novaclient/v1_1/flavors.py | 6 ++++++
700+ tests/v1_1/test_flavors.py | 3 +++
701+ 3 files changed, 15 insertions(+), 2 deletions(-)
702+
703+commit 67d4d7e0fdc6a990484340299a7920b8d64d6a13
704+Author: sathish-nagappan <sathish.nagappan@nebula.com>
705+Date: Mon Oct 29 14:26:32 2012 -0700
706+
707+ Auto-Assign Flavor ID
708+
709+ Auto-assign a flavor ID if the user enters "auto" for the ID.
710+
711+ Change-Id: I745744b9ca44668477635c20df5e2ece6cbf1c27
712+
713+ novaclient/v1_1/flavors.py | 8 +++-----
714+ novaclient/v1_1/shell.py | 3 ---
715+ tests/v1_1/test_flavors.py | 3 ---
716+ 3 files changed, 3 insertions(+), 11 deletions(-)
717+
718+commit 05bbe0fa0efc9abe5461e7e2d3fef7b72d625955
719+Merge: 8617a88 2f7b032
720+Author: Jenkins <jenkins@review.openstack.org>
721+Date: Fri Oct 26 17:04:24 2012 +0000
722+
723+ Merge "Pull in latest openstack-common changes and fix a minor PEP8 issue."
724+
725+commit 2f7b032910cce500f09a5d2a257595d573bdb116
726+Author: Josh Kearney <josh.kearney@pistoncloud.com>
727+Date: Thu Oct 25 11:43:56 2012 -0500
728+
729+ Pull in latest openstack-common changes and fix a minor PEP8 issue.
730+
731+ Latest openstack-common commit: d887090b5a31672e4a12f302b3818e2b0933bef0
732+
733+ Change-Id: I5a4ffb043ab24f8618a8285112c0c5992ea129e7
734+
735+ .mailmap | 3 +-
736+ novaclient/openstack/common/setup.py | 97 +++++++++++++++++-------------
737+ novaclient/openstack/common/timeutils.py | 21 +++++--
738+ tests/test_auth_plugins.py | 1 -
739+ 4 files changed, 73 insertions(+), 49 deletions(-)
740+
741+commit 8617a88765968341c6dc6e8e44b3d2e6038106a7
742+Merge: f100953 805ba8f
743+Author: Jenkins <jenkins@review.openstack.org>
744+Date: Wed Oct 24 00:33:46 2012 +0000
745+
746+ Merge "Exception handling for 'nova flavor-create' arguments"
747+
748+commit f1009534953ed9662e5fe15f71987263c63d6678
749+Merge: 4d3f33d 3463559
750+Author: Jenkins <jenkins@review.openstack.org>
751+Date: Tue Oct 23 15:57:57 2012 +0000
752+
753+ Merge "Add support for backup instance."
754+
755+commit 4d3f33d141dfc10c553bfc649dbfebf4fe7dec15
756+Author: Doug Hellmann <doug.hellmann@dreamhost.com>
757+Date: Mon Oct 22 18:46:41 2012 -0400
758+
759+ Add OpenStack trove classifier for PyPI
760+
761+ Add trove classifier to have the client listed among the
762+ other OpenStack-related projets on PyPI.
763+
764+ Change-Id: If9e10b065d0c54825fb9138893c78cda3ef79ca2
765+ Signed-off-by: Doug Hellmann <doug.hellmann@dreamhost.com>
766+
767+ setup.py | 1 +
768+ 1 file changed, 1 insertion(+)
769+
770+commit 805ba8fdc1763306f4a6dbdc3de274b5c2597485
771+Author: Sathish Nagappan <sathish.nagappan@nebula.com>
772+Date: Wed Oct 17 21:31:34 2012 -0700
773+
774+ Exception handling for 'nova flavor-create' arguments
775+
776+ Fixes client side Bug #1056935
777+
778+ Throws an exception if the user does not input integers for the
779+ corresponding parameters.
780+
781+ Change-Id: I4c4b8148f6565bc5a3b348dbde8c2cf0da00234a
782+
783+ novaclient/v1_1/flavors.py | 35 +++++++++++++++++++++++++++++++++++
784+ tests/v1_1/test_flavors.py | 23 +++++++++++++++++++++++
785+ 2 files changed, 58 insertions(+)
786+
787+commit 34635597a68d0626f9806c9b1220600a955e0ea4
788+Author: TianTian Gao <gtt116@126.com>
789+Date: Mon Oct 15 14:33:52 2012 +0800
790+
791+ Add support for backup instance.
792+
793+ fix bug: 1066665
794+
795+ Change-Id: I1e2c3b2cd9d9e50073b87762973147795059f067
796+
797+ novaclient/v1_1/servers.py | 26 ++++++++++++++++++++++++++
798+ novaclient/v1_1/shell.py | 13 +++++++++++++
799+ tests/v1_1/fakes.py | 4 ++++
800+ tests/v1_1/test_servers.py | 7 +++++++
801+ tests/v1_1/test_shell.py | 12 ++++++++++++
802+ 5 files changed, 62 insertions(+)
803+
804+commit e8c22cd130759fc6ab89c027cf34df19333878b9
805+Merge: ccabbe7 81c01e5
806+Author: Jenkins <jenkins@review.openstack.org>
807+Date: Wed Oct 10 16:57:11 2012 +0000
808+
809+ Merge "Encode user data to utf-8 when creating a server"
810+
811+commit ccabbe77de4a411f8728236969e9a5a50ec79a65
812+Merge: c8696a5 ccc4291
813+Author: Jenkins <jenkins@review.openstack.org>
814+Date: Wed Oct 10 04:00:52 2012 +0000
815+
816+ Merge "Add simple os-api extension cli extension"
817+
818+commit ccc4291c52eb4f68e37691bbe7df34450e89df7a
819+Author: Joshua Harlow <harlowja@yahoo-inc.com>
820+Date: Tue Sep 18 16:36:17 2012 -0700
821+
822+ Add simple os-api extension cli extension
823+
824+ Add a useful extension that will show you what
825+ openstack api extensions are available for usage
826+ and print out the result into a nice little table.
827+
828+ Useful as a example for others to base contrib/
829+ extensions off of.
830+
831+ Example @ http://paste.openstack.org/show/20989/
832+
833+ Change-Id: I5b72f5ea73c00f1c1a0f09f670d744c820e05837
834+
835+ novaclient/v1_1/contrib/list_extensions.py | 46 +++++++++++++++++++++++++
836+ tests/v1_1/contrib/test_list_extensions.py | 21 ++++++++++++
837+ tests/v1_1/fakes.py | 50 +++++++++++++++++++++++++++-
838+ 3 files changed, 116 insertions(+), 1 deletion(-)
839+
840+commit c8696a59e32ccd0d20dafa86a85379dd7e214a77
841+Merge: 6a86308 a9a66ae
842+Author: Jenkins <jenkins@review.openstack.org>
843+Date: Thu Oct 4 22:52:20 2012 +0000
844+
845+ Merge "Raises Exception on improper Auth Configuration"
846+
847+commit 6a8630867f0563e2699caf35d3669f8e83256c5f
848+Merge: aa171ca f391591
849+Author: Jenkins <jenkins@review.openstack.org>
850+Date: Thu Oct 4 21:47:10 2012 +0000
851+
852+ Merge "Add missing port-id usage info."
853+
854+commit a9a66ae7a750e507a0dda4bc9b2f9f62b9cd98a2
855+Author: Stef T <stelford@internap.com>
856+Date: Thu Oct 4 16:20:23 2012 -0400
857+
858+ Raises Exception on improper Auth Configuration
859+
860+ Addresses bug 1061848.
861+
862+ Basically, this bug comes about from not properly
863+ setting up the auth_system for novaclient. In this
864+ case, an exception of EndPointNotFound is flung.
865+
866+ Change-Id: I12533aefd9d0425dd83e2e4c63f4dd5ff6faae71
867+
868+ novaclient/client.py | 2 ++
869+ tests/test_auth_plugins.py | 24 ++++++++++++++++++++++++
870+ 2 files changed, 26 insertions(+)
871+
872+commit aa171ca12b336f9a927dbdec0d598f30386b6501
873+Author: Vincent Untz <vuntz@suse.com>
874+Date: Fri Sep 28 12:42:37 2012 +0200
875+
876+ Do not prefer ALL_TENANTS environment variable to command line arguments
877+
878+ As pointed out in https://review.openstack.org/#/c/13708/ command line
879+ arguments should have higher priority.
880+
881+ Also, do not fail if the environment variable is not representing an
882+ int.
883+
884+ Change-Id: Ie6cd5b2d6aae47236ba0fe6d594d0c8095e9e422
885+
886+ novaclient/v1_1/shell.py | 15 ++++++---------
887+ 1 file changed, 6 insertions(+), 9 deletions(-)
888+
889+commit 81c01e535cecc54c2e6e847000638b52fec506af
890+Author: Vincent Untz <vuntz@suse.com>
891+Date: Fri Sep 28 11:48:38 2012 +0200
892+
893+ Encode user data to utf-8 when creating a server
894+
895+ This is needed for data that we don't read from IO directly, since we're
896+ base64-encoding the user data, and this requires ther user data to not
897+ be of the unicode type.
898+
899+ We're being tolerant, as we'll accept user data that is already in a str
900+ object.
901+
902+ Fixes: bug 1049161
903+ Change-Id: I4320670de564c8029c7aef14da2492c6f8752efe
904+
905+ novaclient/v1_1/base.py | 2 ++
906+ tests/v1_1/test_servers.py | 34 ++++++++++++++++++++++++++++++++++
907+ 2 files changed, 36 insertions(+)
908+
909+commit c01fae73700047072a1a27add416eb61ee5cb1b0
910+Author: Vincent Untz <vuntz@suse.com>
911+Date: Wed Sep 26 14:54:57 2012 +0200
912+
913+ Add --all-tenants option to volume-list
914+
915+ The list and secgroup-list commands have this option, and
916+ nova-volume/cinder respect this search option too nowadays.
917+
918+ Change-Id: Ie95432727dec9702e09a0ce314bf418f6a36b799
919+
920+ novaclient/v1_1/shell.py | 19 +++++++++++++++++--
921+ novaclient/v1_1/volumes.py | 14 +++++++++++---
922+ 2 files changed, 28 insertions(+), 5 deletions(-)
923+
924 commit cdebf729b06d9465ab080fd5b15e433f70f8fe45
925 Merge: e01c25b 02d3aad
926 Author: Jenkins <jenkins@review.openstack.org>
927@@ -473,6 +1294,17 @@
928 tests/v1_1/test_shell.py | 4 ++-
929 9 files changed, 242 insertions(+), 6 deletions(-)
930
931+commit f391591713a3bd16c521a68063a2c529c5f62ccb
932+Author: Yaguang Tang <heut2008@gmail.com>
933+Date: Mon Aug 27 16:03:46 2012 +0800
934+
935+ Add missing port-id usage info.
936+
937+ Change-Id: I3e5de32265512c0f692bda6d322c95be0d1b8851
938+
939+ novaclient/v1_1/shell.py | 2 +-
940+ 1 file changed, 1 insertion(+), 1 deletion(-)
941+
942 commit ae431aba0d3829728d7e7fda6053f8eb4c417759
943 Merge: 8ccd905 52d24b1
944 Author: Jenkins <jenkins@review.openstack.org>
945@@ -1147,7 +1979,7 @@
946 2 files changed, 12 insertions(+), 2 deletions(-)
947
948 commit d4c9b12f39501186e812fba31c314bf813a4cfc0
949-Author: Josh Kearney <josh@jk0.org>
950+Author: Josh Kearney <josh.kearney@pistoncloud.com>
951 Date: Tue Jun 26 11:34:31 2012 -0500
952
953 Indicate unused variables and other misc. house cleaning.
954@@ -1349,7 +2181,7 @@
955 Merge "Move docs to doc."
956
957 commit 8dce04a1cf4ed7f04b0677c451947283e20047e6
958-Author: Josh Kearney <josh@jk0.org>
959+Author: Josh Kearney <josh.kearney@pistoncloud.com>
960 Date: Wed Jun 13 10:03:23 2012 -0500
961
962 Removes NOVACLIENT_DEBUG from client code.
963@@ -1451,7 +2283,7 @@
964 2 files changed, 3 insertions(+), 3 deletions(-)
965
966 commit 051aa3d7dd54a453165a839dee9e2bb6de203abf
967-Author: Josh Kearney <josh@jk0.org>
968+Author: Josh Kearney <josh.kearney@pistoncloud.com>
969 Date: Mon Jun 11 11:44:38 2012 -0500
970
971 Removed generate_authors.sh since it's no longer used.
972@@ -1830,7 +2662,7 @@
973 2 files changed, 2 insertions(+), 19 deletions(-)
974
975 commit 765f551a267f07e43eb3acb92835ac7e5d6ca31b
976-Author: Josh Kearney <josh@jk0.org>
977+Author: Josh Kearney <josh.kearney@pistoncloud.com>
978 Date: Thu Apr 12 14:16:31 2012 -0500
979
980 Rename NOVA_VERSION to OS_COMPUTE_API_VERSION.
981@@ -1977,7 +2809,7 @@
982 2 files changed, 4 insertions(+), 11 deletions(-)
983
984 commit f6014dd8c530e121ae96a53ae6664bc24eb85781
985-Author: Josh Kearney <josh@jk0.org>
986+Author: Josh Kearney <josh.kearney@pistoncloud.com>
987 Date: Mon Apr 2 12:27:30 2012 -0500
988
989 Miscellaneous code cleanup.
990@@ -2739,7 +3571,7 @@
991 Merge "Fix bug 904364: Consistiently handle trailing '/' on URLs"
992
993 commit 3f9c3a6f1a57b11c05e162df0d1be9500b41dae3
994-Author: Josh Kearney <josh@jk0.org>
995+Author: Josh Kearney <josh.kearney@pistoncloud.com>
996 Date: Thu Feb 9 14:34:12 2012 -0600
997
998 Properly handle KeyErrors.
999@@ -4017,7 +4849,7 @@
1000 32 files changed, 35 insertions(+), 53 deletions(-)
1001
1002 commit 6509fe253f9e40f217d6c483941af6fa56bc23f7
1003-Author: Josh Kearney <josh@jk0.org>
1004+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1005 Date: Tue Dec 13 15:54:09 2011 -0600
1006
1007 Add support for RAX authentication.
1008@@ -4289,7 +5121,7 @@
1009 Merge "Rewriting admin-only calls as server actions"
1010
1011 commit 149e00bcf5eeb16e4e5cc13840cdb6d0fe2897e3
1012-Author: Josh Kearney <josh@jk0.org>
1013+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1014 Date: Wed Nov 16 15:21:25 2011 -0600
1015
1016 Adds bash completion support and cleans up setup.py.
1017@@ -4577,7 +5409,7 @@
1018
1019 commit beb40d3adcc15e57d72678be1c1a5aa522b9520f
1020 Merge: fcfa928 05a1ef7
1021-Author: Chris Behrens <cbehrens+github@codestud.com>
1022+Author: comstud <cbehrens+github@codestud.com>
1023 Date: Fri Nov 4 11:53:07 2011 -0700
1024
1025 Merge pull request #147 from SandyWalsh/flavors_are_strings
1026@@ -5129,7 +5961,7 @@
1027
1028 commit 19d11e39ae4a5ac660c7ba25b9f360c844a65deb
1029 Merge: 4b6345e acf8a27
1030-Author: Josh Kearney <josh@jk0.org>
1031+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1032 Date: Tue Sep 27 14:03:59 2011 -0700
1033
1034 Merge pull request #121 from gagupta/master
1035@@ -5452,7 +6284,7 @@
1036
1037 commit 6b56f3be13956f2e6158f860fbfa9215e1bd6b30
1038 Merge: ba96890 07795ce
1039-Author: Josh Kearney <josh@jk0.org>
1040+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1041 Date: Fri Sep 2 09:01:49 2011 -0700
1042
1043 Merge pull request #111 from klmitch/loaded-zones
1044@@ -5531,7 +6363,7 @@
1045
1046 commit be53d30569f62e4018a58ef7662fbd88d041f905
1047 Merge: fe3dbf0 6b4791b
1048-Author: Josh Kearney <josh@jk0.org>
1049+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1050 Date: Thu Sep 1 13:50:12 2011 -0700
1051
1052 Merge pull request #104 from throughnothing/instance_metadata
1053@@ -5540,7 +6372,7 @@
1054
1055 commit fe3dbf056521a3ccaf6c3b90eb495fae7a281437
1056 Merge: 51610e9 25977cd
1057-Author: Josh Kearney <josh@jk0.org>
1058+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1059 Date: Thu Sep 1 13:46:25 2011 -0700
1060
1061 Merge pull request #106 from chmouel/fix-unittest-breakage
1062@@ -5558,7 +6390,7 @@
1063
1064 commit 51610e9949fbd1baa39899046f89378eeac58014
1065 Merge: 2b1b109 7c8ae25
1066-Author: Josh Kearney <josh@jk0.org>
1067+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1068 Date: Thu Sep 1 13:38:31 2011 -0700
1069
1070 Merge pull request #105 from chmouel/fix-unittest-breakage
1071@@ -5579,7 +6411,7 @@
1072
1073 commit 2b1b109aab24ab639bf8a5c16588bde75a8ca8d1
1074 Merge: 230c4f4 c31aeb1
1075-Author: Josh Kearney <josh@jk0.org>
1076+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1077 Date: Thu Sep 1 13:07:37 2011 -0700
1078
1079 Merge pull request #101 from basak/master
1080@@ -5588,7 +6420,7 @@
1081
1082 commit 230c4f4bea57ae27641a1287fc6897da9a1d7368
1083 Merge: 3507905 14c2bd2
1084-Author: Josh Kearney <josh@jk0.org>
1085+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1086 Date: Thu Sep 1 13:04:17 2011 -0700
1087
1088 Merge pull request #100 from throughnothing/image_metadata
1089@@ -5597,7 +6429,7 @@
1090
1091 commit 3507905a7aa0e9463535d5de8aa56c753c7e6ccc
1092 Merge: 3f22be9 40333f0
1093-Author: Josh Kearney <josh@jk0.org>
1094+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1095 Date: Thu Sep 1 13:02:54 2011 -0700
1096
1097 Merge pull request #99 from chmouel/no-auth-url-error
1098@@ -5648,7 +6480,7 @@
1099
1100 commit c35bd291e399c2bfb8ba80889153f476bb3171a3
1101 Merge: 597ef2f 526c5ce
1102-Author: Josh Kearney <josh@jk0.org>
1103+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1104 Date: Thu Sep 1 10:33:30 2011 -0700
1105
1106 Merge pull request #103 from SandyWalsh/fix_2_6_5_tests
1107@@ -6038,7 +6870,7 @@
1108
1109 commit 72d41b1e38034f5d7aedc849d85e7f670aca529a
1110 Merge: 3c254c0 dd37389
1111-Author: Josh Kearney <josh@jk0.org>
1112+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1113 Date: Wed Aug 24 10:38:58 2011 -0700
1114
1115 Merge pull request #88 from bcwaldon/rebuild-adminPass
1116@@ -6148,7 +6980,7 @@
1117
1118 commit 79a34e9dbba3e87e63832084c02f114d25a7a8ef
1119 Merge: f361298 0d997e0
1120-Author: Josh Kearney <josh@jk0.org>
1121+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1122 Date: Mon Aug 22 10:04:10 2011 -0700
1123
1124 Merge pull request #79 from cloudbuilders/quota-fixes
1125@@ -6157,7 +6989,7 @@
1126
1127 commit f361298676e14068e4495e04199e2aba42d6c2cd
1128 Merge: c42b374 328a425
1129-Author: Josh Kearney <josh@jk0.org>
1130+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1131 Date: Mon Aug 22 10:01:28 2011 -0700
1132
1133 Merge pull request #84 from cloudbuilders/shell-test-fixes
1134@@ -6175,7 +7007,7 @@
1135
1136 commit c42b374ed8b6ea4b7fb43125c6100c40214f6247
1137 Merge: 66ecf7c b8f5c91
1138-Author: Josh Kearney <josh@jk0.org>
1139+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1140 Date: Thu Aug 18 15:17:46 2011 -0700
1141
1142 Merge pull request #83 from jk0/master
1143@@ -6183,7 +7015,7 @@
1144 Fixed 1.0 and unit tests.
1145
1146 commit b8f5c91f864e50ea3e94aa23be37a7b8171eeae2
1147-Author: Josh Kearney <josh@jk0.org>
1148+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1149 Date: Thu Aug 18 17:16:38 2011 -0500
1150
1151 Fixed 1.0 and unit tests.
1152@@ -6203,7 +7035,7 @@
1153 Updated rescue in 1.0 and added unit tests.
1154
1155 commit fb72dff889b05cbcd12694b771cdef8ccfd7bb4f
1156-Author: Josh Kearney <josh@jk0.org>
1157+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1158 Date: Thu Aug 18 12:04:55 2011 -0500
1159
1160 Added support for 1.0 and added unit tests.
1161@@ -6226,7 +7058,7 @@
1162 Update rescue/unrescue calls to use public API
1163
1164 commit b9d194e99dede7686df1a7f8ee96908ace0ab0f2
1165-Author: Josh Kearney <josh@jk0.org>
1166+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1167 Date: Thu Aug 18 11:51:26 2011 -0500
1168
1169 Updated rescue/unrescue to use public API.
1170@@ -6341,7 +7173,7 @@
1171
1172 commit a97722dedf490c7546b99e10f68be406e9f9468a
1173 Merge: 4294327 2b70b75
1174-Author: Josh Kearney <josh@jk0.org>
1175+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1176 Date: Sat Aug 13 08:59:15 2011 -0700
1177
1178 Merge pull request #73 from cloudbuilders/more_keystonization
1179@@ -6385,7 +7217,7 @@
1180
1181 commit 42943277a05d22c9ee4047aaf369440d23102631
1182 Merge: d14d2b0 fc8e5e3
1183-Author: Josh Kearney <josh@jk0.org>
1184+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1185 Date: Fri Aug 12 07:24:33 2011 -0700
1186
1187 Merge pull request #72 from comstud/search-fixups
1188@@ -6509,7 +7341,7 @@
1189
1190 commit 064a98bb724f8153e06c247eb534c0b6c206bd80
1191 Merge: 5ece6de 5f64a85
1192-Author: Josh Kearney <josh@jk0.org>
1193+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1194 Date: Wed Aug 10 12:00:27 2011 -0700
1195
1196 Merge pull request #56 from cloudbuilders/keypairs
1197@@ -6622,7 +7454,7 @@
1198 1 file changed, 5 insertions(+)
1199
1200 commit 461d3e7e2f000619a6113c340e39cbcbb95e58e9
1201-Author: Andy Smith <github@anarkystic.com>
1202+Author: termie <github@anarkystic.com>
1203 Date: Tue Aug 9 13:12:09 2011 -0700
1204
1205 add license headers
1206@@ -6632,7 +7464,7 @@
1207 2 files changed, 30 insertions(+)
1208
1209 commit 17208cec6a77f939c68e393c7d3c23695bb35dbb
1210-Author: Andy Smith <github@anarkystic.com>
1211+Author: termie <github@anarkystic.com>
1212 Date: Mon Aug 8 14:48:07 2011 -0700
1213
1214 add support for quotas
1215@@ -6644,7 +7476,7 @@
1216 4 files changed, 131 insertions(+)
1217
1218 commit dfa2c86087554c59b08fc035624f8afa31534c4b
1219-Author: Nikolay Sokolov <nsokolov@griddynamics.com>
1220+Author: Nokolay Sokolov <nsokolov@griddynamics.com>
1221 Date: Tue Aug 9 01:44:01 2011 +0400
1222
1223 pep8, again
1224@@ -6653,7 +7485,7 @@
1225 1 file changed, 1 insertion(+), 1 deletion(-)
1226
1227 commit eff34ef4013912426be511c3235adab1eac305c5
1228-Author: Nikolay Sokolov <nsokolov@griddynamics.com>
1229+Author: Nokolay Sokolov <nsokolov@griddynamics.com>
1230 Date: Tue Aug 9 01:41:51 2011 +0400
1231
1232 Recursion handling.
1233@@ -6662,7 +7494,7 @@
1234 1 file changed, 20 insertions(+), 15 deletions(-)
1235
1236 commit c8b3b13615d4b3874c792549a8467e88575138b9
1237-Author: Josh Kearney <josh@jk0.org>
1238+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1239 Date: Mon Aug 8 16:06:31 2011 -0500
1240
1241 Added .mailmap file for AUTHORS.
1242@@ -6673,7 +7505,7 @@
1243
1244 commit 360ee0a34b37edd71525708127f5bed6e43f5e9b
1245 Merge: 811ba10 f39ca09
1246-Author: Josh Kearney <josh@jk0.org>
1247+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1248 Date: Mon Aug 8 13:58:13 2011 -0700
1249
1250 Merge pull request #64 from piston/conform_to_openstack_standards
1251@@ -6715,7 +7547,7 @@
1252
1253 commit 811ba10e51ae4903c0e5fa46e1a697eaf137f5a5
1254 Merge: 2072f88 6d1361c
1255-Author: Josh Kearney <josh@jk0.org>
1256+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1257 Date: Mon Aug 8 13:34:19 2011 -0700
1258
1259 Merge pull request #61 from bcwaldon/boot_output
1260@@ -6724,7 +7556,7 @@
1261
1262 commit 2072f88dcd09e86d06d0cae8a267541767ad453c
1263 Merge: 7e5a474 536be15
1264-Author: Josh Kearney <josh@jk0.org>
1265+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1266 Date: Mon Aug 8 13:33:38 2011 -0700
1267
1268 Merge pull request #63 from cloudbuilders/whitespace_cleanups
1269@@ -6732,7 +7564,7 @@
1270 Whitespace cleanups
1271
1272 commit e52d095a46f4d486db6bb58717b09d5fc3642797
1273-Author: Nikolay Sokolov <nsokolov@griddynamics.com>
1274+Author: Nokolay Sokolov <nsokolov@griddynamics.com>
1275 Date: Tue Aug 9 00:28:46 2011 +0400
1276
1277 pep8
1278@@ -6741,7 +7573,7 @@
1279 1 file changed, 3 insertions(+), 3 deletions(-)
1280
1281 commit b3af99fa15629ec20d84eedd931ec5d3d0c43034
1282-Author: Nikolay Sokolov <nsokolov@griddynamics.com>
1283+Author: Nokolay Sokolov <nsokolov@griddynamics.com>
1284 Date: Tue Aug 9 00:26:41 2011 +0400
1285
1286 Status code 305 fix, ClientExceptions if we can not handle response
1287@@ -6750,7 +7582,7 @@
1288 1 file changed, 12 insertions(+), 7 deletions(-)
1289
1290 commit 536be15a8777963d9151f36bfdecc85b39b9656b
1291-Author: Andy Smith <github@anarkystic.com>
1292+Author: termie <github@anarkystic.com>
1293 Date: Mon Aug 8 13:20:44 2011 -0700
1294
1295 whitespace cleanups
1296@@ -6862,7 +7694,7 @@
1297 1 file changed, 16 insertions(+), 3 deletions(-)
1298
1299 commit 5853354a7bdbe56053bd286873a0d2305c7c858b
1300-Author: Nikolay Sokolov <nsokolov@griddynamics.com>
1301+Author: Nokolay Sokolov <nsokolov@griddynamics.com>
1302 Date: Tue Aug 9 00:06:55 2011 +0400
1303
1304 Redirection handling.
1305@@ -6922,7 +7754,7 @@
1306
1307 commit f5a078c7eb7f3ae49a8bed9f88d47e52cab7c561
1308 Merge: ae1b052 4a4e9a6
1309-Author: Josh Kearney <josh@jk0.org>
1310+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1311 Date: Fri Aug 5 11:26:27 2011 -0700
1312
1313 Merge pull request #52 from Cerberus98/dead_bodies_redux
1314@@ -6944,7 +7776,7 @@
1315 6 files changed, 26 insertions(+), 30 deletions(-)
1316
1317 commit ae1b0521f04998725ebcad71b92e4085bf11ff8b
1318-Author: Josh Kearney <josh@jk0.org>
1319+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1320 Date: Fri Aug 5 10:38:29 2011 -0500
1321
1322 Corrected docs.
1323@@ -7025,13 +7857,13 @@
1324
1325 commit be3a11d27e4753240417859191bf49452df37a22
1326 Merge: 6b4e9c5 008b43f
1327-Author: Antony Messerli <amesserl@rackspace.com>
1328+Author: root <amesserl@rackspace.com>
1329 Date: Thu Aug 4 18:40:54 2011 +0000
1330
1331 Merge branch 'v1.1-split-and-support' of http://github.com/blamarvt/python-novaclient into v1.1-formatting
1332
1333 commit 6b4e9c5c8b79671d6bdf633d22a61eda0638f01f
1334-Author: Antony Messerli <amesserl@rackspace.com>
1335+Author: root <amesserl@rackspace.com>
1336 Date: Thu Aug 4 18:39:21 2011 +0000
1337
1338 formatting updates
1339@@ -7295,7 +8127,7 @@
1340
1341 commit 4b8879a8eb3fb80494ff16d4b96490fec9aa2161
1342 Merge: 20251cc 40a2bf9
1343-Author: Josh Kearney <josh@jk0.org>
1344+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1345 Date: Fri Jul 29 12:44:50 2011 -0700
1346
1347 Merge pull request #39 from bcwaldon/master
1348@@ -7337,7 +8169,7 @@
1349
1350 commit 20251ccc2ff7a8d030647c92c9a5a288ed5c1229
1351 Merge: 25596fe d72ea5d
1352-Author: Josh Kearney <josh@jk0.org>
1353+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1354 Date: Wed Jul 13 11:03:56 2011 -0700
1355
1356 Merge pull request #32 from SandyWalsh/master
1357@@ -7355,7 +8187,7 @@
1358
1359 commit 25596fef72b3b32a37bae2d2e4c9188953d834b5
1360 Merge: 5560117 1920e32
1361-Author: Chris Behrens <cbehrens+github@codestud.com>
1362+Author: comstud <cbehrens+github@codestud.com>
1363 Date: Tue Jul 12 15:11:08 2011 -0700
1364
1365 Merge pull request #31 from SandyWalsh/master
1366@@ -7413,7 +8245,7 @@
1367
1368 commit ecc2ede1b1e1a75b4d78c985d147f40814511ece
1369 Merge: f1a8117 5f08840
1370-Author: Josh Kearney <josh@jk0.org>
1371+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1372 Date: Fri Jul 8 12:15:58 2011 -0700
1373
1374 Merge pull request #28 from jerdfelt/master
1375@@ -7422,7 +8254,7 @@
1376
1377 commit f1a81175ec997b6fb0eb990c7ed8a9ce6672635b
1378 Merge: 0118cb3 2bba8e2
1379-Author: Josh Kearney <josh@jk0.org>
1380+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1381 Date: Fri Jul 8 12:14:26 2011 -0700
1382
1383 Merge pull request #29 from SandyWalsh/2bba8e2e2b08a53d7dea828047406074826d7622
1384@@ -7460,7 +8292,7 @@
1385
1386 commit 0118cb316158c8f11b635bfb08dcaee43b4e6218
1387 Merge: f81fc89 eb0d5c7
1388-Author: Chris Behrens <cbehrens+github@codestud.com>
1389+Author: comstud <cbehrens+github@codestud.com>
1390 Date: Thu Jul 7 15:15:23 2011 -0700
1391
1392 Merge pull request #27 from EdLeafe/master
1393@@ -7487,7 +8319,7 @@
1394 Migrations!
1395
1396 commit 9b31d54aa2b08a59c7e7f67ba78a0e8e0ae3e88e
1397-Author: Josh Kearney <josh@jk0.org>
1398+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1399 Date: Thu Jul 7 13:33:17 2011 -0500
1400
1401 Added migration functionality.
1402@@ -7501,7 +8333,7 @@
1403
1404 commit ede425d3abfd62412d4d449006936350994d4a67
1405 Merge: c1b1420 cee51f8
1406-Author: Josh Kearney <josh@jk0.org>
1407+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1408 Date: Tue Jun 28 12:54:50 2011 -0700
1409
1410 Merge pull request #25 from jk0/master
1411@@ -7509,7 +8341,7 @@
1412 Refactored backup rotation code.
1413
1414 commit cee51f8aff494c1e7dd266e2a24c9dc9bb7b18f8
1415-Author: Josh Kearney <josh@jk0.org>
1416+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1417 Date: Fri Jun 24 14:48:14 2011 -0500
1418
1419 Refactored backup rotation.
1420@@ -7532,7 +8364,7 @@
1421 Implement backup with rotation.
1422
1423 commit 8a523431e3db9a1390933036532dc9f2ffacf17f
1424-Author: Josh Kearney <josh@jk0.org>
1425+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1426 Date: Fri Jun 24 13:27:02 2011 -0500
1427
1428 Review feedback.
1429@@ -7541,7 +8373,7 @@
1430 1 file changed, 4 insertions(+), 1 deletion(-)
1431
1432 commit 518ca43ef758c08b29d87ac238483d29ce3fc6ea
1433-Author: Josh Kearney <josh@jk0.org>
1434+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1435 Date: Fri Jun 24 13:22:20 2011 -0500
1436
1437 Fixed unit tests.
1438@@ -7571,13 +8403,13 @@
1439
1440 commit ff87b8c449cd5eee042d91c5dc4ad4f98bc184cb
1441 Merge: 787b369 04ef226
1442-Author: Josh Kearney <josh@jk0.org>
1443+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1444 Date: Fri Jun 24 12:25:45 2011 -0500
1445
1446 Merge branch 'backups'
1447
1448 commit 04ef22667633672d0f14eec49fe6ac3ef26200c6
1449-Author: Josh Kearney <josh@jk0.org>
1450+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1451 Date: Fri Jun 24 12:24:26 2011 -0500
1452
1453 Implemented backup with rotation.
1454@@ -7622,7 +8454,7 @@
1455
1456 commit 787b369e6c9cfd402f37ffe81bb54b18a8b55fdb
1457 Merge: a5ef8fc 9e86dd0
1458-Author: Josh Kearney <josh@jk0.org>
1459+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1460 Date: Thu Jun 23 16:10:53 2011 -0700
1461
1462 Merge pull request #21 from comstud/master
1463@@ -7631,7 +8463,7 @@
1464
1465 commit a5ef8fc5bc6e9c1a170d5fe617f09e4b6ae59258
1466 Merge: 459e51b 5b566a0
1467-Author: Josh Kearney <josh@jk0.org>
1468+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1469 Date: Thu Jun 23 16:10:06 2011 -0700
1470
1471 Merge pull request #21 from comstud/master
1472@@ -7793,7 +8625,7 @@
1473
1474 commit 4417c96e1e973a91c95de260228b243720fbb9f6
1475 Merge: 7edce02 6aa43b1
1476-Author: Josh Kearney <josh@jk0.org>
1477+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1478 Date: Fri Jun 17 08:46:46 2011 -0700
1479
1480 Merge pull request #19 from Cerberus98/instance_for_accounts
1481@@ -7894,14 +8726,14 @@
1482
1483 commit 3c10087824c7c04c47de92fa4fbb075afefce80f
1484 Merge: d778d42 c100f21
1485-Author: Josh Kearney <josh@jk0.org>
1486+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1487 Date: Thu Jun 9 12:59:05 2011 -0500
1488
1489 Merge branch 'master' of github.com:rackspace/python-novaclient
1490
1491 commit c100f21d3d01e661e92a7961a7963604d097be83
1492 Merge: 117e455 182b3a7
1493-Author: Josh Kearney <josh@jk0.org>
1494+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1495 Date: Thu Jun 9 10:11:09 2011 -0700
1496
1497 Merge pull request #12 from klmitch/master
1498@@ -7909,7 +8741,7 @@
1499 Add add_fixed_ip() and remove_fixed_ip() on servers
1500
1501 commit d778d4278e952b33cd0bd4fcc08a3e589fdbb223
1502-Author: Josh Kearney <josh@jk0.org>
1503+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1504 Date: Thu Jun 9 10:38:01 2011 -0500
1505
1506 Don't restrict ids to int.
1507@@ -8350,7 +9182,7 @@
1508
1509 commit 27709a3e245826b75c1397ef643c9b98f59b3a7c
1510 Merge: 560c314 c65a0a1
1511-Author: Josh Kearney <josh@jk0.org>
1512+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1513 Date: Thu Feb 17 16:12:16 2011 -0600
1514
1515 Merge remote branch 'SandyWalsh/master'
1516@@ -8375,7 +9207,7 @@
1517 2 files changed, 8 insertions(+), 1 deletion(-)
1518
1519 commit 560c314666d644975e531b40fe4d37a213583ea9
1520-Author: Josh Kearney <josh@jk0.org>
1521+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1522 Date: Wed Feb 16 11:10:13 2011 -0600
1523
1524 Added full flavor detail support
1525@@ -8572,7 +9404,7 @@
1526 1 file changed, 9 insertions(+)
1527
1528 commit 7304ed80df265b3b11a0018a826ce2e38c052572
1529-Author: Josh Kearney <josh@jk0.org>
1530+Author: Josh Kearney <josh.kearney@pistoncloud.com>
1531 Date: Tue Jan 25 14:01:22 2011 -0600
1532
1533 Initial commit from fork
1534
1535=== modified file 'PKG-INFO'
1536--- PKG-INFO 2012-09-27 08:59:05 +0000
1537+++ PKG-INFO 2012-11-30 14:02:33 +0000
1538@@ -1,6 +1,6 @@
1539 Metadata-Version: 1.1
1540 Name: python-novaclient
1541-Version: 2.9.0
1542+Version: 2.10.0
1543 Summary: Client library for OpenStack Nova API.
1544 Home-page: https://github.com/openstack/python-novaclient
1545 Author: Rackspace, based on work by Jacob Kaplan-Moss
1546@@ -269,6 +269,7 @@
1547 Platform: UNKNOWN
1548 Classifier: Development Status :: 5 - Production/Stable
1549 Classifier: Environment :: Console
1550+Classifier: Environment :: OpenStack
1551 Classifier: Intended Audience :: Developers
1552 Classifier: Intended Audience :: Information Technology
1553 Classifier: License :: OSI Approved :: Apache Software License
1554
1555=== modified file 'debian/changelog'
1556--- debian/changelog 2012-09-28 11:57:15 +0000
1557+++ debian/changelog 2012-11-30 14:02:33 +0000
1558@@ -1,3 +1,15 @@
1559+python-novaclient (1:2.10.0-0ubuntu1~cloud0) precise-grizzly; urgency=low
1560+
1561+ * New upstream release for the Ubuntu Cloud Archive.
1562+
1563+ -- Chuck Short <zulcss@ubuntu.com> Fri, 30 Nov 2012 08:00:21 -0600
1564+
1565+python-novaclient (1:2.10.0-0ubuntu1) raring; urgency=low
1566+
1567+ * New upstream release.
1568+
1569+ -- Chuck Short <zulcss@ubuntu.com> Thu, 29 Nov 2012 14:30:55 -0600
1570+
1571 python-novaclient (1:2.9.0-0ubuntu1~cloud0) precise-folsom; urgency=low
1572
1573 * New upstream snapshot for the Ubuntu Cloud Archive.
1574
1575=== modified file 'novaclient/client.py'
1576--- novaclient/client.py 2012-09-27 08:59:05 +0000
1577+++ novaclient/client.py 2012-11-30 14:02:33 +0000
1578@@ -95,6 +95,8 @@
1579 self.projectid = projectid
1580 if not auth_url and auth_system and auth_system != 'keystone':
1581 auth_url = get_auth_system_url(auth_system)
1582+ if not auth_url:
1583+ raise exceptions.EndpointNotFound()
1584 self.auth_url = auth_url.rstrip('/')
1585 self.version = 'v1.1'
1586 self.region_name = region_name
1587@@ -307,7 +309,7 @@
1588
1589 def authenticate(self):
1590 if has_keyring:
1591- keys = [self.auth_url, self.user, self.region_name,
1592+ keys = [self.auth_url, self.projectid, self.user, self.region_name,
1593 self.endpoint_type, self.service_type, self.service_name,
1594 self.volume_service_name]
1595 for index, key in enumerate(keys):
1596
1597=== modified file 'novaclient/openstack/common/setup.py'
1598--- novaclient/openstack/common/setup.py 2012-09-27 08:59:05 +0000
1599+++ novaclient/openstack/common/setup.py 2012-11-30 14:02:33 +0000
1600@@ -31,13 +31,13 @@
1601 def parse_mailmap(mailmap='.mailmap'):
1602 mapping = {}
1603 if os.path.exists(mailmap):
1604- fp = open(mailmap, 'r')
1605- for l in fp:
1606- l = l.strip()
1607- if not l.startswith('#') and ' ' in l:
1608- canonical_email, alias = ['%s>' % x.strip() for x in
1609- l.split('>')][:2]
1610- mapping[alias] = canonical_email
1611+ with open(mailmap, 'r') as fp:
1612+ for l in fp:
1613+ l = l.strip()
1614+ if not l.startswith('#') and ' ' in l:
1615+ canonical_email, alias = [x for x in l.split(' ')
1616+ if x.startswith('<')]
1617+ mapping[alias] = canonical_email
1618 return mapping
1619
1620
1621@@ -52,10 +52,10 @@
1622
1623 # Get requirements from the first file that exists
1624 def get_reqs_from_files(requirements_files):
1625- reqs_in = []
1626 for requirements_file in requirements_files:
1627 if os.path.exists(requirements_file):
1628- return open(requirements_file, 'r').read().split('\n')
1629+ with open(requirements_file, 'r') as fil:
1630+ return fil.read().split('\n')
1631 return []
1632
1633
1634@@ -140,11 +140,19 @@
1635 _run_shell_command("git fetch origin +refs/meta/*:refs/remotes/meta/*")
1636 milestone_cmd = "git show meta/openstack/release:%s" % branch_name
1637 milestonever = _run_shell_command(milestone_cmd)
1638- if not milestonever:
1639- milestonever = ""
1640+ if milestonever:
1641+ first_half = "%s~%s" % (milestonever, datestamp)
1642+ else:
1643+ first_half = datestamp
1644+
1645 post_version = _get_git_post_version()
1646- revno = post_version.split(".")[-1]
1647- return "%s~%s.%s%s" % (milestonever, datestamp, revno_prefix, revno)
1648+ # post version should look like:
1649+ # 0.1.1.4.gcc9e28a
1650+ # where the bit after the last . is the short sha, and the bit between
1651+ # the last and second to last is the revno count
1652+ (revno, sha) = post_version.split(".")[-2:]
1653+ second_half = "%s%s.%s" % (revno_prefix, revno, sha)
1654+ return ".".join((first_half, second_half))
1655
1656
1657 def _get_git_current_tag():
1658@@ -166,39 +174,48 @@
1659 cmd = "git --no-pager log --oneline"
1660 out = _run_shell_command(cmd)
1661 revno = len(out.split("\n"))
1662+ sha = _run_shell_command("git describe --always")
1663 else:
1664 tag_infos = tag_info.split("-")
1665 base_version = "-".join(tag_infos[:-2])
1666- revno = tag_infos[-2]
1667- return "%s.%s" % (base_version, revno)
1668+ (revno, sha) = tag_infos[-2:]
1669+ return "%s.%s.%s" % (base_version, revno, sha)
1670
1671
1672 def write_git_changelog():
1673 """Write a changelog based on the git changelog."""
1674- if os.path.isdir('.git'):
1675- git_log_cmd = 'git log --stat'
1676- changelog = _run_shell_command(git_log_cmd)
1677- mailmap = parse_mailmap()
1678- with open("ChangeLog", "w") as changelog_file:
1679- changelog_file.write(canonicalize_emails(changelog, mailmap))
1680+ new_changelog = 'ChangeLog'
1681+ if not os.getenv('SKIP_WRITE_GIT_CHANGELOG'):
1682+ if os.path.isdir('.git'):
1683+ git_log_cmd = 'git log --stat'
1684+ changelog = _run_shell_command(git_log_cmd)
1685+ mailmap = parse_mailmap()
1686+ with open(new_changelog, "w") as changelog_file:
1687+ changelog_file.write(canonicalize_emails(changelog, mailmap))
1688+ else:
1689+ open(new_changelog, 'w').close()
1690
1691
1692 def generate_authors():
1693 """Create AUTHORS file using git commits."""
1694- jenkins_email = 'jenkins@review.openstack.org'
1695+ jenkins_email = 'jenkins@review.(openstack|stackforge).org'
1696 old_authors = 'AUTHORS.in'
1697 new_authors = 'AUTHORS'
1698- if os.path.isdir('.git'):
1699- # don't include jenkins email address in AUTHORS file
1700- git_log_cmd = ("git log --format='%aN <%aE>' | sort -u | "
1701- "grep -v " + jenkins_email)
1702- changelog = _run_shell_command(git_log_cmd)
1703- mailmap = parse_mailmap()
1704- with open(new_authors, 'w') as new_authors_fh:
1705- new_authors_fh.write(canonicalize_emails(changelog, mailmap))
1706- if os.path.exists(old_authors):
1707- with open(old_authors, "r") as old_authors_fh:
1708- new_authors_fh.write('\n' + old_authors_fh.read())
1709+ if not os.getenv('SKIP_GENERATE_AUTHORS'):
1710+ if os.path.isdir('.git'):
1711+ # don't include jenkins email address in AUTHORS file
1712+ git_log_cmd = ("git log --format='%aN <%aE>' | sort -u | "
1713+ "egrep -v '" + jenkins_email + "'")
1714+ changelog = _run_shell_command(git_log_cmd)
1715+ mailmap = parse_mailmap()
1716+ with open(new_authors, 'w') as new_authors_fh:
1717+ new_authors_fh.write(canonicalize_emails(changelog, mailmap))
1718+ if os.path.exists(old_authors):
1719+ with open(old_authors, "r") as old_authors_fh:
1720+ new_authors_fh.write('\n' + old_authors_fh.read())
1721+ else:
1722+ open(new_authors, 'w').close()
1723+
1724
1725 _rst_template = """%(heading)s
1726 %(underline)s
1727@@ -212,7 +229,7 @@
1728
1729 def read_versioninfo(project):
1730 """Read the versioninfo file. If it doesn't exist, we're in a github
1731- zipball, and there's really know way to know what version we really
1732+ zipball, and there's really no way to know what version we really
1733 are, but that should be ok, because the utility of that should be
1734 just about nil if this code path is in use in the first place."""
1735 versioninfo_path = os.path.join(project, 'versioninfo')
1736@@ -226,7 +243,8 @@
1737
1738 def write_versioninfo(project, version):
1739 """Write a simple file containing the version of the package."""
1740- open(os.path.join(project, 'versioninfo'), 'w').write("%s\n" % version)
1741+ with open(os.path.join(project, 'versioninfo'), 'w') as fil:
1742+ fil.write("%s\n" % version)
1743
1744
1745 def get_cmdclass():
1746@@ -317,7 +335,8 @@
1747
1748
1749 def get_pre_version(projectname, base_version):
1750- """Return a version which is based"""
1751+ """Return a version which is leading up to a version that will
1752+ be released in the future."""
1753 if os.path.isdir('.git'):
1754 current_tag = _get_git_current_tag()
1755 if current_tag is not None:
1756@@ -329,10 +348,10 @@
1757 version_suffix = _get_git_next_version_suffix(branch_name)
1758 version = "%s~%s" % (base_version, version_suffix)
1759 write_versioninfo(projectname, version)
1760- return version.split('~')[0]
1761+ return version
1762 else:
1763 version = read_versioninfo(projectname)
1764- return version.split('~')[0]
1765+ return version
1766
1767
1768 def get_post_version(projectname):
1769
1770=== modified file 'novaclient/openstack/common/timeutils.py'
1771--- novaclient/openstack/common/timeutils.py 2012-09-07 18:32:24 +0000
1772+++ novaclient/openstack/common/timeutils.py 2012-11-30 14:02:33 +0000
1773@@ -62,9 +62,11 @@
1774
1775
1776 def normalize_time(timestamp):
1777- """Normalize time in arbitrary timezone to UTC"""
1778+ """Normalize time in arbitrary timezone to UTC naive object"""
1779 offset = timestamp.utcoffset()
1780- return timestamp.replace(tzinfo=None) - offset if offset else timestamp
1781+ if offset is None:
1782+ return timestamp
1783+ return timestamp.replace(tzinfo=None) - offset
1784
1785
1786 def is_older_than(before, seconds):
1787@@ -72,6 +74,11 @@
1788 return utcnow() - before > datetime.timedelta(seconds=seconds)
1789
1790
1791+def is_newer_than(after, seconds):
1792+ """Return True if after is newer than seconds."""
1793+ return after - utcnow() > datetime.timedelta(seconds=seconds)
1794+
1795+
1796 def utcnow_ts():
1797 """Timestamp version of our utcnow function."""
1798 return calendar.timegm(utcnow().timetuple())
1799@@ -121,6 +128,10 @@
1800
1801 def unmarshall_time(tyme):
1802 """Unmarshall a datetime dict."""
1803- return datetime.datetime(day=tyme['day'], month=tyme['month'],
1804- year=tyme['year'], hour=tyme['hour'], minute=tyme['minute'],
1805- second=tyme['second'], microsecond=tyme['microsecond'])
1806+ return datetime.datetime(day=tyme['day'],
1807+ month=tyme['month'],
1808+ year=tyme['year'],
1809+ hour=tyme['hour'],
1810+ minute=tyme['minute'],
1811+ second=tyme['second'],
1812+ microsecond=tyme['microsecond'])
1813
1814=== modified file 'novaclient/shell.py'
1815--- novaclient/shell.py 2012-09-27 08:59:05 +0000
1816+++ novaclient/shell.py 2012-11-30 14:02:33 +0000
1817@@ -24,6 +24,7 @@
1818 import imp
1819 import itertools
1820 import os
1821+import pkg_resources
1822 import pkgutil
1823 import sys
1824 import logging
1825@@ -257,7 +258,8 @@
1826 extensions = []
1827 for name, module in itertools.chain(
1828 self._discover_via_python_path(),
1829- self._discover_via_contrib_path(version)):
1830+ self._discover_via_contrib_path(version),
1831+ self._discover_via_entry_points()):
1832
1833 extension = novaclient.extension.Extension(name, module)
1834 extensions.append(extension)
1835@@ -289,6 +291,13 @@
1836 module = imp.load_source(name, ext_path)
1837 yield name, module
1838
1839+ def _discover_via_entry_points(self):
1840+ for ep in pkg_resources.iter_entry_points('novaclient.extension'):
1841+ name = ep.name
1842+ module = ep.load()
1843+
1844+ yield name, module
1845+
1846 def _add_bash_completion_subparser(self, subparsers):
1847 subparser = subparsers.add_parser('bash_completion',
1848 add_help=False,
1849@@ -356,7 +365,7 @@
1850 options.os_compute_api_version)
1851 self.parser = subcommand_parser
1852
1853- if options.help and len(args) == 0:
1854+ if options.help or not argv:
1855 subcommand_parser.print_help()
1856 return 0
1857
1858
1859=== modified file 'novaclient/utils.py'
1860--- novaclient/utils.py 2012-09-07 18:32:24 +0000
1861+++ novaclient/utils.py 2012-11-30 14:02:33 +0000
1862@@ -48,9 +48,13 @@
1863 if not val:
1864 return False
1865 try:
1866- return True if bool(int(val)) else False
1867+ return bool(int(val))
1868 except ValueError:
1869- return val.lower() in ['true', 'yes', 'y']
1870+ if val.lower() in ['true', 'yes', 'y']:
1871+ return True
1872+ if val.lower() in ['false', 'no', 'n']:
1873+ return False
1874+ raise
1875
1876
1877 def add_resource_manager_extra_kwargs_hook(f, hook):
1878@@ -171,10 +175,15 @@
1879 """Helper for the _find_* methods."""
1880 # first try to get entity as integer id
1881 try:
1882- if isinstance(name_or_id, int) or name_or_id.isdigit():
1883+ is_intid = isinstance(name_or_id, int) or name_or_id.isdigit()
1884+ except AttributeError:
1885+ is_intid = False
1886+
1887+ if is_intid:
1888+ try:
1889 return manager.get(int(name_or_id))
1890- except exceptions.NotFound:
1891- pass
1892+ except exceptions.NotFound:
1893+ pass
1894
1895 # now try to get entity as uuid
1896 try:
1897
1898=== modified file 'novaclient/v1_1/base.py'
1899--- novaclient/v1_1/base.py 2012-09-27 08:59:05 +0000
1900+++ novaclient/v1_1/base.py 2012-11-30 14:02:33 +0000
1901@@ -66,12 +66,14 @@
1902 """
1903 body = {"server": {
1904 "name": name,
1905- "imageRef": str(base.getid(image)),
1906+ "imageRef": str(base.getid(image)) if image else '',
1907 "flavorRef": str(base.getid(flavor)),
1908 }}
1909 if userdata:
1910 if hasattr(userdata, 'read'):
1911 userdata = userdata.read()
1912+ elif isinstance(userdata, unicode):
1913+ userdata = userdata.encode('utf-8')
1914 body["server"]["user_data"] = base64.b64encode(userdata)
1915 if meta:
1916 body["server"]["metadata"] = meta
1917
1918=== modified file 'novaclient/v1_1/client.py'
1919--- novaclient/v1_1/client.py 2012-09-07 18:32:24 +0000
1920+++ novaclient/v1_1/client.py 2012-11-30 14:02:33 +0000
1921@@ -7,6 +7,7 @@
1922 from novaclient.v1_1 import floating_ip_dns
1923 from novaclient.v1_1 import floating_ips
1924 from novaclient.v1_1 import floating_ip_pools
1925+from novaclient.v1_1 import fping
1926 from novaclient.v1_1 import hosts
1927 from novaclient.v1_1 import hypervisors
1928 from novaclient.v1_1 import images
1929@@ -23,6 +24,8 @@
1930 from novaclient.v1_1 import volumes
1931 from novaclient.v1_1 import volume_snapshots
1932 from novaclient.v1_1 import volume_types
1933+from novaclient.v1_1 import services
1934+from novaclient.v1_1 import fixed_ips
1935
1936
1937 class Client(object):
1938@@ -54,6 +57,7 @@
1939 # FIXME(comstud): Rename the api_key argument above when we
1940 # know it's not being used as keyword argument
1941 password = api_key
1942+ self.project_id = project_id
1943 self.flavors = flavors.FlavorManager(self)
1944 self.flavor_access = flavor_access.FlavorAccessManager(self)
1945 self.images = images.ImageManager(self)
1946@@ -67,6 +71,7 @@
1947 self.certs = certs.CertificateManager(self)
1948 self.floating_ips = floating_ips.FloatingIPManager(self)
1949 self.floating_ip_pools = floating_ip_pools.FloatingIPPoolManager(self)
1950+ self.fping = fping.FpingManager(self)
1951 self.volumes = volumes.VolumeManager(self)
1952 self.volume_snapshots = volume_snapshots.SnapshotManager(self)
1953 self.volume_types = volume_types.VolumeTypeManager(self)
1954@@ -83,6 +88,8 @@
1955 self.aggregates = aggregates.AggregateManager(self)
1956 self.hosts = hosts.HostManager(self)
1957 self.hypervisors = hypervisors.HypervisorManager(self)
1958+ self.services = services.ServiceManager(self)
1959+ self.fixed_ips = fixed_ips.FixedIPsManager(self)
1960
1961 # Add in any extensions...
1962 if extensions:
1963
1964=== modified file 'novaclient/v1_1/cloudpipe.py'
1965--- novaclient/v1_1/cloudpipe.py 2012-04-02 11:29:59 +0000
1966+++ novaclient/v1_1/cloudpipe.py 2012-11-30 14:02:33 +0000
1967@@ -16,6 +16,7 @@
1968 """Cloudpipe interface."""
1969
1970 from novaclient import base
1971+from novaclient.v1_1 import networks
1972
1973
1974 class Cloudpipe(base.Resource):
1975@@ -46,3 +47,16 @@
1976 Get a list of cloudpipe instances.
1977 """
1978 return self._list('/os-cloudpipe', 'cloudpipes')
1979+
1980+ def update(self, address, port):
1981+ """
1982+ Update VPN address and port for all networks associated
1983+ with the project defined by authentication
1984+
1985+ :param address: IP address
1986+ :param port: Port number
1987+ """
1988+
1989+ body = {'configure_project': {'vpn_ip': address,
1990+ 'vpn_port': port}}
1991+ self._update("/os-cloudpipe/configure-project", body)
1992
1993=== added file 'novaclient/v1_1/contrib/list_extensions.py'
1994--- novaclient/v1_1/contrib/list_extensions.py 1970-01-01 00:00:00 +0000
1995+++ novaclient/v1_1/contrib/list_extensions.py 2012-11-30 14:02:33 +0000
1996@@ -0,0 +1,46 @@
1997+# Copyright 2011 OpenStack LLC.
1998+# All Rights Reserved.
1999+#
2000+# Licensed under the Apache License, Version 2.0 (the "License"); you may
2001+# not use this file except in compliance with the License. You may obtain
2002+# a copy of the License at
2003+#
2004+# http://www.apache.org/licenses/LICENSE-2.0
2005+#
2006+# Unless required by applicable law or agreed to in writing, software
2007+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
2008+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
2009+# License for the specific language governing permissions and limitations
2010+# under the License.
2011+
2012+from novaclient import base
2013+from novaclient import utils
2014+
2015+
2016+class ListExtResource(base.Resource):
2017+ @property
2018+ def summary(self):
2019+ descr = self.description.strip()
2020+ if not descr:
2021+ return '??'
2022+ lines = descr.split("\n")
2023+ if len(lines) == 1:
2024+ return lines[0]
2025+ else:
2026+ return lines[0] + "..."
2027+
2028+
2029+class ListExtManager(base.Manager):
2030+ resource_class = ListExtResource
2031+
2032+ def show_all(self):
2033+ return self._list("/extensions", 'extensions')
2034+
2035+
2036+def do_list_extensions(client, _args):
2037+ """
2038+ List all the os-api extensions that are available.
2039+ """
2040+ extensions = client.list_extensions.show_all()
2041+ fields = ["Name", "Summary", "Alias", "Updated"]
2042+ utils.print_list(extensions, fields)
2043
2044=== added file 'novaclient/v1_1/fixed_ips.py'
2045--- novaclient/v1_1/fixed_ips.py 1970-01-01 00:00:00 +0000
2046+++ novaclient/v1_1/fixed_ips.py 2012-11-30 14:02:33 +0000
2047@@ -0,0 +1,58 @@
2048+# vim: tabstop=4 shiftwidth=4 softtabstop=4
2049+
2050+# Copyright 2012 IBM
2051+# All Rights Reserved.
2052+#
2053+# Licensed under the Apache License, Version 2.0 (the "License"); you may
2054+# not use this file except in compliance with the License. You may obtain
2055+# a copy of the License at
2056+#
2057+# http://www.apache.org/licenses/LICENSE-2.0
2058+#
2059+# Unless required by applicable law or agreed to in writing, software
2060+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
2061+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
2062+# License for the specific language governing permissions and limitations
2063+# under the License.
2064+
2065+"""
2066+Fixed IPs interface.
2067+"""
2068+
2069+from novaclient import base
2070+
2071+
2072+class FixedIP(base.Resource):
2073+ def __repr__(self):
2074+ return "<FixedIP: %s>" % self.address
2075+
2076+
2077+class FixedIPsManager(base.ManagerWithFind):
2078+ resource_class = FixedIP
2079+
2080+ def get(self, fixed_ip):
2081+ """
2082+ Show information for a Fixed IP
2083+
2084+ :param fixed_ip: Fixed IP address to get info for
2085+ """
2086+ return self._get('/os-fixed-ips/%s' % base.getid(fixed_ip),
2087+ "fixed_ip")
2088+
2089+ def reserve(self, fixed_ip):
2090+ """Reserve a Fixed IP
2091+
2092+ :param fixed_ip: Fixed IP address to reserve
2093+ """
2094+ body = {"reserve": None}
2095+ self.api.client.post('/os-fixed-ips/%s/action' % base.getid(fixed_ip),
2096+ body=body)
2097+
2098+ def unreserve(self, fixed_ip):
2099+ """Unreserve a Fixed IP
2100+
2101+ :param fixed_ip: Fixed IP address to unreserve
2102+ """
2103+ body = {"unreserve": None}
2104+ self.api.client.post('/os-fixed-ips/%s/action' % base.getid(fixed_ip),
2105+ body=body)
2106
2107=== modified file 'novaclient/v1_1/flavors.py'
2108--- novaclient/v1_1/flavors.py 2012-09-27 08:59:05 +0000
2109+++ novaclient/v1_1/flavors.py 2012-11-30 14:02:33 +0000
2110@@ -5,6 +5,7 @@
2111
2112 from novaclient import base
2113 from novaclient import exceptions
2114+from novaclient import utils
2115
2116
2117 class Flavor(base.Resource):
2118@@ -103,8 +104,8 @@
2119 """
2120 self._delete("/flavors/%s" % base.getid(flavor))
2121
2122- def create(self, name, ram, vcpus, disk, flavorid,
2123- ephemeral=0, swap=0, rxtx_factor=1, is_public=True):
2124+ def create(self, name, ram, vcpus, disk, flavorid=None,
2125+ ephemeral=0, swap=0, rxtx_factor=1.0, is_public=True):
2126 """
2127 Create (allocate) a floating ip for a tenant
2128
2129@@ -112,23 +113,63 @@
2130 :param ram: Memory in MB for the flavor
2131 :param vcpu: Number of VCPUs for the flavor
2132 :param disk: Size of local disk in GB
2133- :param flavorid: Integer ID for the flavor
2134+ :param flavorid: ID for the flavor (optional). You can use the reserved
2135+ value ``"auto"`` to have Nova generate a UUID for the
2136+ flavor in cases where you cannot simply pass ``None``.
2137 :param swap: Swap space in MB
2138 :param rxtx_factor: RX/TX factor
2139 :rtype: :class:`Flavor`
2140 """
2141
2142+ try:
2143+ ram = int(ram)
2144+ except:
2145+ raise exceptions.CommandError("Ram must be an integer.")
2146+
2147+ try:
2148+ vcpus = int(vcpus)
2149+ except:
2150+ raise exceptions.CommandError("VCPUs must be an integer.")
2151+
2152+ try:
2153+ disk = int(disk)
2154+ except:
2155+ raise exceptions.CommandError("Disk must be an integer.")
2156+
2157+ if flavorid == "auto":
2158+ flavorid = None
2159+
2160+ try:
2161+ swap = int(swap)
2162+ except:
2163+ raise exceptions.CommandError("Swap must be an integer.")
2164+
2165+ try:
2166+ ephemeral = int(ephemeral)
2167+ except:
2168+ raise exceptions.CommandError("Ephemeral must be an integer.")
2169+
2170+ try:
2171+ rxtx_factor = float(rxtx_factor)
2172+ except:
2173+ raise exceptions.CommandError("rxtx_factor must be a float.")
2174+
2175+ try:
2176+ is_public = utils.bool_from_str(is_public)
2177+ except:
2178+ raise exceptions.CommandError("is_public must be a boolean.")
2179+
2180 body = {
2181 "flavor": {
2182 "name": name,
2183- "ram": int(ram),
2184- "vcpus": int(vcpus),
2185- "disk": int(disk),
2186- "id": int(flavorid),
2187- "swap": int(swap),
2188- "OS-FLV-EXT-DATA:ephemeral": int(ephemeral),
2189- "rxtx_factor": int(rxtx_factor),
2190- "os-flavor-access:is_public": bool(is_public),
2191+ "ram": ram,
2192+ "vcpus": vcpus,
2193+ "disk": disk,
2194+ "id": flavorid,
2195+ "swap": swap,
2196+ "OS-FLV-EXT-DATA:ephemeral": ephemeral,
2197+ "rxtx_factor": rxtx_factor,
2198+ "os-flavor-access:is_public": is_public,
2199 }
2200 }
2201
2202
2203=== added file 'novaclient/v1_1/fping.py'
2204--- novaclient/v1_1/fping.py 1970-01-01 00:00:00 +0000
2205+++ novaclient/v1_1/fping.py 2012-11-30 14:02:33 +0000
2206@@ -0,0 +1,66 @@
2207+# vim: tabstop=4 shiftwidth=4 softtabstop=4
2208+
2209+# Copyright 2012 OpenStack LLC.
2210+# All Rights Reserved.
2211+#
2212+# Licensed under the Apache License, Version 2.0 (the "License"); you may
2213+# not use this file except in compliance with the License. You may obtain
2214+# a copy of the License at
2215+#
2216+# http://www.apache.org/licenses/LICENSE-2.0
2217+#
2218+# Unless required by applicable law or agreed to in writing, software
2219+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
2220+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
2221+# License for the specific language governing permissions and limitations
2222+# under the License.
2223+
2224+"""
2225+Fping interface.
2226+"""
2227+
2228+from novaclient import base
2229+
2230+
2231+class Fping(base.Resource):
2232+ """
2233+ A server to fping.
2234+ """
2235+ HUMAN_ID = True
2236+
2237+ def __repr__(self):
2238+ return "<Fping: %s>" % self.id
2239+
2240+
2241+class FpingManager(base.ManagerWithFind):
2242+ """
2243+ Manage :class:`Fping` resources.
2244+ """
2245+ resource_class = Fping
2246+
2247+ def list(self, all_tenants=False, include=[], exclude=[]):
2248+ """
2249+ Fping all servers.
2250+
2251+ :rtype: list of :class:`Fping`.
2252+ """
2253+ params = []
2254+ if all_tenants:
2255+ params.append("all_tenants=1")
2256+ if include:
2257+ params.append("include=%s" % ",".join(include))
2258+ elif exclude:
2259+ params.append("exclude=%s" % ",".join(exclude))
2260+ uri = "/os-fping"
2261+ if params:
2262+ uri = "%s?%s" % (uri, "&".join(params))
2263+ return self._list(uri, "servers")
2264+
2265+ def get(self, server):
2266+ """
2267+ Fping a specific server.
2268+
2269+ :param network: ID of the server to fping.
2270+ :rtype: :class:`Fping`
2271+ """
2272+ return self._get("/os-fping/%s" % base.getid(server), "server")
2273
2274=== modified file 'novaclient/v1_1/hosts.py'
2275--- novaclient/v1_1/hosts.py 2012-08-16 12:41:00 +0000
2276+++ novaclient/v1_1/hosts.py 2012-11-30 14:02:33 +0000
2277@@ -62,5 +62,8 @@
2278 url = "/os-hosts/%s/%s" % (host, action)
2279 return self._get(url)
2280
2281- def list_all(self):
2282- return self._list("/os-hosts", "hosts")
2283+ def list_all(self, zone=None):
2284+ url = '/os-hosts'
2285+ if zone:
2286+ url = '/os-hosts?zone=%s' % zone
2287+ return self._list(url, "hosts")
2288
2289=== modified file 'novaclient/v1_1/servers.py'
2290--- novaclient/v1_1/servers.py 2012-09-07 18:32:24 +0000
2291+++ novaclient/v1_1/servers.py 2012-11-30 14:02:33 +0000
2292@@ -215,7 +215,18 @@
2293 :param image_name: The name to assign the newly create image.
2294 :param metadata: Metadata to assign to the image.
2295 """
2296- self.manager.create_image(self, image_name, metadata)
2297+ return self.manager.create_image(self, image_name, metadata)
2298+
2299+ def backup(self, backup_name, backup_type, rotation):
2300+ """
2301+ Backup a server instance.
2302+
2303+ :param backup_name: Name of the backup image
2304+ :param backup_type: The backup type, like 'daily' or 'weekly'
2305+ :param rotation: Int parameter representing how many backups to
2306+ keep around.
2307+ """
2308+ self.manager.backup(self, backup_name, backup_type, rotation)
2309
2310 def confirm_resize(self):
2311 """
2312@@ -603,6 +614,21 @@
2313 image_uuid = location.split('/')[-1]
2314 return image_uuid
2315
2316+ def backup(self, server, backup_name, backup_type, rotation):
2317+ """
2318+ Backup a server instance.
2319+
2320+ :param server: The :class:`Server` (or its ID) to share onto.
2321+ :param backup_name: Name of the backup image
2322+ :param backup_type: The backup type, like 'daily' or 'weekly'
2323+ :param rotation: Int parameter representing how many backups to
2324+ keep around.
2325+ """
2326+ body = {'name': backup_name,
2327+ 'backup_type': backup_type,
2328+ 'rotation': rotation}
2329+ self._action('createBackup', server, body)
2330+
2331 def set_meta(self, server, metadata):
2332 """
2333 Set a servers metadata
2334
2335=== added file 'novaclient/v1_1/services.py'
2336--- novaclient/v1_1/services.py 1970-01-01 00:00:00 +0000
2337+++ novaclient/v1_1/services.py 2012-11-30 14:02:33 +0000
2338@@ -0,0 +1,62 @@
2339+# vim: tabstop=4 shiftwidth=4 softtabstop=4
2340+
2341+# Copyright 2012 IBM
2342+# All Rights Reserved.
2343+#
2344+# Licensed under the Apache License, Version 2.0 (the "License"); you may
2345+# not use this file except in compliance with the License. You may obtain
2346+# a copy of the License at
2347+#
2348+# http://www.apache.org/licenses/LICENSE-2.0
2349+#
2350+# Unless required by applicable law or agreed to in writing, software
2351+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
2352+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
2353+# License for the specific language governing permissions and limitations
2354+# under the License.
2355+
2356+"""
2357+service interface
2358+"""
2359+from novaclient import base
2360+
2361+
2362+class Service(base.Resource):
2363+ def __repr__(self):
2364+ return "<Service: %s>" % self.service
2365+
2366+ def _add_details(self, info):
2367+ dico = 'resource' in info and info['resource'] or info
2368+ for (k, v) in dico.items():
2369+ setattr(self, k, v)
2370+
2371+
2372+class ServiceManager(base.ManagerWithFind):
2373+ resource_class = Service
2374+
2375+ def list(self, host=None, service=None):
2376+ """
2377+ Describes cpu/memory/hdd info for host.
2378+
2379+ :param host: destination host name.
2380+ """
2381+ url = "/os-services"
2382+ if host:
2383+ url = "/os-services?host=%s" % host
2384+ if service:
2385+ url = "/os-services?service=%s" % service
2386+ if host and service:
2387+ url = "/os-services?host=%s&service=%s" % (host, service)
2388+ return self._list(url, "services")
2389+
2390+ def enable(self, host, service):
2391+ """Enable the service specified by hostname and servicename"""
2392+ body = {"host": host, "service": service}
2393+ result = self._update("/os-services/enable", body)
2394+ return self.resource_class(self, result)
2395+
2396+ def disable(self, host, service):
2397+ """Enable the service specified by hostname and servicename"""
2398+ body = {"host": host, "service": service}
2399+ result = self._update("/os-services/disable", body)
2400+ return self.resource_class(self, result)
2401
2402=== modified file 'novaclient/v1_1/shell.py'
2403--- novaclient/v1_1/shell.py 2012-09-27 08:59:05 +0000
2404+++ novaclient/v1_1/shell.py 2012-11-30 14:02:33 +0000
2405@@ -49,7 +49,11 @@
2406 raise exceptions.CommandError("you need to specify a Flavor ID ")
2407
2408 flavor = _find_flavor(cs, args.flavor)
2409- image = _find_image(cs, args.image)
2410+
2411+ if args.image:
2412+ image = _find_image(cs, args.image)
2413+ else:
2414+ image = None
2415
2416 meta = dict(v.split('=', 1) for v in args.meta)
2417
2418@@ -199,7 +203,7 @@
2419 metavar='<key=value>',
2420 help="Send arbitrary key/value pairs to the scheduler for custom use.")
2421 @utils.arg('--nic',
2422- metavar="<net-id=net-uuid,v4-fixed-ip=ip-addr>",
2423+ metavar="<net-id=net-uuid,v4-fixed-ip=ip-addr,port-id=port-uuid>",
2424 action='append',
2425 dest='nics',
2426 default=[],
2427@@ -237,8 +241,11 @@
2428 info['flavor'] = _find_flavor(cs, flavor_id).name
2429
2430 image = info.get('image', {})
2431- image_id = image.get('id', '')
2432- info['image'] = _find_image(cs, image_id).name
2433+ if image:
2434+ image_id = image.get('id', '')
2435+ info['image'] = _find_image(cs, image_id).name
2436+ else: # Booting from volume
2437+ info['image'] = "Attempt to boot from volume - no image supplied"
2438
2439 info.pop('links', None)
2440 info.pop('addresses', None)
2441@@ -262,6 +269,13 @@
2442 cs.cloudpipe.create(args.project)
2443
2444
2445+@utils.arg('address', metavar='<ip address>', help='New IP Address.')
2446+@utils.arg('port', metavar='<port>', help='New Port.')
2447+def do_cloudpipe_configure(cs, args):
2448+ """Create a cloudpipe instance for the given project"""
2449+ cs.cloudpipe.update(args.address, args.port)
2450+
2451+
2452 def _poll_for_status(poll_fn, obj_id, action, final_ok_states,
2453 poll_period=5, show_progress=True,
2454 status_field="status", silent=False):
2455@@ -341,9 +355,6 @@
2456 def do_flavor_list(cs, _args):
2457 """Print a list of available 'flavors' (sizes of servers)."""
2458 flavors = cs.flavors.list()
2459- for flavor in flavors:
2460- # int needed for numerical sort
2461- flavor.id = int(flavor.id)
2462 _print_flavor_list(cs, flavors)
2463
2464
2465@@ -390,7 +401,7 @@
2466 @utils.arg('--rxtx-factor',
2467 metavar='<factor>',
2468 help="RX/TX factor (default 1)",
2469- default=1)
2470+ default=1.0)
2471 @utils.arg('--is-public',
2472 metavar='<is-public>',
2473 help="Make flavor accessible to the public (default true)",
2474@@ -620,12 +631,12 @@
2475 dest='ip',
2476 metavar='<ip-regexp>',
2477 default=None,
2478- help='Search with regular expression match by IP address')
2479+ help='Search with regular expression match by IP address (Admin only).')
2480 @utils.arg('--ip6',
2481 dest='ip6',
2482 metavar='<ip6-regexp>',
2483 default=None,
2484- help='Search with regular expression match by IPv6 address')
2485+ help='Search with regular expression match by IPv6 address (Admin only).')
2486 @utils.arg('--name',
2487 dest='name',
2488 metavar='<name-regexp>',
2489@@ -635,7 +646,7 @@
2490 dest='instance_name',
2491 metavar='<name-regexp>',
2492 default=None,
2493- help='Search with regular expression match by instance name')
2494+ help='Search with regular expression match by instance name (Admin only).')
2495 @utils.arg('--instance_name',
2496 help=argparse.SUPPRESS)
2497 @utils.arg('--status',
2498@@ -658,25 +669,31 @@
2499 dest='host',
2500 metavar='<hostname>',
2501 default=None,
2502- help='Search instances by hostname to which they are assigned')
2503+ help='Search instances by hostname to which they are assigned '
2504+ '(Admin only).')
2505 @utils.arg('--all-tenants',
2506 dest='all_tenants',
2507 metavar='<0|1>',
2508 nargs='?',
2509 type=int,
2510 const=1,
2511- default=0,
2512+ default=int(utils.bool_from_str(os.environ.get("ALL_TENANTS", 'false'))),
2513 help='Display information from all tenants (Admin only).')
2514 @utils.arg('--all_tenants',
2515 nargs='?',
2516 type=int,
2517 const=1,
2518 help=argparse.SUPPRESS)
2519+@utils.arg('--tenant',
2520+ #nova db searches by project_id
2521+ dest='tenant',
2522+ metavar='<tenant>',
2523+ nargs='?',
2524+ help='Display information from single tenant (Admin only).')
2525 def do_list(cs, args):
2526 """List active servers."""
2527- all_tenants = int(os.environ.get("ALL_TENANTS", args.all_tenants))
2528 search_opts = {
2529- 'all_tenants': all_tenants,
2530+ 'all_tenants': args.all_tenants,
2531 'reservation_id': args.reservation_id,
2532 'ip': args.ip,
2533 'ip6': args.ip6,
2534@@ -684,6 +701,7 @@
2535 'image': args.image,
2536 'flavor': args.flavor,
2537 'status': args.status,
2538+ 'project_id': args.tenant,
2539 'host': args.host,
2540 'instance_name': args.instance_name}
2541
2542@@ -799,7 +817,7 @@
2543 default=False,
2544 help='Blocks while instance migrates so progress can be reported.')
2545 def do_migrate(cs, args):
2546- """Migrate a server."""
2547+ """Migrate a server. The new host will be selected by the scheduler."""
2548 server = _find_server(cs, args.server)
2549 server.migrate()
2550
2551@@ -929,6 +947,19 @@
2552 show_progress=False, silent=True)
2553
2554
2555+@utils.arg('server', metavar='<server>', help='Name or ID of server.')
2556+@utils.arg('name', metavar='<name>', help='Name of the backup image.')
2557+@utils.arg('backup_type', metavar='<backup-type>',
2558+ help='The backup type, like "daily" or "weekly".')
2559+@utils.arg('rotation', metavar='<rotation>',
2560+ help='Int parameter representing how many backups to keep around.')
2561+def do_backup(cs, args):
2562+ """ Backup a instance by create a 'backup' type snapshot """
2563+ _find_server(cs, args.server).backup(args.name,
2564+ args.backup_type,
2565+ args.rotation)
2566+
2567+
2568 @utils.arg('server',
2569 metavar='<server>',
2570 help="Name or ID of server")
2571@@ -975,15 +1006,18 @@
2572 flavor_id)
2573
2574 image = info.get('image', {})
2575- image_id = image.get('id', '')
2576- if args.minimal:
2577- info['image'] = image_id
2578- else:
2579- try:
2580- info['image'] = '%s (%s)' % (_find_image(cs, image_id).name,
2581- image_id)
2582- except Exception:
2583- info['image'] = '%s (%s)' % ("Image not found", image_id)
2584+ if image:
2585+ image_id = image.get('id', '')
2586+ if args.minimal:
2587+ info['image'] = image_id
2588+ else:
2589+ try:
2590+ info['image'] = '%s (%s)' % (_find_image(cs, image_id).name,
2591+ image_id)
2592+ except Exception:
2593+ info['image'] = '%s (%s)' % ("Image not found", image_id)
2594+ else: # Booted from volume
2595+ info['image'] = "Attempt to boot from volume - no image supplied"
2596
2597 info.pop('links', None)
2598 info.pop('addresses', None)
2599@@ -1002,10 +1036,15 @@
2600 _print_server(cs, args)
2601
2602
2603-@utils.arg('server', metavar='<server>', help='Name or ID of server.')
2604+@utils.arg('server', metavar='<server>', nargs='+',
2605+ help='Name or ID of server(s).')
2606 def do_delete(cs, args):
2607- """Immediately shut down and delete a server."""
2608- _find_server(cs, args.server).delete()
2609+ """Immediately shut down and delete specified server(s)."""
2610+ for server in args.server:
2611+ try:
2612+ _find_server(cs, server).delete()
2613+ except Exception, e:
2614+ print e
2615
2616
2617 def _find_server(cs, server):
2618@@ -1080,10 +1119,24 @@
2619 setattr(item, to_key, item._info[from_key])
2620
2621
2622+@utils.arg('--all-tenants',
2623+ dest='all_tenants',
2624+ metavar='<0|1>',
2625+ nargs='?',
2626+ type=int,
2627+ const=1,
2628+ default=int(utils.bool_from_str(os.environ.get("ALL_TENANTS", 'false'))),
2629+ help='Display information from all tenants (Admin only).')
2630+@utils.arg('--all_tenants',
2631+ nargs='?',
2632+ type=int,
2633+ const=1,
2634+ help=argparse.SUPPRESS)
2635 @utils.service_type('volume')
2636-def do_volume_list(cs, _args):
2637+def do_volume_list(cs, args):
2638 """List all the volumes."""
2639- volumes = cs.volumes.list()
2640+ search_opts = {'all_tenants': args.all_tenants}
2641+ volumes = cs.volumes.list(search_opts=search_opts)
2642 _translate_volume_keys(volumes)
2643
2644 # Create a list of servers to which the volume is attached
2645@@ -1553,7 +1606,7 @@
2646 nargs='?',
2647 type=int,
2648 const=1,
2649- default=0,
2650+ default=int(utils.bool_from_str(os.environ.get("ALL_TENANTS", 'false'))),
2651 help='Display information from all tenants (Admin only).')
2652 @utils.arg('--all_tenants',
2653 nargs='?',
2654@@ -1562,8 +1615,7 @@
2655 help=argparse.SUPPRESS)
2656 def do_secgroup_list(cs, args):
2657 """List security groups for the current tenant."""
2658- all_tenants = int(os.environ.get("ALL_TENANTS", args.all_tenants))
2659- search_opts = {'all_tenants': all_tenants}
2660+ search_opts = {'all_tenants': args.all_tenants}
2661 _print_secgroups(cs.security_groups.list(search_opts=search_opts))
2662
2663
2664@@ -1849,7 +1901,7 @@
2665 _print_aggregate_details(aggregate)
2666
2667
2668-@utils.arg('id', metavar='<id>', help='Host aggregate id to delete.')
2669+@utils.arg('id', metavar='<id>', help='Aggregate id.')
2670 @utils.arg('host', metavar='<host>', help='The host to add to the aggregate.')
2671 def do_aggregate_add_host(cs, args):
2672 """Add the host to the specified aggregate."""
2673@@ -1858,8 +1910,9 @@
2674 _print_aggregate_details(aggregate)
2675
2676
2677-@utils.arg('id', metavar='<id>', help='Host aggregate id to delete.')
2678-@utils.arg('host', metavar='<host>', help='The host to add to the aggregate.')
2679+@utils.arg('id', metavar='<id>', help='Aggregate id.')
2680+@utils.arg('host', metavar='<host>',
2681+ help='The host to remove from the aggregate.')
2682 def do_aggregate_remove_host(cs, args):
2683 """Remove the specified host from the specified aggregate."""
2684 aggregate = cs.aggregates.remove_host(args.id, args.host)
2685@@ -1867,7 +1920,7 @@
2686 _print_aggregate_details(aggregate)
2687
2688
2689-@utils.arg('id', metavar='<id>', help='Host aggregate id to delete.')
2690+@utils.arg('id', metavar='<id>', help='Aggregate id.')
2691 def do_aggregate_details(cs, args):
2692 """Show details of the specified aggregate."""
2693 _print_aggregate_details(cs.aggregates.get_details(args.id))
2694@@ -1893,7 +1946,7 @@
2695 action='store_true',
2696 dest='disk_over_commit',
2697 default=False,
2698- help='Allow overcommit.(Default=Flase)')
2699+ help='Allow overcommit.(Default=False)')
2700 @utils.arg('--disk_over_commit',
2701 action='store_true',
2702 help=argparse.SUPPRESS)
2703@@ -1914,6 +1967,52 @@
2704 _find_server(cs, args.server).reset_state(args.state)
2705
2706
2707+@utils.arg('--host', metavar='<hostname>', default=None,
2708+ help='Name of host.')
2709+@utils.arg('--servicename', metavar='<servicename>', default=None,
2710+ help='Name of service.')
2711+def do_service_list(cs, args):
2712+ """Show a list of all running services. Filter by host & service name."""
2713+ result = cs.services.list(args.host, args.servicename)
2714+ columns = ["Binary", "Host", "Zone", "Status", "State", "Updated_at"]
2715+ utils.print_list(result, columns)
2716+
2717+
2718+@utils.arg('host', metavar='<hostname>', help='Name of host.')
2719+@utils.arg('service', metavar='<servicename>', help='Name of service.')
2720+def do_service_enable(cs, args):
2721+ """Enable the service"""
2722+ result = cs.services.enable(args.host, args.service)
2723+ utils.print_list([result], ['Host', 'Service', 'Disabled'])
2724+
2725+
2726+@utils.arg('host', metavar='<hostname>', help='Name of host.')
2727+@utils.arg('service', metavar='<servicename>', help='Name of service.')
2728+def do_service_disable(cs, args):
2729+ """Enable the service"""
2730+ result = cs.services.disable(args.host, args.service)
2731+ utils.print_list([result], ['Host', 'Service', 'Disabled'])
2732+
2733+
2734+@utils.arg('fixed_ip', metavar='<fixed_ip>', help='Fixed IP Address.')
2735+def do_fixed_ip_get(cs, args):
2736+ """Get info on a fixed ip"""
2737+ result = cs.fixed_ips.get(args.fixed_ip)
2738+ utils.print_list([result], ['address', 'cidr', 'hostname', 'host'])
2739+
2740+
2741+@utils.arg('fixed_ip', metavar='<fixed_ip>', help='Fixed IP Address.')
2742+def do_fixed_ip_reserve(cs, args):
2743+ """Reserve a fixed ip"""
2744+ cs.fixed_ips.reserve(args.fixed_ip)
2745+
2746+
2747+@utils.arg('fixed_ip', metavar='<fixed_ip>', help='Fixed IP Address.')
2748+def do_fixed_ip_unreserve(cs, args):
2749+ """Unreserve a fixed ip"""
2750+ cs.fixed_ips.unreserve(args.fixed_ip)
2751+
2752+
2753 @utils.arg('host', metavar='<hostname>', help='Name of host.')
2754 def do_host_describe(cs, args):
2755 """Describe a specific host"""
2756@@ -1922,10 +2021,13 @@
2757 utils.print_list(result, columns)
2758
2759
2760+@utils.arg('--zone', metavar='<zone>', default=None,
2761+ help='Filters the list, returning only those '
2762+ 'hosts in the availability zone <zone>.')
2763 def do_host_list(cs, args):
2764 """List all hosts by service"""
2765- columns = ["host_name", "service"]
2766- result = cs.hosts.list_all()
2767+ columns = ["host_name", "service", "zone"]
2768+ result = cs.hosts.list_all(args.zone)
2769 utils.print_list(result, columns)
2770
2771
2772@@ -1989,7 +2091,8 @@
2773 for hyper in hypers:
2774 hyper_host = hyper.hypervisor_hostname
2775 hyper_id = hyper.id
2776- instances.extend([InstanceOnHyper(id=serv['uuid'],
2777+ if hasattr(hyper, 'servers'):
2778+ instances.extend([InstanceOnHyper(id=serv['uuid'],
2779 name=serv['name'],
2780 hypervisor_hostname=hyper_host,
2781 hypervisor_id=hyper_id)
2782@@ -2082,6 +2185,10 @@
2783 dest='identity',
2784 help='Private key file, same as the -i option to the ssh command.',
2785 default='')
2786+@utils.arg('--extra-opts',
2787+ dest='extra',
2788+ help='Extra options to pass to ssh. see: man ssh',
2789+ default='')
2790 def do_ssh(cs, args):
2791 """SSH into a server."""
2792 addresses = _find_server(cs, args.server).addresses
2793@@ -2102,8 +2209,9 @@
2794 identity = '-i %s' % args.identity if len(args.identity) else ''
2795
2796 if ip_address:
2797- os.system("ssh -%d -p%d %s %s@%s" % (version, args.port, identity,
2798- args.login, ip_address))
2799+ os.system("ssh -%d -p%d %s %s@%s %s" % (version, args.port, identity,
2800+ args.login, ip_address,
2801+ args.extra))
2802 else:
2803 pretty_version = "IPv%d" % version
2804 print "ERROR: No %s %s address found." % (address_type,
2805@@ -2119,7 +2227,10 @@
2806 def _quota_show(quotas):
2807 quota_dict = {}
2808 for resource in _quota_resources:
2809- quota_dict[resource] = getattr(quotas, resource, None)
2810+ try:
2811+ quota_dict[resource] = getattr(quotas, resource)
2812+ except AttributeError:
2813+ pass
2814 utils.print_dict(quota_dict)
2815
2816
2817@@ -2134,22 +2245,30 @@
2818 manager.update(identifier, **updates)
2819
2820
2821-@utils.arg('tenant',
2822+@utils.arg('--tenant',
2823 metavar='<tenant-id>',
2824- help='UUID of tenant to list the quotas for.')
2825+ default=None,
2826+ help='UUID or name of tenant to list the quotas for.')
2827 def do_quota_show(cs, args):
2828 """List the quotas for a tenant."""
2829
2830- _quota_show(cs.quotas.get(args.tenant))
2831-
2832-
2833-@utils.arg('tenant',
2834+ if not args.tenant:
2835+ _quota_show(cs.quotas.get(cs.project_id))
2836+ else:
2837+ _quota_show(cs.quotas.get(args.tenant))
2838+
2839+
2840+@utils.arg('--tenant',
2841 metavar='<tenant-id>',
2842- help='UUID of tenant to list the default quotas for.')
2843+ default=None,
2844+ help='UUID or name of tenant to list the default quotas for.')
2845 def do_quota_defaults(cs, args):
2846 """List the default quotas for a tenant."""
2847
2848- _quota_show(cs.quotas.defaults(args.tenant))
2849+ if not args.tenant:
2850+ _quota_show(cs.quotas.defaults(cs.project_id))
2851+ else:
2852+ _quota_show(cs.quotas.defaults(args.tenant))
2853
2854
2855 @utils.arg('tenant',
2856
2857=== modified file 'novaclient/v1_1/volumes.py'
2858--- novaclient/v1_1/volumes.py 2012-09-07 18:32:24 +0000
2859+++ novaclient/v1_1/volumes.py 2012-11-30 14:02:33 +0000
2860@@ -17,6 +17,8 @@
2861 Volume interface (1.1 extension).
2862 """
2863
2864+import urllib
2865+
2866 from novaclient import base
2867
2868
2869@@ -76,16 +78,22 @@
2870 """
2871 return self._get("/volumes/%s" % volume_id, "volume")
2872
2873- def list(self, detailed=True):
2874+ def list(self, detailed=True, search_opts=None):
2875 """
2876 Get a list of all volumes.
2877
2878 :rtype: list of :class:`Volume`
2879 """
2880+ search_opts = search_opts or {}
2881+
2882+ qparams = dict((k, v) for (k, v) in search_opts.iteritems() if v)
2883+
2884+ query_string = '?%s' % urllib.urlencode(qparams) if qparams else ''
2885+
2886 if detailed is True:
2887- return self._list("/volumes/detail", "volumes")
2888+ return self._list("/volumes/detail%s" % query_string, "volumes")
2889 else:
2890- return self._list("/volumes", "volumes")
2891+ return self._list("/volumes%s" % query_string, "volumes")
2892
2893 def delete(self, volume):
2894 """
2895
2896=== modified file 'novaclient/versioninfo'
2897--- novaclient/versioninfo 2012-09-27 08:59:05 +0000
2898+++ novaclient/versioninfo 2012-11-30 14:02:33 +0000
2899@@ -1,1 +1,1 @@
2900-2.9.0
2901+2.10.0
2902
2903=== modified file 'python_novaclient.egg-info/PKG-INFO'
2904--- python_novaclient.egg-info/PKG-INFO 2012-09-27 08:59:05 +0000
2905+++ python_novaclient.egg-info/PKG-INFO 2012-11-30 14:02:33 +0000
2906@@ -1,6 +1,6 @@
2907 Metadata-Version: 1.1
2908 Name: python-novaclient
2909-Version: 2.9.0
2910+Version: 2.10.0
2911 Summary: Client library for OpenStack Nova API.
2912 Home-page: https://github.com/openstack/python-novaclient
2913 Author: Rackspace, based on work by Jacob Kaplan-Moss
2914@@ -269,6 +269,7 @@
2915 Platform: UNKNOWN
2916 Classifier: Development Status :: 5 - Production/Stable
2917 Classifier: Environment :: Console
2918+Classifier: Environment :: OpenStack
2919 Classifier: Intended Audience :: Developers
2920 Classifier: Intended Audience :: Information Technology
2921 Classifier: License :: OSI Approved :: Apache Software License
2922
2923=== modified file 'python_novaclient.egg-info/SOURCES.txt'
2924--- python_novaclient.egg-info/SOURCES.txt 2012-09-07 18:32:24 +0000
2925+++ python_novaclient.egg-info/SOURCES.txt 2012-11-30 14:02:33 +0000
2926@@ -45,11 +45,13 @@
2927 novaclient/v1_1/certs.py
2928 novaclient/v1_1/client.py
2929 novaclient/v1_1/cloudpipe.py
2930+novaclient/v1_1/fixed_ips.py
2931 novaclient/v1_1/flavor_access.py
2932 novaclient/v1_1/flavors.py
2933 novaclient/v1_1/floating_ip_dns.py
2934 novaclient/v1_1/floating_ip_pools.py
2935 novaclient/v1_1/floating_ips.py
2936+novaclient/v1_1/fping.py
2937 novaclient/v1_1/hosts.py
2938 novaclient/v1_1/hypervisors.py
2939 novaclient/v1_1/images.py
2940@@ -61,6 +63,7 @@
2941 novaclient/v1_1/security_group_rules.py
2942 novaclient/v1_1/security_groups.py
2943 novaclient/v1_1/servers.py
2944+novaclient/v1_1/services.py
2945 novaclient/v1_1/shell.py
2946 novaclient/v1_1/usage.py
2947 novaclient/v1_1/virtual_interfaces.py
2948@@ -68,6 +71,7 @@
2949 novaclient/v1_1/volume_types.py
2950 novaclient/v1_1/volumes.py
2951 novaclient/v1_1/contrib/__init__.py
2952+novaclient/v1_1/contrib/list_extensions.py
2953 python_novaclient.egg-info/PKG-INFO
2954 python_novaclient.egg-info/SOURCES.txt
2955 python_novaclient.egg-info/dependency_links.txt
2956@@ -79,6 +83,7 @@
2957 tests/test_auth_plugins.py
2958 tests/test_base.py
2959 tests/test_client.py
2960+tests/test_discover.py
2961 tests/test_http.py
2962 tests/test_service_catalog.py
2963 tests/test_shell.py
2964@@ -90,11 +95,13 @@
2965 tests/v1_1/test_auth.py
2966 tests/v1_1/test_certs.py
2967 tests/v1_1/test_cloudpipe.py
2968+tests/v1_1/test_fixed_ips.py
2969 tests/v1_1/test_flavor_access.py
2970 tests/v1_1/test_flavors.py
2971 tests/v1_1/test_floating_ip_dns.py
2972 tests/v1_1/test_floating_ip_pools.py
2973 tests/v1_1/test_floating_ips.py
2974+tests/v1_1/test_fping.py
2975 tests/v1_1/test_hosts.py
2976 tests/v1_1/test_hypervisors.py
2977 tests/v1_1/test_images.py
2978@@ -106,10 +113,13 @@
2979 tests/v1_1/test_security_group_rules.py
2980 tests/v1_1/test_security_groups.py
2981 tests/v1_1/test_servers.py
2982+tests/v1_1/test_services.py
2983 tests/v1_1/test_shell.py
2984 tests/v1_1/test_usage.py
2985 tests/v1_1/testfile.txt
2986 tests/v1_1/utils.py
2987+tests/v1_1/contrib/__init__.py
2988+tests/v1_1/contrib/test_list_extensions.py
2989 tools/install_venv.py
2990 tools/nova.bash_completion
2991 tools/pip-requires
2992
2993=== modified file 'setup.py'
2994--- setup.py 2012-09-07 18:32:24 +0000
2995+++ setup.py 2012-11-30 14:02:33 +0000
2996@@ -39,6 +39,7 @@
2997 classifiers=[
2998 "Development Status :: 5 - Production/Stable",
2999 "Environment :: Console",
3000+ "Environment :: OpenStack",
3001 "Intended Audience :: Developers",
3002 "Intended Audience :: Information Technology",
3003 "License :: OSI Approved :: Apache Software License",
3004
3005=== modified file 'tests/test_auth_plugins.py'
3006--- tests/test_auth_plugins.py 2012-08-16 12:41:00 +0000
3007+++ tests/test_auth_plugins.py 2012-11-30 14:02:33 +0000
3008@@ -157,3 +157,26 @@
3009 self.assertEquals(cs.client.auth_url, "http://faked/v2.0")
3010
3011 test_auth_call()
3012+
3013+ def test_auth_system_raises_exception_when_missing_auth_url(self):
3014+ class MockAuthUrlEntrypoint(pkg_resources.EntryPoint):
3015+ def load(self):
3016+ return self.auth_url
3017+
3018+ def auth_url(self):
3019+ return None
3020+
3021+ def mock_iter_entry_points(_type):
3022+ return [MockAuthUrlEntrypoint("fakewithauthurl",
3023+ "fakewithauthurl.plugin",
3024+ ["auth_url"])]
3025+
3026+ @mock.patch.object(pkg_resources, "iter_entry_points",
3027+ mock_iter_entry_points)
3028+ def test_auth_call():
3029+ with self.assertRaises(exceptions.EndpointNotFound):
3030+ cs = client.Client("username", "password", "project_id",
3031+ auth_system="fakewithauthurl",
3032+ no_cache=True)
3033+
3034+ test_auth_call()
3035
3036=== added file 'tests/test_discover.py'
3037--- tests/test_discover.py 1970-01-01 00:00:00 +0000
3038+++ tests/test_discover.py 2012-11-30 14:02:33 +0000
3039@@ -0,0 +1,79 @@
3040+# Copyright 2012 OpenStack LLC.
3041+# All Rights Reserved.
3042+#
3043+# Licensed under the Apache License, Version 2.0 (the "License"); you may
3044+# not use this file except in compliance with the License. You may obtain
3045+# a copy of the License at
3046+#
3047+# http://www.apache.org/licenses/LICENSE-2.0
3048+#
3049+# Unless required by applicable law or agreed to in writing, software
3050+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
3051+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
3052+# License for the specific language governing permissions and limitations
3053+# under the License.
3054+
3055+import mock
3056+import imp
3057+import inspect
3058+import pkg_resources
3059+
3060+import novaclient.shell
3061+from tests import utils
3062+
3063+
3064+class DiscoverTest(utils.TestCase):
3065+
3066+ def test_discover_via_entry_points(self):
3067+
3068+ def mock_iter_entry_points(group):
3069+ if group == 'novaclient.extension':
3070+ fake_ep = mock.Mock()
3071+ fake_ep.name = 'foo'
3072+ fake_ep.module = imp.new_module('foo')
3073+ fake_ep.load.return_value = fake_ep.module
3074+ return [fake_ep]
3075+
3076+ @mock.patch.object(pkg_resources, 'iter_entry_points',
3077+ mock_iter_entry_points)
3078+ def test():
3079+ shell = novaclient.shell.OpenStackComputeShell()
3080+ for name, module in shell._discover_via_entry_points():
3081+ self.assertEqual(name, 'foo')
3082+ self.assertTrue(inspect.ismodule(module))
3083+
3084+ test()
3085+
3086+ def test_discover_extensions(self):
3087+
3088+ def mock_discover_via_python_path(self):
3089+ yield 'foo', imp.new_module('foo')
3090+
3091+ def mock_discover_via_contrib_path(self, version):
3092+ yield 'bar', imp.new_module('bar')
3093+
3094+ def mock_discover_via_entry_points(self):
3095+ yield 'baz', imp.new_module('baz')
3096+
3097+ @mock.patch.object(novaclient.shell.OpenStackComputeShell,
3098+ '_discover_via_python_path',
3099+ mock_discover_via_python_path)
3100+ @mock.patch.object(novaclient.shell.OpenStackComputeShell,
3101+ '_discover_via_contrib_path',
3102+ mock_discover_via_contrib_path)
3103+ @mock.patch.object(novaclient.shell.OpenStackComputeShell,
3104+ '_discover_via_entry_points',
3105+ mock_discover_via_entry_points)
3106+ def test():
3107+ shell = novaclient.shell.OpenStackComputeShell()
3108+ extensions = shell._discover_extensions('1.1')
3109+ self.assertEqual(len(extensions), 3)
3110+ names = sorted(['foo', 'bar', 'baz'])
3111+ sorted_extensions = sorted(extensions, key=lambda ext: ext.name)
3112+ for i in range(len(names)):
3113+ ext = sorted_extensions[i]
3114+ name = names[i]
3115+ self.assertEqual(ext.name, name)
3116+ self.assertTrue(inspect.ismodule(ext.module))
3117+
3118+ test()
3119
3120=== modified file 'tests/test_shell.py'
3121--- tests/test_shell.py 2012-05-24 13:30:51 +0000
3122+++ tests/test_shell.py 2012-11-30 14:02:33 +0000
3123@@ -55,10 +55,9 @@
3124 '(?m)^\s+root-password\s+Change the root password',
3125 '(?m)^See "nova help COMMAND" for help on a specific command',
3126 ]
3127- for argstr in ['--help', 'help']:
3128- help_text = self.shell(argstr)
3129- for r in required:
3130- self.assertRegexpMatches(help_text, r)
3131+ help_text = self.shell('help')
3132+ for r in required:
3133+ self.assertRegexpMatches(help_text, r)
3134
3135 def test_help_on_subcommand(self):
3136 required = [
3137@@ -66,11 +65,6 @@
3138 '(?m)^Change the root password',
3139 '(?m)^Positional arguments:',
3140 ]
3141- argstrings = [
3142- 'root-password --help',
3143- 'help root-password',
3144- ]
3145- for argstr in argstrings:
3146- help_text = self.shell(argstr)
3147- for r in required:
3148- self.assertRegexpMatches(help_text, r)
3149+ help_text = self.shell('help root-password')
3150+ for r in required:
3151+ self.assertRegexpMatches(help_text, r)
3152
3153=== modified file 'tests/test_utils.py'
3154--- tests/test_utils.py 2012-08-16 12:41:00 +0000
3155+++ tests/test_utils.py 2012-11-30 14:02:33 +0000
3156@@ -64,10 +64,19 @@
3157 self.manager = FakeManager(None)
3158
3159 def test_find_none(self):
3160+ """Test a few non-valid inputs"""
3161 self.assertRaises(exceptions.CommandError,
3162 utils.find_resource,
3163 self.manager,
3164 'asdf')
3165+ self.assertRaises(exceptions.CommandError,
3166+ utils.find_resource,
3167+ self.manager,
3168+ None)
3169+ self.assertRaises(exceptions.CommandError,
3170+ utils.find_resource,
3171+ self.manager,
3172+ {})
3173
3174 def test_find_by_integer_id(self):
3175 output = utils.find_resource(self.manager, 1234)
3176
3177=== added directory 'tests/v1_1/contrib'
3178=== added file 'tests/v1_1/contrib/__init__.py'
3179=== added file 'tests/v1_1/contrib/test_list_extensions.py'
3180--- tests/v1_1/contrib/test_list_extensions.py 1970-01-01 00:00:00 +0000
3181+++ tests/v1_1/contrib/test_list_extensions.py 2012-11-30 14:02:33 +0000
3182@@ -0,0 +1,21 @@
3183+from novaclient import extension
3184+from novaclient.v1_1.contrib import list_extensions
3185+
3186+from tests import utils
3187+from tests.v1_1 import fakes
3188+
3189+
3190+extensions = [
3191+ extension.Extension(list_extensions.__name__.split(".")[-1],
3192+ list_extensions),
3193+]
3194+cs = fakes.FakeClient(extensions=extensions)
3195+
3196+
3197+class ListExtensionsTests(utils.TestCase):
3198+ def test_list_extensions(self):
3199+ all_exts = cs.list_extensions.show_all()
3200+ cs.assert_called('GET', '/extensions')
3201+ self.assertTrue(len(all_exts) > 0)
3202+ for r in all_exts:
3203+ self.assertTrue(len(r.summary) > 0)
3204
3205=== modified file 'tests/v1_1/fakes.py'
3206--- tests/v1_1/fakes.py 2012-09-27 08:59:05 +0000
3207+++ tests/v1_1/fakes.py 2012-11-30 14:02:33 +0000
3208@@ -13,6 +13,7 @@
3209 # See the License for the specific language governing permissions and
3210 # limitations under the License.
3211
3212+from datetime import datetime
3213 import httplib2
3214 import urlparse
3215
3216@@ -25,7 +26,8 @@
3217
3218 def __init__(self, *args, **kwargs):
3219 client.Client.__init__(self, 'username', 'password',
3220- 'project_id', 'auth_url')
3221+ 'project_id', 'auth_url',
3222+ extensions=kwargs.get('extensions'))
3223 self.client = FakeHTTPClient(**kwargs)
3224
3225
3226@@ -68,6 +70,53 @@
3227 return httplib2.Response({"status": status}), body
3228
3229 #
3230+ # List all extensions
3231+ #
3232+
3233+ def get_extensions(self, **kw):
3234+ exts = [
3235+ {
3236+ "alias": "NMN",
3237+ "description": "Multiple network support",
3238+ "links": [],
3239+ "name": "Multinic",
3240+ "namespace": ("http://docs.openstack.org/"
3241+ "compute/ext/multinic/api/v1.1"),
3242+ "updated": "2011-06-09T00:00:00+00:00"
3243+ },
3244+ {
3245+ "alias": "OS-DCF",
3246+ "description": "Disk Management Extension",
3247+ "links": [],
3248+ "name": "DiskConfig",
3249+ "namespace": ("http://docs.openstack.org/"
3250+ "compute/ext/disk_config/api/v1.1"),
3251+ "updated": "2011-09-27T00:00:00+00:00"
3252+ },
3253+ {
3254+ "alias": "OS-EXT-SRV-ATTR",
3255+ "description": "Extended Server Attributes support.",
3256+ "links": [],
3257+ "name": "ExtendedServerAttributes",
3258+ "namespace": ("http://docs.openstack.org/"
3259+ "compute/ext/extended_status/api/v1.1"),
3260+ "updated": "2011-11-03T00:00:00+00:00"
3261+ },
3262+ {
3263+ "alias": "OS-EXT-STS",
3264+ "description": "Extended Status support",
3265+ "links": [],
3266+ "name": "ExtendedStatus",
3267+ "namespace": ("http://docs.openstack.org/"
3268+ "compute/ext/extended_status/api/v1.1"),
3269+ "updated": "2011-11-03T00:00:00+00:00"
3270+ },
3271+ ]
3272+ return (200, {
3273+ "extensions": exts,
3274+ })
3275+
3276+ #
3277 # Limits
3278 #
3279
3280@@ -200,6 +249,34 @@
3281 "metadata": {
3282 "Server Label": "DB 1"
3283 }
3284+ },
3285+ {
3286+ "id": 9012,
3287+ "name": "sample-server3",
3288+ "image": "",
3289+ "flavor": {
3290+ "id": 1,
3291+ "name": "256 MB Server",
3292+ },
3293+ "hostId": "9e107d9d372bb6826bd81d3542a419d6",
3294+ "status": "ACTIVE",
3295+ "addresses": {
3296+ "public": [{
3297+ "version": 4,
3298+ "addr": "4.5.6.7",
3299+ },
3300+ {
3301+ "version": 4,
3302+ "addr": "5.6.9.8",
3303+ }],
3304+ "private": [{
3305+ "version": 4,
3306+ "addr": "10.13.12.13",
3307+ }],
3308+ },
3309+ "metadata": {
3310+ "Server Label": "DB 1"
3311+ }
3312 }
3313 ]})
3314
3315@@ -213,6 +290,13 @@
3316 fakes.assert_has_keys(pfile, required=['path', 'contents'])
3317 return (202, self.get_servers_1234()[1])
3318
3319+ def post_os_volumes_boot(self, body, **kw):
3320+ assert set(body.keys()) <= set(['server', 'os:scheduler_hints'])
3321+ fakes.assert_has_keys(body['server'],
3322+ required=['name', 'block_device_mapping', 'flavorRef'],
3323+ optional=['imageRef'])
3324+ return (202, self.get_servers_9012()[1])
3325+
3326 def get_servers_1234(self, **kw):
3327 r = {'server': self.get_servers_detail()[1]['servers'][0]}
3328 return (200, r)
3329@@ -221,6 +305,10 @@
3330 r = {'server': self.get_servers_detail()[1]['servers'][1]}
3331 return (200, r)
3332
3333+ def get_servers_9012(self, **kw):
3334+ r = {'server': self.get_servers_detail()[1]['servers'][2]}
3335+ return (200, r)
3336+
3337 def put_servers_1234(self, body, **kw):
3338 assert body.keys() == ['server']
3339 fakes.assert_has_keys(body['server'], optional=['name', 'adminPass'])
3340@@ -345,6 +433,10 @@
3341 assert body[action].keys() == ['name']
3342 elif action == 'removeSecurityGroup':
3343 assert body[action].keys() == ['name']
3344+ elif action == 'createBackup':
3345+ assert set(body[action].keys()) == set(['name',
3346+ 'backup_type',
3347+ 'rotation'])
3348 else:
3349 raise AssertionError("Unexpected server action: %s" % action)
3350 return (resp, _body)
3351@@ -361,6 +453,9 @@
3352 def post_os_cloudpipe(self, **ks):
3353 return (202, {'instance_id': '9d5824aa-20e6-4b9f-b967-76a699fc51fd'})
3354
3355+ def put_os_cloudpipe_configure_project(self, **kw):
3356+ return (202, None)
3357+
3358 #
3359 # Flavors
3360 #
3361@@ -817,6 +912,48 @@
3362 return (202, None)
3363
3364 #
3365+ # Services
3366+ #
3367+ def get_os_services(self, **kw):
3368+ host = kw.get('host', 'host1')
3369+ service = kw.get('service', 'nova-compute')
3370+ return (200, {'services':
3371+ [{'binary': service,
3372+ 'host': host,
3373+ 'zone': 'nova',
3374+ 'status': 'enabled',
3375+ 'state': 'up',
3376+ 'updated_at': datetime(2012, 10, 29, 13, 42, 2)},
3377+ {'binary': service,
3378+ 'host': host,
3379+ 'zone': 'nova',
3380+ 'status': 'disabled',
3381+ 'state': 'down',
3382+ 'updated_at': datetime(2012, 9, 18, 8, 3, 38)},
3383+ ]})
3384+
3385+ def put_os_services_enable(self, body, **kw):
3386+ return (200, {'host': body['host'], 'service': body['service'],
3387+ 'disabled': False})
3388+
3389+ def put_os_services_disable(self, body, **kw):
3390+ return (200, {'host': body['host'], 'service': body['service'],
3391+ 'disabled': True})
3392+
3393+ #
3394+ # Fixed IPs
3395+ #
3396+ def get_os_fixed_ips_192_168_1_1(self, *kw):
3397+ return (200, {"fixed_ip":
3398+ {'cidr': '192.168.1.0/24',
3399+ 'address': '192.168.1.1',
3400+ 'hostname': 'foo',
3401+ 'host': 'bar'}})
3402+
3403+ def post_os_fixed_ips_192_168_1_1_action(self, body, **kw):
3404+ return (202, None)
3405+
3406+ #
3407 # Hosts
3408 #
3409 def get_os_hosts_host(self, *kw):
3410@@ -830,6 +967,16 @@
3411 {'resource': {'project': 'admin', 'host': 'dummy',
3412 'cpu': 1, 'memory_mb': 2048, 'disk_gb': 30}}]})
3413
3414+ def get_os_hosts(self, **kw):
3415+ zone = kw.get('zone', 'nova1')
3416+ return (200, {'hosts':
3417+ [{'host': 'host1',
3418+ 'service': 'nova-compute',
3419+ 'zone': zone},
3420+ {'host': 'host1',
3421+ 'service': 'nova-cert',
3422+ 'zone': zone}]})
3423+
3424 def get_os_hosts_sample_host(self, *kw):
3425 return (200, {'host': [{'resource': {'host': 'sample_host'}}], })
3426
3427@@ -988,3 +1135,32 @@
3428
3429 def post_os_networks_networkdisassociate_action(self, **kw):
3430 return (202, None)
3431+
3432+ def get_os_fping(self, **kw):
3433+ return (
3434+ 200, {
3435+ 'servers': [
3436+ {
3437+ "id": "1",
3438+ "project_id": "fake-project",
3439+ "alive": True,
3440+ },
3441+ {
3442+ "id": "2",
3443+ "project_id": "fake-project",
3444+ "alive": True,
3445+ },
3446+ ]
3447+ }
3448+ )
3449+
3450+ def get_os_fping_1(self, **kw):
3451+ return (
3452+ 200, {
3453+ 'server': {
3454+ "id": "1",
3455+ "project_id": "fake-project",
3456+ "alive": True,
3457+ }
3458+ }
3459+ )
3460
3461=== modified file 'tests/v1_1/test_cloudpipe.py'
3462--- tests/v1_1/test_cloudpipe.py 2012-04-02 11:29:59 +0000
3463+++ tests/v1_1/test_cloudpipe.py 2012-11-30 14:02:33 +0000
3464@@ -20,3 +20,9 @@
3465 body = {'cloudpipe': {'project_id': project}}
3466 cs.assert_called('POST', '/os-cloudpipe', body)
3467 self.assertTrue(isinstance(cp, str))
3468+
3469+ def test_update(self):
3470+ cs.cloudpipe.update("192.168.1.1", 2345)
3471+ body = {'configure_project': {'vpn_ip': "192.168.1.1",
3472+ 'vpn_port': 2345}}
3473+ cs.assert_called('PUT', '/os-cloudpipe/configure-project', body)
3474
3475=== added file 'tests/v1_1/test_fixed_ips.py'
3476--- tests/v1_1/test_fixed_ips.py 1970-01-01 00:00:00 +0000
3477+++ tests/v1_1/test_fixed_ips.py 2012-11-30 14:02:33 +0000
3478@@ -0,0 +1,43 @@
3479+# vim: tabstop=4 shiftwidth=4 softtabstop=4
3480+
3481+# Copyright 2012 IBM
3482+# All Rights Reserved.
3483+#
3484+# Licensed under the Apache License, Version 2.0 (the "License"); you may
3485+# not use this file except in compliance with the License. You may obtain
3486+# a copy of the License at
3487+#
3488+# http://www.apache.org/licenses/LICENSE-2.0
3489+#
3490+# Unless required by applicable law or agreed to in writing, software
3491+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
3492+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
3493+# License for the specific language governing permissions and limitations
3494+# under the License.
3495+
3496+from novaclient.v1_1 import fixed_ips
3497+from tests.v1_1 import fakes
3498+from tests import utils
3499+
3500+cs = fakes.FakeClient()
3501+
3502+
3503+class FixedIpsTest(utils.TestCase):
3504+
3505+ def test_get_fixed_ip(self):
3506+ info = cs.fixed_ips.get(fixed_ip='192.168.1.1')
3507+ cs.assert_called('GET', '/os-fixed-ips/192.168.1.1')
3508+ self.assertEqual(info.cidr, '192.168.1.0/24')
3509+ self.assertEqual(info.address, '192.168.1.1')
3510+ self.assertEqual(info.hostname, 'foo')
3511+ self.assertEqual(info.host, 'bar')
3512+
3513+ def test_reserve_fixed_ip(self):
3514+ body = {"reserve": None}
3515+ res = cs.fixed_ips.reserve(fixed_ip='192.168.1.1')
3516+ cs.assert_called('POST', '/os-fixed-ips/192.168.1.1/action', body)
3517+
3518+ def test_unreserve_fixed_ip(self):
3519+ body = {"unreserve": None}
3520+ res = cs.fixed_ips.unreserve(fixed_ip='192.168.1.1')
3521+ cs.assert_called('POST', '/os-fixed-ips/192.168.1.1/action', body)
3522
3523=== modified file 'tests/v1_1/test_flavors.py'
3524--- tests/v1_1/test_flavors.py 2012-09-27 08:59:05 +0000
3525+++ tests/v1_1/test_flavors.py 2012-11-30 14:02:33 +0000
3526@@ -60,7 +60,7 @@
3527 "OS-FLV-EXT-DATA:ephemeral": 10,
3528 "id": 1234,
3529 "swap": 0,
3530- "rxtx_factor": 1,
3531+ "rxtx_factor": 1.0,
3532 "os-flavor-access:is_public": False,
3533 }
3534 }
3535@@ -80,7 +80,7 @@
3536 "OS-FLV-EXT-DATA:ephemeral": 0,
3537 "id": 1234,
3538 "swap": 0,
3539- "rxtx_factor": 1,
3540+ "rxtx_factor": 1.0,
3541 "os-flavor-access:is_public": True,
3542 }
3543 }
3544@@ -88,6 +88,29 @@
3545 cs.assert_called('POST', '/flavors', body)
3546 self.assertTrue(isinstance(f, flavors.Flavor))
3547
3548+ def test_invalid_parameters_create(self):
3549+ self.assertRaises(exceptions.CommandError, cs.flavors.create,
3550+ "flavorcreate", "invalid", 1, 10, 1234, swap=0,
3551+ ephemeral=0, rxtx_factor=1.0, is_public=True)
3552+ self.assertRaises(exceptions.CommandError, cs.flavors.create,
3553+ "flavorcreate", 512, "invalid", 10, 1234, swap=0,
3554+ ephemeral=0, rxtx_factor=1.0, is_public=True)
3555+ self.assertRaises(exceptions.CommandError, cs.flavors.create,
3556+ "flavorcreate", 512, 1, "invalid", 1234, swap=0,
3557+ ephemeral=0, rxtx_factor=1.0, is_public=True)
3558+ self.assertRaises(exceptions.CommandError, cs.flavors.create,
3559+ "flavorcreate", 512, 1, 10, 1234, swap="invalid",
3560+ ephemeral=0, rxtx_factor=1.0, is_public=True)
3561+ self.assertRaises(exceptions.CommandError, cs.flavors.create,
3562+ "flavorcreate", 512, 1, 10, 1234, swap=0,
3563+ ephemeral="invalid", rxtx_factor=1.0, is_public=True)
3564+ self.assertRaises(exceptions.CommandError, cs.flavors.create,
3565+ "flavorcreate", 512, 1, 10, 1234, swap=0,
3566+ ephemeral=0, rxtx_factor="invalid", is_public=True)
3567+ self.assertRaises(exceptions.CommandError, cs.flavors.create,
3568+ "flavorcreate", 512, 1, 10, 1234, swap=0,
3569+ ephemeral=0, rxtx_factor=1.0, is_public='invalid')
3570+
3571 def test_delete(self):
3572 cs.flavors.delete("flavordelete")
3573 cs.assert_called('DELETE', '/flavors/flavordelete')
3574
3575=== added file 'tests/v1_1/test_fping.py'
3576--- tests/v1_1/test_fping.py 1970-01-01 00:00:00 +0000
3577+++ tests/v1_1/test_fping.py 2012-11-30 14:02:33 +0000
3578@@ -0,0 +1,41 @@
3579+# vim: tabstop=4 shiftwidth=4 softtabstop=4
3580+
3581+# Copyright 2012 OpenStack LLC.
3582+# All Rights Reserved.
3583+#
3584+# Licensed under the Apache License, Version 2.0 (the "License"); you may
3585+# not use this file except in compliance with the License. You may obtain
3586+# a copy of the License at
3587+#
3588+# http://www.apache.org/licenses/LICENSE-2.0
3589+#
3590+# Unless required by applicable law or agreed to in writing, software
3591+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
3592+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
3593+# License for the specific language governing permissions and limitations
3594+# under the License.
3595+
3596+from novaclient import exceptions
3597+from novaclient.v1_1 import fping
3598+from tests import utils
3599+from tests.v1_1 import fakes
3600+
3601+
3602+cs = fakes.FakeClient()
3603+
3604+
3605+class FpingTest(utils.TestCase):
3606+
3607+ def test_list_fpings(self):
3608+ fl = cs.fping.list()
3609+ cs.assert_called('GET', '/os-fping')
3610+ [self.assertTrue(isinstance(f, fping.Fping)) for f in fl]
3611+ [self.assertEqual(f.project_id, "fake-project") for f in fl]
3612+ [self.assertEqual(f.alive, True) for f in fl]
3613+
3614+ def test_get_fping(self):
3615+ f = cs.fping.get(1)
3616+ cs.assert_called('GET', '/os-fping/1')
3617+ self.assertTrue(isinstance(f, fping.Fping))
3618+ self.assertEqual(f.project_id, "fake-project")
3619+ self.assertEqual(f.alive, True)
3620
3621=== modified file 'tests/v1_1/test_hosts.py'
3622--- tests/v1_1/test_hosts.py 2012-02-24 09:35:35 +0000
3623+++ tests/v1_1/test_hosts.py 2012-11-30 14:02:33 +0000
3624@@ -13,6 +13,18 @@
3625 cs.assert_called('GET', '/os-hosts/host')
3626 [self.assertTrue(isinstance(h, hosts.Host)) for h in hs]
3627
3628+ def test_list_host(self):
3629+ hs = cs.hosts.list_all()
3630+ cs.assert_called('GET', '/os-hosts')
3631+ [self.assertTrue(isinstance(h, hosts.Host)) for h in hs]
3632+ [self.assertEqual(h.zone, 'nova1') for h in hs]
3633+
3634+ def test_list_host_with_zone(self):
3635+ hs = cs.hosts.list_all('nova')
3636+ cs.assert_called('GET', '/os-hosts?zone=nova')
3637+ [self.assertTrue(isinstance(h, hosts.Host)) for h in hs]
3638+ [self.assertEqual(h.zone, 'nova') for h in hs]
3639+
3640 def test_update_enable(self):
3641 host = cs.hosts.get('sample_host')[0]
3642 values = {"status": "enabled"}
3643
3644=== modified file 'tests/v1_1/test_servers.py'
3645--- tests/v1_1/test_servers.py 2012-08-16 12:41:00 +0000
3646+++ tests/v1_1/test_servers.py 2012-11-30 14:02:33 +0000
3647@@ -1,3 +1,5 @@
3648+# -*- coding: utf-8 -*-
3649+
3650 import StringIO
3651
3652 from novaclient import exceptions
3653@@ -59,6 +61,38 @@
3654 cs.assert_called('POST', '/servers')
3655 self.assertTrue(isinstance(s, servers.Server))
3656
3657+ def test_create_server_userdata_unicode(self):
3658+ s = cs.servers.create(
3659+ name="My server",
3660+ image=1,
3661+ flavor=1,
3662+ meta={'foo': 'bar'},
3663+ userdata=u'こんにちは',
3664+ key_name="fakekey",
3665+ files={
3666+ '/etc/passwd': 'some data', # a file
3667+ '/tmp/foo.txt': StringIO.StringIO('data'), # a stream
3668+ },
3669+ )
3670+ cs.assert_called('POST', '/servers')
3671+ self.assertTrue(isinstance(s, servers.Server))
3672+
3673+ def test_create_server_userdata_utf8(self):
3674+ s = cs.servers.create(
3675+ name="My server",
3676+ image=1,
3677+ flavor=1,
3678+ meta={'foo': 'bar'},
3679+ userdata='こんにちは',
3680+ key_name="fakekey",
3681+ files={
3682+ '/etc/passwd': 'some data', # a file
3683+ '/tmp/foo.txt': StringIO.StringIO('data'), # a stream
3684+ },
3685+ )
3686+ cs.assert_called('POST', '/servers')
3687+ self.assertTrue(isinstance(s, servers.Server))
3688+
3689 def test_update_server(self):
3690 s = cs.servers.get(1234)
3691
3692@@ -102,7 +136,7 @@
3693 flavor={"id": 1, "name": "256 MB Server"})
3694
3695 sl = cs.servers.findall(flavor={"id": 1, "name": "256 MB Server"})
3696- self.assertEqual([s.id for s in sl], [1234, 5678])
3697+ self.assertEqual([s.id for s in sl], [1234, 5678, 9012])
3698
3699 def test_reboot_server(self):
3700 s = cs.servers.get(1234)
3701@@ -230,6 +264,13 @@
3702 cs.servers.unlock(s)
3703 cs.assert_called('POST', '/servers/1234/action')
3704
3705+ def test_backup(self):
3706+ s = cs.servers.get(1234)
3707+ s.backup('back1', 'daily', 1)
3708+ cs.assert_called('POST', '/servers/1234/action')
3709+ cs.servers.backup(s, 'back1', 'daily', 2)
3710+ cs.assert_called('POST', '/servers/1234/action')
3711+
3712 def test_get_console_output_without_length(self):
3713 success = 'foo'
3714 s = cs.servers.get(1234)
3715
3716=== added file 'tests/v1_1/test_services.py'
3717--- tests/v1_1/test_services.py 1970-01-01 00:00:00 +0000
3718+++ tests/v1_1/test_services.py 2012-11-30 14:02:33 +0000
3719@@ -0,0 +1,68 @@
3720+# vim: tabstop=4 shiftwidth=4 softtabstop=4
3721+
3722+# Copyright 2012 IBM
3723+# All Rights Reserved.
3724+#
3725+# Licensed under the Apache License, Version 2.0 (the "License"); you may
3726+# not use this file except in compliance with the License. You may obtain
3727+# a copy of the License at
3728+#
3729+# http://www.apache.org/licenses/LICENSE-2.0
3730+#
3731+# Unless required by applicable law or agreed to in writing, software
3732+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
3733+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
3734+# License for the specific language governing permissions and limitations
3735+# under the License.
3736+
3737+from novaclient.v1_1 import services
3738+from tests.v1_1 import fakes
3739+from tests import utils
3740+
3741+
3742+cs = fakes.FakeClient()
3743+
3744+
3745+class ServicesTest(utils.TestCase):
3746+
3747+ def test_list_services(self):
3748+ svs = cs.services.list()
3749+ cs.assert_called('GET', '/os-services')
3750+ [self.assertTrue(isinstance(s, services.Service)) for s in svs]
3751+ [self.assertEqual(s.binary, 'nova-compute') for s in svs]
3752+ [self.assertEqual(s.host, 'host1') for s in svs]
3753+
3754+ def test_list_services_with_hostname(self):
3755+ svs = cs.services.list(host='host2')
3756+ cs.assert_called('GET', '/os-services?host=host2')
3757+ [self.assertTrue(isinstance(s, services.Service)) for s in svs]
3758+ [self.assertEqual(s.binary, 'nova-compute') for s in svs]
3759+ [self.assertEqual(s.host, 'host2') for s in svs]
3760+
3761+ def test_list_services_with_service(self):
3762+ svs = cs.services.list(service='nova-cert')
3763+ cs.assert_called('GET', '/os-services?service=nova-cert')
3764+ [self.assertTrue(isinstance(s, services.Service)) for s in svs]
3765+ [self.assertEqual(s.binary, 'nova-cert') for s in svs]
3766+ [self.assertEqual(s.host, 'host1') for s in svs]
3767+
3768+ def test_list_services_with_host_service(self):
3769+ svs = cs.services.list('host2', 'nova-cert')
3770+ cs.assert_called('GET', '/os-services?host=host2&service=nova-cert')
3771+ [self.assertTrue(isinstance(s, services.Service)) for s in svs]
3772+ [self.assertEqual(s.binary, 'nova-cert') for s in svs]
3773+ [self.assertEqual(s.host, 'host2') for s in svs]
3774+
3775+ def test_services_enable(self):
3776+ service = cs.services.enable('host1', 'nova-cert')
3777+ values = {"host": "host1", 'service': 'nova-cert'}
3778+ cs.assert_called('PUT', '/os-services/enable', values)
3779+ self.assertTrue(isinstance(service, services.Service))
3780+ self.assertFalse(service.disabled)
3781+
3782+ def test_services_disable(self):
3783+ service = cs.services.disable('host1', 'nova-cert')
3784+ values = {"host": "host1", 'service': 'nova-cert'}
3785+ cs.assert_called('PUT', '/os-services/disable', values)
3786+ self.assertTrue(isinstance(service, services.Service))
3787+ self.assertTrue(service.disabled)
3788
3789=== modified file 'tests/v1_1/test_shell.py'
3790--- tests/v1_1/test_shell.py 2012-09-27 08:59:05 +0000
3791+++ tests/v1_1/test_shell.py 2012-11-30 14:02:33 +0000
3792@@ -86,6 +86,33 @@
3793 }},
3794 )
3795
3796+ def test_boot_no_image_no_bdms(self):
3797+ cmd = 'boot --flavor 1 some-server'
3798+ self.assertRaises(exceptions.CommandError, self.run_command, cmd)
3799+
3800+ def test_boot_no_image_bdms(self):
3801+ self.run_command(
3802+ 'boot --flavor 1 --block_device_mapping vda=blah:::0 some-server'
3803+ )
3804+ self.assert_called_anytime(
3805+ 'POST', '/os-volumes_boot',
3806+ {'server': {
3807+ 'flavorRef': '1',
3808+ 'name': 'some-server',
3809+ 'block_device_mapping': [
3810+ {
3811+ 'volume_size': '',
3812+ 'volume_id': 'blah',
3813+ 'delete_on_termination': '0',
3814+ 'device_name':'vda'
3815+ }
3816+ ],
3817+ 'imageRef': '',
3818+ 'min_count': 1,
3819+ 'max_count': 1,
3820+ }},
3821+ )
3822+
3823 def test_boot_metadata(self):
3824 self.run_command('boot --image 1 --flavor 1 --meta foo=bar=pants'
3825 ' --meta spam=eggs some-server ')
3826@@ -276,6 +303,11 @@
3827 self.assert_called('GET', '/flavors/1', pos=-2)
3828 self.assert_called('GET', '/images/2')
3829
3830+ def test_show_no_image(self):
3831+ self.run_command('show 9012')
3832+ self.assert_called('GET', '/servers/9012', pos=-2)
3833+ self.assert_called('GET', '/flavors/1', pos=-1)
3834+
3835 def test_show_bad_id(self):
3836 self.assertRaises(exceptions.CommandError,
3837 self.run_command, 'show xxx')
3838@@ -454,6 +486,54 @@
3839 self.assert_called('POST', '/servers/1234/action',
3840 {'os-resetState': {'state': 'active'}})
3841
3842+ def test_services_list(self):
3843+ self.run_command('service-list')
3844+ self.assert_called('GET', '/os-services')
3845+
3846+ def test_services_list_with_host(self):
3847+ self.run_command('service-list --host host1')
3848+ self.assert_called('GET', '/os-services?host=host1')
3849+
3850+ def test_services_list_with_servicename(self):
3851+ self.run_command('service-list --servicename nova-cert')
3852+ self.assert_called('GET', '/os-services?service=nova-cert')
3853+
3854+ def test_services_list_with_host_servicename(self):
3855+ self.run_command('service-list --host host1 --servicename nova-cert')
3856+ self.assert_called('GET', '/os-services?host=host1&service=nova-cert')
3857+
3858+ def test_services_enable(self):
3859+ self.run_command('service-enable host1 nova-cert')
3860+ body = {'host': 'host1', 'service': 'nova-cert'}
3861+ self.assert_called('PUT', '/os-services/enable', body)
3862+
3863+ def test_services_disable(self):
3864+ self.run_command('service-disable host1 nova-cert')
3865+ body = {'host': 'host1', 'service': 'nova-cert'}
3866+ self.assert_called('PUT', '/os-services/disable', body)
3867+
3868+ def test_fixed_ips_get(self):
3869+ self.run_command('fixed-ip-get 192.168.1.1')
3870+ self.assert_called('GET', '/os-fixed-ips/192.168.1.1')
3871+
3872+ def test_fixed_ips_reserve(self):
3873+ self.run_command('fixed-ip-reserve 192.168.1.1')
3874+ body = {'reserve': None}
3875+ self.assert_called('POST', '/os-fixed-ips/192.168.1.1/action', body)
3876+
3877+ def test_fixed_ips_unreserve(self):
3878+ self.run_command('fixed-ip-unreserve 192.168.1.1')
3879+ body = {'unreserve': None}
3880+ self.assert_called('POST', '/os-fixed-ips/192.168.1.1/action', body)
3881+
3882+ def test_host_list(self):
3883+ self.run_command('host-list')
3884+ self.assert_called('GET', '/os-hosts')
3885+
3886+ def test_host_list_with_zone(self):
3887+ self.run_command('host-list --zone nova')
3888+ self.assert_called('GET', '/os-hosts?zone=nova')
3889+
3890 def test_host_update_status(self):
3891 self.run_command('host-update sample-host_1 --status enabled')
3892 body = {'status': 'enabled'}
3893@@ -507,11 +587,11 @@
3894 self.assert_called('GET', '/os-hypervisors/statistics')
3895
3896 def test_quota_show(self):
3897- self.run_command('quota-show test')
3898+ self.run_command('quota-show --tenant test')
3899 self.assert_called('GET', '/os-quota-sets/test')
3900
3901 def test_quota_defaults(self):
3902- self.run_command('quota-defaults test')
3903+ self.run_command('quota-defaults --tenant test')
3904 self.assert_called('GET', '/os-quota-sets/test/defaults')
3905
3906 def test_quota_update(self):
3907@@ -533,3 +613,30 @@
3908 def test_network_show(self):
3909 self.run_command('network-show 1')
3910 self.assert_called('GET', '/os-networks/1')
3911+
3912+ def test_cloudpipe_list(self):
3913+ self.run_command('cloudpipe-list')
3914+ self.assert_called('GET', '/os-cloudpipe')
3915+
3916+ def test_cloudpipe_create(self):
3917+ self.run_command('cloudpipe-create myproject')
3918+ body = {'cloudpipe': {'project_id': "myproject"}}
3919+ self.assert_called('POST', '/os-cloudpipe', body)
3920+
3921+ def test_cloudpipe_configure(self):
3922+ self.run_command('cloudpipe-configure 192.168.1.1 1234')
3923+ body = {'configure_project': {'vpn_ip': "192.168.1.1",
3924+ 'vpn_port': '1234'}}
3925+ self.assert_called('PUT', '/os-cloudpipe/configure-project', body)
3926+
3927+ def test_backup(self):
3928+ self.run_command('backup sample-server back1 daily 1')
3929+ self.assert_called('POST', '/servers/1234/action',
3930+ {'createBackup': {'name': 'back1',
3931+ 'backup_type': 'daily',
3932+ 'rotation': '1'}})
3933+ self.run_command('backup 1234 back1 daily 1')
3934+ self.assert_called('POST', '/servers/1234/action',
3935+ {'createBackup': {'name': 'back1',
3936+ 'backup_type': 'daily',
3937+ 'rotation': '1'}})

Subscribers

People subscribed via source and target branches