summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.openstack.org>2018-08-15 03:41:23 +0000
committerGerrit Code Review <review@openstack.org>2018-08-15 03:41:23 +0000
commit604141a23001a0caea874c48c041c691b0751df0 (patch)
tree7d08fa1ee670ab1478696615f0debf13ca316201
parent3280aaacfcc4c109182e7d3794aa06ff8189ae21 (diff)
parent56d9c30f8f64c790111fe9c877a5d344c9d75790 (diff)
Merge "Convert endpoints api to flask native dispatching"HEADmaster
-rw-r--r--keystone/api/__init__.py3
-rw-r--r--keystone/api/endpoints.py149
-rw-r--r--keystone/api/os_ep_filter.py10
-rw-r--r--keystone/catalog/__init__.py1
-rw-r--r--keystone/catalog/controllers.py114
-rw-r--r--keystone/catalog/routers.py28
-rw-r--r--keystone/endpoint_policy/controllers.py13
-rw-r--r--keystone/endpoint_policy/routers.py6
-rw-r--r--keystone/server/flask/application.py3
9 files changed, 157 insertions, 170 deletions
diff --git a/keystone/api/__init__.py b/keystone/api/__init__.py
index 2e714eb..ca99cdd 100644
--- a/keystone/api/__init__.py
+++ b/keystone/api/__init__.py
@@ -12,6 +12,7 @@
12 12
13from keystone.api import credentials 13from keystone.api import credentials
14from keystone.api import discovery 14from keystone.api import discovery
15from keystone.api import endpoints
15from keystone.api import limits 16from keystone.api import limits
16from keystone.api import os_ep_filter 17from keystone.api import os_ep_filter
17from keystone.api import os_oauth1 18from keystone.api import os_oauth1
@@ -25,6 +26,7 @@ from keystone.api import trusts
25__all__ = ( 26__all__ = (
26 'discovery', 27 'discovery',
27 'credentials', 28 'credentials',
29 'endpoints',
28 'limits', 30 'limits',
29 'os_ep_filter', 31 'os_ep_filter',
30 'os_oauth1', 32 'os_oauth1',
@@ -39,6 +41,7 @@ __all__ = (
39__apis__ = ( 41__apis__ = (
40 discovery, 42 discovery,
41 credentials, 43 credentials,
44 endpoints,
42 limits, 45 limits,
43 os_ep_filter, 46 os_ep_filter,
44 os_oauth1, 47 os_oauth1,
diff --git a/keystone/api/endpoints.py b/keystone/api/endpoints.py
new file mode 100644
index 0000000..348fe82
--- /dev/null
+++ b/keystone/api/endpoints.py
@@ -0,0 +1,149 @@
1# Licensed under the Apache License, Version 2.0 (the "License"); you may
2# not use this file except in compliance with the License. You may obtain
3# a copy of the License at
4#
5# http://www.apache.org/licenses/LICENSE-2.0
6#
7# Unless required by applicable law or agreed to in writing, software
8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10# License for the specific language governing permissions and limitations
11# under the License.
12
13# This file handles all flask-restful resources for /v3/services
14
15import flask_restful
16import functools
17from six.moves import http_client
18
19from keystone.catalog import schema
20from keystone.common import json_home
21from keystone.common import provider_api
22from keystone.common import rbac_enforcer
23from keystone.common import utils
24from keystone.common import validation
25from keystone import exception
26from keystone.server import flask as ks_flask
27
28
29ENFORCER = rbac_enforcer.RBACEnforcer
30PROVIDERS = provider_api.ProviderAPIs
31
32# TODO(morgan) move the partial functions to a common place so that they
33# can be referenced by multiple APIs, such as endpoints and endpoint_policy.
34_build_resource_relation = functools.partial(
35 json_home.build_v3_extension_resource_relation,
36 extension_name='OS-ENDPOINT-POLICY', extension_version='1.0')
37
38
39def _filter_endpoint(ref):
40 ref.pop('legacy_endpoint_id', None)
41 ref['region'] = ref['region_id']
42 return ref
43
44
45class EndpointResource(ks_flask.ResourceBase):
46 collection_key = 'endpoints'
47 member_key = 'endpoint'
48
49 def __init__(self):
50 super(EndpointResource, self).__init__()
51 self.get_member_from_driver = PROVIDERS.catalog_api.get_endpoint
52
53 @staticmethod
54 def _validate_endpoint_region(endpoint):
55 """Ensure the region for the endpoint exists.
56
57 If 'region_id' is used to specify the region, then we will let the
58 manager/driver take care of this. If, however, 'region' is used,
59 then for backward compatibility, we will auto-create the region.
60
61 """
62 if (endpoint.get('region_id') is None and
63 endpoint.get('region') is not None):
64 # To maintain backward compatibility with clients that are
65 # using the v3 API in the same way as they used the v2 API,
66 # create the endpoint region, if that region does not exist
67 # in keystone.
68 endpoint['region_id'] = endpoint.pop('region')
69 try:
70 PROVIDERS.catalog_api.get_region(endpoint['region_id'])
71 except exception.RegionNotFound:
72 region = dict(id=endpoint['region_id'])
73 PROVIDERS.catalog_api.create_region(
74 region, initiator=ks_flask.build_audit_initiator())
75 return endpoint
76
77 def _get_endpoint(self, endpoint_id):
78 ENFORCER.enforce_call(action='identity:get_endpoint')
79 return self.wrap_member(_filter_endpoint(
80 PROVIDERS.catalog_api.get_endpoint(endpoint_id)))
81
82 def _list_endpoints(self):
83 filters = ['interface', 'service_id', 'region_id']
84 ENFORCER.enforce_call(action='identity:list_endpoints',
85 filters=filters)
86 hints = self.build_driver_hints(filters)
87 refs = PROVIDERS.catalog_api.list_endpoints(hints=hints)
88 return self.wrap_collection([_filter_endpoint(r) for r in refs],
89 hints=hints)
90
91 def get(self, endpoint_id=None):
92 if endpoint_id is not None:
93 return self._get_endpoint(endpoint_id)
94 return self._list_endpoints()
95
96 def post(self):
97 ENFORCER.enforce_call(action='identity:create_endpoint')
98 endpoint = self.request_body_json.get('endpoint')
99 validation.lazy_validate(schema.endpoint_create, endpoint)
100 utils.check_endpoint_url(endpoint['url'])
101 endpoint = self._assign_unique_id(self._normalize_dict(endpoint))
102 endpoint = self._validate_endpoint_region(endpoint)
103 ref = PROVIDERS.catalog_api.create_endpoint(
104 endpoint['id'], endpoint, initiator=self.audit_initiator)
105 return self.wrap_member(_filter_endpoint(ref)), http_client.CREATED
106
107 def patch(self, endpoint_id):
108 ENFORCER.enforce_call(action='identity:update_endpoint')
109 endpoint = self.request_body_json.get('endpoint')
110 validation.lazy_validate(schema.endpoint_update, endpoint)
111 self._require_matching_id(endpoint)
112 endpoint = self._validate_endpoint_region(endpoint)
113 ref = PROVIDERS.catalog_api.update_endpoint(
114 endpoint_id, endpoint, initiator=self.audit_initiator)
115 return self.wrap_member(_filter_endpoint(ref))
116
117 def delete(self, endpoint_id):
118 ENFORCER.enforce_call(action='identity:delete_endpoint')
119 PROVIDERS.catalog_api.delete_endpoint(endpoint_id,
120 initiator=self.audit_initiator)
121 return None, http_client.NO_CONTENT
122
123
124class EndpointPolicyEndpointResource(flask_restful.Resource):
125 def get(self, endpoint_id):
126 ENFORCER.enforce_call(action='identity:get_policy_for_endpoint')
127 PROVIDERS.catalog_api.get_endpoint(endpoint_id)
128 ref = PROVIDERS.endpoint_policy_api.get_policy_for_endpoint(
129 endpoint_id)
130 return ks_flask.ResourceBase.wrap_member(
131 ref, collection_name='endpoints', member_name='policy')
132
133
134class EndpointAPI(ks_flask.APIBase):
135 _name = 'endpoints'
136 _import_name = __name__
137 resources = [EndpointResource]
138 resource_mapping = [
139 ks_flask.construct_resource_map(
140 resource=EndpointPolicyEndpointResource,
141 url='/endpoints/<string:endpoint_id>/OS-ENDPOINT-POLICY/policy',
142 resource_kwargs={},
143 rel='endpoint_policy',
144 resource_relation_func=_build_resource_relation,
145 path_vars={'endpoint_id': json_home.Parameters.ENDPOINT_ID})
146 ]
147
148
149APIs = (EndpointAPI,)
diff --git a/keystone/api/os_ep_filter.py b/keystone/api/os_ep_filter.py
index 072d030..47ca233 100644
--- a/keystone/api/os_ep_filter.py
+++ b/keystone/api/os_ep_filter.py
@@ -16,6 +16,7 @@ import flask_restful
16import functools 16import functools
17from six.moves import http_client 17from six.moves import http_client
18 18
19from keystone.api import endpoints as _endpoints_api
19from keystone.catalog import schema 20from keystone.catalog import schema
20from keystone.common import json_home 21from keystone.common import json_home
21from keystone.common import provider_api 22from keystone.common import provider_api
@@ -41,12 +42,9 @@ _ENDPOINT_GROUP_PARAMETER_RELATION = _build_parameter_relation(
41 parameter_name='endpoint_group_id') 42 parameter_name='endpoint_group_id')
42 43
43 44
44# TODO(morgan): move this to a common location once catalog endpoint API is 45# NOTE(morgan): This is shared from keystone.api.endpoint, this is a special
45# converted to flask 46# case where cross-api code is used. This pattern should not be replicated.
46def _filter_endpoint(ref): 47_filter_endpoint = _endpoints_api._filter_endpoint
47 ref.pop('legacy_endpoint_id', None)
48 ref['region'] = ref['region_id']
49 return ref
50 48
51 49
52class EndpointGroupsResource(ks_flask.ResourceBase): 50class EndpointGroupsResource(ks_flask.ResourceBase):
diff --git a/keystone/catalog/__init__.py b/keystone/catalog/__init__.py
index 29f297d..fc3e854 100644
--- a/keystone/catalog/__init__.py
+++ b/keystone/catalog/__init__.py
@@ -12,5 +12,4 @@
12# License for the specific language governing permissions and limitations 12# License for the specific language governing permissions and limitations
13# under the License. 13# under the License.
14 14
15from keystone.catalog import controllers # noqa
16from keystone.catalog.core import * # noqa 15from keystone.catalog.core import * # noqa
diff --git a/keystone/catalog/controllers.py b/keystone/catalog/controllers.py
deleted file mode 100644
index 7dbd793..0000000
--- a/keystone/catalog/controllers.py
+++ /dev/null
@@ -1,114 +0,0 @@
1# Copyright 2012 OpenStack Foundation
2# Copyright 2012 Canonical Ltd.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
16from keystone.catalog import schema
17from keystone.common import controller
18from keystone.common import provider_api
19from keystone.common import utils
20from keystone.common import validation
21from keystone import exception
22
23
24INTERFACES = ['public', 'internal', 'admin']
25PROVIDERS = provider_api.ProviderAPIs
26
27
28class EndpointV3(controller.V3Controller):
29 collection_name = 'endpoints'
30 member_name = 'endpoint'
31
32 def __init__(self):
33 super(EndpointV3, self).__init__()
34 self.get_member_from_driver = PROVIDERS.catalog_api.get_endpoint
35
36 @classmethod
37 def filter_endpoint(cls, ref):
38 if 'legacy_endpoint_id' in ref:
39 ref.pop('legacy_endpoint_id')
40 ref['region'] = ref['region_id']
41 return ref
42
43 @classmethod
44 def wrap_member(cls, context, ref):
45 ref = cls.filter_endpoint(ref)
46 return super(EndpointV3, cls).wrap_member(context, ref)
47
48 def _validate_endpoint_region(self, endpoint, request):
49 """Ensure the region for the endpoint exists.
50
51 If 'region_id' is used to specify the region, then we will let the
52 manager/driver take care of this. If, however, 'region' is used,
53 then for backward compatibility, we will auto-create the region.
54
55 """
56 if (endpoint.get('region_id') is None and
57 endpoint.get('region') is not None):
58 # To maintain backward compatibility with clients that are
59 # using the v3 API in the same way as they used the v2 API,
60 # create the endpoint region, if that region does not exist
61 # in keystone.
62 endpoint['region_id'] = endpoint.pop('region')
63 try:
64 PROVIDERS.catalog_api.get_region(endpoint['region_id'])
65 except exception.RegionNotFound:
66 region = dict(id=endpoint['region_id'])
67 PROVIDERS.catalog_api.create_region(
68 region, initiator=request.audit_initiator
69 )
70
71 return endpoint
72
73 @controller.protected()
74 def create_endpoint(self, request, endpoint):
75 validation.lazy_validate(schema.endpoint_create, endpoint)
76 utils.check_endpoint_url(endpoint['url'])
77 ref = self._assign_unique_id(self._normalize_dict(endpoint))
78 ref = self._validate_endpoint_region(ref, request)
79 ref = PROVIDERS.catalog_api.create_endpoint(
80 ref['id'], ref, initiator=request.audit_initiator
81 )
82 return EndpointV3.wrap_member(request.context_dict, ref)
83
84 @controller.filterprotected('interface', 'service_id', 'region_id')
85 def list_endpoints(self, request, filters):
86 hints = EndpointV3.build_driver_hints(request, filters)
87 refs = PROVIDERS.catalog_api.list_endpoints(hints=hints)
88 return EndpointV3.wrap_collection(request.context_dict,
89 refs,
90 hints=hints)
91
92 @controller.protected()
93 def get_endpoint(self, request, endpoint_id):
94 ref = PROVIDERS.catalog_api.get_endpoint(endpoint_id)
95 return EndpointV3.wrap_member(request.context_dict, ref)
96
97 @controller.protected()
98 def update_endpoint(self, request, endpoint_id, endpoint):
99 validation.lazy_validate(schema.endpoint_update, endpoint)
100 self._require_matching_id(endpoint_id, endpoint)
101
102 endpoint = self._validate_endpoint_region(endpoint.copy(),
103 request)
104
105 ref = PROVIDERS.catalog_api.update_endpoint(
106 endpoint_id, endpoint, initiator=request.audit_initiator
107 )
108 return EndpointV3.wrap_member(request.context_dict, ref)
109
110 @controller.protected()
111 def delete_endpoint(self, request, endpoint_id):
112 return PROVIDERS.catalog_api.delete_endpoint(
113 endpoint_id, initiator=request.audit_initiator
114 )
diff --git a/keystone/catalog/routers.py b/keystone/catalog/routers.py
deleted file mode 100644
index 7fde383..0000000
--- a/keystone/catalog/routers.py
+++ /dev/null
@@ -1,28 +0,0 @@
1# Copyright 2012 OpenStack Foundation
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14
15from keystone.catalog import controllers
16from keystone.common import router
17from keystone.common import wsgi
18
19
20class Routers(wsgi.RoutersBase):
21 """API for the keystone catalog."""
22
23 _path_prefixes = ('endpoints',)
24
25 def append_v3_routers(self, mapper, routers):
26 routers.append(router.Router(controllers.EndpointV3(),
27 'endpoints', 'endpoint',
28 resource_descriptions=self.v3_resources))
diff --git a/keystone/endpoint_policy/controllers.py b/keystone/endpoint_policy/controllers.py
index 52c721c..ca4df6b 100644
--- a/keystone/endpoint_policy/controllers.py
+++ b/keystone/endpoint_policy/controllers.py
@@ -135,19 +135,6 @@ class EndpointPolicyV3Controller(controller.V3Controller):
135 PROVIDERS.endpoint_policy_api.delete_policy_association( 135 PROVIDERS.endpoint_policy_api.delete_policy_association(
136 policy_id, service_id=service_id, region_id=region_id) 136 policy_id, service_id=service_id, region_id=region_id)
137 137
138 @controller.protected()
139 def get_policy_for_endpoint(self, request, endpoint_id):
140 """Get the effective policy for an endpoint."""
141 PROVIDERS.catalog_api.get_endpoint(endpoint_id)
142 ref = PROVIDERS.endpoint_policy_api.get_policy_for_endpoint(
143 endpoint_id
144 )
145 # NOTE(henry-nash): since the collection and member for this class is
146 # set to endpoints, we have to handle wrapping this policy entity
147 # ourselves.
148 self._add_self_referential_link(request.context_dict, ref)
149 return {'policy': ref}
150
151 # NOTE(henry-nash): As in the catalog controller, we must ensure that the 138 # NOTE(henry-nash): As in the catalog controller, we must ensure that the
152 # legacy_endpoint_id does not escape. 139 # legacy_endpoint_id does not escape.
153 140
diff --git a/keystone/endpoint_policy/routers.py b/keystone/endpoint_policy/routers.py
index 5f51d37..744cd75 100644
--- a/keystone/endpoint_policy/routers.py
+++ b/keystone/endpoint_policy/routers.py
@@ -35,12 +35,6 @@ class Routers(wsgi.RoutersBase):
35 35
36 self._add_resource( 36 self._add_resource(
37 mapper, endpoint_policy_controller, 37 mapper, endpoint_policy_controller,
38 path='/endpoints/{endpoint_id}' + self.PATH_PREFIX + '/policy',
39 get_head_action='get_policy_for_endpoint',
40 rel=build_resource_relation(resource_name='endpoint_policy'),
41 path_vars={'endpoint_id': json_home.Parameters.ENDPOINT_ID})
42 self._add_resource(
43 mapper, endpoint_policy_controller,
44 path='/policies/{policy_id}' + self.PATH_PREFIX + '/endpoints', 38 path='/policies/{policy_id}' + self.PATH_PREFIX + '/endpoints',
45 get_head_action='list_endpoints_for_policy', 39 get_head_action='list_endpoints_for_policy',
46 rel=build_resource_relation(resource_name='policy_endpoints'), 40 rel=build_resource_relation(resource_name='policy_endpoints'),
diff --git a/keystone/server/flask/application.py b/keystone/server/flask/application.py
index 4d2c6da..4707b72 100644
--- a/keystone/server/flask/application.py
+++ b/keystone/server/flask/application.py
@@ -27,7 +27,6 @@ import keystone.api
27from keystone.application_credential import routers as app_cred_routers 27from keystone.application_credential import routers as app_cred_routers
28from keystone.assignment import routers as assignment_routers 28from keystone.assignment import routers as assignment_routers
29from keystone.auth import routers as auth_routers 29from keystone.auth import routers as auth_routers
30from keystone.catalog import routers as catalog_routers
31from keystone.common import wsgi as keystone_wsgi 30from keystone.common import wsgi as keystone_wsgi
32from keystone.contrib.ec2 import routers as ec2_routers 31from keystone.contrib.ec2 import routers as ec2_routers
33from keystone.contrib.s3 import routers as s3_routers 32from keystone.contrib.s3 import routers as s3_routers
@@ -42,6 +41,7 @@ from keystone.resource import routers as resource_routers
42# support is removed. 41# support is removed.
43_MOVED_API_PREFIXES = frozenset( 42_MOVED_API_PREFIXES = frozenset(
44 ['credentials', 43 ['credentials',
44 'endpoints',
45 'OS-OAUTH1', 45 'OS-OAUTH1',
46 'OS-EP-FILTER', 46 'OS-EP-FILTER',
47 'OS-REVOKE', 47 'OS-REVOKE',
@@ -59,7 +59,6 @@ LOG = log.getLogger(__name__)
59 59
60ALL_API_ROUTERS = [auth_routers, 60ALL_API_ROUTERS = [auth_routers,
61 assignment_routers, 61 assignment_routers,
62 catalog_routers,
63 identity_routers, 62 identity_routers,
64 app_cred_routers, 63 app_cred_routers,
65 policy_routers, 64 policy_routers,