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