diff --git a/.gitignore b/.gitignore index 99c9ee5b..cd36ef49 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ *.py[cod] *.pyc +cirros* +tempest.conf # Packages *.egg* diff --git a/README.rst b/README.rst index 4a5f485e..100ed764 100644 --- a/README.rst +++ b/README.rst @@ -83,3 +83,27 @@ RPM Installation (RDO) ``config_tempest.py`` script and it **accepts the same parameters.** More about new features can be found `here `__ + + +os-client-config support +~~~~~~~~~~~~~~~~~~~~~~~~ + +python-tempestconf supports `os-client-config `__ +so instead of sourcing openstackrc files you can use clouds.yml files. Location where +these files should be stored and syntax which is used to specify cloud.yaml files +can be found `here `__ + +In case of git usage: + +.. code-block:: shell-session + + (py27) $ python config_tempest/config_tempest.py --debug --create --os-cloud + +In case of RPM: + +.. code-block:: shell-session + + $ tempest init testingdir + $ cd testingdir + $ discover-tempest-config --debug --create --os-cloud + diff --git a/config_tempest/config_tempest.py b/config_tempest/config_tempest.py index c0384772..26daec05 100755 --- a/config_tempest/config_tempest.py +++ b/config_tempest/config_tempest.py @@ -42,6 +42,8 @@ import sys import tempest.config import urllib2 +import os_client_config +from oslo_config import cfg from tempest.common import identity from tempest.lib import auth from tempest.lib import exceptions @@ -131,7 +133,11 @@ def main(): conf.set(section, key, value, priority=True) for section, key, value in args.overrides: conf.set(section, key, value, priority=True) - uri = conf.get("identity", "uri") + if conf.has_option("identity", "uri"): + uri = conf.get("identity", "uri") + else: + uri = args.config['auth'].get('auth_url') + conf.set("identity", "uri", uri) api_version = 2 v3_only = False if "v3" in uri and v3_only: @@ -149,7 +155,7 @@ def main(): conf.set("auth", "allow_tenant_isolation", "False") if args.use_test_accounts: conf.set("auth", "allow_tenant_isolation", "True") - clients = ClientManager(conf, not args.non_admin) + clients = ClientManager(conf, not args.non_admin, args) swift_discover = conf.get_defaulted('object-storage-feature-enabled', 'discoverability') services = api_discovery.discover( @@ -189,7 +195,9 @@ def main(): def parse_arguments(): # TODO(tkammer): add mutual exclusion groups + cloud_config = os_client_config.OpenStackConfig() parser = argparse.ArgumentParser(__doc__) + cloud_config.register_argparse_arguments(parser, sys.argv) parser.add_argument('--create', action='store_true', default=False, help='create default tempest resources') parser.add_argument('--out', default="etc/tempest.conf", @@ -235,14 +243,14 @@ def parse_arguments(): --remove feature-enabled.api_ext=http,https""") args = parser.parse_args() - if args.create and args.non_admin: raise Exception("Options '--create' and '--non-admin' cannot be used" " together, since creating" " resources requires" " admin rights") args.overrides = parse_overrides(args.overrides) args.remove = parse_values_to_remove(args.remove) - return args + cloud = cloud_config.get_one_cloud(argparse=args) + return cloud def parse_values_to_remove(options): @@ -343,16 +351,40 @@ class ClientManager(object): else: return "v2" - def __init__(self, conf, admin): + def __init__(self, conf, admin, args): self.identity_version = self.get_identity_version(conf) + username = None + password = None + tenant_name = None + os_client_creds = args.config.get('auth') + if os_client_creds: + username = os_client_creds.get('username') + password = os_client_creds.get('password') + tenant_name = os_client_creds.get('project_name') if admin: - username = conf.get_defaulted('identity', 'admin_username') - password = conf.get_defaulted('identity', 'admin_password') - tenant_name = conf.get_defaulted('identity', 'admin_tenant_name') + try: + username = conf.get_defaulted('identity', 'admin_username') + password = conf.get_defaulted('identity', 'admin_password') + tenant_name = conf.get_defaulted('identity', + 'admin_tenant_name') + except cfg.NoSuchOptError: + LOG.warning( + 'Could not load some identity admin options from %s', + DEFAULTS_FILE) else: - username = conf.get_defaulted('identity', 'username') - password = conf.get_defaulted('identity', 'password') - tenant_name = conf.get_defaulted('identity', 'tenant_name') + try: + # override values only when were set in CLI + if conf.has_option('identity', 'username'): + username = conf.get_defaulted('identity', 'username') + if conf.has_option('identity', 'password'): + password = conf.get_defaulted('identity', 'password') + if conf.has_option('identity', 'tenant_name'): + tenant_name = conf.get_defaulted('identity', 'tenant_name') + + except cfg.NoSuchOptError: + LOG.warning( + 'Could not load some identity options from %s', + DEFAULTS_FILE) self.identity_region = conf.get_defaulted('identity', 'region') default_params = { diff --git a/config_tempest/tests/base.py b/config_tempest/tests/base.py index fd1be934..8530efd4 100644 --- a/config_tempest/tests/base.py +++ b/config_tempest/tests/base.py @@ -19,7 +19,7 @@ from config_tempest import api_discovery as api from config_tempest import config_tempest as tool from fixtures import MonkeyPatch import json -from mock import Mock +import mock from oslotest import base @@ -44,9 +44,13 @@ class BaseConfigTempestTest(base.BaseTestCase): conf.set("auth", "allow_tenant_isolation", "False") return conf - def _get_clients(self, conf, admin=False): + @mock.patch('os_client_config.cloud_config.CloudConfig') + def _get_clients(self, conf, mock_args, admin=False): """Returns ClientManager instance""" - return tool.ClientManager(conf, admin=admin) + mock_function = mock.Mock(return_value=False) + func2mock = 'os_client_config.cloud_config.CloudConfig.config.get' + self.useFixture(MonkeyPatch(func2mock, mock_function)) + return tool.ClientManager(conf, admin=admin, args=mock_args) class BaseServiceTest(base.BaseTestCase): @@ -176,7 +180,7 @@ class BaseServiceTest(base.BaseTestCase): def _fake_service_do_get_method(self, fake_data): function2mock = 'config_tempest.api_discovery.Service.do_get' do_get_output = json.dumps(fake_data) - mocked_do_get = Mock() + mocked_do_get = mock.Mock() mocked_do_get.return_value = do_get_output self.useFixture(MonkeyPatch(function2mock, mocked_do_get)) diff --git a/config_tempest/tests/test_config_tempest.py b/config_tempest/tests/test_config_tempest.py index d807f041..28f4e0c9 100644 --- a/config_tempest/tests/test_config_tempest.py +++ b/config_tempest/tests/test_config_tempest.py @@ -102,7 +102,7 @@ class TestClientManager(BaseConfigTempestTest): mock_function = mock.Mock(return_value={"id": "my_fake_id"}) func2mock = 'config_tempest.config_tempest.identity.get_tenant_by_name' self.useFixture(MonkeyPatch(func2mock, mock_function)) - tool.ClientManager(self.conf, admin=True) + self._get_clients(self.conf, admin=True) # check if admin credentials were set admin_tenant = self.conf.get("identity", "admin_tenant_name") admin_password = self.conf.get("identity", "admin_password") @@ -114,6 +114,87 @@ class TestClientManager(BaseConfigTempestTest): self.assertEqual(admin_tenant_id, "my_fake_id") +class TestOsClientConfigSupport(BaseConfigTempestTest): + + def setUp(self): + super(TestOsClientConfigSupport, self).setUp() + self.conf = self._get_conf("v2.0", "v3") + + def _check_credentials(self, manager, username, password, tenant_name): + exp_user = manager.auth_provider.credentials._initial['username'] + exp_pass = manager.auth_provider.credentials._initial['password'] + exp_tenant = manager.auth_provider.credentials._initial['tenant_name'] + self.assertEqual(exp_user, username) + self.assertEqual(exp_pass, password) + self.assertEqual(exp_tenant, tenant_name) + + def _override_setup(self): + cloud_args = { + 'username': 'cloud_user', + 'password': 'cloud_pass', + 'project_name': 'cloud_project' + } + mock_function = mock.Mock(return_value=cloud_args) + func2mock = 'os_client_config.cloud_config.CloudConfig.config.get' + self.useFixture(MonkeyPatch(func2mock, mock_function)) + mock_function = mock.Mock(return_value={"id": "my_fake_id"}) + func2mock = 'config_tempest.config_tempest.identity.get_tenant_by_name' + self.useFixture(MonkeyPatch(func2mock, mock_function)) + + @mock.patch('os_client_config.cloud_config.CloudConfig') + def test_init_manager_client_config(self, mock_args): + cloud_args = { + 'username': 'cloud_user', + 'password': 'cloud_pass', + 'project_name': 'cloud_project' + } + mock_function = mock.Mock(return_value=cloud_args) + func2mock = 'os_client_config.cloud_config.CloudConfig.config.get' + self.useFixture(MonkeyPatch(func2mock, mock_function)) + # remove options, pretend like they aren't set in CLI + self.conf.remove_option('identity', 'username') + self.conf.remove_option('identity', 'password') + self.conf.remove_option('identity', 'tenant_name') + manager = tool.ClientManager(self.conf, admin=False, args=mock_args) + # check if cloud_args credentials were used + self._check_credentials(manager, + cloud_args['username'], + cloud_args['password'], + cloud_args['project_name']) + + @mock.patch('os_client_config.cloud_config.CloudConfig') + def test_init_manager_client_config_get_default(self, mock_args): + mock_function = mock.Mock(return_value={}) + func2mock = 'os_client_config.cloud_config.CloudConfig.config.get' + self.useFixture(MonkeyPatch(func2mock, mock_function)) + manager = tool.ClientManager(self.conf, admin=False, args=mock_args) + # cloud_args is empty => check if default credentials were used + self._check_credentials(manager, + self.conf.get('identity', 'username'), + self.conf.get('identity', 'password'), + self.conf.get('identity', 'tenant_name')) + + @mock.patch('os_client_config.cloud_config.CloudConfig') + def test_init_manager_client_config_override(self, mock_args): + self._override_setup() + manager = tool.ClientManager(self.conf, admin=False, args=mock_args) + # check if cloud_args credentials were overrided by the ones set in CLI + self._check_credentials(manager, + self.conf.get('identity', 'username'), + self.conf.get('identity', 'password'), + self.conf.get('identity', 'tenant_name')) + + @mock.patch('os_client_config.cloud_config.CloudConfig') + def test_init_manager_client_config_admin_override(self, mock_args): + self._override_setup() + manager = tool.ClientManager(self.conf, admin=True, args=mock_args) + # check if cloud_args credentials were overrided by admin ones + self._check_credentials(manager, + self.conf.get('identity', 'admin_username'), + self.conf.get('identity', 'admin_password'), + self.conf.get('identity', 'admin_tenant_name')) + + class TestTempestConf(BaseConfigTempestTest): def setUp(self): super(TestTempestConf, self).setUp() diff --git a/releasenotes/notes/add-os_client_config_support-dd093b137edd8c91.yaml b/releasenotes/notes/add-os_client_config_support-dd093b137edd8c91.yaml new file mode 100644 index 00000000..a9f45d11 --- /dev/null +++ b/releasenotes/notes/add-os_client_config_support-dd093b137edd8c91.yaml @@ -0,0 +1,8 @@ +--- +features: + - | + Enable os-client-config support [1]. + The tempest config tool now is able to support os-client-config env vars + and cloud.yaml support. + + [1] https://github.com/openstack/os-client-config diff --git a/requirements.txt b/requirements.txt index 92d29e7d..f0724399 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,3 +6,5 @@ pbr>=1.8 # Apache-2.0 tempest>=14.0.0 # Apache-2.0 requests>=2.10.0,!=2.12.2 # Apache-2.0 os-testr>=0.8.0 # Apache-2.0 +os-client-config>=1.26.0 # Apache-2.0 +oslo_config>=3.23.0 # Apache-2.0