launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #06500
[Merge] lp:~rvb/maas/maas-api-versionning into lp:maas
Raphaël Badin has proposed merging lp:~rvb/maas/maas-api-versionning into lp:maas.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~rvb/maas/maas-api-versionning/+merge/94725
This branch adds proper versioning to the API (/api/nodes/ is now /api/1.0/nodes).
Drive-by fixes:
- refactor tests to factor out the API version part APIV1TestMixin.get_uri. This will allow us to reuse the tests when we create another API version (all we will have to do is override the test case's 'get_uri' method).
- refactor API urls in a separate file (urls_api.py)
--
https://code.launchpad.net/~rvb/maas/maas-api-versionning/+merge/94725
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~rvb/maas/maas-api-versionning into lp:maas.
=== modified file 'src/maas/settings.py'
--- src/maas/settings.py 2012-02-22 14:04:11 +0000
+++ src/maas/settings.py 2012-02-27 07:50:23 +0000
@@ -33,7 +33,7 @@
LOGOUT_URL = '/'
LOGIN_REDIRECT_URL = '/'
-API_URL_REGEXP = '^/api/'
+API_URL_REGEXP = '^/api/1\.0/'
METADATA_URL_REGEXP = '^/metadata/'
=== modified file 'src/maasserver/tests/test_api.py'
--- src/maasserver/tests/test_api.py 2012-02-24 14:58:22 +0000
+++ src/maasserver/tests/test_api.py 2012-02-27 07:50:23 +0000
@@ -32,13 +32,24 @@
from metadataserver.nodeinituser import get_node_init_user
-class AnonymousEnlistmentAPITest(TestCase):
+class APIV1TestMixin:
+
+ def get_uri(self, path):
+ """GET an API V1 uri.
+
+ :return: The API uri.
+ """
+ api_root = '/api/1.0/'
+ return api_root + path
+
+
+class AnonymousEnlistmentAPITest(APIV1TestMixin, TestCase):
# Nodes can be enlisted anonymously.
def test_POST_new_creates_node(self):
# The API allows a Node to be created.
response = self.client.post(
- '/api/nodes/',
+ self.get_uri('nodes/'),
{
'op': 'new',
'hostname': 'diane',
@@ -58,7 +69,7 @@
# The API allows a Node to be created and associated with MAC
# Addresses.
self.client.post(
- '/api/nodes/',
+ self.get_uri('nodes/'),
{
'op': 'new',
'hostname': 'diane',
@@ -72,7 +83,7 @@
def test_POST_returns_limited_fields(self):
response = self.client.post(
- '/api/nodes/',
+ self.get_uri('nodes/'),
{
'op': 'new',
'hostname': 'diane',
@@ -87,7 +98,7 @@
# If there is no operation ('op=operation_name') specified in the
# request data, a 'Bad request' response is returned.
response = self.client.post(
- '/api/nodes/',
+ self.get_uri('nodes/'),
{
'hostname': 'diane',
'mac_addresses': ['aa:bb:cc:dd:ee:ff', 'invalid'],
@@ -101,7 +112,7 @@
# If the operation ('op=operation_name') specified in the
# request data is unknown, a 'Bad request' response is returned.
response = self.client.post(
- '/api/nodes/',
+ self.get_uri('nodes/'),
{
'op': 'invalid_operation',
'hostname': 'diane',
@@ -116,7 +127,7 @@
# If the data provided to create a node with an invalid MAC
# Address, a 'Bad request' response is returned.
response = self.client.post(
- '/api/nodes/',
+ self.get_uri('nodes/'),
{
'op': 'new',
'hostname': 'diane',
@@ -132,28 +143,28 @@
parsed_result['mac_addresses'])
-class NodeAnonAPITest(TestCase):
+class NodeAnonAPITest(APIV1TestMixin, TestCase):
def test_anon_nodes_GET(self):
# Anonymous requests to the API are denied.
- response = self.client.get('/api/nodes/')
+ response = self.client.get(self.get_uri('nodes/'))
self.assertEqual(httplib.UNAUTHORIZED, response.status_code)
def test_anon_api_doc(self):
# The documentation is accessible to anon users.
- response = self.client.get('/api/doc/')
+ response = self.client.get(self.get_uri('doc/'))
self.assertEqual(httplib.OK, response.status_code)
def test_node_init_user_cannot_access(self):
token = NodeKey.objects.create_token(factory.make_node())
client = OAuthAuthenticatedClient(get_node_init_user(), token)
- response = client.get('/api/nodes/', {'op': 'list'})
+ response = client.get(self.get_uri('nodes/'), {'op': 'list'})
self.assertEqual(httplib.FORBIDDEN, response.status_code)
-class APITestCase(TestCase):
+class APITestCase(APIV1TestMixin, TestCase):
"""Extension to `TestCase`: log in first.
:ivar logged_in_user: A user who is currently logged in and can access
@@ -179,12 +190,12 @@
return [node.get('system_id') for node in parsed_result]
-class NodeAPILoggedInTest(LoggedInTestCase):
+class NodeAPILoggedInTest(APIV1TestMixin, LoggedInTestCase):
def test_nodes_GET_logged_in(self):
# A (Django) logged-in user can access the API.
node = factory.make_node()
- response = self.client.get('/api/nodes/', {'op': 'list'})
+ response = self.client.get(self.get_uri('nodes/'), {'op': 'list'})
parsed_result = json.loads(response.content)
self.assertEqual(httplib.OK, response.status_code)
@@ -192,16 +203,16 @@
class TestNodeAPI(APITestCase):
- """Tests for /api/nodes/<node>/."""
+ """Tests for /api/1.0/nodes/<node>/."""
- def get_uri(self, node):
+ def get_node_uri(self, node):
"""Get the API URI for `node`."""
- return '/api/nodes/%s/' % node.system_id
+ return self.get_uri('nodes/%s/') % node.system_id
def test_GET_returns_node(self):
# The api allows for fetching a single Node (using system_id).
node = factory.make_node(set_hostname=True)
- response = self.client.get(self.get_uri(node))
+ response = self.client.get(self.get_node_uri(node))
parsed_result = json.loads(response.content)
self.assertEqual(httplib.OK, response.status_code)
@@ -214,58 +225,58 @@
other_node = factory.make_node(
status=NODE_STATUS.ALLOCATED, owner=factory.make_user())
- response = self.client.get(self.get_uri(other_node))
+ response = self.client.get(self.get_node_uri(other_node))
self.assertEqual(httplib.FORBIDDEN, response.status_code)
def test_GET_refuses_to_access_nonexistent_node(self):
# When fetching a Node, the api returns a 'Not Found' (404) error
# if no node is found.
- response = self.client.get('/api/nodes/invalid-uuid/')
+ response = self.client.get(self.get_uri('nodes/invalid-uuid/'))
self.assertEqual(httplib.NOT_FOUND, response.status_code)
def test_POST_stop_checks_permission(self):
node = factory.make_node()
- response = self.client.post(self.get_uri(node), {'op': 'stop'})
+ response = self.client.post(self.get_node_uri(node), {'op': 'stop'})
self.assertEqual(httplib.FORBIDDEN, response.status_code)
def test_POST_stop_returns_node(self):
node = factory.make_node(owner=self.logged_in_user)
- response = self.client.post(self.get_uri(node), {'op': 'stop'})
+ response = self.client.post(self.get_node_uri(node), {'op': 'stop'})
self.assertEqual(httplib.OK, response.status_code)
self.assertEqual(
node.system_id, json.loads(response.content)['system_id'])
def test_POST_stop_may_be_repeated(self):
node = factory.make_node(owner=self.logged_in_user)
- self.client.post(self.get_uri(node), {'op': 'stop'})
- response = self.client.post(self.get_uri(node), {'op': 'stop'})
+ self.client.post(self.get_node_uri(node), {'op': 'stop'})
+ response = self.client.post(self.get_node_uri(node), {'op': 'stop'})
self.assertEqual(httplib.OK, response.status_code)
def test_POST_start_checks_permission(self):
node = factory.make_node()
- response = self.client.post(self.get_uri(node), {'op': 'start'})
+ response = self.client.post(self.get_node_uri(node), {'op': 'start'})
self.assertEqual(httplib.FORBIDDEN, response.status_code)
def test_POST_start_returns_node(self):
node = factory.make_node(owner=self.logged_in_user)
- response = self.client.post(self.get_uri(node), {'op': 'start'})
+ response = self.client.post(self.get_node_uri(node), {'op': 'start'})
self.assertEqual(httplib.OK, response.status_code)
self.assertEqual(
node.system_id, json.loads(response.content)['system_id'])
def test_POST_start_may_be_repeated(self):
node = factory.make_node(owner=self.logged_in_user)
- self.client.post(self.get_uri(node), {'op': 'start'})
- response = self.client.post(self.get_uri(node), {'op': 'start'})
+ self.client.post(self.get_node_uri(node), {'op': 'start'})
+ response = self.client.post(self.get_node_uri(node), {'op': 'start'})
self.assertEqual(httplib.OK, response.status_code)
def test_PUT_updates_node(self):
# The api allows to update a Node.
node = factory.make_node(hostname='diane')
response = self.client.put(
- self.get_uri(node), {'hostname': 'francis'})
+ self.get_node_uri(node), {'hostname': 'francis'})
parsed_result = json.loads(response.content)
self.assertEqual(httplib.OK, response.status_code)
@@ -277,11 +288,12 @@
# When a Node is returned by the API, the field 'resource_uri'
# provides the URI for this Node.
node = factory.make_node(hostname='diane')
- response = self.client.put(self.get_uri(node), {'hostname': 'francis'})
+ response = self.client.put(
+ self.get_node_uri(node), {'hostname': 'francis'})
parsed_result = json.loads(response.content)
self.assertEqual(
- '/api/nodes/%s/' % (parsed_result['system_id']),
+ self.get_uri('nodes/%s/') % (parsed_result['system_id']),
parsed_result['resource_uri'])
def test_PUT_rejects_invalid_data(self):
@@ -289,7 +301,7 @@
# response is returned.
node = factory.make_node(hostname='diane')
response = self.client.put(
- self.get_uri(node), {'hostname': 'too long' * 100})
+ self.get_node_uri(node), {'hostname': 'too long' * 100})
parsed_result = json.loads(response.content)
self.assertEqual(httplib.BAD_REQUEST, response.status_code)
@@ -305,14 +317,14 @@
other_node = factory.make_node(
status=NODE_STATUS.ALLOCATED, owner=factory.make_user())
- response = self.client.put(self.get_uri(other_node))
+ response = self.client.put(self.get_node_uri(other_node))
self.assertEqual(httplib.FORBIDDEN, response.status_code)
def test_PUT_refuses_to_update_nonexistent_node(self):
# When updating a Node, the api returns a 'Not Found' (404) error
# if no node is found.
- response = self.client.put('/api/nodes/no-node-here/')
+ response = self.client.put(self.get_uri('nodes/no-node-here/'))
self.assertEqual(httplib.NOT_FOUND, response.status_code)
@@ -320,7 +332,7 @@
# The api allows to delete a Node.
node = factory.make_node(set_hostname=True)
system_id = node.system_id
- response = self.client.delete(self.get_uri(node))
+ response = self.client.delete(self.get_node_uri(node))
self.assertEqual(204, response.status_code)
self.assertItemsEqual([], Node.objects.filter(system_id=system_id))
@@ -331,25 +343,25 @@
other_node = factory.make_node(
status=NODE_STATUS.ALLOCATED, owner=factory.make_user())
- response = self.client.delete(self.get_uri(other_node))
+ response = self.client.delete(self.get_node_uri(other_node))
self.assertEqual(httplib.FORBIDDEN, response.status_code)
def test_DELETE_refuses_to_delete_nonexistent_node(self):
# When deleting a Node, the api returns a 'Not Found' (404) error
# if no node is found.
- response = self.client.delete('/api/nodes/no-node-here/')
+ response = self.client.delete(self.get_uri('nodes/no-node-here/'))
self.assertEqual(httplib.NOT_FOUND, response.status_code)
class TestNodesAPI(APITestCase):
- """Tests for /api/nodes/."""
+ """Tests for /api/1.0/nodes/."""
def test_POST_new_creates_node(self):
# The API allows a Node to be created, even as a logged-in user.
response = self.client.post(
- '/api/nodes/',
+ self.get_uri('nodes/'),
{
'op': 'new',
'hostname': 'diane',
@@ -365,7 +377,7 @@
node2 = factory.make_node(
set_hostname=True, status=NODE_STATUS.ALLOCATED,
owner=self.logged_in_user)
- response = self.client.get('/api/nodes/', {'op': 'list'})
+ response = self.client.get(self.get_uri('nodes/'), {'op': 'list'})
parsed_result = json.loads(response.content)
self.assertEqual(httplib.OK, response.status_code)
@@ -376,13 +388,13 @@
def test_GET_list_without_nodes_returns_empty_list(self):
# If there are no nodes to list, the "list" op still works but
# returns an empty list.
- response = self.client.get('/api/nodes/', {'op': 'list'})
+ response = self.client.get(self.get_uri('nodes/'), {'op': 'list'})
self.assertItemsEqual([], json.loads(response.content))
def test_GET_list_orders_by_id(self):
# Nodes are returned in id order.
nodes = [factory.make_node() for counter in range(3)]
- response = self.client.get('/api/nodes/', {'op': 'list'})
+ response = self.client.get(self.get_uri('nodes/'), {'op': 'list'})
parsed_result = json.loads(response.content)
self.assertSequenceEqual(
[node.system_id for node in nodes],
@@ -393,7 +405,7 @@
# nodes with matching ids will be returned.
ids = [factory.make_node().system_id for counter in range(3)]
matching_id = ids[0]
- response = self.client.get('/api/nodes/', {
+ response = self.client.get(self.get_uri('nodes/'), {
'op': 'list',
'id': [matching_id],
})
@@ -406,7 +418,7 @@
# no nodes -- even if other (non-matching) nodes exist.
existing_id = factory.make_node().system_id
nonexistent_id = existing_id + factory.getRandomString()
- response = self.client.get('/api/nodes/', {
+ response = self.client.get(self.get_uri('nodes/'), {
'op': 'list',
'id': [nonexistent_id],
})
@@ -416,7 +428,7 @@
# Even when ids are passed to "list," nodes are returned in id
# order, not necessarily in the order of the id arguments.
ids = [factory.make_node().system_id for counter in range(3)]
- response = self.client.get('/api/nodes/', {
+ response = self.client.get(self.get_uri('nodes/'), {
'op': 'list',
'id': list(reversed(ids)),
})
@@ -428,7 +440,7 @@
# matching ones are returned.
existing_id = factory.make_node().system_id
nonexistent_id = existing_id + factory.getRandomString()
- response = self.client.get('/api/nodes/', {
+ response = self.client.get(self.get_uri('nodes/'), {
'op': 'list',
'id': [existing_id, nonexistent_id],
})
@@ -440,7 +452,7 @@
# The "acquire" operation returns an available node.
available_status = NODE_STATUS.READY
node = factory.make_node(status=available_status, owner=None)
- response = self.client.post('/api/nodes/', {'op': 'acquire'})
+ response = self.client.post(self.get_uri('nodes/'), {'op': 'acquire'})
self.assertEqual(200, response.status_code)
parsed_result = json.loads(response.content)
self.assertEqual(node.system_id, parsed_result['system_id'])
@@ -449,14 +461,14 @@
# The "acquire" operation allocates the node it returns.
available_status = NODE_STATUS.READY
node = factory.make_node(status=available_status, owner=None)
- self.client.post('/api/nodes/', {'op': 'acquire'})
+ self.client.post(self.get_uri('nodes/'), {'op': 'acquire'})
node = Node.objects.get(system_id=node.system_id)
self.assertEqual(self.logged_in_user, node.owner)
def test_POST_acquire_fails_if_no_node_present(self):
# The "acquire" operation returns a Conflict error if no nodes
# are available.
- response = self.client.post('/api/nodes/', {'op': 'acquire'})
+ response = self.client.post(self.get_uri('nodes/'), {'op': 'acquire'})
# Fails with Conflict error: resource can't satisfy request.
self.assertEqual(httplib.CONFLICT, response.status_code)
@@ -471,7 +483,8 @@
def test_macs_GET(self):
# The api allows for fetching the list of the MAC Addresss for a node.
- response = self.client.get('/api/nodes/%s/macs/' % self.node.system_id)
+ response = self.client.get(
+ self.get_uri('nodes/%s/macs/') % self.node.system_id)
parsed_result = json.loads(response.content)
self.assertEqual(httplib.OK, response.status_code)
@@ -487,14 +500,14 @@
other_node = factory.make_node(
status=NODE_STATUS.ALLOCATED, owner=factory.make_user())
response = self.client.get(
- '/api/nodes/%s/macs/' % other_node.system_id)
+ self.get_uri('nodes/%s/macs/') % other_node.system_id)
self.assertEqual(httplib.FORBIDDEN, response.status_code)
def test_macs_GET_not_found(self):
# When fetching MAC Addresses, the api returns a 'Not Found' (404)
# error if no node is found.
- response = self.client.get('/api/nodes/invalid-id/macs/')
+ response = self.client.get(self.get_uri('nodes/invalid-id/macs/'))
self.assertEqual(httplib.NOT_FOUND, response.status_code)
@@ -502,7 +515,8 @@
# When fetching a MAC Address, the api returns a 'Not Found' (404)
# error if the MAC Address does not exist.
response = self.client.get(
- '/api/nodes/%s/macs/00-aa-22-cc-44-dd/' % self.node.system_id)
+ self.get_uri(
+ 'nodes/%s/macs/00-aa-22-cc-44-dd/') % self.node.system_id)
self.assertEqual(httplib.NOT_FOUND, response.status_code)
@@ -512,7 +526,8 @@
other_node = factory.make_node(
status=NODE_STATUS.ALLOCATED, owner=factory.make_user())
response = self.client.get(
- '/api/nodes/%s/macs/0-aa-22-cc-44-dd/' % other_node.system_id)
+ self.get_uri(
+ 'nodes/%s/macs/0-aa-22-cc-44-dd/') % other_node.system_id)
self.assertEqual(httplib.FORBIDDEN, response.status_code)
@@ -520,7 +535,7 @@
# When fetching a MAC Address, the api returns a 'Bad Request' (400)
# error if the MAC Address is not valid.
response = self.client.get(
- '/api/nodes/%s/macs/invalid-mac/' % self.node.system_id)
+ self.get_uri('nodes/%s/macs/invalid-mac/') % self.node.system_id)
self.assertEqual(400, response.status_code)
@@ -528,7 +543,7 @@
# The api allows to add a MAC Address to an existing node.
nb_macs = MACAddress.objects.filter(node=self.node).count()
response = self.client.post(
- '/api/nodes/%s/macs/' % self.node.system_id,
+ self.get_uri('nodes/%s/macs/') % self.node.system_id,
{'mac_address': 'AA:BB:CC:DD:EE:FF'})
parsed_result = json.loads(response.content)
@@ -542,7 +557,7 @@
# A 'Bad Request' response is returned if one tries to add an invalid
# MAC Address to a node.
response = self.client.post(
- '/api/nodes/%s/macs/' % self.node.system_id,
+ self.get_uri('nodes/%s/macs/') % self.node.system_id,
{'mac_address': 'invalid-mac'})
parsed_result = json.loads(response.content)
@@ -556,7 +571,7 @@
# The api allows to delete a MAC Address.
nb_macs = self.node.macaddress_set.count()
response = self.client.delete(
- '/api/nodes/%s/macs/%s/' % (
+ self.get_uri('nodes/%s/macs/%s/') % (
self.node.system_id, self.mac1.mac_address))
self.assertEqual(204, response.status_code)
@@ -570,7 +585,7 @@
other_node = factory.make_node(
status=NODE_STATUS.ALLOCATED, owner=factory.make_user())
response = self.client.delete(
- '/api/nodes/%s/macs/%s/' % (
+ self.get_uri('nodes/%s/macs/%s/') % (
other_node.system_id, self.mac1.mac_address))
self.assertEqual(httplib.FORBIDDEN, response.status_code)
@@ -579,7 +594,7 @@
# When deleting a MAC Address, the api returns a 'Not Found' (404)
# error if no existing MAC Address is found.
response = self.client.delete(
- '/api/nodes/%s/macs/%s/' % (
+ self.get_uri('nodes/%s/macs/%s/') % (
self.node.system_id, '00-aa-22-cc-44-dd'))
self.assertEqual(httplib.NOT_FOUND, response.status_code)
@@ -588,7 +603,7 @@
# When deleting a MAC Address, the api returns a 'Bad Request' (400)
# error if the provided MAC Address is not valid.
response = self.client.delete(
- '/api/nodes/%s/macs/%s/' % (
+ self.get_uri('nodes/%s/macs/%s/') % (
self.node.system_id, 'invalid-mac'))
self.assertEqual(httplib.BAD_REQUEST, response.status_code)
@@ -600,7 +615,7 @@
# The api operation create_authorisation_token returns a json dict
# with the consumer_key, the token_key and the token_secret in it.
response = self.client.post(
- '/api/account/', {'op': 'create_authorisation_token'})
+ self.get_uri('account/'), {'op': 'create_authorisation_token'})
parsed_result = json.loads(response.content)
self.assertEqual(
@@ -614,7 +629,7 @@
# If the provided token_key does not exist (for the currently
# logged-in user), the api returns a 'Not Found' (404) error.
response = self.client.post(
- '/api/account/',
+ self.get_uri('account/'),
{'op': 'delete_authorisation_token', 'token_key': 'no-such-token'})
self.assertEqual(httplib.NOT_FOUND, response.status_code)
@@ -624,7 +639,7 @@
# delete_authorisation_token. It it is not present in the request's
# parameters, the api returns a 'Bad Request' (400) error.
response = self.client.post(
- '/api/account/', {'op': 'delete_authorisation_token'})
+ self.get_uri('account/'), {'op': 'delete_authorisation_token'})
self.assertEqual(httplib.BAD_REQUEST, response.status_code)
@@ -661,12 +676,12 @@
def make_API_POST_request(self, op=None, filename=None, fileObj=None):
"""Make an API POST request and return the response."""
params = self._create_API_params(op, filename, fileObj)
- return self.client.post("/api/files/", params)
+ return self.client.post(self.get_uri('files/'), params)
def make_API_GET_request(self, op=None, filename=None, fileObj=None):
"""Make an API GET request and return the response."""
params = self._create_API_params(op, filename, fileObj)
- return self.client.get("/api/files/", params)
+ return self.client.get(self.get_uri('files/'), params)
def test_add_file_succeeds(self):
filepath = self.make_file()
@@ -699,7 +714,7 @@
with open(filepath) as f, open(filepath2) as f2:
response = self.client.post(
- "/api/files/",
+ self.get_uri('files/'),
{
"op": "add",
"filename": "foo",
=== modified file 'src/maasserver/tests/test_middleware.py'
--- src/maasserver/tests/test_middleware.py 2012-02-24 17:37:01 +0000
+++ src/maasserver/tests/test_middleware.py 2012-02-27 07:50:23 +0000
@@ -116,7 +116,7 @@
def test_handles_error_on_API(self):
middleware = APIErrorsMiddleware()
- non_api_request = fake_request("/api/hello")
+ non_api_request = fake_request("/api/1.0/hello")
exception = MaaSAPINotFound("Have you looked under the couch?")
response = middleware.process_exception(non_api_request, exception)
self.assertEqual(
=== modified file 'src/maasserver/urls.py'
--- src/maasserver/urls.py 2012-02-23 09:25:48 +0000
+++ src/maasserver/urls.py 2012-02-27 07:50:23 +0000
@@ -12,6 +12,7 @@
__all__ = []
from django.conf.urls.defaults import (
+ include,
patterns,
url,
)
@@ -21,17 +22,6 @@
direct_to_template,
redirect_to,
)
-from maas.api_auth import api_auth
-from maasserver.api import (
- AccountHandler,
- api_doc,
- FilesHandler,
- NodeHandler,
- NodeMacHandler,
- NodeMacsHandler,
- NodesHandler,
- RestrictedResource,
- )
from maasserver.models import Node
from maasserver.views import (
AccountsAdd,
@@ -92,35 +82,7 @@
)
-# API.
-account_handler = RestrictedResource(AccountHandler, authentication=api_auth)
-files_handler = RestrictedResource(FilesHandler, authentication=api_auth)
-node_handler = RestrictedResource(NodeHandler, authentication=api_auth)
-nodes_handler = RestrictedResource(NodesHandler, authentication=api_auth)
-node_mac_handler = RestrictedResource(NodeMacHandler, authentication=api_auth)
-node_macs_handler = RestrictedResource(
- NodeMacsHandler, authentication=api_auth)
-
-
-# API URLs accessible to anonymous users.
-urlpatterns += patterns('',
- url(r'^api/doc/$', api_doc, name='api-doc'),
-)
-
-
-# API URLs for logged-in users.
-urlpatterns += patterns('',
- url(
- r'^api/nodes/(?P<system_id>[\w\-]+)/macs/(?P<mac_address>.+)/$',
- node_mac_handler, name='node_mac_handler'),
- url(
- r'^api/nodes/(?P<system_id>[\w\-]+)/macs/$', node_macs_handler,
- name='node_macs_handler'),
-
- url(
- r'^api/nodes/(?P<system_id>[\w\-]+)/$', node_handler,
- name='node_handler'),
- url(r'^api/nodes/$', nodes_handler, name='nodes_handler'),
- url(r'^api/files/$', files_handler, name='files_handler'),
- url(r'^api/account/$', account_handler, name='account_handler'),
-)
+# API URLs.
+urlpatterns += patterns('',
+ (r'^api/1\.0/', include('maasserver.urls_api'))
+ )
=== added file 'src/maasserver/urls_api.py'
--- src/maasserver/urls_api.py 1970-01-01 00:00:00 +0000
+++ src/maasserver/urls_api.py 2012-02-27 07:50:23 +0000
@@ -0,0 +1,59 @@
+# Copyright 2012 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""URL API routing configuration."""
+
+from __future__ import (
+ print_function,
+ unicode_literals,
+ )
+
+__metaclass__ = type
+__all__ = []
+
+from django.conf.urls.defaults import (
+ patterns,
+ url,
+ )
+from maas.api_auth import api_auth
+from maasserver.api import (
+ AccountHandler,
+ api_doc,
+ FilesHandler,
+ NodeHandler,
+ NodeMacHandler,
+ NodeMacsHandler,
+ NodesHandler,
+ RestrictedResource,
+ )
+account_handler = RestrictedResource(AccountHandler, authentication=api_auth)
+files_handler = RestrictedResource(FilesHandler, authentication=api_auth)
+node_handler = RestrictedResource(NodeHandler, authentication=api_auth)
+nodes_handler = RestrictedResource(NodesHandler, authentication=api_auth)
+node_mac_handler = RestrictedResource(NodeMacHandler, authentication=api_auth)
+node_macs_handler = RestrictedResource(
+ NodeMacsHandler, authentication=api_auth)
+
+
+# API URLs accessible to anonymous users.
+urlpatterns = patterns('',
+ url(r'doc/$', api_doc, name='api-doc'),
+)
+
+
+# API URLs for logged-in users.
+urlpatterns += patterns('',
+ url(
+ r'nodes/(?P<system_id>[\w\-]+)/macs/(?P<mac_address>.+)/$',
+ node_mac_handler, name='node_mac_handler'),
+ url(
+ r'nodes/(?P<system_id>[\w\-]+)/macs/$', node_macs_handler,
+ name='node_macs_handler'),
+
+ url(
+ r'nodes/(?P<system_id>[\w\-]+)/$', node_handler,
+ name='node_handler'),
+ url(r'nodes/$', nodes_handler, name='nodes_handler'),
+ url(r'files/$', files_handler, name='files_handler'),
+ url(r'account/$', account_handler, name='account_handler'),
+)