diff --git a/bin/melange-manage b/bin/melange-manage index aae887c7..751cbcfa 100755 --- a/bin/melange-manage +++ b/bin/melange-manage @@ -39,6 +39,7 @@ from melange import version from melange.common import config from melange.common import utils from melange.db import db_api +from melange.ipam import service def create_options(parser): @@ -69,11 +70,23 @@ class Commands(object): def db_downgrade(self, version, repo_path=None): db_api.db_downgrade(self.conf, version, repo_path=repo_path) + def routes(self, version): + version = version.split('=')[-1].upper().replace('.', '') + if not version.startswith('V'): + version = 'V' + version + + api = getattr(service, 'API' + version, None) + if not api: + print _('Could not import Router %s') % api + + for route in api().map.matchlist: + print route.routepath, route.conditions['method'] + def execute(self, command_name, *args): if self.has(command_name): return getattr(self, command_name)(*args) - _commands = ['db_sync', 'db_upgrade', 'db_downgrade'] + _commands = ['db_sync', 'db_upgrade', 'db_downgrade', 'routes'] @classmethod def has(cls, command_name): diff --git a/melange/ipam/service.py b/melange/ipam/service.py index d8edd42b..7ca55343 100644 --- a/melange/ipam/service.py +++ b/melange/ipam/service.py @@ -568,106 +568,11 @@ class InterfaceAllowedIpsController(BaseController): interface.disallow_ip(ip) -class APIV01(wsgi.Router): +class APICommon(wsgi.Router): def __init__(self): mapper = routes.Mapper() - super(APIV01, self).__init__(mapper) - self._networks_maper(mapper) - self._interface_ip_allocations_mapper(mapper) - self._interface_mapper(mapper) - self._allowed_ips_mapper(mapper) - APICommon(mapper) - - def _networks_maper(self, mapper): - resource = NetworksController().create_resource() - path = "/ipam/tenants/{tenant_id}/networks/{network_id}" - mapper.resource("networks", path, controller=resource) - - def _interface_ip_allocations_mapper(self, mapper): - path = ("/ipam/tenants/{tenant_id}/networks" - "/{network_id}/interfaces/{interface_id}") - resource = InterfaceIpAllocationsController().create_resource() - with mapper.submapper(controller=resource, path_prefix=path) as submap: - _connect(submap, "/ip_allocations", action='create', - conditions=dict(method=['POST'])) - _connect(submap, - "/ip_allocations", - action='index', - conditions=dict(method=['GET'])) - _connect(submap, "/ip_allocations", action='bulk_delete', - conditions=dict(method=['DELETE'])) - - def _interface_mapper(self, mapper): - interface_res = InterfacesController().create_resource() - path = "/ipam/interfaces" - _connect(mapper, - "/ipam/tenants/{tenant_id}/" - "interfaces/{virtual_interface_id}", - controller=interface_res, - action="show", - conditions=dict(method=['GET'])) - _connect(mapper, - "/ipam/interfaces/{virtual_interface_id}", - controller=interface_res, - action="delete", - conditions=dict(method=['DELETE'])) - mapper.resource("interfaces", path, controller=interface_res) - - def _allowed_ips_mapper(self, mapper): - interface_allowed_ips = InterfaceAllowedIpsController() - mapper.connect("/ipam/tenants/{tenant_id}/" - "interfaces/{interface_id}/allowed_ips/{address:.+?}", - action="delete", - controller=interface_allowed_ips.create_resource(), - conditions=dict(method=["DELETE"])) - mapper.connect("/ipam/tenants/{tenant_id}/" - "interfaces/{interface_id}/allowed_ips/{address:.+?}", - action="show", - controller=interface_allowed_ips.create_resource(), - conditions=dict(method=["GET"])) - mapper.resource("allowed_ips", - "/allowed_ips", - controller=interface_allowed_ips.create_resource(), - path_prefix=("/ipam/tenants/{tenant_id}/" - "interfaces/{interface_id}")) - - @classmethod - def app_factory(cls, global_conf, **local_conf): - return APIV01() - - -class APIV10(wsgi.Router): - - def __init__(self): - mapper = routes.Mapper() - super(APIV10, self).__init__(mapper) - APICommon(mapper) - self._instance_interface_ips_mapper(mapper) - - def _instance_interface_ips_mapper(self, mapper): - res = InstanceInterfaceIpsController().create_resource() - path_prefix = ("/ipam/instances/{device_id}/" - "interfaces/{interface_id}") - with mapper.submapper(controller=res, - path_prefix=path_prefix) as submap: - _connect(submap, - "/ip_addresses/{address:.+?}", - action="delete", - conditions=dict(method=["DELETE"])) - mapper.resource("ip_addresses", - "/ip_addresses", - controller=res, - path_prefix=path_prefix) - - @classmethod - def app_factory(cls, global_conf, **local_conf): - return APIV10() - - -class APICommon(): - - def __init__(self, mapper): + super(APICommon, self).__init__(mapper) self._natting_mapper(mapper, "inside_globals", InsideGlobalsController().create_resource()) @@ -816,5 +721,97 @@ class APICommon(): conditions=dict(method=["DELETE"])) +class APIV01(APICommon): + def __init__(self): + super(APIV01, self).__init__() + self._networks_maper(self.map) + self._interface_ip_allocations_mapper(self.map) + self._interface_mapper(self.map) + self._allowed_ips_mapper(self.map) + + def _networks_maper(self, mapper): + resource = NetworksController().create_resource() + path = "/ipam/tenants/{tenant_id}/networks/{network_id}" + mapper.resource("networks", path, controller=resource) + + def _interface_ip_allocations_mapper(self, mapper): + path = ("/ipam/tenants/{tenant_id}/networks" + "/{network_id}/interfaces/{interface_id}") + resource = InterfaceIpAllocationsController().create_resource() + with mapper.submapper(controller=resource, path_prefix=path) as submap: + _connect(submap, "/ip_allocations", action='create', + conditions=dict(method=['POST'])) + _connect(submap, + "/ip_allocations", + action='index', + conditions=dict(method=['GET'])) + _connect(submap, "/ip_allocations", action='bulk_delete', + conditions=dict(method=['DELETE'])) + + def _interface_mapper(self, mapper): + interface_res = InterfacesController().create_resource() + path = "/ipam/interfaces" + _connect(mapper, + "/ipam/tenants/{tenant_id}/" + "interfaces/{virtual_interface_id}", + controller=interface_res, + action="show", + conditions=dict(method=['GET'])) + _connect(mapper, + "/ipam/interfaces/{virtual_interface_id}", + controller=interface_res, + action="delete", + conditions=dict(method=['DELETE'])) + mapper.resource("interfaces", path, controller=interface_res) + + def _allowed_ips_mapper(self, mapper): + interface_allowed_ips = InterfaceAllowedIpsController() + mapper.connect("/ipam/tenants/{tenant_id}/" + "interfaces/{interface_id}/allowed_ips/{address:.+?}", + action="delete", + controller=interface_allowed_ips.create_resource(), + conditions=dict(method=["DELETE"])) + mapper.connect("/ipam/tenants/{tenant_id}/" + "interfaces/{interface_id}/allowed_ips/{address:.+?}", + action="show", + controller=interface_allowed_ips.create_resource(), + conditions=dict(method=["GET"])) + mapper.resource("allowed_ips", + "/allowed_ips", + controller=interface_allowed_ips.create_resource(), + path_prefix=("/ipam/tenants/{tenant_id}/" + "interfaces/{interface_id}")) + + @classmethod + def app_factory(cls, global_conf, **local_conf): + return APIV01() + + +class APIV10(APICommon): + + def __init__(self): + super(APIV10, self).__init__() + self._instance_interface_ips_mapper(self.map) + + def _instance_interface_ips_mapper(self, mapper): + res = InstanceInterfaceIpsController().create_resource() + path_prefix = ("/ipam/instances/{device_id}/" + "interfaces/{interface_id}") + with mapper.submapper(controller=res, + path_prefix=path_prefix) as submap: + _connect(submap, + "/ip_addresses/{address:.+?}", + action="delete", + conditions=dict(method=["DELETE"])) + mapper.resource("ip_addresses", + "/ip_addresses", + controller=res, + path_prefix=path_prefix) + + @classmethod + def app_factory(cls, global_conf, **local_conf): + return APIV10() + + def _connect(mapper, path, *args, **kwargs): return mapper.connect(path + "{.format:(json|xml)?}", *args, **kwargs) diff --git a/melange/tests/unit/test_versions.py b/melange/tests/unit/test_versions.py index ed068ac5..35eeac54 100644 --- a/melange/tests/unit/test_versions.py +++ b/melange/tests/unit/test_versions.py @@ -31,12 +31,18 @@ class TestVersionsController(tests.BaseTest): def test_versions_index(self): response = self.test_app.get("/") - link = [{'href': "http://localhost/v0.1", 'rel': 'self'}] + v01link = [{'href': "http://localhost/v0.1", 'rel': 'self'}] + v10link = [{'href': "http://localhost/v1.0", 'rel': 'self'}] self.assertEqual(response.json, {'versions': [{ - 'status':'CURRENT', + 'status':'DEPRECATED', 'name': 'v0.1', - 'links': link, + 'links': v01link, + }, + { + 'status':'CURRENT', + 'name': 'v1.0', + 'links': v10link, }] }) @@ -48,10 +54,15 @@ class TestVersionsController(tests.BaseTest): self.assertEqual(response.xml.tag, 'versions') self.assertEqual(response.body, """ - + + + + + + """) diff --git a/melange/versions.py b/melange/versions.py index f79d3f18..835a03a9 100644 --- a/melange/versions.py +++ b/melange/versions.py @@ -26,7 +26,8 @@ class VersionsController(wsgi.Controller): def index(self, request): """Respond to a request for all OpenStack API versions.""" - versions = [Version("v0.1", "CURRENT", request.application_url)] + versions = [Version("v0.1", "DEPRECATED", request.application_url), + Version("v1.0", "CURRENT", request.application_url)] return wsgi.Result(VersionsDataView(versions))