Merge lp:~elkirya/nova/floating-os-api into lp:~hudson-openstack/nova/trunk
- floating-os-api
- Merge into trunk
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Devin Carlen | ||||
Approved revision: | 1205 | ||||
Merged at revision: | 1218 | ||||
Proposed branch: | lp:~elkirya/nova/floating-os-api | ||||
Merge into: | lp:~hudson-openstack/nova/trunk | ||||
Diff against target: |
598 lines (+449/-7) 10 files modified
.mailmap (+4/-0) Authors (+3/-2) nova/api/openstack/contrib/floating_ips.py (+172/-0) nova/db/api.py (+8/-0) nova/db/sqlalchemy/api.py (+41/-2) nova/exception.py (+4/-0) nova/network/api.py (+13/-0) nova/tests/api/openstack/contrib/__init__.py (+15/-0) nova/tests/api/openstack/contrib/test_floating_ips.py (+186/-0) nova/tests/api/openstack/fakes.py (+3/-3) |
||||
To merge this branch: | bzr merge lp:~elkirya/nova/floating-os-api | ||||
Related bugs: |
|
||||
Related blueprints: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Devin Carlen (community) | Approve | ||
Brian Waldon (community) | Approve | ||
Vish Ishaya (community) | Approve | ||
Review via email: mp+65845@code.launchpad.net |
Commit message
Added floating IP support in OS API
Description of the change
- 1199. By Ilya Alekseyev
-
trunk merged. conflicts resolved
- 1200. By Ilya Alekseyev
-
merged
Vish Ishaya (vishvananda) wrote : | # |
- 1201. By Ilya Alekseyev
-
mailmap
- 1202. By Ilya Alekseyev
-
mailmap
Ilya Alekseyev (ilyaalekseyev) wrote : | # |
> Can you edit .Mailmap for secondary addresses instead of adding multiple
> emails in authors?
Yep, sorry. Fixed.
Vish Ishaya (vishvananda) wrote : | # |
This looks good. Passing it off to Brian for review on os api implementation.
Brian Waldon (bcwaldon) wrote : | # |
This is really cool stuff, guys. I did find a few things:
Can you please add the "os-" prefix to your extension alias? Refer to the Volumes extension as an example.
192: Can we call this class FloatingIPs, or FloatingIPsExte
212: the spacing looks a bit odd here. Can you line up the arguments to the ResourceExtension call?
311: This exception message seems a bit counter-intuitive. Would you prefer to actually use the FloatingIpNotFound exception that already exists? If the "fixed_ip" is the problem, you can move the existing FloatingIpNotFound exception to FloatinIpNotFou
325, 333: Can you make these method names more specific? get_floating_ip and list_floating_ips sound better
367,368: I'm not sure about the non-OpenStack copyright. Vish, can you comment on this?
Thierry Carrez (ttx) wrote : | # |
Non-OpenStack copyrights are OK (since we do not require copyright assignments). However the mention "All rights reserved" is probably not OK and in contradiction with the terms of the Apache license mentioned below it (disclaimer: IANAL)
Thierry Carrez (ttx) wrote : | # |
Apparently the mention "All rights reserved" is OK since it only applies to copyright and does not interfere with license, so ignore me.
- 1203. By Ilya Alekseyev
-
review issues fixed
- 1204. By Eldar Nugaev
-
fixed pep style
Eldar Nugaev (reldan) wrote : | # |
Hi Brian
Thank you for very cool review.
Fixed.
But we cannot rename then class, because we get WARNING extensions [-] Did not find expected name "Floating_ips" in /home/ilya/
Brian Waldon (bcwaldon) wrote : | # |
That's fine, Eldar. One last thing:
211: Can you make this "os-floating-ips"? I would appreciate the consistency.
- 1205. By Eldar Nugaev
-
changed extension alias to os-floating-ips
Eldar Nugaev (reldan) wrote : | # |
Thank you!
Fixed
Brian Waldon (bcwaldon) wrote : | # |
Good work, Eldar.
Eldar Nugaev (reldan) wrote : | # |
Thank you for approve.
Could you please change the proposal status to approve?
Brian Waldon (bcwaldon) wrote : | # |
I would very much like to hear from another reviewer. I requested a review from nova-core.
Devin Carlen (devcamcar) wrote : | # |
Brian, this is great!
Devin Carlen (devcamcar) wrote : | # |
Oh, I misread. I mean, Edgar, this is great! :)
Preview Diff
1 | === modified file '.mailmap' |
2 | --- .mailmap 2011-05-11 19:16:37 +0000 |
3 | +++ .mailmap 2011-06-27 16:39:52 +0000 |
4 | @@ -47,3 +47,7 @@ |
5 | <vishvananda@gmail.com> <root@mirror.nasanebula.net> |
6 | <vishvananda@gmail.com> <root@ubuntu> |
7 | <vishvananda@gmail.com> <vishvananda@yahoo.com> |
8 | +<ilyaalekseyev@acm.org> <ialekseev@griddynamics.com> |
9 | +<ilyaalekseyev@acm.org> <ilya@oscloud.ru> |
10 | +<reldan@oscloud.ru> <enugaev@griddynamics.com> |
11 | +<kshileev@gmail.com> <kshileev@griddynamics.com> |
12 | \ No newline at end of file |
13 | |
14 | === modified file 'Authors' |
15 | --- Authors 2011-06-24 12:01:51 +0000 |
16 | +++ Authors 2011-06-27 16:39:52 +0000 |
17 | @@ -22,14 +22,14 @@ |
18 | Dean Troyer <dtroyer@gmail.com> |
19 | Devin Carlen <devin.carlen@gmail.com> |
20 | Ed Leafe <ed@leafe.com> |
21 | -Eldar Nugaev <enugaev@griddynamics.com> |
22 | +Eldar Nugaev <reldan@oscloud.ru> |
23 | Eric Day <eday@oddments.org> |
24 | Eric Windisch <eric@cloudscaling.com> |
25 | Ewan Mellor <ewan.mellor@citrix.com> |
26 | Gabe Westmaas <gabe.westmaas@rackspace.com> |
27 | Hisaharu Ishii <ishii.hisaharu@lab.ntt.co.jp> |
28 | Hisaki Ohara <hisaki.ohara@intel.com> |
29 | -Ilya Alekseyev <ialekseev@griddynamics.com> |
30 | +Ilya Alekseyev <ilyaalekseyev@acm.org> |
31 | Isaku Yamahata <yamahata@valinux.co.jp> |
32 | Jason Cannavale <jason.cannavale@rackspace.com> |
33 | Jason Koelker <jason@koelker.net> |
34 | @@ -53,6 +53,7 @@ |
35 | Ken Pepple <ken.pepple@gmail.com> |
36 | Kevin Bringard <kbringard@attinteractive.com> |
37 | Kevin L. Mitchell <kevin.mitchell@rackspace.com> |
38 | +Kirill Shileev <kshileev@gmail.com> |
39 | Koji Iida <iida.koji@lab.ntt.co.jp> |
40 | Lorin Hochstein <lorin@isi.edu> |
41 | Lvov Maxim <usrleon@gmail.com> |
42 | |
43 | === added file 'nova/api/openstack/contrib/floating_ips.py' |
44 | --- nova/api/openstack/contrib/floating_ips.py 1970-01-01 00:00:00 +0000 |
45 | +++ nova/api/openstack/contrib/floating_ips.py 2011-06-27 16:39:52 +0000 |
46 | @@ -0,0 +1,172 @@ |
47 | +# vim: tabstop=4 shiftwidth=4 softtabstop=4 |
48 | + |
49 | +# Copyright 2011 OpenStack LLC. |
50 | +# Copyright 2011 Grid Dynamics |
51 | +# Copyright 2011 Eldar Nugaev, Kirill Shileev, Ilya Alekseyev |
52 | +# |
53 | +# Licensed under the Apache License, Version 2.0 (the "License"); you may |
54 | +# not use this file except in compliance with the License. You may obtain |
55 | +# a copy of the License at |
56 | +# |
57 | +# http://www.apache.org/licenses/LICENSE-2.0 |
58 | +# |
59 | +# Unless required by applicable law or agreed to in writing, software |
60 | +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
61 | +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
62 | +# License for the specific language governing permissions and limitations |
63 | +# under the License |
64 | +from webob import exc |
65 | + |
66 | +from nova import exception |
67 | +from nova import network |
68 | +from nova import rpc |
69 | +from nova.api.openstack import faults |
70 | +from nova.api.openstack import extensions |
71 | + |
72 | + |
73 | +def _translate_floating_ip_view(floating_ip): |
74 | + result = {'id': floating_ip['id'], |
75 | + 'ip': floating_ip['address']} |
76 | + if 'fixed_ip' in floating_ip: |
77 | + result['fixed_ip'] = floating_ip['fixed_ip']['address'] |
78 | + else: |
79 | + result['fixed_ip'] = None |
80 | + if 'instance' in floating_ip: |
81 | + result['instance_id'] = floating_ip['instance']['id'] |
82 | + else: |
83 | + result['instance_id'] = None |
84 | + return {'floating_ip': result} |
85 | + |
86 | + |
87 | +def _translate_floating_ips_view(floating_ips): |
88 | + return {'floating_ips': [_translate_floating_ip_view(floating_ip) |
89 | + for floating_ip in floating_ips]} |
90 | + |
91 | + |
92 | +class FloatingIPController(object): |
93 | + """The Floating IPs API controller for the OpenStack API.""" |
94 | + |
95 | + _serialization_metadata = { |
96 | + 'application/xml': { |
97 | + "attributes": { |
98 | + "floating_ip": [ |
99 | + "id", |
100 | + "ip", |
101 | + "instance_id", |
102 | + "fixed_ip", |
103 | + ]}}} |
104 | + |
105 | + def __init__(self): |
106 | + self.network_api = network.API() |
107 | + super(FloatingIPController, self).__init__() |
108 | + |
109 | + def show(self, req, id): |
110 | + """Return data about the given floating ip.""" |
111 | + context = req.environ['nova.context'] |
112 | + |
113 | + try: |
114 | + floating_ip = self.network_api.get_floating_ip(context, id) |
115 | + except exception.NotFound: |
116 | + return faults.Fault(exc.HTTPNotFound()) |
117 | + |
118 | + return _translate_floating_ip_view(floating_ip) |
119 | + |
120 | + def index(self, req): |
121 | + context = req.environ['nova.context'] |
122 | + |
123 | + floating_ips = self.network_api.list_floating_ips(context) |
124 | + |
125 | + return _translate_floating_ips_view(floating_ips) |
126 | + |
127 | + def create(self, req, body): |
128 | + context = req.environ['nova.context'] |
129 | + |
130 | + try: |
131 | + address = self.network_api.allocate_floating_ip(context) |
132 | + ip = self.network_api.get_floating_ip_by_ip(context, address) |
133 | + except rpc.RemoteError as ex: |
134 | + if ex.exc_type == 'NoMoreAddresses': |
135 | + raise exception.NoMoreFloatingIps() |
136 | + else: |
137 | + raise |
138 | + |
139 | + return {'allocated': { |
140 | + "id": ip['id'], |
141 | + "floating_ip": ip['address']}} |
142 | + |
143 | + def delete(self, req, id): |
144 | + context = req.environ['nova.context'] |
145 | + |
146 | + ip = self.network_api.get_floating_ip(context, id) |
147 | + self.network_api.release_floating_ip(context, address=ip) |
148 | + |
149 | + return {'released': { |
150 | + "id": ip['id'], |
151 | + "floating_ip": ip['address']}} |
152 | + |
153 | + def associate(self, req, id, body): |
154 | + """ /floating_ips/{id}/associate fixed ip in body """ |
155 | + context = req.environ['nova.context'] |
156 | + floating_ip = self._get_ip_by_id(context, id) |
157 | + |
158 | + fixed_ip = body['associate_address']['fixed_ip'] |
159 | + |
160 | + try: |
161 | + self.network_api.associate_floating_ip(context, |
162 | + floating_ip, fixed_ip) |
163 | + except rpc.RemoteError: |
164 | + raise |
165 | + |
166 | + return {'associated': |
167 | + { |
168 | + "floating_ip_id": id, |
169 | + "floating_ip": floating_ip, |
170 | + "fixed_ip": fixed_ip}} |
171 | + |
172 | + def disassociate(self, req, id, body): |
173 | + """ POST /floating_ips/{id}/disassociate """ |
174 | + context = req.environ['nova.context'] |
175 | + floating_ip = self.network_api.get_floating_ip(context, id) |
176 | + address = floating_ip['address'] |
177 | + fixed_ip = floating_ip['fixed_ip']['address'] |
178 | + |
179 | + try: |
180 | + self.network_api.disassociate_floating_ip(context, address) |
181 | + except rpc.RemoteError: |
182 | + raise |
183 | + |
184 | + return {'disassociated': {'floating_ip': address, |
185 | + 'fixed_ip': fixed_ip}} |
186 | + |
187 | + def _get_ip_by_id(self, context, value): |
188 | + """Checks that value is id and then returns its address.""" |
189 | + return self.network_api.get_floating_ip(context, value)['address'] |
190 | + |
191 | + |
192 | +class Floating_ips(extensions.ExtensionDescriptor): |
193 | + def get_name(self): |
194 | + return "Floating_ips" |
195 | + |
196 | + def get_alias(self): |
197 | + return "os-floating-ips" |
198 | + |
199 | + def get_description(self): |
200 | + return "Floating IPs support" |
201 | + |
202 | + def get_namespace(self): |
203 | + return "http://docs.openstack.org/ext/floating_ips/api/v1.1" |
204 | + |
205 | + def get_updated(self): |
206 | + return "2011-06-16T00:00:00+00:00" |
207 | + |
208 | + def get_resources(self): |
209 | + resources = [] |
210 | + |
211 | + res = extensions.ResourceExtension('os-floating-ips', |
212 | + FloatingIPController(), |
213 | + member_actions={ |
214 | + 'associate': 'POST', |
215 | + 'disassociate': 'POST'}) |
216 | + resources.append(res) |
217 | + |
218 | + return resources |
219 | |
220 | === modified file 'nova/db/api.py' |
221 | --- nova/db/api.py 2011-06-25 19:38:07 +0000 |
222 | +++ nova/db/api.py 2011-06-27 16:39:52 +0000 |
223 | @@ -223,6 +223,9 @@ |
224 | |
225 | ################### |
226 | |
227 | +def floating_ip_get(context, floating_ip_id): |
228 | + return IMPL.floating_ip_get(context, floating_ip_id) |
229 | + |
230 | |
231 | def floating_ip_allocate_address(context, host, project_id): |
232 | """Allocate free floating ip and return the address. |
233 | @@ -289,6 +292,11 @@ |
234 | return IMPL.floating_ip_get_by_address(context, address) |
235 | |
236 | |
237 | +def floating_ip_get_by_ip(context, ip): |
238 | + """Get a floating ip by floating address.""" |
239 | + return IMPL.floating_ip_get_by_ip(context, ip) |
240 | + |
241 | + |
242 | def floating_ip_update(context, address, values): |
243 | """Update a floating ip by address or raise if it doesn't exist.""" |
244 | return IMPL.floating_ip_update(context, address, values) |
245 | |
246 | === modified file 'nova/db/sqlalchemy/api.py' |
247 | --- nova/db/sqlalchemy/api.py 2011-06-25 19:38:07 +0000 |
248 | +++ nova/db/sqlalchemy/api.py 2011-06-27 16:39:52 +0000 |
249 | @@ -428,6 +428,29 @@ |
250 | |
251 | |
252 | ################### |
253 | +@require_context |
254 | +def floating_ip_get(context, id): |
255 | + session = get_session() |
256 | + result = None |
257 | + if is_admin_context(context): |
258 | + result = session.query(models.FloatingIp).\ |
259 | + options(joinedload('fixed_ip')).\ |
260 | + options(joinedload_all('fixed_ip.instance')).\ |
261 | + filter_by(id=id).\ |
262 | + filter_by(deleted=can_read_deleted(context)).\ |
263 | + first() |
264 | + elif is_user_context(context): |
265 | + result = session.query(models.FloatingIp).\ |
266 | + options(joinedload('fixed_ip')).\ |
267 | + options(joinedload_all('fixed_ip.instance')).\ |
268 | + filter_by(project_id=context.project_id).\ |
269 | + filter_by(id=id).\ |
270 | + filter_by(deleted=False).\ |
271 | + first() |
272 | + if not result: |
273 | + raise exception.FloatingIpNotFoundForFixedAddress() |
274 | + |
275 | + return result |
276 | |
277 | |
278 | @require_context |
279 | @@ -582,7 +605,23 @@ |
280 | filter_by(deleted=can_read_deleted(context)).\ |
281 | first() |
282 | if not result: |
283 | - raise exception.FloatingIpNotFound(fixed_ip=address) |
284 | + raise exception.FloatingIpNotFoundForFixedAddress(fixed_ip=address) |
285 | + |
286 | + return result |
287 | + |
288 | + |
289 | +@require_context |
290 | +def floating_ip_get_by_ip(context, ip, session=None): |
291 | + if not session: |
292 | + session = get_session() |
293 | + |
294 | + result = session.query(models.FloatingIp).\ |
295 | + filter_by(address=ip).\ |
296 | + filter_by(deleted=can_read_deleted(context)).\ |
297 | + first() |
298 | + |
299 | + if not result: |
300 | + raise exception.FloatingIpNotFound(floating_ip=ip) |
301 | |
302 | return result |
303 | |
304 | @@ -722,7 +761,7 @@ |
305 | options(joinedload('instance')).\ |
306 | first() |
307 | if not result: |
308 | - raise exception.FloatingIpNotFound(fixed_ip=address) |
309 | + raise exception.FloatingIpNotFoundForFixedAddress(fixed_ip=address) |
310 | |
311 | if is_user_context(context): |
312 | authorize_project_context(context, result.instance.project_id) |
313 | |
314 | === modified file 'nova/exception.py' |
315 | --- nova/exception.py 2011-06-24 12:01:51 +0000 |
316 | +++ nova/exception.py 2011-06-27 16:39:52 +0000 |
317 | @@ -361,6 +361,10 @@ |
318 | |
319 | |
320 | class FloatingIpNotFound(NotFound): |
321 | + message = _("Floating ip %(floating_ip)s not found") |
322 | + |
323 | + |
324 | +class FloatingIpNotFoundForFixedAddress(NotFound): |
325 | message = _("Floating ip not found for fixed address %(fixed_ip)s.") |
326 | |
327 | |
328 | |
329 | === modified file 'nova/network/api.py' |
330 | --- nova/network/api.py 2011-05-11 19:24:01 +0000 |
331 | +++ nova/network/api.py 2011-06-27 16:39:52 +0000 |
332 | @@ -34,6 +34,19 @@ |
333 | class API(base.Base): |
334 | """API for interacting with the network manager.""" |
335 | |
336 | + def get_floating_ip(self, context, id): |
337 | + rv = self.db.floating_ip_get(context, id) |
338 | + return dict(rv.iteritems()) |
339 | + |
340 | + def get_floating_ip_by_ip(self, context, address): |
341 | + res = self.db.floating_ip_get_by_ip(context, address) |
342 | + return dict(res.iteritems()) |
343 | + |
344 | + def list_floating_ips(self, context): |
345 | + ips = self.db.floating_ip_get_all_by_project(context, |
346 | + context.project_id) |
347 | + return ips |
348 | + |
349 | def allocate_floating_ip(self, context): |
350 | if quota.allowed_floating_ips(context, 1) < 1: |
351 | LOG.warn(_('Quota exceeeded for %s, tried to allocate ' |
352 | |
353 | === added directory 'nova/tests/api/openstack/contrib' |
354 | === added file 'nova/tests/api/openstack/contrib/__init__.py' |
355 | --- nova/tests/api/openstack/contrib/__init__.py 1970-01-01 00:00:00 +0000 |
356 | +++ nova/tests/api/openstack/contrib/__init__.py 2011-06-27 16:39:52 +0000 |
357 | @@ -0,0 +1,15 @@ |
358 | +# vim: tabstop=4 shiftwidth=4 softtabstop=4 |
359 | + |
360 | +# Copyright 2011 OpenStack LLC |
361 | +# |
362 | +# Licensed under the Apache License, Version 2.0 (the "License"); you may |
363 | +# not use this file except in compliance with the License. You may obtain |
364 | +# a copy of the License at |
365 | +# |
366 | +# http://www.apache.org/licenses/LICENSE-2.0 |
367 | +# |
368 | +# Unless required by applicable law or agreed to in writing, software |
369 | +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
370 | +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
371 | +# License for the specific language governing permissions and limitations |
372 | +# under the License. |
373 | |
374 | === added file 'nova/tests/api/openstack/contrib/test_floating_ips.py' |
375 | --- nova/tests/api/openstack/contrib/test_floating_ips.py 1970-01-01 00:00:00 +0000 |
376 | +++ nova/tests/api/openstack/contrib/test_floating_ips.py 2011-06-27 16:39:52 +0000 |
377 | @@ -0,0 +1,186 @@ |
378 | +# Copyright 2011 Eldar Nugaev |
379 | +# All Rights Reserved. |
380 | +# |
381 | +# Licensed under the Apache License, Version 2.0 (the "License"); you may |
382 | +# not use this file except in compliance with the License. You may obtain |
383 | +# a copy of the License at |
384 | +# |
385 | +# http://www.apache.org/licenses/LICENSE-2.0 |
386 | +# |
387 | +# Unless required by applicable law or agreed to in writing, software |
388 | +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
389 | +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
390 | +# License for the specific language governing permissions and limitations |
391 | +# under the License. |
392 | + |
393 | +import json |
394 | +import stubout |
395 | +import webob |
396 | + |
397 | +from nova import context |
398 | +from nova import db |
399 | +from nova import test |
400 | +from nova import network |
401 | +from nova.tests.api.openstack import fakes |
402 | + |
403 | + |
404 | +from nova.api.openstack.contrib.floating_ips import FloatingIPController |
405 | +from nova.api.openstack.contrib.floating_ips import _translate_floating_ip_view |
406 | + |
407 | + |
408 | +def network_api_get_floating_ip(self, context, id): |
409 | + return {'id': 1, 'address': '10.10.10.10', |
410 | + 'fixed_ip': {'address': '11.0.0.1'}} |
411 | + |
412 | + |
413 | +def network_api_list_floating_ips(self, context): |
414 | + return [{'id': 1, |
415 | + 'address': '10.10.10.10', |
416 | + 'instance': {'id': 11}, |
417 | + 'fixed_ip': {'address': '10.0.0.1'}}, |
418 | + {'id': 2, |
419 | + 'address': '10.10.10.11'}] |
420 | + |
421 | + |
422 | +def network_api_allocate(self, context): |
423 | + return '10.10.10.10' |
424 | + |
425 | + |
426 | +def network_api_release(self, context, address): |
427 | + pass |
428 | + |
429 | + |
430 | +def network_api_associate(self, context, floating_ip, fixed_ip): |
431 | + pass |
432 | + |
433 | + |
434 | +def network_api_disassociate(self, context, floating_address): |
435 | + pass |
436 | + |
437 | + |
438 | +class FloatingIpTest(test.TestCase): |
439 | + address = "10.10.10.10" |
440 | + |
441 | + def _create_floating_ip(self): |
442 | + """Create a floating ip object.""" |
443 | + host = "fake_host" |
444 | + return db.floating_ip_create(self.context, |
445 | + {'address': self.address, |
446 | + 'host': host}) |
447 | + |
448 | + def _delete_floating_ip(self): |
449 | + db.floating_ip_destroy(self.context, self.address) |
450 | + |
451 | + def setUp(self): |
452 | + super(FloatingIpTest, self).setUp() |
453 | + self.controller = FloatingIPController() |
454 | + self.stubs = stubout.StubOutForTesting() |
455 | + fakes.FakeAuthManager.reset_fake_data() |
456 | + fakes.FakeAuthDatabase.data = {} |
457 | + fakes.stub_out_networking(self.stubs) |
458 | + fakes.stub_out_rate_limiting(self.stubs) |
459 | + fakes.stub_out_auth(self.stubs) |
460 | + self.stubs.Set(network.api.API, "get_floating_ip", |
461 | + network_api_get_floating_ip) |
462 | + self.stubs.Set(network.api.API, "list_floating_ips", |
463 | + network_api_list_floating_ips) |
464 | + self.stubs.Set(network.api.API, "allocate_floating_ip", |
465 | + network_api_allocate) |
466 | + self.stubs.Set(network.api.API, "release_floating_ip", |
467 | + network_api_release) |
468 | + self.stubs.Set(network.api.API, "associate_floating_ip", |
469 | + network_api_associate) |
470 | + self.stubs.Set(network.api.API, "disassociate_floating_ip", |
471 | + network_api_disassociate) |
472 | + self.context = context.get_admin_context() |
473 | + self._create_floating_ip() |
474 | + |
475 | + def tearDown(self): |
476 | + self.stubs.UnsetAll() |
477 | + self._delete_floating_ip() |
478 | + super(FloatingIpTest, self).tearDown() |
479 | + |
480 | + def test_translate_floating_ip_view(self): |
481 | + floating_ip_address = self._create_floating_ip() |
482 | + floating_ip = db.floating_ip_get_by_address(self.context, |
483 | + floating_ip_address) |
484 | + view = _translate_floating_ip_view(floating_ip) |
485 | + self.assertTrue('floating_ip' in view) |
486 | + self.assertTrue(view['floating_ip']['id']) |
487 | + self.assertEqual(view['floating_ip']['ip'], self.address) |
488 | + self.assertEqual(view['floating_ip']['fixed_ip'], None) |
489 | + self.assertEqual(view['floating_ip']['instance_id'], None) |
490 | + |
491 | + def test_floating_ips_list(self): |
492 | + req = webob.Request.blank('/v1.1/os-floating-ips') |
493 | + res = req.get_response(fakes.wsgi_app()) |
494 | + self.assertEqual(res.status_int, 200) |
495 | + res_dict = json.loads(res.body) |
496 | + response = {'floating_ips': [{'floating_ip': {'instance_id': 11, |
497 | + 'ip': '10.10.10.10', |
498 | + 'fixed_ip': '10.0.0.1', |
499 | + 'id': 1}}, |
500 | + {'floating_ip': {'instance_id': None, |
501 | + 'ip': '10.10.10.11', |
502 | + 'fixed_ip': None, |
503 | + 'id': 2}}]} |
504 | + self.assertEqual(res_dict, response) |
505 | + |
506 | + def test_floating_ip_show(self): |
507 | + req = webob.Request.blank('/v1.1/os-floating-ips/1') |
508 | + res = req.get_response(fakes.wsgi_app()) |
509 | + self.assertEqual(res.status_int, 200) |
510 | + res_dict = json.loads(res.body) |
511 | + self.assertEqual(res_dict['floating_ip']['id'], 1) |
512 | + self.assertEqual(res_dict['floating_ip']['ip'], '10.10.10.10') |
513 | + self.assertEqual(res_dict['floating_ip']['fixed_ip'], '11.0.0.1') |
514 | + self.assertEqual(res_dict['floating_ip']['instance_id'], None) |
515 | + |
516 | + def test_floating_ip_allocate(self): |
517 | + req = webob.Request.blank('/v1.1/os-floating-ips') |
518 | + req.method = 'POST' |
519 | + res = req.get_response(fakes.wsgi_app()) |
520 | + self.assertEqual(res.status_int, 200) |
521 | + ip = json.loads(res.body)['allocated'] |
522 | + expected = { |
523 | + "id": 1, |
524 | + "floating_ip": '10.10.10.10'} |
525 | + self.assertEqual(ip, expected) |
526 | + |
527 | + def test_floating_ip_release(self): |
528 | + req = webob.Request.blank('/v1.1/os-floating-ips/1') |
529 | + req.method = 'DELETE' |
530 | + res = req.get_response(fakes.wsgi_app()) |
531 | + self.assertEqual(res.status_int, 200) |
532 | + actual = json.loads(res.body)['released'] |
533 | + expected = { |
534 | + "id": 1, |
535 | + "floating_ip": '10.10.10.10'} |
536 | + self.assertEqual(actual, expected) |
537 | + |
538 | + def test_floating_ip_associate(self): |
539 | + body = dict(associate_address=dict(fixed_ip='1.2.3.4')) |
540 | + req = webob.Request.blank('/v1.1/os-floating-ips/1/associate') |
541 | + req.method = 'POST' |
542 | + req.body = json.dumps(body) |
543 | + req.headers["content-type"] = "application/json" |
544 | + |
545 | + res = req.get_response(fakes.wsgi_app()) |
546 | + self.assertEqual(res.status_int, 200) |
547 | + actual = json.loads(res.body)['associated'] |
548 | + expected = { |
549 | + "floating_ip_id": '1', |
550 | + "floating_ip": "10.10.10.10", |
551 | + "fixed_ip": "1.2.3.4"} |
552 | + self.assertEqual(actual, expected) |
553 | + |
554 | + def test_floating_ip_disassociate(self): |
555 | + req = webob.Request.blank('/v1.1/os-floating-ips/1/disassociate') |
556 | + req.method = 'POST' |
557 | + res = req.get_response(fakes.wsgi_app()) |
558 | + self.assertEqual(res.status_int, 200) |
559 | + ip = json.loads(res.body)['disassociated'] |
560 | + expected = { |
561 | + "floating_ip": '10.10.10.10', |
562 | + "fixed_ip": '11.0.0.1'} |
563 | + self.assertEqual(ip, expected) |
564 | |
565 | === modified file 'nova/tests/api/openstack/fakes.py' |
566 | --- nova/tests/api/openstack/fakes.py 2011-06-24 12:01:51 +0000 |
567 | +++ nova/tests/api/openstack/fakes.py 2011-06-27 16:39:52 +0000 |
568 | @@ -16,7 +16,6 @@ |
569 | # under the License. |
570 | |
571 | import copy |
572 | -import json |
573 | import random |
574 | import string |
575 | |
576 | @@ -29,11 +28,11 @@ |
577 | |
578 | from nova import context |
579 | from nova import exception as exc |
580 | -from nova import flags |
581 | from nova import utils |
582 | import nova.api.openstack.auth |
583 | from nova.api import openstack |
584 | from nova.api.openstack import auth |
585 | +from nova.api.openstack import extensions |
586 | from nova.api.openstack import versions |
587 | from nova.api.openstack import limits |
588 | from nova.auth.manager import User, Project |
589 | @@ -82,7 +81,8 @@ |
590 | api10 = openstack.FaultWrapper(auth.AuthMiddleware( |
591 | limits.RateLimitingMiddleware(inner_app10))) |
592 | api11 = openstack.FaultWrapper(auth.AuthMiddleware( |
593 | - limits.RateLimitingMiddleware(inner_app11))) |
594 | + limits.RateLimitingMiddleware( |
595 | + extensions.ExtensionMiddleware(inner_app11)))) |
596 | mapper['/v1.0'] = api10 |
597 | mapper['/v1.1'] = api11 |
598 | mapper['/'] = openstack.FaultWrapper(versions.Versions()) |
Can you edit .Mailmap for secondary addresses instead of adding multiple emails in authors?