From df55840009c9bcac52a0e1a99faabc885e8a9052 Mon Sep 17 00:00:00 2001 From: Kirill Izotov Date: Fri, 28 Feb 2014 15:45:40 +0700 Subject: [PATCH] Made keystone authentication optional You need to supply auth_url to authenticate using Keystone. Otherwise, auth_token, user_id, project_id and mistral_url provided will be directly transmitted to HTTPClient. Also: * renamed input_auth_token as auth_token * optimized few checks * added checks to prevent header update when not needed * simplified API test setUp Change-Id: I1b34282956d21a1809ec37b0368fbb68aa113bea Implements: blueprint mistral-optional-keystone-authentication --- mistralclient/api/client.py | 85 ++++++++++++++++++--------------- mistralclient/api/httpclient.py | 13 +++-- mistralclient/shell.py | 4 +- mistralclient/tests/base.py | 5 +- 4 files changed, 59 insertions(+), 48 deletions(-) diff --git a/mistralclient/api/client.py b/mistralclient/api/client.py index 386b2816..e6195ebe 100644 --- a/mistralclient/api/client.py +++ b/mistralclient/api/client.py @@ -29,19 +29,23 @@ class Client(object): def __init__(self, mistral_url=None, username=None, api_key=None, project_name=None, auth_url=None, project_id=None, endpoint_type='publicURL', service_type='workflow', - input_auth_token=None): + auth_token=None, user_id=None): - (mistral_url, - token, - project_id, - user_id) = self.authenticate(mistral_url, username, - api_key, project_name, - auth_url, project_id, - endpoint_type, service_type, - input_auth_token) + if mistral_url and not isinstance(mistral_url, six.string_types): + raise RuntimeError('Mistral url should be string') + + if auth_url: + (mistral_url, auth_token, project_id, user_id) = \ + self.authenticate(mistral_url, username, api_key, + project_name, auth_url, project_id, + endpoint_type, service_type, auth_token, + user_id) + + if not mistral_url: + mistral_url = "http://localhost:8989/v1" self.http_client = httpclient.HTTPClient(mistral_url, - token, + auth_token, project_id, user_id) # Create all resource managers. @@ -53,34 +57,42 @@ class Client(object): def authenticate(self, mistral_url=None, username=None, api_key=None, project_name=None, auth_url=None, project_id=None, endpoint_type='publicURL', service_type='workflow', - input_auth_token=None): - if mistral_url and not isinstance(mistral_url, six.string_types): - raise RuntimeError('Mistral url should be string') - if ((isinstance(project_name, six.string_types) and project_name) or - (isinstance(project_id, six.string_types) and project_id)): - if project_name and project_id: - raise RuntimeError('Only project name or ' - 'project id should be set') + auth_token=None, user_id=None): - if "v2.0" in auth_url: - raise RuntimeError('Mistral supports only v3 ' - 'keystone API.') + if (not (project_name or project_id) or + not (isinstance(project_name, six.string_types) or + isinstance(project_id, six.string_types))): + raise RuntimeError('Either project name or project id should' + ' be non-empty string') + if project_name and project_id: + raise RuntimeError('Only project name or ' + 'project id should be set') - keystone = keystone_client.Client(username=username, - password=api_key, - token=input_auth_token, - tenant_id=project_id, - tenant_name=project_name, - auth_url=auth_url) + if (not (username or user_id) or + not (isinstance(username, six.string_types) or + isinstance(user_id, six.string_types))): + raise RuntimeError('Either user name or user id should' + ' be non-empty string') + if username and user_id: + raise RuntimeError('Only user name or user id' + ' should be set') - keystone.authenticate() - token = keystone.auth_token - user_id = keystone.user_id - if project_name and not project_id: - project_id = keystone.project_id - else: - raise RuntimeError('Project name or project id should' - ' not be empty and should be non-empty string') + if "v2.0" in auth_url: + raise RuntimeError('Mistral supports only v3 ' + 'keystone API.') + + keystone = keystone_client.Client(username=username, + user_id=user_id, + password=api_key, + token=auth_token, + project_id=project_id, + project_name=project_name, + auth_url=auth_url) + + keystone.authenticate() + token = keystone.auth_token + user_id = keystone.user_id + project_id = keystone.project_id if not mistral_url: catalog = keystone.service_catalog.get_endpoints(service_type) @@ -90,7 +102,4 @@ class Client(object): mistral_url = endpoint break - if not mistral_url: - mistral_url = "http://localhost:8989/v1" - return mistral_url, token, project_id, user_id diff --git a/mistralclient/api/httpclient.py b/mistralclient/api/httpclient.py index 3a9bd5ec..6611cf58 100644 --- a/mistralclient/api/httpclient.py +++ b/mistralclient/api/httpclient.py @@ -18,7 +18,7 @@ import requests class HTTPClient(object): - def __init__(self, base_url, token, project_id, user_id): + def __init__(self, base_url, token=None, project_id=None, user_id=None): self.base_url = base_url self.token = token self.project_id = project_id @@ -51,12 +51,17 @@ class HTTPClient(object): def _update_headers(self, headers): if not headers: headers = {} + token = headers.get('x-auth-token', self.token) - headers['x-auth-token'] = token + if token: + headers['x-auth-token'] = token project_id = headers.get('X-Project-Id', self.project_id) - headers['X-Project-Id'] = project_id + if project_id: + headers['X-Project-Id'] = project_id user_id = headers.get('X-User-Id', self.user_id) - headers['X-User-Id'] = user_id + if user_id: + headers['X-User-Id'] = user_id + return headers diff --git a/mistralclient/shell.py b/mistralclient/shell.py index 30eccdfd..f5fdff01 100644 --- a/mistralclient/shell.py +++ b/mistralclient/shell.py @@ -176,7 +176,7 @@ class MistralShell(App): '--os-auth-url', action='store', dest='auth_url', - default=env('OS_AUTH_URL', default='http://localhost:5000/v3'), + default=env('OS_AUTH_URL'), help='Authentication URL (Env: OS_AUTH_URL)' ) return parser @@ -190,7 +190,7 @@ class MistralShell(App): project_id=self.options.tenant_id, endpoint_type='publicURL', service_type='workflow', - input_auth_token=self.options.token) + auth_token=self.options.token) def main(argv=sys.argv[1:]): diff --git a/mistralclient/tests/base.py b/mistralclient/tests/base.py index 7688b6c3..3ffdff1a 100644 --- a/mistralclient/tests/base.py +++ b/mistralclient/tests/base.py @@ -33,11 +33,8 @@ class FakeResponse(object): class BaseClientTest(unittest2.TestCase): - @mock.patch('keystoneclient.v3.client.Client') - def setUp(self, keystone): - keystone.return_value = mock.Mock() + def setUp(self): self._client = client.Client(project_name="test", - auth_url="v3.0", mistral_url="test") self.workbooks = self._client.workbooks self.executions = self._client.executions