__init__.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. # Copyright (c) 2013 OpenStack Foundation
  2. #
  3. # All Rights Reserved.
  4. #
  5. # Licensed under the Apache License, Version 2.0 (the "License"); you may
  6. # not use this file except in compliance with the License. You may obtain
  7. # a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  13. # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  14. # License for the specific language governing permissions and limitations
  15. # under the License.
  16. """
  17. WSGI middleware for OpenStack API controllers.
  18. """
  19. from oslo_log import log as logging
  20. from oslo_service import wsgi as base_wsgi
  21. from paste import urlmap
  22. import routes
  23. from coriolis.api import wsgi
  24. from coriolis.i18n import _, _LW
  25. LOG = logging.getLogger(__name__)
  26. def root_app_factory(loader, global_conf, **local_conf):
  27. return urlmap.urlmap_factory(loader, global_conf, **local_conf)
  28. class APIMapper(routes.Mapper):
  29. def routematch(self, url=None, environ=None):
  30. if url is "":
  31. result = self._match("", environ)
  32. return result[0], result[1]
  33. return routes.Mapper.routematch(self, url, environ)
  34. def connect(self, *args, **kwargs):
  35. # NOTE(inhye): Default the format part of a route to only accept json
  36. # and xml so it doesn't eat all characters after a '.'
  37. # in the url.
  38. kwargs.setdefault('requirements', {})
  39. if not kwargs['requirements'].get('format'):
  40. kwargs['requirements']['format'] = 'json|xml'
  41. return routes.Mapper.connect(self, *args, **kwargs)
  42. class ProjectMapper(APIMapper):
  43. def resource(self, member_name, collection_name, **kwargs):
  44. if 'parent_resource' not in kwargs:
  45. kwargs['path_prefix'] = '{project_id}/'
  46. else:
  47. parent_resource = kwargs['parent_resource']
  48. p_collection = parent_resource['collection_name']
  49. p_member = parent_resource['member_name']
  50. kwargs['path_prefix'] = '{project_id}/%s/:%s_id' % (p_collection,
  51. p_member)
  52. routes.Mapper.resource(self,
  53. member_name,
  54. collection_name,
  55. **kwargs)
  56. class APIRouter(base_wsgi.Router):
  57. """Routes requests on the API to the appropriate controller and method."""
  58. ExtensionManager = None # override in subclasses
  59. @classmethod
  60. def factory(cls, global_config, **local_config):
  61. return cls()
  62. def __init__(self, ext_mgr=None):
  63. if ext_mgr is None:
  64. if self.ExtensionManager:
  65. ext_mgr = self.ExtensionManager()
  66. else:
  67. raise Exception(_("Must specify an ExtensionManager class"))
  68. mapper = ProjectMapper()
  69. self.resources = {}
  70. self._setup_routes(mapper, ext_mgr)
  71. self._setup_ext_routes(mapper, ext_mgr)
  72. self._setup_extensions(ext_mgr)
  73. super(APIRouter, self).__init__(mapper)
  74. def _setup_ext_routes(self, mapper, ext_mgr):
  75. for resource in ext_mgr.get_resources():
  76. LOG.debug('Extended resource: %s',
  77. resource.collection)
  78. wsgi_resource = wsgi.Resource(resource.controller)
  79. self.resources[resource.collection] = wsgi_resource
  80. kargs = dict(
  81. controller=wsgi_resource,
  82. collection=resource.collection_actions,
  83. member=resource.member_actions)
  84. if resource.parent:
  85. kargs['parent_resource'] = resource.parent
  86. mapper.resource(resource.collection, resource.collection, **kargs)
  87. if resource.custom_routes_fn:
  88. resource.custom_routes_fn(mapper, wsgi_resource)
  89. def _setup_extensions(self, ext_mgr):
  90. for extension in ext_mgr.get_controller_extensions():
  91. collection = extension.collection
  92. controller = extension.controller
  93. if collection not in self.resources:
  94. LOG.warning(_LW('Extension %(ext_name)s: Cannot extend '
  95. 'resource %(collection)s: No such resource'),
  96. {'ext_name': extension.extension.name,
  97. 'collection': collection})
  98. continue
  99. LOG.debug('Extension %(ext_name)s extending resource: '
  100. '%(collection)s',
  101. {'ext_name': extension.extension.name,
  102. 'collection': collection})
  103. resource = self.resources[collection]
  104. resource.register_actions(controller)
  105. resource.register_extensions(controller)
  106. def _setup_routes(self, mapper, ext_mgr):
  107. raise NotImplementedError