Merge "Use service catalog from authentication response"

This commit is contained in:
Jenkins 2016-11-02 11:00:29 +00:00 committed by Gerrit Code Review
commit 5452662928
3 changed files with 54 additions and 30 deletions

View File

@ -76,7 +76,6 @@ class MistralContext(BaseContext):
"project_id", "project_id",
"auth_token", "auth_token",
"service_catalog", "service_catalog",
"target_service_catalog",
"user_name", "user_name",
"project_name", "project_name",
"roles", "roles",
@ -85,6 +84,7 @@ class MistralContext(BaseContext):
"redelivered", "redelivered",
"expires_at", "expires_at",
"trust_id", "trust_id",
"is_target",
]) ])
def __repr__(self): def __repr__(self):
@ -108,18 +108,19 @@ def set_ctx(new_ctx):
def context_from_headers_and_env(headers, env): def context_from_headers_and_env(headers, env):
params = _extract_auth_params_from_headers(headers) params = _extract_auth_params_from_headers(headers)
auth_cacert = params['auth_cacert'] auth_cacert = params['auth_cacert']
auth_token = params['auth_token'] auth_token = params['auth_token']
auth_uri = params['auth_uri'] auth_uri = params['auth_uri']
project_id = params['project_id'] project_id = params['project_id']
user_id = params['user_id'] user_id = params['user_id']
user_name = params['user_name'] user_name = params['user_name']
target_service_catalog = params['target_service_catalog'] is_target = params['is_target']
token_info = env.get('keystone.token_info') token_info = env.get('keystone.token_info', {})
if token_info and target_service_catalog is None: service_catalog = (params['service_catalog'] if is_target
target_service_catalog = token_info['token'] else token_info.get('token', {}))
return MistralContext( return MistralContext(
auth_uri=auth_uri, auth_uri=auth_uri,
@ -127,7 +128,8 @@ def context_from_headers_and_env(headers, env):
user_id=user_id, user_id=user_id,
project_id=project_id, project_id=project_id,
auth_token=auth_token, auth_token=auth_token,
target_service_catalog=target_service_catalog, is_target=is_target,
service_catalog=service_catalog,
user_name=user_name, user_name=user_name,
project_name=headers.get('X-Project-Name'), project_name=headers.get('X-Project-Name'),
roles=headers.get('X-Roles', "").split(","), roles=headers.get('X-Roles', "").split(","),
@ -137,7 +139,7 @@ def context_from_headers_and_env(headers, env):
def _extract_auth_params_from_headers(headers): def _extract_auth_params_from_headers(headers):
target_service_catalog = None service_catalog = None
if headers.get("X-Target-Auth-Uri"): if headers.get("X-Target-Auth-Uri"):
params = { params = {
@ -148,13 +150,17 @@ def _extract_auth_params_from_headers(headers):
'project_id': headers.get('X-Target-Project-Id'), 'project_id': headers.get('X-Target-Project-Id'),
'user_id': headers.get('X-Target-User-Id'), 'user_id': headers.get('X-Target-User-Id'),
'user_name': headers.get('X-Target-User-Name'), 'user_name': headers.get('X-Target-User-Name'),
'is_target': True
} }
if not params['auth_token']: if not params['auth_token']:
raise (exc.MistralException( raise (exc.MistralException(
'Target auth URI (X-Target-Auth-Uri) target auth token ' 'Target auth URI (X-Target-Auth-Uri) target auth token '
'(X-Target-Auth-Token) must be present')) '(X-Target-Auth-Token) must be present'))
target_service_catalog = _extract_service_catalog_from_headers( # It's possible that target service catalog is not provided, in this
# case, Mistral needs to get target service catalog dynamically when
# talking to target openstack deployment later on.
service_catalog = _extract_service_catalog_from_headers(
headers headers
) )
else: else:
@ -165,9 +171,10 @@ def _extract_auth_params_from_headers(headers):
'project_id': headers.get('X-Project-Id'), 'project_id': headers.get('X-Project-Id'),
'user_id': headers.get('X-User-Id'), 'user_id': headers.get('X-User-Id'),
'user_name': headers.get('X-User-Name'), 'user_name': headers.get('X-User-Name'),
'is_target': False
} }
params['target_service_catalog'] = target_service_catalog params['service_catalog'] = service_catalog
return params return params

View File

@ -12,7 +12,8 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from mistral import config from mistral import context as auth_context
from mistral import exceptions
from mistral.tests.unit import base from mistral.tests.unit import base
from mistral.utils.openstack import keystone from mistral.utils.openstack import keystone
@ -23,10 +24,6 @@ class KeystoneUtilsTest(base.BaseTest):
self.values = {'id': 'my_id'} self.values = {'id': 'my_id'}
def override_config(self, name, override, group=None):
config.CONF.set_override(name, override, group)
self.addCleanup(config.CONF.clear_override, name, group)
def test_format_url_dollar_sign(self): def test_format_url_dollar_sign(self):
url_template = "http://host:port/v1/$(id)s" url_template = "http://host:port/v1/$(id)s"
@ -46,3 +43,14 @@ class KeystoneUtilsTest(base.BaseTest):
expected, expected,
keystone.format_url(url_template, self.values) keystone.format_url(url_template, self.values)
) )
def test_get_endpoint_for_project_noauth(self):
# service_catalog is not set by default.
auth_context.set_ctx(base.get_context())
self.addCleanup(auth_context.set_ctx, None)
self.assertRaises(
exceptions.UnauthorizedException,
keystone.get_endpoint_for_project,
'keystone'
)

View File

@ -20,8 +20,10 @@ from keystoneclient.v3 import client as ks_client
from keystoneclient.v3 import endpoints as ks_endpoints from keystoneclient.v3 import endpoints as ks_endpoints
from oslo_config import cfg from oslo_config import cfg
from oslo_utils import timeutils from oslo_utils import timeutils
import six
from mistral import context from mistral import context
from mistral import exceptions
CONF = cfg.CONF CONF = cfg.CONF
@ -76,30 +78,29 @@ def get_endpoint_for_project(service_name=None, service_type=None):
service_catalog = obtain_service_catalog(ctx) service_catalog = obtain_service_catalog(ctx)
catalog = service_catalog.get_endpoints( service_endpoints = service_catalog.get_endpoints(
service_name=service_name, service_name=service_name,
service_type=service_type service_type=service_type
) )
endpoint = None endpoint = None
for service_type in catalog: for endpoints in six.itervalues(service_endpoints):
service = catalog.get(service_type) for ep in endpoints:
for interface in service:
# is V3 interface? # is V3 interface?
if 'interface' in interface: if 'interface' in ep:
interface_type = interface['interface'] interface_type = ep['interface']
if CONF.os_actions_endpoint_type in interface_type: if CONF.os_actions_endpoint_type in interface_type:
endpoint = ks_endpoints.Endpoint( endpoint = ks_endpoints.Endpoint(
None, None,
interface, ep,
loaded=True loaded=True
) )
break break
# is V2 interface? # is V2 interface?
if 'publicURL' in interface: if 'publicURL' in ep:
endpoint_data = { endpoint_data = {
'url': interface['publicURL'], 'url': ep['publicURL'],
'region': interface['region'] 'region': ep['region']
} }
endpoint = ks_endpoints.Endpoint( endpoint = ks_endpoints.Endpoint(
None, None,
@ -122,6 +123,7 @@ def get_endpoint_for_project(service_name=None, service_type=None):
def obtain_service_catalog(ctx): def obtain_service_catalog(ctx):
token = ctx.auth_token token = ctx.auth_token
if ctx.is_trust_scoped and is_token_trust_scoped(token): if ctx.is_trust_scoped and is_token_trust_scoped(token):
if ctx.trust_id is None: if ctx.trust_id is None:
raise Exception( raise Exception(
@ -134,22 +136,29 @@ def obtain_service_catalog(ctx):
include_catalog=True include_catalog=True
)['token'] )['token']
else: else:
if not ctx.target_service_catalog: response = ctx.service_catalog
# Target service catalog may not be passed via API.
if not response and ctx.is_target:
response = client().tokens.get_token_data( response = client().tokens.get_token_data(
token, token,
include_catalog=True)['token'] include_catalog=True
else: )['token']
response = ctx.target_service_catalog
if not response:
raise exceptions.UnauthorizedException()
service_catalog = ks_service_catalog.ServiceCatalog.factory(response) service_catalog = ks_service_catalog.ServiceCatalog.factory(response)
return service_catalog return service_catalog
def get_keystone_endpoint_v2(): def get_keystone_endpoint_v2():
return get_endpoint_for_project('keystone') return get_endpoint_for_project('keystone', service_type='identity')
def get_keystone_url_v2(): def get_keystone_url_v2():
return get_endpoint_for_project('keystone').url return get_endpoint_for_project('keystone', service_type='identity').url
def format_url(url_template, values): def format_url(url_template, values):