From 669ab5c8302b92017658a8d388e5ba60539cd046 Mon Sep 17 00:00:00 2001 From: Paul Glass Date: Mon, 20 Apr 2015 20:14:57 +0000 Subject: [PATCH] Functional tests: minus tempest, plus noauth support * Functional tests no longer need tempest installed * Functional tests can run against a Keystone-less environment Change-Id: I2c2603b7207bfa09bb96ad180b959e4164096858 --- contrib/devstack/run_tempest_tests.sh | 2 + doc/source/tempest.rst | 15 ++++--- functionaltests/common/client.py | 36 +++++++++++----- functionaltests/common/config.py | 60 ++++++++++++++++++++++++++ functionaltests/common/noauth.py | 61 +++++++++++++++++++++++++++ 5 files changed, 156 insertions(+), 18 deletions(-) create mode 100644 functionaltests/common/config.py create mode 100644 functionaltests/common/noauth.py diff --git a/contrib/devstack/run_tempest_tests.sh b/contrib/devstack/run_tempest_tests.sh index c81eef82c..2f7cabf64 100755 --- a/contrib/devstack/run_tempest_tests.sh +++ b/contrib/devstack/run_tempest_tests.sh @@ -29,6 +29,8 @@ TEMPEST_DIR=${TEMPEST_DIR:-/opt/stack/new/tempest} # Install tempest pip install -e $TEMPEST_DIR +export TEMPEST_CONFIG=$TEMPEST_DIR/etc/tempest.conf + pushd $DESIGNATE_DIR/functionaltests # run the tests in parallel diff --git a/doc/source/tempest.rst b/doc/source/tempest.rst index 34ddd22ff..baf80c52a 100644 --- a/doc/source/tempest.rst +++ b/doc/source/tempest.rst @@ -14,10 +14,6 @@ The tests depend on both ``tempest-lib`` and ``tempest``: :: - # install tempest - git clone https://github.com/openstack/tempest.git - pip install tempest/ - # tempest-lib is in test-requirements.txt cd designate pip install -r requirements.txt -r test-requirements.txt @@ -26,9 +22,9 @@ The tests depend on both ``tempest-lib`` and ``tempest``: Configuration ============= -The Tempest tests look for the file ``functionaltests/designate-tempest.conf``, -which contains information about your Keystone setup. For the time being, these -tests require Keystone. +The Tempest tests look for the ``TEMPEST_CONFIG`` environment variable, or the +file ``tempest.conf`` in the current directory which contains the config below. +Set ``use_noauth=True`` to hit a Designate endpoint without Keystone. :: @@ -49,6 +45,11 @@ tests require Keystone. admin_password=password admin_domain_name=Default + [noauth] + use_noauth=False + designate_endpoint=http://127.0.0.1:9001 + tenant_id='noauth-project' + Execution ========= diff --git a/functionaltests/common/client.py b/functionaltests/common/client.py index a10b0c375..3557a9b15 100644 --- a/functionaltests/common/client.py +++ b/functionaltests/common/client.py @@ -15,23 +15,37 @@ limitations under the License. """ from tempest_lib.common.rest_client import RestClient -from tempest.auth import KeystoneV2Credentials -from tempest.config import CONF -import tempest.manager +from tempest_lib.auth import KeystoneV2Credentials +from tempest_lib.auth import KeystoneV2AuthProvider +from config import cfg +from noauth import NoAuthAuthProvider class DesignateClient(RestClient): def __init__(self): - creds = KeystoneV2Credentials( - username=CONF.identity.admin_username, - password=CONF.identity.admin_password, - tenant_name=CONF.identity.admin_tenant_name, - ) - auth_provider = tempest.manager.get_auth_provider(creds) - auth_provider.fill_credentials() + if cfg.CONF.noauth.use_noauth: + auth_provider = self._get_noauth_auth_provider() + else: + auth_provider = self._get_keystone_auth_provider() super(DesignateClient, self).__init__( auth_provider=auth_provider, service='dns', - region=CONF.identity.region, + region=cfg.CONF.identity.region, ) + + def _get_noauth_auth_provider(self): + creds = KeystoneV2Credentials( + tenant_id=cfg.CONF.noauth.tenant_id, + ) + return NoAuthAuthProvider(creds, cfg.CONF.noauth.designate_endpoint) + + def _get_keystone_auth_provider(self): + creds = KeystoneV2Credentials( + username=cfg.CONF.identity.admin_username, + password=cfg.CONF.identity.admin_password, + tenant_name=cfg.CONF.identity.admin_tenant_name, + ) + auth_provider = KeystoneV2AuthProvider(creds, cfg.CONF.identity.uri) + auth_provider.fill_credentials() + return auth_provider diff --git a/functionaltests/common/config.py b/functionaltests/common/config.py new file mode 100644 index 000000000..a773e81fe --- /dev/null +++ b/functionaltests/common/config.py @@ -0,0 +1,60 @@ +""" +Copyright 2015 Rackspace + +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 os + +from oslo.config import cfg + +cfg.CONF.register_group(cfg.OptGroup( + name='identity', title="Configuration for Keystone auth" +)) + +cfg.CONF.register_group(cfg.OptGroup( + name='noauth', title="Configuration to run tests without Keystone" +)) + +cfg.CONF.register_opts([ + cfg.StrOpt('designate_endpoint_override', + help="Endpoint to use to bypass Keystone auth"), + + cfg.StrOpt('uri', help="The Keystone v2 endpoint"), + cfg.StrOpt('uri_v3', help="The Keystone v3 endpoint"), + cfg.StrOpt('auth_version', default='v2'), + cfg.StrOpt('region', default='RegionOne'), + + cfg.StrOpt('username'), + cfg.StrOpt('tenant_name'), + cfg.StrOpt('password', secret=True), + cfg.StrOpt('domain_name'), + + cfg.StrOpt('admin_username'), + cfg.StrOpt('admin_tenant_name'), + cfg.StrOpt('admin_password', secret=True), + cfg.StrOpt('admin_domain_name'), +], group='identity') + +cfg.CONF.register_opts([ + cfg.StrOpt('designate_endpoint', help="The Designate API endpoint"), + cfg.StrOpt('tenant_id', default='noauth-project'), + cfg.BoolOpt('use_noauth', default=False), +], group='noauth') + + +def find_config_file(): + return os.environ.get('TEMPEST_CONFIG', 'tempest.conf') + + +cfg.CONF(args=[], default_config_files=[find_config_file()]) diff --git a/functionaltests/common/noauth.py b/functionaltests/common/noauth.py new file mode 100644 index 000000000..72e107379 --- /dev/null +++ b/functionaltests/common/noauth.py @@ -0,0 +1,61 @@ +""" +Copyright 2015 Rackspace + +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 copy +import urlparse +import re + +from tempest_lib.auth import AuthProvider + + +class NoAuthAuthProvider(AuthProvider): + + def __init__(self, creds, override_url): + super(NoAuthAuthProvider, self).__init__(creds) + self.override_url = override_url + + @classmethod + def check_credentials(cls, credentials): + return True + + def base_url(self, *args, **kwargs): + return self.override_url + + def _decorate_request(self, filters, method, url, headers=None, body=None, + auth_data=None): + base_url = self.base_url(filters=filters, auth_data=auth_data) + # build the unauthenticated request + _headers = copy.deepcopy(headers) if headers is not None else {} + _headers['X-Auth-Project-ID'] = self.credentials.tenant_id + if url is None or url == "": + _url = base_url + else: + # Join base URL and url, and remove multiple contiguous slashes + _url = "/".join([base_url, url]) + parts = [x for x in urlparse.urlparse(_url)] + parts[2] = re.sub("/{2,}", "/", parts[2]) + _url = urlparse.urlunparse(parts) + # no change to method or body + return str(_url), _headers, body + + def _get_auth(self): + return None + + def is_expired(self): + return False + + def _fill_credentials(self): + pass