aboutsummaryrefslogtreecommitdiffstats
path: root/keystone-moon/keystone/version
diff options
context:
space:
mode:
Diffstat (limited to 'keystone-moon/keystone/version')
-rw-r--r--keystone-moon/keystone/version/__init__.py0
-rw-r--r--keystone-moon/keystone/version/controllers.py215
-rw-r--r--keystone-moon/keystone/version/routers.py80
-rw-r--r--keystone-moon/keystone/version/service.py161
4 files changed, 456 insertions, 0 deletions
diff --git a/keystone-moon/keystone/version/__init__.py b/keystone-moon/keystone/version/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/keystone-moon/keystone/version/__init__.py
diff --git a/keystone-moon/keystone/version/controllers.py b/keystone-moon/keystone/version/controllers.py
new file mode 100644
index 00000000..2a7bacdf
--- /dev/null
+++ b/keystone-moon/keystone/version/controllers.py
@@ -0,0 +1,215 @@
+# Copyright 2012 OpenStack Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from oslo_serialization import jsonutils
+import webob
+
+from keystone.common import extension
+from keystone.common import json_home
+from keystone.common import wsgi
+from keystone import exception
+
+
+MEDIA_TYPE_JSON = 'application/vnd.openstack.identity-%s+json'
+
+_VERSIONS = []
+
+# NOTE(blk-u): latest_app will be set by keystone.version.service.loadapp(). It
+# gets set to the application that was just loaded. In the case of keystone-all
+# loadapp() gets called twice, once for the public app and once for the admin
+# app. In the case of httpd/keystone, loadapp() gets called once for the public
+# app if this is the public instance or loadapp() gets called for the admin app
+# if it's the admin instance.
+# This is used to fetch the /v3 JSON Home response. The /v3 JSON Home response
+# is the same whether it's the admin or public service so either admin or
+# public works.
+latest_app = None
+
+
+def request_v3_json_home(new_prefix):
+ if 'v3' not in _VERSIONS:
+ # No V3 support, so return an empty JSON Home document.
+ return {'resources': {}}
+
+ req = webob.Request.blank(
+ '/v3', headers={'Accept': 'application/json-home'})
+ v3_json_home_str = req.get_response(latest_app).body
+ v3_json_home = jsonutils.loads(v3_json_home_str)
+ json_home.translate_urls(v3_json_home, new_prefix)
+
+ return v3_json_home
+
+
+class Extensions(wsgi.Application):
+ """Base extensions controller to be extended by public and admin API's."""
+
+ # extend in subclass to specify the set of extensions
+ @property
+ def extensions(self):
+ return None
+
+ def get_extensions_info(self, context):
+ return {'extensions': {'values': list(self.extensions.values())}}
+
+ def get_extension_info(self, context, extension_alias):
+ try:
+ return {'extension': self.extensions[extension_alias]}
+ except KeyError:
+ raise exception.NotFound(target=extension_alias)
+
+
+class AdminExtensions(Extensions):
+ @property
+ def extensions(self):
+ return extension.ADMIN_EXTENSIONS
+
+
+class PublicExtensions(Extensions):
+ @property
+ def extensions(self):
+ return extension.PUBLIC_EXTENSIONS
+
+
+def register_version(version):
+ _VERSIONS.append(version)
+
+
+class MimeTypes(object):
+ JSON = 'application/json'
+ JSON_HOME = 'application/json-home'
+
+
+def v3_mime_type_best_match(context):
+
+ # accept_header is a WebOb MIMEAccept object so supports best_match.
+ accept_header = context['accept_header']
+
+ if not accept_header:
+ return MimeTypes.JSON
+
+ SUPPORTED_TYPES = [MimeTypes.JSON, MimeTypes.JSON_HOME]
+ return accept_header.best_match(SUPPORTED_TYPES)
+
+
+class Version(wsgi.Application):
+
+ def __init__(self, version_type, routers=None):
+ self.endpoint_url_type = version_type
+ self._routers = routers
+
+ super(Version, self).__init__()
+
+ def _get_identity_url(self, context, version):
+ """Returns a URL to keystone's own endpoint."""
+ url = self.base_url(context, self.endpoint_url_type)
+ return '%s/%s/' % (url, version)
+
+ def _get_versions_list(self, context):
+ """The list of versions is dependent on the context."""
+ versions = {}
+ if 'v2.0' in _VERSIONS:
+ versions['v2.0'] = {
+ 'id': 'v2.0',
+ 'status': 'stable',
+ 'updated': '2014-04-17T00:00:00Z',
+ 'links': [
+ {
+ 'rel': 'self',
+ 'href': self._get_identity_url(context, 'v2.0'),
+ }, {
+ 'rel': 'describedby',
+ 'type': 'text/html',
+ 'href': 'http://docs.openstack.org/'
+ }
+ ],
+ 'media-types': [
+ {
+ 'base': 'application/json',
+ 'type': MEDIA_TYPE_JSON % 'v2.0'
+ }
+ ]
+ }
+
+ if 'v3' in _VERSIONS:
+ versions['v3'] = {
+ 'id': 'v3.6',
+ 'status': 'stable',
+ 'updated': '2016-04-04T00:00:00Z',
+ 'links': [
+ {
+ 'rel': 'self',
+ 'href': self._get_identity_url(context, 'v3'),
+ }
+ ],
+ 'media-types': [
+ {
+ 'base': 'application/json',
+ 'type': MEDIA_TYPE_JSON % 'v3'
+ }
+ ]
+ }
+
+ return versions
+
+ def get_versions(self, context):
+
+ req_mime_type = v3_mime_type_best_match(context)
+ if req_mime_type == MimeTypes.JSON_HOME:
+ v3_json_home = request_v3_json_home('/v3')
+ return wsgi.render_response(
+ body=v3_json_home,
+ headers=(('Content-Type', MimeTypes.JSON_HOME),))
+
+ versions = self._get_versions_list(context)
+ return wsgi.render_response(status=(300, 'Multiple Choices'), body={
+ 'versions': {
+ 'values': list(versions.values())
+ }
+ })
+
+ def get_version_v2(self, context):
+ versions = self._get_versions_list(context)
+ if 'v2.0' in _VERSIONS:
+ return wsgi.render_response(body={
+ 'version': versions['v2.0']
+ })
+ else:
+ raise exception.VersionNotFound(version='v2.0')
+
+ def _get_json_home_v3(self):
+
+ def all_resources():
+ for router in self._routers:
+ for resource in router.v3_resources:
+ yield resource
+
+ return {
+ 'resources': dict(all_resources())
+ }
+
+ def get_version_v3(self, context):
+ versions = self._get_versions_list(context)
+ if 'v3' in _VERSIONS:
+ req_mime_type = v3_mime_type_best_match(context)
+
+ if req_mime_type == MimeTypes.JSON_HOME:
+ return wsgi.render_response(
+ body=self._get_json_home_v3(),
+ headers=(('Content-Type', MimeTypes.JSON_HOME),))
+
+ return wsgi.render_response(body={
+ 'version': versions['v3']
+ })
+ else:
+ raise exception.VersionNotFound(version='v3')
diff --git a/keystone-moon/keystone/version/routers.py b/keystone-moon/keystone/version/routers.py
new file mode 100644
index 00000000..5da4951c
--- /dev/null
+++ b/keystone-moon/keystone/version/routers.py
@@ -0,0 +1,80 @@
+# Copyright 2012 OpenStack Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+"""
+The only types of routers in this file should be ``ComposingRouters``.
+
+The routers for the backends should be in the backend-specific router modules.
+For example, the ``ComposableRouter`` for ``identity`` belongs in::
+
+ keystone.identity.routers
+
+"""
+
+
+from keystone.common import wsgi
+from keystone.version import controllers
+
+
+class Extension(wsgi.ComposableRouter):
+ def __init__(self, is_admin=True):
+ if is_admin:
+ self.controller = controllers.AdminExtensions()
+ else:
+ self.controller = controllers.PublicExtensions()
+
+ def add_routes(self, mapper):
+ extensions_controller = self.controller
+ mapper.connect('/extensions',
+ controller=extensions_controller,
+ action='get_extensions_info',
+ conditions=dict(method=['GET']))
+ mapper.connect('/extensions/{extension_alias}',
+ controller=extensions_controller,
+ action='get_extension_info',
+ conditions=dict(method=['GET']))
+
+
+class VersionV2(wsgi.ComposableRouter):
+ def __init__(self, description):
+ self.description = description
+
+ def add_routes(self, mapper):
+ version_controller = controllers.Version(self.description)
+ mapper.connect('/',
+ controller=version_controller,
+ action='get_version_v2')
+
+
+class VersionV3(wsgi.ComposableRouter):
+ def __init__(self, description, routers):
+ self.description = description
+ self._routers = routers
+
+ def add_routes(self, mapper):
+ version_controller = controllers.Version(self.description,
+ routers=self._routers)
+ mapper.connect('/',
+ controller=version_controller,
+ action='get_version_v3')
+
+
+class Versions(wsgi.ComposableRouter):
+ def __init__(self, description):
+ self.description = description
+
+ def add_routes(self, mapper):
+ version_controller = controllers.Version(self.description)
+ mapper.connect('/',
+ controller=version_controller,
+ action='get_versions')
diff --git a/keystone-moon/keystone/version/service.py b/keystone-moon/keystone/version/service.py
new file mode 100644
index 00000000..b0ed3b76
--- /dev/null
+++ b/keystone-moon/keystone/version/service.py
@@ -0,0 +1,161 @@
+# Copyright 2012 OpenStack Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import functools
+import sys
+
+from oslo_config import cfg
+from oslo_log import log
+from paste import deploy
+import routes
+
+from keystone.assignment import routers as assignment_routers
+from keystone.auth import routers as auth_routers
+from keystone.catalog import routers as catalog_routers
+from keystone.common import wsgi
+from keystone.credential import routers as credential_routers
+from keystone.endpoint_policy import routers as endpoint_policy_routers
+from keystone.federation import routers as federation_routers
+from keystone.i18n import _LW
+from keystone.identity import routers as identity_routers
+from keystone.oauth1 import routers as oauth1_routers
+from keystone.policy import routers as policy_routers
+from keystone.resource import routers as resource_routers
+from keystone.revoke import routers as revoke_routers
+from keystone.token import _simple_cert as simple_cert_ext
+from keystone.token import routers as token_routers
+from keystone.trust import routers as trust_routers
+from keystone.v2_crud import admin_crud
+from keystone.v2_crud import user_crud
+from keystone.version import controllers
+from keystone.version import routers
+
+
+CONF = cfg.CONF
+LOG = log.getLogger(__name__)
+
+
+def loadapp(conf, name):
+ # NOTE(blk-u): Save the application being loaded in the controllers module.
+ # This is similar to how public_app_factory() and v3_app_factory()
+ # register the version with the controllers module.
+ controllers.latest_app = deploy.loadapp(conf, name=name)
+ return controllers.latest_app
+
+
+def fail_gracefully(f):
+ """Logs exceptions and aborts."""
+ @functools.wraps(f)
+ def wrapper(*args, **kw):
+ try:
+ return f(*args, **kw)
+ except Exception as e:
+ LOG.debug(e, exc_info=True)
+
+ # exception message is printed to all logs
+ LOG.critical(e)
+ sys.exit(1)
+
+ return wrapper
+
+
+def warn_local_conf(f):
+ @functools.wraps(f)
+ def wrapper(*args, **local_conf):
+ if local_conf:
+ LOG.warning(_LW('\'local conf\' from PasteDeploy INI is being '
+ 'ignored.'))
+ return f(*args, **local_conf)
+ return wrapper
+
+
+@fail_gracefully
+@warn_local_conf
+def public_app_factory(global_conf, **local_conf):
+ controllers.register_version('v2.0')
+ return wsgi.ComposingRouter(routes.Mapper(),
+ [assignment_routers.Public(),
+ token_routers.Router(),
+ user_crud.Router(),
+ routers.VersionV2('public'),
+ routers.Extension(False)])
+
+
+@fail_gracefully
+@warn_local_conf
+def admin_app_factory(global_conf, **local_conf):
+ controllers.register_version('v2.0')
+ return wsgi.ComposingRouter(routes.Mapper(),
+ [identity_routers.Admin(),
+ assignment_routers.Admin(),
+ token_routers.Router(),
+ resource_routers.Admin(),
+ admin_crud.Router(),
+ routers.VersionV2('admin'),
+ routers.Extension()])
+
+
+@fail_gracefully
+@warn_local_conf
+def public_version_app_factory(global_conf, **local_conf):
+ return wsgi.ComposingRouter(routes.Mapper(),
+ [routers.Versions('public')])
+
+
+@fail_gracefully
+@warn_local_conf
+def admin_version_app_factory(global_conf, **local_conf):
+ return wsgi.ComposingRouter(routes.Mapper(),
+ [routers.Versions('admin')])
+
+
+@fail_gracefully
+@warn_local_conf
+def v3_app_factory(global_conf, **local_conf):
+ controllers.register_version('v3')
+ mapper = routes.Mapper()
+ sub_routers = []
+ _routers = []
+
+ # NOTE(dstanek): Routers should be ordered by their frequency of use in
+ # a live system. This is due to the routes implementation. The most
+ # frequently used routers should appear first.
+ all_api_routers = [auth_routers,
+ assignment_routers,
+ catalog_routers,
+ credential_routers,
+ identity_routers,
+ policy_routers,
+ resource_routers,
+ revoke_routers,
+ federation_routers,
+ oauth1_routers,
+ # TODO(morganfainberg): Remove the simple_cert router
+ # when PKI and PKIZ tokens are removed.
+ simple_cert_ext]
+
+ if CONF.trust.enabled:
+ all_api_routers.append(trust_routers)
+
+ if CONF.endpoint_policy.enabled:
+ all_api_routers.append(endpoint_policy_routers)
+
+ for api_routers in all_api_routers:
+ routers_instance = api_routers.Routers()
+ _routers.append(routers_instance)
+ routers_instance.append_v3_routers(mapper, sub_routers)
+
+ # Add in the v3 version api
+ sub_routers.append(routers.VersionV3('public', _routers))
+ return wsgi.ComposingRouter(mapper, sub_routers)