Merge lp:~rackspace-titan/nova/osapi-server-ips-lp751560 into lp:~hudson-openstack/nova/trunk

Proposed by Naveed Massjouni
Status: Merged
Approved by: Devin Carlen
Approved revision: 947
Merged at revision: 959
Proposed branch: lp:~rackspace-titan/nova/osapi-server-ips-lp751560
Merge into: lp:~hudson-openstack/nova/trunk
Prerequisite: lp:~rackspace-titan/nova/osapi-xml-serialization
Diff against target: 232 lines (+164/-11)
5 files modified
nova/api/openstack/__init__.py (+6/-0)
nova/api/openstack/ips.py (+72/-0)
nova/api/openstack/servers.py (+0/-9)
nova/api/openstack/views/addresses.py (+8/-2)
nova/tests/api/openstack/test_servers.py (+78/-0)
To merge this branch: bzr merge lp:~rackspace-titan/nova/osapi-server-ips-lp751560
Reviewer Review Type Date Requested Status
Devin Carlen (community) Approve
Rick Harris (community) Approve
Brian Waldon (community) Approve
Jay Pipes (community) Approve
Review via email: mp+56645@code.launchpad.net

Description of the change

Added support for listing addresses of a server in the openstack api.
Now you can GET
 * /servers/1/ips
 * /servers/1/ips/public
 * /servers/1/ips/private
Supports v1.0 json and xml.
Added corresponding tests.

To post a comment you must log in.
Revision history for this message
Jay Pipes (jaypipes) wrote :

lgtm. nice work.

review: Approve
Revision history for this message
Brian Waldon (bcwaldon) wrote :

Should build_private/public_parts be private?

review: Needs Information
Revision history for this message
Brian Waldon (bcwaldon) wrote :

Do you have any plans for v1.1 support?

Revision history for this message
Naveed Massjouni (ironcamel) wrote :

@Brian:

> Should build_private/public_parts be private?

Nope. I abstracted that logic out so I could call it from the nova/api/openstack/ips.py controller.

> Do you have any plans for v1.1 support?

Not for cactus.

Revision history for this message
Brian Waldon (bcwaldon) wrote :

> @Brian:
>
> > Should build_private/public_parts be private?
>
> Nope. I abstracted that logic out so I could call it from the
> nova/api/openstack/ips.py controller.
>
> > Do you have any plans for v1.1 support?
>
> Not for cactus.

Gotcha.

review: Approve
946. By Naveed Massjouni

Merge from trunk

947. By Naveed Massjouni

Controllers now inherit from nova.api.openstack.common.OpenstackController.

Revision history for this message
Rick Harris (rconradharris) wrote :

lgtm

review: Approve
Revision history for this message
Devin Carlen (devcamcar) wrote :

great unit tests, approve

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'nova/api/openstack/__init__.py'
--- nova/api/openstack/__init__.py 2011-03-30 02:09:42 +0000
+++ nova/api/openstack/__init__.py 2011-04-06 21:51:35 +0000
@@ -34,6 +34,7 @@
34from nova.api.openstack import flavors34from nova.api.openstack import flavors
35from nova.api.openstack import images35from nova.api.openstack import images
36from nova.api.openstack import image_metadata36from nova.api.openstack import image_metadata
37from nova.api.openstack import ips
37from nova.api.openstack import limits38from nova.api.openstack import limits
38from nova.api.openstack import servers39from nova.api.openstack import servers
39from nova.api.openstack import server_metadata40from nova.api.openstack import server_metadata
@@ -144,6 +145,11 @@
144 parent_resource=dict(member_name='server',145 parent_resource=dict(member_name='server',
145 collection_name='servers'))146 collection_name='servers'))
146147
148 mapper.resource("ip", "ips", controller=ips.Controller(),
149 collection=dict(public='GET', private='GET'),
150 parent_resource=dict(member_name='server',
151 collection_name='servers'))
152
147153
148class APIRouterV11(APIRouter):154class APIRouterV11(APIRouter):
149 """Define routes specific to OpenStack API V1.1."""155 """Define routes specific to OpenStack API V1.1."""
150156
=== added file 'nova/api/openstack/ips.py'
--- nova/api/openstack/ips.py 1970-01-01 00:00:00 +0000
+++ nova/api/openstack/ips.py 2011-04-06 21:51:35 +0000
@@ -0,0 +1,72 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2011 OpenStack LLC.
4# All Rights Reserved.
5#
6# Licensed under the Apache License, Version 2.0 (the "License"); you may
7# not use this file except in compliance with the License. You may obtain
8# a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15# License for the specific language governing permissions and limitations
16# under the License.
17
18import time
19
20from webob import exc
21
22import nova
23import nova.api.openstack.views.addresses
24from nova.api.openstack import common
25from nova.api.openstack import faults
26
27
28class Controller(common.OpenstackController):
29 """The servers addresses API controller for the Openstack API."""
30
31 _serialization_metadata = {
32 'application/xml': {
33 'list_collections': {
34 'public': {'item_name': 'ip', 'item_key': 'addr'},
35 'private': {'item_name': 'ip', 'item_key': 'addr'},
36 },
37 },
38 }
39
40 def __init__(self):
41 self.compute_api = nova.compute.API()
42 self.builder = nova.api.openstack.views.addresses.ViewBuilderV10()
43
44 def index(self, req, server_id):
45 try:
46 instance = self.compute_api.get(req.environ['nova.context'], id)
47 except nova.exception.NotFound:
48 return faults.Fault(exc.HTTPNotFound())
49 return {'addresses': self.builder.build(instance)}
50
51 def public(self, req, server_id):
52 try:
53 instance = self.compute_api.get(req.environ['nova.context'], id)
54 except nova.exception.NotFound:
55 return faults.Fault(exc.HTTPNotFound())
56 return {'public': self.builder.build_public_parts(instance)}
57
58 def private(self, req, server_id):
59 try:
60 instance = self.compute_api.get(req.environ['nova.context'], id)
61 except nova.exception.NotFound:
62 return faults.Fault(exc.HTTPNotFound())
63 return {'private': self.builder.build_private_parts(instance)}
64
65 def show(self, req, server_id, id):
66 return faults.Fault(exc.HTTPNotImplemented())
67
68 def create(self, req, server_id):
69 return faults.Fault(exc.HTTPNotImplemented())
70
71 def delete(self, req, server_id, id):
72 return faults.Fault(exc.HTTPNotImplemented())
073
=== modified file 'nova/api/openstack/servers.py'
--- nova/api/openstack/servers.py 2011-04-06 21:51:35 +0000
+++ nova/api/openstack/servers.py 2011-04-06 21:51:35 +0000
@@ -70,15 +70,6 @@
70 self._image_service = utils.import_object(FLAGS.image_service)70 self._image_service = utils.import_object(FLAGS.image_service)
71 super(Controller, self).__init__()71 super(Controller, self).__init__()
7272
73 def ips(self, req, id):
74 try:
75 instance = self.compute_api.get(req.environ['nova.context'], id)
76 except exception.NotFound:
77 return faults.Fault(exc.HTTPNotFound())
78
79 builder = self._get_addresses_view_builder(req)
80 return builder.build(instance)
81
82 def index(self, req):73 def index(self, req):
83 """ Returns a list of server names and ids for a given user """74 """ Returns a list of server names and ids for a given user """
84 return self._items(req, is_detail=False)75 return self._items(req, is_detail=False)
8576
=== modified file 'nova/api/openstack/views/addresses.py'
--- nova/api/openstack/views/addresses.py 2011-03-17 07:21:09 +0000
+++ nova/api/openstack/views/addresses.py 2011-04-06 21:51:35 +0000
@@ -28,10 +28,16 @@
2828
29class ViewBuilderV10(ViewBuilder):29class ViewBuilderV10(ViewBuilder):
30 def build(self, inst):30 def build(self, inst):
31 private_ips = utils.get_from_path(inst, 'fixed_ip/address')31 private_ips = self.build_private_parts(inst)
32 public_ips = utils.get_from_path(inst, 'fixed_ip/floating_ips/address')32 public_ips = self.build_public_parts(inst)
33 return dict(public=public_ips, private=private_ips)33 return dict(public=public_ips, private=private_ips)
3434
35 def build_public_parts(self, inst):
36 return utils.get_from_path(inst, 'fixed_ip/floating_ips/address')
37
38 def build_private_parts(self, inst):
39 return utils.get_from_path(inst, 'fixed_ip/address')
40
3541
36class ViewBuilderV11(ViewBuilder):42class ViewBuilderV11(ViewBuilder):
37 def build(self, inst):43 def build(self, inst):
3844
=== modified file 'nova/tests/api/openstack/test_servers.py'
--- nova/tests/api/openstack/test_servers.py 2011-04-06 21:51:35 +0000
+++ nova/tests/api/openstack/test_servers.py 2011-04-06 21:51:35 +0000
@@ -228,6 +228,84 @@
228 self.assertEqual(len(addresses["private"]), 1)228 self.assertEqual(len(addresses["private"]), 1)
229 self.assertEqual(addresses["private"][0], private)229 self.assertEqual(addresses["private"][0], private)
230230
231 def test_get_server_addresses_V10(self):
232 private = '192.168.0.3'
233 public = ['1.2.3.4']
234 new_return_server = return_server_with_addresses(private, public)
235 self.stubs.Set(nova.db.api, 'instance_get', new_return_server)
236 req = webob.Request.blank('/v1.0/servers/1/ips')
237 res = req.get_response(fakes.wsgi_app())
238 res_dict = json.loads(res.body)
239 self.assertEqual(res_dict, {
240 'addresses': {'public': public, 'private': [private]}})
241
242 def test_get_server_addresses_xml_V10(self):
243 private_expected = "192.168.0.3"
244 public_expected = ["1.2.3.4"]
245 new_return_server = return_server_with_addresses(private_expected,
246 public_expected)
247 self.stubs.Set(nova.db.api, 'instance_get', new_return_server)
248 req = webob.Request.blank('/v1.0/servers/1/ips')
249 req.headers['Accept'] = 'application/xml'
250 res = req.get_response(fakes.wsgi_app())
251 dom = minidom.parseString(res.body)
252 (addresses,) = dom.childNodes
253 self.assertEquals(addresses.nodeName, 'addresses')
254 (public,) = addresses.getElementsByTagName('public')
255 (ip,) = public.getElementsByTagName('ip')
256 self.assertEquals(ip.getAttribute('addr'), public_expected[0])
257 (private,) = addresses.getElementsByTagName('private')
258 (ip,) = private.getElementsByTagName('ip')
259 self.assertEquals(ip.getAttribute('addr'), private_expected)
260
261 def test_get_server_addresses_public_V10(self):
262 private = "192.168.0.3"
263 public = ["1.2.3.4"]
264 new_return_server = return_server_with_addresses(private, public)
265 self.stubs.Set(nova.db.api, 'instance_get', new_return_server)
266 req = webob.Request.blank('/v1.0/servers/1/ips/public')
267 res = req.get_response(fakes.wsgi_app())
268 res_dict = json.loads(res.body)
269 self.assertEqual(res_dict, {'public': public})
270
271 def test_get_server_addresses_private_V10(self):
272 private = "192.168.0.3"
273 public = ["1.2.3.4"]
274 new_return_server = return_server_with_addresses(private, public)
275 self.stubs.Set(nova.db.api, 'instance_get', new_return_server)
276 req = webob.Request.blank('/v1.0/servers/1/ips/private')
277 res = req.get_response(fakes.wsgi_app())
278 res_dict = json.loads(res.body)
279 self.assertEqual(res_dict, {'private': [private]})
280
281 def test_get_server_addresses_public_xml_V10(self):
282 private = "192.168.0.3"
283 public = ["1.2.3.4"]
284 new_return_server = return_server_with_addresses(private, public)
285 self.stubs.Set(nova.db.api, 'instance_get', new_return_server)
286 req = webob.Request.blank('/v1.0/servers/1/ips/public')
287 req.headers['Accept'] = 'application/xml'
288 res = req.get_response(fakes.wsgi_app())
289 dom = minidom.parseString(res.body)
290 (public_node,) = dom.childNodes
291 self.assertEquals(public_node.nodeName, 'public')
292 (ip,) = public_node.getElementsByTagName('ip')
293 self.assertEquals(ip.getAttribute('addr'), public[0])
294
295 def test_get_server_addresses_private_xml_V10(self):
296 private = "192.168.0.3"
297 public = ["1.2.3.4"]
298 new_return_server = return_server_with_addresses(private, public)
299 self.stubs.Set(nova.db.api, 'instance_get', new_return_server)
300 req = webob.Request.blank('/v1.0/servers/1/ips/private')
301 req.headers['Accept'] = 'application/xml'
302 res = req.get_response(fakes.wsgi_app())
303 dom = minidom.parseString(res.body)
304 (private_node,) = dom.childNodes
305 self.assertEquals(private_node.nodeName, 'private')
306 (ip,) = private_node.getElementsByTagName('ip')
307 self.assertEquals(ip.getAttribute('addr'), private)
308
231 def test_get_server_by_id_with_addresses_v11(self):309 def test_get_server_by_id_with_addresses_v11(self):
232 private = "192.168.0.3"310 private = "192.168.0.3"
233 public = ["1.2.3.4"]311 public = ["1.2.3.4"]