diff --git a/mistral/context.py b/mistral/context.py index e00add9d3..999a6f5bb 100644 --- a/mistral/context.py +++ b/mistral/context.py @@ -128,20 +128,55 @@ def spawn(thread_description, func, *args, **kwargs): def context_from_headers(headers): + params = _extract_auth_params_from_headers(headers) + auth_cacert = params['auth_cacert'] + auth_token = params['auth_token'] + auth_uri = params['auth_uri'] + project_id = params['project_id'] + user_id = params['user_id'] + user_name = params['user_name'] + return MistralContext( - auth_uri=CONF.keystone_authtoken.auth_uri, - auth_cacert=CONF.keystone_authtoken.cafile, - user_id=headers.get('X-User-Id'), - project_id=headers.get('X-Project-Id'), - auth_token=headers.get('X-Auth-Token'), + auth_uri=auth_uri, + auth_cacert=auth_cacert, + user_id=user_id, + project_id=project_id, + auth_token=auth_token, service_catalog=headers.get('X-Service-Catalog'), - user_name=headers.get('X-User-Name'), + user_name=user_name, project_name=headers.get('X-Project-Name'), roles=headers.get('X-Roles', "").split(","), is_trust_scoped=False, ) +def _extract_auth_params_from_headers(headers): + if headers.get("X-Target-Auth-Uri"): + params = { + # TODO(akovi): Target cert not handled yet + 'auth_cacert': None, + 'auth_token': headers.get('X-Target-Auth-Token'), + 'auth_uri': headers.get('X-Target-Auth-Uri'), + 'project_id': headers.get('X-Target-Project-Id'), + 'user_id': headers.get('X-Target-User-Id'), + 'user_name': headers.get('X-Target-User-Name'), + } + if not params['auth_token']: + raise (exc.MistralException( + 'Target auth URI (X-Target-Auth-Uri) target auth token ' + '(X-Target-Auth-Token) must be present')) + else: + params = { + 'auth_cacert': CONF.keystone_authtoken.cafile, + 'auth_token': headers.get('X-Auth-Token'), + 'auth_uri': CONF.keystone_authtoken.auth_uri, + 'project_id': headers.get('X-Project-Id'), + 'user_id': headers.get('X-User-Id'), + 'user_name': headers.get('X-User-Name'), + } + return params + + def context_from_config(): keystone = keystone_client.Client( username=CONF.keystone_authtoken.admin_user, diff --git a/mistral/utils/openstack/keystone.py b/mistral/utils/openstack/keystone.py index db29f3d8d..212677392 100644 --- a/mistral/utils/openstack/keystone.py +++ b/mistral/utils/openstack/keystone.py @@ -27,7 +27,7 @@ def client(): auth_url = ctx.auth_uri cl = ks_client.Client( - username=ctx.user_name, + user_id=ctx.user_id, token=ctx.auth_token, tenant_id=ctx.project_id, auth_url=auth_url diff --git a/mistral_tempest_tests/services/v2/mistral_client.py b/mistral_tempest_tests/services/v2/mistral_client.py index f9c8c4bc6..eeb4fbff4 100644 --- a/mistral_tempest_tests/services/v2/mistral_client.py +++ b/mistral_tempest_tests/services/v2/mistral_client.py @@ -29,9 +29,9 @@ class MistralClientV2(base.MistralClientBase): return self.post(url, base.get_resource(file_name), headers=headers) - def post_json(self, url, obj): + def post_json(self, url, obj, extra_headers={}): headers = {"Content-Type": "application/json"} - + headers = dict(headers, **extra_headers) return self.post(url, json.dumps(obj), headers=headers) def update_request(self, url, file_name): @@ -129,8 +129,10 @@ class MistralClientV2(base.MistralClientBase): return [t for t in all_tasks if t['workflow_name'] == wf_name] - def create_action_execution(self, request_body): - resp, body = self.post_json('action_executions', request_body) + def create_action_execution(self, request_body, extra_headers={}): + resp, body = self.post_json('action_executions', + request_body, + extra_headers) params = json.loads(request_body.get('params', '{}')) if params.get('save_result', False): diff --git a/mistral_tempest_tests/tests/scenario/engine/actions/v2/test_multi_vim_authentication.py b/mistral_tempest_tests/tests/scenario/engine/actions/v2/test_multi_vim_authentication.py new file mode 100644 index 000000000..c6aa77e9d --- /dev/null +++ b/mistral_tempest_tests/tests/scenario/engine/actions/v2/test_multi_vim_authentication.py @@ -0,0 +1,67 @@ +# Copyright 2016 - Nokia, Inc. +# +# 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 json +from mistral_tempest_tests.tests import base +from tempest import test +from urlparse import urlparse +import uuid + + +class MultiVimActionsTests(base.TestCase): + _service = 'workflowv2' + + @classmethod + def resource_setup(cls): + super(MultiVimActionsTests, cls).resource_setup() + + @test.attr(type='openstack') + def test_multi_vim_support(self): + + client_1 = self.alt_client + client_2 = self.client + + stack_name = 'multi_vim_test_stack_{}'.format(str(uuid.uuid4())[:8]) + create_request = { + 'name': 'heat.stacks_create', + 'input': { + 'stack_name': stack_name, + "template": {"heat_template_version": "2013-05-23"} + } + } + _, body = client_2.create_action_execution(create_request) + stack_id = str(json.loads(body['output'])['result']['stack']['id']) + + u = urlparse(client_2.auth_provider.auth_url) + v3_auth_url = '{}://{}/identity/v3/'.format(u.scheme, u.netloc) + extra_headers = { + 'X-Target-Auth-Token': client_2.token, + 'X-Target-Auth-Uri': v3_auth_url, + 'X-Target-Project-Id': client_2.tenant_id, + 'X-Target-User-Id': client_2.user_id, + 'X-Target-User-Name': client_2.user, + } + + list_request = { + 'name': 'heat.stacks_list', + } + + _, body = client_1.create_action_execution(list_request) + self.assertEmpty(json.loads(body['output'])['result']) + + _, body = client_1.create_action_execution(list_request, + extra_headers=extra_headers) + self.assertEqual( + stack_id, + str(json.loads(body['output'])['result'][0]['id']) + )