Promote v1.0 to current
* Mark v0.1 as deprecated * Add v1.0 to version list * Use subclasses for wsgi Routers * Add melange-manage route command to print routes * Fixes certain routes not being exposed in the v1.0 api (LP947327) Change-Id: Iac8294f2534decbbddf53230386fdbe8c622ff84
This commit is contained in:
parent
b69e9db4c1
commit
01cb899ef7
@ -39,6 +39,7 @@ from melange import version
|
|||||||
from melange.common import config
|
from melange.common import config
|
||||||
from melange.common import utils
|
from melange.common import utils
|
||||||
from melange.db import db_api
|
from melange.db import db_api
|
||||||
|
from melange.ipam import service
|
||||||
|
|
||||||
|
|
||||||
def create_options(parser):
|
def create_options(parser):
|
||||||
@ -69,11 +70,23 @@ class Commands(object):
|
|||||||
def db_downgrade(self, version, repo_path=None):
|
def db_downgrade(self, version, repo_path=None):
|
||||||
db_api.db_downgrade(self.conf, version, repo_path=repo_path)
|
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):
|
def execute(self, command_name, *args):
|
||||||
if self.has(command_name):
|
if self.has(command_name):
|
||||||
return getattr(self, command_name)(*args)
|
return getattr(self, command_name)(*args)
|
||||||
|
|
||||||
_commands = ['db_sync', 'db_upgrade', 'db_downgrade']
|
_commands = ['db_sync', 'db_upgrade', 'db_downgrade', 'routes']
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def has(cls, command_name):
|
def has(cls, command_name):
|
||||||
|
@ -568,106 +568,11 @@ class InterfaceAllowedIpsController(BaseController):
|
|||||||
interface.disallow_ip(ip)
|
interface.disallow_ip(ip)
|
||||||
|
|
||||||
|
|
||||||
class APIV01(wsgi.Router):
|
class APICommon(wsgi.Router):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
mapper = routes.Mapper()
|
mapper = routes.Mapper()
|
||||||
super(APIV01, self).__init__(mapper)
|
super(APICommon, 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):
|
|
||||||
self._natting_mapper(mapper,
|
self._natting_mapper(mapper,
|
||||||
"inside_globals",
|
"inside_globals",
|
||||||
InsideGlobalsController().create_resource())
|
InsideGlobalsController().create_resource())
|
||||||
@ -816,5 +721,97 @@ class APICommon():
|
|||||||
conditions=dict(method=["DELETE"]))
|
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):
|
def _connect(mapper, path, *args, **kwargs):
|
||||||
return mapper.connect(path + "{.format:(json|xml)?}", *args, **kwargs)
|
return mapper.connect(path + "{.format:(json|xml)?}", *args, **kwargs)
|
||||||
|
@ -31,12 +31,18 @@ class TestVersionsController(tests.BaseTest):
|
|||||||
|
|
||||||
def test_versions_index(self):
|
def test_versions_index(self):
|
||||||
response = self.test_app.get("/")
|
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':
|
self.assertEqual(response.json, {'versions':
|
||||||
[{
|
[{
|
||||||
'status':'CURRENT',
|
'status':'DEPRECATED',
|
||||||
'name': 'v0.1',
|
'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.xml.tag, 'versions')
|
||||||
self.assertEqual(response.body,
|
self.assertEqual(response.body,
|
||||||
"""<versions>
|
"""<versions>
|
||||||
<version name="v0.1" status="CURRENT">
|
<version name="v0.1" status="DEPRECATED">
|
||||||
<links>
|
<links>
|
||||||
<link href="http://localhost/v0.1" rel="self"/>
|
<link href="http://localhost/v0.1" rel="self"/>
|
||||||
</links>
|
</links>
|
||||||
</version>
|
</version>
|
||||||
|
<version name="v1.0" status="CURRENT">
|
||||||
|
<links>
|
||||||
|
<link href="http://localhost/v1.0" rel="self"/>
|
||||||
|
</links>
|
||||||
|
</version>
|
||||||
</versions>
|
</versions>
|
||||||
""")
|
""")
|
||||||
|
@ -26,7 +26,8 @@ class VersionsController(wsgi.Controller):
|
|||||||
|
|
||||||
def index(self, request):
|
def index(self, request):
|
||||||
"""Respond to a request for all OpenStack API versions."""
|
"""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))
|
return wsgi.Result(VersionsDataView(versions))
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user