[Core] Create new plugin based class for credentials

* Moved credential class from rally.objects to rally.deployment.
* Added OpenStackCredential plugin.
* Simplified getting of osclients.
* Enabled client caching on OpenStackCredential plugin.

spec: deployment_type.rst

Change-Id: I9ac8c4989c681885534683bd4ee4bc34fcfabaac
This commit is contained in:
Anton Studenov 2017-03-21 12:49:11 +03:00
parent 91f22381a2
commit 7792aa71b7
46 changed files with 1111 additions and 645 deletions

View File

@ -50,12 +50,16 @@ then
cat >$1 <<EOF cat >$1 <<EOF
{ {
"type": "ExistingCloud", "type": "ExistingCloud",
"auth_url": "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_SERVICE_PORT/v$IDENTITY_API_VERSION", "creds": {
"region_name": "$REGION_NAME", "openstack": {
"admin": { "auth_url": "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_SERVICE_PORT/v$IDENTITY_API_VERSION",
"username": "admin", "region_name": "$REGION_NAME",
"password": "$ADMIN_PASSWORD", "admin": {
"tenant_name": "admin", "username": "admin",
"password": "$ADMIN_PASSWORD",
"tenant_name": "admin",
}
}
} }
} }
EOF EOF
@ -65,14 +69,18 @@ then
cat >$1 <<EOF cat >$1 <<EOF
{ {
"type": "ExistingCloud", "type": "ExistingCloud",
"auth_url": "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_SERVICE_PORT/v$IDENTITY_API_VERSION", "creds": {
"region_name": "$REGION_NAME", "openstack": {
"admin": { "auth_url": "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_SERVICE_PORT/v$IDENTITY_API_VERSION",
"username": "admin", "region_name": "$REGION_NAME",
"password": "$ADMIN_PASSWORD", "admin": {
"project_name": "admin", "username": "admin",
"user_domain_name": "Default", "password": "$ADMIN_PASSWORD",
"project_domain_name": "Default" "project_name": "admin",
"user_domain_name": "Default",
"project_domain_name": "Default"
}
}
} }
} }
EOF EOF

View File

@ -33,7 +33,6 @@ from rally.common import version as rally_version
from rally import consts from rally import consts
from rally.deployment import engine as deploy_engine from rally.deployment import engine as deploy_engine
from rally import exceptions from rally import exceptions
from rally import osclients
from rally.task import engine from rally.task import engine
from rally.verification import context as vcontext from rally.verification import context as vcontext
from rally.verification import manager as vmanager from rally.verification import manager as vmanager
@ -149,10 +148,9 @@ class _Deployment(object):
:param deployment: Deployment object :param deployment: Deployment object
:returns: Service list :returns: Service list
""" """
# TODO(astudenov): put this work into Credential plugins # TODO(astudenov): make this method platform independent
admin = deployment.get_credentials_for("openstack")["admin"] admin = deployment.get_credentials_for("openstack")["admin"]
clients = osclients.Clients(objects.Credential(**admin)) return admin.list_services()
return clients.services()
@staticmethod @staticmethod
def list(status=None, parent_uuid=None, name=None): def list(status=None, parent_uuid=None, name=None):
@ -168,13 +166,12 @@ class _Deployment(object):
:returns: Service list :returns: Service list
""" """
# TODO(astudenov): put this work into Credential plugins # TODO(astudenov): make this method platform independent
services = cls.service_list(deployment) creds = deployment.get_credentials_for("openstack")
users = deployment.get_credentials_for("openstack")["users"] creds["admin"].verify_connection()
for endpoint_dict in users: for user in creds["users"]:
osclients.Clients(objects.Credential(**endpoint_dict)).keystone() user.verify_connection()
return creds["admin"].list_services()
return services
class _Task(object): class _Task(object):

View File

@ -191,11 +191,13 @@ class DeploymentCommands(object):
metavar="<uuid>", required=False, metavar="<uuid>", required=False,
help="UUID or name of the deployment.") help="UUID or name of the deployment.")
@envutils.with_default_deployment() @envutils.with_default_deployment()
@plugins.ensure_plugins_are_loaded
def show(self, api, deployment=None): def show(self, api, deployment=None):
"""Show the credentials of the deployment. """Show the credentials of the deployment.
:param deployment: UUID or name of the deployment :param deployment: UUID or name of the deployment
""" """
# TODO(astudenov): make this method platform independent
headers = ["auth_url", "username", "password", "tenant_name", headers = ["auth_url", "username", "password", "tenant_name",
"region_name", "endpoint_type"] "region_name", "endpoint_type"]
@ -208,7 +210,7 @@ class DeploymentCommands(object):
credentials = users + [admin] if admin else users credentials = users + [admin] if admin else users
for ep in credentials: for ep in credentials:
data = ["***" if m == "password" else ep.get(m, "") data = ["***" if m == "password" else getattr(ep, m, "")
for m in headers] for m in headers]
table_rows.append(utils.Struct(**dict(zip(headers, data)))) table_rows.append(utils.Struct(**dict(zip(headers, data))))
cliutils.print_list(table_rows, headers) cliutils.print_list(table_rows, headers)
@ -217,11 +219,13 @@ class DeploymentCommands(object):
metavar="<uuid>", required=False, metavar="<uuid>", required=False,
help="UUID or name of the deployment.") help="UUID or name of the deployment.")
@envutils.with_default_deployment() @envutils.with_default_deployment()
@plugins.ensure_plugins_are_loaded
def check(self, api, deployment=None): def check(self, api, deployment=None):
"""Check keystone authentication and list all available services. """Check keystone authentication and list all available services.
:param deployment: UUID or name of the deployment :param deployment: UUID or name of the deployment
""" """
# TODO(astudenov): make this method platform independent
headers = ["services", "type", "status"] headers = ["services", "type", "status"]
table_rows = [] table_rows = []
try: try:
@ -235,7 +239,7 @@ class DeploymentCommands(object):
services = api.deployment.check(deployment) services = api.deployment.check(deployment)
except keystone_exceptions.ConnectionRefused: except keystone_exceptions.ConnectionRefused:
admin = deployment.get_credentials_for("openstack")["admin"] admin = deployment.get_credentials_for("openstack")["admin"]
print(_("Unable to connect %s.") % admin["auth_url"]) print(_("Unable to connect %s.") % admin.auth_url)
return(1) return(1)
except exceptions.InvalidArgumentsException: except exceptions.InvalidArgumentsException:
@ -296,11 +300,13 @@ class DeploymentCommands(object):
@cliutils.args("--deployment", dest="deployment", type=str, @cliutils.args("--deployment", dest="deployment", type=str,
metavar="<uuid>", required=False, metavar="<uuid>", required=False,
help="UUID or name of a deployment.") help="UUID or name of a deployment.")
@plugins.ensure_plugins_are_loaded
def use(self, api, deployment): def use(self, api, deployment):
"""Set active deployment. """Set active deployment.
:param deployment: UUID or name of the deployment :param deployment: UUID or name of the deployment
""" """
# TODO(astudenov): make this method platform independent
try: try:
deployment = api.deployment.get(deployment) deployment = api.deployment.get(deployment)
print("Using deployment: %s" % deployment["uuid"]) print("Using deployment: %s" % deployment["uuid"])
@ -309,8 +315,9 @@ class DeploymentCommands(object):
deployment["uuid"]) deployment["uuid"])
creds = deployment.get_credentials_for("openstack") creds = deployment.get_credentials_for("openstack")
credential = creds["admin"] or creds["users"][0]
self._update_openrc_deployment_file( self._update_openrc_deployment_file(
deployment["uuid"], creds["admin"] or creds["users"][0]) deployment["uuid"], credential.to_dict())
print("~/.rally/openrc was updated\n\nHINTS:\n" print("~/.rally/openrc was updated\n\nHINTS:\n"
"\n* To use standard OpenStack clients, set up your env by " "\n* To use standard OpenStack clients, set up your env by "
"running:\n\tsource ~/.rally/openrc\n" "running:\n\tsource ~/.rally/openrc\n"

View File

@ -13,43 +13,16 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from rally import consts from rally.plugins.openstack import credential
# TODO(astudenov): remove this class in future releases
class Credential(object): class Credential(credential.OpenStackCredential):
"""Deprecated version of OpenStackCredential class"""
def __init__(self, auth_url, username, password, tenant_name=None,
project_name=None,
permission=consts.EndpointPermission.USER,
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):
self.auth_url = auth_url
self.username = username
self.password = password
self.tenant_name = tenant_name or project_name
self.permission = permission
self.region_name = region_name
self.endpoint_type = endpoint_type
self.domain_name = domain_name
self.user_domain_name = user_domain_name
self.project_domain_name = project_domain_name
self.endpoint = endpoint
self.insecure = https_insecure
self.cacert = https_cacert
def to_dict(self, include_permission=False): def to_dict(self, include_permission=False):
dct = {"auth_url": self.auth_url, "username": self.username, dct = super(Credential, self).to_dict()
"password": self.password, "tenant_name": self.tenant_name, if not include_permission:
"region_name": self.region_name, dct.pop("permission")
"endpoint_type": self.endpoint_type,
"domain_name": self.domain_name,
"endpoint": self.endpoint,
"https_insecure": self.insecure,
"https_cacert": self.cacert,
"user_domain_name": self.user_domain_name,
"project_domain_name": self.project_domain_name}
if include_permission:
dct["permission"] = self.permission
return dct return dct

View File

@ -21,6 +21,7 @@ from rally.common.i18n import _, _LW
from rally.common import db from rally.common import db
from rally.common import logging from rally.common import logging
from rally import consts from rally import consts
from rally.deployment import credential
from rally import exceptions from rally import exceptions
@ -34,7 +35,7 @@ CREDENTIALS_SCHEMA = {
"items": { "items": {
"type": "object", "type": "object",
"properties": { "properties": {
"admin": {"type": "object"}, "admin": {"type": ["object", "null"]},
"users": { "users": {
"type": "array", "type": "array",
"items": {"type": "object"} "items": {"type": "object"}
@ -97,12 +98,17 @@ class Deployment(object):
def get_credentials_for(self, namespace): def get_credentials_for(self, namespace):
try: try:
return self.deployment["credentials"][namespace][0] creds = self.deployment["credentials"][namespace][0]
except (KeyError, IndexError) as e: except (KeyError, IndexError) as e:
LOG.exception(e) LOG.exception(e)
raise exceptions.RallyException(_( raise exceptions.RallyException(_(
"No credentials found for %s") % namespace) "No credentials found for %s") % namespace)
admin = creds["admin"]
credential_cls = credential.get(namespace)
return {"admin": credential_cls(**admin) if admin else None,
"users": [credential_cls(**user) for user in creds["users"]]}
def set_started(self): def set_started(self):
self._update({"started_at": dt.datetime.now(), self._update({"started_at": dt.datetime.now(),
"status": consts.DeployStatus.DEPLOY_STARTED}) "status": consts.DeployStatus.DEPLOY_STARTED})

View File

@ -0,0 +1,89 @@
# Copyright 2017: Mirantis Inc.
# 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.
import abc
import jsonschema
import six
from rally.common.plugin import plugin
def configure(namespace):
def wrapper(cls):
cls = plugin.configure(name="credential", namespace=namespace)(cls)
return cls
return wrapper
def get(namespace):
return Credential.get(name="credential", namespace=namespace)
@plugin.base()
@six.add_metaclass(abc.ABCMeta)
class Credential(plugin.Plugin):
"""Base class for credentials."""
@abc.abstractmethod
def to_dict(self):
"""Converts creedential object to dict.
:returns: dict that can be used to recreate credential using
constructor: Credential(**credential.to_dict())
"""
@abc.abstractmethod
def verify_connection(self):
"""Verifies that credential can be used for connection."""
@abc.abstractmethod
def list_services(self):
"""Returns available services.
:returns: dict
"""
def configure_builder(namespace):
def wrapper(cls):
cls = plugin.configure(name="credential_builder",
namespace=namespace)(cls)
return cls
return wrapper
def get_builder(namespace):
return CredentialBuilder.get(name="credential_builder",
namespace=namespace)
@plugin.base()
@six.add_metaclass(abc.ABCMeta)
class CredentialBuilder(plugin.Plugin):
"""Base class for extensions of ExistingCloud deployment."""
CONFIG_SCHEMA = {"type": "null"}
def __init__(self, config):
self.config = config
@classmethod
def validate(cls, config):
jsonschema.validate(config, cls.CONFIG_SCHEMA)
@abc.abstractmethod
def build_credentials(self):
"""Builds credentials from provided configuration"""

View File

@ -19,7 +19,6 @@ import six
from rally.common.i18n import _ from rally.common.i18n import _
from rally.common import logging from rally.common import logging
from rally.common import objects
from rally import consts from rally import consts
from rally.deployment import engine from rally.deployment import engine
from rally.deployment.serverprovider import provider from rally.deployment.serverprovider import provider
@ -133,17 +132,13 @@ class DevstackEngine(engine.Engine):
stdin=local_conf) stdin=local_conf)
devstack_server.ssh.run("~/devstack/stack.sh") devstack_server.ssh.run("~/devstack/stack.sh")
admin_credential = objects.Credential( admin_dict = dict(
"http://%s:5000/v2.0/" % self.servers[0].host, "admin", auth_url="http://%s:5000/v2.0/" % self.servers[0].host,
self.local_conf["ADMIN_PASSWORD"], "admin", username="admin",
consts.EndpointPermission.ADMIN) password=self.local_conf["ADMIN_PASSWORD"],
return { tenant_name="admin",
"openstack": [ permission=consts.EndpointPermission.ADMIN)
{ return {"openstack": [{"admin": admin_dict, "users": []}]}
"admin": admin_credential.to_dict(include_permission=True),
"users": []
}
]}
def cleanup(self): def cleanup(self):
for resource in self.deployment.get_resources(type="credentials"): for resource in self.deployment.get_resources(type="credentials"):

View File

@ -13,16 +13,61 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from rally.common import objects import copy
from rally.common import logging
from rally import consts from rally import consts
from rally.deployment import credential
from rally.deployment import engine from rally.deployment import engine
LOG = logging.getLogger(__name__)
@engine.configure(name="ExistingCloud") @engine.configure(name="ExistingCloud")
class ExistingCloud(engine.Engine): class ExistingCloud(engine.Engine):
"""Just use an existing OpenStack deployment without deploying anything. """Platform independent deployment engine.
To use ExistingCloud, you should put credential information to the config: This deployment engine allows specifing list of credentials for one
or more platforms.
Example configuration:
.. code-block:: json
{
"type": "ExistingCloud",
"creds": {
"openstack": {
"auth_url": "http://localhost:5000/v3/",
"region_name": "RegionOne",
"endpoint_type": "public",
"admin": {
"username": "admin",
"password": "admin",
"user_domain_name": "admin",
"project_name": "admin",
"project_domain_name": "admin",
},
"https_insecure": False,
"https_cacert": "",
}
}
}
To specify extra options use can use special "extra" parameter:
.. code-block:: json
{
"type": "ExistingCloud",
...
"extra": {"some_var": "some_value"}
}
It also support deprecated version of configuration that supports
only OpenStack.
keystone v2:
.. code-block:: json .. code-block:: json
@ -40,7 +85,7 @@ class ExistingCloud(engine.Engine):
"https_cacert": "", "https_cacert": "",
} }
Or, using keystone v3 API endpoint: keystone v3 API endpoint:
.. code-block:: json .. code-block:: json
@ -60,114 +105,132 @@ class ExistingCloud(engine.Engine):
"https_cacert": "", "https_cacert": "",
} }
To specify extra options use can use special "extra" parameter:
.. code-block:: json
{
"type": "ExistingCloud",
"auth_url": "http://localhost:5000/v2.0/",
"region_name": "RegionOne",
"endpoint_type": "public",
"admin": {
"username": "admin",
"password": "password",
"tenant_name": "demo"
},
"https_insecure": False,
"https_cacert": "",
"extra": {"some_var": "some_value"}
}
""" """
CONFIG_SCHEMA = { USER_SCHEMA = {
"type": "object", "type": "object",
"oneOf": [
"definitions": { {
"user": { "description": "Keystone V2.0",
"type": "object", "properties": {
"oneOf": [ "username": {"type": "string"},
{ "password": {"type": "string"},
"description": "Keystone V2.0", "tenant_name": {"type": "string"},
"properties": { },
"username": {"type": "string"}, "required": ["username", "password", "tenant_name"],
"password": {"type": "string"}, "additionalProperties": False
"tenant_name": {"type": "string"}, },
}, {
"required": ["username", "password", "tenant_name"], "description": "Keystone V3.0",
"additionalProperties": False "properties": {
}, "username": {"type": "string"},
{ "password": {"type": "string"},
"description": "Keystone V3.0", "domain_name": {"type": "string"},
"properties": { "user_domain_name": {"type": "string"},
"username": {"type": "string"}, "project_name": {"type": "string"},
"password": {"type": "string"}, "project_domain_name": {"type": "string"},
"domain_name": {"type": "string"}, },
"user_domain_name": {"type": "string"}, "required": ["username", "password", "project_name"],
"project_name": {"type": "string"}, "additionalProperties": False
"project_domain_name": {"type": "string"},
},
"required": ["username", "password", "project_name"],
"additionalProperties": False
}
],
} }
}, ],
}
OLD_CONFIG_SCHEMA = {
"type": "object",
"description": "Deprecated schema (openstack only)",
"properties": { "properties": {
"type": {"type": "string"}, "type": {"type": "string"},
"auth_url": {"type": "string"}, "auth_url": {"type": "string"},
"region_name": {"type": "string"}, "region_name": {"type": "string"},
"endpoint": {"oneOf": [ # NOTE(andreykurilin): it looks like we do not use endpoint
# NOTE(andreykurilin): it looks like we do not use endpoint # var at all
# var at all "endpoint": {"type": ["string", "null"]},
{"type": "string", "description": ""},
{"type": "null", "description": ""}]},
"endpoint_type": {"enum": [consts.EndpointType.ADMIN, "endpoint_type": {"enum": [consts.EndpointType.ADMIN,
consts.EndpointType.INTERNAL, consts.EndpointType.INTERNAL,
consts.EndpointType.PUBLIC, consts.EndpointType.PUBLIC,
None]}, None]},
"https_insecure": {"type": "boolean"}, "https_insecure": {"type": "boolean"},
"https_cacert": {"type": "string"}, "https_cacert": {"type": "string"},
"admin": {"$ref": "#/definitions/user"}, "admin": USER_SCHEMA,
"users": { "users": {"type": "array", "items": USER_SCHEMA},
"type": "array",
"items": {"$ref": "#/definitions/user"}
},
"extra": {"type": "object", "additionalProperties": True} "extra": {"type": "object", "additionalProperties": True}
}, },
"required": ["type", "auth_url", "admin"], "required": ["type", "auth_url", "admin"],
"additionalProperties": False "additionalProperties": False
} }
def _create_credential(self, common, user, permission): NEW_CONFIG_SCHEMA = {
return objects.Credential( "type": "object",
common["auth_url"], user["username"], user["password"], "description": "New schema for multiplatform deployment",
tenant_name=user.get("project_name", user.get("tenant_name")), "properties": {
permission=permission, "type": {"enum": ["ExistingCloud"]},
region_name=common.get("region_name"), "creds": {
endpoint_type=common.get("endpoint_type"), "type": "object",
endpoint=common.get("endpoint"), "patternProperties": {
domain_name=user.get("domain_name"), "^[a-z0-9_-]+$": {
user_domain_name=user.get("user_domain_name", None), "oneOf": [
project_domain_name=user.get("project_domain_name", None), {
https_insecure=common.get("https_insecure", False), "description": "Single credential",
https_cacert=common.get("https_cacert") "type": "object"
) },
{
"description": "List of credentials",
"type": "array",
"items": {"type": "object"}
},
]
}
}
},
"extra": {"type": "object", "additionalProperties": True}
},
"required": ["type", "creds"],
"additionalProperties": False
}
CONFIG_SCHEMA = {"type": "object",
"oneOf": [OLD_CONFIG_SCHEMA, NEW_CONFIG_SCHEMA]}
def validate(self, config=None):
config = config or self.config
super(ExistingCloud, self).validate(config)
creds_config = self._get_creds(config)
for platform, config in creds_config.items():
builder_cls = credential.get_builder(platform)
for creds in config:
builder_cls.validate(creds)
def _get_creds(self, config):
if "creds" not in config:
# backward compatibility with old schema
config = copy.deepcopy(config)
del config["type"]
creds_config = {"openstack": [config]}
else:
creds_config = config["creds"]
# convert all credentials to list
for platform, config in creds_config.items():
if isinstance(config, dict):
creds_config[platform] = [config]
return creds_config
def deploy(self): def deploy(self):
permissions = consts.EndpointPermission if "creds" not in self.config:
LOG.warning("Old config schema is deprecated since Rally 0.10.0. "
users = [self._create_credential(self.config, user, permissions.USER) "Please use new config schema for ExistingCloud")
for user in self.config.get("users", [])] creds_config = self._get_creds(self.config)
users = [user.to_dict(include_permission=True) for user in users] parsed_credentials = {}
for platform, config in creds_config.items():
admin = self._create_credential(self.config, builder_cls = credential.get_builder(platform)
self.config.get("admin"), credentials = []
permissions.ADMIN) for creds in config:
admin = admin.to_dict(include_permission=True) builder = builder_cls(creds)
credentials.append(builder.build_credentials())
return {"openstack": [{"admin": admin, "users": users}]} parsed_credentials[platform] = credentials
return parsed_credentials
def cleanup(self): def cleanup(self):
pass pass

View File

@ -150,9 +150,7 @@ class LxcEngine(engine.Engine):
if network: if network:
network += 1 network += 1
admin = objects.Credential("", "", "", "").to_dict( return {"openstack": [{"admin": None, "users": []}]}
include_permission=True)
return {"openstack": [{"admin": admin, "users": []}]}
def cleanup(self): def cleanup(self):
resources = self.deployment.get_resources() resources = self.deployment.get_resources()

View File

@ -21,10 +21,9 @@ import novaclient.exceptions
from rally.common.i18n import _ from rally.common.i18n import _
from rally.common import logging from rally.common import logging
from rally.common import objects
from rally.deployment.serverprovider import provider from rally.deployment.serverprovider import provider
from rally import exceptions from rally import exceptions
from rally import osclients from rally.plugins.openstack import credential
from rally.task import utils from rally.task import utils
@ -144,11 +143,13 @@ class OpenStackProvider(provider.ProviderFactory):
def __init__(self, deployment, config): def __init__(self, deployment, config):
super(OpenStackProvider, self).__init__(deployment, config) super(OpenStackProvider, self).__init__(deployment, config)
user_credential = objects.Credential( user_credential = credential.OpenStackCredential(
config["auth_url"], config["user"], auth_url=config["auth_url"],
config["password"], config["tenant"], username=config["user"],
password=config["password"],
tenant_name=config["tenant"],
region_name=config.get("region")) region_name=config.get("region"))
clients = osclients.Clients(user_credential) clients = user_credential.clients()
self.nova = clients.nova() self.nova = clients.nova()
self.sg = None self.sg = None
try: try:

View File

@ -22,7 +22,6 @@ from six.moves.urllib import parse
from rally.cli import envutils from rally.cli import envutils
from rally.common.i18n import _ from rally.common.i18n import _
from rally.common import logging from rally.common import logging
from rally.common import objects
from rally.common.plugin import plugin from rally.common.plugin import plugin
from rally import consts from rally import consts
from rally import exceptions from rally import exceptions
@ -687,10 +686,10 @@ class Watcher(OSClient):
class Clients(object): class Clients(object):
"""This class simplify and unify work with OpenStack python clients.""" """This class simplify and unify work with OpenStack python clients."""
def __init__(self, credential, api_info=None): def __init__(self, credential, api_info=None, cache=None):
self.credential = credential self.credential = credential
self.api_info = api_info or {} self.api_info = api_info or {}
self.cache = {} self.cache = cache or {}
def __getattr__(self, client_name): def __getattr__(self, client_name):
"""Lazy load of clients.""" """Lazy load of clients."""
@ -700,20 +699,20 @@ class Clients(object):
@classmethod @classmethod
def create_from_env(cls): def create_from_env(cls):
creds = envutils.get_creds_from_env_vars() creds = envutils.get_creds_from_env_vars()
return cls( from rally.plugins.openstack import credential
objects.Credential( oscred = credential.OpenStackCredential(
creds["auth_url"], auth_url=creds["auth_url"],
creds["admin"]["username"], username=creds["admin"]["username"],
creds["admin"]["password"], password=creds["admin"]["password"],
creds["admin"]["tenant_name"], tenant_name=creds["admin"]["tenant_name"],
endpoint_type=creds["endpoint_type"], endpoint_type=creds["endpoint_type"],
user_domain_name=creds["admin"].get("user_domain_name"), user_domain_name=creds["admin"].get("user_domain_name"),
project_domain_name=creds["admin"].get("project_domain_name"), project_domain_name=creds["admin"].get("project_domain_name"),
endpoint=creds["endpoint"], endpoint=creds["endpoint"],
region_name=creds["region_name"], region_name=creds["region_name"],
https_cacert=creds["https_cacert"], https_cacert=creds["https_cacert"],
https_insecure=creds["https_insecure"] https_insecure=creds["https_insecure"])
)) return cls(oscred)
def clear(self): def clear(self):
"""Remove all cached client handles.""" """Remove all cached client handles."""

View File

@ -21,7 +21,6 @@ from rally.common import logging
from rally.common.plugin import discover from rally.common.plugin import discover
from rally.common.plugin import plugin from rally.common.plugin import plugin
from rally.common import utils as rutils from rally.common import utils as rutils
from rally import osclients
from rally.plugins.openstack.cleanup import base from rally.plugins.openstack.cleanup import base
@ -29,7 +28,6 @@ LOG = logging.getLogger(__name__)
class SeekAndDestroy(object): class SeekAndDestroy(object):
cache = {}
def __init__(self, manager_cls, admin, users, api_versions=None, def __init__(self, manager_cls, admin, users, api_versions=None,
resource_classes=None, task_id=None): resource_classes=None, task_id=None):
@ -58,15 +56,8 @@ class SeekAndDestroy(object):
"""Simplifies initialization and caching OpenStack clients.""" """Simplifies initialization and caching OpenStack clients."""
if not user: if not user:
return None return None
# NOTE(astudenov): Credential now supports caching by default
if self.api_versions: return user["credential"].clients(api_info=self.api_versions)
key = str((user["credential"], sorted(self.api_versions.items())))
else:
key = user["credential"]
if key not in self.cache:
self.cache[key] = osclients.Clients(
user["credential"], api_info=self.api_versions)
return self.cache[key]
def _delete_single_resource(self, resource): def _delete_single_resource(self, resource):
"""Safe resource deletion with retries and timeouts. """Safe resource deletion with retries and timeouts.
@ -170,7 +161,6 @@ class SeekAndDestroy(object):
admin=admin_client, admin=admin_client,
user=self._get_cached_client(user), user=self._get_cached_client(user),
tenant_uuid=user["tenant_id"]) tenant_uuid=user["tenant_id"])
_publish(self.admin, user, manager) _publish(self.admin, user, manager)
def _consumer(self, cache, args): def _consumer(self, cache, args):
@ -268,14 +258,14 @@ def cleanup(names=None, admin_required=None, admin=None, users=None,
:param admin_required: If None -> return all plugins :param admin_required: If None -> return all plugins
If True -> return only admin plugins If True -> return only admin plugins
If False -> return only non admin plugins If False -> return only non admin plugins
:param admin: rally.common.objects.Credential that corresponds to OpenStack :param admin: rally.deployment.credential.Credential that corresponds to
admin. OpenStack admin.
:param users: List of OpenStack users that was used during benchmarking. :param users: List of OpenStack users that was used during benchmarking.
Every user has next structure: Every user has next structure:
{ {
"id": <uuid1>, "id": <uuid1>,
"tenant_id": <uuid2>, "tenant_id": <uuid2>,
"credential": <rally.common.objects.Credential> "credential": <rally.deployment.credential.Credential>
} }
:param superclass: The plugin superclass to perform cleanup :param superclass: The plugin superclass to perform cleanup
for. E.g., this could be for. E.g., this could be

View File

@ -15,8 +15,6 @@
from rally.common.i18n import _ from rally.common.i18n import _
from rally.common import logging from rally.common import logging
from rally.common import objects
from rally import osclients
from rally.task import context from rally.task import context
@ -46,10 +44,8 @@ class ExistingUsers(context.Context):
self.context["tenants"] = {} self.context["tenants"] = {}
self.context["user_choice_method"] = "random" self.context["user_choice_method"] = "random"
for user in self.config: for user_credential in self.config:
user_credential = objects.Credential(**user) user_clients = user_credential.clients()
user_clients = osclients.Clients(user_credential)
user_id = user_clients.keystone.auth_ref.user_id user_id = user_clients.keystone.auth_ref.user_id
tenant_id = user_clients.keystone.auth_ref.project_id tenant_id = user_clients.keystone.auth_ref.project_id

View File

@ -21,11 +21,11 @@ from oslo_config import cfg
from rally.common import broker from rally.common import broker
from rally.common.i18n import _ from rally.common.i18n import _
from rally.common import logging from rally.common import logging
from rally.common import objects
from rally.common import utils as rutils from rally.common import utils as rutils
from rally import consts from rally import consts
from rally import exceptions from rally import exceptions
from rally import osclients from rally import osclients
from rally.plugins.openstack import credential
from rally.plugins.openstack.services.identity import identity from rally.plugins.openstack.services.identity import identity
from rally.plugins.openstack.wrappers import network from rally.plugins.openstack.wrappers import network
from rally.task import context from rally.task import context
@ -207,10 +207,12 @@ class UserGenerator(context.Context):
project_id=tenant_id, project_id=tenant_id,
domain_name=user_dom, domain_name=user_dom,
default_role=default_role) default_role=default_role)
user_credential = objects.Credential( user_credential = credential.OpenStackCredential(
self.credential.auth_url, user.name, password, auth_url=self.credential.auth_url,
self.context["tenants"][tenant_id]["name"], username=user.name,
consts.EndpointPermission.USER, password=password,
tenant_name=self.context["tenants"][tenant_id]["name"],
permission=consts.EndpointPermission.USER,
project_domain_name=project_dom, project_domain_name=project_dom,
user_domain_name=user_dom, user_domain_name=user_dom,
endpoint_type=self.credential.endpoint_type, endpoint_type=self.credential.endpoint_type,

View File

@ -0,0 +1,173 @@
# Copyright 2017: Mirantis Inc.
# 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 consts
from rally.deployment import credential
from rally import osclients
@credential.configure("openstack")
class OpenStackCredential(credential.Credential):
"""Credential for OpenStack."""
def __init__(self, auth_url, username, password, tenant_name=None,
project_name=None,
permission=consts.EndpointPermission.USER,
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):
self.auth_url = auth_url
self.username = username
self.password = password
self.tenant_name = tenant_name or project_name
self.permission = permission
self.region_name = region_name
self.endpoint_type = endpoint_type
self.domain_name = domain_name
self.user_domain_name = user_domain_name
self.project_domain_name = project_domain_name
self.endpoint = endpoint
self.https_insecure = https_insecure
self.https_cacert = https_cacert
self._clients_cache = {}
# backward compatibility
@property
def insecure(self):
return self.https_insecure
# backward compatibility
@property
def cacert(self):
return self.https_cacert
def to_dict(self):
return {"auth_url": self.auth_url,
"username": self.username,
"password": self.password,
"tenant_name": self.tenant_name,
"region_name": self.region_name,
"endpoint_type": self.endpoint_type,
"domain_name": self.domain_name,
"endpoint": self.endpoint,
"https_insecure": self.https_insecure,
"https_cacert": self.https_cacert,
"user_domain_name": self.user_domain_name,
"project_domain_name": self.project_domain_name,
"permission": self.permission}
def verify_connection(self):
if self.permission == consts.EndpointPermission.ADMIN:
self.clients().verified_keystone()
else:
self.clients().keystone()
def list_services(self):
return self.clients().services()
def clients(self, api_info=None):
return osclients.Clients(self, api_info=api_info,
cache=self._clients_cache)
@credential.configure_builder("openstack")
class OpenStackCredentialBuilder(credential.CredentialBuilder):
"""Builds credentials provided by ExistingCloud config."""
USER_SCHEMA = {
"type": "object",
"oneOf": [
{
"description": "Keystone V2.0",
"properties": {
"username": {"type": "string"},
"password": {"type": "string"},
"tenant_name": {"type": "string"},
},
"required": ["username", "password", "tenant_name"],
"additionalProperties": False
},
{
"description": "Keystone V3.0",
"properties": {
"username": {"type": "string"},
"password": {"type": "string"},
"domain_name": {"type": "string"},
"user_domain_name": {"type": "string"},
"project_name": {"type": "string"},
"project_domain_name": {"type": "string"},
},
"required": ["username", "password", "project_name"],
"additionalProperties": False
}
],
}
CONFIG_SCHEMA = {
"type": "object",
"properties": {
"admin": USER_SCHEMA,
"users": {"type": "array", "items": USER_SCHEMA},
"auth_url": {"type": "string"},
"region_name": {"type": "string"},
# NOTE(andreykurilin): it looks like we do not use endpoint
# var at all
"endpoint": {"type": ["string", "null"]},
"endpoint_type": {
"enum": [consts.EndpointType.ADMIN,
consts.EndpointType.INTERNAL,
consts.EndpointType.PUBLIC,
None]},
"https_insecure": {"type": "boolean"},
"https_cacert": {"type": "string"},
},
"required": ["auth_url", "admin"],
"additionalProperties": False
}
def _create_credential(self, common, user, permission):
cred = OpenStackCredential(
auth_url=common["auth_url"],
username=user["username"],
password=user["password"],
tenant_name=user.get("project_name", user.get("tenant_name")),
permission=permission,
region_name=common.get("region_name"),
endpoint_type=common.get("endpoint_type"),
endpoint=common.get("endpoint"),
domain_name=user.get("domain_name"),
user_domain_name=user.get("user_domain_name", None),
project_domain_name=user.get("project_domain_name", None),
https_insecure=common.get("https_insecure", False),
https_cacert=common.get("https_cacert"))
return cred.to_dict()
def build_credentials(self):
permissions = consts.EndpointPermission
users = [self._create_credential(self.config, user, permissions.USER)
for user in self.config.get("users", [])]
admin = self._create_credential(self.config,
self.config.get("admin"),
permissions.ADMIN)
return {"admin": admin, "users": users}
# NOTE(astudenov): Let's consider moving rally.osclients here

View File

@ -108,9 +108,9 @@ class OpenStackScenario(scenario.Scenario):
@classmethod @classmethod
def validate(cls, name, config, admin=None, users=None, deployment=None): def validate(cls, name, config, admin=None, users=None, deployment=None):
if admin: if admin:
admin = osclients.Clients(admin) admin = admin.clients()
if users: if users:
users = [osclients.Clients(user["credential"]) for user in users] users = [user["credential"].clients() for user in users]
super(OpenStackScenario, cls).validate( super(OpenStackScenario, cls).validate(
name=name, config=config, admin=admin, users=users, name=name, config=config, admin=admin, users=users,
deployment=deployment) deployment=deployment)

View File

@ -21,8 +21,6 @@ import six
from six.moves import configparser from six.moves import configparser
from six.moves.urllib import parse from six.moves.urllib import parse
from rally.common import objects
from rally import osclients
from rally.verification import utils from rally.verification import utils
@ -88,7 +86,7 @@ class TempestConfigfileManager(object):
def __init__(self, deployment): def __init__(self, deployment):
self.credential = deployment.get_credentials_for("openstack")["admin"] self.credential = deployment.get_credentials_for("openstack")["admin"]
self.clients = osclients.Clients(objects.Credential(**self.credential)) self.clients = self.credential.clients()
self.available_services = self.clients.services().values() self.available_services = self.clients.services().values()
self.conf = configparser.ConfigParser() self.conf = configparser.ConfigParser()
@ -100,14 +98,14 @@ class TempestConfigfileManager(object):
def _configure_auth(self, section_name="auth"): def _configure_auth(self, section_name="auth"):
self.conf.set(section_name, "admin_username", self.conf.set(section_name, "admin_username",
self.credential["username"]) self.credential.username)
self.conf.set(section_name, "admin_password", self.conf.set(section_name, "admin_password",
self.credential["password"]) self.credential.password)
self.conf.set(section_name, "admin_project_name", self.conf.set(section_name, "admin_project_name",
self.credential["tenant_name"]) self.credential.tenant_name)
# Keystone v3 related parameter # Keystone v3 related parameter
self.conf.set(section_name, "admin_domain_name", self.conf.set(section_name, "admin_domain_name",
self.credential["user_domain_name"] or "Default") self.credential.user_domain_name or "Default")
# Sahara has two service types: 'data_processing' and 'data-processing'. # Sahara has two service types: 'data_processing' and 'data-processing'.
# 'data_processing' is deprecated, but it can be used in previous OpenStack # 'data_processing' is deprecated, but it can be used in previous OpenStack
@ -120,9 +118,9 @@ class TempestConfigfileManager(object):
def _configure_identity(self, section_name="identity"): def _configure_identity(self, section_name="identity"):
self.conf.set(section_name, "region", self.conf.set(section_name, "region",
self.credential["region_name"]) self.credential.region_name)
auth_url = self.credential["auth_url"] auth_url = self.credential.auth_url
if "/v2" not in auth_url and "/v3" not in auth_url: if "/v2" not in auth_url and "/v3" not in auth_url:
auth_version = "v2" auth_version = "v2"
auth_url_v2 = parse.urljoin(auth_url, "/v2.0") auth_url_v2 = parse.urljoin(auth_url, "/v2.0")
@ -136,9 +134,9 @@ class TempestConfigfileManager(object):
auth_url_v2.replace("/v2.0", "/v3")) auth_url_v2.replace("/v2.0", "/v3"))
self.conf.set(section_name, "disable_ssl_certificate_validation", self.conf.set(section_name, "disable_ssl_certificate_validation",
str(self.credential["https_insecure"])) str(self.credential.https_insecure))
self.conf.set(section_name, "ca_certificates_file", self.conf.set(section_name, "ca_certificates_file",
self.credential["https_cacert"]) self.credential.https_cacert)
# The compute section is configured in context class for Tempest resources. # The compute section is configured in context class for Tempest resources.
# Options which are configured there: 'image_ref', 'image_ref_alt', # Options which are configured there: 'image_ref', 'image_ref_alt',

View File

@ -21,9 +21,7 @@ from six.moves import configparser
from rally.common.i18n import _ from rally.common.i18n import _
from rally.common import logging from rally.common import logging
from rally.common import objects
from rally import exceptions from rally import exceptions
from rally import osclients
from rally.plugins.openstack.verification.tempest import config as conf from rally.plugins.openstack.verification.tempest import config as conf
from rally.plugins.openstack.wrappers import glance from rally.plugins.openstack.wrappers import glance
from rally.plugins.openstack.wrappers import network from rally.plugins.openstack.wrappers import network
@ -45,7 +43,7 @@ class TempestContext(context.VerifierContext):
super(TempestContext, self).__init__(ctx) super(TempestContext, self).__init__(ctx)
creds = self.verifier.deployment.get_credentials_for("openstack") creds = self.verifier.deployment.get_credentials_for("openstack")
self.clients = osclients.Clients(objects.Credential(**creds["admin"])) self.clients = creds["admin"].clients()
self.available_services = self.clients.services().values() self.available_services = self.clients.services().values()
self.conf = configparser.ConfigParser() self.conf = configparser.ConfigParser()

View File

@ -326,13 +326,9 @@ class TaskEngine(object):
for platform, workloads in platforms.items(): for platform, workloads in platforms.items():
creds = self.deployment.get_credentials_for(platform) creds = self.deployment.get_credentials_for(platform)
admin = objects.Credential(**creds["admin"]) admin = creds["admin"]
if admin:
# TODO(astudenov): move this check to validator of Credential admin.verify_connection()
if platform == "openstack":
from rally import osclients
clients = osclients.Clients(admin)
clients.verified_keystone()
workloads_with_users = [] workloads_with_users = []
workloads_with_existing_users = [] workloads_with_existing_users = []
@ -399,9 +395,6 @@ class TaskEngine(object):
creds = self.deployment.get_credentials_for(namespace) creds = self.deployment.get_credentials_for(namespace)
existing_users = creds["users"] existing_users = creds["users"]
# TODO(astudenov): use credential plugin in future refactoring
admin = objects.Credential(**creds["admin"])
scenario_context = copy.deepcopy(scenario_cls.get_default_context()) scenario_context = copy.deepcopy(scenario_cls.get_default_context())
if existing_users and "users" not in ctx: if existing_users and "users" not in ctx:
scenario_context.setdefault("existing_users", existing_users) scenario_context.setdefault("existing_users", existing_users)
@ -411,7 +404,7 @@ class TaskEngine(object):
scenario_context.update(ctx) scenario_context.update(ctx)
context_obj = { context_obj = {
"task": self.task, "task": self.task,
"admin": {"credential": admin}, "admin": {"credential": creds["admin"]},
"scenario_name": name, "scenario_name": name,
"config": scenario_context "config": scenario_context
} }

View File

@ -23,11 +23,9 @@ from novaclient import exceptions as nova_exc
import six import six
from rally.common.i18n import _ from rally.common.i18n import _
from rally.common import objects
from rally.common import yamlutils as yaml from rally.common import yamlutils as yaml
from rally import consts from rally import consts
from rally import exceptions from rally import exceptions
from rally import osclients
from rally.plugins.openstack.context.nova import flavors as flavors_ctx from rally.plugins.openstack.context.nova import flavors as flavors_ctx
from rally.plugins.openstack import types as openstack_types from rally.plugins.openstack import types as openstack_types
from rally.task import types from rally.task import types
@ -461,8 +459,7 @@ def required_services(config, clients, deployment, *required_services):
if consts.Service.NOVA_NET in required_services: if consts.Service.NOVA_NET in required_services:
creds = deployment.get_credentials_for("openstack") creds = deployment.get_credentials_for("openstack")
nova = osclients.Clients( nova = creds["admin"].clients().nova()
objects.Credential(**creds["admin"])).nova()
for service in nova.services.list(): for service in nova.services.list():
if (service.binary == consts.Service.NOVA_NET and if (service.binary == consts.Service.NOVA_NET and
service.status == "enabled"): service.status == "enabled"):
@ -507,8 +504,7 @@ def required_cinder_services(config, clients, deployment, service_name):
:param service_name: Cinder service name :param service_name: Cinder service name
""" """
creds = deployment.get_credentials_for("openstack") creds = deployment.get_credentials_for("openstack")
admin_client = osclients.Clients( admin_client = creds["admin"].clients().cinder()
objects.Credential(**creds["admin"])).cinder()
for service in admin_client.services.list(): for service in admin_client.services.list():
if (service.binary == six.text_type(service_name) and if (service.binary == six.text_type(service_name) and
@ -529,7 +525,7 @@ def required_clients(config, clients, deployment, *components, **kwargs):
""" """
if kwargs.get("admin", False): if kwargs.get("admin", False):
creds = deployment.get_credentials_for("openstack") creds = deployment.get_credentials_for("openstack")
clients = osclients.Clients(objects.Credential(**creds["admin"])) clients = creds["admin"].clients()
for client_component in components: for client_component in components:
try: try:

View File

@ -24,10 +24,9 @@ import sys
import six import six
from rally.cli import cliutils from rally.cli import cliutils
from rally.common import objects
from rally.common.plugin import discover from rally.common.plugin import discover
from rally import consts from rally import consts
from rally import osclients from rally.plugins.openstack import credential
def skip_if_service(service): def skip_if_service(service):
@ -340,7 +339,7 @@ class CloudResources(object):
""" """
def __init__(self, **kwargs): def __init__(self, **kwargs):
self.clients = osclients.Clients(objects.Credential(**kwargs)) self.clients = credential.OpenStackCredential(**kwargs).clients()
def _deduplicate(self, lst): def _deduplicate(self, lst):
"""Change list duplicates to make all items unique. """Change list duplicates to make all items unique.
@ -426,8 +425,8 @@ def main():
out = subprocess.check_output(["rally", "deployment", out = subprocess.check_output(["rally", "deployment",
"config"]) "config"])
config = json.loads(out if six.PY2 else out.decode("utf-8")) config = json.loads(out if six.PY2 else out.decode("utf-8"))
config = config["creds"]["openstack"]
config.update(config.pop("admin")) config.update(config.pop("admin"))
del config["type"]
if "users" in config: if "users" in config:
del config["users"] del config["users"]

View File

@ -64,7 +64,7 @@ function setUp () {
DEPLOYMENT_CONFIG_FILE=~/.rally/with-existing-users-config DEPLOYMENT_CONFIG_FILE=~/.rally/with-existing-users-config
rally deployment config > $DEPLOYMENT_CONFIG_FILE rally deployment config > $DEPLOYMENT_CONFIG_FILE
sed -i '1a "users": [\ sed -i '3a "users": [\
{\ {\
"username": "rally-test-user-1",\ "username": "rally-test-user-1",\
"password": "rally-test-password-1",\ "password": "rally-test-password-1",\

View File

@ -23,8 +23,7 @@ import sys
import uuid import uuid
from rally.cli import envutils from rally.cli import envutils
from rally.common import objects from rally.plugins.openstack import credential
from rally import osclients
from rally.ui import utils from rally.ui import utils
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -172,9 +171,9 @@ def main():
config = json.loads( config = json.loads(
subprocess.check_output(["rally", "deployment", "config"])) subprocess.check_output(["rally", "deployment", "config"]))
config = config["creds"]["openstack"]
config.update(config.pop("admin")) config.update(config.pop("admin"))
del config["type"] clients = credential.OpenStackCredential(**config).clients()
clients = osclients.Clients(objects.Credential(**config))
if args.ctx_create_resources: if args.ctx_create_resources:
# If the 'ctx-create-resources' arg is provided, delete images and # If the 'ctx-create-resources' arg is provided, delete images and

View File

@ -25,7 +25,6 @@ import six
from rally import api from rally import api
from rally.common import db from rally.common import db
from rally.common import objects
from rally import plugins from rally import plugins
from rally.plugins.openstack.context.keystone import users from rally.plugins.openstack.context.keystone import users
from tests.functional import utils from tests.functional import utils
@ -51,7 +50,7 @@ class TestTaskSamples(unittest.TestCase):
return False return False
@plugins.ensure_plugins_are_loaded @plugins.ensure_plugins_are_loaded
def test_task_samples_is_valid(self): def test_task_samples_are_valid(self):
rally = utils.Rally(force_new_db=True) rally = utils.Rally(force_new_db=True)
# In TestTaskSamples, Rally API will be called directly (not via # In TestTaskSamples, Rally API will be called directly (not via
# subprocess), so we need to change database options to temp database. # subprocess), so we need to change database options to temp database.
@ -60,8 +59,7 @@ class TestTaskSamples(unittest.TestCase):
# let's use pre-created users to make TestTaskSamples quicker # let's use pre-created users to make TestTaskSamples quicker
deployment = api.Deployment.get("MAIN") deployment = api.Deployment.get("MAIN")
creds = deployment.get_credentials_for("openstack") admin_cred = deployment.get_credentials_for("openstack")["admin"]
admin_cred = objects.Credential(**creds["admin"])
ctx = {"admin": {"credential": admin_cred}, ctx = {"admin": {"credential": admin_cred},
"task": {"uuid": self.__class__.__name__}} "task": {"uuid": self.__class__.__name__}}
@ -70,15 +68,16 @@ class TestTaskSamples(unittest.TestCase):
self.addCleanup(user_ctx.cleanup) self.addCleanup(user_ctx.cleanup)
config = deployment["config"] config = deployment["config"]
user = copy.copy(config["admin"]) os_creds = config["creds"]["openstack"]
user = copy.copy(os_creds["admin"])
user["username"] = ctx["users"][0]["credential"].username user["username"] = ctx["users"][0]["credential"].username
user["password"] = ctx["users"][0]["credential"].password user["password"] = ctx["users"][0]["credential"].password
if "project_name" in config["admin"]: if "project_name" in os_creds["admin"]:
# it is Keystone # it is Keystone
user["project_name"] = ctx["users"][0]["credential"].tenant_name user["project_name"] = ctx["users"][0]["credential"].tenant_name
else: else:
user["tenant_name"] = ctx["users"][0]["credential"].tenant_name user["tenant_name"] = ctx["users"][0]["credential"].tenant_name
config["users"] = [user] config["creds"]["openstack"]["users"] = [user]
rally("deployment destroy MAIN", write_report=False) rally("deployment destroy MAIN", write_report=False)
deployment_cfg = os.path.join(rally.tmp_dir, "new_deployment.json") deployment_cfg = os.path.join(rally.tmp_dir, "new_deployment.json")

View File

@ -20,7 +20,6 @@ import mock
from rally.cli.commands import deployment from rally.cli.commands import deployment
from rally.cli import envutils from rally.cli import envutils
from rally.common import objects
from rally import consts from rally import consts
from rally import exceptions from rally import exceptions
from tests.unit import fakes from tests.unit import fakes
@ -231,14 +230,13 @@ class DeploymentCommandsTestCase(test.TestCase):
def test_show(self, mock_struct, mock_print_list): def test_show(self, mock_struct, mock_print_list):
deployment_id = "b1a6153e-a314-4cb3-b63b-cf08c1a416c3" deployment_id = "b1a6153e-a314-4cb3-b63b-cf08c1a416c3"
value = { value = {
"admin": { "admin": fakes.fake_credential(
"auth_url": "url", auth_url="url",
"username": "u", username="u",
"password": "p", password="p",
"tenant_name": "t", tenant_name="t",
"region_name": "r", region_name="r",
"endpoint_type": consts.EndpointType.INTERNAL endpoint_type=consts.EndpointType.INTERNAL),
},
"users": [] "users": []
} }
deployment = self.fake_api.deployment.get.return_value deployment = self.fake_api.deployment.get.return_value
@ -267,12 +265,12 @@ class DeploymentCommandsTestCase(test.TestCase):
deployment_id = "593b683c-4b16-4b2b-a56b-e162bd60f10b" deployment_id = "593b683c-4b16-4b2b-a56b-e162bd60f10b"
self.fake_api.deployment.get.return_value = fakes.FakeDeployment( self.fake_api.deployment.get.return_value = fakes.FakeDeployment(
uuid=deployment_id, uuid=deployment_id,
admin={"auth_url": "fake_auth_url", admin=fakes.fake_credential(**{"auth_url": "fake_auth_url",
"username": "fake_username", "username": "fake_username",
"password": "fake_password", "password": "fake_password",
"tenant_name": "fake_tenant_name", "tenant_name": "fake_tenant_name",
"endpoint": "fake_endpoint", "endpoint": "fake_endpoint",
"region_name": None}) "region_name": None}))
with mock.patch("rally.cli.commands.deployment.open", mock.mock_open(), with mock.patch("rally.cli.commands.deployment.open", mock.mock_open(),
create=True) as mock_file: create=True) as mock_file:
@ -304,7 +302,7 @@ class DeploymentCommandsTestCase(test.TestCase):
self.fake_api.deployment.get.return_value = fakes.FakeDeployment( self.fake_api.deployment.get.return_value = fakes.FakeDeployment(
uuid=deployment_id, uuid=deployment_id,
admin={ admin=fakes.fake_credential(**{
"auth_url": "http://localhost:5000/v3", "auth_url": "http://localhost:5000/v3",
"username": "fake_username", "username": "fake_username",
"password": "fake_password", "password": "fake_password",
@ -312,7 +310,7 @@ class DeploymentCommandsTestCase(test.TestCase):
"endpoint": "fake_endpoint", "endpoint": "fake_endpoint",
"region_name": None, "region_name": None,
"user_domain_name": "fake_user_domain", "user_domain_name": "fake_user_domain",
"project_domain_name": "fake_project_domain"}) "project_domain_name": "fake_project_domain"}))
with mock.patch("rally.cli.commands.deployment.open", mock.mock_open(), with mock.patch("rally.cli.commands.deployment.open", mock.mock_open(),
create=True) as mock_file: create=True) as mock_file:
@ -342,9 +340,10 @@ class DeploymentCommandsTestCase(test.TestCase):
@mock.patch("rally.common.fileutils.update_globals_file") @mock.patch("rally.common.fileutils.update_globals_file")
def test_use_by_name(self, mock_update_globals_file, def test_use_by_name(self, mock_update_globals_file,
mock__update_openrc_deployment_file): mock__update_openrc_deployment_file):
fake_credential = fakes.fake_credential(foo="fake_credentials")
fake_deployment = fakes.FakeDeployment( fake_deployment = fakes.FakeDeployment(
uuid="fake_uuid", uuid="fake_uuid",
admin="fake_credentials") admin=fake_credential)
self.fake_api.deployment.list.return_value = [fake_deployment] self.fake_api.deployment.list.return_value = [fake_deployment]
self.fake_api.deployment.get.return_value = fake_deployment self.fake_api.deployment.get.return_value = fake_deployment
status = self.deployment.use(self.fake_api, deployment="fake_name") status = self.deployment.use(self.fake_api, deployment="fake_name")
@ -353,7 +352,7 @@ class DeploymentCommandsTestCase(test.TestCase):
mock_update_globals_file.assert_called_once_with( mock_update_globals_file.assert_called_once_with(
envutils.ENV_DEPLOYMENT, "fake_uuid") envutils.ENV_DEPLOYMENT, "fake_uuid")
mock__update_openrc_deployment_file.assert_called_once_with( mock__update_openrc_deployment_file.assert_called_once_with(
"fake_uuid", "fake_credentials") "fake_uuid", {"foo": "fake_credentials"})
def test_deployment_not_found(self): def test_deployment_not_found(self):
deployment_id = "e87e4dca-b515-4477-888d-5f6103f13b42" deployment_id = "e87e4dca-b515-4477-888d-5f6103f13b42"
@ -364,9 +363,9 @@ class DeploymentCommandsTestCase(test.TestCase):
@mock.patch("rally.cli.commands.deployment.cliutils.print_list") @mock.patch("rally.cli.commands.deployment.cliutils.print_list")
def test_deployment_check(self, mock_print_list): def test_deployment_check(self, mock_print_list):
deployment_id = "e87e4dca-b515-4477-888d-5f6103f13b42" deployment_id = "e87e4dca-b515-4477-888d-5f6103f13b42"
sample_credential = objects.Credential("http://192.168.1.1:5000/v2.0/", sample_credential = fakes.fake_credential(
"admin", auth_url="http://192.168.1.1:5000/v2.0/",
"adminpass").to_dict() username="admin", password="adminpass")
deployment = {"admin": sample_credential, deployment = {"admin": sample_credential,
"users": [sample_credential]} "users": [sample_credential]}
self.fake_api.deployment.get.return_value = deployment self.fake_api.deployment.get.return_value = deployment
@ -388,10 +387,9 @@ class DeploymentCommandsTestCase(test.TestCase):
def test_deployment_check_raise(self): def test_deployment_check_raise(self):
deployment_id = "e87e4dca-b515-4477-888d-5f6103f13b42" deployment_id = "e87e4dca-b515-4477-888d-5f6103f13b42"
sample_credential = objects.Credential("http://192.168.1.1:5000/v2.0/", sample_credential = fakes.fake_credential(
"admin", auth_url="http://192.168.1.1:5000/v2.0/",
"adminpass").to_dict() username="admin", password="adminpass")
sample_credential["not-exist-key"] = "error"
deployment = self.fake_api.deployment.get.return_value deployment = self.fake_api.deployment.get.return_value
deployment.get_credentials_for.return_value = { deployment.get_credentials_for.return_value = {
"admin": sample_credential, "users": []} "admin": sample_credential, "users": []}

View File

@ -18,6 +18,8 @@ from rally import consts
from tests.unit import test from tests.unit import test
# TODO(astudenov): remove this class in future releases
class CredentialTestCase(test.TestCase): class CredentialTestCase(test.TestCase):
def test_to_dict(self): def test_to_dict(self):

View File

@ -117,8 +117,10 @@ class DeploymentTestCase(test.TestCase):
{"config": {"opt": "val"}}, {"config": {"opt": "val"}},
) )
@mock.patch("rally.deployment.credential.get")
@mock.patch("rally.common.objects.deploy.db.deployment_update") @mock.patch("rally.common.objects.deploy.db.deployment_update")
def test_update_credentials(self, mock_deployment_update): def test_update_credentials(self, mock_deployment_update,
mock_credential_get):
mock_deployment_update.return_value = self.deployment mock_deployment_update.return_value = self.deployment
deploy = objects.Deployment(deployment=self.deployment) deploy = objects.Deployment(deployment=self.deployment)
credentials = {"foo": [{"admin": {"fake_admin": True}, credentials = {"foo": [{"admin": {"fake_admin": True},
@ -132,23 +134,38 @@ class DeploymentTestCase(test.TestCase):
"users": [{"fake_user": True}]}]} "users": [{"fake_user": True}]}]}
}) })
def test_get_credentials_for(self): @mock.patch("rally.deployment.credential.get")
def test_get_credentials_for(self, mock_credential_get):
credential_cls = mock_credential_get.return_value
credential_inst = credential_cls.return_value
credentials = {"foo": [{"admin": {"fake_admin": True}, credentials = {"foo": [{"admin": {"fake_admin": True},
"users": [{"fake_user": True}]}]} "users": [{"fake_user": True}]}]}
self.deployment["credentials"] = credentials self.deployment["credentials"] = credentials
deploy = objects.Deployment(deployment=self.deployment) deploy = objects.Deployment(deployment=self.deployment)
creds = deploy.get_credentials_for("foo") creds = deploy.get_credentials_for("foo")
self.assertEqual(credentials["foo"][0], creds)
def test_get_deprecated(self): mock_credential_get.assert_called_once_with("foo")
credential_cls.assert_has_calls((
mock.call(fake_admin=True),
mock.call(fake_user=True),
))
self.assertEqual({"admin": credential_inst,
"users": [credential_inst]}, creds)
@mock.patch("rally.deployment.credential.get")
def test_get_deprecated(self, mock_credential_get):
credential_cls = mock_credential_get.return_value
credential_inst = credential_cls.return_value
credentials = {"openstack": [{"admin": {"fake_admin": True}, credentials = {"openstack": [{"admin": {"fake_admin": True},
"users": [{"fake_user": True}]}]} "users": [{"fake_user": True}]}]}
self.deployment["credentials"] = credentials self.deployment["credentials"] = credentials
deploy = objects.Deployment(deployment=self.deployment) deploy = objects.Deployment(deployment=self.deployment)
self.assertEqual(credentials["openstack"][0]["admin"], deploy["admin"]) self.assertEqual(credential_inst, deploy["admin"])
self.assertEqual(credentials["openstack"][0]["users"], deploy["users"]) self.assertEqual([credential_inst], deploy["users"])
def test_update_empty_credentials(self): def test_update_empty_credentials(self):
deploy = objects.Deployment(deployment=self.deployment) deploy = objects.Deployment(deployment=self.deployment)

View File

@ -16,6 +16,7 @@
import jsonschema import jsonschema
import mock import mock
from rally import consts
from rally.deployment.engines import devstack from rally.deployment.engines import devstack
from tests.unit import test from tests.unit import test
@ -77,14 +78,12 @@ class DevstackEngineTestCase(test.TestCase):
@mock.patch("rally.deployment.engines.devstack.get_updated_server") @mock.patch("rally.deployment.engines.devstack.get_updated_server")
@mock.patch("rally.deployment.engines.devstack.get_script") @mock.patch("rally.deployment.engines.devstack.get_script")
@mock.patch("rally.deployment.serverprovider.provider.Server") @mock.patch("rally.deployment.serverprovider.provider.Server")
@mock.patch("rally.deployment.engines.devstack.objects.Credential") def test_deploy(self, mock_server, mock_get_script,
def test_deploy(self, mock_credential, mock_server, mock_get_script,
mock_get_updated_server, mock_engine_get_provider): mock_get_updated_server, mock_engine_get_provider):
mock_engine_get_provider.return_value = fake_provider = ( mock_engine_get_provider.return_value = fake_provider = (
mock.Mock() mock.Mock()
) )
server = mock.Mock(host="host") server = mock.Mock(host="host")
mock_credential.return_value.to_dict.return_value = "fake_credential"
mock_get_updated_server.return_value = ds_server = mock.Mock() mock_get_updated_server.return_value = ds_server = mock.Mock()
mock_get_script.return_value = "fake_script" mock_get_script.return_value = "fake_script"
server.get_credentials.return_value = "fake_credentials" server.get_credentials.return_value = "fake_credentials"
@ -92,12 +91,16 @@ class DevstackEngineTestCase(test.TestCase):
with mock.patch.object(self.engine, "deployment") as mock_deployment: with mock.patch.object(self.engine, "deployment") as mock_deployment:
credentials = self.engine.deploy() credentials = self.engine.deploy()
self.assertEqual( self.assertEqual(
{"openstack": [{"admin": "fake_credential", "users": []}]}, {"openstack": [{
"admin": {
"auth_url": "http://host:5000/v2.0/",
"username": "admin",
"password": "secret",
"permission": consts.EndpointPermission.ADMIN,
"tenant_name": "admin",
},
"users": []}]},
credentials) credentials)
mock_credential.assert_called_once_with(
"http://host:5000/v2.0/", "admin", "secret", "admin", "admin")
mock_credential.return_value.to_dict.assert_called_once_with(
include_permission=True)
mock_deployment.add_resource.assert_called_once_with( mock_deployment.add_resource.assert_called_once_with(
info="fake_credentials", info="fake_credentials",
provider_name="DevstackEngine", provider_name="DevstackEngine",

View File

@ -61,15 +61,35 @@ class TestExistingCloud(test.TestCase):
"user_domain_name": "Default", "user_domain_name": "Default",
} }
} }
},
"abstract": {
"config": {
"type": "ExistingCloud",
"creds": {
"openstack": {
"auth_url": "http://example.net:5000/v2.0/",
"region_name": "RegionOne",
"endpoint_type": consts.EndpointType.INTERNAL,
"https_insecure": False,
"https_cacert": "cacert",
"admin": {
"username": "admin",
"password": "myadminpass",
"tenant_name": "demo"
}
}
}
}
} }
} }
@ddt.data("v2.0", "v3") @ddt.data("v2.0", "v3", "abstract")
def test_init_and_valid_config(self, keystone_version): def test_init_and_valid_config(self, keystone_version):
engine = existing.ExistingCloud(self.deployments[keystone_version]) engine = existing.ExistingCloud(self.deployments[keystone_version])
engine.validate() engine.validate()
@ddt.data("v2.0", "v3") @ddt.data("v2.0", "v3", "abstract")
def test_invalid_config(self, keystone_version): def test_invalid_config(self, keystone_version):
deployment = self.deployments[keystone_version] deployment = self.deployments[keystone_version]
deployment["config"]["admin"] = 42 deployment["config"]["admin"] = 42
@ -77,7 +97,7 @@ class TestExistingCloud(test.TestCase):
self.assertRaises(jsonschema.ValidationError, self.assertRaises(jsonschema.ValidationError,
engine.validate) engine.validate)
@ddt.data("v2.0", "v3") @ddt.data("v2.0", "v3", "abstract")
def test_additional_vars(self, keystone_version): def test_additional_vars(self, keystone_version):
deployment = self.deployments[keystone_version] deployment = self.deployments[keystone_version]
deployment["extra"] = {} deployment["extra"] = {}
@ -122,11 +142,36 @@ class TestExistingCloud(test.TestCase):
self.assertEqual(admin_credential, actual_credentials) self.assertEqual(admin_credential, actual_credentials)
self.assertEqual([], credentials["users"]) self.assertEqual([], credentials["users"])
@ddt.data("v2.0", "v3") def test_deploy_abstract(self):
deployment = self.deployments["abstract"]
engine = existing.ExistingCloud(deployment)
credentials = engine.deploy()
self.assertEqual(1, len(credentials))
self.assertIn("openstack", credentials)
self.assertEqual(1, len(credentials["openstack"]))
credentials = credentials["openstack"][0]
self.assertEqual([], credentials["users"])
admin_credential = credentials["admin"]
self.assertEqual({
"auth_url": "http://example.net:5000/v2.0/",
"domain_name": None,
"endpoint": None,
"endpoint_type": "internal",
"https_cacert": "cacert",
"https_insecure": False,
"password": "myadminpass",
"permission": "admin",
"project_domain_name": None,
"region_name": "RegionOne",
"tenant_name": "demo",
"user_domain_name": None,
"username": "admin"}, admin_credential)
@ddt.data("v2.0", "v3", "abstract")
def test_cleanup(self, keystone_version): def test_cleanup(self, keystone_version):
existing.ExistingCloud(self.deployments[keystone_version]).cleanup() existing.ExistingCloud(self.deployments[keystone_version]).cleanup()
@ddt.data("v2.0", "v3") @ddt.data("v2.0", "v3", "abstract")
def test_is_in_factory(self, keystone_version): def test_is_in_factory(self, keystone_version):
name = self.deployments[keystone_version]["config"]["type"] name = self.deployments[keystone_version]["config"]["type"]
engine = deploy_engine.Engine.get_engine( engine = deploy_engine.Engine.get_engine(

View File

@ -27,6 +27,7 @@ from tests.unit import fakes
from tests.unit import test from tests.unit import test
MOD_NAME = "rally.deployment.serverprovider.providers.openstack" MOD_NAME = "rally.deployment.serverprovider.providers.openstack"
OS_CREDENTIAL_NAME = "rally.plugins.openstack.credential"
OSProvider = provider.OpenStackProvider OSProvider = provider.OpenStackProvider
@ -82,11 +83,10 @@ class OpenStackProviderTestCase(test.TestCase):
self.clients.nova = mock.MagicMock(return_value=self.nova_client) self.clients.nova = mock.MagicMock(return_value=self.nova_client)
@mock.patch( @mock.patch("rally.osclients.Clients")
"rally.deployment.serverprovider.providers.openstack.osclients") def test_openstack_provider_init(self, mock_clients):
def test_openstack_provider_init(self, mock_osclients):
cfg = self._get_valid_config() cfg = self._get_valid_config()
mock_osclients.Clients = mock.MagicMock(return_value=FakeOSClients()) mock_clients.return_value = FakeOSClients()
os_provider = OSProvider(mock.MagicMock(), cfg) os_provider = OSProvider(mock.MagicMock(), cfg)
self.assertEqual("nova", os_provider.nova) self.assertEqual("nova", os_provider.nova)
self.assertEqual("glance", os_provider.glance) self.assertEqual("glance", os_provider.glance)
@ -98,60 +98,53 @@ class OpenStackProviderTestCase(test.TestCase):
provider = OSProvider(mock.MagicMock(), cfg) provider = OSProvider(mock.MagicMock(), cfg)
self.assertIsNone(provider.glance) self.assertIsNone(provider.glance)
@mock.patch( @mock.patch("rally.osclients.Clients")
"rally.deployment.serverprovider.providers.openstack.osclients")
def test_openstack_provider_init_with_invalid_conf_no_user(self, def test_openstack_provider_init_with_invalid_conf_no_user(self,
mock_osclients): mock_clients):
cfg = self._get_valid_config() cfg = self._get_valid_config()
cfg.pop("user") cfg.pop("user")
self.assertRaises(jsonschema.ValidationError, OSProvider, self.assertRaises(jsonschema.ValidationError, OSProvider,
mock.MagicMock(), cfg) mock.MagicMock(), cfg)
@mock.patch( @mock.patch("rally.osclients.Clients")
"rally.deployment.serverprovider.providers.openstack.osclients")
def test_openstack_provider_init_with_invalid_conf_no_url(self, def test_openstack_provider_init_with_invalid_conf_no_url(self,
mock_osclients): mock_clients):
cfg = self._get_valid_config() cfg = self._get_valid_config()
del cfg["image"]["url"] del cfg["image"]["url"]
del cfg["image"]["checksum"] del cfg["image"]["checksum"]
self.assertRaises(jsonschema.ValidationError, OSProvider, self.assertRaises(jsonschema.ValidationError, OSProvider,
mock.MagicMock(), cfg) mock.MagicMock(), cfg)
@mock.patch( @mock.patch("rally.osclients.Clients")
"rally.deployment.serverprovider.providers.openstack.osclients")
def test_openstack_provider_init_with_invalid_conf_extra_key( def test_openstack_provider_init_with_invalid_conf_extra_key(
self, mock_osclients): self, mock_clients):
cfg = self._get_valid_config() cfg = self._get_valid_config()
cfg["aaaaa"] = "bbbbb" cfg["aaaaa"] = "bbbbb"
self.assertRaises(jsonschema.ValidationError, OSProvider, self.assertRaises(jsonschema.ValidationError, OSProvider,
mock.MagicMock(), cfg) mock.MagicMock(), cfg)
@mock.patch( @mock.patch("rally.osclients.Clients")
"rally.deployment.serverprovider.providers.openstack.osclients")
def test_openstack_provider_init_with_invalid_conf_flavor_(self, def test_openstack_provider_init_with_invalid_conf_flavor_(self,
mock_osclients): mock_clients):
cfg = self._get_valid_config()["user"] = 1111 cfg = self._get_valid_config()["user"] = 1111
self.assertRaises(jsonschema.ValidationError, OSProvider, self.assertRaises(jsonschema.ValidationError, OSProvider,
mock.MagicMock(), cfg) mock.MagicMock(), cfg)
@mock.patch( @mock.patch("rally.osclients.Clients")
"rally.deployment.serverprovider.providers.openstack.osclients")
def test_openstack_provider_with_valid_config(self, def test_openstack_provider_with_valid_config(self,
mock_osclients): mock_clients):
cfg = self._get_valid_config() cfg = self._get_valid_config()
OSProvider(mock.MagicMock(), cfg) OSProvider(mock.MagicMock(), cfg)
@mock.patch( @mock.patch("rally.osclients.Clients")
"rally.deployment.serverprovider.providers.openstack.osclients") def test_openstack_provider_with_valid_config_uuid(self, mock_clients):
def test_openstack_provider_with_valid_config_uuid(self, mock_osclients):
cfg = self._get_valid_config() cfg = self._get_valid_config()
cfg["image"] = dict(uuid="289D7A51-1A0C-43C4-800D-706EA8A3CDF3") cfg["image"] = dict(uuid="289D7A51-1A0C-43C4-800D-706EA8A3CDF3")
OSProvider(mock.MagicMock(), cfg) OSProvider(mock.MagicMock(), cfg)
@mock.patch( @mock.patch("rally.osclients.Clients")
"rally.deployment.serverprovider.providers.openstack.osclients")
def test_openstack_provider_with_valid_config_checksum(self, def test_openstack_provider_with_valid_config_checksum(self,
mock_osclients): mock_clients):
cfg = self._get_valid_config() cfg = self._get_valid_config()
cfg["image"] = dict(checksum="checksum") cfg["image"] = dict(checksum="checksum")
OSProvider(mock.MagicMock(), cfg) OSProvider(mock.MagicMock(), cfg)
@ -194,9 +187,9 @@ class OpenStackProviderTestCase(test.TestCase):
@mock.patch("time.sleep") @mock.patch("time.sleep")
@mock.patch(MOD_NAME + ".provider.Server") @mock.patch(MOD_NAME + ".provider.Server")
@mock.patch(MOD_NAME + ".osclients") @mock.patch("rally.osclients.Clients")
@mock.patch(MOD_NAME + ".utils") @mock.patch(MOD_NAME + ".utils")
def test_create_servers(self, mock_utils, mock_osclients, def test_create_servers(self, mock_utils, mock_clients,
mock_server, mock_sleep): mock_server, mock_sleep):
fake_keypair = mock.Mock() fake_keypair = mock.Mock()
fake_keypair.name = "fake_key_name" fake_keypair.name = "fake_key_name"
@ -229,41 +222,40 @@ class OpenStackProviderTestCase(test.TestCase):
nics="fake_nics", key_name="fake_key_name", config_drive=False, nics="fake_nics", key_name="fake_key_name", config_drive=False,
security_groups=[provider.sg.name]) security_groups=[provider.sg.name])
@mock.patch(MOD_NAME + ".osclients") @mock.patch("rally.osclients.Clients")
def test_get_image_found_by_checksum(self, mock_osclients): def test_get_image_found_by_checksum(self, mock_clients):
self._init_mock_clients() self._init_mock_clients()
mock_osclients.Clients = mock.MagicMock(return_value=self.clients) mock_clients.return_value = self.clients
prov = OSProvider(mock.MagicMock(), self._get_valid_config()) prov = OSProvider(mock.MagicMock(), self._get_valid_config())
image_uuid = prov.get_image_uuid() image_uuid = prov.get_image_uuid()
self.assertEqual(image_uuid, "fake-uuid") self.assertEqual(image_uuid, "fake-uuid")
@mock.patch(MOD_NAME + ".osclients") @mock.patch("rally.osclients.Clients")
def test_get_image_download(self, mock_osclients): def test_get_image_download(self, mock_clients):
self._init_mock_clients() self._init_mock_clients()
self.glance_client.images.list = mock.Mock(return_value=[]) self.glance_client.images.list = mock.Mock(return_value=[])
mock_osclients.Clients = mock.MagicMock(return_value=self.clients) mock_clients.return_value = self.clients
prov = OSProvider(mock.MagicMock(), self._get_valid_config()) prov = OSProvider(mock.MagicMock(), self._get_valid_config())
image_uuid = prov.get_image_uuid() image_uuid = prov.get_image_uuid()
self.assertEqual(image_uuid, "fake-uuid") self.assertEqual(image_uuid, "fake-uuid")
@mock.patch(MOD_NAME + ".osclients") @mock.patch("rally.osclients.Clients")
def test_get_image_no_glance_exception( def test_get_image_no_glance_exception(self, mock_clients):
self, mock_osclients):
prov = OSProvider(mock.MagicMock(), self._get_valid_config()) prov = OSProvider(mock.MagicMock(), self._get_valid_config())
prov.glance = None prov.glance = None
self.assertRaises(exceptions.InvalidConfigException, self.assertRaises(exceptions.InvalidConfigException,
prov.get_image_uuid) prov.get_image_uuid)
@mock.patch(MOD_NAME + ".osclients") @mock.patch("rally.osclients.Clients")
def test_get_image_from_uuid_no_glance(self, mock_osclients): def test_get_image_from_uuid_no_glance(self, mock_clients):
conf = self._get_valid_config() conf = self._get_valid_config()
conf["image"]["uuid"] = "EC7A1DB7-C5BD-49A2-8066-613809CB22F5" conf["image"]["uuid"] = "EC7A1DB7-C5BD-49A2-8066-613809CB22F5"
prov = OSProvider(mock.MagicMock(), conf) prov = OSProvider(mock.MagicMock(), conf)
prov.glance = True prov.glance = True
self.assertEqual(conf["image"]["uuid"], prov.get_image_uuid()) self.assertEqual(conf["image"]["uuid"], prov.get_image_uuid())
@mock.patch(MOD_NAME + ".osclients") @mock.patch("rally.osclients.Clients")
def test_destroy_servers(self, mock_osclients): def test_destroy_servers(self, mock_clients):
prov = OSProvider(mock.MagicMock(), self._get_valid_config()) prov = OSProvider(mock.MagicMock(), self._get_valid_config())
prov.resources.get_all.side_effect = [ prov.resources.get_all.side_effect = [
[fakes.FakeResource( [fakes.FakeResource(

View File

@ -0,0 +1,84 @@
# Copyright 2017: Mirantis Inc.
# 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.
import jsonschema
from rally.deployment import credential
from tests.unit import test
@credential.configure("foo")
class FooCredential(credential.Credential):
def __init__(self, bar=None):
self.bar = bar
def to_dict(self):
return {"bar": self.bar}
def verify_connection(self):
pass
def list_services(self):
return {"foo": "foo-type"}
class CredentialTestCase(test.TestCase):
def setUp(self):
super(CredentialTestCase, self).setUp()
self.cred_cls = credential.get("foo")
def test_configure_and_get(self):
self.assertIs(FooCredential, self.cred_cls)
def test_foo_credential(self):
cred = self.cred_cls(bar=42)
cred.verify_connection()
self.assertEqual({"bar": 42}, cred.to_dict())
self.assertEqual({"foo": "foo-type"}, cred.list_services())
@credential.configure_builder("foo")
class FooCredentialBuilder(credential.CredentialBuilder):
CONFIG_SCHEMA = {
"type": "object",
"properties": {
"bar": {"type": "integer"}
},
"required": ["bar"],
"additionalProperties": False
}
def build_credentials(self):
return {"admin": {"bar": self.config["bar"]}, "users": []}
class CredentialBuilderTestCase(test.TestCase):
def setUp(self):
super(CredentialBuilderTestCase, self).setUp()
self.cred_builder_cls = credential.get_builder("foo")
def test_configure_and_get(self):
self.assertIs(FooCredentialBuilder, self.cred_builder_cls)
def test_validate(self):
self.cred_builder_cls.validate({"bar": 42})
def test_validate_error(self):
self.assertRaises(jsonschema.ValidationError,
self.cred_builder_cls.validate,
{"bar": "spam"})

View File

@ -151,7 +151,7 @@ class LxcEngineTestCase(test.TestCase):
self.assertEqual(1, len(credentials["openstack"])) self.assertEqual(1, len(credentials["openstack"]))
credential = credentials["openstack"][0] credential = credentials["openstack"][0]
self.assertIsInstance(credential["admin"], dict) self.assertIsNone(credential["admin"])
self.assertEqual([], credential["users"]) self.assertEqual([], credential["users"])
lxc_host_calls = [ lxc_host_calls = [
mock.call(fake_servers[0], {"network": "10.128.128.0/28", mock.call(fake_servers[0], {"network": "10.128.128.0/28",

View File

@ -115,11 +115,12 @@ class ConfigSchemasTestCase(test.TestCase):
self.fail(p, schema, ("Found unexpected key(s) for integer/number " self.fail(p, schema, ("Found unexpected key(s) for integer/number "
"type: %s." % ", ".join(unexpected_keys))) "type: %s." % ", ".join(unexpected_keys)))
def _check_simpliest_types(self, p, schema): def _check_simpliest_types(self, p, schema, type_name):
unexpected_keys = set(schema.keys()) - {"type", "description"} unexpected_keys = set(schema.keys()) - {"type", "description"}
if unexpected_keys: if unexpected_keys:
self.fail(p, schema, ("Found unexpected key(s) for boolean type: " self.fail(p, schema, ("Found unexpected key(s) for %s type: "
"%s." % ", ".join(unexpected_keys))) "%s." % (type_name,
", ".join(unexpected_keys))))
def _check_item(self, p, schema, definitions): def _check_item(self, p, schema, definitions):
if "type" in schema or "anyOf" in schema or "oneOf" in schema: if "type" in schema or "anyOf" in schema or "oneOf" in schema:
@ -135,7 +136,9 @@ class ConfigSchemasTestCase(test.TestCase):
elif schema["type"] in ("number", "integer"): elif schema["type"] in ("number", "integer"):
self._check_number_type(p, schema) self._check_number_type(p, schema)
elif schema["type"] in ("boolean", "null"): elif schema["type"] in ("boolean", "null"):
self._check_simpliest_types(p, schema) self._check_simpliest_types(p, schema, schema["type"])
elif isinstance(schema["type"], list):
self._check_simpliest_types(p, schema, "mixed")
else: else:
self.fail(p, schema, self.fail(p, schema,
"Wrong type is used: %s" % schema["type"]) "Wrong type is used: %s" % schema["type"])

View File

@ -28,7 +28,6 @@ import six
from swiftclient import exceptions as swift_exceptions from swiftclient import exceptions as swift_exceptions
from rally import api from rally import api
from rally.common import objects
from rally.common import utils as rally_utils from rally.common import utils as rally_utils
from rally import consts from rally import consts
from rally.task import context from rally.task import context
@ -83,6 +82,14 @@ def setup_dict(data, required=None, defaults=None):
return defaults 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 FakeResource(object): class FakeResource(object):
def __init__(self, manager=None, name=None, status="ACTIVE", items=None, def __init__(self, manager=None, name=None, status="ACTIVE", items=None,
@ -1594,11 +1601,11 @@ class FakeClients(object):
self._ec2 = None self._ec2 = None
self._senlin = None self._senlin = None
self._watcher = None self._watcher = None
self._credential = credential_ or objects.Credential( self._credential = credential_ or fake_credential(
"http://fake.example.org:5000/v2.0/", auth_url="http://fake.example.org:5000/v2.0/",
"fake_username", username="fake_username",
"fake_password", password="fake_password",
"fake_tenant_name") tenant_name="fake_tenant_name")
def keystone(self, version=None): def keystone(self, version=None):
if not self._keystone: if not self._keystone:
@ -1806,11 +1813,19 @@ class FakeUserContext(FakeContext):
admin = { admin = {
"id": "adminuuid", "id": "adminuuid",
"credential": objects.Credential("aurl", "aname", "apwd", "atenant") "credential": fake_credential(
auth_url="aurl",
username="aname",
password="apwd",
tenant_name="atenant")
} }
user = { user = {
"id": "uuid", "id": "uuid",
"credential": objects.Credential("url", "name", "pwd", "tenant"), "credential": fake_credential(
auth_url="url",
username="name",
password="pwd",
tenant_name="tenant"),
"tenant_id": "uuid" "tenant_id": "uuid"
} }
tenants = {"uuid": {"name": "tenant"}} tenants = {"uuid": {"name": "tenant"}}

View File

@ -31,86 +31,19 @@ class SeekAndDestroyTestCase(test.TestCase):
# clear out the client cache # clear out the client cache
manager.SeekAndDestroy.cache = {} manager.SeekAndDestroy.cache = {}
@mock.patch("%s.osclients.Clients" % BASE, def test__get_cached_client(self):
side_effect=[mock.MagicMock(), mock.MagicMock()])
def test__get_cached_client(self, mock_clients):
destroyer = manager.SeekAndDestroy(None, None, None)
self.assertIsNone(destroyer._get_cached_client(None))
users = [{"credential": "a"}, {"credential": "b"}]
self.assertEqual(destroyer._get_cached_client(users[0]),
destroyer._get_cached_client(users[0]))
# ensure that cache is used
self.assertItemsEqual(mock_clients.call_args_list,
[mock.call("a", api_info=None)])
mock_clients.reset_mock()
self.assertEqual(destroyer._get_cached_client(users[1]),
destroyer._get_cached_client(users[1]))
self.assertItemsEqual(mock_clients.call_args_list,
[mock.call("b", api_info=None)])
mock_clients.reset_mock()
self.assertNotEqual(destroyer._get_cached_client(users[0]),
destroyer._get_cached_client(users[1]))
self.assertFalse(mock_clients.called)
@mock.patch("%s.osclients.Clients" % BASE,
side_effect=[mock.MagicMock(), mock.MagicMock()])
def test__get_cached_client_shared_cache(self, mock_clients):
# ensure that cache is shared between SeekAndDestroy objects
destroyer1 = manager.SeekAndDestroy(None, None, None)
destroyer2 = manager.SeekAndDestroy(None, None, None)
user = {"credential": "a"}
self.assertEqual(destroyer1._get_cached_client(user),
destroyer2._get_cached_client(user))
self.assertItemsEqual(mock_clients.call_args_list,
[mock.call("a", api_info=None)])
@mock.patch("%s.osclients.Clients" % BASE,
side_effect=[mock.MagicMock(), mock.MagicMock()])
def test__get_cached_client_shared_cache_api_versions(self, mock_clients):
# ensure that cache is shared between SeekAndDestroy objects
# with matching api_versions dicts
api_versions = {"cinder": {"version": "1", "service_type": "volume"}} api_versions = {"cinder": {"version": "1", "service_type": "volume"}}
destroyer1 = manager.SeekAndDestroy(None, None, None, destroyer = manager.SeekAndDestroy(None, None, None,
api_versions=api_versions) api_versions=api_versions)
destroyer2 = manager.SeekAndDestroy(None, None, None, cred = mock.Mock()
api_versions=api_versions) user = {"credential": cred}
user = {"credential": "a"} clients = destroyer._get_cached_client(user)
self.assertIs(cred.clients.return_value, clients)
cred.clients.assert_called_once_with(api_info=api_versions)
self.assertEqual(destroyer1._get_cached_client(user), self.assertIsNone(destroyer._get_cached_client(None))
destroyer2._get_cached_client(user))
self.assertItemsEqual(mock_clients.call_args_list,
[mock.call("a", api_info=api_versions)])
@mock.patch("%s.osclients.Clients" % BASE,
side_effect=[mock.MagicMock(), mock.MagicMock()])
def test__get_cached_client_no_cache_api_versions(self, mock_clients):
# ensure that cache is not shared between SeekAndDestroy
# objects with different api_versions dicts
api_versions = [
{"cinder": {"version": "1", "service_type": "volume"}},
{"cinder": {"version": "2", "service_type": "volumev2"}}
]
destroyer1 = manager.SeekAndDestroy(None, None, None,
api_versions=api_versions[0])
destroyer2 = manager.SeekAndDestroy(None, None, None,
api_versions=api_versions[1])
user = {"credential": "a"}
self.assertNotEqual(destroyer1._get_cached_client(user),
destroyer2._get_cached_client(user))
self.assertItemsEqual(mock_clients.call_args_list,
[mock.call("a", api_info=api_versions[0]),
mock.call("a", api_info=api_versions[1])])
@mock.patch("%s.LOG" % BASE) @mock.patch("%s.LOG" % BASE)
def test__delete_single_resource(self, mock_log): def test__delete_single_resource(self, mock_log):

View File

@ -22,9 +22,7 @@ CTX = "rally.plugins.openstack.context"
class ExistingUserTestCase(test.TestCase): class ExistingUserTestCase(test.TestCase):
@mock.patch("%s.keystone.existing_users.osclients.Clients" % CTX) def test_setup(self):
@mock.patch("%s.keystone.existing_users.objects.Credential" % CTX)
def test_setup(self, mock_credential, mock_clients):
user1 = mock.MagicMock(tenant_id="1", user_id="1", user1 = mock.MagicMock(tenant_id="1", user_id="1",
tenant_name="proj", username="usr") tenant_name="proj", username="usr")
user2 = mock.MagicMock(tenant_id="1", user_id="2", user2 = mock.MagicMock(tenant_id="1", user_id="2",
@ -48,8 +46,10 @@ class ExistingUserTestCase(test.TestCase):
self.PROJECT_ID_COUNT += 1 self.PROJECT_ID_COUNT += 1
return user_list[self.PROJECT_ID_COUNT - 1].tenant_id return user_list[self.PROJECT_ID_COUNT - 1].tenant_id
mock_clients.return_value.keystone.auth_ref = AuthRef() auth_ref = AuthRef()
mock_credential.side_effect = user_list user1.clients.return_value.keystone.auth_ref = auth_ref
user2.clients.return_value.keystone.auth_ref = auth_ref
user3.clients.return_value.keystone.auth_ref = auth_ref
context = { context = {
"task": mock.MagicMock(), "task": mock.MagicMock(),

View File

@ -15,10 +15,10 @@
import mock import mock
from rally.common import objects
from rally import consts from rally import consts
from rally import exceptions from rally import exceptions
from rally.plugins.openstack.context.keystone import users from rally.plugins.openstack.context.keystone import users
from rally.plugins.openstack import credential as oscredential
from tests.unit import test from tests.unit import test
CTX = "rally.plugins.openstack.context.keystone.users" CTX = "rally.plugins.openstack.context.keystone.users"
@ -274,16 +274,17 @@ class UserGeneratorTestCase(test.ScenarioTestCase):
def test_users_and_tenants_in_context(self, mock_identity): def test_users_and_tenants_in_context(self, mock_identity):
identity_service = mock_identity.Identity.return_value identity_service = mock_identity.Identity.return_value
credential = objects.Credential("foo_url", "foo", "foo_pass", credential = oscredential.OpenStackCredential(
https_insecure=True, "foo_url", "foo", "foo_pass",
https_cacert="cacert") https_insecure=True,
https_cacert="cacert")
tmp_context = dict(self.context) tmp_context = dict(self.context)
tmp_context["config"]["users"] = {"tenants": 1, tmp_context["config"]["users"] = {"tenants": 1,
"users_per_tenant": 2, "users_per_tenant": 2,
"resource_management_workers": 1} "resource_management_workers": 1}
tmp_context["admin"]["credential"] = credential tmp_context["admin"]["credential"] = credential
credential_dict = credential.to_dict(False) credential_dict = credential.to_dict()
user_list = [mock.MagicMock(id="id_%d" % i) user_list = [mock.MagicMock(id="id_%d" % i)
for i in range(self.users_num)] for i in range(self.users_num)]
identity_service.create_user.side_effect = user_list identity_service.create_user.side_effect = user_list
@ -302,7 +303,7 @@ class UserGeneratorTestCase(test.ScenarioTestCase):
self.assertEqual(set(["id", "credential", "tenant_id"]), self.assertEqual(set(["id", "credential", "tenant_id"]),
set(user.keys())) set(user.keys()))
user_credential_dict = user["credential"].to_dict(False) user_credential_dict = user["credential"].to_dict()
excluded_keys = ["auth_url", "username", "password", excluded_keys = ["auth_url", "username", "password",
"tenant_name", "region_name", "tenant_name", "region_name",
@ -323,7 +324,7 @@ class UserGeneratorTestCase(test.ScenarioTestCase):
@mock.patch("%s.identity" % CTX) @mock.patch("%s.identity" % CTX)
def test_users_contains_correct_endpoint_type(self, mock_identity): def test_users_contains_correct_endpoint_type(self, mock_identity):
credential = objects.Credential( credential = oscredential.OpenStackCredential(
"foo_url", "foo", "foo_pass", "foo_url", "foo", "foo_pass",
endpoint_type=consts.EndpointType.INTERNAL) endpoint_type=consts.EndpointType.INTERNAL)
config = { config = {
@ -346,7 +347,8 @@ class UserGeneratorTestCase(test.ScenarioTestCase):
@mock.patch("%s.identity" % CTX) @mock.patch("%s.identity" % CTX)
def test_users_contains_default_endpoint_type(self, mock_identity): def test_users_contains_default_endpoint_type(self, mock_identity):
credential = objects.Credential("foo_url", "foo", "foo_pass") credential = oscredential.OpenStackCredential(
"foo_url", "foo", "foo_pass")
config = { config = {
"config": { "config": {
"users": { "users": {

View File

@ -14,8 +14,8 @@
import mock import mock
from rally.common import objects
from rally.plugins.openstack.context.sahara import sahara_output_data_sources from rally.plugins.openstack.context.sahara import sahara_output_data_sources
from rally.plugins.openstack import credential as oscredential
from rally.plugins.openstack.scenarios.sahara import utils as sahara_utils from rally.plugins.openstack.scenarios.sahara import utils as sahara_utils
from tests.unit import test from tests.unit import test
@ -26,8 +26,8 @@ class SaharaOutputDataSourcesTestCase(test.ScenarioTestCase):
def setUp(self): def setUp(self):
super(SaharaOutputDataSourcesTestCase, self).setUp() super(SaharaOutputDataSourcesTestCase, self).setUp()
fake_dict = objects.Credential("http://fake.example.org:5000/v2.0/", fake_dict = oscredential.OpenStackCredential(
"user", "passwd") "http://fake.example.org:5000/v2.0/", "user", "passwd")
self.tenants_num = 2 self.tenants_num = 2
self.users_per_tenant = 2 self.users_per_tenant = 2
self.users = self.tenants_num * self.users_per_tenant self.users = self.tenants_num * self.users_per_tenant

View File

@ -0,0 +1,149 @@
# Copyright 2017: Mirantis Inc.
# 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.
import jsonschema
import mock
from rally import consts
from rally.deployment import credential
from tests.unit import test
class OpenStackCredentialTestCase(test.TestCase):
def setUp(self):
super(OpenStackCredentialTestCase, self).setUp()
cred_cls = credential.get("openstack")
self.credential = cred_cls(
"foo_url", "foo_user", "foo_password",
tenant_name="foo_tenant",
permission=consts.EndpointPermission.ADMIN)
def test_to_dict(self):
self.assertEqual({"auth_url": "foo_url",
"username": "foo_user",
"password": "foo_password",
"tenant_name": "foo_tenant",
"region_name": None,
"domain_name": None,
"endpoint": None,
"permission": consts.EndpointPermission.ADMIN,
"endpoint_type": None,
"https_insecure": False,
"https_cacert": None,
"project_domain_name": None,
"user_domain_name": None}, self.credential.to_dict())
@mock.patch("rally.osclients.Clients")
def test_verify_connection_admin(self, mock_clients):
self.credential.verify_connection()
mock_clients.assert_called_once_with(
self.credential, api_info=None, cache={})
mock_clients.return_value.verified_keystone.assert_called_once_with()
@mock.patch("rally.osclients.Clients")
def test_verify_connection_user(self, mock_clients):
self.credential.permission = consts.EndpointPermission.USER
self.credential.verify_connection()
mock_clients.assert_called_once_with(
self.credential, api_info=None, cache={})
mock_clients.return_value.keystone.assert_called_once_with()
@mock.patch("rally.osclients.Clients")
def test_list_services(self, mock_clients):
result = self.credential.list_services()
mock_clients.assert_called_once_with(
self.credential, api_info=None, cache={})
mock_clients.return_value.services.assert_called_once_with()
self.assertIs(mock_clients.return_value.services.return_value, result)
@mock.patch("rally.osclients.Clients")
def test_clients(self, mock_clients):
clients = self.credential.clients(api_info="fake_info")
mock_clients.assert_called_once_with(
self.credential, api_info="fake_info", cache={})
self.assertIs(mock_clients.return_value, clients)
class OpenStackCredentialBuilderTestCase(test.TestCase):
def setUp(self):
super(OpenStackCredentialBuilderTestCase, self).setUp()
self.config = {
"auth_url": "http://example.net:5000/v2.0/",
"region_name": "RegionOne",
"endpoint_type": consts.EndpointType.INTERNAL,
"https_insecure": False,
"https_cacert": "cacert",
"admin": {
"username": "admin",
"password": "myadminpass",
"tenant_name": "demo"
},
"users": [
{
"username": "user1",
"password": "userpass",
"tenant_name": "demo"
}
]
}
self.cred_builder_cls = credential.get_builder("openstack")
def test_validate(self):
self.cred_builder_cls.validate(self.config)
def test_validate_error(self):
self.assertRaises(jsonschema.ValidationError,
self.cred_builder_cls.validate,
{"foo": "bar"})
def test_build_credentials(self):
creds_builder = self.cred_builder_cls(self.config)
creds = creds_builder.build_credentials()
self.assertEqual({
"admin": {
"auth_url": "http://example.net:5000/v2.0/",
"username": "admin",
"password": "myadminpass",
"permission": consts.EndpointPermission.ADMIN,
"domain_name": None,
"endpoint": None,
"endpoint_type": consts.EndpointType.INTERNAL,
"https_cacert": "cacert",
"https_insecure": False,
"project_domain_name": None,
"region_name": "RegionOne",
"tenant_name": "demo",
"user_domain_name": None,
},
"users": [
{
"auth_url": "http://example.net:5000/v2.0/",
"username": "user1",
"password": "userpass",
"permission": consts.EndpointPermission.USER,
"domain_name": None,
"endpoint": None,
"endpoint_type": consts.EndpointType.INTERNAL,
"https_cacert": "cacert",
"https_insecure": False,
"project_domain_name": None,
"region_name": "RegionOne",
"tenant_name": "demo",
"user_domain_name": None,
}
]
}, creds)

View File

@ -18,6 +18,7 @@ import mock
from oslotest import mockpatch from oslotest import mockpatch
from rally.plugins.openstack import scenario as base_scenario from rally.plugins.openstack import scenario as base_scenario
from tests.unit import fakes
from tests.unit import test from tests.unit import test
@ -130,27 +131,21 @@ class OpenStackScenarioTestCase(test.TestCase):
@mock.patch("rally.task.scenario.Scenario.validate") @mock.patch("rally.task.scenario.Scenario.validate")
def test_validate(self, mock_scenario_validate): def test_validate(self, mock_scenario_validate):
cred1 = mock.Mock() cred1 = fakes.fake_credential(foo="bar1")
cred2 = mock.Mock() cred2 = fakes.fake_credential(foo="bar2")
cred3 = mock.Mock() cred3 = fakes.fake_credential(foo="bar3")
self.osclients.mock.side_effect = [cred1, cred2, cred3]
base_scenario.OpenStackScenario.validate( base_scenario.OpenStackScenario.validate(
name="foo_name", name="foo_name",
config="foo_config", config="foo_config",
admin="foo_admin", admin=cred1,
users=[{"credential": "foo_user1"}, users=[{"credential": cred2},
{"credential": "foo_user2"}], {"credential": cred3}],
deployment=None) deployment=None)
mock_scenario_validate.assert_called_once_with( mock_scenario_validate.assert_called_once_with(
name="foo_name", name="foo_name",
config="foo_config", config="foo_config",
admin=cred1, admin=cred1.clients.return_value,
users=[cred2, cred3], users=[cred2.clients.return_value, cred3.clients.return_value],
deployment=None) deployment=None)
self.osclients.mock.assert_has_calls([
mock.call("foo_admin"),
mock.call("foo_user1"),
mock.call("foo_user2"),
])

View File

@ -25,20 +25,17 @@ from tests.unit import test
CONF = cfg.CONF CONF = cfg.CONF
CREDS = { CRED = {
"admin": { "username": "admin",
"username": "admin", "tenant_name": "admin",
"tenant_name": "admin", "password": "admin-12345",
"password": "admin-12345", "auth_url": "http://test:5000/v2.0/",
"auth_url": "http://test:5000/v2.0/", "permission": "admin",
"permission": "admin", "region_name": "test",
"region_name": "test", "https_insecure": False,
"https_insecure": False, "https_cacert": "/path/to/cacert/file",
"https_cacert": "/path/to/cacert/file", "user_domain_name": "admin",
"user_domain_name": "admin", "project_domain_name": "admin"
"project_domain_name": "admin"
},
"uuid": "fake_deployment"
} }
PATH = "rally.plugins.openstack.verification.tempest.config" PATH = "rally.plugins.openstack.verification.tempest.config"
@ -49,10 +46,8 @@ class TempestConfigfileManagerTestCase(test.TestCase):
def setUp(self): def setUp(self):
super(TempestConfigfileManagerTestCase, self).setUp() super(TempestConfigfileManagerTestCase, self).setUp()
deployment = fakes.FakeDeployment(uuid="fake_deployment",
mock.patch("rally.osclients.Clients").start() admin=fakes.fake_credential(**CRED))
deployment = fakes.FakeDeployment(**CREDS)
self.tempest = config.TempestConfigfileManager(deployment) self.tempest = config.TempestConfigfileManager(deployment)
def test__configure_auth(self): def test__configure_auth(self):
@ -60,10 +55,10 @@ class TempestConfigfileManagerTestCase(test.TestCase):
self.tempest._configure_auth() self.tempest._configure_auth()
expected = ( expected = (
("admin_username", CREDS["admin"]["username"]), ("admin_username", CRED["username"]),
("admin_password", CREDS["admin"]["password"]), ("admin_password", CRED["password"]),
("admin_project_name", CREDS["admin"]["tenant_name"]), ("admin_project_name", CRED["tenant_name"]),
("admin_domain_name", CREDS["admin"]["user_domain_name"])) ("admin_domain_name", CRED["user_domain_name"]))
result = self.tempest.conf.items("auth") result = self.tempest.conf.items("auth")
for item in expected: for item in expected:
self.assertIn(item, result) self.assertIn(item, result)
@ -85,13 +80,13 @@ class TempestConfigfileManagerTestCase(test.TestCase):
self.tempest._configure_identity() self.tempest._configure_identity()
expected = ( expected = (
("region", CREDS["admin"]["region_name"]), ("region", CRED["region_name"]),
("auth_version", "v2"), ("auth_version", "v2"),
("uri", CREDS["admin"]["auth_url"][:-1]), ("uri", CRED["auth_url"][:-1]),
("uri_v3", CREDS["admin"]["auth_url"].replace("/v2.0/", "/v3")), ("uri_v3", CRED["auth_url"].replace("/v2.0/", "/v3")),
("disable_ssl_certificate_validation", ("disable_ssl_certificate_validation",
str(CREDS["admin"]["https_insecure"])), str(CRED["https_insecure"])),
("ca_certificates_file", CREDS["admin"]["https_cacert"])) ("ca_certificates_file", CRED["https_cacert"]))
result = self.tempest.conf.items("identity") result = self.tempest.conf.items("identity")
for item in expected: for item in expected:
self.assertIn(item, result) self.assertIn(item, result)

View File

@ -30,20 +30,17 @@ from tests.unit import test
CONF = cfg.CONF CONF = cfg.CONF
CREDS = { CRED = {
"admin": { "username": "admin",
"username": "admin", "tenant_name": "admin",
"tenant_name": "admin", "password": "admin-12345",
"password": "admin-12345", "auth_url": "http://test:5000/v2.0/",
"auth_url": "http://test:5000/v2.0/", "permission": "admin",
"permission": "admin", "region_name": "test",
"region_name": "test", "https_insecure": False,
"https_insecure": False, "https_cacert": "/path/to/cacert/file",
"https_cacert": "/path/to/cacert/file", "user_domain_name": "admin",
"user_domain_name": "admin", "project_domain_name": "admin"
"project_domain_name": "admin"
},
"uuid": "fake_deployment"
} }
PATH = "rally.plugins.openstack.verification.tempest.context" PATH = "rally.plugins.openstack.verification.tempest.context"
@ -55,11 +52,12 @@ class TempestContextTestCase(test.TestCase):
def setUp(self): def setUp(self):
super(TempestContextTestCase, self).setUp() super(TempestContextTestCase, self).setUp()
mock.patch("rally.osclients.Clients").start()
self.mock_isfile = mock.patch("os.path.isfile", self.mock_isfile = mock.patch("os.path.isfile",
return_value=True).start() return_value=True).start()
self.deployment = fakes.FakeDeployment(**CREDS) self.cred = fakes.fake_credential(**CRED)
self.deployment = fakes.FakeDeployment(
uuid="fake_deployment", admin=self.cred)
cfg = {"verifier": mock.Mock(deployment=self.deployment), cfg = {"verifier": mock.Mock(deployment=self.deployment),
"verification": {"uuid": "uuid"}} "verification": {"uuid": "uuid"}}
cfg["verifier"].manager.home_dir = "/p/a/t/h" cfg["verifier"].manager.home_dir = "/p/a/t/h"
@ -244,6 +242,7 @@ class TempestContextTestCase(test.TestCase):
def test__discover_or_create_flavor(self): def test__discover_or_create_flavor(self):
client = self.context.clients.nova() client = self.context.clients.nova()
client.flavors.list.return_value = []
client.flavors.create.side_effect = [fakes.FakeFlavor(id="id1")] client.flavors.create.side_effect = [fakes.FakeFlavor(id="id1")]
flavor = self.context._discover_or_create_flavor(64) flavor = self.context._discover_or_create_flavor(64)
@ -260,6 +259,7 @@ class TempestContextTestCase(test.TestCase):
client.create_network.side_effect = [{"network": fake_network}] client.create_network.side_effect = [{"network": fake_network}]
client.create_router.side_effect = [{"router": {"id": "rid1"}}] client.create_router.side_effect = [{"router": {"id": "rid1"}}]
client.create_subnet.side_effect = [{"subnet": {"id": "subid1"}}] client.create_subnet.side_effect = [{"subnet": {"id": "subid1"}}]
client.list_networks.return_value = {"networks": []}
network = self.context._create_network_resources() network = self.context._create_network_resources()
self.assertEqual("nid1", network["id"]) self.assertEqual("nid1", network["id"])
@ -333,16 +333,14 @@ class TempestContextTestCase(test.TestCase):
@mock.patch("%s.TempestContext._configure_option" % PATH) @mock.patch("%s.TempestContext._configure_option" % PATH)
@mock.patch("%s.TempestContext._create_tempest_roles" % PATH) @mock.patch("%s.TempestContext._create_tempest_roles" % PATH)
@mock.patch("rally.verification.utils.create_dir") @mock.patch("rally.verification.utils.create_dir")
@mock.patch("%s.osclients.Clients" % PATH) def test_setup(self, mock_create_dir,
def test_setup(self, mock_clients, mock_create_dir,
mock__create_tempest_roles, mock__configure_option, mock__create_tempest_roles, mock__configure_option,
mock_open): mock_open):
self.deployment = fakes.FakeDeployment(**CREDS)
verifier = mock.Mock(deployment=self.deployment) verifier = mock.Mock(deployment=self.deployment)
verifier.manager.home_dir = "/p/a/t/h" verifier.manager.home_dir = "/p/a/t/h"
# case #1: no neutron and heat # case #1: no neutron and heat
mock_clients.return_value.services.return_value = {} self.cred.clients.return_value.services.return_value = {}
ctx = context.TempestContext({"verifier": verifier}) ctx = context.TempestContext({"verifier": verifier})
ctx.conf = mock.Mock() ctx.conf = mock.Mock()
@ -377,10 +375,12 @@ class TempestContextTestCase(test.TestCase):
mock__configure_option.reset_mock() mock__configure_option.reset_mock()
# case #2: neutron and heat are presented # case #2: neutron and heat are presented
mock_clients.return_value.services.return_value = { self.cred.clients.return_value.services.return_value = {
"network": "neutron", "orchestration": "heat"} "network": "neutron", "orchestration": "heat"}
ctx = context.TempestContext({"verifier": verifier}) ctx = context.TempestContext({"verifier": verifier})
neutron = ctx.clients.neutron()
neutron.list_networks.return_value = {"networks": ["fake_net"]}
ctx.conf = mock.Mock() ctx.conf = mock.Mock()
ctx.setup() ctx.setup()

View File

@ -16,7 +16,6 @@
"""Tests for the Test engine.""" """Tests for the Test engine."""
import collections import collections
import copy
import threading import threading
import jsonschema import jsonschema
@ -286,10 +285,8 @@ class TaskEngineTestCase(test.TestCase):
eng._validate_config_semantic_helper, "a", eng._validate_config_semantic_helper, "a",
user_context, workloads, "fake_deployment") user_context, workloads, "fake_deployment")
@mock.patch("rally.osclients.Clients")
@mock.patch("rally.task.engine.scenario.Scenario.get") @mock.patch("rally.task.engine.scenario.Scenario.get")
@mock.patch("rally.task.engine.context.Context") @mock.patch("rally.task.engine.context.Context")
@mock.patch("rally.task.engine.objects.Credential")
@mock.patch("rally.task.engine.TaskConfig") @mock.patch("rally.task.engine.TaskConfig")
@mock.patch("rally.task.engine.TaskEngine" @mock.patch("rally.task.engine.TaskEngine"
"._validate_config_semantic_helper") "._validate_config_semantic_helper")
@ -298,11 +295,12 @@ class TaskEngineTestCase(test.TestCase):
def test__validate_config_semantic( def test__validate_config_semantic(
self, mock_deployment_get, self, mock_deployment_get,
mock__validate_config_semantic_helper, mock__validate_config_semantic_helper,
mock_task_config, mock_credential, mock_context, mock_task_config, mock_context,
mock_scenario_get, mock_clients): mock_scenario_get):
admin = fakes.fake_credential(foo="admin")
users = [fakes.fake_credential(bar="user1")]
deployment = fakes.FakeDeployment( deployment = fakes.FakeDeployment(
uuid="deployment_uuid", admin={"foo": "admin"}, uuid="deployment_uuid", admin=admin, users=users)
users=[{"bar": "user1"}])
scenario_cls = mock_scenario_get.return_value scenario_cls = mock_scenario_get.return_value
scenario_cls.get_namespace.return_value = "default" scenario_cls.get_namespace.return_value = "default"
@ -324,12 +322,8 @@ class TaskEngineTestCase(test.TestCase):
eng._validate_config_semantic(mock_task_instance) eng._validate_config_semantic(mock_task_instance)
admin = mock_credential.return_value
user_context = mock_context.get.return_value.return_value user_context = mock_context.get.return_value.return_value
mock_clients.assert_called_once_with(admin)
mock_clients.return_value.verified_keystone.assert_called_once_with()
mock__validate_config_semantic_helper.assert_has_calls([ mock__validate_config_semantic_helper.assert_has_calls([
mock.call(admin, user_context, [wconf1], deployment), mock.call(admin, user_context, [wconf1], deployment),
mock.call(admin, user_context, [wconf2, wconf3], deployment), mock.call(admin, user_context, [wconf2, wconf3], deployment),
@ -356,7 +350,6 @@ class TaskEngineTestCase(test.TestCase):
mock.call(consts.TaskStatus.FINISHED) mock.call(consts.TaskStatus.FINISHED)
]) ])
@mock.patch("rally.task.engine.objects.Credential")
@mock.patch("rally.task.engine.objects.task.Task.get_status") @mock.patch("rally.task.engine.objects.task.Task.get_status")
@mock.patch("rally.task.engine.TaskConfig") @mock.patch("rally.task.engine.TaskConfig")
@mock.patch("rally.task.engine.LOG") @mock.patch("rally.task.engine.LOG")
@ -368,7 +361,7 @@ class TaskEngineTestCase(test.TestCase):
def test_run_exception_is_logged( def test_run_exception_is_logged(
self, mock_context_manager_setup, mock_context_manager_cleanup, self, mock_context_manager_setup, mock_context_manager_cleanup,
mock_scenario_runner, mock_scenario, mock_result_consumer, mock_scenario_runner, mock_scenario, mock_result_consumer,
mock_log, mock_task_config, mock_task_get_status, mock_credential): mock_log, mock_task_config, mock_task_get_status):
scenario_cls = mock_scenario.get.return_value scenario_cls = mock_scenario.get.return_value
scenario_cls.get_namespace.return_value = "openstack" scenario_cls.get_namespace.return_value = "openstack"
@ -394,7 +387,6 @@ class TaskEngineTestCase(test.TestCase):
self.assertEqual(2, mock_log.exception.call_count) self.assertEqual(2, mock_log.exception.call_count)
@mock.patch("rally.task.engine.objects.Credential")
@mock.patch("rally.task.engine.ResultConsumer") @mock.patch("rally.task.engine.ResultConsumer")
@mock.patch("rally.task.engine.context.ContextManager.cleanup") @mock.patch("rally.task.engine.context.ContextManager.cleanup")
@mock.patch("rally.task.engine.context.ContextManager.setup") @mock.patch("rally.task.engine.context.ContextManager.setup")
@ -403,7 +395,7 @@ class TaskEngineTestCase(test.TestCase):
def test_run__task_soft_aborted( def test_run__task_soft_aborted(
self, mock_scenario_runner, mock_scenario, self, mock_scenario_runner, mock_scenario,
mock_context_manager_setup, mock_context_manager_cleanup, mock_context_manager_setup, mock_context_manager_cleanup,
mock_result_consumer, mock_credential): mock_result_consumer):
scenario_cls = mock_scenario.get.return_value scenario_cls = mock_scenario.get.return_value
scenario_cls.get_namespace.return_value = "openstack" scenario_cls.get_namespace.return_value = "openstack"
task = mock.MagicMock() task = mock.MagicMock()
@ -455,11 +447,9 @@ class TaskEngineTestCase(test.TestCase):
self.assertEqual(mock.call(consts.TaskStatus.ABORTED), self.assertEqual(mock.call(consts.TaskStatus.ABORTED),
task.update_status.mock_calls[-1]) task.update_status.mock_calls[-1])
@mock.patch("rally.task.engine.objects.Credential")
@mock.patch("rally.task.engine.TaskConfig") @mock.patch("rally.task.engine.TaskConfig")
@mock.patch("rally.task.engine.scenario.Scenario.get") @mock.patch("rally.task.engine.scenario.Scenario.get")
def test__prepare_context(self, mock_scenario_get, mock_task_config, def test__prepare_context(self, mock_scenario_get, mock_task_config):
mock_credential):
default_context = {"a": 1, "b": 2} default_context = {"a": 1, "b": 2}
mock_scenario = mock_scenario_get.return_value mock_scenario = mock_scenario_get.return_value
mock_scenario.get_default_context.return_value = default_context mock_scenario.get_default_context.return_value = default_context
@ -470,28 +460,24 @@ class TaskEngineTestCase(test.TestCase):
config = { config = {
"a.task": [{"context": {"context_a": {"a": 1}}}], "a.task": [{"context": {"context_a": {"a": 1}}}],
} }
admin = fakes.fake_credential(foo="admin")
deployment = fakes.FakeDeployment( deployment = fakes.FakeDeployment(
uuid="deployment_uuid", admin={"foo": "admin"}) uuid="deployment_uuid", admin=admin)
eng = engine.TaskEngine(config, task, deployment) eng = engine.TaskEngine(config, task, deployment)
result = eng._prepare_context(context, name) result = eng._prepare_context(context, name)
expected_context = copy.deepcopy(default_context)
expected_context.setdefault("users", {})
expected_context.update(context)
expected_result = { expected_result = {
"task": task, "task": task,
"admin": {"credential": mock_credential.return_value}, "admin": {"credential": admin},
"scenario_name": name, "scenario_name": name,
"config": expected_context "config": {"a": 1, "b": 3, "c": 4, "users": {}}
} }
self.assertEqual(result, expected_result) self.assertEqual(result, expected_result)
mock_scenario_get.assert_called_once_with(name) mock_scenario_get.assert_called_once_with(name)
@mock.patch("rally.task.engine.objects.Credential")
@mock.patch("rally.task.engine.TaskConfig") @mock.patch("rally.task.engine.TaskConfig")
@mock.patch("rally.task.engine.scenario.Scenario.get") @mock.patch("rally.task.engine.scenario.Scenario.get")
def test__prepare_context_with_existing_users(self, mock_scenario_get, def test__prepare_context_with_existing_users(self, mock_scenario_get,
mock_task_config, mock_task_config):
mock_credential):
mock_scenario = mock_scenario_get.return_value mock_scenario = mock_scenario_get.return_value
mock_scenario.get_default_context.return_value = {} mock_scenario.get_default_context.return_value = {}
mock_scenario.get_namespace.return_value = "default" mock_scenario.get_namespace.return_value = "default"
@ -501,18 +487,17 @@ class TaskEngineTestCase(test.TestCase):
config = { config = {
"a.task": [{"context": {"context_a": {"a": 1}}}], "a.task": [{"context": {"context_a": {"a": 1}}}],
} }
deployment = fakes.FakeDeployment( admin = fakes.fake_credential(foo="admin")
uuid="deployment_uuid", admin={"foo": "admin"}, users = [fakes.fake_credential(bar="user1")]
users=[{"bar": "user1"}]) deployment = fakes.FakeDeployment(uuid="deployment_uuid",
admin=admin, users=users)
eng = engine.TaskEngine(config, task, deployment) eng = engine.TaskEngine(config, task, deployment)
result = eng._prepare_context(context, name) result = eng._prepare_context(context, name)
expected_context = {"existing_users": [{"bar": "user1"}]}
expected_context.update(context)
expected_result = { expected_result = {
"task": task, "task": task,
"admin": {"credential": mock_credential.return_value}, "admin": {"credential": admin},
"scenario_name": name, "scenario_name": name,
"config": expected_context "config": {"b": 3, "c": 4, "existing_users": users}
} }
self.assertEqual(result, expected_result) self.assertEqual(result, expected_result)
mock_scenario_get.assert_called_once_with(name) mock_scenario_get.assert_called_once_with(name)

View File

@ -24,7 +24,6 @@ import six
from rally.common.plugin import plugin from rally.common.plugin import plugin
from rally import consts from rally import consts
from rally import exceptions from rally import exceptions
import rally.osclients
from rally.task import validation from rally.task import validation
from tests.unit import fakes from tests.unit import fakes
from tests.unit import test from tests.unit import test
@ -557,35 +556,32 @@ class ValidatorsTestCase(test.TestCase):
result = validator({"args": {"a": 1, "c": 3}}, None, None) result = validator({"args": {"a": 1, "c": 3}}, None, None)
self.assertFalse(result.is_valid, result.msg) self.assertFalse(result.is_valid, result.msg)
@mock.patch("rally.common.objects.Credential") def test_required_service(self):
def test_required_service(self, mock_credential):
validator = self._unwrap_validator(validation.required_services, validator = self._unwrap_validator(validation.required_services,
consts.Service.KEYSTONE, consts.Service.KEYSTONE,
consts.Service.NOVA, consts.Service.NOVA,
consts.Service.NOVA_NET) consts.Service.NOVA_NET)
clients = mock.MagicMock() admin = fakes.fake_credential(foo="bar")
clients = mock.Mock()
clients.services().values.return_value = [consts.Service.KEYSTONE, clients.services().values.return_value = [consts.Service.KEYSTONE,
consts.Service.NOVA, consts.Service.NOVA,
consts.Service.NOVA_NET] consts.Service.NOVA_NET]
fake_service = mock.Mock(binary="nova-network", status="enabled") fake_service = mock.Mock(binary="nova-network", status="enabled")
admin_clients = admin.clients.return_value
nova_client = admin_clients.nova.return_value
nova_client.services.list.return_value = [fake_service]
deployment = fakes.FakeDeployment(admin=admin)
result = validator({}, clients, deployment)
with mock.patch("rally.osclients.Clients") as clients_cls:
nova_client = clients_cls.return_value.nova.return_value
nova_client.services.list.return_value = [fake_service]
deployment = fakes.FakeDeployment(admin={"info": "admin"})
result = validator({}, clients, deployment)
clients_cls.assert_called_once_with(mock_credential.return_value)
mock_credential.assert_called_once_with(info="admin")
self.assertTrue(result.is_valid, result.msg) self.assertTrue(result.is_valid, result.msg)
validator = self._unwrap_validator(validation.required_services, validator = self._unwrap_validator(validation.required_services,
consts.Service.KEYSTONE, consts.Service.KEYSTONE,
consts.Service.NOVA) consts.Service.NOVA)
clients.services().values.return_value = [consts.Service.KEYSTONE] clients.services().values.return_value = [consts.Service.KEYSTONE]
with mock.patch("rally.osclients.Clients") as clients_cls:
result = validator({}, clients, None) result = validator({}, clients, None)
self.assertFalse(clients_cls.called)
self.assertFalse(result.is_valid, result.msg) self.assertFalse(result.is_valid, result.msg)
def test_required_service_wrong_service(self): def test_required_service_wrong_service(self):
@ -752,37 +748,33 @@ class ValidatorsTestCase(test.TestCase):
result = validator(context, clients, mock.MagicMock()) result = validator(context, clients, mock.MagicMock())
self.assertFalse(result.is_valid, result.msg) self.assertFalse(result.is_valid, result.msg)
@mock.patch(MODULE + "osclients") def test_required_clients(self):
def test_required_clients(self, mock_osclients):
validator = self._unwrap_validator(validation.required_clients, validator = self._unwrap_validator(validation.required_clients,
"keystone", "nova") "keystone", "nova")
clients = mock.MagicMock() clients = mock.Mock()
clients.keystone.return_value = "keystone" clients.keystone.return_value = "keystone"
clients.nova.return_value = "nova" clients.nova.return_value = "nova"
deployment = fakes.FakeDeployment() deployment = fakes.FakeDeployment()
result = validator({}, clients, deployment) result = validator({}, clients, deployment)
self.assertTrue(result.is_valid, result.msg) self.assertTrue(result.is_valid, result.msg)
self.assertFalse(mock_osclients.Clients.called)
clients.nova.side_effect = ImportError clients.nova.side_effect = ImportError
result = validator({}, clients, deployment) result = validator({}, clients, deployment)
self.assertFalse(result.is_valid, result.msg) self.assertFalse(result.is_valid, result.msg)
@mock.patch(MODULE + "objects") def test_required_clients_with_admin(self):
@mock.patch(MODULE + "osclients")
def test_required_clients_with_admin(self, mock_osclients, mock_objects):
validator = self._unwrap_validator(validation.required_clients, validator = self._unwrap_validator(validation.required_clients,
"keystone", "nova", admin=True) "keystone", "nova", admin=True)
clients = mock.Mock() admin = fakes.fake_credential(foo="bar")
clients = admin.clients.return_value
clients.keystone.return_value = "keystone" clients.keystone.return_value = "keystone"
clients.nova.return_value = "nova" clients.nova.return_value = "nova"
mock_osclients.Clients.return_value = clients
mock_objects.Credential.return_value = "foo_credential" deployment = fakes.FakeDeployment(admin=admin)
deployment = fakes.FakeDeployment(admin={"foo": "bar"})
result = validator({}, clients, deployment) result = validator({}, clients, deployment)
self.assertTrue(result.is_valid, result.msg) self.assertTrue(result.is_valid, result.msg)
mock_objects.Credential.assert_called_once_with(foo="bar")
mock_osclients.Clients.assert_called_once_with("foo_credential")
clients.nova.side_effect = ImportError clients.nova.side_effect = ImportError
result = validator({}, clients, deployment) result = validator({}, clients, deployment)
self.assertFalse(result.is_valid, result.msg) self.assertFalse(result.is_valid, result.msg)
@ -810,24 +802,17 @@ class ValidatorsTestCase(test.TestCase):
validation.required_cinder_services, validation.required_cinder_services,
service_name=six.text_type("cinder-service")) service_name=six.text_type("cinder-service"))
with mock.patch.object(rally.osclients.Cinder, "create_client") as c: fake_service = mock.Mock(binary="cinder-service", state="up")
fake_service = mock.Mock(binary="cinder-service", state="up") admin = fakes.fake_credential(foo="bar")
cinder_client = mock.Mock() cinder = admin.clients.return_value.cinder.return_value
services = mock.Mock() cinder.services.list.return_value = [fake_service]
services.list.return_value = [fake_service] deployment = fakes.FakeDeployment(admin=admin)
cinder_client.services = services result = validator({}, None, deployment)
c.return_value = cinder_client self.assertTrue(result.is_valid, result.msg)
deployment = fakes.FakeDeployment( fake_service.state = "down"
admin={"auth_url": "fake_credential", result = validator({}, None, deployment)
"username": "username", self.assertFalse(result.is_valid, result.msg)
"password": "password"})
result = validator({}, None, deployment)
self.assertTrue(result.is_valid, result.msg)
fake_service.state = "down"
result = validator({}, None, deployment)
self.assertFalse(result.is_valid, result.msg)
def test_restricted_parameters(self): def test_restricted_parameters(self):
validator = self._unwrap_validator( validator = self._unwrap_validator(

View File

@ -20,7 +20,6 @@ import os
import ddt import ddt
import jsonschema import jsonschema
from keystoneclient import exceptions as keystone_exceptions
import mock import mock
from oslo_config import cfg from oslo_config import cfg
@ -349,8 +348,8 @@ class BaseDeploymentTestCase(test.TestCase):
class DeploymentAPITestCase(BaseDeploymentTestCase): class DeploymentAPITestCase(BaseDeploymentTestCase):
@mock.patch("rally.common.objects.deploy.db.deployment_update") @mock.patch("rally.common.objects.deploy.db.deployment_update")
@mock.patch("rally.common.objects.deploy.db.deployment_create") @mock.patch("rally.common.objects.deploy.db.deployment_create")
@mock.patch("rally.deployment.engine.Engine.validate") @mock.patch("rally.deployment.engines.existing.ExistingCloud.validate")
def test_create(self, mock_engine_validate, def test_create(self, mock_existing_cloud_validate,
mock_deployment_create, mock_deployment_update): mock_deployment_create, mock_deployment_update):
mock_deployment_create.return_value = self.deployment mock_deployment_create.return_value = self.deployment
mock_deployment_update.return_value = self.deployment mock_deployment_update.return_value = self.deployment
@ -360,7 +359,7 @@ class DeploymentAPITestCase(BaseDeploymentTestCase):
"name": "fake_deployment", "name": "fake_deployment",
"config": self.deployment_config, "config": self.deployment_config,
}) })
mock_engine_validate.assert_called_once_with() mock_existing_cloud_validate.assert_called_once_with()
mock_deployment_update.assert_has_calls([ mock_deployment_update.assert_has_calls([
mock.call(self.deployment_uuid, mock.call(self.deployment_uuid,
{"credentials": {"openstack": [self.credentials]}}) {"credentials": {"openstack": [self.credentials]}})
@ -368,10 +367,10 @@ class DeploymentAPITestCase(BaseDeploymentTestCase):
@mock.patch("rally.common.objects.deploy.db.deployment_update") @mock.patch("rally.common.objects.deploy.db.deployment_update")
@mock.patch("rally.common.objects.deploy.db.deployment_create") @mock.patch("rally.common.objects.deploy.db.deployment_create")
@mock.patch("rally.deployment.engine.Engine.validate", @mock.patch("rally.deployment.engines.existing.ExistingCloud.validate",
side_effect=jsonschema.ValidationError("ValidationError")) side_effect=jsonschema.ValidationError("ValidationError"))
def test_create_validation_error( def test_create_validation_error(
self, mock_engine_validate, mock_deployment_create, self, mock_existing_cloud_validate, mock_deployment_create,
mock_deployment_update): mock_deployment_update):
mock_deployment_create.return_value = self.deployment mock_deployment_create.return_value = self.deployment
self.assertRaises(jsonschema.ValidationError, self.assertRaises(jsonschema.ValidationError,
@ -488,41 +487,25 @@ class DeploymentAPITestCase(BaseDeploymentTestCase):
for key in self.deployment: for key in self.deployment:
self.assertEqual(ret[key], self.deployment[key]) self.assertEqual(ret[key], self.deployment[key])
@mock.patch("rally.osclients.Clients.services") def test_deployment_check(self):
@mock.patch("rally.osclients.Keystone.create_client") fake_credential1 = fakes.fake_credential()
def test_deployment_check(self, mock_keystone_create_client, fake_credential2 = fakes.fake_credential()
mock_clients_services):
sample_credential = objects.Credential("http://192.168.1.1:5000/v2.0/",
"admin",
"adminpass").to_dict()
deployment = mock.Mock(spec=objects.Deployment) deployment = mock.Mock(spec=objects.Deployment)
deployment.get_credentials_for.return_value = { deployment.get_credentials_for.return_value = {
"admin": sample_credential, "users": [sample_credential]} "admin": fake_credential1, "users": [fake_credential2]}
api._Deployment.check(deployment) result = api._Deployment.check(deployment)
mock_keystone_create_client.assert_called_with() fake_credential1.verify_connection.assert_called_once_with()
mock_clients_services.assert_called_once_with() fake_credential2.verify_connection.assert_called_once_with()
self.assertEqual(fake_credential1.list_services.return_value, result)
def test_deployment_check_raise(self): def test_service_list(self):
sample_credential = objects.Credential("http://192.168.1.1:5000/v2.0/", fake_credential = fakes.fake_credential()
"admin",
"adminpass").to_dict()
sample_credential["not-exist-key"] = "error"
deployment = mock.Mock(spec=objects.Deployment)
self.assertRaises(TypeError, api._Deployment.check, deployment)
@mock.patch("rally.osclients.Clients.services")
def test_deployment_check_connect_failed(self, mock_clients_services):
sample_credential = objects.Credential("http://192.168.1.1:5000/v2.0/",
"admin",
"adminpass").to_dict()
deployment = mock.Mock(spec=objects.Deployment) deployment = mock.Mock(spec=objects.Deployment)
deployment.get_credentials_for.return_value = { deployment.get_credentials_for.return_value = {
"admin": sample_credential, "users": []} "admin": fake_credential, "users": []}
refused = keystone_exceptions.ConnectionRefused() result = api._Deployment.service_list(deployment)
mock_clients_services.side_effect = refused self.assertEqual(fake_credential.list_services.return_value, result)
self.assertRaises(
keystone_exceptions.ConnectionRefused,
api._Deployment.check, deployment)
class APITestCase(test.TestCase): class APITestCase(test.TestCase):

View File

@ -18,10 +18,10 @@ from keystoneclient import exceptions as keystone_exceptions
import mock import mock
from oslo_config import cfg from oslo_config import cfg
from rally.common import objects
from rally import consts from rally import consts
from rally import exceptions from rally import exceptions
from rally import osclients from rally import osclients
from rally.plugins.openstack import credential as oscredential
from tests.unit import fakes from tests.unit import fakes
from tests.unit import test from tests.unit import test
@ -91,9 +91,10 @@ class OSClientTestCase(test.TestCase, OSClientTestCaseUtils):
@ddt.unpack @ddt.unpack
def test__get_endpoint(self, mock_keystone_service_catalog, endpoint_type, def test__get_endpoint(self, mock_keystone_service_catalog, endpoint_type,
service_type, region_name): service_type, region_name):
credential = objects.Credential("http://auth_url/v2.0", "user", "pass", credential = oscredential.OpenStackCredential(
endpoint_type=endpoint_type, "http://auth_url/v2.0", "user", "pass",
region_name=region_name) endpoint_type=endpoint_type,
region_name=region_name)
mock_choose_service_type = mock.MagicMock() mock_choose_service_type = mock.MagicMock()
osclient = osclients.OSClient(credential, {}, mock.MagicMock()) osclient = osclients.OSClient(credential, {}, mock.MagicMock())
osclient.choose_service_type = mock_choose_service_type osclient.choose_service_type = mock_choose_service_type
@ -153,8 +154,8 @@ class TestCreateKeystoneClient(test.TestCase, OSClientTestCaseUtils):
def setUp(self): def setUp(self):
super(TestCreateKeystoneClient, self).setUp() super(TestCreateKeystoneClient, self).setUp()
self.credential = objects.Credential("http://auth_url/v2.0", "user", self.credential = oscredential.OpenStackCredential(
"pass", "tenant") "http://auth_url/v2.0", "user", "pass", "tenant")
def test_create_client(self): def test_create_client(self):
# NOTE(bigjools): This is a very poor testing strategy as it # NOTE(bigjools): This is a very poor testing strategy as it
@ -201,8 +202,8 @@ class TestCreateKeystoneClient(test.TestCase, OSClientTestCaseUtils):
@ddt.data("http://auth_url/v2.0", "http://auth_url/v3", @ddt.data("http://auth_url/v2.0", "http://auth_url/v3",
"http://auth_url/", "auth_url") "http://auth_url/", "auth_url")
def test_keystone_get_session(self, auth_url): def test_keystone_get_session(self, auth_url):
credential = objects.Credential(auth_url, "user", credential = oscredential.OpenStackCredential(
"pass", "tenant") auth_url, "user", "pass", "tenant")
self.set_up_keystone_mocks() self.set_up_keystone_mocks()
keystone = osclients.Keystone(credential, {}, {}) keystone = osclients.Keystone(credential, {}, {})
@ -255,8 +256,8 @@ class OSClientsTestCase(test.TestCase):
def setUp(self): def setUp(self):
super(OSClientsTestCase, self).setUp() super(OSClientsTestCase, self).setUp()
self.credential = objects.Credential("http://auth_url/v2.0", "user", self.credential = oscredential.OpenStackCredential(
"pass", "tenant") "http://auth_url/v2.0", "user", "pass", "tenant")
self.clients = osclients.Clients(self.credential, {}) self.clients = osclients.Clients(self.credential, {})
self.fake_keystone = fakes.FakeKeystoneClient() self.fake_keystone = fakes.FakeKeystoneClient()