Merge lp:~bcwaldon/nova/osapi-servers-links into lp:~hudson-openstack/nova/trunk

Proposed by Brian Waldon
Status: Superseded
Proposed branch: lp:~bcwaldon/nova/osapi-servers-links
Merge into: lp:~hudson-openstack/nova/trunk
Diff against target: 223 lines (+116/-15)
3 files modified
nova/api/openstack/servers.py (+7/-3)
nova/api/openstack/views/servers.py (+53/-10)
nova/tests/api/openstack/test_servers.py (+56/-2)
To merge this branch: bzr merge lp:~bcwaldon/nova/osapi-servers-links
Reviewer Review Type Date Requested Status
Paul Voccio (community) Approve
Thierry Carrez (community) ffe Approve
Matt Dietz (community) Approve
Titan Pending
Review via email: mp+54264@code.launchpad.net

This proposal supersedes a proposal from 2011-03-18.

This proposal has been superseded by a proposal from 2011-03-25.

Commit message

Adding links container to openstack api v1.1 servers entities.

Description of the change

Adding links container to openstack api v1.1 servers entities. Resubmitted without prerequisite.

To post a comment you must log in.
Revision history for this message
Matt Dietz (cerberus) wrote :

You've got some conflicts you need to look at

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

> You've got some conflicts you need to look at

Resolved. The branch got a little stale while I was looking at other things.

Revision history for this message
Matt Dietz (cerberus) wrote :

115 +import re
116 +from nova import exception
117 +from webob import exc

Pep8 says modules should be ordered as such:

1. standard library imports
2. related third party imports
3. local application/library specific imports

So it should be re, webob and finally nova. Most people seem to be leaving a line of whitespace between each "tier" of module import

519 + if inst.get('instance_type') != None:

A little nit-picky, but you don't need to be this explicit. If inst.get(...): would be sufficient

540 + flavor_id = inst.get("instance_type", None)

Get already by default returns None

For the *_id cases near the above, you probably want to leave them the way they are since 0 obviously equates to false.

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

I decided to not do any value testing at all, and simply use whatever value was there.

I should also point out that this branch has a prerequisite branch (~rackspace-titan/nova/openstack-api-versioned-controllers) that hasn't landed yet. I prematurely removed it from this merge prop. It's a hassle to deal with prereqs and merge props, so I'm not going to resubmit it another two times. We can just wait to merge it.

Revision history for this message
Matt Dietz (cerberus) wrote :

lgtm.

review: Approve
Revision history for this message
Thierry Carrez (ttx) wrote :

This is really close to getting merged and is reasonable, FFe granted for late merging before EOD Monday

review: Approve (ffe)
Revision history for this message
Paul Voccio (pvo) wrote :

lgtm.

review: Approve
Revision history for this message
OpenStack Infra (hudson-openstack) wrote :

There are additional revisions which have not been approved in review. Please seek review and approval of these new revisions.

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'nova/api/openstack/servers.py'
2--- nova/api/openstack/servers.py 2011-03-25 12:51:35 +0000
3+++ nova/api/openstack/servers.py 2011-03-25 15:12:57 +0000
4@@ -48,11 +48,15 @@
5 """ The Server API controller for the OpenStack API """
6
7 _serialization_metadata = {
8- 'application/xml': {
9+ "application/xml": {
10 "attributes": {
11 "server": ["id", "imageId", "name", "flavorId", "hostId",
12 "status", "progress", "adminPass", "flavorRef",
13- "imageRef"]}}}
14+ "imageRef"],
15+ "link": ["rel", "type", "href"],
16+ },
17+ },
18+ }
19
20 def __init__(self):
21 self.compute_api = compute.API()
22@@ -572,7 +576,7 @@
23 base_url)
24 addresses_builder = nova.api.openstack.views.addresses.ViewBuilderV11()
25 return nova.api.openstack.views.servers.ViewBuilderV11(
26- addresses_builder, flavor_builder, image_builder)
27+ addresses_builder, flavor_builder, image_builder, base_url)
28
29 def _get_addresses_view_builder(self, req):
30 return nova.api.openstack.views.addresses.ViewBuilderV11(req)
31
32=== modified file 'nova/api/openstack/views/servers.py'
33--- nova/api/openstack/views/servers.py 2011-03-24 05:08:17 +0000
34+++ nova/api/openstack/views/servers.py 2011-03-25 15:12:57 +0000
35@@ -16,6 +16,7 @@
36 # under the License.
37
38 import hashlib
39+import os
40
41 from nova.compute import power_state
42 import nova.compute
43@@ -41,9 +42,13 @@
44 def build(self, inst, is_detail):
45 """Return a dict that represenst a server."""
46 if is_detail:
47- return self._build_detail(inst)
48+ server = self._build_detail(inst)
49 else:
50- return self._build_simple(inst)
51+ server = self._build_simple(inst)
52+
53+ self._build_extra(server, inst)
54+
55+ return server
56
57 def _build_simple(self, inst):
58 """Return a simple model of a server."""
59@@ -97,29 +102,67 @@
60 """Return the flavor sub-resource of a server."""
61 raise NotImplementedError()
62
63+ def _build_extra(self, response, inst):
64+ pass
65+
66
67 class ViewBuilderV10(ViewBuilder):
68 """Model an Openstack API V1.0 server response."""
69
70 def _build_image(self, response, inst):
71- response['imageId'] = inst['image_id']
72+ if 'image_id' in dict(inst):
73+ response['imageId'] = inst['image_id']
74
75 def _build_flavor(self, response, inst):
76- response['flavorId'] = inst['instance_type']
77+ if 'instance_type' in dict(inst):
78+ response['flavorId'] = inst['instance_type']
79
80
81 class ViewBuilderV11(ViewBuilder):
82 """Model an Openstack API V1.0 server response."""
83-
84- def __init__(self, addresses_builder, flavor_builder, image_builder):
85+ def __init__(self, addresses_builder, flavor_builder, image_builder,
86+ base_url):
87 ViewBuilder.__init__(self, addresses_builder)
88 self.flavor_builder = flavor_builder
89 self.image_builder = image_builder
90+ self.base_url = base_url
91
92 def _build_image(self, response, inst):
93- image_id = inst["image_id"]
94- response["imageRef"] = self.image_builder.generate_href(image_id)
95+ if "image_id" in dict(inst):
96+ image_id = inst.get("image_id")
97+ response["imageRef"] = self.image_builder.generate_href(image_id)
98
99 def _build_flavor(self, response, inst):
100- flavor_id = inst["instance_type"]
101- response["flavorRef"] = self.flavor_builder.generate_href(flavor_id)
102+ if "instance_type" in dict(inst):
103+ flavor_id = inst["instance_type"]
104+ flavor_ref = self.flavor_builder.generate_href(flavor_id)
105+ response["flavorRef"] = flavor_ref
106+
107+ def _build_extra(self, response, inst):
108+ self._build_links(response, inst)
109+
110+ def _build_links(self, response, inst):
111+ href = self.generate_href(inst["id"])
112+
113+ links = [
114+ {
115+ "rel": "self",
116+ "href": href,
117+ },
118+ {
119+ "rel": "bookmark",
120+ "type": "application/json",
121+ "href": href,
122+ },
123+ {
124+ "rel": "bookmark",
125+ "type": "application/xml",
126+ "href": href,
127+ },
128+ ]
129+
130+ response["server"]["links"] = links
131+
132+ def generate_href(self, server_id):
133+ """Create an url that refers to a specific server id."""
134+ return os.path.join(self.base_url, "servers", str(server_id))
135
136=== modified file 'nova/tests/api/openstack/test_servers.py'
137--- nova/tests/api/openstack/test_servers.py 2011-03-25 12:51:35 +0000
138+++ nova/tests/api/openstack/test_servers.py 2011-03-25 15:12:57 +0000
139@@ -164,6 +164,33 @@
140 self.assertEqual(res_dict['server']['id'], 1)
141 self.assertEqual(res_dict['server']['name'], 'server1')
142
143+ def test_get_server_by_id_v11(self):
144+ req = webob.Request.blank('/v1.1/servers/1')
145+ res = req.get_response(fakes.wsgi_app())
146+ res_dict = json.loads(res.body)
147+ self.assertEqual(res_dict['server']['id'], 1)
148+ self.assertEqual(res_dict['server']['name'], 'server1')
149+
150+ expected_links = [
151+ {
152+ "rel": "self",
153+ "href": "http://localhost/v1.1/servers/1",
154+ },
155+ {
156+ "rel": "bookmark",
157+ "type": "application/json",
158+ "href": "http://localhost/v1.1/servers/1",
159+ },
160+ {
161+ "rel": "bookmark",
162+ "type": "application/xml",
163+ "href": "http://localhost/v1.1/servers/1",
164+ },
165+ ]
166+
167+ print res_dict['server']
168+ self.assertEqual(res_dict['server']['links'], expected_links)
169+
170 def test_get_server_by_id_with_addresses(self):
171 private = "192.168.0.3"
172 public = ["1.2.3.4"]
173@@ -186,7 +213,6 @@
174 new_return_server = return_server_with_addresses(private, public)
175 self.stubs.Set(nova.db.api, 'instance_get', new_return_server)
176 req = webob.Request.blank('/v1.1/servers/1')
177- req.environ['api.version'] = '1.1'
178 res = req.get_response(fakes.wsgi_app())
179 res_dict = json.loads(res.body)
180 self.assertEqual(res_dict['server']['id'], 1)
181@@ -211,6 +237,35 @@
182 self.assertEqual(s.get('imageId', None), None)
183 i += 1
184
185+ def test_get_server_list_v11(self):
186+ req = webob.Request.blank('/v1.1/servers')
187+ res = req.get_response(fakes.wsgi_app())
188+ res_dict = json.loads(res.body)
189+
190+ for i, s in enumerate(res_dict['servers']):
191+ self.assertEqual(s['id'], i)
192+ self.assertEqual(s['name'], 'server%d' % i)
193+ self.assertEqual(s.get('imageId', None), None)
194+
195+ expected_links = [
196+ {
197+ "rel": "self",
198+ "href": "http://localhost/v1.1/servers/%d" % (i,),
199+ },
200+ {
201+ "rel": "bookmark",
202+ "type": "application/json",
203+ "href": "http://localhost/v1.1/servers/%d" % (i,),
204+ },
205+ {
206+ "rel": "bookmark",
207+ "type": "application/xml",
208+ "href": "http://localhost/v1.1/servers/%d" % (i,),
209+ },
210+ ]
211+
212+ self.assertEqual(s['links'], expected_links)
213+
214 def test_get_servers_with_limit(self):
215 req = webob.Request.blank('/v1.0/servers?limit=3')
216 res = req.get_response(fakes.wsgi_app())
217@@ -458,7 +513,6 @@
218
219 def test_get_all_server_details_v1_1(self):
220 req = webob.Request.blank('/v1.1/servers/detail')
221- req.environ['api.version'] = '1.1'
222 res = req.get_response(fakes.wsgi_app())
223 res_dict = json.loads(res.body)
224