Merge lp:~rvb/maas/use-reverse into lp:~maas-committers/maas/trunk
- use-reverse
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Raphaël Badin |
Approved revision: | no longer in the source branch. |
Merged at revision: | 659 |
Proposed branch: | lp:~rvb/maas/use-reverse |
Merge into: | lp:~maas-committers/maas/trunk |
Prerequisite: | lp:~rvb/maas/pxe-off-preseed |
Diff against target: |
286 lines (+60/-60) 2 files modified
src/maas/urls.py (+1/-1) src/metadataserver/tests/test_api.py (+59/-59) |
To merge this branch: | bzr merge lp:~rvb/maas/use-reverse |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Gavin Panella (community) | Approve | ||
Francesco Banconi (community) | code* | Approve | |
Review via email: mp+111240@code.launchpad.net |
Commit message
Use Django's reverse in src/metadataser
Description of the change
This branch fixes a problem I spotted when I was working on the pre-req branch.
The metadata application should be hooked up (in src/maas/urls.py) like this:
urlpatterns = patterns('',
url(r'^', include(
url(
)
Note the trailing slash at the end of '^metadata/'. Otherwise, reverse(...) does not return a correct path.
See https:/
I refactored src/metadataser
Gavin Panella (allenap) : | # |
Preview Diff
1 | === modified file 'src/maas/urls.py' | |||
2 | --- src/maas/urls.py 2012-04-16 10:00:51 +0000 | |||
3 | +++ src/maas/urls.py 2012-06-20 16:33:18 +0000 | |||
4 | @@ -23,7 +23,7 @@ | |||
5 | 23 | 23 | ||
6 | 24 | urlpatterns = patterns('', | 24 | urlpatterns = patterns('', |
7 | 25 | url(r'^', include('maasserver.urls')), | 25 | url(r'^', include('maasserver.urls')), |
9 | 26 | url(r'^metadata', include('metadataserver.urls')), | 26 | url(r'^metadata/', include('metadataserver.urls')), |
10 | 27 | ) | 27 | ) |
11 | 28 | 28 | ||
12 | 29 | if settings.STATIC_LOCAL_SERVE: | 29 | if settings.STATIC_LOCAL_SERVE: |
13 | 30 | 30 | ||
14 | === modified file 'src/metadataserver/tests/test_api.py' | |||
15 | --- src/metadataserver/tests/test_api.py 2012-06-20 16:33:18 +0000 | |||
16 | +++ src/metadataserver/tests/test_api.py 2012-06-20 16:33:18 +0000 | |||
17 | @@ -18,6 +18,7 @@ | |||
18 | 18 | 18 | ||
19 | 19 | from django.conf import settings | 19 | from django.conf import settings |
20 | 20 | from django.core.exceptions import PermissionDenied | 20 | from django.core.exceptions import PermissionDenied |
21 | 21 | from django.core.urlresolvers import reverse | ||
22 | 21 | from maasserver.enum import NODE_STATUS | 22 | from maasserver.enum import NODE_STATUS |
23 | 22 | from maasserver.exceptions import ( | 23 | from maasserver.exceptions import ( |
24 | 23 | MAASAPINotFound, | 24 | MAASAPINotFound, |
25 | @@ -128,33 +129,6 @@ | |||
26 | 128 | token = NodeKey.objects.get_token_for_node(node) | 129 | token = NodeKey.objects.get_token_for_node(node) |
27 | 129 | return OAuthAuthenticatedClient(get_node_init_user(), token) | 130 | return OAuthAuthenticatedClient(get_node_init_user(), token) |
28 | 130 | 131 | ||
29 | 131 | def make_url(self, path): | ||
30 | 132 | """Create an absolute URL for `path` on the metadata API. | ||
31 | 133 | |||
32 | 134 | :param path: Path within the metadata API to access. Should start | ||
33 | 135 | with a slash. | ||
34 | 136 | :return: An absolute URL for the given path within the metadata | ||
35 | 137 | service tree. | ||
36 | 138 | """ | ||
37 | 139 | assert path.startswith('/'), "Give absolute metadata API path." | ||
38 | 140 | # Root of the metadata API service. | ||
39 | 141 | metadata_root = "/metadata" | ||
40 | 142 | return metadata_root + path | ||
41 | 143 | |||
42 | 144 | def get(self, path, client=None): | ||
43 | 145 | """GET a resource from the metadata API. | ||
44 | 146 | |||
45 | 147 | :param path: Path within the metadata API to access. Should start | ||
46 | 148 | with a slash. | ||
47 | 149 | :param token: If given, authenticate the request using this token. | ||
48 | 150 | :type token: oauth.oauth.OAuthToken | ||
49 | 151 | :return: A response to the GET request. | ||
50 | 152 | :rtype: django.http.HttpResponse | ||
51 | 153 | """ | ||
52 | 154 | if client is None: | ||
53 | 155 | client = self.client | ||
54 | 156 | return client.get(self.make_url(path)) | ||
55 | 157 | |||
56 | 158 | def call_signal(self, client=None, version='latest', files={}, **kwargs): | 132 | def call_signal(self, client=None, version='latest', files={}, **kwargs): |
57 | 159 | """Call the API's signal method. | 133 | """Call the API's signal method. |
58 | 160 | 134 | ||
59 | @@ -177,37 +151,43 @@ | |||
60 | 177 | for name, content in files.items(): | 151 | for name, content in files.items(): |
61 | 178 | params[name] = BytesIO(content) | 152 | params[name] = BytesIO(content) |
62 | 179 | params[name].name = name | 153 | params[name].name = name |
64 | 180 | return client.post(self.make_url('/%s/' % version), params) | 154 | url = reverse('metadata-version', args=[version]) |
65 | 155 | return client.post(url, params) | ||
66 | 181 | 156 | ||
67 | 182 | def test_no_anonymous_access(self): | 157 | def test_no_anonymous_access(self): |
69 | 183 | self.assertEqual(httplib.UNAUTHORIZED, self.get('/').status_code) | 158 | self.assertEqual( |
70 | 159 | httplib.UNAUTHORIZED, | ||
71 | 160 | self.client.get(reverse('metadata')).status_code) | ||
72 | 184 | 161 | ||
73 | 185 | def test_metadata_index_shows_latest(self): | 162 | def test_metadata_index_shows_latest(self): |
74 | 186 | client = self.make_node_client() | 163 | client = self.make_node_client() |
76 | 187 | self.assertIn('latest', self.get('/', client).content) | 164 | self.assertIn('latest', client.get(reverse('metadata')).content) |
77 | 188 | 165 | ||
78 | 189 | def test_metadata_index_shows_only_known_versions(self): | 166 | def test_metadata_index_shows_only_known_versions(self): |
79 | 190 | client = self.make_node_client() | 167 | client = self.make_node_client() |
81 | 191 | for item in self.get('/', client).content.splitlines(): | 168 | for item in client.get(reverse('metadata')).content.splitlines(): |
82 | 192 | check_version(item) | 169 | check_version(item) |
83 | 193 | # The test is that we get here without exception. | 170 | # The test is that we get here without exception. |
84 | 194 | pass | 171 | pass |
85 | 195 | 172 | ||
86 | 196 | def test_version_index_shows_meta_data(self): | 173 | def test_version_index_shows_meta_data(self): |
87 | 197 | client = self.make_node_client() | 174 | client = self.make_node_client() |
89 | 198 | items = self.get('/latest/', client).content.splitlines() | 175 | url = reverse('metadata-version', args=['latest']) |
90 | 176 | items = client.get(url).content.splitlines() | ||
91 | 199 | self.assertIn('meta-data', items) | 177 | self.assertIn('meta-data', items) |
92 | 200 | 178 | ||
93 | 201 | def test_version_index_does_not_show_user_data_if_not_available(self): | 179 | def test_version_index_does_not_show_user_data_if_not_available(self): |
94 | 202 | client = self.make_node_client() | 180 | client = self.make_node_client() |
96 | 203 | items = self.get('/latest/', client).content.splitlines() | 181 | url = reverse('metadata-version', args=['latest']) |
97 | 182 | items = client.get(url).content.splitlines() | ||
98 | 204 | self.assertNotIn('user-data', items) | 183 | self.assertNotIn('user-data', items) |
99 | 205 | 184 | ||
100 | 206 | def test_version_index_shows_user_data_if_available(self): | 185 | def test_version_index_shows_user_data_if_available(self): |
101 | 207 | node = factory.make_node() | 186 | node = factory.make_node() |
102 | 208 | NodeUserData.objects.set_user_data(node, b"User data for node") | 187 | NodeUserData.objects.set_user_data(node, b"User data for node") |
103 | 209 | client = self.make_node_client(node) | 188 | client = self.make_node_client(node) |
105 | 210 | items = self.get('/latest/', client).content.splitlines() | 189 | url = reverse('metadata-version', args=['latest']) |
106 | 190 | items = client.get(url).content.splitlines() | ||
107 | 211 | self.assertIn('user-data', items) | 191 | self.assertIn('user-data', items) |
108 | 212 | 192 | ||
109 | 213 | def test_meta_data_view_lists_fields(self): | 193 | def test_meta_data_view_lists_fields(self): |
110 | @@ -215,20 +195,23 @@ | |||
111 | 215 | user, _ = factory.make_user_with_keys(n_keys=2, username='my-user') | 195 | user, _ = factory.make_user_with_keys(n_keys=2, username='my-user') |
112 | 216 | node = factory.make_node(owner=user) | 196 | node = factory.make_node(owner=user) |
113 | 217 | client = self.make_node_client(node=node) | 197 | client = self.make_node_client(node=node) |
115 | 218 | response = self.get('/latest/meta-data/', client) | 198 | url = reverse('metadata-meta-data', args=['latest', '']) |
116 | 199 | response = client.get(url) | ||
117 | 219 | self.assertIn('text/plain', response['Content-Type']) | 200 | self.assertIn('text/plain', response['Content-Type']) |
118 | 220 | self.assertItemsEqual( | 201 | self.assertItemsEqual( |
119 | 221 | MetaDataHandler.fields, response.content.split()) | 202 | MetaDataHandler.fields, response.content.split()) |
120 | 222 | 203 | ||
121 | 223 | def test_meta_data_view_is_sorted(self): | 204 | def test_meta_data_view_is_sorted(self): |
122 | 224 | client = self.make_node_client() | 205 | client = self.make_node_client() |
124 | 225 | response = self.get('/latest/meta-data/', client) | 206 | url = reverse('metadata-meta-data', args=['latest', '']) |
125 | 207 | response = client.get(url) | ||
126 | 226 | attributes = response.content.split() | 208 | attributes = response.content.split() |
127 | 227 | self.assertEqual(sorted(attributes), attributes) | 209 | self.assertEqual(sorted(attributes), attributes) |
128 | 228 | 210 | ||
129 | 229 | def test_meta_data_unknown_item_is_not_found(self): | 211 | def test_meta_data_unknown_item_is_not_found(self): |
130 | 230 | client = self.make_node_client() | 212 | client = self.make_node_client() |
132 | 231 | response = self.get('/latest/meta-data/UNKNOWN-ITEM-HA-HA-HA', client) | 213 | url = reverse('metadata-meta-data', args=['latest', 'UNKNOWN-ITEM']) |
133 | 214 | response = client.get(url) | ||
134 | 232 | self.assertEqual(httplib.NOT_FOUND, response.status_code) | 215 | self.assertEqual(httplib.NOT_FOUND, response.status_code) |
135 | 233 | 216 | ||
136 | 234 | def test_get_attribute_producer_supports_all_fields(self): | 217 | def test_get_attribute_producer_supports_all_fields(self): |
137 | @@ -239,7 +222,8 @@ | |||
138 | 239 | def test_meta_data_local_hostname_returns_hostname(self): | 222 | def test_meta_data_local_hostname_returns_hostname(self): |
139 | 240 | hostname = factory.getRandomString() | 223 | hostname = factory.getRandomString() |
140 | 241 | client = self.make_node_client(factory.make_node(hostname=hostname)) | 224 | client = self.make_node_client(factory.make_node(hostname=hostname)) |
142 | 242 | response = self.get('/latest/meta-data/local-hostname', client) | 225 | url = reverse('metadata-meta-data', args=['latest', 'local-hostname']) |
143 | 226 | response = client.get(url) | ||
144 | 243 | self.assertEqual( | 227 | self.assertEqual( |
145 | 244 | (httplib.OK, hostname), | 228 | (httplib.OK, hostname), |
146 | 245 | (response.status_code, response.content.decode('ascii'))) | 229 | (response.status_code, response.content.decode('ascii'))) |
147 | @@ -248,7 +232,8 @@ | |||
148 | 248 | def test_meta_data_instance_id_returns_system_id(self): | 232 | def test_meta_data_instance_id_returns_system_id(self): |
149 | 249 | node = factory.make_node() | 233 | node = factory.make_node() |
150 | 250 | client = self.make_node_client(node) | 234 | client = self.make_node_client(node) |
152 | 251 | response = self.get('/latest/meta-data/instance-id', client) | 235 | url = reverse('metadata-meta-data', args=['latest', 'instance-id']) |
153 | 236 | response = client.get(url) | ||
154 | 252 | self.assertEqual( | 237 | self.assertEqual( |
155 | 253 | (httplib.OK, node.system_id), | 238 | (httplib.OK, node.system_id), |
156 | 254 | (response.status_code, response.content.decode('ascii'))) | 239 | (response.status_code, response.content.decode('ascii'))) |
157 | @@ -259,39 +244,45 @@ | |||
158 | 259 | node = factory.make_node() | 244 | node = factory.make_node() |
159 | 260 | NodeUserData.objects.set_user_data(node, data) | 245 | NodeUserData.objects.set_user_data(node, data) |
160 | 261 | client = self.make_node_client(node) | 246 | client = self.make_node_client(node) |
162 | 262 | response = self.get('/latest/user-data', client) | 247 | response = client.get(reverse('metadata-user-data', args=['latest'])) |
163 | 263 | self.assertEqual('application/octet-stream', response['Content-Type']) | 248 | self.assertEqual('application/octet-stream', response['Content-Type']) |
164 | 264 | self.assertIsInstance(response.content, str) | 249 | self.assertIsInstance(response.content, str) |
165 | 265 | self.assertEqual( | 250 | self.assertEqual( |
166 | 266 | (httplib.OK, data), (response.status_code, response.content)) | 251 | (httplib.OK, data), (response.status_code, response.content)) |
167 | 267 | 252 | ||
168 | 268 | def test_user_data_for_node_without_user_data_returns_not_found(self): | 253 | def test_user_data_for_node_without_user_data_returns_not_found(self): |
170 | 269 | response = self.get('/latest/user-data', self.make_node_client()) | 254 | client = self.make_node_client() |
171 | 255 | response = client.get(reverse('metadata-user-data', args=['latest'])) | ||
172 | 270 | self.assertEqual(httplib.NOT_FOUND, response.status_code) | 256 | self.assertEqual(httplib.NOT_FOUND, response.status_code) |
173 | 271 | 257 | ||
174 | 272 | def test_public_keys_not_listed_for_node_without_public_keys(self): | 258 | def test_public_keys_not_listed_for_node_without_public_keys(self): |
176 | 273 | response = self.get('/latest/meta-data/', self.make_node_client()) | 259 | url = reverse('metadata-meta-data', args=['latest', '']) |
177 | 260 | client = self.make_node_client() | ||
178 | 261 | response = client.get(url) | ||
179 | 274 | self.assertNotIn( | 262 | self.assertNotIn( |
180 | 275 | 'public-keys', response.content.decode('ascii').split('\n')) | 263 | 'public-keys', response.content.decode('ascii').split('\n')) |
181 | 276 | 264 | ||
182 | 277 | def test_public_keys_listed_for_node_with_public_keys(self): | 265 | def test_public_keys_listed_for_node_with_public_keys(self): |
183 | 278 | user, _ = factory.make_user_with_keys(n_keys=2, username='my-user') | 266 | user, _ = factory.make_user_with_keys(n_keys=2, username='my-user') |
184 | 279 | node = factory.make_node(owner=user) | 267 | node = factory.make_node(owner=user) |
187 | 280 | response = self.get( | 268 | url = reverse('metadata-meta-data', args=['latest', '']) |
188 | 281 | '/latest/meta-data/', self.make_node_client(node=node)) | 269 | client = self.make_node_client(node=node) |
189 | 270 | response = client.get(url) | ||
190 | 282 | self.assertIn( | 271 | self.assertIn( |
191 | 283 | 'public-keys', response.content.decode('ascii').split('\n')) | 272 | 'public-keys', response.content.decode('ascii').split('\n')) |
192 | 284 | 273 | ||
193 | 285 | def test_public_keys_for_node_without_public_keys_returns_not_found(self): | 274 | def test_public_keys_for_node_without_public_keys_returns_not_found(self): |
196 | 286 | response = self.get( | 275 | url = reverse('metadata-meta-data', args=['latest', 'public-keys']) |
197 | 287 | '/latest/meta-data/public-keys', self.make_node_client()) | 276 | client = self.make_node_client() |
198 | 277 | response = client.get(url) | ||
199 | 288 | self.assertEqual(httplib.NOT_FOUND, response.status_code) | 278 | self.assertEqual(httplib.NOT_FOUND, response.status_code) |
200 | 289 | 279 | ||
201 | 290 | def test_public_keys_for_node_returns_list_of_keys(self): | 280 | def test_public_keys_for_node_returns_list_of_keys(self): |
202 | 291 | user, _ = factory.make_user_with_keys(n_keys=2, username='my-user') | 281 | user, _ = factory.make_user_with_keys(n_keys=2, username='my-user') |
203 | 292 | node = factory.make_node(owner=user) | 282 | node = factory.make_node(owner=user) |
206 | 293 | response = self.get( | 283 | url = reverse('metadata-meta-data', args=['latest', 'public-keys']) |
207 | 294 | '/latest/meta-data/public-keys', self.make_node_client(node=node)) | 284 | client = self.make_node_client(node=node) |
208 | 285 | response = client.get(url) | ||
209 | 295 | self.assertEqual(httplib.OK, response.status_code) | 286 | self.assertEqual(httplib.OK, response.status_code) |
210 | 296 | keys = SSHKey.objects.filter(user=user).values_list('key', flat=True) | 287 | keys = SSHKey.objects.filter(user=user).values_list('key', flat=True) |
211 | 297 | expected_response = '\n'.join(keys) | 288 | expected_response = '\n'.join(keys) |
212 | @@ -320,7 +311,8 @@ | |||
213 | 320 | def test_signaling_requires_status_code(self): | 311 | def test_signaling_requires_status_code(self): |
214 | 321 | node = factory.make_node(status=NODE_STATUS.COMMISSIONING) | 312 | node = factory.make_node(status=NODE_STATUS.COMMISSIONING) |
215 | 322 | client = self.make_node_client(node=node) | 313 | client = self.make_node_client(node=node) |
217 | 323 | response = client.post(self.make_url('/latest/'), {'op': 'signal'}) | 314 | url = reverse('metadata-version', args=['latest']) |
218 | 315 | response = client.post(url, {'op': 'signal'}) | ||
219 | 324 | self.assertEqual(httplib.BAD_REQUEST, response.status_code) | 316 | self.assertEqual(httplib.BAD_REQUEST, response.status_code) |
220 | 325 | 317 | ||
221 | 326 | def test_signaling_rejects_unknown_status_code(self): | 318 | def test_signaling_rejects_unknown_status_code(self): |
222 | @@ -505,8 +497,10 @@ | |||
223 | 505 | 497 | ||
224 | 506 | def test_api_retrieves_node_metadata_by_mac(self): | 498 | def test_api_retrieves_node_metadata_by_mac(self): |
225 | 507 | mac = factory.make_mac_address() | 499 | mac = factory.make_mac_address() |
228 | 508 | response = self.get( | 500 | url = reverse( |
229 | 509 | '/latest/by-mac/%s/meta-data/instance-id/' % mac.mac_address) | 501 | 'metadata-meta-data-by-mac', |
230 | 502 | args=['latest', mac.mac_address, 'instance-id']) | ||
231 | 503 | response = self.client.get(url) | ||
232 | 510 | self.assertEqual( | 504 | self.assertEqual( |
233 | 511 | (httplib.OK, mac.node.system_id), | 505 | (httplib.OK, mac.node.system_id), |
234 | 512 | (response.status_code, response.content)) | 506 | (response.status_code, response.content)) |
235 | @@ -515,7 +509,9 @@ | |||
236 | 515 | mac = factory.make_mac_address() | 509 | mac = factory.make_mac_address() |
237 | 516 | user_data = factory.getRandomString().encode('ascii') | 510 | user_data = factory.getRandomString().encode('ascii') |
238 | 517 | NodeUserData.objects.set_user_data(mac.node, user_data) | 511 | NodeUserData.objects.set_user_data(mac.node, user_data) |
240 | 518 | response = self.get('/latest/by-mac/%s/user-data' % mac.mac_address) | 512 | url = reverse( |
241 | 513 | 'metadata-user-data-by-mac', args=['latest', mac.mac_address]) | ||
242 | 514 | response = self.client.get(url) | ||
243 | 519 | self.assertEqual( | 515 | self.assertEqual( |
244 | 520 | (httplib.OK, user_data), | 516 | (httplib.OK, user_data), |
245 | 521 | (response.status_code, response.content)) | 517 | (response.status_code, response.content)) |
246 | @@ -523,29 +519,33 @@ | |||
247 | 523 | def test_api_normally_disallows_anonymous_node_metadata_access(self): | 519 | def test_api_normally_disallows_anonymous_node_metadata_access(self): |
248 | 524 | self.patch(settings, 'ALLOW_ANONYMOUS_METADATA_ACCESS', False) | 520 | self.patch(settings, 'ALLOW_ANONYMOUS_METADATA_ACCESS', False) |
249 | 525 | mac = factory.make_mac_address() | 521 | mac = factory.make_mac_address() |
252 | 526 | response = self.get( | 522 | url = reverse( |
253 | 527 | '/latest/by-mac/%s/meta-data/instance-id/' % mac.mac_address) | 523 | 'metadata-meta-data-by-mac', |
254 | 524 | args=['latest', mac.mac_address, 'instance-id']) | ||
255 | 525 | response = self.client.get(url) | ||
256 | 528 | self.assertEqual(httplib.FORBIDDEN, response.status_code) | 526 | self.assertEqual(httplib.FORBIDDEN, response.status_code) |
257 | 529 | 527 | ||
258 | 530 | def test_netboot_off(self): | 528 | def test_netboot_off(self): |
259 | 531 | node = factory.make_node(netboot=True) | 529 | node = factory.make_node(netboot=True) |
260 | 532 | client = self.make_node_client(node=node) | 530 | client = self.make_node_client(node=node) |
263 | 533 | response = client.post( | 531 | url = reverse('metadata-version', args=['latest']) |
264 | 534 | self.make_url('/latest/'), {'op': 'netboot_off'}) | 532 | response = client.post(url, {'op': 'netboot_off'}) |
265 | 535 | node = reload_object(node) | 533 | node = reload_object(node) |
266 | 536 | self.assertFalse(node.netboot, response) | 534 | self.assertFalse(node.netboot, response) |
267 | 537 | 535 | ||
268 | 538 | def test_netboot_on(self): | 536 | def test_netboot_on(self): |
269 | 539 | node = factory.make_node(netboot=False) | 537 | node = factory.make_node(netboot=False) |
270 | 540 | client = self.make_node_client(node=node) | 538 | client = self.make_node_client(node=node) |
272 | 541 | response = client.post(self.make_url('/latest/'), {'op': 'netboot_on'}) | 539 | url = reverse('metadata-version', args=['latest']) |
273 | 540 | response = client.post(url, {'op': 'netboot_on'}) | ||
274 | 542 | node = reload_object(node) | 541 | node = reload_object(node) |
275 | 543 | self.assertTrue(node.netboot, response) | 542 | self.assertTrue(node.netboot, response) |
276 | 544 | 543 | ||
277 | 545 | def test_anonymous_netboot_off(self): | 544 | def test_anonymous_netboot_off(self): |
278 | 546 | node = factory.make_node(netboot=True) | 545 | node = factory.make_node(netboot=True) |
281 | 547 | anon_netboot_off_url = self.make_url( | 546 | anon_netboot_off_url = reverse( |
282 | 548 | '/latest/%s/edit/' % node.system_id) | 547 | 'metadata-anon-node-edit', args=['latest', |
283 | 548 | node.system_id]) | ||
284 | 549 | response = self.client.post( | 549 | response = self.client.post( |
285 | 550 | anon_netboot_off_url, {'op': 'netboot_off'}) | 550 | anon_netboot_off_url, {'op': 'netboot_off'}) |
286 | 551 | node = reload_object(node) | 551 | node = reload_object(node) |
Looks good.