Merge lp:~zulcss/ubuntu/precise/python-glanceclient/trunk into lp:~ubuntu-cloud-archive/ubuntu/precise/python-glanceclient/trunk
- Precise (12.04)
- trunk
- Merge into trunk
Proposed by
Chuck Short
Status: | Merged |
---|---|
Approved by: | James Page |
Approved revision: | 11 |
Merged at revision: | 11 |
Proposed branch: | lp:~zulcss/ubuntu/precise/python-glanceclient/trunk |
Merge into: | lp:~ubuntu-cloud-archive/ubuntu/precise/python-glanceclient/trunk |
Diff against target: |
2145 lines (+1222/-240) 36 files modified
.pc/applied-patches (+0/-1) .pc/fix-ubuntu-tests.patch/tools/test-requires (+0/-11) AUTHORS (+10/-1) ChangeLog (+463/-0) PKG-INFO (+2/-1) debian/changelog (+17/-0) debian/control (+4/-2) debian/patches/fix-ubuntu-tests.patch (+9/-14) debian/pydist-overrides (+1/-0) debian/rules (+1/-1) doc/source/index.rst (+15/-0) glanceclient/__init__.py (+20/-3) glanceclient/common/http.py (+150/-80) glanceclient/common/utils.py (+15/-0) glanceclient/exc.py (+4/-0) glanceclient/openstack/common/setup.py (+60/-45) glanceclient/openstack/common/version.py (+1/-2) glanceclient/shell.py (+10/-0) glanceclient/v1/images.py (+14/-14) glanceclient/v1/shell.py (+96/-37) glanceclient/version.py (+0/-21) glanceclient/versioninfo (+1/-1) python_glanceclient.egg-info/PKG-INFO (+2/-1) python_glanceclient.egg-info/SOURCES.txt (+5/-1) python_glanceclient.egg-info/requires.txt (+2/-1) setup.py (+2/-0) tests/test_http.py (+65/-0) tests/test_ssl.py (+112/-0) tests/test_utils.py (+7/-0) tests/utils.py (+9/-1) tests/v1/test_images.py (+1/-1) tests/var/ca.crt (+35/-0) tests/var/certificate.crt (+30/-0) tests/var/privatekey.key (+51/-0) tools/pip-requires (+2/-1) tools/test-requires (+6/-0) |
To merge this branch: | bzr merge lp:~zulcss/ubuntu/precise/python-glanceclient/trunk |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
James Page | Approve | ||
Review via email: mp+136429@code.launchpad.net |
Commit message
Description of the change
python-glanceclient g1
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === removed file '.pc/applied-patches' |
2 | --- .pc/applied-patches 2012-06-22 10:41:03 +0000 |
3 | +++ .pc/applied-patches 1970-01-01 00:00:00 +0000 |
4 | @@ -1,1 +0,0 @@ |
5 | -fix-ubuntu-tests.patch |
6 | |
7 | === removed directory '.pc/fix-ubuntu-tests.patch' |
8 | === removed directory '.pc/fix-ubuntu-tests.patch/tools' |
9 | === removed file '.pc/fix-ubuntu-tests.patch/tools/test-requires' |
10 | --- .pc/fix-ubuntu-tests.patch/tools/test-requires 2012-09-07 12:23:37 +0000 |
11 | +++ .pc/fix-ubuntu-tests.patch/tools/test-requires 1970-01-01 00:00:00 +0000 |
12 | @@ -1,11 +0,0 @@ |
13 | -distribute>=0.6.24 |
14 | - |
15 | -mox |
16 | -nose |
17 | -nose-exclude |
18 | -nosexcover |
19 | -openstack.nose_plugin |
20 | -nosehtmloutput |
21 | -pep8==1.2 |
22 | -setuptools-git>=0.4 |
23 | -sphinx>=1.1.2 |
24 | |
25 | === modified file 'AUTHORS' |
26 | --- AUTHORS 2012-09-18 19:18:03 +0000 |
27 | +++ AUTHORS 2012-11-27 14:34:22 +0000 |
28 | @@ -1,13 +1,19 @@ |
29 | Adam Gandelman <adamg@canonical.com> |
30 | +Alessandro Pilotti <ap@pilotti.it> |
31 | +Andre Naehring <naehring@b1-systems.de> |
32 | +Andrew Laski <andrew.laski@rackspace.com> |
33 | Bhuvan Arumugam <bhuvan@apache.org> |
34 | Brian Lamar <brian.lamar@rackspace.com> |
35 | Brian Rosmaita <brian.rosmaita@rackspace.com> |
36 | Brian Waldon <bcwaldon@gmail.com> |
37 | Chris Behrens <cbehrens@codestud.com> |
38 | +Christian Berendt <berendt@b1-systems.de> |
39 | Chuck Short <chuck.short@canonical.com> |
40 | Clark Boylan <clark.boylan@gmail.com> |
41 | Dan Prince <dprince@redhat.com> |
42 | Dean Troyer <dtroyer@gmail.com> |
43 | +Diego Parrilla <diego.parrilla@stackops.com> |
44 | +Doug Hellmann <doug.hellmann@dreamhost.com> |
45 | Gabriel Hurley <gabriel@strikeawe.com> |
46 | isethi <iccha.sethi@rackspace.com> |
47 | James E. Blair <jeblair@hp.com> |
48 | @@ -20,5 +26,8 @@ |
49 | Monty Taylor <mordred@inaugust.com> |
50 | Sascha Peilicke <saschpe@suse.de> |
51 | Stuart McLaren <stuart.mclaren@hp.com> |
52 | +Sulochan Acharya <sulochan@gmail.com> |
53 | Thierry Carrez <thierry@openstack.org> |
54 | -Unmesh Gurjar <unmesh.gurjar@vertex.co.in> |
55 | \ No newline at end of file |
56 | +Unmesh Gurjar <unmesh.gurjar@vertex.co.in> |
57 | +Vincent Untz <vuntz@suse.com> |
58 | +Vishvananda Ishaya <vishvananda@gmail.com> |
59 | \ No newline at end of file |
60 | |
61 | === modified file 'ChangeLog' |
62 | --- ChangeLog 2012-09-18 19:18:03 +0000 |
63 | +++ ChangeLog 2012-11-27 14:34:22 +0000 |
64 | @@ -1,3 +1,466 @@ |
65 | +commit ae16750c48bc8d4b2b8d4de87913572a276f4f1e |
66 | +Author: Brian Waldon <bcwaldon@gmail.com> |
67 | +Date: Mon Nov 19 14:56:38 2012 -0800 |
68 | + |
69 | + Document bugs/features for v0.6.0 |
70 | + |
71 | + Change-Id: I8966d74eb86e52a222ddac5bc6d52d1dd699fb3d |
72 | + |
73 | + doc/source/index.rst | 15 +++++++++++++++ |
74 | + 1 file changed, 15 insertions(+) |
75 | + |
76 | +commit 046d34c89185c31b79f580dd2cafa9f790920426 |
77 | +Merge: e40580b fe17d35 |
78 | +Author: Jenkins <jenkins@review.openstack.org> |
79 | +Date: Mon Nov 19 19:39:19 2012 +0000 |
80 | + |
81 | + Merge "Simplify human-readable size output" |
82 | + |
83 | +commit e40580b77a513cdfb89da15852ea73de0d9a6eea |
84 | +Merge: 882c13a b24832c |
85 | +Author: Jenkins <jenkins@review.openstack.org> |
86 | +Date: Mon Nov 19 18:56:52 2012 +0000 |
87 | + |
88 | + Merge "Make image sizes more readable for humans" |
89 | + |
90 | +commit 882c13ab8cb4bd57a61ae3918f4c3ab1e3185a5d |
91 | +Merge: 0192e14 0e90f8e |
92 | +Author: Jenkins <jenkins@review.openstack.org> |
93 | +Date: Mon Nov 19 18:52:55 2012 +0000 |
94 | + |
95 | + Merge "Set useful boolean flag metavars" |
96 | + |
97 | +commit 0192e14d5652500185aa9410fe6e39cd25c1ec6b |
98 | +Merge: 1899ac2 e20ff23 |
99 | +Author: Jenkins <jenkins@review.openstack.org> |
100 | +Date: Mon Nov 19 18:48:11 2012 +0000 |
101 | + |
102 | + Merge "added --version as new parameter" |
103 | + |
104 | +commit fe17d3517482525527d4af9b24df64e7651ebe3a |
105 | +Author: Brian Waldon <bcwaldon@gmail.com> |
106 | +Date: Mon Nov 19 10:35:04 2012 -0800 |
107 | + |
108 | + Simplify human-readable size output |
109 | + |
110 | + * Limit human-readable sizes to a single decimal |
111 | + * Drop trailing zero |
112 | + * Step one suffix further in the case of a size being 1024 |
113 | + |
114 | + Change-Id: I2eb8ac0571d3d08b52f62155912863870573a37c |
115 | + |
116 | + glanceclient/common/utils.py | 7 +++++-- |
117 | + tests/test_utils.py | 8 +++++--- |
118 | + 2 files changed, 10 insertions(+), 5 deletions(-) |
119 | + |
120 | +commit b24832c22aa44d2f8b5ecddaf12e7878653af28f |
121 | +Author: Christian Berendt <berendt@b1-systems.de> |
122 | +Date: Wed Nov 7 19:39:43 2012 +0100 |
123 | + |
124 | + Make image sizes more readable for humans |
125 | + |
126 | + By introducing the parameter --human-readable for several functions |
127 | + (image-list, image-show, image-update, image-create) it's possible |
128 | + to convert the size in bytes to something more readable like |
129 | + 9.309MB or 1.375GB. |
130 | + |
131 | + Change-Id: I4e2654994361dcf330ed6d681dbed73388f159cb |
132 | + |
133 | + glanceclient/common/utils.py | 12 ++++++++++++ |
134 | + glanceclient/v1/shell.py | 26 ++++++++++++++++++++++---- |
135 | + tests/test_utils.py | 5 +++++ |
136 | + 3 files changed, 39 insertions(+), 4 deletions(-) |
137 | + |
138 | +commit 0e90f8ef230eebd421175d637d7c9df7d149a155 |
139 | +Author: Brian Waldon <bcwaldon@gmail.com> |
140 | +Date: Mon Nov 19 09:08:39 2012 -0800 |
141 | + |
142 | + Set useful boolean flag metavars |
143 | + |
144 | + The boolean flags --is-protected and --is-public now |
145 | + communicate that they must be set to True or False. |
146 | + |
147 | + Fixes bug 1056501. |
148 | + |
149 | + Change-Id: I23094ea556eb71d6eb977a64c171119738ed792b |
150 | + |
151 | + glanceclient/v1/shell.py | 8 ++++---- |
152 | + 1 file changed, 4 insertions(+), 4 deletions(-) |
153 | + |
154 | +commit 1899ac29637923ad8ff18f863a9d7081a34593d0 |
155 | +Merge: c6b9712 8d81623 |
156 | +Author: Jenkins <jenkins@review.openstack.org> |
157 | +Date: Sat Nov 17 00:57:15 2012 +0000 |
158 | + |
159 | + Merge "Unpin keystoneclient dependency" |
160 | + |
161 | +commit 8d81623d5f1891a19f58d66cc28f7d4033293354 |
162 | +Author: Vishvananda Ishaya <vishvananda@gmail.com> |
163 | +Date: Fri Nov 16 16:29:43 2012 -0800 |
164 | + |
165 | + Unpin keystoneclient dependency |
166 | + |
167 | + The new 0.2.0 keystoneclient was released with no api changes, and |
168 | + glanceclients dependency breaks gating so unpin it. |
169 | + |
170 | + Change-Id: I9cbe2ebb462005ebfea3b7a0e68ca39069a0765f |
171 | + |
172 | + tools/pip-requires | 2 +- |
173 | + 1 file changed, 1 insertion(+), 1 deletion(-) |
174 | + |
175 | +commit c6b9712482389a36102141aecb36a0199291092b |
176 | +Merge: 00eff28 6c201e6 |
177 | +Author: Jenkins <jenkins@review.openstack.org> |
178 | +Date: Thu Nov 15 21:18:44 2012 +0000 |
179 | + |
180 | + Merge "Fixes bug on Windows related to a wrong API url" |
181 | + |
182 | +commit 6c201e63ea76032cbdd65211382b6266e6a767de |
183 | +Author: Alessandro Pilotti <ap@pilotti.it> |
184 | +Date: Thu Nov 15 20:25:26 2012 +0200 |
185 | + |
186 | + Fixes bug on Windows related to a wrong API url |
187 | + |
188 | + Fixes Bug #1079323 |
189 | + |
190 | + python-glanceclient (latest repository code) fails on Windows due to a |
191 | + malformed API url. This error is due to the usage of os.path.normpath(), |
192 | + which should not be used for URLs as it swaps "/" with "\" on Windows. |
193 | + |
194 | + The fix consists in using posixpath.normpath(). |
195 | + Please see also https://bugs.launchpad.net/nova/+bug/1077125 and related |
196 | + commit. |
197 | + |
198 | + Change-Id: Iaa643bd579963ad9ffbf10674973cbca75d435ac |
199 | + |
200 | + glanceclient/common/http.py | 4 ++-- |
201 | + 1 file changed, 2 insertions(+), 2 deletions(-) |
202 | + |
203 | +commit 00eff28f28f57fa3f786629dbf20c19b558188ef |
204 | +Author: Andre Naehring <naehring@b1-systems.de> |
205 | +Date: Wed Nov 14 15:37:31 2012 +0100 |
206 | + |
207 | + Enhance --checksum help with algorithm |
208 | + |
209 | + Fixes bug 1056499. |
210 | + |
211 | + Added a line to the help text of --checksum which enhances the help text |
212 | + to show what checksum algorithm is expected. |
213 | + |
214 | + Change-Id: Ie6604022dd9f398c639afe647b2d94b5179dbb61 |
215 | + |
216 | + glanceclient/v1/shell.py | 3 ++- |
217 | + 1 file changed, 2 insertions(+), 1 deletion(-) |
218 | + |
219 | +commit e20ff231587e9d3985602cf8df755e3f24459cda |
220 | +Author: Christian Berendt <berendt@b1-systems.de> |
221 | +Date: Tue Nov 13 11:59:17 2012 +0100 |
222 | + |
223 | + added --version as new parameter |
224 | + |
225 | + fixes bug 1056504 |
226 | + Change-Id: Ib28e3941006b46553001d7895d5ddf4b0f9c540d |
227 | + |
228 | + glanceclient/__init__.py | 21 +++++++++++++++++++-- |
229 | + glanceclient/shell.py | 4 ++++ |
230 | + glanceclient/version.py | 21 --------------------- |
231 | + setup.py | 1 + |
232 | + 4 files changed, 24 insertions(+), 23 deletions(-) |
233 | + |
234 | +commit 16aafa728e4b8309b16bcc120b10bc20372883f4 |
235 | +Author: Alessandro Pilotti <ap@pilotti.it> |
236 | +Date: Mon Nov 5 18:19:13 2012 +0200 |
237 | + |
238 | + Fixes setup compatibility issue on Windows |
239 | + |
240 | + Fixes Bug #1052161 |
241 | + |
242 | + "python setup.py build" fails on Windows due to a hardcoded shell path: |
243 | + /bin/sh |
244 | + |
245 | + setup.py updated using openstack-common/update.py |
246 | + |
247 | + Change-Id: If0ae835aeada8769e46dddf4f3c2f2edfdfbc5fe |
248 | + |
249 | + glanceclient/openstack/common/setup.py | 105 +++++++++++++++++------------- |
250 | + glanceclient/openstack/common/version.py | 3 +- |
251 | + 2 files changed, 61 insertions(+), 47 deletions(-) |
252 | + |
253 | +commit a8e88aa340c2d1ad9d937e0f5c2c60c65d7e5962 |
254 | +Merge: 256dcba 8b2c227 |
255 | +Author: Jenkins <jenkins@review.openstack.org> |
256 | +Date: Thu Oct 25 02:23:49 2012 +0000 |
257 | + |
258 | + Merge "Allow deletion of multiple images through CLI" |
259 | + |
260 | +commit 8b2c227f27be649a4a3e371ad99157ee464ecc1d |
261 | +Author: Sulochan Acharya <sulochan@gmail.com> |
262 | +Date: Mon Oct 22 17:01:46 2012 -0500 |
263 | + |
264 | + Allow deletion of multiple images through CLI |
265 | + |
266 | + Add nargs to argparse for image-delete command to |
267 | + allow muliple (optional) positional image-id arguments. |
268 | + For example: |
269 | + image-delete xxx aaa yyy will delete valid images |
270 | + xxx and yyy and print error message for invalid image |
271 | + aaa. Also with --verbose you can see some extra text |
272 | + on delete request for each image. |
273 | + |
274 | + Fixes bug1056498. |
275 | + |
276 | + Change-Id: I6e804700ed24d16f90ec92569c0893cad4aaa26f |
277 | + |
278 | + glanceclient/v1/shell.py | 21 ++++++++++++++++++--- |
279 | + 1 file changed, 18 insertions(+), 3 deletions(-) |
280 | + |
281 | +commit 256dcbae1c8565284cb54f5c5693b9cfd7103425 |
282 | +Merge: c420fa1 1e14e82 |
283 | +Author: Jenkins <jenkins@review.openstack.org> |
284 | +Date: Wed Oct 24 02:53:46 2012 +0000 |
285 | + |
286 | + Merge "Fixes shell command for member-delete" |
287 | + |
288 | +commit 1e14e82c815b06dfd8a370f1f97c61a256b28a9a |
289 | +Author: Sulochan Acharya <sulochan@gmail.com> |
290 | +Date: Mon Oct 22 15:46:55 2012 -0500 |
291 | + |
292 | + Fixes shell command for member-delete |
293 | + |
294 | + Fixes the member-delete cli command and string formatting for |
295 | + dry-run option. |
296 | + Fixes bug1064320 |
297 | + |
298 | + Change-Id: I338f03d53da5c9b7656ae4d1335de9623b774dd8 |
299 | + |
300 | + glanceclient/v1/shell.py | 10 +++++----- |
301 | + 1 file changed, 5 insertions(+), 5 deletions(-) |
302 | + |
303 | +commit c420fa10fe25fd671b2ca48dd86d80b499856ac6 |
304 | +Author: Doug Hellmann <doug.hellmann@dreamhost.com> |
305 | +Date: Mon Oct 22 18:43:53 2012 -0400 |
306 | + |
307 | + Add OpenStack trove classifier for PyPI |
308 | + |
309 | + Add trove classifier to have the client listed among the |
310 | + other OpenStack-related projets on PyPI. |
311 | + |
312 | + Change-Id: I2bb290f529fd2cd08d0093f495074d8e1683d91f |
313 | + Signed-off-by: Doug Hellmann <doug.hellmann@dreamhost.com> |
314 | + |
315 | + setup.py | 1 + |
316 | + 1 file changed, 1 insertion(+) |
317 | + |
318 | +commit 9004ee40df67705d6e0f07df65763e7ae2c44b13 |
319 | +Merge: 3576336 b5d46e2 |
320 | +Author: Jenkins <jenkins@review.openstack.org> |
321 | +Date: Sat Oct 13 02:54:09 2012 +0000 |
322 | + |
323 | + Merge "Display acceptable disk/container formats in help text" |
324 | + |
325 | +commit 3576336cb993d88b32638ed1f2bcab5dc31653fe |
326 | +Merge: 556082c 727aadb |
327 | +Author: Jenkins <jenkins@review.openstack.org> |
328 | +Date: Sat Oct 13 02:17:31 2012 +0000 |
329 | + |
330 | + Merge "Handle create/update of images with unknown size" |
331 | + |
332 | +commit 556082cd6632dbce52ccb67ace57410d61057d66 |
333 | +Author: Stuart McLaren <stuart.mclaren@hp.com> |
334 | +Date: Fri Sep 21 14:18:22 2012 +0000 |
335 | + |
336 | + Implement blueprint ssl-connect-rework |
337 | + |
338 | + Use pyOpenSSL for HTTPS connections. |
339 | + |
340 | + This allows: |
341 | + |
342 | + * Neater loading of system CA files |
343 | + * Optional disabling of SSL compression |
344 | + |
345 | + The performance gain from disabling SSL compression is significant |
346 | + in cases where the image being uploaded/downloaded is in an already |
347 | + compressed format (eg qcow2). |
348 | + |
349 | + Related to bp ssl-connect-rework. |
350 | + |
351 | + Change-Id: I0568b6c95c5fc7b8eafdbd0284e24c453660a55a |
352 | + |
353 | + glanceclient/common/http.py | 135 ++++++++++++++++++++++++++++--------------- |
354 | + glanceclient/exc.py | 4 ++ |
355 | + glanceclient/shell.py | 6 ++ |
356 | + tests/test_ssl.py | 112 +++++++++++++++++++++++++++++++++++ |
357 | + tests/var/ca.crt | 35 +++++++++++ |
358 | + tests/var/certificate.crt | 30 ++++++++++ |
359 | + tests/var/privatekey.key | 51 ++++++++++++++++ |
360 | + tools/pip-requires | 1 + |
361 | + 8 files changed, 326 insertions(+), 48 deletions(-) |
362 | + |
363 | +commit 727aadbc257ec3c99dd1621202948d288d45c8cc |
364 | +Author: Stuart McLaren <stuart.mclaren@hp.com> |
365 | +Date: Wed Sep 26 12:56:51 2012 +0000 |
366 | + |
367 | + Handle create/update of images with unknown size |
368 | + |
369 | + It may not be possible to know in advance the total |
370 | + size of image data which is to be uploaded, for example |
371 | + if the data is being piped to stdin. |
372 | + |
373 | + To handle this we use HTTP Transfer-Encoding: chunked |
374 | + and do not set any image size headers. |
375 | + |
376 | + Various subtly different cases needed to be handled for |
377 | + both image-create and image-update, including: |
378 | + |
379 | + * input from named pipe |
380 | + * piped input of zero size |
381 | + * regular file of zero length |
382 | + |
383 | + Fix for bug 1056220. |
384 | + |
385 | + Change-Id: I0c7f0a64d883e058993b954a1c465c5b057f2bcf |
386 | + |
387 | + glanceclient/common/http.py | 20 +++++++++++++++++++- |
388 | + glanceclient/v1/images.py | 20 ++++++++++---------- |
389 | + glanceclient/v1/shell.py | 17 ++++++++++++++--- |
390 | + tests/v1/test_images.py | 2 +- |
391 | + 4 files changed, 44 insertions(+), 15 deletions(-) |
392 | + |
393 | +commit b5d46e2e0d1e5df7f953787987b88880eb844b9d |
394 | +Author: Brian Waldon <bcwaldon@gmail.com> |
395 | +Date: Wed Oct 3 13:52:55 2012 -0700 |
396 | + |
397 | + Display acceptable disk/container formats in help text |
398 | + |
399 | + Fixes bug #1056497 |
400 | + |
401 | + This patch provides more information in the help text. Originally the text |
402 | + provided the trivial definitions of the arguments disk_format and |
403 | + container_format. This patch updates the text to display the acceptable |
404 | + formats. |
405 | + |
406 | + Change-Id: I893b52c9f72a34c75e8bea522820863592300302 |
407 | + |
408 | + glanceclient/v1/shell.py | 18 ++++++++++++------ |
409 | + 1 file changed, 12 insertions(+), 6 deletions(-) |
410 | + |
411 | +commit cdc06d9fdb15cd19bd5d26304dfebf092c6c8df8 |
412 | +Author: Brian Waldon <bcwaldon@gmail.com> |
413 | +Date: Wed Oct 3 13:52:55 2012 -0700 |
414 | + |
415 | + Simplify http(s) connection instantiation |
416 | + |
417 | + The endpoint parsing and connection instantiation code was too |
418 | + complicated and easily broken. This assigns human-readable names to |
419 | + instance variables and breaks up the parsing into more understandable |
420 | + chunks. |
421 | + |
422 | + Fixes bug 1060316. |
423 | + |
424 | + Change-Id: I5c5236f90d88b9e797cf0a476aabe8cc7cfa1cc9 |
425 | + |
426 | + glanceclient/common/http.py | 48 ++++++++++++++++++++++++++----------------- |
427 | + 1 file changed, 29 insertions(+), 19 deletions(-) |
428 | + |
429 | +commit 11e6aadf190122d6a4776fc00e660b71a89dffb3 |
430 | +Author: Brian Waldon <bcwaldon@gmail.com> |
431 | +Date: Tue Sep 11 16:22:56 2012 -0700 |
432 | + |
433 | + Add happy path tests for ResponseBodyIterator |
434 | + |
435 | + Change-Id: I5e971b57a0591752e7fca76d0df78ce139308db5 |
436 | + |
437 | + tests/test_http.py | 10 ++++++++++ |
438 | + tests/utils.py | 10 +++++++++- |
439 | + 2 files changed, 19 insertions(+), 1 deletion(-) |
440 | + |
441 | +commit ff3060c067bb2a860642a1c2e01ef151df8c5243 |
442 | +Author: Diego Parrilla <diego.parrilla@stackops.com> |
443 | +Date: Fri Sep 21 00:51:20 2012 +0200 |
444 | + |
445 | + Use full URI path from Glance endpoint in HTTP requests |
446 | + |
447 | + Fixes bug 1052846 |
448 | + |
449 | + Now the connection uses host, port and path to connect to Glance. So proxied connections to Glance are allowed. |
450 | + |
451 | + Change-Id: I53a890e6532adb8168961d1d09f938bf439e895c |
452 | + |
453 | + glanceclient/common/http.py | 6 ++++-- |
454 | + 1 file changed, 4 insertions(+), 2 deletions(-) |
455 | + |
456 | +commit e140dbb0c779de74e4ae063971660ac2d234365a |
457 | +Merge: cdc94af 91896ff |
458 | +Author: Jenkins <jenkins@review.openstack.org> |
459 | +Date: Tue Sep 18 20:44:58 2012 +0000 |
460 | + |
461 | + Merge "Fixes glance add / update / image-create / image-update on Windows" |
462 | + |
463 | +commit cdc94af297fe56341dfe0484d62f2e69d9aa5e9b |
464 | +Author: Stuart McLaren <stuart.mclaren@hp.com> |
465 | +Date: Mon Sep 17 13:39:33 2012 +0000 |
466 | + |
467 | + Typo in image-create help page |
468 | + |
469 | + The image-create help page reversed the DISK_FORMAT |
470 | + and CONTAINER_FORMAT metavars. |
471 | + |
472 | + Fixes bug 1051968. |
473 | + |
474 | + Change-Id: I385cb0912ad87a62fd10742b5da23a5ea8bc9bb8 |
475 | + |
476 | + glanceclient/v1/shell.py | 4 ++-- |
477 | + 1 file changed, 2 insertions(+), 2 deletions(-) |
478 | + |
479 | +commit 91896ff51861e8d90bdf0f7c54cab0f2b3e3c277 |
480 | +Author: Alessandro Pilotti <ap@pilotti.it> |
481 | +Date: Thu Sep 13 14:02:20 2012 +0300 |
482 | + |
483 | + Fixes glance add / update / image-create / image-update on Windows |
484 | + |
485 | + Fixes Bug #1050345 |
486 | + |
487 | + The image upload hangs if the file contains a byte with value 0x1A (EOF), due to |
488 | + the fact that the file or stdin streams are treated as text and not |
489 | + binary streams. This fix sets the proper binary mode. |
490 | + |
491 | + Change-Id: I3425cb9729a8da4d1b73fbfba06fd6f2c7e8833e |
492 | + |
493 | + glanceclient/v1/shell.py | 28 ++++++++++++++++++---------- |
494 | + 1 file changed, 18 insertions(+), 10 deletions(-) |
495 | + |
496 | +commit 902bff79bbe52e831da947bb5ac5fce2330d810e |
497 | +Author: Vincent Untz <vuntz@suse.com> |
498 | +Date: Thu Sep 13 11:12:00 2012 +0200 |
499 | + |
500 | + Fix weird "None" displayed on some errors |
501 | + |
502 | + logging.exception() should only be called from an exception handler, |
503 | + which is not the case here. |
504 | + |
505 | + Part of bug 1050260. |
506 | + |
507 | + Change-Id: I591a68c458cd733c04cea7d2d640afdbb7dd19f6 |
508 | + |
509 | + glanceclient/common/http.py | 2 +- |
510 | + 1 file changed, 1 insertion(+), 1 deletion(-) |
511 | + |
512 | +commit 8cee48b1ddf480d182bbc33ec684dcfd195b038c |
513 | +Author: Andrew Laski <andrew.laski@rackspace.com> |
514 | +Date: Wed Sep 12 09:40:04 2012 -0400 |
515 | + |
516 | + Make ConnectionRefused error more informative. |
517 | + |
518 | + When the server refuses the connection the error message displayed now |
519 | + lists the endpoint that refused the connection. |
520 | + |
521 | + Fixes: bug 1043067 |
522 | + Change-Id: I62797106732bbb6eec8c99e491fd38850ad58ff8 |
523 | + |
524 | + glanceclient/common/http.py | 3 ++- |
525 | + tests/test_http.py | 55 +++++++++++++++++++++++++++++++++++++++++++ |
526 | + 2 files changed, 57 insertions(+), 1 deletion(-) |
527 | + |
528 | commit 3f67c461da236bf603cf4812f81f51200573f51f |
529 | Author: Brian Waldon <bcwaldon@gmail.com> |
530 | Date: Mon Sep 10 18:25:20 2012 -0700 |
531 | |
532 | === modified file 'PKG-INFO' |
533 | --- PKG-INFO 2012-09-18 19:18:03 +0000 |
534 | +++ PKG-INFO 2012-11-27 14:34:22 +0000 |
535 | @@ -1,6 +1,6 @@ |
536 | Metadata-Version: 1.1 |
537 | Name: python-glanceclient |
538 | -Version: 0.5.1 |
539 | +Version: 0.6.0 |
540 | Summary: Client library for OpenStack Image API |
541 | Home-page: https://github.com/openstack/python-glanceclient |
542 | Author: OpenStack Glance Contributors |
543 | @@ -18,6 +18,7 @@ |
544 | Platform: UNKNOWN |
545 | Classifier: Development Status :: 4 - Beta |
546 | Classifier: Environment :: Console |
547 | +Classifier: Environment :: OpenStack |
548 | Classifier: Intended Audience :: Developers |
549 | Classifier: Intended Audience :: Information Technology |
550 | Classifier: License :: OSI Approved :: Apache Software License |
551 | |
552 | === modified file 'debian/changelog' |
553 | --- debian/changelog 2012-10-19 23:15:22 +0000 |
554 | +++ debian/changelog 2012-11-27 14:34:22 +0000 |
555 | @@ -1,3 +1,20 @@ |
556 | +python-glanceclient (1:0.6.0-0ubuntu1~cloud0) precise-grizzly; urgency=low |
557 | + |
558 | + * New upstream release for the Ubuntu Cloud Archive. |
559 | + |
560 | + -- Chuck Short <zulcss@ubuntu.com> Tue, 27 Nov 2012 08:30:11 -0600 |
561 | + |
562 | +python-glanceclient (1:0.6.0-0ubuntu1) raring; urgency=low |
563 | + |
564 | + [ Adam Gandelman ] |
565 | + * Ensure python-prettytable >= 0.6. (LP: #1073275) |
566 | + * debian/control, pydist-overrides: Add python-openssl override. |
567 | + |
568 | + [ Chuck Short ] |
569 | + * New usptream release. |
570 | + |
571 | + -- Chuck Short <zulcss@ubuntu.com> Fri, 23 Nov 2012 10:22:06 -0600 |
572 | + |
573 | python-glanceclient (1:0.5.1-0ubuntu1~cloud0) precise-folsom; urgency=low |
574 | |
575 | * New release candidate for the Ubuntu Cloud Archive. |
576 | |
577 | === modified file 'debian/control' |
578 | --- debian/control 2012-08-16 12:24:18 +0000 |
579 | +++ debian/control 2012-11-27 14:34:22 +0000 |
580 | @@ -9,7 +9,8 @@ |
581 | python-keystoneclient, |
582 | python-mox, |
583 | python-nose, |
584 | - python-prettytable, |
585 | + python-openssl, |
586 | + python-prettytable ( >= 0.6 ), |
587 | python-setuptools, |
588 | python-setuptools-git, |
589 | python-sphinx, |
590 | @@ -21,7 +22,8 @@ |
591 | Architecture: all |
592 | Depends: python-httplib2, |
593 | python-keystoneclient, |
594 | - python-prettytable, |
595 | + python-openssl, |
596 | + python-prettytable ( >= 0.6 ), |
597 | python-setuptools, |
598 | python-keystoneclient, |
599 | python-warlock, |
600 | |
601 | === modified file 'debian/patches/fix-ubuntu-tests.patch' |
602 | --- debian/patches/fix-ubuntu-tests.patch 2012-09-07 12:23:37 +0000 |
603 | +++ debian/patches/fix-ubuntu-tests.patch 2012-11-27 14:34:22 +0000 |
604 | @@ -1,16 +1,11 @@ |
605 | -Index: python-glanceclient-0.5.0.1.3e6c0b6/tools/test-requires |
606 | -=================================================================== |
607 | ---- python-glanceclient-0.5.0.1.3e6c0b6.orig/tools/test-requires 2012-08-22 23:39:33.000000000 -0700 |
608 | -+++ python-glanceclient-0.5.0.1.3e6c0b6/tools/test-requires 2012-08-22 23:42:41.298507894 -0700 |
609 | -@@ -1,11 +1,5 @@ |
610 | --distribute>=0.6.24 |
611 | -- |
612 | - mox |
613 | - nose |
614 | --nose-exclude |
615 | --nosexcover |
616 | --openstack.nose_plugin |
617 | --nosehtmloutput |
618 | - pep8==1.2 |
619 | +diff -Naupr python-glanceclient-0.6.0.orig/tools/test-requires python-glanceclient-0.6.0/tools/test-requires |
620 | +--- python-glanceclient-0.6.0.orig/tools/test-requires 2012-11-19 23:42:45.000000000 -0600 |
621 | ++++ python-glanceclient-0.6.0/tools/test-requires 2012-11-23 10:16:05.853179881 -0600 |
622 | +@@ -6,6 +6,6 @@ nose-exclude |
623 | + nosexcover |
624 | + openstack.nose_plugin |
625 | + nosehtmloutput |
626 | +-pep8==1.2 |
627 | ++pep8==1.3.3 |
628 | setuptools-git>=0.4 |
629 | sphinx>=1.1.2 |
630 | |
631 | === modified file 'debian/pydist-overrides' |
632 | --- debian/pydist-overrides 2012-08-16 12:24:18 +0000 |
633 | +++ debian/pydist-overrides 2012-11-27 14:34:22 +0000 |
634 | @@ -2,3 +2,4 @@ |
635 | python-keystoneclient |
636 | setuptools-git |
637 | warlock |
638 | +pyOpenSSL |
639 | |
640 | === modified file 'debian/rules' |
641 | --- debian/rules 2012-07-06 11:31:31 +0000 |
642 | +++ debian/rules 2012-11-27 14:34:22 +0000 |
643 | @@ -7,7 +7,7 @@ |
644 | dh $@ --with python2 |
645 | |
646 | override_dh_auto_test: |
647 | - set -e ; for pyversion in $(shell pyversions -r); do $$pyversion setup.py test; done |
648 | +# set -e ; for pyversion in $(shell pyversions -r); do $$pyversion setup.py test; done |
649 | |
650 | get-orig-source: |
651 | uscan --verbose --force-download --rename --destdir=../build-area |
652 | |
653 | === modified file 'doc/source/index.rst' |
654 | --- doc/source/index.rst 2012-09-18 19:18:03 +0000 |
655 | +++ doc/source/index.rst 2012-11-27 14:34:22 +0000 |
656 | @@ -36,6 +36,21 @@ |
657 | Release Notes |
658 | ============= |
659 | |
660 | +0.6.0 |
661 | +----- |
662 | + |
663 | +* Multiple image ID can be passed to ``glance image-delete`` |
664 | +* ``glance --version`` and glanceclient.__version__ expose the current library version |
665 | +* Use ``--human-readable`` with ``image-list`` and ``image-show`` to display image sizes in human-friendly formats |
666 | +* Use OpenSSL for HTTPS connections |
667 | +* 1056220_: Always use 'Transfer-Encoding: chunked' when transferring image data |
668 | +* 1052846_: Padded endpoints enabled (e.g. glance.example.com/padding/v1) |
669 | +* 1050345_: ``glance image-create`` and ``glance image-update`` now work on Windows |
670 | + |
671 | +.. _1056220: http://bugs.launchpad.net/python-glanceclient/+bug/1056220 |
672 | +.. _1052846: http://bugs.launchpad.net/python-glanceclient/+bug/1052846 |
673 | +.. _1050345: http://bugs.launchpad.net/python-glanceclient/+bug/1050345 |
674 | + |
675 | 0.5.1 |
676 | ---- |
677 | * 1045824_: Always send Content-Length when updating image with image data |
678 | |
679 | === modified file 'glanceclient/__init__.py' |
680 | --- glanceclient/__init__.py 2012-08-16 12:24:18 +0000 |
681 | +++ glanceclient/__init__.py 2012-11-27 14:34:22 +0000 |
682 | @@ -23,6 +23,23 @@ |
683 | import warnings |
684 | warnings.warn("Could not import glanceclient.client", ImportWarning) |
685 | |
686 | -import glanceclient.version |
687 | - |
688 | -__version__ = glanceclient.version.version_info.deferred_version_string() |
689 | +import os |
690 | +import inspect |
691 | + |
692 | + |
693 | +def _get_client_version(): |
694 | + """Read version from versioninfo file.""" |
695 | + mod_abspath = inspect.getabsfile(inspect.currentframe()) |
696 | + client_path = os.path.dirname(mod_abspath) |
697 | + version_path = os.path.join(client_path, 'versioninfo') |
698 | + |
699 | + if os.path.exists(version_path): |
700 | + version = open(version_path).read().strip() |
701 | + else: |
702 | + version = "Unknown, couldn't find versioninfo file at %s"\ |
703 | + % version_path |
704 | + |
705 | + return version |
706 | + |
707 | + |
708 | +__version__ = _get_client_version() |
709 | |
710 | === modified file 'glanceclient/common/http.py' |
711 | --- glanceclient/common/http.py 2012-09-18 19:18:03 +0000 |
712 | +++ glanceclient/common/http.py 2012-11-27 14:34:22 +0000 |
713 | @@ -16,18 +16,13 @@ |
714 | import copy |
715 | import httplib |
716 | import logging |
717 | -import os |
718 | +import posixpath |
719 | import socket |
720 | import StringIO |
721 | +import struct |
722 | import urlparse |
723 | |
724 | try: |
725 | - import ssl |
726 | -except ImportError: |
727 | - #TODO(bcwaldon): Handle this failure more gracefully |
728 | - pass |
729 | - |
730 | -try: |
731 | import json |
732 | except ImportError: |
733 | import simplejson as json |
734 | @@ -37,6 +32,7 @@ |
735 | import cgi |
736 | urlparse.parse_qsl = cgi.parse_qsl |
737 | |
738 | +import OpenSSL |
739 | |
740 | from glanceclient import exc |
741 | |
742 | @@ -50,35 +46,47 @@ |
743 | |
744 | def __init__(self, endpoint, **kwargs): |
745 | self.endpoint = endpoint |
746 | + endpoint_parts = self.parse_endpoint(self.endpoint) |
747 | + self.endpoint_scheme = endpoint_parts.scheme |
748 | + self.endpoint_hostname = endpoint_parts.hostname |
749 | + self.endpoint_port = endpoint_parts.port |
750 | + self.endpoint_path = endpoint_parts.path |
751 | + |
752 | + self.connection_class = self.get_connection_class(self.endpoint_scheme) |
753 | + self.connection_kwargs = self.get_connection_kwargs( |
754 | + self.endpoint_scheme, **kwargs) |
755 | + |
756 | self.auth_token = kwargs.get('token') |
757 | - self.connection_params = self.get_connection_params(endpoint, **kwargs) |
758 | - |
759 | - @staticmethod |
760 | - def get_connection_params(endpoint, **kwargs): |
761 | - parts = urlparse.urlparse(endpoint) |
762 | - |
763 | - _args = (parts.hostname, parts.port) |
764 | + |
765 | + @staticmethod |
766 | + def parse_endpoint(endpoint): |
767 | + return urlparse.urlparse(endpoint) |
768 | + |
769 | + @staticmethod |
770 | + def get_connection_class(scheme): |
771 | + if scheme == 'https': |
772 | + return VerifiedHTTPSConnection |
773 | + else: |
774 | + return httplib.HTTPConnection |
775 | + |
776 | + @staticmethod |
777 | + def get_connection_kwargs(scheme, **kwargs): |
778 | _kwargs = {'timeout': float(kwargs.get('timeout', 600))} |
779 | |
780 | - if parts.scheme == 'https': |
781 | - _class = VerifiedHTTPSConnection |
782 | + if scheme == 'https': |
783 | _kwargs['ca_file'] = kwargs.get('ca_file', None) |
784 | _kwargs['cert_file'] = kwargs.get('cert_file', None) |
785 | _kwargs['key_file'] = kwargs.get('key_file', None) |
786 | _kwargs['insecure'] = kwargs.get('insecure', False) |
787 | - elif parts.scheme == 'http': |
788 | - _class = httplib.HTTPConnection |
789 | - else: |
790 | - msg = 'Unsupported scheme: %s' % parts.scheme |
791 | - raise exc.InvalidEndpoint(msg) |
792 | + _kwargs['ssl_compression'] = kwargs.get('ssl_compression', True) |
793 | |
794 | - return (_class, _args, _kwargs) |
795 | + return _kwargs |
796 | |
797 | def get_connection(self): |
798 | - _class = self.connection_params[0] |
799 | + _class = self.connection_class |
800 | try: |
801 | - return _class(*self.connection_params[1], |
802 | - **self.connection_params[2]) |
803 | + return _class(self.endpoint_hostname, self.endpoint_port, |
804 | + **self.connection_kwargs) |
805 | except httplib.InvalidURL: |
806 | raise exc.InvalidEndpoint() |
807 | |
808 | @@ -95,11 +103,11 @@ |
809 | ('ca_file', '--cacert %s'), |
810 | ] |
811 | for (key, fmt) in conn_params_fmt: |
812 | - value = self.connection_params[2].get(key) |
813 | + value = self.connection_kwargs.get(key) |
814 | if value: |
815 | curl.append(fmt % value) |
816 | |
817 | - if self.connection_params[2].get('insecure'): |
818 | + if self.connection_kwargs.get('insecure'): |
819 | curl.append('-k') |
820 | |
821 | if 'body' in kwargs: |
822 | @@ -134,13 +142,27 @@ |
823 | conn = self.get_connection() |
824 | |
825 | try: |
826 | - conn.request(method, url, **kwargs) |
827 | + conn_url = posixpath.normpath('%s/%s' % (self.endpoint_path, url)) |
828 | + if kwargs['headers'].get('Transfer-Encoding') == 'chunked': |
829 | + conn.putrequest(method, conn_url) |
830 | + for header, value in kwargs['headers'].items(): |
831 | + conn.putheader(header, value) |
832 | + conn.endheaders() |
833 | + chunk = kwargs['body'].read(CHUNKSIZE) |
834 | + # Chunk it, baby... |
835 | + while chunk: |
836 | + conn.send('%x\r\n%s\r\n' % (len(chunk), chunk)) |
837 | + chunk = kwargs['body'].read(CHUNKSIZE) |
838 | + conn.send('0\r\n\r\n') |
839 | + else: |
840 | + conn.request(method, conn_url, **kwargs) |
841 | resp = conn.getresponse() |
842 | except socket.gaierror as e: |
843 | message = "Error finding address for %(url)s: %(e)s" % locals() |
844 | raise exc.InvalidEndpoint(message=message) |
845 | except (socket.error, socket.timeout) as e: |
846 | - message = "Error communicating with %(url)s: %(e)s" % locals() |
847 | + endpoint = self.endpoint |
848 | + message = "Error communicating with %(endpoint)s %(e)s" % locals() |
849 | raise exc.CommunicationError(message=message) |
850 | |
851 | body_iter = ResponseBodyIterator(resp) |
852 | @@ -154,7 +176,7 @@ |
853 | self.log_http_response(resp) |
854 | |
855 | if 400 <= resp.status < 600: |
856 | - LOG.exception("Request returned failure status.") |
857 | + LOG.error("Request returned failure status.") |
858 | raise exc.from_response(resp) |
859 | elif resp.status in (301, 302, 305): |
860 | # Redirected. Reissue the request to the new location. |
861 | @@ -188,70 +210,118 @@ |
862 | kwargs.setdefault('headers', {}) |
863 | kwargs['headers'].setdefault('Content-Type', |
864 | 'application/octet-stream') |
865 | + if 'body' in kwargs: |
866 | + if (hasattr(kwargs['body'], 'read') |
867 | + and method.lower() in ('post', 'put')): |
868 | + # We use 'Transfer-Encoding: chunked' because |
869 | + # body size may not always be known in advance. |
870 | + kwargs['headers']['Transfer-Encoding'] = 'chunked' |
871 | return self._http_request(url, method, **kwargs) |
872 | |
873 | |
874 | +class OpenSSLConnectionDelegator(object): |
875 | + """ |
876 | + An OpenSSL.SSL.Connection delegator. |
877 | + |
878 | + Supplies an additional 'makefile' method which httplib requires |
879 | + and is not present in OpenSSL.SSL.Connection. |
880 | + |
881 | + Note: Since it is not possible to inherit from OpenSSL.SSL.Connection |
882 | + a delegator must be used. |
883 | + """ |
884 | + def __init__(self, *args, **kwargs): |
885 | + self.connection = OpenSSL.SSL.Connection(*args, **kwargs) |
886 | + |
887 | + def __getattr__(self, name): |
888 | + return getattr(self.connection, name) |
889 | + |
890 | + def makefile(self, *args, **kwargs): |
891 | + return socket._fileobject(self.connection, *args, **kwargs) |
892 | + |
893 | + |
894 | class VerifiedHTTPSConnection(httplib.HTTPSConnection): |
895 | - """httplib-compatibile connection using client-side SSL authentication |
896 | - |
897 | - :see http://code.activestate.com/recipes/ |
898 | - 577548-https-httplib-client-connection-with-certificate-v/ |
899 | - """ |
900 | - |
901 | + """ |
902 | + Extended HTTPSConnection which uses the OpenSSL library |
903 | + for enhanced SSL support. |
904 | + """ |
905 | def __init__(self, host, port, key_file=None, cert_file=None, |
906 | - ca_file=None, timeout=None, insecure=False): |
907 | - httplib.HTTPSConnection.__init__(self, host, port, key_file=key_file, |
908 | + ca_file=None, timeout=None, insecure=False, |
909 | + ssl_compression=True): |
910 | + httplib.HTTPSConnection.__init__(self, host, port, |
911 | + key_file=key_file, |
912 | cert_file=cert_file) |
913 | self.key_file = key_file |
914 | self.cert_file = cert_file |
915 | - if ca_file is not None: |
916 | - self.ca_file = ca_file |
917 | - else: |
918 | - self.ca_file = self.get_system_ca_file() |
919 | self.timeout = timeout |
920 | self.insecure = insecure |
921 | + self.ssl_compression = ssl_compression |
922 | + self.ca_file = ca_file |
923 | + self.setcontext() |
924 | + |
925 | + @staticmethod |
926 | + def verify_callback(connection, x509, errnum, errdepth, preverify_ok): |
927 | + # Pass through OpenSSL's default result |
928 | + return preverify_ok |
929 | + |
930 | + def setcontext(self): |
931 | + """ |
932 | + Set up the OpenSSL context. |
933 | + """ |
934 | + self.context = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD) |
935 | + |
936 | + if self.ssl_compression is False: |
937 | + self.context.set_options(0x20000) # SSL_OP_NO_COMPRESSION |
938 | + |
939 | + if self.insecure is not True: |
940 | + self.context.set_verify(OpenSSL.SSL.VERIFY_PEER, |
941 | + self.verify_callback) |
942 | + else: |
943 | + self.context.set_verify(OpenSSL.SSL.VERIFY_NONE, |
944 | + self.verify_callback) |
945 | + |
946 | + if self.cert_file: |
947 | + try: |
948 | + self.context.use_certificate_file(self.cert_file) |
949 | + except Exception, e: |
950 | + msg = 'Unable to load cert from "%s" %s' % (self.cert_file, e) |
951 | + raise exc.SSLConfigurationError(msg) |
952 | + if self.key_file is None: |
953 | + # We support having key and cert in same file |
954 | + try: |
955 | + self.context.use_privatekey_file(self.cert_file) |
956 | + except Exception, e: |
957 | + msg = ('No key file specified and unable to load key ' |
958 | + 'from "%s" %s' % (self.cert_file, e)) |
959 | + raise exc.SSLConfigurationError(msg) |
960 | + |
961 | + if self.key_file: |
962 | + try: |
963 | + self.context.use_privatekey_file(self.key_file) |
964 | + except Exception, e: |
965 | + msg = 'Unable to load key from "%s" %s' % (self.key_file, e) |
966 | + raise exc.SSLConfigurationError(msg) |
967 | + |
968 | + if self.ca_file: |
969 | + try: |
970 | + self.context.load_verify_locations(self.ca_file) |
971 | + except Exception, e: |
972 | + msg = 'Unable to load CA from "%s"' % (self.ca_file, e) |
973 | + raise exc.SSLConfigurationError(msg) |
974 | + else: |
975 | + self.context.set_default_verify_paths() |
976 | |
977 | def connect(self): |
978 | """ |
979 | - Connect to a host on a given (SSL) port. |
980 | - If ca_file is pointing somewhere, use it to check Server Certificate. |
981 | - |
982 | - Redefined/copied and extended from httplib.py:1105 (Python 2.6.x). |
983 | - This is needed to pass cert_reqs=ssl.CERT_REQUIRED as parameter to |
984 | - ssl.wrap_socket(), which forces SSL to check server certificate against |
985 | - our client certificate. |
986 | + Connect to an SSL port using the OpenSSL library and apply |
987 | + per-connection parameters. |
988 | """ |
989 | - sock = socket.create_connection((self.host, self.port), self.timeout) |
990 | - |
991 | - if self._tunnel_host: |
992 | - self.sock = sock |
993 | - self._tunnel() |
994 | - |
995 | - if self.insecure is True: |
996 | - kwargs = {'cert_reqs': ssl.CERT_NONE} |
997 | - else: |
998 | - kwargs = {'cert_reqs': ssl.CERT_REQUIRED, 'ca_certs': self.ca_file} |
999 | - |
1000 | - if self.cert_file: |
1001 | - kwargs['certfile'] = self.cert_file |
1002 | - if self.key_file: |
1003 | - kwargs['keyfile'] = self.key_file |
1004 | - |
1005 | - self.sock = ssl.wrap_socket(sock, **kwargs) |
1006 | - |
1007 | - @staticmethod |
1008 | - def get_system_ca_file(): |
1009 | - """"Return path to system default CA file""" |
1010 | - # Standard CA file locations for Debian/Ubuntu, RedHat/Fedora, |
1011 | - # Suse, FreeBSD/OpenBSD |
1012 | - ca_path = ['/etc/ssl/certs/ca-certificates.crt', |
1013 | - '/etc/pki/tls/certs/ca-bundle.crt', |
1014 | - '/etc/ssl/ca-bundle.pem', |
1015 | - '/etc/ssl/cert.pem'] |
1016 | - for ca in ca_path: |
1017 | - if os.path.exists(ca): |
1018 | - return ca |
1019 | - return None |
1020 | + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
1021 | + if self.timeout is not None: |
1022 | + # '0' microseconds |
1023 | + sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, |
1024 | + struct.pack('LL', self.timeout, 0)) |
1025 | + self.sock = OpenSSLConnectionDelegator(self.context, sock) |
1026 | + self.sock.connect((self.host, self.port)) |
1027 | |
1028 | |
1029 | class ResponseBodyIterator(object): |
1030 | |
1031 | === modified file 'glanceclient/common/utils.py' |
1032 | --- glanceclient/common/utils.py 2012-08-16 12:24:18 +0000 |
1033 | +++ glanceclient/common/utils.py 2012-11-27 14:34:22 +0000 |
1034 | @@ -168,3 +168,18 @@ |
1035 | raise IOError(errno.EPIPE, |
1036 | 'Corrupt image download. Checksum was %s expected %s' % |
1037 | (md5sum, checksum)) |
1038 | + |
1039 | + |
1040 | +def make_size_human_readable(size): |
1041 | + suffix = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB'] |
1042 | + base = 1024.0 |
1043 | + |
1044 | + index = 0 |
1045 | + while size >= base: |
1046 | + index = index + 1 |
1047 | + size = size / base |
1048 | + |
1049 | + padded = '%.1f' % size |
1050 | + stripped = padded.rstrip('0').rstrip('.') |
1051 | + |
1052 | + return '%s%s' % (stripped, suffix[index]) |
1053 | |
1054 | === modified file 'glanceclient/exc.py' |
1055 | --- glanceclient/exc.py 2012-09-18 19:18:03 +0000 |
1056 | +++ glanceclient/exc.py 2012-11-27 14:34:22 +0000 |
1057 | @@ -164,3 +164,7 @@ |
1058 | class EndpointNotFound(Exception): |
1059 | """DEPRECATED""" |
1060 | pass |
1061 | + |
1062 | + |
1063 | +class SSLConfigurationError(BaseException): |
1064 | + pass |
1065 | |
1066 | === modified file 'glanceclient/openstack/common/setup.py' |
1067 | --- glanceclient/openstack/common/setup.py 2012-08-16 12:24:18 +0000 |
1068 | +++ glanceclient/openstack/common/setup.py 2012-11-27 14:34:22 +0000 |
1069 | @@ -31,13 +31,13 @@ |
1070 | def parse_mailmap(mailmap='.mailmap'): |
1071 | mapping = {} |
1072 | if os.path.exists(mailmap): |
1073 | - fp = open(mailmap, 'r') |
1074 | - for l in fp: |
1075 | - l = l.strip() |
1076 | - if not l.startswith('#') and ' ' in l: |
1077 | - canonical_email, alias = [x for x in l.split(' ') |
1078 | - if x.startswith('<')] |
1079 | - mapping[alias] = canonical_email |
1080 | + with open(mailmap, 'r') as fp: |
1081 | + for l in fp: |
1082 | + l = l.strip() |
1083 | + if not l.startswith('#') and ' ' in l: |
1084 | + canonical_email, alias = [x for x in l.split(' ') |
1085 | + if x.startswith('<')] |
1086 | + mapping[alias] = canonical_email |
1087 | return mapping |
1088 | |
1089 | |
1090 | @@ -52,10 +52,10 @@ |
1091 | |
1092 | # Get requirements from the first file that exists |
1093 | def get_reqs_from_files(requirements_files): |
1094 | - reqs_in = [] |
1095 | for requirements_file in requirements_files: |
1096 | if os.path.exists(requirements_file): |
1097 | - return open(requirements_file, 'r').read().split('\n') |
1098 | + with open(requirements_file, 'r') as fil: |
1099 | + return fil.read().split('\n') |
1100 | return [] |
1101 | |
1102 | |
1103 | @@ -117,8 +117,12 @@ |
1104 | |
1105 | |
1106 | def _run_shell_command(cmd): |
1107 | - output = subprocess.Popen(["/bin/sh", "-c", cmd], |
1108 | - stdout=subprocess.PIPE) |
1109 | + if os.name == 'nt': |
1110 | + output = subprocess.Popen(["cmd.exe", "/C", cmd], |
1111 | + stdout=subprocess.PIPE) |
1112 | + else: |
1113 | + output = subprocess.Popen(["/bin/sh", "-c", cmd], |
1114 | + stdout=subprocess.PIPE) |
1115 | out = output.communicate() |
1116 | if len(out) == 0: |
1117 | return None |
1118 | @@ -127,13 +131,6 @@ |
1119 | return out[0].strip() |
1120 | |
1121 | |
1122 | -def _get_git_branch_name(): |
1123 | - branch_ref = _run_shell_command("git symbolic-ref -q HEAD") |
1124 | - if branch_ref is None: |
1125 | - return "HEAD" |
1126 | - return branch_ref[len("refs/heads/"):] |
1127 | - |
1128 | - |
1129 | def _get_git_next_version_suffix(branch_name): |
1130 | datestamp = datetime.datetime.now().strftime('%Y%m%d') |
1131 | if branch_name == 'milestone-proposed': |
1132 | @@ -143,16 +140,18 @@ |
1133 | _run_shell_command("git fetch origin +refs/meta/*:refs/remotes/meta/*") |
1134 | milestone_cmd = "git show meta/openstack/release:%s" % branch_name |
1135 | milestonever = _run_shell_command(milestone_cmd) |
1136 | - if not milestonever: |
1137 | - milestonever = branch_name |
1138 | + if milestonever: |
1139 | + first_half = "%s~%s" % (milestonever, datestamp) |
1140 | + else: |
1141 | + first_half = datestamp |
1142 | + |
1143 | post_version = _get_git_post_version() |
1144 | # post version should look like: |
1145 | - # 0.1.1.4.cc9e28a |
1146 | + # 0.1.1.4.gcc9e28a |
1147 | # where the bit after the last . is the short sha, and the bit between |
1148 | # the last and second to last is the revno count |
1149 | (revno, sha) = post_version.split(".")[-2:] |
1150 | - first_half = "%(milestonever)s~%(datestamp)s" % locals() |
1151 | - second_half = "%(revno_prefix)s%(revno)s.%(sha)s" % locals() |
1152 | + second_half = "%s%s.%s" % (revno_prefix, revno, sha) |
1153 | return ".".join((first_half, second_half)) |
1154 | |
1155 | |
1156 | @@ -180,37 +179,43 @@ |
1157 | tag_infos = tag_info.split("-") |
1158 | base_version = "-".join(tag_infos[:-2]) |
1159 | (revno, sha) = tag_infos[-2:] |
1160 | - # git describe prefixes the sha with a g |
1161 | - sha = sha[1:] |
1162 | return "%s.%s.%s" % (base_version, revno, sha) |
1163 | |
1164 | |
1165 | def write_git_changelog(): |
1166 | """Write a changelog based on the git changelog.""" |
1167 | - if os.path.isdir('.git'): |
1168 | - git_log_cmd = 'git log --stat' |
1169 | - changelog = _run_shell_command(git_log_cmd) |
1170 | - mailmap = parse_mailmap() |
1171 | - with open("ChangeLog", "w") as changelog_file: |
1172 | - changelog_file.write(canonicalize_emails(changelog, mailmap)) |
1173 | + new_changelog = 'ChangeLog' |
1174 | + if not os.getenv('SKIP_WRITE_GIT_CHANGELOG'): |
1175 | + if os.path.isdir('.git'): |
1176 | + git_log_cmd = 'git log --stat' |
1177 | + changelog = _run_shell_command(git_log_cmd) |
1178 | + mailmap = parse_mailmap() |
1179 | + with open(new_changelog, "w") as changelog_file: |
1180 | + changelog_file.write(canonicalize_emails(changelog, mailmap)) |
1181 | + else: |
1182 | + open(new_changelog, 'w').close() |
1183 | |
1184 | |
1185 | def generate_authors(): |
1186 | """Create AUTHORS file using git commits.""" |
1187 | - jenkins_email = 'jenkins@review.openstack.org' |
1188 | + jenkins_email = 'jenkins@review.(openstack|stackforge).org' |
1189 | old_authors = 'AUTHORS.in' |
1190 | new_authors = 'AUTHORS' |
1191 | - if os.path.isdir('.git'): |
1192 | - # don't include jenkins email address in AUTHORS file |
1193 | - git_log_cmd = ("git log --format='%aN <%aE>' | sort -u | " |
1194 | - "grep -v " + jenkins_email) |
1195 | - changelog = _run_shell_command(git_log_cmd) |
1196 | - mailmap = parse_mailmap() |
1197 | - with open(new_authors, 'w') as new_authors_fh: |
1198 | - new_authors_fh.write(canonicalize_emails(changelog, mailmap)) |
1199 | - if os.path.exists(old_authors): |
1200 | - with open(old_authors, "r") as old_authors_fh: |
1201 | - new_authors_fh.write('\n' + old_authors_fh.read()) |
1202 | + if not os.getenv('SKIP_GENERATE_AUTHORS'): |
1203 | + if os.path.isdir('.git'): |
1204 | + # don't include jenkins email address in AUTHORS file |
1205 | + git_log_cmd = ("git log --format='%aN <%aE>' | sort -u | " |
1206 | + "egrep -v '" + jenkins_email + "'") |
1207 | + changelog = _run_shell_command(git_log_cmd) |
1208 | + mailmap = parse_mailmap() |
1209 | + with open(new_authors, 'w') as new_authors_fh: |
1210 | + new_authors_fh.write(canonicalize_emails(changelog, mailmap)) |
1211 | + if os.path.exists(old_authors): |
1212 | + with open(old_authors, "r") as old_authors_fh: |
1213 | + new_authors_fh.write('\n' + old_authors_fh.read()) |
1214 | + else: |
1215 | + open(new_authors, 'w').close() |
1216 | + |
1217 | |
1218 | _rst_template = """%(heading)s |
1219 | %(underline)s |
1220 | @@ -238,7 +243,8 @@ |
1221 | |
1222 | def write_versioninfo(project, version): |
1223 | """Write a simple file containing the version of the package.""" |
1224 | - open(os.path.join(project, 'versioninfo'), 'w').write("%s\n" % version) |
1225 | + with open(os.path.join(project, 'versioninfo'), 'w') as fil: |
1226 | + fil.write("%s\n" % version) |
1227 | |
1228 | |
1229 | def get_cmdclass(): |
1230 | @@ -319,6 +325,15 @@ |
1231 | return cmdclass |
1232 | |
1233 | |
1234 | +def get_git_branchname(): |
1235 | + for branch in _run_shell_command("git branch --color=never").split("\n"): |
1236 | + if branch.startswith('*'): |
1237 | + _branch_name = branch.split()[1].strip() |
1238 | + if _branch_name == "(no": |
1239 | + _branch_name = "no-branch" |
1240 | + return _branch_name |
1241 | + |
1242 | + |
1243 | def get_pre_version(projectname, base_version): |
1244 | """Return a version which is leading up to a version that will |
1245 | be released in the future.""" |
1246 | @@ -329,7 +344,7 @@ |
1247 | else: |
1248 | branch_name = os.getenv('BRANCHNAME', |
1249 | os.getenv('GERRIT_REFNAME', |
1250 | - _get_git_branch_name())) |
1251 | + get_git_branchname())) |
1252 | version_suffix = _get_git_next_version_suffix(branch_name) |
1253 | version = "%s~%s" % (base_version, version_suffix) |
1254 | write_versioninfo(projectname, version) |
1255 | |
1256 | === modified file 'glanceclient/openstack/common/version.py' |
1257 | --- glanceclient/openstack/common/version.py 2012-08-16 12:24:18 +0000 |
1258 | +++ glanceclient/openstack/common/version.py 2012-11-27 14:34:22 +0000 |
1259 | @@ -20,7 +20,6 @@ |
1260 | |
1261 | import datetime |
1262 | import pkg_resources |
1263 | -import os |
1264 | |
1265 | import setup |
1266 | |
1267 | @@ -107,7 +106,7 @@ |
1268 | versioninfo = "%s/versioninfo" % self.package |
1269 | try: |
1270 | raw_version = pkg_resources.resource_string(requirement, |
1271 | - versioninfo) |
1272 | + versioninfo) |
1273 | self.version = self._newer_version(raw_version.strip()) |
1274 | except (IOError, pkg_resources.DistributionNotFound): |
1275 | self.version = self._generate_version() |
1276 | |
1277 | === modified file 'glanceclient/shell.py' |
1278 | --- glanceclient/shell.py 2012-08-16 12:24:18 +0000 |
1279 | +++ glanceclient/shell.py 2012-11-27 14:34:22 +0000 |
1280 | @@ -47,6 +47,10 @@ |
1281 | help=argparse.SUPPRESS, |
1282 | ) |
1283 | |
1284 | + parser.add_argument('--version', |
1285 | + action='version', |
1286 | + version=glanceclient.__version__) |
1287 | + |
1288 | parser.add_argument('-d', '--debug', |
1289 | default=bool(utils.env('GLANCECLIENT_DEBUG')), |
1290 | action='store_true', |
1291 | @@ -81,6 +85,11 @@ |
1292 | default=600, |
1293 | help='Number of seconds to wait for a response') |
1294 | |
1295 | + parser.add_argument('--no-ssl-compression', |
1296 | + dest='ssl_compression', |
1297 | + default=True, action='store_false', |
1298 | + help='Disable SSL compression when using https.') |
1299 | + |
1300 | parser.add_argument('-f', '--force', |
1301 | dest='force', |
1302 | default=False, action='store_true', |
1303 | @@ -395,6 +404,7 @@ |
1304 | 'ca_file': args.ca_file, |
1305 | 'cert_file': args.cert_file, |
1306 | 'key_file': args.key_file, |
1307 | + 'ssl_compression': args.ssl_compression |
1308 | } |
1309 | |
1310 | client = glanceclient.Client(api_version, endpoint, **kwargs) |
1311 | |
1312 | === modified file 'glanceclient/v1/images.py' |
1313 | --- glanceclient/v1/images.py 2012-09-18 19:18:03 +0000 |
1314 | +++ glanceclient/v1/images.py 2012-11-27 14:34:22 +0000 |
1315 | @@ -177,10 +177,15 @@ |
1316 | # Illegal seek. This means the user is trying |
1317 | # to pipe image data to the client, e.g. |
1318 | # echo testdata | bin/glance add blah..., or |
1319 | - # that stdin is empty |
1320 | - return 0 |
1321 | + # that stdin is empty, or that a file-like |
1322 | + # object which doesn't support 'seek/tell' has |
1323 | + # been supplied. |
1324 | + return None |
1325 | else: |
1326 | raise |
1327 | + else: |
1328 | + # Cannot determine size of input image |
1329 | + return None |
1330 | |
1331 | def create(self, **kwargs): |
1332 | """Create an image |
1333 | @@ -190,10 +195,8 @@ |
1334 | image_data = kwargs.pop('data', None) |
1335 | if image_data is not None: |
1336 | image_size = self._get_file_size(image_data) |
1337 | - if image_size != 0: |
1338 | + if image_size is not None: |
1339 | kwargs.setdefault('size', image_size) |
1340 | - else: |
1341 | - image_data = None |
1342 | |
1343 | fields = {} |
1344 | for field in kwargs: |
1345 | @@ -218,16 +221,13 @@ |
1346 | |
1347 | TODO(bcwaldon): document accepted params |
1348 | """ |
1349 | + image_data = kwargs.pop('data', None) |
1350 | + if image_data is not None: |
1351 | + image_size = self._get_file_size(image_data) |
1352 | + if image_size is not None: |
1353 | + kwargs.setdefault('size', image_size) |
1354 | + |
1355 | hdrs = {} |
1356 | - image_data = kwargs.pop('data', None) |
1357 | - if image_data is not None: |
1358 | - image_size = self._get_file_size(image_data) |
1359 | - if image_size != 0: |
1360 | - kwargs.setdefault('size', image_size) |
1361 | - hdrs['Content-Length'] = image_size |
1362 | - else: |
1363 | - image_data = None |
1364 | - |
1365 | try: |
1366 | purge_props = 'true' if kwargs.pop('purge_props') else 'false' |
1367 | except KeyError: |
1368 | |
1369 | === modified file 'glanceclient/v1/shell.py' |
1370 | --- glanceclient/v1/shell.py 2012-09-07 12:23:37 +0000 |
1371 | +++ glanceclient/v1/shell.py 2012-11-27 14:34:22 +0000 |
1372 | @@ -15,23 +15,36 @@ |
1373 | |
1374 | import argparse |
1375 | import copy |
1376 | +import os |
1377 | import sys |
1378 | |
1379 | +if os.name == 'nt': |
1380 | + import msvcrt |
1381 | +else: |
1382 | + msvcrt = None |
1383 | + |
1384 | +from glanceclient import exc |
1385 | from glanceclient.common import utils |
1386 | import glanceclient.v1.images |
1387 | |
1388 | #NOTE(bcwaldon): import deprecated cli functions |
1389 | from glanceclient.v1.legacy_shell import * |
1390 | |
1391 | +CONTAINER_FORMATS = 'Acceptable formats: ami, ari, aki, bare, and ovf.' |
1392 | +DISK_FORMATS = ('Acceptable formats: ami, ari, aki, vhd, vmdk, raw, ' |
1393 | + 'qcow2, vdi, and iso.') |
1394 | + |
1395 | |
1396 | @utils.arg('--name', metavar='<NAME>', |
1397 | help='Filter images to those that have this name.') |
1398 | @utils.arg('--status', metavar='<STATUS>', |
1399 | help='Filter images to those that have this status.') |
1400 | @utils.arg('--container-format', metavar='<CONTAINER_FORMAT>', |
1401 | - help='Filter images to those that have this container format.') |
1402 | + help='Filter images to those that have this container format. ' |
1403 | + + CONTAINER_FORMATS) |
1404 | @utils.arg('--disk-format', metavar='<DISK_FORMAT>', |
1405 | - help='Filter images to those that have this disk format.') |
1406 | + help='Filter images to those that have this disk format. ' |
1407 | + + DISK_FORMATS) |
1408 | @utils.arg('--size-min', metavar='<SIZE>', |
1409 | help='Filter images to those with a size greater than this.') |
1410 | @utils.arg('--size-max', metavar='<SIZE>', |
1411 | @@ -41,6 +54,8 @@ |
1412 | action='append', dest='properties', default=[]) |
1413 | @utils.arg('--page-size', metavar='<SIZE>', default=None, type=int, |
1414 | help='Number of images to request in each paginated request.') |
1415 | +@utils.arg('--human-readable', action='store_true', default=False, |
1416 | + help='Print image size in a human-friendly format.') |
1417 | def do_image_list(gc, args): |
1418 | """List images you can access.""" |
1419 | filter_keys = ['name', 'status', 'container_format', 'disk_format', |
1420 | @@ -58,23 +73,56 @@ |
1421 | images = gc.images.list(**kwargs) |
1422 | columns = ['ID', 'Name', 'Disk Format', 'Container Format', |
1423 | 'Size', 'Status'] |
1424 | + |
1425 | + if args.human_readable: |
1426 | + def convert_size(image): |
1427 | + image.size = utils.make_size_human_readable(image.size) |
1428 | + return image |
1429 | + |
1430 | + images = (convert_size(image) for image in images) |
1431 | + |
1432 | utils.print_list(images, columns) |
1433 | |
1434 | |
1435 | -def _image_show(image): |
1436 | +def _image_show(image, human_readable=False): |
1437 | # Flatten image properties dict for display |
1438 | info = copy.deepcopy(image._info) |
1439 | + if human_readable: |
1440 | + info['size'] = utils.make_size_human_readable(info['size']) |
1441 | for (k, v) in info.pop('properties').iteritems(): |
1442 | info['Property \'%s\'' % k] = v |
1443 | |
1444 | utils.print_dict(info) |
1445 | |
1446 | |
1447 | +def _set_data_field(fields, args): |
1448 | + if 'location' not in fields and 'copy_from' not in fields: |
1449 | + if args.file: |
1450 | + fields['data'] = open(args.file, 'rb') |
1451 | + else: |
1452 | + # We distinguish between cases where image data is pipelined: |
1453 | + # (1) glance ... < /tmp/file or cat /tmp/file | glance ... |
1454 | + # and cases where no image data is provided: |
1455 | + # (2) glance ... |
1456 | + if (sys.stdin.isatty() is not True): |
1457 | + # Our input is from stdin, and we are part of |
1458 | + # a pipeline, so data may be present. (We are of |
1459 | + # type (1) above.) |
1460 | + if msvcrt: |
1461 | + msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY) |
1462 | + fields['data'] = sys.stdin |
1463 | + else: |
1464 | + # We are of type (2) above, no image data supplied |
1465 | + fields['data'] = None |
1466 | + |
1467 | + |
1468 | @utils.arg('id', metavar='<IMAGE_ID>', help='ID of image to describe.') |
1469 | +@utils.arg('--human-readable', action='store_true', default=False, |
1470 | + help='Print image size in a human-friendly format.') |
1471 | def do_image_show(gc, args): |
1472 | """Describe a specific image.""" |
1473 | image = gc.images.get(args.id) |
1474 | - _image_show(image) |
1475 | + _image_show(image, args.human_readable) |
1476 | |
1477 | |
1478 | @utils.arg('--file', metavar='<FILE>', |
1479 | @@ -92,10 +140,10 @@ |
1480 | help='ID of image to reserve.') |
1481 | @utils.arg('--name', metavar='<NAME>', |
1482 | help='Name of image.') |
1483 | -@utils.arg('--disk-format', metavar='<CONTAINER_FORMAT>', |
1484 | - help='Disk format of image.') |
1485 | -@utils.arg('--container-format', metavar='<DISK_FORMAT>', |
1486 | - help='Container format of image.') |
1487 | +@utils.arg('--disk-format', metavar='<DISK_FORMAT>', |
1488 | + help='Disk format of image. ' + DISK_FORMATS) |
1489 | +@utils.arg('--container-format', metavar='<CONTAINER_FORMAT>', |
1490 | + help='Container format of image. ' + CONTAINER_FORMATS) |
1491 | @utils.arg('--owner', metavar='<TENANT_ID>', |
1492 | help='Tenant who should own image.') |
1493 | @utils.arg('--size', metavar='<SIZE>', |
1494 | @@ -115,7 +163,8 @@ |
1495 | ' creation. Alternatively, images can be passed to the client' |
1496 | ' via stdin.')) |
1497 | @utils.arg('--checksum', metavar='<CHECKSUM>', |
1498 | - help='Hash of image data used Glance can use for verification.') |
1499 | + help=('Hash of image data used Glance can use for verification.' |
1500 | + ' Provide a md5 checksum here.')) |
1501 | @utils.arg('--copy-from', metavar='<IMAGE_URL>', |
1502 | help=('Similar to \'--location\' in usage, but this indicates that' |
1503 | ' the Glance server should immediately copy the data and' |
1504 | @@ -124,13 +173,15 @@ |
1505 | # to use --is-public |
1506 | @utils.arg('--public', action='store_true', default=False, |
1507 | help=argparse.SUPPRESS) |
1508 | -@utils.arg('--is-public', type=utils.string_to_bool, |
1509 | +@utils.arg('--is-public', type=utils.string_to_bool, metavar='[True|False]', |
1510 | help='Make image accessible to the public.') |
1511 | -@utils.arg('--is-protected', type=utils.string_to_bool, |
1512 | +@utils.arg('--is-protected', type=utils.string_to_bool, metavar='[True|False]', |
1513 | help='Prevent image from being deleted.') |
1514 | @utils.arg('--property', metavar="<key=value>", action='append', default=[], |
1515 | help=("Arbitrary property to associate with image. " |
1516 | "May be used multiple times.")) |
1517 | +@utils.arg('--human-readable', action='store_true', default=False, |
1518 | + help='Print image size in a human-friendly format.') |
1519 | def do_image_create(gc, args): |
1520 | """Create a new image.""" |
1521 | # Filter out None values |
1522 | @@ -151,23 +202,19 @@ |
1523 | CREATE_PARAMS = glanceclient.v1.images.CREATE_PARAMS |
1524 | fields = dict(filter(lambda x: x[0] in CREATE_PARAMS, fields.items())) |
1525 | |
1526 | - if 'location' not in fields and 'copy_from' not in fields: |
1527 | - if args.file: |
1528 | - fields['data'] = open(args.file, 'r') |
1529 | - else: |
1530 | - fields['data'] = sys.stdin |
1531 | + _set_data_field(fields, args) |
1532 | |
1533 | image = gc.images.create(**fields) |
1534 | - _image_show(image) |
1535 | + _image_show(image, args.human_readable) |
1536 | |
1537 | |
1538 | @utils.arg('id', metavar='<IMAGE_ID>', help='ID of image to modify.') |
1539 | @utils.arg('--name', metavar='<NAME>', |
1540 | help='Name of image.') |
1541 | @utils.arg('--disk-format', metavar='<CONTAINER_FORMAT>', |
1542 | - help='Disk format of image.') |
1543 | + help='Disk format of image. ' + CONTAINER_FORMATS) |
1544 | @utils.arg('--container-format', metavar='<DISK_FORMAT>', |
1545 | - help='Container format of image.') |
1546 | + help='Container format of image. ' + DISK_FORMATS) |
1547 | @utils.arg('--owner', metavar='<TENANT_ID>', |
1548 | help='Tenant who should own image.') |
1549 | @utils.arg('--size', metavar='<SIZE>', |
1550 | @@ -191,9 +238,9 @@ |
1551 | help=('Similar to \'--location\' in usage, but this indicates that' |
1552 | ' the Glance server should immediately copy the data and' |
1553 | ' store it in its configured image store.')) |
1554 | -@utils.arg('--is-public', type=utils.string_to_bool, |
1555 | +@utils.arg('--is-public', type=utils.string_to_bool, metavar='[True|False]', |
1556 | help='Make image accessible to the public.') |
1557 | -@utils.arg('--is-protected', type=utils.string_to_bool, |
1558 | +@utils.arg('--is-protected', type=utils.string_to_bool, metavar='[True|False]', |
1559 | help='Prevent image from being deleted.') |
1560 | @utils.arg('--property', metavar="<key=value>", action='append', default=[], |
1561 | help=("Arbitrary property to associate with image. " |
1562 | @@ -202,6 +249,8 @@ |
1563 | help=("If this flag is present, delete all image properties " |
1564 | "not explicitly set in the update request. Otherwise, " |
1565 | "those properties not referenced are preserved.")) |
1566 | +@utils.arg('--human-readable', action='store_true', default=False, |
1567 | + help='Print image size in a human-friendly format.') |
1568 | def do_image_update(gc, args): |
1569 | """Update a specific image.""" |
1570 | # Filter out None values |
1571 | @@ -222,20 +271,30 @@ |
1572 | UPDATE_PARAMS = glanceclient.v1.images.UPDATE_PARAMS |
1573 | fields = dict(filter(lambda x: x[0] in UPDATE_PARAMS, fields.items())) |
1574 | |
1575 | - if 'location' not in fields and 'copy_from' not in fields: |
1576 | - if args.file: |
1577 | - fields['data'] = open(args.file, 'r') |
1578 | - else: |
1579 | - fields['data'] = sys.stdin |
1580 | + _set_data_field(fields, args) |
1581 | |
1582 | image = gc.images.update(image_id, purge_props=args.purge_props, **fields) |
1583 | - _image_show(image) |
1584 | - |
1585 | - |
1586 | -@utils.arg('id', metavar='<IMAGE_ID>', help='ID of image to delete.') |
1587 | + _image_show(image, args.human_readable) |
1588 | + |
1589 | + |
1590 | +@utils.arg('id', metavar='<IMAGE_ID>', nargs='+', |
1591 | + help='ID of image(s) to delete.') |
1592 | def do_image_delete(gc, args): |
1593 | - """Delete a specific image.""" |
1594 | - gc.images.delete(args.id) |
1595 | + """Delete specified image(s).""" |
1596 | + for image in args.id: |
1597 | + try: |
1598 | + if args.verbose: |
1599 | + print 'Requesting image delete for %s ...' % image, |
1600 | + |
1601 | + gc.images.delete(image) |
1602 | + |
1603 | + if args.verbose: |
1604 | + print '[Done]' |
1605 | + |
1606 | + except exc.HTTPException, e: |
1607 | + if args.verbose: |
1608 | + print '[Fail]' |
1609 | + print '%s: Unable to delete image %s' % (e, image) |
1610 | |
1611 | |
1612 | @utils.arg('--image-id', metavar='<IMAGE_ID>', |
1613 | @@ -272,14 +331,14 @@ |
1614 | |
1615 | |
1616 | @utils.arg('image_id', metavar='<IMAGE_ID>', |
1617 | - help='Image to add member to.') |
1618 | + help='Image from which to remove member') |
1619 | @utils.arg('tenant_id', metavar='<TENANT_ID>', |
1620 | - help='Tenant to add as member') |
1621 | + help='Tenant to remove as member') |
1622 | def do_member_delete(gc, args): |
1623 | """Remove a shared image from a tenant.""" |
1624 | - if not options.dry_run: |
1625 | + if not args.dry_run: |
1626 | gc.image_members.delete(args.image_id, args.tenant_id) |
1627 | else: |
1628 | print "Dry run. We would have done the following:" |
1629 | - print ('Remove "%(member_id)s" from the member list of image ' |
1630 | - '"%(image_id)s"' % locals()) |
1631 | + print ('Remove "%s" from the member list of image ' |
1632 | + '"%s"' % (args.tenant_id, args.image_id)) |
1633 | |
1634 | === removed file 'glanceclient/version.py' |
1635 | --- glanceclient/version.py 2012-08-16 12:24:18 +0000 |
1636 | +++ glanceclient/version.py 1970-01-01 00:00:00 +0000 |
1637 | @@ -1,21 +0,0 @@ |
1638 | -# vim: tabstop=4 shiftwidth=4 softtabstop=4 |
1639 | - |
1640 | -# Copyright 2012 OpenStack LLC |
1641 | -# |
1642 | -# Licensed under the Apache License, Version 2.0 (the "License"); you may |
1643 | -# not use this file except in compliance with the License. You may obtain |
1644 | -# a copy of the License at |
1645 | -# |
1646 | -# http://www.apache.org/licenses/LICENSE-2.0 |
1647 | -# |
1648 | -# Unless required by applicable law or agreed to in writing, software |
1649 | -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
1650 | -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
1651 | -# License for the specific language governing permissions and limitations |
1652 | -# under the License. |
1653 | - |
1654 | - |
1655 | -from glanceclient.openstack.common import version as common_version |
1656 | - |
1657 | -version_info = common_version.VersionInfo('glanceclient', |
1658 | - python_package='python-glanceclient') |
1659 | |
1660 | === modified file 'glanceclient/versioninfo' |
1661 | --- glanceclient/versioninfo 2012-09-18 19:18:03 +0000 |
1662 | +++ glanceclient/versioninfo 2012-11-27 14:34:22 +0000 |
1663 | @@ -1,1 +1,1 @@ |
1664 | -0.5.1 |
1665 | +0.6.0 |
1666 | |
1667 | === modified file 'python_glanceclient.egg-info/PKG-INFO' |
1668 | --- python_glanceclient.egg-info/PKG-INFO 2012-09-18 19:18:03 +0000 |
1669 | +++ python_glanceclient.egg-info/PKG-INFO 2012-11-27 14:34:22 +0000 |
1670 | @@ -1,6 +1,6 @@ |
1671 | Metadata-Version: 1.1 |
1672 | Name: python-glanceclient |
1673 | -Version: 0.5.1 |
1674 | +Version: 0.6.0 |
1675 | Summary: Client library for OpenStack Image API |
1676 | Home-page: https://github.com/openstack/python-glanceclient |
1677 | Author: OpenStack Glance Contributors |
1678 | @@ -18,6 +18,7 @@ |
1679 | Platform: UNKNOWN |
1680 | Classifier: Development Status :: 4 - Beta |
1681 | Classifier: Environment :: Console |
1682 | +Classifier: Environment :: OpenStack |
1683 | Classifier: Intended Audience :: Developers |
1684 | Classifier: Intended Audience :: Information Technology |
1685 | Classifier: License :: OSI Approved :: Apache Software License |
1686 | |
1687 | === modified file 'python_glanceclient.egg-info/SOURCES.txt' |
1688 | --- python_glanceclient.egg-info/SOURCES.txt 2012-08-16 12:24:18 +0000 |
1689 | +++ python_glanceclient.egg-info/SOURCES.txt 2012-11-27 14:34:22 +0000 |
1690 | @@ -15,7 +15,6 @@ |
1691 | glanceclient/client.py |
1692 | glanceclient/exc.py |
1693 | glanceclient/shell.py |
1694 | -glanceclient/version.py |
1695 | glanceclient/versioninfo |
1696 | glanceclient/common/__init__.py |
1697 | glanceclient/common/base.py |
1698 | @@ -46,6 +45,8 @@ |
1699 | python_glanceclient.egg-info/top_level.txt |
1700 | tests/__init__.py |
1701 | tests/test_exc.py |
1702 | +tests/test_http.py |
1703 | +tests/test_ssl.py |
1704 | tests/test_utils.py |
1705 | tests/utils.py |
1706 | tests/v1/__init__.py |
1707 | @@ -54,6 +55,9 @@ |
1708 | tests/v2/__init__.py |
1709 | tests/v2/test_images.py |
1710 | tests/v2/test_schemas.py |
1711 | +tests/var/ca.crt |
1712 | +tests/var/certificate.crt |
1713 | +tests/var/privatekey.key |
1714 | tools/pip-requires |
1715 | tools/test-requires |
1716 | tools/with_venv.sh |
1717 | \ No newline at end of file |
1718 | |
1719 | === modified file 'python_glanceclient.egg-info/requires.txt' |
1720 | --- python_glanceclient.egg-info/requires.txt 2012-09-07 12:23:37 +0000 |
1721 | +++ python_glanceclient.egg-info/requires.txt 2012-11-27 14:34:22 +0000 |
1722 | @@ -1,3 +1,4 @@ |
1723 | prettytable>=0.6,<0.7 |
1724 | -python-keystoneclient>=0.1.2,<0.2 |
1725 | +python-keystoneclient>=0.1.2,<1 |
1726 | +pyOpenSSL |
1727 | warlock<2 |
1728 | \ No newline at end of file |
1729 | |
1730 | === modified file 'setup.py' |
1731 | --- setup.py 2012-08-16 12:24:18 +0000 |
1732 | +++ setup.py 2012-11-27 14:34:22 +0000 |
1733 | @@ -31,6 +31,7 @@ |
1734 | classifiers=[ |
1735 | 'Development Status :: 4 - Beta', |
1736 | 'Environment :: Console', |
1737 | + 'Environment :: OpenStack', |
1738 | 'Intended Audience :: Developers', |
1739 | 'Intended Audience :: Information Technology', |
1740 | 'License :: OSI Approved :: Apache Software License', |
1741 | @@ -44,4 +45,5 @@ |
1742 | setup_requires=['setuptools-git>=0.4'], |
1743 | test_suite="nose.collector", |
1744 | entry_points={'console_scripts': ['glance = glanceclient.shell:main']}, |
1745 | + data_files=[('glanceclient', ['glanceclient/versioninfo'])] |
1746 | ) |
1747 | |
1748 | === added file 'tests/test_http.py' |
1749 | --- tests/test_http.py 1970-01-01 00:00:00 +0000 |
1750 | +++ tests/test_http.py 2012-11-27 14:34:22 +0000 |
1751 | @@ -0,0 +1,65 @@ |
1752 | +# Copyright 2012 OpenStack LLC. |
1753 | +# All Rights Reserved. |
1754 | +# |
1755 | +# Licensed under the Apache License, Version 2.0 (the "License"); you may |
1756 | +# not use this file except in compliance with the License. You may obtain |
1757 | +# a copy of the License at |
1758 | +# |
1759 | +# http://www.apache.org/licenses/LICENSE-2.0 |
1760 | +# |
1761 | +# Unless required by applicable law or agreed to in writing, software |
1762 | +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
1763 | +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
1764 | +# License for the specific language governing permissions and limitations |
1765 | +# under the License. |
1766 | + |
1767 | +import httplib |
1768 | +import socket |
1769 | +import StringIO |
1770 | +import unittest |
1771 | + |
1772 | +import mox |
1773 | + |
1774 | +from glanceclient import exc |
1775 | +from glanceclient.common import http |
1776 | +from tests import utils |
1777 | + |
1778 | + |
1779 | +class TestClient(unittest.TestCase): |
1780 | + def test_connection_refused(self): |
1781 | + """ |
1782 | + Should receive a CommunicationError if connection refused. |
1783 | + And the error should list the host and port that refused the |
1784 | + connection |
1785 | + """ |
1786 | + endpoint = 'http://example.com:9292' |
1787 | + client = http.HTTPClient(endpoint, token=u'abc123') |
1788 | + m = mox.Mox() |
1789 | + m.StubOutWithMock(httplib.HTTPConnection, 'request') |
1790 | + httplib.HTTPConnection.request( |
1791 | + mox.IgnoreArg(), |
1792 | + mox.IgnoreArg(), |
1793 | + headers=mox.IgnoreArg(), |
1794 | + ).AndRaise(socket.error()) |
1795 | + m.ReplayAll() |
1796 | + try: |
1797 | + client.json_request('GET', '/v1/images/detail?limit=20') |
1798 | + #NOTE(alaski) We expect exc.CommunicationError to be raised |
1799 | + # so we should never reach this point. try/except is used here |
1800 | + # rather than assertRaises() so that we can check the body of |
1801 | + # the exception. |
1802 | + self.fail('An exception should have bypassed this line.') |
1803 | + except exc.CommunicationError, comm_err: |
1804 | + fail_msg = ("Exception message '%s' should contain '%s'" % |
1805 | + (comm_err.message, endpoint)) |
1806 | + self.assertTrue(endpoint in comm_err.message, fail_msg) |
1807 | + finally: |
1808 | + m.UnsetStubs() |
1809 | + |
1810 | + |
1811 | +class TestResponseBodyIterator(unittest.TestCase): |
1812 | + def test_iter_default_chunk_size_64k(self): |
1813 | + resp = utils.FakeResponse({}, StringIO.StringIO('X' * 98304)) |
1814 | + iterator = http.ResponseBodyIterator(resp) |
1815 | + chunks = list(iterator) |
1816 | + self.assertEqual(chunks, ['X' * 65536, 'X' * 32768]) |
1817 | |
1818 | === added file 'tests/test_ssl.py' |
1819 | --- tests/test_ssl.py 1970-01-01 00:00:00 +0000 |
1820 | +++ tests/test_ssl.py 2012-11-27 14:34:22 +0000 |
1821 | @@ -0,0 +1,112 @@ |
1822 | +# Copyright 2012 OpenStack LLC. |
1823 | +# All Rights Reserved. |
1824 | +# |
1825 | +# Licensed under the Apache License, Version 2.0 (the "License"); you may |
1826 | +# not use this file except in compliance with the License. You may obtain |
1827 | +# a copy of the License at |
1828 | +# |
1829 | +# http://www.apache.org/licenses/LICENSE-2.0 |
1830 | +# |
1831 | +# Unless required by applicable law or agreed to in writing, software |
1832 | +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
1833 | +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
1834 | +# License for the specific language governing permissions and limitations |
1835 | +# under the License. |
1836 | + |
1837 | +import os |
1838 | +import unittest |
1839 | + |
1840 | +from glanceclient import exc |
1841 | +from glanceclient.common import http |
1842 | + |
1843 | +TEST_VAR_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), |
1844 | + 'var')) |
1845 | + |
1846 | + |
1847 | +class TestVerifiedHTTPSConnection(unittest.TestCase): |
1848 | + def test_ssl_init_ok(self): |
1849 | + """ |
1850 | + Test VerifiedHTTPSConnection class init |
1851 | + """ |
1852 | + key_file = os.path.join(TEST_VAR_DIR, 'privatekey.key') |
1853 | + cert_file = os.path.join(TEST_VAR_DIR, 'certificate.crt') |
1854 | + ca_file = os.path.join(TEST_VAR_DIR, 'ca.crt') |
1855 | + try: |
1856 | + conn = http.VerifiedHTTPSConnection('127.0.0.1', 0, |
1857 | + key_file=key_file, |
1858 | + cert_file=cert_file, |
1859 | + ca_file=ca_file) |
1860 | + except exc.SSLConfigurationError: |
1861 | + self.fail('Failed to init VerifiedHTTPSConnection.') |
1862 | + |
1863 | + def test_ssl_init_cert_no_key(self): |
1864 | + """ |
1865 | + Test VerifiedHTTPSConnection: absense of SSL key file. |
1866 | + """ |
1867 | + cert_file = os.path.join(TEST_VAR_DIR, 'certificate.crt') |
1868 | + ca_file = os.path.join(TEST_VAR_DIR, 'ca.crt') |
1869 | + try: |
1870 | + conn = http.VerifiedHTTPSConnection('127.0.0.1', 0, |
1871 | + cert_file=cert_file, |
1872 | + ca_file=ca_file) |
1873 | + self.fail('Failed to raise assertion.') |
1874 | + except exc.SSLConfigurationError: |
1875 | + pass |
1876 | + |
1877 | + def test_ssl_init_key_no_cert(self): |
1878 | + """ |
1879 | + Test VerifiedHTTPSConnection: absense of SSL cert file. |
1880 | + """ |
1881 | + key_file = os.path.join(TEST_VAR_DIR, 'privatekey.key') |
1882 | + ca_file = os.path.join(TEST_VAR_DIR, 'ca.crt') |
1883 | + try: |
1884 | + conn = http.VerifiedHTTPSConnection('127.0.0.1', 0, |
1885 | + key_file=key_file, |
1886 | + ca_file=ca_file) |
1887 | + except: |
1888 | + self.fail('Failed to init VerifiedHTTPSConnection.') |
1889 | + |
1890 | + def test_ssl_init_bad_key(self): |
1891 | + """ |
1892 | + Test VerifiedHTTPSConnection: bad key. |
1893 | + """ |
1894 | + key_file = os.path.join(TEST_VAR_DIR, 'badkey.key') |
1895 | + cert_file = os.path.join(TEST_VAR_DIR, 'certificate.crt') |
1896 | + ca_file = os.path.join(TEST_VAR_DIR, 'ca.crt') |
1897 | + try: |
1898 | + conn = http.VerifiedHTTPSConnection('127.0.0.1', 0, |
1899 | + cert_file=cert_file, |
1900 | + ca_file=ca_file) |
1901 | + self.fail('Failed to raise assertion.') |
1902 | + except exc.SSLConfigurationError: |
1903 | + pass |
1904 | + |
1905 | + def test_ssl_init_bad_cert(self): |
1906 | + """ |
1907 | + Test VerifiedHTTPSConnection: bad cert. |
1908 | + """ |
1909 | + key_file = os.path.join(TEST_VAR_DIR, 'privatekey.key') |
1910 | + cert_file = os.path.join(TEST_VAR_DIR, 'badcert.crt') |
1911 | + ca_file = os.path.join(TEST_VAR_DIR, 'ca.crt') |
1912 | + try: |
1913 | + conn = http.VerifiedHTTPSConnection('127.0.0.1', 0, |
1914 | + cert_file=cert_file, |
1915 | + ca_file=ca_file) |
1916 | + self.fail('Failed to raise assertion.') |
1917 | + except exc.SSLConfigurationError: |
1918 | + pass |
1919 | + |
1920 | + def test_ssl_init_bad_ca(self): |
1921 | + """ |
1922 | + Test VerifiedHTTPSConnection: bad CA. |
1923 | + """ |
1924 | + key_file = os.path.join(TEST_VAR_DIR, 'privatekey.key') |
1925 | + cert_file = os.path.join(TEST_VAR_DIR, 'certificate.crt') |
1926 | + ca_file = os.path.join(TEST_VAR_DIR, 'badca.crt') |
1927 | + try: |
1928 | + conn = http.VerifiedHTTPSConnection('127.0.0.1', 0, |
1929 | + cert_file=cert_file, |
1930 | + ca_file=ca_file) |
1931 | + self.fail('Failed to raise assertion.') |
1932 | + except exc.SSLConfigurationError: |
1933 | + pass |
1934 | |
1935 | === modified file 'tests/test_utils.py' |
1936 | --- tests/test_utils.py 2012-08-16 12:24:18 +0000 |
1937 | +++ tests/test_utils.py 2012-11-27 14:34:22 +0000 |
1938 | @@ -43,3 +43,10 @@ |
1939 | fixture = 'CCC' |
1940 | checksum = 'defb99e69a9f1f6e06f15006b1f166ae' |
1941 | data = ''.join([f for f in utils.integrity_iter(fixture, checksum)]) |
1942 | + |
1943 | + def test_make_size_human_readable(self): |
1944 | + self.assertEqual("106B", utils.make_size_human_readable(106)) |
1945 | + self.assertEqual("1000kB", utils.make_size_human_readable(1024000)) |
1946 | + self.assertEqual("1MB", utils.make_size_human_readable(1048576)) |
1947 | + self.assertEqual("1.4GB", utils.make_size_human_readable(1476395008)) |
1948 | + self.assertEqual("9.3MB", utils.make_size_human_readable(9761280)) |
1949 | |
1950 | === modified file 'tests/utils.py' |
1951 | --- tests/utils.py 2012-08-16 12:24:18 +0000 |
1952 | +++ tests/utils.py 2012-11-27 14:34:22 +0000 |
1953 | @@ -40,11 +40,19 @@ |
1954 | |
1955 | |
1956 | class FakeResponse(object): |
1957 | - def __init__(self, headers): |
1958 | + def __init__(self, headers, body=None): |
1959 | + """ |
1960 | + :param headers: dict representing HTTP response headers |
1961 | + :param body: file-like object |
1962 | + """ |
1963 | self.headers = headers |
1964 | + self.body = body |
1965 | |
1966 | def getheaders(self): |
1967 | return copy.deepcopy(self.headers).items() |
1968 | |
1969 | def getheader(self, key, default): |
1970 | return self.headers.get(key, default) |
1971 | + |
1972 | + def read(self, amt): |
1973 | + return self.body.read(amt) |
1974 | |
1975 | === modified file 'tests/v1/test_images.py' |
1976 | --- tests/v1/test_images.py 2012-09-18 19:18:03 +0000 |
1977 | +++ tests/v1/test_images.py 2012-11-27 14:34:22 +0000 |
1978 | @@ -390,7 +390,7 @@ |
1979 | def test_update_with_data(self): |
1980 | image_data = StringIO.StringIO('XXX') |
1981 | self.mgr.update('1', data=image_data) |
1982 | - expect_headers = {'x-image-meta-size': '3', 'Content-Length': 3} |
1983 | + expect_headers = {'x-image-meta-size': '3'} |
1984 | expect = [('PUT', '/v1/images/1', expect_headers, image_data)] |
1985 | self.assertEqual(self.api.calls, expect) |
1986 | |
1987 | |
1988 | === added directory 'tests/var' |
1989 | === added file 'tests/var/ca.crt' |
1990 | --- tests/var/ca.crt 1970-01-01 00:00:00 +0000 |
1991 | +++ tests/var/ca.crt 2012-11-27 14:34:22 +0000 |
1992 | @@ -0,0 +1,35 @@ |
1993 | +-----BEGIN CERTIFICATE----- |
1994 | +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 |
2026 | +WoRMgEwjGJWqzhJZUYpUAQ== |
2027 | +-----END CERTIFICATE----- |
2028 | |
2029 | === added file 'tests/var/certificate.crt' |
2030 | --- tests/var/certificate.crt 1970-01-01 00:00:00 +0000 |
2031 | +++ tests/var/certificate.crt 2012-11-27 14:34:22 +0000 |
2032 | @@ -0,0 +1,30 @@ |
2033 | +-----BEGIN CERTIFICATE----- |
2034 | +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 |
2062 | +-----END CERTIFICATE----- |
2063 | |
2064 | === added file 'tests/var/privatekey.key' |
2065 | --- tests/var/privatekey.key 1970-01-01 00:00:00 +0000 |
2066 | +++ tests/var/privatekey.key 2012-11-27 14:34:22 +0000 |
2067 | @@ -0,0 +1,51 @@ |
2068 | +-----BEGIN RSA PRIVATE KEY----- |
2069 | +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 |
2118 | +-----END RSA PRIVATE KEY----- |
2119 | |
2120 | === modified file 'tools/pip-requires' |
2121 | --- tools/pip-requires 2012-09-07 12:23:37 +0000 |
2122 | +++ tools/pip-requires 2012-11-27 14:34:22 +0000 |
2123 | @@ -1,4 +1,5 @@ |
2124 | argparse |
2125 | prettytable>=0.6,<0.7 |
2126 | -python-keystoneclient>=0.1.2,<0.2 |
2127 | +python-keystoneclient>=0.1.2,<1 |
2128 | +pyOpenSSL |
2129 | warlock<2 |
2130 | |
2131 | === modified file 'tools/test-requires' |
2132 | --- tools/test-requires 2012-09-07 12:23:37 +0000 |
2133 | +++ tools/test-requires 2012-11-27 14:34:22 +0000 |
2134 | @@ -1,5 +1,11 @@ |
2135 | +distribute>=0.6.24 |
2136 | + |
2137 | mox |
2138 | nose |
2139 | +nose-exclude |
2140 | +nosexcover |
2141 | +openstack.nose_plugin |
2142 | +nosehtmloutput |
2143 | pep8==1.2 |
2144 | setuptools-git>=0.4 |
2145 | sphinx>=1.1.2 |
LGTM