Refactor osclients

Now keystoneclient are separeted into 2 parts: working with resources
and authorization part. Secand part was moved into keystoneauth1 repo.

That patch is intended to drop depraceted usage of keystoneclient for
authorization in favor of keystoneauth1. Furthermore, in the next patch
we are going to use keystoneauth1 session for initialization of clients
where its possible.

Also :
  * Remove deprecated register decorator from osclient
  * Use _get_endpoint() in proper places
  * Refactor create_client in Keystone
  * Refactor unit tests in test_osclients

Change-Id: If67dffcd27f9bc3e7484d02eac62035c82415c3a
This commit is contained in:
Roman Vasilets 2016-06-29 17:24:36 +03:00
parent f8a86b4489
commit 35c149c1a2
3 changed files with 232 additions and 379 deletions

View File

@ -148,33 +148,45 @@ class OSClient(plugin.Plugin):
self.cache)
return keystone(*args, **kwargs)
def _get_session(self, auth=None, endpoint=None):
from keystoneclient.auth import token_endpoint
from keystoneclient import session as ks_session
if auth is None:
endpoint = endpoint or self._get_endpoint()
kc = self.keystone()
auth = token_endpoint.Token(endpoint, kc.auth_token)
verify = self.credential.cacert or not self.credential.insecure
return ks_session.Session(
auth=auth, verify=verify,
timeout=CONF.openstack_client_http_timeout)
def _get_keystoneauth_session(self):
from keystoneauth1 import loading
def _get_session(self, auth_url=None, version=None):
from keystoneauth1 import discover
from keystoneauth1 import session
loader = loading.get_plugin_loader("password")
plugin = loader.load_from_options(
auth_url=self.credential.auth_url,
username=self.credential.username,
password=self.credential.password,
user_domain_name=self.credential.user_domain_name,
project_name=self.credential.tenant_name,
project_domain_name=self.credential.project_domain_name)
sess = session.Session(auth=plugin, verify=(
not self.credential.insecure))
return sess
from keystoneclient.auth import identity
password_args = {
"auth_url": auth_url or self.credential.auth_url,
"username": self.credential.username,
"password": self.credential.password,
"tenant_name": self.credential.tenant_name
}
version = OSClient.get("keystone")(
self.credential, self.api_info, self.cache).choose_version(version)
if version is None:
# NOTE(rvasilets): If version not specified than we discover
# available version with the smallest number. To be able to
# discover versions we need session
temp_session = session.Session(
verify=(
self.credential.cacert or not self.credential.insecure),
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"):
password_args.update({
"user_domain_name": self.credential.user_domain_name,
"domain_name": self.credential.domain_name,
"project_domain_name": self.credential.project_domain_name,
})
identity_plugin = identity.Password(**password_args)
sess = session.Session(
auth=identity_plugin, verify=(
self.credential.cacert or not self.credential.insecure),
timeout=CONF.openstack_client_http_timeout)
return sess, identity_plugin
def _get_endpoint(self, service_type=None):
kc = self.keystone()
@ -239,36 +251,6 @@ class Keystone(OSClient):
raise exceptions.RallyException(_("Method 'keystone' is restricted "
"for keystoneclient. :)"))
def _create_keystone_client(self, args, version=None):
from keystoneclient.auth import identity
from keystoneclient import client
auth_arg_list = [
"username", "project_name", "tenant_name", "auth_url",
"password",
]
# NOTE(bigjools): If forcing a v2.0 URL then you cannot specify
# domain-related info, or the service discovery will fail.
if "v2.0" not in args["auth_url"] and version != "2":
auth_arg_list.extend(
["user_domain_name", "domain_name", "project_domain_name"])
auth_args = {key: args.get(key) for key in auth_arg_list}
auth = identity.Password(**auth_args)
session = self._get_session(auth=auth)
args["session"] = session
# NOTE(bigjools): When using sessions, keystoneclient no longer
# does any pre-auth and calling client.authenticate() with
# sessions is deprecated (it's still possible to call it but if
# endpoint is defined it'll crash). We're forcing that pre-auth
# here because the use of the service_catalog depends on doing
# this. Also note that while the API has got the
# endpoints.list() equivalent, there is no service_type in that
# list which is why we need to ensure service_catalog is still
# present.
auth_ref = auth.get_access(session)
ks = client.Client(version=version, **args)
ks.auth_ref = auth_ref
return ks
def _remove_url_version(self):
"""Remove any version from the auth_url.
@ -291,20 +273,32 @@ class Keystone(OSClient):
If this object was constructed with a version in the api_info
then that will be used unless the version parameter is passed.
"""
from keystoneclient import client
# Use the version in the api_info if provided, otherwise fall
# back to the passed version (which may be None, in which case
# keystoneclient chooses).
version = self.choose_version(version)
new_kw = {
"timeout": CONF.openstack_client_http_timeout,
"insecure": self.credential.insecure,
"cacert": self.credential.cacert
}
kw = self.credential.to_dict()
kw.update(new_kw)
auth_url = self.credential.auth_url
if version is not None:
kw["auth_url"] = self._remove_url_version()
return self._create_keystone_client(kw, version=version)
auth_url = self._remove_url_version()
sess, plugin = self._get_session(auth_url=auth_url, version=version)
# NOTE(bigjools): When using sessions, keystoneclient no longer
# does any pre-auth and calling client.authenticate() with
# sessions is deprecated (it's still possible to call it but if
# endpoint is defined it'll crash). We're forcing that pre-auth
# here because the use of the service_catalog depends on doing
# this. Also note that while the API has got the
# endpoints.list() equivalent, there is no service_type in that
# list which is why we need to ensure service_catalog is still
# present.
auth_ref = plugin.get_access(sess)
ks = client.Client(version=version, session=sess,
timeout=CONF.openstack_client_http_timeout)
ks.auth_ref = auth_ref
return ks
@configure("nova", default_version="2", default_service_type="compute")
@ -323,18 +317,15 @@ class Nova(OSClient):
def create_client(self, version=None, service_type=None):
"""Return nova client."""
from novaclient import client as nova
kc = self.keystone()
compute_api_url = kc.service_catalog.url_for(
service_type=self.choose_service_type(service_type),
endpoint_type=self.credential.endpoint_type,
region_name=self.credential.region_name)
client = nova.Client(self.choose_version(version),
auth_token=kc.auth_token,
http_log_debug=logging.is_debug(),
timeout=CONF.openstack_client_http_timeout,
insecure=self.credential.insecure,
**self._get_auth_info(password_key="api_key"))
client.set_management_url(compute_api_url)
client.set_management_url(self._get_endpoint(service_type))
return client
@ -344,14 +335,11 @@ class Neutron(OSClient):
def create_client(self, version=None, service_type=None):
"""Return neutron client."""
from neutronclient.neutron import client as neutron
kc = self.keystone()
network_api_url = kc.service_catalog.url_for(
service_type=self.choose_service_type(service_type),
endpoint_type=self.credential.endpoint_type,
region_name=self.credential.region_name)
client = neutron.Client(self.choose_version(version),
token=kc.auth_token,
endpoint_url=network_api_url,
endpoint_url=self._get_endpoint(service_type),
timeout=CONF.openstack_client_http_timeout,
insecure=self.credential.insecure,
**self._get_auth_info(
@ -366,13 +354,10 @@ class Glance(OSClient):
def create_client(self, version=None, service_type=None):
"""Return glance client."""
import glanceclient as glance
kc = self.keystone()
image_api_url = kc.service_catalog.url_for(
service_type=self.choose_service_type(service_type),
endpoint_type=self.credential.endpoint_type,
region_name=self.credential.region_name)
client = glance.Client(self.choose_version(version),
endpoint=image_api_url,
endpoint=self._get_endpoint(service_type),
token=kc.auth_token,
timeout=CONF.openstack_client_http_timeout,
insecure=self.credential.insecure,
@ -386,13 +371,10 @@ class Heat(OSClient):
def create_client(self, version=None, service_type=None):
"""Return heat client."""
from heatclient import client as heat
kc = self.keystone()
orchestration_api_url = kc.service_catalog.url_for(
service_type=self.choose_service_type(service_type),
endpoint_type=self.credential.endpoint_type,
region_name=self.credential.region_name)
client = heat.Client(self.choose_version(version),
endpoint=orchestration_api_url,
endpoint=self._get_endpoint(service_type),
token=kc.auth_token,
timeout=CONF.openstack_client_http_timeout,
insecure=self.credential.insecure,
@ -407,17 +389,14 @@ class Cinder(OSClient):
def create_client(self, version=None, service_type=None):
"""Return cinder client."""
from cinderclient import client as cinder
client = cinder.Client(self.choose_version(version),
http_log_debug=logging.is_debug(),
timeout=CONF.openstack_client_http_timeout,
insecure=self.credential.insecure,
**self._get_auth_info(password_key="api_key"))
kc = self.keystone()
volume_api_url = kc.service_catalog.url_for(
service_type=self.choose_service_type(service_type),
endpoint_type=self.credential.endpoint_type,
region_name=self.credential.region_name)
client.client.management_url = volume_api_url
client.client.management_url = self._get_endpoint(service_type)
client.client.auth_token = kc.auth_token
return client
@ -437,10 +416,7 @@ class Manila(OSClient):
**self._get_auth_info(password_key="api_key",
project_name_key="project_name"))
kc = self.keystone()
manila_client.client.management_url = kc.service_catalog.url_for(
service_type=self.choose_service_type(service_type),
endpoint_type=self.credential.endpoint_type,
region_name=self.credential.region_name)
manila_client.client.management_url = self._get_endpoint(service_type)
manila_client.client.auth_token = kc.auth_token
return manila_client
@ -451,11 +427,8 @@ class Ceilometer(OSClient):
def create_client(self, version=None, service_type=None):
"""Return ceilometer client."""
from ceilometerclient import client as ceilometer
kc = self.keystone()
metering_api_url = kc.service_catalog.url_for(
service_type=self.choose_service_type(service_type),
endpoint_type=self.credential.endpoint_type,
region_name=self.credential.region_name)
auth_token = kc.auth_token
if not hasattr(auth_token, "__call__"):
# python-ceilometerclient requires auth_token to be a callable
@ -463,7 +436,7 @@ class Ceilometer(OSClient):
client = ceilometer.get_client(
self.choose_version(version),
os_endpoint=metering_api_url,
os_endpoint=self._get_endpoint(service_type),
token=auth_token,
timeout=CONF.openstack_client_http_timeout,
insecure=self.credential.insecure,
@ -480,8 +453,9 @@ class Gnocchi(OSClient):
# NOTE(sumantmurke): gnocchiclient requires keystoneauth1 for
# authenticating and creating a session.
from gnocchiclient import client as gnocchi
service_type = self.choose_service_type(service_type)
sess = self._get_keystoneauth_session()
sess = self._get_session()[0]
gclient = gnocchi.Client(version=self.choose_version(
version), session=sess, service_type=service_type)
return gclient
@ -494,14 +468,11 @@ class Ironic(OSClient):
def create_client(self, version=None, service_type=None):
"""Return Ironic client."""
from ironicclient import client as ironic
kc = self.keystone()
baremetal_api_url = kc.service_catalog.url_for(
service_type=self.choose_service_type(service_type),
endpoint_type=self.credential.endpoint_type,
region_name=self.credential.region_name)
client = ironic.get_client(self.choose_version(version),
os_auth_token=kc.auth_token,
ironic_url=baremetal_api_url,
ironic_url=self._get_endpoint(service_type),
timeout=CONF.openstack_client_http_timeout,
insecure=self.credential.insecure,
cacert=self.credential.cacert)
@ -525,6 +496,7 @@ class Sahara(OSClient):
def create_client(self, version=None, service_type=None):
"""Return Sahara client."""
from saharaclient import client as sahara
client = sahara.Client(
self.choose_version(version),
service_type=self.choose_service_type(service_type),
@ -547,10 +519,6 @@ class Zaqar(OSClient):
"""Return Zaqar client."""
from zaqarclient.queues import client as zaqar
kc = self.keystone()
messaging_api_url = kc.service_catalog.url_for(
service_type=self.choose_service_type(service_type),
endpoint_type=self.credential.endpoint_type,
region_name=self.credential.region_name)
conf = {"auth_opts": {"backend": "keystone", "options": {
"os_username": self.credential.username,
"os_password": self.credential.password,
@ -559,7 +527,7 @@ class Zaqar(OSClient):
"os_auth_url": self.credential.auth_url,
"insecure": self.credential.insecure,
}}}
client = zaqar.Client(url=messaging_api_url,
client = zaqar.Client(url=self._get_endpoint(),
version=self.choose_version(version),
conf=conf)
return client
@ -572,15 +540,10 @@ class Murano(OSClient):
def create_client(self, version=None, service_type=None):
"""Return Murano client."""
from muranoclient import client as murano
kc = self.keystone()
murano_url = kc.service_catalog.url_for(
service_type=self.choose_service_type(service_type),
endpoint_type=self.credential.endpoint_type,
region_name=self.credential.region_name
)
kc = self.keystone()
client = murano.Client(self.choose_version(version),
endpoint=murano_url,
endpoint=self._get_endpoint(service_type),
token=kc.auth_token)
return client
@ -598,7 +561,7 @@ class Designate(OSClient):
api_url = self._get_endpoint(service_type)
api_url += "/v%s" % version
session = self._get_session(endpoint=api_url)
session = self._get_session(auth_url=api_url)[0]
return client.Client(version, session=session)
@ -607,6 +570,7 @@ class Trove(OSClient):
def create_client(self, version=None):
"""Returns trove client."""
from troveclient import client as trove
client = trove.Client(self.choose_version(version),
region_name=self.credential.region_name,
timeout=CONF.openstack_client_http_timeout,
@ -621,15 +585,10 @@ class Mistral(OSClient):
def create_client(self, service_type=None):
"""Return Mistral client."""
from mistralclient.api import client
kc = self.keystone()
mistral_url = kc.service_catalog.url_for(
service_type=self.choose_service_type(service_type),
endpoint_type=self.credential.endpoint_type,
region_name=self.credential.region_name)
client = client.client(
mistral_url=mistral_url,
mistral_url=self._get_endpoint(service_type),
service_type=self.choose_service_type(service_type),
auth_token=kc.auth_token)
return client
@ -640,13 +599,10 @@ class Swift(OSClient):
def create_client(self, service_type=None):
"""Return swift client."""
from swiftclient import client as swift
kc = self.keystone()
object_api_url = kc.service_catalog.url_for(
service_type=self.choose_service_type(service_type),
endpoint_type=self.credential.endpoint_type,
region_name=self.credential.region_name)
client = swift.Connection(retries=1,
preauthurl=object_api_url,
preauthurl=self._get_endpoint(service_type),
preauthtoken=kc.auth_token,
insecure=self.credential.insecure,
cacert=self.credential.cacert,
@ -661,6 +617,7 @@ class EC2(OSClient):
def create_client(self):
"""Return ec2 client."""
import boto
kc = self.keystone()
if kc.version != "v2.0":
raise exceptions.RallyException(
@ -668,12 +625,8 @@ class EC2(OSClient):
"Keystone version 2"))
ec2_credential = kc.ec2.create(user_id=kc.auth_user_id,
tenant_id=kc.auth_tenant_id)
ec2_api_url = kc.service_catalog.url_for(
service_type=consts.ServiceType.EC2,
endpoint_type=self.credential.endpoint_type,
region_name=self.credential.region_name)
client = boto.connect_ec2_endpoint(
url=ec2_api_url,
url=self._get_endpoint(),
aws_access_key_id=ec2_credential.access,
aws_secret_access_key=ec2_credential.secret,
is_secure=self.credential.insecure)
@ -686,15 +639,12 @@ class Monasca(OSClient):
def create_client(self, version=None, service_type=None):
"""Return monasca client."""
from monascaclient import client as monasca
kc = self.keystone()
monitoring_api_url = kc.service_catalog.url_for(
service_type=self.choose_service_type(service_type),
endpoint_type=self.credential.endpoint_type,
region_name=self.credential.region_name)
auth_token = kc.auth_token
client = monasca.Client(
self.choose_version(version),
monitoring_api_url,
self._get_endpoint(service_type),
token=auth_token,
timeout=CONF.openstack_client_http_timeout,
insecure=self.credential.insecure,
@ -712,10 +662,10 @@ class Cue(OSClient):
api_url = self._get_endpoint(service_type)
api_url += "v%s" % version
session = self._get_session(endpoint=api_url)
endpoint_type = self.credential.endpoint_type,
session = self._get_session(auth_url=api_url)[0]
endpoint_type = self.credential.endpoint_type
return cue.Client(session=session, interface=endpoint_type[0])
return cue.Client(session=session, interface=endpoint_type)
@configure("senlin", default_version="1", default_service_type="clustering",
@ -724,6 +674,7 @@ class Senlin(OSClient):
def create_client(self, version=None, service_type=None):
"""Return senlin client."""
from senlinclient import client as senlin
return senlin.Client(
self.choose_version(version),
**self._get_auth_info(project_name_key="project_name",
@ -738,10 +689,10 @@ class Magnum(OSClient):
from magnumclient import client as magnum
api_url = self._get_endpoint(service_type)
session = self._get_session(endpoint=api_url)
endpoint_type = self.credential.endpoint_type,
session = self._get_session(auth_url=api_url)[0]
endpoint_type = self.credential.endpoint_type
return magnum.Client(session=session, interface=endpoint_type[0])
return magnum.Client(session=session, interface=endpoint_type)
@configure("watcher", default_version="1", default_service_type="infra-optim",
@ -835,50 +786,3 @@ class Clients(object):
self.cache["services_data"] = services_data
return self.cache["services_data"]
@classmethod
@logging.log_deprecated("Use rally.osclients.configure decorator instead.",
"0.1.2")
def register(cls, client_name):
"""DEPRECATED!Decorator that adds new OpenStack client dynamically.
Use rally.osclients.configure decorator instead!
:param client_name: str name how client will be named in Rally clients
Decorated class will be added to Clients in runtime, so its sole
argument is a Clients instance.
Decorated function will be added to Clients in runtime, so its sole
argument is a Clients instance.
Example:
>>> from rally import osclients
>>> @osclients.Clients.register("supernova")
... def another_nova_client(self):
... from novaclient import client as nova
... return nova.Client("2", auth_token=self.keystone().auth_token,
... **self._get_auth_info(password_key="key"))
...
>>> clients = osclients.Clients.create_from_env()
>>> clients.supernova().services.list()[:2]
[<Service: nova-conductor>, <Service: nova-cert>]
"""
def wrap(client_func):
try:
OSClient.get(client_name)
except exceptions.PluginNotFound:
# everything is ok
pass
else:
raise ValueError(
_("Can not register client: name already exists: %s")
% client_name)
@configure(client_name)
class NewClient(OSClient):
create_client = client_func
return NewClient
return wrap

View File

@ -1039,7 +1039,7 @@ class FakeKeystoneClient(object):
self.auth_ref = mock.Mock()
self.auth_ref.role_names = ["admin"]
self.version = "v2.0"
self.session = mock.Mock()
self.session = mock.MagicMock()
self.authenticate = mock.MagicMock()
def authenticate(self):

View File

@ -14,11 +14,9 @@
# under the License.
import ddt
from keystoneclient.auth import token_endpoint
from keystoneclient import exceptions as keystone_exceptions
import mock
from oslo_config import cfg
from testtools import matchers
from rally.common import objects
from rally import consts
@ -34,7 +32,51 @@ class DummyClient(osclients.OSClient):
pass
class OSClientTestCase(test.TestCase):
class OSClientTestCaseUtils(object):
def set_up_keystone_mocks(self):
self.ksc_module = mock.MagicMock()
self.ksc_client = mock.MagicMock()
self.ksc_identity = mock.MagicMock()
self.ksc_identity_plugin = mock.MagicMock()
self.ksc_password = mock.MagicMock(
return_value=self.ksc_identity_plugin)
self.ksc_auth = mock.MagicMock()
self.ksa_auth = mock.MagicMock()
self.ksa_session = mock.MagicMock()
self.patcher = mock.patch.dict("sys.modules",
{"keystoneclient": self.ksc_module,
"keystoneclient.auth": self.ksc_auth,
"keystoneauth1": self.ksa_auth})
self.patcher.start()
self.addCleanup(self.patcher.stop)
self.ksc_module.client = self.ksc_client
self.ksc_auth.identity = self.ksc_identity
self.ksc_auth.identity.Password = self.ksc_password
self.ksa_auth.session = self.ksa_session
def make_auth_args(self):
auth_kwargs = {
"auth_url": "http://auth_url/", "username": "user",
"password": "password", "tenant_name": "tenant",
"domain_name": "domain", "project_name": "project_name",
"project_domain_name": "project_domain_name",
"user_domain_name": "user_domain_name",
}
kwargs = {"https_insecure": False, "https_cacert": None}
kwargs.update(auth_kwargs)
return auth_kwargs, kwargs
@ddt.ddt
class OSClientTestCase(test.TestCase, OSClientTestCaseUtils):
def setUp(self):
super(OSClientTestCase, self).setUp()
self.credential = objects.Credential("http://auth_url/v2.0", "user",
"pass", "tenant")
def test_choose_service_type(self):
default_service_type = "default_service_type"
@ -49,6 +91,45 @@ class OSClientTestCase(test.TestCase):
self.assertEqual("foo",
fake_client.choose_service_type("foo"))
@ddt.data(
{"auth_url": "http://auth_url/v2.0"},
{"auth_url": "http://auth_url/v3"},
{"auth_url": "http://auth_url/"},
{"auth_url": None},
)
@ddt.unpack
def test__get_session(self, auth_url):
mock_keystoneauth1 = mock.MagicMock()
self.set_up_keystone_mocks()
osclient = osclients.OSClient(
self.credential, {}, mock.MagicMock())
with mock.patch.dict(
"sys.modules", {
"keystoneauth1": mock_keystoneauth1}):
mock_keystoneauth1.discover.Discover.return_value = (
mock.Mock(version_data=mock.Mock(return_value=[
{"version": (1, 0)}]))
)
osclient._get_session(auth_url=auth_url)
if auth_url == "http://auth_url/v2.0":
self.ksc_password.assert_called_once_with(
auth_url=auth_url, password="pass",
tenant_name="tenant", username="user")
elif auth_url is None:
self.ksc_password.assert_called_once_with(
auth_url="http://auth_url/v2.0", password="pass",
tenant_name="tenant", username="user")
else:
self.ksc_password.assert_called_once_with(
auth_url=auth_url, password="pass",
tenant_name="tenant", username="user",
domain_name=None, project_domain_name=None,
user_domain_name=None)
mock_keystoneauth1.session.Session.assert_has_calls(
[mock.call(timeout=180.0, verify=True),
mock.call(auth=self.ksc_identity_plugin, timeout=180.0,
verify=True)])
class CachedTestCase(test.TestCase):
@ -77,38 +158,14 @@ class CachedTestCase(test.TestCase):
self.assertEqual({}, clients.cache)
class TestCreateKeystoneClient(test.TestCase):
class TestCreateKeystoneClient(test.TestCase, OSClientTestCaseUtils):
def make_auth_args(self):
auth_kwargs = {
"auth_url": "http://auth_url", "username": "user",
"password": "password", "tenant_name": "tenant",
"domain_name": "domain", "project_name": "project_name",
"project_domain_name": "project_domain_name",
"user_domain_name": "user_domain_name",
}
kwargs = {"https_insecure": False, "https_cacert": None}
kwargs.update(auth_kwargs)
return auth_kwargs, kwargs
def setUp(self):
super(TestCreateKeystoneClient, self).setUp()
self.credential = objects.Credential("http://auth_url/v2.0", "user",
"pass", "tenant")
def set_up_keystone_mocks(self):
self.ksc_module = mock.MagicMock()
self.ksc_client = mock.MagicMock()
self.ksc_identity = mock.MagicMock()
self.ksc_password = mock.MagicMock()
self.ksc_session = mock.MagicMock()
self.ksc_auth = mock.MagicMock()
self.patcher = mock.patch.dict("sys.modules",
{"keystoneclient": self.ksc_module,
"keystoneclient.auth": self.ksc_auth})
self.patcher.start()
self.addCleanup(self.patcher.stop)
self.ksc_module.client = self.ksc_client
self.ksc_auth.identity = self.ksc_identity
self.ksc_auth.identity.Password = self.ksc_password
self.ksc_module.session = self.ksc_session
def test_create_keystone_client(self):
def test_create_client(self):
# NOTE(bigjools): This is a very poor testing strategy as it
# tightly couples the test implementation to the tested
# function's implementation. Ideally, we'd use a fake keystone
@ -117,33 +174,31 @@ class TestCreateKeystoneClient(test.TestCase):
# client. Hopefully one day we'll get a real fake from the
# keystone guys.
self.set_up_keystone_mocks()
auth_kwargs, all_kwargs = self.make_auth_args()
keystone = osclients.Keystone(
mock.MagicMock(), mock.sentinel, mock.sentinel)
client = keystone._create_keystone_client(all_kwargs)
keystone = osclients.Keystone(self.credential, {}, mock.MagicMock())
keystone._get_session = mock.Mock(
return_value=(self.ksa_session, self.ksc_identity_plugin,))
self.ksc_identity_plugin.get_access = mock.Mock(
return_value="fake_auth_ref")
client = keystone.create_client(version=3)
self.ksc_password.assert_called_once_with(**auth_kwargs)
self.ksc_session.Session.assert_called_once_with(
auth=self.ksc_identity.Password(), timeout=mock.ANY,
verify=mock.ANY)
kwargs_session = self.credential.to_dict()
kwargs_session.update({
"auth_url": "http://auth_url/",
"session": self.ksa_session,
"timeout": 180.0})
keystone._get_session.assert_called_once_with(
auth_url="http://auth_url/", version="3")
self.ksc_identity_plugin.get_access.assert_called_once_with(
self.ksa_session)
self.ksc_client.Client.assert_called_once_with(
version=None, **all_kwargs)
session=self.ksa_session, timeout=180.0, version="3")
self.assertIs(client, self.ksc_client.Client())
def test_client_is_pre_authed(self):
self.assertEqual("fake_auth_ref", self.ksc_client.Client().auth_ref)
# The client needs to be pre-authed so that service_catalog
# works. This is because when using sessions, lazy auth is done
# in keystoneclient.
self.set_up_keystone_mocks()
_, all_kwargs = self.make_auth_args()
keystone = osclients.Keystone(
mock.MagicMock(), mock.sentinel, mock.sentinel)
client = keystone._create_keystone_client(all_kwargs)
auth_ref = getattr(client, "auth_ref", None)
self.assertIsNot(auth_ref, None)
self.ksc_client.Client.assert_called_once_with(
version=None, **all_kwargs)
self.assertIs(client, self.ksc_client.Client())
def test_create_client_removes_url_path_if_version_specified(self):
# If specifying a version on the client creation call, ensure
@ -151,62 +206,17 @@ class TestCreateKeystoneClient(test.TestCase):
# into the Client() call.
self.set_up_keystone_mocks()
auth_kwargs, all_kwargs = self.make_auth_args()
credential = objects.Credential(
"http://auth_url/v2.0", "user", "pass", "tenant")
keystone = osclients.Keystone(
credential, {}, mock.MagicMock())
self.credential, {}, mock.MagicMock())
keystone._get_session = mock.Mock(
return_value=(self.ksa_session, self.ksc_identity_plugin,))
client = keystone.create_client(version="3")
self.assertIs(client, self.ksc_client.Client())
called_with = self.ksc_client.Client.call_args_list[0][1]
self.expectThat(
called_with["auth_url"], matchers.Equals("http://auth_url/"))
self.expectThat(called_with["version"], matchers.Equals("3"))
def test_create_keystone_client_with_v2_url_omits_domain(self):
# NOTE(bigjools): Test that domain-related info is not present
# when forcing a v2 URL, because it breaks keystoneclient's
# service discovery.
self.set_up_keystone_mocks()
auth_kwargs, all_kwargs = self.make_auth_args()
all_kwargs["auth_url"] = "http://auth_url/v2.0"
auth_kwargs["auth_url"] = all_kwargs["auth_url"]
keystone = osclients.Keystone(
mock.MagicMock(), mock.sentinel, mock.sentinel)
client = keystone._create_keystone_client(all_kwargs)
auth_kwargs.pop("user_domain_name")
auth_kwargs.pop("project_domain_name")
auth_kwargs.pop("domain_name")
self.ksc_password.assert_called_once_with(**auth_kwargs)
self.ksc_session.Session.assert_called_once_with(
auth=self.ksc_identity.Password(), timeout=mock.ANY,
verify=mock.ANY)
self.ksc_client.Client.assert_called_once_with(
version=None, **all_kwargs)
self.assertIs(client, self.ksc_client.Client())
def test_create_keystone_client_with_v2_version_omits_domain(self):
self.set_up_keystone_mocks()
auth_kwargs, all_kwargs = self.make_auth_args()
all_kwargs["auth_url"] = "http://auth_url/"
auth_kwargs["auth_url"] = all_kwargs["auth_url"]
keystone = osclients.Keystone(
mock.MagicMock(), mock.sentinel, mock.sentinel)
client = keystone._create_keystone_client(all_kwargs, version="2")
auth_kwargs.pop("user_domain_name")
auth_kwargs.pop("project_domain_name")
auth_kwargs.pop("domain_name")
self.ksc_password.assert_called_once_with(**auth_kwargs)
self.ksc_session.Session.assert_called_once_with(
auth=self.ksc_identity.Password(), timeout=mock.ANY,
verify=mock.ANY)
self.ksc_client.Client.assert_called_once_with(
version="2", **all_kwargs)
self.assertIs(client, self.ksc_client.Client())
self.assertEqual(
{"session": self.ksa_session, "timeout": 180.0, "version": "3"},
called_with)
@ddt.ddt
@ -214,7 +224,7 @@ class OSClientsTestCase(test.TestCase):
def setUp(self):
super(OSClientsTestCase, self).setUp()
self.credential = objects.Credential("http://auth_url/v2.0", "use",
self.credential = objects.Credential("http://auth_url/v2.0", "user",
"pass", "tenant")
self.clients = osclients.Clients(self.credential, {})
@ -224,7 +234,7 @@ class OSClientsTestCase(test.TestCase):
self.service_catalog.url_for = mock.MagicMock()
keystone_patcher = mock.patch(
"rally.osclients.Keystone._create_keystone_client")
"rally.osclients.Keystone.create_client")
self.mock_create_keystone_client = keystone_patcher.start()
self.addCleanup(keystone_patcher.stop)
self.mock_create_keystone_client.return_value = self.fake_keystone
@ -247,69 +257,6 @@ class OSClientsTestCase(test.TestCase):
self.assertEqual("foo_tenant_name", clients.credential.tenant_name)
self.assertEqual("foo_region_name", clients.credential.region_name)
@mock.patch.object(DummyClient, "_get_endpoint")
@mock.patch("keystoneclient.session.Session")
def test_get_session(self, mock_session, mock_dummy_client__get_endpoint):
# Use DummyClient since if not the abc meta kicks in
osc = DummyClient(self.credential, {}, {})
with mock.patch.object(token_endpoint, "Token") as token:
osc._get_session()
token.assert_called_once_with(
mock_dummy_client__get_endpoint.return_value,
self.fake_keystone.auth_token
)
mock_session.assert_called_once_with(
auth=token.return_value, verify=not self.credential.insecure,
timeout=cfg.CONF.openstack_client_http_timeout)
@mock.patch.object(DummyClient, "_get_endpoint")
@mock.patch("keystoneclient.session.Session")
def test_get_session_with_endpoint(
self, mock_session, mock_dummy_client__get_endpoint):
# Use DummyClient since if not the abc meta kicks in
osc = DummyClient(self.credential, {}, {})
fake_endpoint = mock.Mock()
with mock.patch.object(token_endpoint, "Token") as token:
osc._get_session(endpoint=fake_endpoint)
self.assertFalse(mock_dummy_client__get_endpoint.called)
token.assert_called_once_with(
fake_endpoint,
self.fake_keystone.auth_token
)
mock_session.assert_called_once_with(
auth=token.return_value, verify=not self.credential.insecure,
timeout=cfg.CONF.openstack_client_http_timeout)
@mock.patch("keystoneclient.session.Session")
def test_get_session_with_auth(self, mock_session):
# Use DummyClient since if not the abc meta kicks in
osc = DummyClient(self.credential, {}, {})
fake_auth = mock.Mock()
osc._get_session(auth=fake_auth)
mock_session.assert_called_once_with(
auth=fake_auth, verify=not self.credential.insecure,
timeout=cfg.CONF.openstack_client_http_timeout)
@mock.patch("keystoneclient.session.Session")
def test_get_session_with_ca(self, mock_session):
# Use DummyClient since if not the abc meta kicks in
osc = DummyClient(self.credential, {}, {})
self.credential.cacert = "/fake/ca"
fake_auth = mock.Mock()
osc._get_session(auth=fake_auth)
mock_session.assert_called_once_with(
auth=fake_auth, verify="/fake/ca",
timeout=cfg.CONF.openstack_client_http_timeout)
def test_keystone(self):
self.assertNotIn("keystone", self.clients.cache)
client = self.clients.keystone()
@ -317,9 +264,8 @@ class OSClientsTestCase(test.TestCase):
credential = {"timeout": cfg.CONF.openstack_client_http_timeout,
"insecure": False, "cacert": None}
kwargs = self.credential.to_dict()
kwargs.update(credential.items())
self.mock_create_keystone_client.assert_called_once_with(
kwargs, version=None)
kwargs.update(credential)
self.mock_create_keystone_client.assert_called_once_with()
self.assertEqual(self.fake_keystone, self.clients.cache["keystone"])
@mock.patch("rally.osclients.Keystone.create_client")
@ -515,6 +461,10 @@ class OSClientsTestCase(test.TestCase):
with mock.patch.dict("sys.modules",
{"gnocchiclient": mock_gnocchi,
"keystoneauth1": mock_keystoneauth1}):
mock_keystoneauth1.discover.Discover.return_value = (
mock.Mock(version_data=mock.Mock(return_value=[
{"version": (1, 0)}]))
)
client = self.clients.gnocchi()
self.assertEqual(fake_gnocchi, client)
@ -691,23 +641,21 @@ class OSClientsTestCase(test.TestCase):
mock_swift.client.Connection.assert_called_once_with(**kw)
self.assertEqual(self.clients.cache["swift"], fake_swift)
def test_ec2(self):
@mock.patch("rally.osclients.EC2._get_endpoint")
def test_ec2(self, mock_ec2__get_endpoint):
mock_boto = mock.Mock()
self.service_catalog.url_for.return_value = "http://fake.to:1/fake"
self.fake_keystone.ec2 = mock.Mock()
self.fake_keystone.ec2.create.return_value = mock.Mock(
access="fake_access", secret="fake_secret")
mock_ec2__get_endpoint.return_value = "http://fake.to:1/fake"
fake_ec2 = fakes.FakeEC2Client()
mock_boto.connect_ec2_endpoint.return_value = fake_ec2
self.assertNotIn("ec2", self.clients.cache)
with mock.patch.dict("sys.modules", {"boto": mock_boto}):
client = self.clients.ec2()
self.assertEqual(fake_ec2, client)
self.service_catalog.url_for.assert_called_once_with(
service_type="ec2",
endpoint_type=consts.EndpointType.PUBLIC,
region_name=self.credential.region_name)
kw = {
"url": "http://fake.to:1/fake",
"aws_access_key_id": "fake_access",
@ -764,7 +712,8 @@ class OSClientsTestCase(test.TestCase):
mock_designate = mock.Mock()
mock_designate.client.Client.return_value = fake_designate
mock_designate__get_session.return_value = self.fake_keystone.session
mock_designate__get_session.return_value = ("fake_session",
"fake_auth_plugin")
self.assertNotIn("designate", self.clients.cache)
with mock.patch.dict("sys.modules",
@ -787,10 +736,10 @@ class OSClientsTestCase(test.TestCase):
url.__iadd__.assert_called_once_with("/v%s" % default)
mock_designate__get_session.assert_called_once_with(
endpoint=url.__iadd__.return_value)
auth_url=url.__iadd__.return_value)
mock_designate.client.Client.assert_called_once_with(
default, session=self.fake_keystone.session)
default, session="fake_session")
key = "designate"
if version is not None:
@ -802,9 +751,8 @@ class OSClientsTestCase(test.TestCase):
fake_cue = fakes.FakeCueClient()
mock_cue = mock.MagicMock()
mock_cue.client.Client = mock.MagicMock(return_value=fake_cue)
mock_cue__get_session.return_value = self.fake_keystone.session
mock_cue__get_session.return_value = ("fake_session",
"fake_auth_plugin")
self.assertNotIn("cue", self.clients.cache)
with mock.patch.dict("sys.modules", {"cueclient": mock_cue,
"cueclient.v1": mock_cue}):
@ -812,7 +760,7 @@ class OSClientsTestCase(test.TestCase):
self.assertEqual(fake_cue, client)
mock_cue.client.Client.assert_called_once_with(
interface=consts.EndpointType.PUBLIC,
session=self.fake_keystone.session)
session="fake_session")
self.assertEqual(fake_cue, self.clients.cache["cue"])
def test_senlin(self):
@ -838,7 +786,8 @@ class OSClientsTestCase(test.TestCase):
mock_magnum = mock.MagicMock()
mock_magnum.client.Client.return_value = fake_magnum
mock_magnum__get_session.return_value = self.fake_keystone.session
mock_magnum__get_session.return_value = (self.fake_keystone.session,
"fake_auth_plugin")
self.assertNotIn("magnum", self.clients.cache)
with mock.patch.dict("sys.modules", {"magnumclient": mock_magnum}):