Extend existing@openstack platform with cert keys

* add support for https_cert and https_key options
* also fix some small issues which appeared after forsing
  using credentials object inside the osclients

Change-Id: Icc885a8b21fd7725009f871c7713a5ce98b60ddb
This commit is contained in:
Andrey Kurilin 2018-08-22 18:10:18 +03:00
parent faedcbcb18
commit 230ade51af
14 changed files with 101 additions and 61 deletions

View File

@ -23,6 +23,10 @@ Added
~~~~~
* Support Python 3.7 environment.
* ``https_cert`` and ``https_key`` options of the spec for
``existing@openstack`` platform to represent client certificate bundle and
key files. Also the support for appropriate system environment variables (
``OS_CERT``, ``OS_KEY``) is added.
Changed
~~~~~~~

View File

@ -14,7 +14,6 @@
# under the License.
from rally.common import logging
from rally_openstack import osclients
LOG = logging.getLogger(__file__)
@ -28,7 +27,7 @@ class OpenStackCredential(dict):
region_name=None, endpoint_type=None,
domain_name=None, endpoint=None, user_domain_name=None,
project_domain_name=None,
https_insecure=False, https_cacert=None,
https_insecure=False, https_cacert=None, https_cert=None,
profiler_hmac_key=None, profiler_conn_str=None, **kwargs):
if kwargs:
raise TypeError("%s" % kwargs)
@ -49,6 +48,7 @@ class OpenStackCredential(dict):
("project_domain_name", project_domain_name),
("https_insecure", https_insecure),
("https_cacert", https_cacert),
("https_cert", https_cert),
("profiler_hmac_key", profiler_hmac_key),
("profiler_conn_str", profiler_conn_str)
])
@ -70,5 +70,7 @@ class OpenStackCredential(dict):
# this method is mostly used by validation step. let's refactor it and
# deprecated this
def clients(self, api_info=None):
from rally_openstack import osclients
return osclients.Clients(self, api_info=api_info,
cache=self._clients_cache)

View File

@ -0,0 +1,23 @@
# All Rights Reserved.
#
# 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.
from rally import exceptions as rally_exceptions
RallyException = rally_exceptions.RallyException
class AuthenticationFailed(rally_exceptions.InvalidArgumentsException):
error_code = 220
msg_fmt = ("Failed to authenticate to %(url)s for user '%(username)s'"
" in project '%(project)s': %(etype)s: %(error)s")

View File

@ -20,11 +20,11 @@ from rally.cli import envutils
from rally.common import cfg
from rally.common import logging
from rally.common.plugin import plugin
from rally.common import utils
from rally import exceptions
from six.moves.urllib import parse
from rally_openstack import consts
from rally_openstack import credential as oscred
LOG = logging.getLogger(__name__)
@ -105,12 +105,12 @@ def configure(name, default_version=None, default_service_type=None,
@plugin.base()
class OSClient(plugin.Plugin):
"""Base class for openstack clients"""
"""Base class for OpenStack clients"""
def __init__(self, credential, api_info, cache_obj):
self.credential = credential
if isinstance(self.credential, dict):
self.credential = utils.Struct(**self.credential)
if not isinstance(self.credential, oscred.OpenStackCredential):
self.credential = oscred.OpenStackCredential(**self.credential)
self.api_info = api_info
self.cache = cache_obj
@ -187,13 +187,6 @@ class OSClient(plugin.Plugin):
return OSClient.get("keystone")(self.credential, self.api_info,
self.cache)
def _get_session(self, auth_url=None, version=None):
LOG.warning(
"Method `rally.osclient.OSClient._get_session` is deprecated since"
" Rally 0.6.0. Use "
"`rally.osclient.OSClient.keystone.get_session` instead.")
return self.keystone.get_session(version)
def _get_endpoint(self, service_type=None):
kw = {"service_type": self.choose_service_type(service_type),
"region_name": self.credential.region_name}
@ -317,13 +310,13 @@ class Keystone(OSClient):
temp_session = session.Session(
verify=(self.credential.https_cacert or
not self.credential.https_insecure),
cert=self.credential.https_cert,
timeout=CONF.openstack_client_http_timeout)
version = str(discover.Discover(
temp_session,
password_args["auth_url"]).version_data()[0]["version"][0])
if "v2.0" not in password_args["auth_url"] and (
version != "2"):
if "v2.0" not in password_args["auth_url"] and version != "2":
password_args.update({
"user_domain_name": self.credential.user_domain_name,
"domain_name": self.credential.domain_name,
@ -334,6 +327,7 @@ class Keystone(OSClient):
auth=identity_plugin,
verify=(self.credential.https_cacert or
not self.credential.https_insecure),
cert=self.credential.https_cert,
timeout=CONF.openstack_client_http_timeout)
self.cache[key] = (sess, identity_plugin)
return self.cache[key]

View File

@ -72,6 +72,8 @@ class OpenStack(platform.Platform):
"endpoint_type": {"enum": ["public", "internal", "admin", None]},
"https_insecure": {"type": "boolean"},
"https_cacert": {"type": "string"},
"https_cert": {"type": "string"},
"https_key": {"type": "string"},
"profiler_hmac_key": {"type": ["string", "null"]},
"profiler_conn_str": {"type": ["string", "null"]},
"admin": {"$ref": "#/definitions/user"},
@ -114,6 +116,10 @@ class OpenStack(platform.Platform):
admin = new_data.pop("admin", None)
users = new_data.pop("users", [])
if new_data.get("https_cert") and new_data.get("https_key"):
new_data["https_cert"] = (new_data["https_cert"],
new_data.pop("https_key"))
if admin:
if "project_name" in admin:
admin["tenant_name"] = admin.pop("project_name")
@ -240,6 +246,8 @@ class OpenStack(platform.Platform):
"endpoint_type": endpoint_type,
"region_name": sys_environ.get("OS_REGION_NAME", ""),
"https_cacert": sys_environ.get("OS_CACERT", ""),
"https_cert": sys_environ.get("OS_CERT", ""),
"https_key": sys_environ.get("OS_KEY", ""),
"https_insecure": strutils.bool_from_string(
sys_environ.get("OS_INSECURE")),
"profiler_hmac_key": sys_environ.get("OSPROFILER_HMAC_KEY"),

View File

@ -153,7 +153,7 @@
- name: Check Environment works
become: True
become_user: stack
command: "rally env check"
command: "rally --debug env check"
- name: Print Environment info
become: True

View File

@ -16,6 +16,7 @@ import mock
from rally import exceptions
from rally_openstack.contexts.sahara import sahara_image
from tests.unit import fakes
from tests.unit import test
@ -42,7 +43,7 @@ class SaharaImageTestCase(test.ScenarioTestCase):
for j in range(self.users_per_tenant):
self.users_key.append({"id": "%s_%s" % (str(i), str(j)),
"tenant_id": str(i),
"credential": mock.MagicMock()})
"credential": fakes.FakeCredential()})
@property
def url_image_context(self):
@ -59,7 +60,7 @@ class SaharaImageTestCase(test.ScenarioTestCase):
"username": "test_user"
}
},
"admin": {"credential": mock.MagicMock()},
"admin": {"credential": fakes.FakeCredential()},
"users": self.users_key,
"tenants": self.tenants
})
@ -77,7 +78,7 @@ class SaharaImageTestCase(test.ScenarioTestCase):
"image_uuid": "some_id"
}
},
"admin": {"credential": mock.MagicMock()},
"admin": {"credential": fakes.FakeCredential()},
"users": self.users_key,
"tenants": self.tenants,
})

View File

@ -33,6 +33,7 @@ import six
from swiftclient import exceptions as swift_exceptions
from rally_openstack import consts
from rally_openstack import credential
def generate_uuid():
@ -83,12 +84,13 @@ def setup_dict(data, required=None, defaults=None):
return defaults
def fake_credential(**config):
m = mock.Mock()
m.to_dict.return_value = config
for key, value in config.items():
setattr(m, key, value)
return m
class FakeCredential(credential.OpenStackCredential):
def __init__(self, **creds):
creds.setdefault("auth_url", "https://example.com")
creds.setdefault("username", "admin")
creds.setdefault("password", "pass")
super(FakeCredential, self).__init__(**creds)
self.clients = mock.Mock()
class FakeResource(object):
@ -1610,7 +1612,7 @@ class FakeClients(object):
self._ec2 = None
self._senlin = None
self._watcher = None
self._credential = credential_ or fake_credential(
self._credential = credential_ or FakeCredential(
auth_url="http://fake.example.org:5000/v2.0/",
username="fake_username",
password="fake_password",
@ -1827,7 +1829,7 @@ class FakeUserContext(FakeContext):
admin = {
"id": "adminuuid",
"credential": fake_credential(
"credential": FakeCredential(
auth_url="aurl",
username="aname",
password="apwd",
@ -1835,7 +1837,7 @@ class FakeUserContext(FakeContext):
}
user = {
"id": "uuid",
"credential": fake_credential(
"credential": FakeCredential(
auth_url="url",
username="name",
password="pwd",

View File

@ -155,8 +155,10 @@ class ExistingPlatformTestCase(PlatformBaseTestCase):
"OS_INTERFACE": "publicURL",
"OS_REGION_NAME": "Region1",
"OS_CACERT": "Cacert",
"OS_CERT": "cert",
"OS_KEY": "key",
"OS_INSECURE": True,
"OSPROFILER_HMAC_KEY": "key",
"OSPROFILER_HMAC_KEY": "hmackey",
"OSPROFILER_CONN_STR": "https://example2.com",
}
@ -173,8 +175,10 @@ class ExistingPlatformTestCase(PlatformBaseTestCase):
"endpoint_type": "public",
"region_name": "Region1",
"https_cacert": "Cacert",
"https_cert": "cert",
"https_key": "key",
"https_insecure": True,
"profiler_hmac_key": "key",
"profiler_hmac_key": "hmackey",
"profiler_conn_str": "https://example2.com"
}, result["spec"])
@ -182,7 +186,7 @@ class ExistingPlatformTestCase(PlatformBaseTestCase):
sys_env["OS_IDENTITY_API_VERSION"] = "3"
result = existing.OpenStack.create_spec_from_sys_environ(sys_env)
print(json.dumps(result["spec"], indent=4))
self.assertEqual(
{
"admin": {
@ -196,8 +200,10 @@ class ExistingPlatformTestCase(PlatformBaseTestCase):
"auth_url": "https://example.com",
"region_name": "Region1",
"https_cacert": "Cacert",
"https_cert": "cert",
"https_key": "key",
"https_insecure": True,
"profiler_hmac_key": "key",
"profiler_hmac_key": "hmackey",
"profiler_conn_str": "https://example2.com"
}, result["spec"])

View File

@ -15,6 +15,7 @@
import mock
from rally_openstack import credential
from rally_openstack.scenarios.cinder import utils
from tests.unit import test
@ -23,13 +24,17 @@ class CinderBasicTestCase(test.ScenarioTestCase):
def _get_context(self):
context = test.get_test_context()
cred = credential.OpenStackCredential(auth_url="url",
username="user",
password="pass")
context.update({
"admin": {
"id": "fake_user_id",
"credential": mock.MagicMock()
"credential": cred
},
"user": {"id": "fake_user_id",
"credential": mock.MagicMock()},
"credential": cred},
"tenant": {"id": "fake", "name": "fake",
"volumes": [{"id": "uuid", "size": 1}],
"servers": [1]}})

View File

@ -39,6 +39,7 @@ class OpenStackCredentialTestCase(test.TestCase):
"endpoint_type": None,
"https_insecure": False,
"https_cacert": None,
"https_cert": None,
"project_domain_name": None,
"user_domain_name": None,
"profiler_hmac_key": None,

View File

@ -85,12 +85,13 @@ class OSClientTestCase(test.TestCase, OSClientTestCaseUtils):
def test_choose_service_type(self):
default_service_type = "default_service_type"
@osclients.configure("test_choose_service_type",
@osclients.configure(self.id(),
default_service_type=default_service_type)
class FakeClient(osclients.OSClient):
create_client = mock.MagicMock()
fake_client = FakeClient(mock.MagicMock(), {}, {})
fake_client = FakeClient({"auth_url": "url", "username": "user",
"password": "pass"}, {}, {})
self.assertEqual(default_service_type,
fake_client.choose_service_type())
self.assertEqual("foo",
@ -122,40 +123,33 @@ class OSClientTestCase(test.TestCase, OSClientTestCaseUtils):
mock_url_for.assert_called_once_with(**call_args)
mock_choose_service_type.assert_called_once_with(service_type)
@mock.patch("%s.Keystone.get_session" % PATH)
def test__get_session(self, mock_keystone_get_session):
osclient = osclients.OSClient(None, None, None)
auth_url = "auth_url"
version = "version"
import warnings
with mock.patch.object(warnings, "warn") as mock_warn:
self.assertEqual(mock_keystone_get_session.return_value,
osclient._get_session(auth_url, version))
self.assertFalse(mock_warn.called)
mock_keystone_get_session.assert_called_once_with(version)
class CachedTestCase(test.TestCase):
def test_cached(self):
clients = osclients.Clients(mock.MagicMock())
client_name = "CachedTestCase.test_cached"
fake_client = osclients.configure(client_name)(osclients.OSClient)(
clients.credential, clients.api_info, clients.cache)
clients = osclients.Clients({"auth_url": "url", "username": "user",
"password": "pass"})
@osclients.configure(self.id())
class SomeClient(osclients.OSClient):
pass
fake_client = SomeClient(clients.credential, clients.api_info,
clients.cache)
fake_client.create_client = mock.MagicMock()
self.assertEqual({}, clients.cache)
fake_client()
self.assertEqual(
{client_name: fake_client.create_client.return_value},
{self.id(): fake_client.create_client.return_value},
clients.cache)
fake_client.create_client.assert_called_once_with()
fake_client()
fake_client.create_client.assert_called_once_with()
fake_client("2")
self.assertEqual(
{client_name: fake_client.create_client.return_value,
"%s('2',)" % client_name: fake_client.create_client.return_value},
{self.id(): fake_client.create_client.return_value,
"%s('2',)" % self.id(): fake_client.create_client.return_value},
clients.cache)
clients.clear()
self.assertEqual({}, clients.cache)
@ -258,12 +252,12 @@ class TestCreateKeystoneClient(test.TestCase, OSClientTestCaseUtils):
domain_name=None, project_domain_name=None,
user_domain_name=None)
self.ksa_session.Session.assert_has_calls(
[mock.call(timeout=180.0, verify=True),
[mock.call(timeout=180.0, verify=True, cert=None),
mock.call(auth=self.ksa_identity_plugin, timeout=180.0,
verify=True)])
verify=True, cert=None)])
def test_keystone_property(self):
keystone = osclients.Keystone(None, None, None)
keystone = osclients.Keystone(self.credential, None, None)
self.assertRaises(exceptions.RallyException, lambda: keystone.keystone)
@mock.patch("%s.Keystone.get_session" % PATH)
@ -272,7 +266,7 @@ class TestCreateKeystoneClient(test.TestCase, OSClientTestCaseUtils):
auth_plugin = mock.MagicMock()
mock_keystone_get_session.return_value = (session, auth_plugin)
cache = {}
keystone = osclients.Keystone(None, None, cache)
keystone = osclients.Keystone(self.credential, None, cache)
self.assertEqual(auth_plugin.get_access.return_value,
keystone.auth_ref)

View File

@ -48,7 +48,7 @@ class TempestConfigfileManagerTestCase(test.TestCase):
def setUp(self):
super(TempestConfigfileManagerTestCase, self).setUp()
deployment = fakes.FakeDeployment(uuid="fake_deployment",
admin=fakes.fake_credential(**CRED))
admin=fakes.FakeCredential(**CRED))
self.tempest = config.TempestConfigfileManager(deployment)
def test__configure_auth(self):

View File

@ -55,7 +55,7 @@ class TempestContextTestCase(test.TestCase):
self.mock_isfile = mock.patch("os.path.isfile",
return_value=True).start()
self.cred = fakes.fake_credential(**CRED)
self.cred = fakes.FakeCredential(**CRED)
self.deployment = fakes.FakeDeployment(
uuid="fake_deployment", admin=self.cred)
cfg = {"verifier": mock.Mock(deployment=self.deployment),