[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:
parent
91f22381a2
commit
7792aa71b7
@ -50,12 +50,16 @@ then
|
||||
cat >$1 <<EOF
|
||||
{
|
||||
"type": "ExistingCloud",
|
||||
"auth_url": "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_SERVICE_PORT/v$IDENTITY_API_VERSION",
|
||||
"region_name": "$REGION_NAME",
|
||||
"admin": {
|
||||
"username": "admin",
|
||||
"password": "$ADMIN_PASSWORD",
|
||||
"tenant_name": "admin",
|
||||
"creds": {
|
||||
"openstack": {
|
||||
"auth_url": "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_SERVICE_PORT/v$IDENTITY_API_VERSION",
|
||||
"region_name": "$REGION_NAME",
|
||||
"admin": {
|
||||
"username": "admin",
|
||||
"password": "$ADMIN_PASSWORD",
|
||||
"tenant_name": "admin",
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
@ -65,14 +69,18 @@ then
|
||||
cat >$1 <<EOF
|
||||
{
|
||||
"type": "ExistingCloud",
|
||||
"auth_url": "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_SERVICE_PORT/v$IDENTITY_API_VERSION",
|
||||
"region_name": "$REGION_NAME",
|
||||
"admin": {
|
||||
"username": "admin",
|
||||
"password": "$ADMIN_PASSWORD",
|
||||
"project_name": "admin",
|
||||
"user_domain_name": "Default",
|
||||
"project_domain_name": "Default"
|
||||
"creds": {
|
||||
"openstack": {
|
||||
"auth_url": "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_SERVICE_PORT/v$IDENTITY_API_VERSION",
|
||||
"region_name": "$REGION_NAME",
|
||||
"admin": {
|
||||
"username": "admin",
|
||||
"password": "$ADMIN_PASSWORD",
|
||||
"project_name": "admin",
|
||||
"user_domain_name": "Default",
|
||||
"project_domain_name": "Default"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
19
rally/api.py
19
rally/api.py
@ -33,7 +33,6 @@ from rally.common import version as rally_version
|
||||
from rally import consts
|
||||
from rally.deployment import engine as deploy_engine
|
||||
from rally import exceptions
|
||||
from rally import osclients
|
||||
from rally.task import engine
|
||||
from rally.verification import context as vcontext
|
||||
from rally.verification import manager as vmanager
|
||||
@ -149,10 +148,9 @@ class _Deployment(object):
|
||||
:param deployment: Deployment object
|
||||
: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"]
|
||||
clients = osclients.Clients(objects.Credential(**admin))
|
||||
return clients.services()
|
||||
return admin.list_services()
|
||||
|
||||
@staticmethod
|
||||
def list(status=None, parent_uuid=None, name=None):
|
||||
@ -168,13 +166,12 @@ class _Deployment(object):
|
||||
|
||||
:returns: Service list
|
||||
"""
|
||||
# TODO(astudenov): put this work into Credential plugins
|
||||
services = cls.service_list(deployment)
|
||||
users = deployment.get_credentials_for("openstack")["users"]
|
||||
for endpoint_dict in users:
|
||||
osclients.Clients(objects.Credential(**endpoint_dict)).keystone()
|
||||
|
||||
return services
|
||||
# TODO(astudenov): make this method platform independent
|
||||
creds = deployment.get_credentials_for("openstack")
|
||||
creds["admin"].verify_connection()
|
||||
for user in creds["users"]:
|
||||
user.verify_connection()
|
||||
return creds["admin"].list_services()
|
||||
|
||||
|
||||
class _Task(object):
|
||||
|
@ -191,11 +191,13 @@ class DeploymentCommands(object):
|
||||
metavar="<uuid>", required=False,
|
||||
help="UUID or name of the deployment.")
|
||||
@envutils.with_default_deployment()
|
||||
@plugins.ensure_plugins_are_loaded
|
||||
def show(self, api, deployment=None):
|
||||
"""Show the credentials 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",
|
||||
"region_name", "endpoint_type"]
|
||||
@ -208,7 +210,7 @@ class DeploymentCommands(object):
|
||||
credentials = users + [admin] if admin else users
|
||||
|
||||
for ep in credentials:
|
||||
data = ["***" if m == "password" else ep.get(m, "")
|
||||
data = ["***" if m == "password" else getattr(ep, m, "")
|
||||
for m in headers]
|
||||
table_rows.append(utils.Struct(**dict(zip(headers, data))))
|
||||
cliutils.print_list(table_rows, headers)
|
||||
@ -217,11 +219,13 @@ class DeploymentCommands(object):
|
||||
metavar="<uuid>", required=False,
|
||||
help="UUID or name of the deployment.")
|
||||
@envutils.with_default_deployment()
|
||||
@plugins.ensure_plugins_are_loaded
|
||||
def check(self, api, deployment=None):
|
||||
"""Check keystone authentication and list all available services.
|
||||
|
||||
:param deployment: UUID or name of the deployment
|
||||
"""
|
||||
# TODO(astudenov): make this method platform independent
|
||||
headers = ["services", "type", "status"]
|
||||
table_rows = []
|
||||
try:
|
||||
@ -235,7 +239,7 @@ class DeploymentCommands(object):
|
||||
services = api.deployment.check(deployment)
|
||||
except keystone_exceptions.ConnectionRefused:
|
||||
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)
|
||||
|
||||
except exceptions.InvalidArgumentsException:
|
||||
@ -296,11 +300,13 @@ class DeploymentCommands(object):
|
||||
@cliutils.args("--deployment", dest="deployment", type=str,
|
||||
metavar="<uuid>", required=False,
|
||||
help="UUID or name of a deployment.")
|
||||
@plugins.ensure_plugins_are_loaded
|
||||
def use(self, api, deployment):
|
||||
"""Set active deployment.
|
||||
|
||||
:param deployment: UUID or name of the deployment
|
||||
"""
|
||||
# TODO(astudenov): make this method platform independent
|
||||
try:
|
||||
deployment = api.deployment.get(deployment)
|
||||
print("Using deployment: %s" % deployment["uuid"])
|
||||
@ -309,8 +315,9 @@ class DeploymentCommands(object):
|
||||
deployment["uuid"])
|
||||
|
||||
creds = deployment.get_credentials_for("openstack")
|
||||
credential = creds["admin"] or creds["users"][0]
|
||||
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"
|
||||
"\n* To use standard OpenStack clients, set up your env by "
|
||||
"running:\n\tsource ~/.rally/openrc\n"
|
||||
|
@ -13,43 +13,16 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from rally import consts
|
||||
from rally.plugins.openstack import credential
|
||||
|
||||
# TODO(astudenov): remove this class in future releases
|
||||
|
||||
|
||||
class Credential(object):
|
||||
|
||||
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
|
||||
class Credential(credential.OpenStackCredential):
|
||||
"""Deprecated version of OpenStackCredential class"""
|
||||
|
||||
def to_dict(self, include_permission=False):
|
||||
dct = {"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.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
|
||||
dct = super(Credential, self).to_dict()
|
||||
if not include_permission:
|
||||
dct.pop("permission")
|
||||
return dct
|
||||
|
@ -21,6 +21,7 @@ from rally.common.i18n import _, _LW
|
||||
from rally.common import db
|
||||
from rally.common import logging
|
||||
from rally import consts
|
||||
from rally.deployment import credential
|
||||
from rally import exceptions
|
||||
|
||||
|
||||
@ -34,7 +35,7 @@ CREDENTIALS_SCHEMA = {
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"admin": {"type": "object"},
|
||||
"admin": {"type": ["object", "null"]},
|
||||
"users": {
|
||||
"type": "array",
|
||||
"items": {"type": "object"}
|
||||
@ -97,12 +98,17 @@ class Deployment(object):
|
||||
|
||||
def get_credentials_for(self, namespace):
|
||||
try:
|
||||
return self.deployment["credentials"][namespace][0]
|
||||
creds = self.deployment["credentials"][namespace][0]
|
||||
except (KeyError, IndexError) as e:
|
||||
LOG.exception(e)
|
||||
raise exceptions.RallyException(_(
|
||||
"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):
|
||||
self._update({"started_at": dt.datetime.now(),
|
||||
"status": consts.DeployStatus.DEPLOY_STARTED})
|
||||
|
89
rally/deployment/credential.py
Normal file
89
rally/deployment/credential.py
Normal 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"""
|
@ -19,7 +19,6 @@ import six
|
||||
|
||||
from rally.common.i18n import _
|
||||
from rally.common import logging
|
||||
from rally.common import objects
|
||||
from rally import consts
|
||||
from rally.deployment import engine
|
||||
from rally.deployment.serverprovider import provider
|
||||
@ -133,17 +132,13 @@ class DevstackEngine(engine.Engine):
|
||||
stdin=local_conf)
|
||||
devstack_server.ssh.run("~/devstack/stack.sh")
|
||||
|
||||
admin_credential = objects.Credential(
|
||||
"http://%s:5000/v2.0/" % self.servers[0].host, "admin",
|
||||
self.local_conf["ADMIN_PASSWORD"], "admin",
|
||||
consts.EndpointPermission.ADMIN)
|
||||
return {
|
||||
"openstack": [
|
||||
{
|
||||
"admin": admin_credential.to_dict(include_permission=True),
|
||||
"users": []
|
||||
}
|
||||
]}
|
||||
admin_dict = dict(
|
||||
auth_url="http://%s:5000/v2.0/" % self.servers[0].host,
|
||||
username="admin",
|
||||
password=self.local_conf["ADMIN_PASSWORD"],
|
||||
tenant_name="admin",
|
||||
permission=consts.EndpointPermission.ADMIN)
|
||||
return {"openstack": [{"admin": admin_dict, "users": []}]}
|
||||
|
||||
def cleanup(self):
|
||||
for resource in self.deployment.get_resources(type="credentials"):
|
||||
|
@ -13,16 +13,61 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from rally.common import objects
|
||||
import copy
|
||||
|
||||
from rally.common import logging
|
||||
from rally import consts
|
||||
from rally.deployment import credential
|
||||
from rally.deployment import engine
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@engine.configure(name="ExistingCloud")
|
||||
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
|
||||
|
||||
@ -40,7 +85,7 @@ class ExistingCloud(engine.Engine):
|
||||
"https_cacert": "",
|
||||
}
|
||||
|
||||
Or, using keystone v3 API endpoint:
|
||||
keystone v3 API endpoint:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
@ -60,114 +105,132 @@ class ExistingCloud(engine.Engine):
|
||||
"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",
|
||||
|
||||
"definitions": {
|
||||
"user": {
|
||||
"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
|
||||
}
|
||||
],
|
||||
"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
|
||||
}
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
OLD_CONFIG_SCHEMA = {
|
||||
"type": "object",
|
||||
"description": "Deprecated schema (openstack only)",
|
||||
"properties": {
|
||||
"type": {"type": "string"},
|
||||
"auth_url": {"type": "string"},
|
||||
"region_name": {"type": "string"},
|
||||
"endpoint": {"oneOf": [
|
||||
# NOTE(andreykurilin): it looks like we do not use endpoint
|
||||
# var at all
|
||||
{"type": "string", "description": ""},
|
||||
{"type": "null", "description": ""}]},
|
||||
# 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"},
|
||||
"admin": {"$ref": "#/definitions/user"},
|
||||
"users": {
|
||||
"type": "array",
|
||||
"items": {"$ref": "#/definitions/user"}
|
||||
},
|
||||
"admin": USER_SCHEMA,
|
||||
"users": {"type": "array", "items": USER_SCHEMA},
|
||||
"extra": {"type": "object", "additionalProperties": True}
|
||||
},
|
||||
"required": ["type", "auth_url", "admin"],
|
||||
"additionalProperties": False
|
||||
}
|
||||
|
||||
def _create_credential(self, common, user, permission):
|
||||
return objects.Credential(
|
||||
common["auth_url"], user["username"], 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")
|
||||
)
|
||||
NEW_CONFIG_SCHEMA = {
|
||||
"type": "object",
|
||||
"description": "New schema for multiplatform deployment",
|
||||
"properties": {
|
||||
"type": {"enum": ["ExistingCloud"]},
|
||||
"creds": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^[a-z0-9_-]+$": {
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "Single credential",
|
||||
"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):
|
||||
permissions = consts.EndpointPermission
|
||||
|
||||
users = [self._create_credential(self.config, user, permissions.USER)
|
||||
for user in self.config.get("users", [])]
|
||||
users = [user.to_dict(include_permission=True) for user in users]
|
||||
|
||||
admin = self._create_credential(self.config,
|
||||
self.config.get("admin"),
|
||||
permissions.ADMIN)
|
||||
admin = admin.to_dict(include_permission=True)
|
||||
|
||||
return {"openstack": [{"admin": admin, "users": users}]}
|
||||
if "creds" not in self.config:
|
||||
LOG.warning("Old config schema is deprecated since Rally 0.10.0. "
|
||||
"Please use new config schema for ExistingCloud")
|
||||
creds_config = self._get_creds(self.config)
|
||||
parsed_credentials = {}
|
||||
for platform, config in creds_config.items():
|
||||
builder_cls = credential.get_builder(platform)
|
||||
credentials = []
|
||||
for creds in config:
|
||||
builder = builder_cls(creds)
|
||||
credentials.append(builder.build_credentials())
|
||||
parsed_credentials[platform] = credentials
|
||||
return parsed_credentials
|
||||
|
||||
def cleanup(self):
|
||||
pass
|
||||
|
@ -150,9 +150,7 @@ class LxcEngine(engine.Engine):
|
||||
if network:
|
||||
network += 1
|
||||
|
||||
admin = objects.Credential("", "", "", "").to_dict(
|
||||
include_permission=True)
|
||||
return {"openstack": [{"admin": admin, "users": []}]}
|
||||
return {"openstack": [{"admin": None, "users": []}]}
|
||||
|
||||
def cleanup(self):
|
||||
resources = self.deployment.get_resources()
|
||||
|
@ -21,10 +21,9 @@ import novaclient.exceptions
|
||||
|
||||
from rally.common.i18n import _
|
||||
from rally.common import logging
|
||||
from rally.common import objects
|
||||
from rally.deployment.serverprovider import provider
|
||||
from rally import exceptions
|
||||
from rally import osclients
|
||||
from rally.plugins.openstack import credential
|
||||
from rally.task import utils
|
||||
|
||||
|
||||
@ -144,11 +143,13 @@ class OpenStackProvider(provider.ProviderFactory):
|
||||
|
||||
def __init__(self, deployment, config):
|
||||
super(OpenStackProvider, self).__init__(deployment, config)
|
||||
user_credential = objects.Credential(
|
||||
config["auth_url"], config["user"],
|
||||
config["password"], config["tenant"],
|
||||
user_credential = credential.OpenStackCredential(
|
||||
auth_url=config["auth_url"],
|
||||
username=config["user"],
|
||||
password=config["password"],
|
||||
tenant_name=config["tenant"],
|
||||
region_name=config.get("region"))
|
||||
clients = osclients.Clients(user_credential)
|
||||
clients = user_credential.clients()
|
||||
self.nova = clients.nova()
|
||||
self.sg = None
|
||||
try:
|
||||
|
@ -22,7 +22,6 @@ from six.moves.urllib import parse
|
||||
from rally.cli import envutils
|
||||
from rally.common.i18n import _
|
||||
from rally.common import logging
|
||||
from rally.common import objects
|
||||
from rally.common.plugin import plugin
|
||||
from rally import consts
|
||||
from rally import exceptions
|
||||
@ -687,10 +686,10 @@ class Watcher(OSClient):
|
||||
class Clients(object):
|
||||
"""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.api_info = api_info or {}
|
||||
self.cache = {}
|
||||
self.cache = cache or {}
|
||||
|
||||
def __getattr__(self, client_name):
|
||||
"""Lazy load of clients."""
|
||||
@ -700,20 +699,20 @@ class Clients(object):
|
||||
@classmethod
|
||||
def create_from_env(cls):
|
||||
creds = envutils.get_creds_from_env_vars()
|
||||
return cls(
|
||||
objects.Credential(
|
||||
creds["auth_url"],
|
||||
creds["admin"]["username"],
|
||||
creds["admin"]["password"],
|
||||
creds["admin"]["tenant_name"],
|
||||
endpoint_type=creds["endpoint_type"],
|
||||
user_domain_name=creds["admin"].get("user_domain_name"),
|
||||
project_domain_name=creds["admin"].get("project_domain_name"),
|
||||
endpoint=creds["endpoint"],
|
||||
region_name=creds["region_name"],
|
||||
https_cacert=creds["https_cacert"],
|
||||
https_insecure=creds["https_insecure"]
|
||||
))
|
||||
from rally.plugins.openstack import credential
|
||||
oscred = credential.OpenStackCredential(
|
||||
auth_url=creds["auth_url"],
|
||||
username=creds["admin"]["username"],
|
||||
password=creds["admin"]["password"],
|
||||
tenant_name=creds["admin"]["tenant_name"],
|
||||
endpoint_type=creds["endpoint_type"],
|
||||
user_domain_name=creds["admin"].get("user_domain_name"),
|
||||
project_domain_name=creds["admin"].get("project_domain_name"),
|
||||
endpoint=creds["endpoint"],
|
||||
region_name=creds["region_name"],
|
||||
https_cacert=creds["https_cacert"],
|
||||
https_insecure=creds["https_insecure"])
|
||||
return cls(oscred)
|
||||
|
||||
def clear(self):
|
||||
"""Remove all cached client handles."""
|
||||
|
@ -21,7 +21,6 @@ from rally.common import logging
|
||||
from rally.common.plugin import discover
|
||||
from rally.common.plugin import plugin
|
||||
from rally.common import utils as rutils
|
||||
from rally import osclients
|
||||
from rally.plugins.openstack.cleanup import base
|
||||
|
||||
|
||||
@ -29,7 +28,6 @@ LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SeekAndDestroy(object):
|
||||
cache = {}
|
||||
|
||||
def __init__(self, manager_cls, admin, users, api_versions=None,
|
||||
resource_classes=None, task_id=None):
|
||||
@ -58,15 +56,8 @@ class SeekAndDestroy(object):
|
||||
"""Simplifies initialization and caching OpenStack clients."""
|
||||
if not user:
|
||||
return None
|
||||
|
||||
if 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]
|
||||
# NOTE(astudenov): Credential now supports caching by default
|
||||
return user["credential"].clients(api_info=self.api_versions)
|
||||
|
||||
def _delete_single_resource(self, resource):
|
||||
"""Safe resource deletion with retries and timeouts.
|
||||
@ -170,7 +161,6 @@ class SeekAndDestroy(object):
|
||||
admin=admin_client,
|
||||
user=self._get_cached_client(user),
|
||||
tenant_uuid=user["tenant_id"])
|
||||
|
||||
_publish(self.admin, user, manager)
|
||||
|
||||
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
|
||||
If True -> return only admin plugins
|
||||
If False -> return only non admin plugins
|
||||
:param admin: rally.common.objects.Credential that corresponds to OpenStack
|
||||
admin.
|
||||
:param admin: rally.deployment.credential.Credential that corresponds to
|
||||
OpenStack admin.
|
||||
:param users: List of OpenStack users that was used during benchmarking.
|
||||
Every user has next structure:
|
||||
{
|
||||
"id": <uuid1>,
|
||||
"tenant_id": <uuid2>,
|
||||
"credential": <rally.common.objects.Credential>
|
||||
"credential": <rally.deployment.credential.Credential>
|
||||
}
|
||||
:param superclass: The plugin superclass to perform cleanup
|
||||
for. E.g., this could be
|
||||
|
@ -15,8 +15,6 @@
|
||||
|
||||
from rally.common.i18n import _
|
||||
from rally.common import logging
|
||||
from rally.common import objects
|
||||
from rally import osclients
|
||||
from rally.task import context
|
||||
|
||||
|
||||
@ -46,10 +44,8 @@ class ExistingUsers(context.Context):
|
||||
self.context["tenants"] = {}
|
||||
self.context["user_choice_method"] = "random"
|
||||
|
||||
for user in self.config:
|
||||
user_credential = objects.Credential(**user)
|
||||
user_clients = osclients.Clients(user_credential)
|
||||
|
||||
for user_credential in self.config:
|
||||
user_clients = user_credential.clients()
|
||||
user_id = user_clients.keystone.auth_ref.user_id
|
||||
tenant_id = user_clients.keystone.auth_ref.project_id
|
||||
|
||||
|
@ -21,11 +21,11 @@ from oslo_config import cfg
|
||||
from rally.common import broker
|
||||
from rally.common.i18n import _
|
||||
from rally.common import logging
|
||||
from rally.common import objects
|
||||
from rally.common import utils as rutils
|
||||
from rally import consts
|
||||
from rally import exceptions
|
||||
from rally import osclients
|
||||
from rally.plugins.openstack import credential
|
||||
from rally.plugins.openstack.services.identity import identity
|
||||
from rally.plugins.openstack.wrappers import network
|
||||
from rally.task import context
|
||||
@ -207,10 +207,12 @@ class UserGenerator(context.Context):
|
||||
project_id=tenant_id,
|
||||
domain_name=user_dom,
|
||||
default_role=default_role)
|
||||
user_credential = objects.Credential(
|
||||
self.credential.auth_url, user.name, password,
|
||||
self.context["tenants"][tenant_id]["name"],
|
||||
consts.EndpointPermission.USER,
|
||||
user_credential = credential.OpenStackCredential(
|
||||
auth_url=self.credential.auth_url,
|
||||
username=user.name,
|
||||
password=password,
|
||||
tenant_name=self.context["tenants"][tenant_id]["name"],
|
||||
permission=consts.EndpointPermission.USER,
|
||||
project_domain_name=project_dom,
|
||||
user_domain_name=user_dom,
|
||||
endpoint_type=self.credential.endpoint_type,
|
||||
|
173
rally/plugins/openstack/credential.py
Normal file
173
rally/plugins/openstack/credential.py
Normal 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
|
@ -108,9 +108,9 @@ class OpenStackScenario(scenario.Scenario):
|
||||
@classmethod
|
||||
def validate(cls, name, config, admin=None, users=None, deployment=None):
|
||||
if admin:
|
||||
admin = osclients.Clients(admin)
|
||||
admin = admin.clients()
|
||||
if users:
|
||||
users = [osclients.Clients(user["credential"]) for user in users]
|
||||
users = [user["credential"].clients() for user in users]
|
||||
super(OpenStackScenario, cls).validate(
|
||||
name=name, config=config, admin=admin, users=users,
|
||||
deployment=deployment)
|
||||
|
@ -21,8 +21,6 @@ import six
|
||||
from six.moves import configparser
|
||||
from six.moves.urllib import parse
|
||||
|
||||
from rally.common import objects
|
||||
from rally import osclients
|
||||
from rally.verification import utils
|
||||
|
||||
|
||||
@ -88,7 +86,7 @@ class TempestConfigfileManager(object):
|
||||
|
||||
def __init__(self, deployment):
|
||||
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.conf = configparser.ConfigParser()
|
||||
@ -100,14 +98,14 @@ class TempestConfigfileManager(object):
|
||||
|
||||
def _configure_auth(self, section_name="auth"):
|
||||
self.conf.set(section_name, "admin_username",
|
||||
self.credential["username"])
|
||||
self.credential.username)
|
||||
self.conf.set(section_name, "admin_password",
|
||||
self.credential["password"])
|
||||
self.credential.password)
|
||||
self.conf.set(section_name, "admin_project_name",
|
||||
self.credential["tenant_name"])
|
||||
self.credential.tenant_name)
|
||||
# Keystone v3 related parameter
|
||||
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'.
|
||||
# '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"):
|
||||
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:
|
||||
auth_version = "v2"
|
||||
auth_url_v2 = parse.urljoin(auth_url, "/v2.0")
|
||||
@ -136,9 +134,9 @@ class TempestConfigfileManager(object):
|
||||
auth_url_v2.replace("/v2.0", "/v3"))
|
||||
|
||||
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.credential["https_cacert"])
|
||||
self.credential.https_cacert)
|
||||
|
||||
# The compute section is configured in context class for Tempest resources.
|
||||
# Options which are configured there: 'image_ref', 'image_ref_alt',
|
||||
|
@ -21,9 +21,7 @@ from six.moves import configparser
|
||||
|
||||
from rally.common.i18n import _
|
||||
from rally.common import logging
|
||||
from rally.common import objects
|
||||
from rally import exceptions
|
||||
from rally import osclients
|
||||
from rally.plugins.openstack.verification.tempest import config as conf
|
||||
from rally.plugins.openstack.wrappers import glance
|
||||
from rally.plugins.openstack.wrappers import network
|
||||
@ -45,7 +43,7 @@ class TempestContext(context.VerifierContext):
|
||||
super(TempestContext, self).__init__(ctx)
|
||||
|
||||
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.conf = configparser.ConfigParser()
|
||||
|
@ -326,13 +326,9 @@ class TaskEngine(object):
|
||||
for platform, workloads in platforms.items():
|
||||
creds = self.deployment.get_credentials_for(platform)
|
||||
|
||||
admin = objects.Credential(**creds["admin"])
|
||||
|
||||
# TODO(astudenov): move this check to validator of Credential
|
||||
if platform == "openstack":
|
||||
from rally import osclients
|
||||
clients = osclients.Clients(admin)
|
||||
clients.verified_keystone()
|
||||
admin = creds["admin"]
|
||||
if admin:
|
||||
admin.verify_connection()
|
||||
|
||||
workloads_with_users = []
|
||||
workloads_with_existing_users = []
|
||||
@ -399,9 +395,6 @@ class TaskEngine(object):
|
||||
creds = self.deployment.get_credentials_for(namespace)
|
||||
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())
|
||||
if existing_users and "users" not in ctx:
|
||||
scenario_context.setdefault("existing_users", existing_users)
|
||||
@ -411,7 +404,7 @@ class TaskEngine(object):
|
||||
scenario_context.update(ctx)
|
||||
context_obj = {
|
||||
"task": self.task,
|
||||
"admin": {"credential": admin},
|
||||
"admin": {"credential": creds["admin"]},
|
||||
"scenario_name": name,
|
||||
"config": scenario_context
|
||||
}
|
||||
|
@ -23,11 +23,9 @@ from novaclient import exceptions as nova_exc
|
||||
import six
|
||||
|
||||
from rally.common.i18n import _
|
||||
from rally.common import objects
|
||||
from rally.common import yamlutils as yaml
|
||||
from rally import consts
|
||||
from rally import exceptions
|
||||
from rally import osclients
|
||||
from rally.plugins.openstack.context.nova import flavors as flavors_ctx
|
||||
from rally.plugins.openstack import types as openstack_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:
|
||||
creds = deployment.get_credentials_for("openstack")
|
||||
nova = osclients.Clients(
|
||||
objects.Credential(**creds["admin"])).nova()
|
||||
nova = creds["admin"].clients().nova()
|
||||
for service in nova.services.list():
|
||||
if (service.binary == consts.Service.NOVA_NET and
|
||||
service.status == "enabled"):
|
||||
@ -507,8 +504,7 @@ def required_cinder_services(config, clients, deployment, service_name):
|
||||
:param service_name: Cinder service name
|
||||
"""
|
||||
creds = deployment.get_credentials_for("openstack")
|
||||
admin_client = osclients.Clients(
|
||||
objects.Credential(**creds["admin"])).cinder()
|
||||
admin_client = creds["admin"].clients().cinder()
|
||||
|
||||
for service in admin_client.services.list():
|
||||
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):
|
||||
creds = deployment.get_credentials_for("openstack")
|
||||
clients = osclients.Clients(objects.Credential(**creds["admin"]))
|
||||
clients = creds["admin"].clients()
|
||||
|
||||
for client_component in components:
|
||||
try:
|
||||
|
@ -24,10 +24,9 @@ import sys
|
||||
import six
|
||||
|
||||
from rally.cli import cliutils
|
||||
from rally.common import objects
|
||||
from rally.common.plugin import discover
|
||||
from rally import consts
|
||||
from rally import osclients
|
||||
from rally.plugins.openstack import credential
|
||||
|
||||
|
||||
def skip_if_service(service):
|
||||
@ -340,7 +339,7 @@ class CloudResources(object):
|
||||
"""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.clients = osclients.Clients(objects.Credential(**kwargs))
|
||||
self.clients = credential.OpenStackCredential(**kwargs).clients()
|
||||
|
||||
def _deduplicate(self, lst):
|
||||
"""Change list duplicates to make all items unique.
|
||||
@ -426,8 +425,8 @@ def main():
|
||||
out = subprocess.check_output(["rally", "deployment",
|
||||
"config"])
|
||||
config = json.loads(out if six.PY2 else out.decode("utf-8"))
|
||||
config = config["creds"]["openstack"]
|
||||
config.update(config.pop("admin"))
|
||||
del config["type"]
|
||||
if "users" in config:
|
||||
del config["users"]
|
||||
|
||||
|
@ -64,7 +64,7 @@ function setUp () {
|
||||
DEPLOYMENT_CONFIG_FILE=~/.rally/with-existing-users-config
|
||||
|
||||
rally deployment config > $DEPLOYMENT_CONFIG_FILE
|
||||
sed -i '1a "users": [\
|
||||
sed -i '3a "users": [\
|
||||
{\
|
||||
"username": "rally-test-user-1",\
|
||||
"password": "rally-test-password-1",\
|
||||
|
@ -23,8 +23,7 @@ import sys
|
||||
import uuid
|
||||
|
||||
from rally.cli import envutils
|
||||
from rally.common import objects
|
||||
from rally import osclients
|
||||
from rally.plugins.openstack import credential
|
||||
from rally.ui import utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
@ -172,9 +171,9 @@ def main():
|
||||
|
||||
config = json.loads(
|
||||
subprocess.check_output(["rally", "deployment", "config"]))
|
||||
config = config["creds"]["openstack"]
|
||||
config.update(config.pop("admin"))
|
||||
del config["type"]
|
||||
clients = osclients.Clients(objects.Credential(**config))
|
||||
clients = credential.OpenStackCredential(**config).clients()
|
||||
|
||||
if args.ctx_create_resources:
|
||||
# If the 'ctx-create-resources' arg is provided, delete images and
|
||||
|
@ -25,7 +25,6 @@ import six
|
||||
|
||||
from rally import api
|
||||
from rally.common import db
|
||||
from rally.common import objects
|
||||
from rally import plugins
|
||||
from rally.plugins.openstack.context.keystone import users
|
||||
from tests.functional import utils
|
||||
@ -51,7 +50,7 @@ class TestTaskSamples(unittest.TestCase):
|
||||
return False
|
||||
|
||||
@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)
|
||||
# In TestTaskSamples, Rally API will be called directly (not via
|
||||
# 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
|
||||
deployment = api.Deployment.get("MAIN")
|
||||
creds = deployment.get_credentials_for("openstack")
|
||||
admin_cred = objects.Credential(**creds["admin"])
|
||||
admin_cred = deployment.get_credentials_for("openstack")["admin"]
|
||||
|
||||
ctx = {"admin": {"credential": admin_cred},
|
||||
"task": {"uuid": self.__class__.__name__}}
|
||||
@ -70,15 +68,16 @@ class TestTaskSamples(unittest.TestCase):
|
||||
self.addCleanup(user_ctx.cleanup)
|
||||
|
||||
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["password"] = ctx["users"][0]["credential"].password
|
||||
if "project_name" in config["admin"]:
|
||||
if "project_name" in os_creds["admin"]:
|
||||
# it is Keystone
|
||||
user["project_name"] = ctx["users"][0]["credential"].tenant_name
|
||||
else:
|
||||
user["tenant_name"] = ctx["users"][0]["credential"].tenant_name
|
||||
config["users"] = [user]
|
||||
config["creds"]["openstack"]["users"] = [user]
|
||||
|
||||
rally("deployment destroy MAIN", write_report=False)
|
||||
deployment_cfg = os.path.join(rally.tmp_dir, "new_deployment.json")
|
||||
|
@ -20,7 +20,6 @@ import mock
|
||||
|
||||
from rally.cli.commands import deployment
|
||||
from rally.cli import envutils
|
||||
from rally.common import objects
|
||||
from rally import consts
|
||||
from rally import exceptions
|
||||
from tests.unit import fakes
|
||||
@ -231,14 +230,13 @@ class DeploymentCommandsTestCase(test.TestCase):
|
||||
def test_show(self, mock_struct, mock_print_list):
|
||||
deployment_id = "b1a6153e-a314-4cb3-b63b-cf08c1a416c3"
|
||||
value = {
|
||||
"admin": {
|
||||
"auth_url": "url",
|
||||
"username": "u",
|
||||
"password": "p",
|
||||
"tenant_name": "t",
|
||||
"region_name": "r",
|
||||
"endpoint_type": consts.EndpointType.INTERNAL
|
||||
},
|
||||
"admin": fakes.fake_credential(
|
||||
auth_url="url",
|
||||
username="u",
|
||||
password="p",
|
||||
tenant_name="t",
|
||||
region_name="r",
|
||||
endpoint_type=consts.EndpointType.INTERNAL),
|
||||
"users": []
|
||||
}
|
||||
deployment = self.fake_api.deployment.get.return_value
|
||||
@ -267,12 +265,12 @@ class DeploymentCommandsTestCase(test.TestCase):
|
||||
deployment_id = "593b683c-4b16-4b2b-a56b-e162bd60f10b"
|
||||
self.fake_api.deployment.get.return_value = fakes.FakeDeployment(
|
||||
uuid=deployment_id,
|
||||
admin={"auth_url": "fake_auth_url",
|
||||
"username": "fake_username",
|
||||
"password": "fake_password",
|
||||
"tenant_name": "fake_tenant_name",
|
||||
"endpoint": "fake_endpoint",
|
||||
"region_name": None})
|
||||
admin=fakes.fake_credential(**{"auth_url": "fake_auth_url",
|
||||
"username": "fake_username",
|
||||
"password": "fake_password",
|
||||
"tenant_name": "fake_tenant_name",
|
||||
"endpoint": "fake_endpoint",
|
||||
"region_name": None}))
|
||||
|
||||
with mock.patch("rally.cli.commands.deployment.open", mock.mock_open(),
|
||||
create=True) as mock_file:
|
||||
@ -304,7 +302,7 @@ class DeploymentCommandsTestCase(test.TestCase):
|
||||
|
||||
self.fake_api.deployment.get.return_value = fakes.FakeDeployment(
|
||||
uuid=deployment_id,
|
||||
admin={
|
||||
admin=fakes.fake_credential(**{
|
||||
"auth_url": "http://localhost:5000/v3",
|
||||
"username": "fake_username",
|
||||
"password": "fake_password",
|
||||
@ -312,7 +310,7 @@ class DeploymentCommandsTestCase(test.TestCase):
|
||||
"endpoint": "fake_endpoint",
|
||||
"region_name": None,
|
||||
"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(),
|
||||
create=True) as mock_file:
|
||||
@ -342,9 +340,10 @@ class DeploymentCommandsTestCase(test.TestCase):
|
||||
@mock.patch("rally.common.fileutils.update_globals_file")
|
||||
def test_use_by_name(self, mock_update_globals_file,
|
||||
mock__update_openrc_deployment_file):
|
||||
fake_credential = fakes.fake_credential(foo="fake_credentials")
|
||||
fake_deployment = fakes.FakeDeployment(
|
||||
uuid="fake_uuid",
|
||||
admin="fake_credentials")
|
||||
admin=fake_credential)
|
||||
self.fake_api.deployment.list.return_value = [fake_deployment]
|
||||
self.fake_api.deployment.get.return_value = fake_deployment
|
||||
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(
|
||||
envutils.ENV_DEPLOYMENT, "fake_uuid")
|
||||
mock__update_openrc_deployment_file.assert_called_once_with(
|
||||
"fake_uuid", "fake_credentials")
|
||||
"fake_uuid", {"foo": "fake_credentials"})
|
||||
|
||||
def test_deployment_not_found(self):
|
||||
deployment_id = "e87e4dca-b515-4477-888d-5f6103f13b42"
|
||||
@ -364,9 +363,9 @@ class DeploymentCommandsTestCase(test.TestCase):
|
||||
@mock.patch("rally.cli.commands.deployment.cliutils.print_list")
|
||||
def test_deployment_check(self, mock_print_list):
|
||||
deployment_id = "e87e4dca-b515-4477-888d-5f6103f13b42"
|
||||
sample_credential = objects.Credential("http://192.168.1.1:5000/v2.0/",
|
||||
"admin",
|
||||
"adminpass").to_dict()
|
||||
sample_credential = fakes.fake_credential(
|
||||
auth_url="http://192.168.1.1:5000/v2.0/",
|
||||
username="admin", password="adminpass")
|
||||
deployment = {"admin": sample_credential,
|
||||
"users": [sample_credential]}
|
||||
self.fake_api.deployment.get.return_value = deployment
|
||||
@ -388,10 +387,9 @@ class DeploymentCommandsTestCase(test.TestCase):
|
||||
|
||||
def test_deployment_check_raise(self):
|
||||
deployment_id = "e87e4dca-b515-4477-888d-5f6103f13b42"
|
||||
sample_credential = objects.Credential("http://192.168.1.1:5000/v2.0/",
|
||||
"admin",
|
||||
"adminpass").to_dict()
|
||||
sample_credential["not-exist-key"] = "error"
|
||||
sample_credential = fakes.fake_credential(
|
||||
auth_url="http://192.168.1.1:5000/v2.0/",
|
||||
username="admin", password="adminpass")
|
||||
deployment = self.fake_api.deployment.get.return_value
|
||||
deployment.get_credentials_for.return_value = {
|
||||
"admin": sample_credential, "users": []}
|
||||
|
@ -18,6 +18,8 @@ from rally import consts
|
||||
from tests.unit import test
|
||||
|
||||
|
||||
# TODO(astudenov): remove this class in future releases
|
||||
|
||||
class CredentialTestCase(test.TestCase):
|
||||
|
||||
def test_to_dict(self):
|
||||
|
@ -117,8 +117,10 @@ class DeploymentTestCase(test.TestCase):
|
||||
{"config": {"opt": "val"}},
|
||||
)
|
||||
|
||||
@mock.patch("rally.deployment.credential.get")
|
||||
@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
|
||||
deploy = objects.Deployment(deployment=self.deployment)
|
||||
credentials = {"foo": [{"admin": {"fake_admin": True},
|
||||
@ -132,23 +134,38 @@ class DeploymentTestCase(test.TestCase):
|
||||
"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},
|
||||
"users": [{"fake_user": True}]}]}
|
||||
self.deployment["credentials"] = credentials
|
||||
deploy = objects.Deployment(deployment=self.deployment)
|
||||
|
||||
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},
|
||||
"users": [{"fake_user": True}]}]}
|
||||
self.deployment["credentials"] = credentials
|
||||
|
||||
deploy = objects.Deployment(deployment=self.deployment)
|
||||
|
||||
self.assertEqual(credentials["openstack"][0]["admin"], deploy["admin"])
|
||||
self.assertEqual(credentials["openstack"][0]["users"], deploy["users"])
|
||||
self.assertEqual(credential_inst, deploy["admin"])
|
||||
self.assertEqual([credential_inst], deploy["users"])
|
||||
|
||||
def test_update_empty_credentials(self):
|
||||
deploy = objects.Deployment(deployment=self.deployment)
|
||||
|
@ -16,6 +16,7 @@
|
||||
import jsonschema
|
||||
import mock
|
||||
|
||||
from rally import consts
|
||||
from rally.deployment.engines import devstack
|
||||
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_script")
|
||||
@mock.patch("rally.deployment.serverprovider.provider.Server")
|
||||
@mock.patch("rally.deployment.engines.devstack.objects.Credential")
|
||||
def test_deploy(self, mock_credential, mock_server, mock_get_script,
|
||||
def test_deploy(self, mock_server, mock_get_script,
|
||||
mock_get_updated_server, mock_engine_get_provider):
|
||||
mock_engine_get_provider.return_value = fake_provider = (
|
||||
mock.Mock()
|
||||
)
|
||||
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_script.return_value = "fake_script"
|
||||
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:
|
||||
credentials = self.engine.deploy()
|
||||
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)
|
||||
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(
|
||||
info="fake_credentials",
|
||||
provider_name="DevstackEngine",
|
||||
|
@ -61,15 +61,35 @@ class TestExistingCloud(test.TestCase):
|
||||
"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):
|
||||
engine = existing.ExistingCloud(self.deployments[keystone_version])
|
||||
engine.validate()
|
||||
|
||||
@ddt.data("v2.0", "v3")
|
||||
@ddt.data("v2.0", "v3", "abstract")
|
||||
def test_invalid_config(self, keystone_version):
|
||||
deployment = self.deployments[keystone_version]
|
||||
deployment["config"]["admin"] = 42
|
||||
@ -77,7 +97,7 @@ class TestExistingCloud(test.TestCase):
|
||||
self.assertRaises(jsonschema.ValidationError,
|
||||
engine.validate)
|
||||
|
||||
@ddt.data("v2.0", "v3")
|
||||
@ddt.data("v2.0", "v3", "abstract")
|
||||
def test_additional_vars(self, keystone_version):
|
||||
deployment = self.deployments[keystone_version]
|
||||
deployment["extra"] = {}
|
||||
@ -122,11 +142,36 @@ class TestExistingCloud(test.TestCase):
|
||||
self.assertEqual(admin_credential, actual_credentials)
|
||||
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):
|
||||
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):
|
||||
name = self.deployments[keystone_version]["config"]["type"]
|
||||
engine = deploy_engine.Engine.get_engine(
|
||||
|
@ -27,6 +27,7 @@ from tests.unit import fakes
|
||||
from tests.unit import test
|
||||
|
||||
MOD_NAME = "rally.deployment.serverprovider.providers.openstack"
|
||||
OS_CREDENTIAL_NAME = "rally.plugins.openstack.credential"
|
||||
OSProvider = provider.OpenStackProvider
|
||||
|
||||
|
||||
@ -82,11 +83,10 @@ class OpenStackProviderTestCase(test.TestCase):
|
||||
|
||||
self.clients.nova = mock.MagicMock(return_value=self.nova_client)
|
||||
|
||||
@mock.patch(
|
||||
"rally.deployment.serverprovider.providers.openstack.osclients")
|
||||
def test_openstack_provider_init(self, mock_osclients):
|
||||
@mock.patch("rally.osclients.Clients")
|
||||
def test_openstack_provider_init(self, mock_clients):
|
||||
cfg = self._get_valid_config()
|
||||
mock_osclients.Clients = mock.MagicMock(return_value=FakeOSClients())
|
||||
mock_clients.return_value = FakeOSClients()
|
||||
os_provider = OSProvider(mock.MagicMock(), cfg)
|
||||
self.assertEqual("nova", os_provider.nova)
|
||||
self.assertEqual("glance", os_provider.glance)
|
||||
@ -98,60 +98,53 @@ class OpenStackProviderTestCase(test.TestCase):
|
||||
provider = OSProvider(mock.MagicMock(), cfg)
|
||||
self.assertIsNone(provider.glance)
|
||||
|
||||
@mock.patch(
|
||||
"rally.deployment.serverprovider.providers.openstack.osclients")
|
||||
@mock.patch("rally.osclients.Clients")
|
||||
def test_openstack_provider_init_with_invalid_conf_no_user(self,
|
||||
mock_osclients):
|
||||
mock_clients):
|
||||
cfg = self._get_valid_config()
|
||||
cfg.pop("user")
|
||||
self.assertRaises(jsonschema.ValidationError, OSProvider,
|
||||
mock.MagicMock(), cfg)
|
||||
|
||||
@mock.patch(
|
||||
"rally.deployment.serverprovider.providers.openstack.osclients")
|
||||
@mock.patch("rally.osclients.Clients")
|
||||
def test_openstack_provider_init_with_invalid_conf_no_url(self,
|
||||
mock_osclients):
|
||||
mock_clients):
|
||||
cfg = self._get_valid_config()
|
||||
del cfg["image"]["url"]
|
||||
del cfg["image"]["checksum"]
|
||||
self.assertRaises(jsonschema.ValidationError, OSProvider,
|
||||
mock.MagicMock(), cfg)
|
||||
|
||||
@mock.patch(
|
||||
"rally.deployment.serverprovider.providers.openstack.osclients")
|
||||
@mock.patch("rally.osclients.Clients")
|
||||
def test_openstack_provider_init_with_invalid_conf_extra_key(
|
||||
self, mock_osclients):
|
||||
self, mock_clients):
|
||||
cfg = self._get_valid_config()
|
||||
cfg["aaaaa"] = "bbbbb"
|
||||
self.assertRaises(jsonschema.ValidationError, OSProvider,
|
||||
mock.MagicMock(), cfg)
|
||||
|
||||
@mock.patch(
|
||||
"rally.deployment.serverprovider.providers.openstack.osclients")
|
||||
@mock.patch("rally.osclients.Clients")
|
||||
def test_openstack_provider_init_with_invalid_conf_flavor_(self,
|
||||
mock_osclients):
|
||||
mock_clients):
|
||||
cfg = self._get_valid_config()["user"] = 1111
|
||||
self.assertRaises(jsonschema.ValidationError, OSProvider,
|
||||
mock.MagicMock(), cfg)
|
||||
|
||||
@mock.patch(
|
||||
"rally.deployment.serverprovider.providers.openstack.osclients")
|
||||
@mock.patch("rally.osclients.Clients")
|
||||
def test_openstack_provider_with_valid_config(self,
|
||||
mock_osclients):
|
||||
mock_clients):
|
||||
cfg = self._get_valid_config()
|
||||
OSProvider(mock.MagicMock(), cfg)
|
||||
|
||||
@mock.patch(
|
||||
"rally.deployment.serverprovider.providers.openstack.osclients")
|
||||
def test_openstack_provider_with_valid_config_uuid(self, mock_osclients):
|
||||
@mock.patch("rally.osclients.Clients")
|
||||
def test_openstack_provider_with_valid_config_uuid(self, mock_clients):
|
||||
cfg = self._get_valid_config()
|
||||
cfg["image"] = dict(uuid="289D7A51-1A0C-43C4-800D-706EA8A3CDF3")
|
||||
OSProvider(mock.MagicMock(), cfg)
|
||||
|
||||
@mock.patch(
|
||||
"rally.deployment.serverprovider.providers.openstack.osclients")
|
||||
@mock.patch("rally.osclients.Clients")
|
||||
def test_openstack_provider_with_valid_config_checksum(self,
|
||||
mock_osclients):
|
||||
mock_clients):
|
||||
cfg = self._get_valid_config()
|
||||
cfg["image"] = dict(checksum="checksum")
|
||||
OSProvider(mock.MagicMock(), cfg)
|
||||
@ -194,9 +187,9 @@ class OpenStackProviderTestCase(test.TestCase):
|
||||
|
||||
@mock.patch("time.sleep")
|
||||
@mock.patch(MOD_NAME + ".provider.Server")
|
||||
@mock.patch(MOD_NAME + ".osclients")
|
||||
@mock.patch("rally.osclients.Clients")
|
||||
@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):
|
||||
fake_keypair = mock.Mock()
|
||||
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,
|
||||
security_groups=[provider.sg.name])
|
||||
|
||||
@mock.patch(MOD_NAME + ".osclients")
|
||||
def test_get_image_found_by_checksum(self, mock_osclients):
|
||||
@mock.patch("rally.osclients.Clients")
|
||||
def test_get_image_found_by_checksum(self, 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())
|
||||
image_uuid = prov.get_image_uuid()
|
||||
self.assertEqual(image_uuid, "fake-uuid")
|
||||
|
||||
@mock.patch(MOD_NAME + ".osclients")
|
||||
def test_get_image_download(self, mock_osclients):
|
||||
@mock.patch("rally.osclients.Clients")
|
||||
def test_get_image_download(self, mock_clients):
|
||||
self._init_mock_clients()
|
||||
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())
|
||||
image_uuid = prov.get_image_uuid()
|
||||
self.assertEqual(image_uuid, "fake-uuid")
|
||||
|
||||
@mock.patch(MOD_NAME + ".osclients")
|
||||
def test_get_image_no_glance_exception(
|
||||
self, mock_osclients):
|
||||
@mock.patch("rally.osclients.Clients")
|
||||
def test_get_image_no_glance_exception(self, mock_clients):
|
||||
prov = OSProvider(mock.MagicMock(), self._get_valid_config())
|
||||
prov.glance = None
|
||||
self.assertRaises(exceptions.InvalidConfigException,
|
||||
prov.get_image_uuid)
|
||||
|
||||
@mock.patch(MOD_NAME + ".osclients")
|
||||
def test_get_image_from_uuid_no_glance(self, mock_osclients):
|
||||
@mock.patch("rally.osclients.Clients")
|
||||
def test_get_image_from_uuid_no_glance(self, mock_clients):
|
||||
conf = self._get_valid_config()
|
||||
conf["image"]["uuid"] = "EC7A1DB7-C5BD-49A2-8066-613809CB22F5"
|
||||
prov = OSProvider(mock.MagicMock(), conf)
|
||||
prov.glance = True
|
||||
self.assertEqual(conf["image"]["uuid"], prov.get_image_uuid())
|
||||
|
||||
@mock.patch(MOD_NAME + ".osclients")
|
||||
def test_destroy_servers(self, mock_osclients):
|
||||
@mock.patch("rally.osclients.Clients")
|
||||
def test_destroy_servers(self, mock_clients):
|
||||
prov = OSProvider(mock.MagicMock(), self._get_valid_config())
|
||||
prov.resources.get_all.side_effect = [
|
||||
[fakes.FakeResource(
|
||||
|
84
tests/unit/deployment/test_credential.py
Normal file
84
tests/unit/deployment/test_credential.py
Normal 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"})
|
@ -151,7 +151,7 @@ class LxcEngineTestCase(test.TestCase):
|
||||
self.assertEqual(1, len(credentials["openstack"]))
|
||||
credential = credentials["openstack"][0]
|
||||
|
||||
self.assertIsInstance(credential["admin"], dict)
|
||||
self.assertIsNone(credential["admin"])
|
||||
self.assertEqual([], credential["users"])
|
||||
lxc_host_calls = [
|
||||
mock.call(fake_servers[0], {"network": "10.128.128.0/28",
|
||||
|
@ -115,11 +115,12 @@ class ConfigSchemasTestCase(test.TestCase):
|
||||
self.fail(p, schema, ("Found unexpected key(s) for integer/number "
|
||||
"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"}
|
||||
if unexpected_keys:
|
||||
self.fail(p, schema, ("Found unexpected key(s) for boolean type: "
|
||||
"%s." % ", ".join(unexpected_keys)))
|
||||
self.fail(p, schema, ("Found unexpected key(s) for %s type: "
|
||||
"%s." % (type_name,
|
||||
", ".join(unexpected_keys))))
|
||||
|
||||
def _check_item(self, p, schema, definitions):
|
||||
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"):
|
||||
self._check_number_type(p, schema)
|
||||
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:
|
||||
self.fail(p, schema,
|
||||
"Wrong type is used: %s" % schema["type"])
|
||||
|
@ -28,7 +28,6 @@ import six
|
||||
from swiftclient import exceptions as swift_exceptions
|
||||
|
||||
from rally import api
|
||||
from rally.common import objects
|
||||
from rally.common import utils as rally_utils
|
||||
from rally import consts
|
||||
from rally.task import context
|
||||
@ -83,6 +82,14 @@ def setup_dict(data, required=None, defaults=None):
|
||||
return defaults
|
||||
|
||||
|
||||
def fake_credential(**config):
|
||||
m = mock.Mock()
|
||||
m.to_dict.return_value = config
|
||||
for key, value in config.items():
|
||||
setattr(m, key, value)
|
||||
return m
|
||||
|
||||
|
||||
class FakeResource(object):
|
||||
|
||||
def __init__(self, manager=None, name=None, status="ACTIVE", items=None,
|
||||
@ -1594,11 +1601,11 @@ class FakeClients(object):
|
||||
self._ec2 = None
|
||||
self._senlin = None
|
||||
self._watcher = None
|
||||
self._credential = credential_ or objects.Credential(
|
||||
"http://fake.example.org:5000/v2.0/",
|
||||
"fake_username",
|
||||
"fake_password",
|
||||
"fake_tenant_name")
|
||||
self._credential = credential_ or fake_credential(
|
||||
auth_url="http://fake.example.org:5000/v2.0/",
|
||||
username="fake_username",
|
||||
password="fake_password",
|
||||
tenant_name="fake_tenant_name")
|
||||
|
||||
def keystone(self, version=None):
|
||||
if not self._keystone:
|
||||
@ -1806,11 +1813,19 @@ class FakeUserContext(FakeContext):
|
||||
|
||||
admin = {
|
||||
"id": "adminuuid",
|
||||
"credential": objects.Credential("aurl", "aname", "apwd", "atenant")
|
||||
"credential": fake_credential(
|
||||
auth_url="aurl",
|
||||
username="aname",
|
||||
password="apwd",
|
||||
tenant_name="atenant")
|
||||
}
|
||||
user = {
|
||||
"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"
|
||||
}
|
||||
tenants = {"uuid": {"name": "tenant"}}
|
||||
|
@ -31,86 +31,19 @@ class SeekAndDestroyTestCase(test.TestCase):
|
||||
# clear out the client cache
|
||||
manager.SeekAndDestroy.cache = {}
|
||||
|
||||
@mock.patch("%s.osclients.Clients" % BASE,
|
||||
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
|
||||
def test__get_cached_client(self):
|
||||
api_versions = {"cinder": {"version": "1", "service_type": "volume"}}
|
||||
|
||||
destroyer1 = manager.SeekAndDestroy(None, None, None,
|
||||
api_versions=api_versions)
|
||||
destroyer2 = manager.SeekAndDestroy(None, None, None,
|
||||
api_versions=api_versions)
|
||||
destroyer = manager.SeekAndDestroy(None, None, None,
|
||||
api_versions=api_versions)
|
||||
cred = mock.Mock()
|
||||
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),
|
||||
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])])
|
||||
self.assertIsNone(destroyer._get_cached_client(None))
|
||||
|
||||
@mock.patch("%s.LOG" % BASE)
|
||||
def test__delete_single_resource(self, mock_log):
|
||||
|
@ -22,9 +22,7 @@ CTX = "rally.plugins.openstack.context"
|
||||
|
||||
class ExistingUserTestCase(test.TestCase):
|
||||
|
||||
@mock.patch("%s.keystone.existing_users.osclients.Clients" % CTX)
|
||||
@mock.patch("%s.keystone.existing_users.objects.Credential" % CTX)
|
||||
def test_setup(self, mock_credential, mock_clients):
|
||||
def test_setup(self):
|
||||
user1 = mock.MagicMock(tenant_id="1", user_id="1",
|
||||
tenant_name="proj", username="usr")
|
||||
user2 = mock.MagicMock(tenant_id="1", user_id="2",
|
||||
@ -48,8 +46,10 @@ class ExistingUserTestCase(test.TestCase):
|
||||
self.PROJECT_ID_COUNT += 1
|
||||
return user_list[self.PROJECT_ID_COUNT - 1].tenant_id
|
||||
|
||||
mock_clients.return_value.keystone.auth_ref = AuthRef()
|
||||
mock_credential.side_effect = user_list
|
||||
auth_ref = AuthRef()
|
||||
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 = {
|
||||
"task": mock.MagicMock(),
|
||||
|
@ -15,10 +15,10 @@
|
||||
|
||||
import mock
|
||||
|
||||
from rally.common import objects
|
||||
from rally import consts
|
||||
from rally import exceptions
|
||||
from rally.plugins.openstack.context.keystone import users
|
||||
from rally.plugins.openstack import credential as oscredential
|
||||
from tests.unit import test
|
||||
|
||||
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):
|
||||
identity_service = mock_identity.Identity.return_value
|
||||
|
||||
credential = objects.Credential("foo_url", "foo", "foo_pass",
|
||||
https_insecure=True,
|
||||
https_cacert="cacert")
|
||||
credential = oscredential.OpenStackCredential(
|
||||
"foo_url", "foo", "foo_pass",
|
||||
https_insecure=True,
|
||||
https_cacert="cacert")
|
||||
tmp_context = dict(self.context)
|
||||
tmp_context["config"]["users"] = {"tenants": 1,
|
||||
"users_per_tenant": 2,
|
||||
"resource_management_workers": 1}
|
||||
tmp_context["admin"]["credential"] = credential
|
||||
|
||||
credential_dict = credential.to_dict(False)
|
||||
credential_dict = credential.to_dict()
|
||||
user_list = [mock.MagicMock(id="id_%d" % i)
|
||||
for i in range(self.users_num)]
|
||||
identity_service.create_user.side_effect = user_list
|
||||
@ -302,7 +303,7 @@ class UserGeneratorTestCase(test.ScenarioTestCase):
|
||||
self.assertEqual(set(["id", "credential", "tenant_id"]),
|
||||
set(user.keys()))
|
||||
|
||||
user_credential_dict = user["credential"].to_dict(False)
|
||||
user_credential_dict = user["credential"].to_dict()
|
||||
|
||||
excluded_keys = ["auth_url", "username", "password",
|
||||
"tenant_name", "region_name",
|
||||
@ -323,7 +324,7 @@ class UserGeneratorTestCase(test.ScenarioTestCase):
|
||||
|
||||
@mock.patch("%s.identity" % CTX)
|
||||
def test_users_contains_correct_endpoint_type(self, mock_identity):
|
||||
credential = objects.Credential(
|
||||
credential = oscredential.OpenStackCredential(
|
||||
"foo_url", "foo", "foo_pass",
|
||||
endpoint_type=consts.EndpointType.INTERNAL)
|
||||
config = {
|
||||
@ -346,7 +347,8 @@ class UserGeneratorTestCase(test.ScenarioTestCase):
|
||||
|
||||
@mock.patch("%s.identity" % CTX)
|
||||
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": {
|
||||
"users": {
|
||||
|
@ -14,8 +14,8 @@
|
||||
|
||||
import mock
|
||||
|
||||
from rally.common import objects
|
||||
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 tests.unit import test
|
||||
|
||||
@ -26,8 +26,8 @@ class SaharaOutputDataSourcesTestCase(test.ScenarioTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(SaharaOutputDataSourcesTestCase, self).setUp()
|
||||
fake_dict = objects.Credential("http://fake.example.org:5000/v2.0/",
|
||||
"user", "passwd")
|
||||
fake_dict = oscredential.OpenStackCredential(
|
||||
"http://fake.example.org:5000/v2.0/", "user", "passwd")
|
||||
self.tenants_num = 2
|
||||
self.users_per_tenant = 2
|
||||
self.users = self.tenants_num * self.users_per_tenant
|
||||
|
149
tests/unit/plugins/openstack/test_credential.py
Normal file
149
tests/unit/plugins/openstack/test_credential.py
Normal 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)
|
@ -18,6 +18,7 @@ import mock
|
||||
from oslotest import mockpatch
|
||||
|
||||
from rally.plugins.openstack import scenario as base_scenario
|
||||
from tests.unit import fakes
|
||||
from tests.unit import test
|
||||
|
||||
|
||||
@ -130,27 +131,21 @@ class OpenStackScenarioTestCase(test.TestCase):
|
||||
|
||||
@mock.patch("rally.task.scenario.Scenario.validate")
|
||||
def test_validate(self, mock_scenario_validate):
|
||||
cred1 = mock.Mock()
|
||||
cred2 = mock.Mock()
|
||||
cred3 = mock.Mock()
|
||||
self.osclients.mock.side_effect = [cred1, cred2, cred3]
|
||||
cred1 = fakes.fake_credential(foo="bar1")
|
||||
cred2 = fakes.fake_credential(foo="bar2")
|
||||
cred3 = fakes.fake_credential(foo="bar3")
|
||||
|
||||
base_scenario.OpenStackScenario.validate(
|
||||
name="foo_name",
|
||||
config="foo_config",
|
||||
admin="foo_admin",
|
||||
users=[{"credential": "foo_user1"},
|
||||
{"credential": "foo_user2"}],
|
||||
admin=cred1,
|
||||
users=[{"credential": cred2},
|
||||
{"credential": cred3}],
|
||||
deployment=None)
|
||||
|
||||
mock_scenario_validate.assert_called_once_with(
|
||||
name="foo_name",
|
||||
config="foo_config",
|
||||
admin=cred1,
|
||||
users=[cred2, cred3],
|
||||
admin=cred1.clients.return_value,
|
||||
users=[cred2.clients.return_value, cred3.clients.return_value],
|
||||
deployment=None)
|
||||
self.osclients.mock.assert_has_calls([
|
||||
mock.call("foo_admin"),
|
||||
mock.call("foo_user1"),
|
||||
mock.call("foo_user2"),
|
||||
])
|
||||
|
@ -25,20 +25,17 @@ from tests.unit import test
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
CREDS = {
|
||||
"admin": {
|
||||
"username": "admin",
|
||||
"tenant_name": "admin",
|
||||
"password": "admin-12345",
|
||||
"auth_url": "http://test:5000/v2.0/",
|
||||
"permission": "admin",
|
||||
"region_name": "test",
|
||||
"https_insecure": False,
|
||||
"https_cacert": "/path/to/cacert/file",
|
||||
"user_domain_name": "admin",
|
||||
"project_domain_name": "admin"
|
||||
},
|
||||
"uuid": "fake_deployment"
|
||||
CRED = {
|
||||
"username": "admin",
|
||||
"tenant_name": "admin",
|
||||
"password": "admin-12345",
|
||||
"auth_url": "http://test:5000/v2.0/",
|
||||
"permission": "admin",
|
||||
"region_name": "test",
|
||||
"https_insecure": False,
|
||||
"https_cacert": "/path/to/cacert/file",
|
||||
"user_domain_name": "admin",
|
||||
"project_domain_name": "admin"
|
||||
}
|
||||
|
||||
PATH = "rally.plugins.openstack.verification.tempest.config"
|
||||
@ -49,10 +46,8 @@ class TempestConfigfileManagerTestCase(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TempestConfigfileManagerTestCase, self).setUp()
|
||||
|
||||
mock.patch("rally.osclients.Clients").start()
|
||||
|
||||
deployment = fakes.FakeDeployment(**CREDS)
|
||||
deployment = fakes.FakeDeployment(uuid="fake_deployment",
|
||||
admin=fakes.fake_credential(**CRED))
|
||||
self.tempest = config.TempestConfigfileManager(deployment)
|
||||
|
||||
def test__configure_auth(self):
|
||||
@ -60,10 +55,10 @@ class TempestConfigfileManagerTestCase(test.TestCase):
|
||||
self.tempest._configure_auth()
|
||||
|
||||
expected = (
|
||||
("admin_username", CREDS["admin"]["username"]),
|
||||
("admin_password", CREDS["admin"]["password"]),
|
||||
("admin_project_name", CREDS["admin"]["tenant_name"]),
|
||||
("admin_domain_name", CREDS["admin"]["user_domain_name"]))
|
||||
("admin_username", CRED["username"]),
|
||||
("admin_password", CRED["password"]),
|
||||
("admin_project_name", CRED["tenant_name"]),
|
||||
("admin_domain_name", CRED["user_domain_name"]))
|
||||
result = self.tempest.conf.items("auth")
|
||||
for item in expected:
|
||||
self.assertIn(item, result)
|
||||
@ -85,13 +80,13 @@ class TempestConfigfileManagerTestCase(test.TestCase):
|
||||
self.tempest._configure_identity()
|
||||
|
||||
expected = (
|
||||
("region", CREDS["admin"]["region_name"]),
|
||||
("region", CRED["region_name"]),
|
||||
("auth_version", "v2"),
|
||||
("uri", CREDS["admin"]["auth_url"][:-1]),
|
||||
("uri_v3", CREDS["admin"]["auth_url"].replace("/v2.0/", "/v3")),
|
||||
("uri", CRED["auth_url"][:-1]),
|
||||
("uri_v3", CRED["auth_url"].replace("/v2.0/", "/v3")),
|
||||
("disable_ssl_certificate_validation",
|
||||
str(CREDS["admin"]["https_insecure"])),
|
||||
("ca_certificates_file", CREDS["admin"]["https_cacert"]))
|
||||
str(CRED["https_insecure"])),
|
||||
("ca_certificates_file", CRED["https_cacert"]))
|
||||
result = self.tempest.conf.items("identity")
|
||||
for item in expected:
|
||||
self.assertIn(item, result)
|
||||
|
@ -30,20 +30,17 @@ from tests.unit import test
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
CREDS = {
|
||||
"admin": {
|
||||
"username": "admin",
|
||||
"tenant_name": "admin",
|
||||
"password": "admin-12345",
|
||||
"auth_url": "http://test:5000/v2.0/",
|
||||
"permission": "admin",
|
||||
"region_name": "test",
|
||||
"https_insecure": False,
|
||||
"https_cacert": "/path/to/cacert/file",
|
||||
"user_domain_name": "admin",
|
||||
"project_domain_name": "admin"
|
||||
},
|
||||
"uuid": "fake_deployment"
|
||||
CRED = {
|
||||
"username": "admin",
|
||||
"tenant_name": "admin",
|
||||
"password": "admin-12345",
|
||||
"auth_url": "http://test:5000/v2.0/",
|
||||
"permission": "admin",
|
||||
"region_name": "test",
|
||||
"https_insecure": False,
|
||||
"https_cacert": "/path/to/cacert/file",
|
||||
"user_domain_name": "admin",
|
||||
"project_domain_name": "admin"
|
||||
}
|
||||
|
||||
PATH = "rally.plugins.openstack.verification.tempest.context"
|
||||
@ -55,11 +52,12 @@ class TempestContextTestCase(test.TestCase):
|
||||
def setUp(self):
|
||||
super(TempestContextTestCase, self).setUp()
|
||||
|
||||
mock.patch("rally.osclients.Clients").start()
|
||||
self.mock_isfile = mock.patch("os.path.isfile",
|
||||
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),
|
||||
"verification": {"uuid": "uuid"}}
|
||||
cfg["verifier"].manager.home_dir = "/p/a/t/h"
|
||||
@ -244,6 +242,7 @@ class TempestContextTestCase(test.TestCase):
|
||||
|
||||
def test__discover_or_create_flavor(self):
|
||||
client = self.context.clients.nova()
|
||||
client.flavors.list.return_value = []
|
||||
client.flavors.create.side_effect = [fakes.FakeFlavor(id="id1")]
|
||||
|
||||
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_router.side_effect = [{"router": {"id": "rid1"}}]
|
||||
client.create_subnet.side_effect = [{"subnet": {"id": "subid1"}}]
|
||||
client.list_networks.return_value = {"networks": []}
|
||||
|
||||
network = self.context._create_network_resources()
|
||||
self.assertEqual("nid1", network["id"])
|
||||
@ -333,16 +333,14 @@ class TempestContextTestCase(test.TestCase):
|
||||
@mock.patch("%s.TempestContext._configure_option" % PATH)
|
||||
@mock.patch("%s.TempestContext._create_tempest_roles" % PATH)
|
||||
@mock.patch("rally.verification.utils.create_dir")
|
||||
@mock.patch("%s.osclients.Clients" % PATH)
|
||||
def test_setup(self, mock_clients, mock_create_dir,
|
||||
def test_setup(self, mock_create_dir,
|
||||
mock__create_tempest_roles, mock__configure_option,
|
||||
mock_open):
|
||||
self.deployment = fakes.FakeDeployment(**CREDS)
|
||||
verifier = mock.Mock(deployment=self.deployment)
|
||||
verifier.manager.home_dir = "/p/a/t/h"
|
||||
|
||||
# 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.conf = mock.Mock()
|
||||
@ -377,10 +375,12 @@ class TempestContextTestCase(test.TestCase):
|
||||
mock__configure_option.reset_mock()
|
||||
|
||||
# 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"}
|
||||
|
||||
ctx = context.TempestContext({"verifier": verifier})
|
||||
neutron = ctx.clients.neutron()
|
||||
neutron.list_networks.return_value = {"networks": ["fake_net"]}
|
||||
ctx.conf = mock.Mock()
|
||||
ctx.setup()
|
||||
|
||||
|
@ -16,7 +16,6 @@
|
||||
"""Tests for the Test engine."""
|
||||
|
||||
import collections
|
||||
import copy
|
||||
import threading
|
||||
|
||||
import jsonschema
|
||||
@ -286,10 +285,8 @@ class TaskEngineTestCase(test.TestCase):
|
||||
eng._validate_config_semantic_helper, "a",
|
||||
user_context, workloads, "fake_deployment")
|
||||
|
||||
@mock.patch("rally.osclients.Clients")
|
||||
@mock.patch("rally.task.engine.scenario.Scenario.get")
|
||||
@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.TaskEngine"
|
||||
"._validate_config_semantic_helper")
|
||||
@ -298,11 +295,12 @@ class TaskEngineTestCase(test.TestCase):
|
||||
def test__validate_config_semantic(
|
||||
self, mock_deployment_get,
|
||||
mock__validate_config_semantic_helper,
|
||||
mock_task_config, mock_credential, mock_context,
|
||||
mock_scenario_get, mock_clients):
|
||||
mock_task_config, mock_context,
|
||||
mock_scenario_get):
|
||||
admin = fakes.fake_credential(foo="admin")
|
||||
users = [fakes.fake_credential(bar="user1")]
|
||||
deployment = fakes.FakeDeployment(
|
||||
uuid="deployment_uuid", admin={"foo": "admin"},
|
||||
users=[{"bar": "user1"}])
|
||||
uuid="deployment_uuid", admin=admin, users=users)
|
||||
|
||||
scenario_cls = mock_scenario_get.return_value
|
||||
scenario_cls.get_namespace.return_value = "default"
|
||||
@ -324,12 +322,8 @@ class TaskEngineTestCase(test.TestCase):
|
||||
|
||||
eng._validate_config_semantic(mock_task_instance)
|
||||
|
||||
admin = mock_credential.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.call(admin, user_context, [wconf1], deployment),
|
||||
mock.call(admin, user_context, [wconf2, wconf3], deployment),
|
||||
@ -356,7 +350,6 @@ class TaskEngineTestCase(test.TestCase):
|
||||
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.TaskConfig")
|
||||
@mock.patch("rally.task.engine.LOG")
|
||||
@ -368,7 +361,7 @@ class TaskEngineTestCase(test.TestCase):
|
||||
def test_run_exception_is_logged(
|
||||
self, mock_context_manager_setup, mock_context_manager_cleanup,
|
||||
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.get_namespace.return_value = "openstack"
|
||||
|
||||
@ -394,7 +387,6 @@ class TaskEngineTestCase(test.TestCase):
|
||||
|
||||
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.context.ContextManager.cleanup")
|
||||
@mock.patch("rally.task.engine.context.ContextManager.setup")
|
||||
@ -403,7 +395,7 @@ class TaskEngineTestCase(test.TestCase):
|
||||
def test_run__task_soft_aborted(
|
||||
self, mock_scenario_runner, mock_scenario,
|
||||
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.get_namespace.return_value = "openstack"
|
||||
task = mock.MagicMock()
|
||||
@ -455,11 +447,9 @@ class TaskEngineTestCase(test.TestCase):
|
||||
self.assertEqual(mock.call(consts.TaskStatus.ABORTED),
|
||||
task.update_status.mock_calls[-1])
|
||||
|
||||
@mock.patch("rally.task.engine.objects.Credential")
|
||||
@mock.patch("rally.task.engine.TaskConfig")
|
||||
@mock.patch("rally.task.engine.scenario.Scenario.get")
|
||||
def test__prepare_context(self, mock_scenario_get, mock_task_config,
|
||||
mock_credential):
|
||||
def test__prepare_context(self, mock_scenario_get, mock_task_config):
|
||||
default_context = {"a": 1, "b": 2}
|
||||
mock_scenario = mock_scenario_get.return_value
|
||||
mock_scenario.get_default_context.return_value = default_context
|
||||
@ -470,28 +460,24 @@ class TaskEngineTestCase(test.TestCase):
|
||||
config = {
|
||||
"a.task": [{"context": {"context_a": {"a": 1}}}],
|
||||
}
|
||||
admin = fakes.fake_credential(foo="admin")
|
||||
deployment = fakes.FakeDeployment(
|
||||
uuid="deployment_uuid", admin={"foo": "admin"})
|
||||
uuid="deployment_uuid", admin=admin)
|
||||
eng = engine.TaskEngine(config, task, deployment)
|
||||
result = eng._prepare_context(context, name)
|
||||
expected_context = copy.deepcopy(default_context)
|
||||
expected_context.setdefault("users", {})
|
||||
expected_context.update(context)
|
||||
expected_result = {
|
||||
"task": task,
|
||||
"admin": {"credential": mock_credential.return_value},
|
||||
"admin": {"credential": admin},
|
||||
"scenario_name": name,
|
||||
"config": expected_context
|
||||
"config": {"a": 1, "b": 3, "c": 4, "users": {}}
|
||||
}
|
||||
self.assertEqual(result, expected_result)
|
||||
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.scenario.Scenario.get")
|
||||
def test__prepare_context_with_existing_users(self, mock_scenario_get,
|
||||
mock_task_config,
|
||||
mock_credential):
|
||||
mock_task_config):
|
||||
mock_scenario = mock_scenario_get.return_value
|
||||
mock_scenario.get_default_context.return_value = {}
|
||||
mock_scenario.get_namespace.return_value = "default"
|
||||
@ -501,18 +487,17 @@ class TaskEngineTestCase(test.TestCase):
|
||||
config = {
|
||||
"a.task": [{"context": {"context_a": {"a": 1}}}],
|
||||
}
|
||||
deployment = fakes.FakeDeployment(
|
||||
uuid="deployment_uuid", admin={"foo": "admin"},
|
||||
users=[{"bar": "user1"}])
|
||||
admin = fakes.fake_credential(foo="admin")
|
||||
users = [fakes.fake_credential(bar="user1")]
|
||||
deployment = fakes.FakeDeployment(uuid="deployment_uuid",
|
||||
admin=admin, users=users)
|
||||
eng = engine.TaskEngine(config, task, deployment)
|
||||
result = eng._prepare_context(context, name)
|
||||
expected_context = {"existing_users": [{"bar": "user1"}]}
|
||||
expected_context.update(context)
|
||||
expected_result = {
|
||||
"task": task,
|
||||
"admin": {"credential": mock_credential.return_value},
|
||||
"admin": {"credential": admin},
|
||||
"scenario_name": name,
|
||||
"config": expected_context
|
||||
"config": {"b": 3, "c": 4, "existing_users": users}
|
||||
}
|
||||
self.assertEqual(result, expected_result)
|
||||
mock_scenario_get.assert_called_once_with(name)
|
||||
|
@ -24,7 +24,6 @@ import six
|
||||
from rally.common.plugin import plugin
|
||||
from rally import consts
|
||||
from rally import exceptions
|
||||
import rally.osclients
|
||||
from rally.task import validation
|
||||
from tests.unit import fakes
|
||||
from tests.unit import test
|
||||
@ -557,35 +556,32 @@ class ValidatorsTestCase(test.TestCase):
|
||||
result = validator({"args": {"a": 1, "c": 3}}, None, None)
|
||||
self.assertFalse(result.is_valid, result.msg)
|
||||
|
||||
@mock.patch("rally.common.objects.Credential")
|
||||
def test_required_service(self, mock_credential):
|
||||
def test_required_service(self):
|
||||
validator = self._unwrap_validator(validation.required_services,
|
||||
consts.Service.KEYSTONE,
|
||||
consts.Service.NOVA,
|
||||
consts.Service.NOVA_NET)
|
||||
clients = mock.MagicMock()
|
||||
admin = fakes.fake_credential(foo="bar")
|
||||
clients = mock.Mock()
|
||||
clients.services().values.return_value = [consts.Service.KEYSTONE,
|
||||
consts.Service.NOVA,
|
||||
consts.Service.NOVA_NET]
|
||||
|
||||
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)
|
||||
|
||||
validator = self._unwrap_validator(validation.required_services,
|
||||
consts.Service.KEYSTONE,
|
||||
consts.Service.NOVA)
|
||||
clients.services().values.return_value = [consts.Service.KEYSTONE]
|
||||
with mock.patch("rally.osclients.Clients") as clients_cls:
|
||||
result = validator({}, clients, None)
|
||||
self.assertFalse(clients_cls.called)
|
||||
|
||||
result = validator({}, clients, None)
|
||||
self.assertFalse(result.is_valid, result.msg)
|
||||
|
||||
def test_required_service_wrong_service(self):
|
||||
@ -752,37 +748,33 @@ class ValidatorsTestCase(test.TestCase):
|
||||
result = validator(context, clients, mock.MagicMock())
|
||||
self.assertFalse(result.is_valid, result.msg)
|
||||
|
||||
@mock.patch(MODULE + "osclients")
|
||||
def test_required_clients(self, mock_osclients):
|
||||
def test_required_clients(self):
|
||||
validator = self._unwrap_validator(validation.required_clients,
|
||||
"keystone", "nova")
|
||||
clients = mock.MagicMock()
|
||||
clients = mock.Mock()
|
||||
clients.keystone.return_value = "keystone"
|
||||
clients.nova.return_value = "nova"
|
||||
deployment = fakes.FakeDeployment()
|
||||
result = validator({}, clients, deployment)
|
||||
self.assertTrue(result.is_valid, result.msg)
|
||||
self.assertFalse(mock_osclients.Clients.called)
|
||||
|
||||
clients.nova.side_effect = ImportError
|
||||
result = validator({}, clients, deployment)
|
||||
self.assertFalse(result.is_valid, result.msg)
|
||||
|
||||
@mock.patch(MODULE + "objects")
|
||||
@mock.patch(MODULE + "osclients")
|
||||
def test_required_clients_with_admin(self, mock_osclients, mock_objects):
|
||||
def test_required_clients_with_admin(self):
|
||||
validator = self._unwrap_validator(validation.required_clients,
|
||||
"keystone", "nova", admin=True)
|
||||
clients = mock.Mock()
|
||||
admin = fakes.fake_credential(foo="bar")
|
||||
|
||||
clients = admin.clients.return_value
|
||||
clients.keystone.return_value = "keystone"
|
||||
clients.nova.return_value = "nova"
|
||||
mock_osclients.Clients.return_value = clients
|
||||
mock_objects.Credential.return_value = "foo_credential"
|
||||
deployment = fakes.FakeDeployment(admin={"foo": "bar"})
|
||||
|
||||
deployment = fakes.FakeDeployment(admin=admin)
|
||||
result = validator({}, clients, deployment)
|
||||
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
|
||||
result = validator({}, clients, deployment)
|
||||
self.assertFalse(result.is_valid, result.msg)
|
||||
@ -810,24 +802,17 @@ class ValidatorsTestCase(test.TestCase):
|
||||
validation.required_cinder_services,
|
||||
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")
|
||||
cinder_client = mock.Mock()
|
||||
services = mock.Mock()
|
||||
services.list.return_value = [fake_service]
|
||||
cinder_client.services = services
|
||||
c.return_value = cinder_client
|
||||
fake_service = mock.Mock(binary="cinder-service", state="up")
|
||||
admin = fakes.fake_credential(foo="bar")
|
||||
cinder = admin.clients.return_value.cinder.return_value
|
||||
cinder.services.list.return_value = [fake_service]
|
||||
deployment = fakes.FakeDeployment(admin=admin)
|
||||
result = validator({}, None, deployment)
|
||||
self.assertTrue(result.is_valid, result.msg)
|
||||
|
||||
deployment = fakes.FakeDeployment(
|
||||
admin={"auth_url": "fake_credential",
|
||||
"username": "username",
|
||||
"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)
|
||||
fake_service.state = "down"
|
||||
result = validator({}, None, deployment)
|
||||
self.assertFalse(result.is_valid, result.msg)
|
||||
|
||||
def test_restricted_parameters(self):
|
||||
validator = self._unwrap_validator(
|
||||
|
@ -20,7 +20,6 @@ import os
|
||||
|
||||
import ddt
|
||||
import jsonschema
|
||||
from keystoneclient import exceptions as keystone_exceptions
|
||||
import mock
|
||||
from oslo_config import cfg
|
||||
|
||||
@ -349,8 +348,8 @@ class BaseDeploymentTestCase(test.TestCase):
|
||||
class DeploymentAPITestCase(BaseDeploymentTestCase):
|
||||
@mock.patch("rally.common.objects.deploy.db.deployment_update")
|
||||
@mock.patch("rally.common.objects.deploy.db.deployment_create")
|
||||
@mock.patch("rally.deployment.engine.Engine.validate")
|
||||
def test_create(self, mock_engine_validate,
|
||||
@mock.patch("rally.deployment.engines.existing.ExistingCloud.validate")
|
||||
def test_create(self, mock_existing_cloud_validate,
|
||||
mock_deployment_create, mock_deployment_update):
|
||||
mock_deployment_create.return_value = self.deployment
|
||||
mock_deployment_update.return_value = self.deployment
|
||||
@ -360,7 +359,7 @@ class DeploymentAPITestCase(BaseDeploymentTestCase):
|
||||
"name": "fake_deployment",
|
||||
"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.call(self.deployment_uuid,
|
||||
{"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_create")
|
||||
@mock.patch("rally.deployment.engine.Engine.validate",
|
||||
@mock.patch("rally.deployment.engines.existing.ExistingCloud.validate",
|
||||
side_effect=jsonschema.ValidationError("ValidationError"))
|
||||
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_create.return_value = self.deployment
|
||||
self.assertRaises(jsonschema.ValidationError,
|
||||
@ -488,41 +487,25 @@ class DeploymentAPITestCase(BaseDeploymentTestCase):
|
||||
for key in self.deployment:
|
||||
self.assertEqual(ret[key], self.deployment[key])
|
||||
|
||||
@mock.patch("rally.osclients.Clients.services")
|
||||
@mock.patch("rally.osclients.Keystone.create_client")
|
||||
def test_deployment_check(self, mock_keystone_create_client,
|
||||
mock_clients_services):
|
||||
sample_credential = objects.Credential("http://192.168.1.1:5000/v2.0/",
|
||||
"admin",
|
||||
"adminpass").to_dict()
|
||||
def test_deployment_check(self):
|
||||
fake_credential1 = fakes.fake_credential()
|
||||
fake_credential2 = fakes.fake_credential()
|
||||
|
||||
deployment = mock.Mock(spec=objects.Deployment)
|
||||
deployment.get_credentials_for.return_value = {
|
||||
"admin": sample_credential, "users": [sample_credential]}
|
||||
api._Deployment.check(deployment)
|
||||
mock_keystone_create_client.assert_called_with()
|
||||
mock_clients_services.assert_called_once_with()
|
||||
"admin": fake_credential1, "users": [fake_credential2]}
|
||||
result = api._Deployment.check(deployment)
|
||||
fake_credential1.verify_connection.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):
|
||||
sample_credential = objects.Credential("http://192.168.1.1:5000/v2.0/",
|
||||
"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()
|
||||
def test_service_list(self):
|
||||
fake_credential = fakes.fake_credential()
|
||||
deployment = mock.Mock(spec=objects.Deployment)
|
||||
deployment.get_credentials_for.return_value = {
|
||||
"admin": sample_credential, "users": []}
|
||||
refused = keystone_exceptions.ConnectionRefused()
|
||||
mock_clients_services.side_effect = refused
|
||||
self.assertRaises(
|
||||
keystone_exceptions.ConnectionRefused,
|
||||
api._Deployment.check, deployment)
|
||||
"admin": fake_credential, "users": []}
|
||||
result = api._Deployment.service_list(deployment)
|
||||
self.assertEqual(fake_credential.list_services.return_value, result)
|
||||
|
||||
|
||||
class APITestCase(test.TestCase):
|
||||
|
@ -18,10 +18,10 @@ from keystoneclient import exceptions as keystone_exceptions
|
||||
import mock
|
||||
from oslo_config import cfg
|
||||
|
||||
from rally.common import objects
|
||||
from rally import consts
|
||||
from rally import exceptions
|
||||
from rally import osclients
|
||||
from rally.plugins.openstack import credential as oscredential
|
||||
from tests.unit import fakes
|
||||
from tests.unit import test
|
||||
|
||||
@ -91,9 +91,10 @@ class OSClientTestCase(test.TestCase, OSClientTestCaseUtils):
|
||||
@ddt.unpack
|
||||
def test__get_endpoint(self, mock_keystone_service_catalog, endpoint_type,
|
||||
service_type, region_name):
|
||||
credential = objects.Credential("http://auth_url/v2.0", "user", "pass",
|
||||
endpoint_type=endpoint_type,
|
||||
region_name=region_name)
|
||||
credential = oscredential.OpenStackCredential(
|
||||
"http://auth_url/v2.0", "user", "pass",
|
||||
endpoint_type=endpoint_type,
|
||||
region_name=region_name)
|
||||
mock_choose_service_type = mock.MagicMock()
|
||||
osclient = osclients.OSClient(credential, {}, mock.MagicMock())
|
||||
osclient.choose_service_type = mock_choose_service_type
|
||||
@ -153,8 +154,8 @@ class TestCreateKeystoneClient(test.TestCase, OSClientTestCaseUtils):
|
||||
|
||||
def setUp(self):
|
||||
super(TestCreateKeystoneClient, self).setUp()
|
||||
self.credential = objects.Credential("http://auth_url/v2.0", "user",
|
||||
"pass", "tenant")
|
||||
self.credential = oscredential.OpenStackCredential(
|
||||
"http://auth_url/v2.0", "user", "pass", "tenant")
|
||||
|
||||
def test_create_client(self):
|
||||
# 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",
|
||||
"http://auth_url/", "auth_url")
|
||||
def test_keystone_get_session(self, auth_url):
|
||||
credential = objects.Credential(auth_url, "user",
|
||||
"pass", "tenant")
|
||||
credential = oscredential.OpenStackCredential(
|
||||
auth_url, "user", "pass", "tenant")
|
||||
self.set_up_keystone_mocks()
|
||||
keystone = osclients.Keystone(credential, {}, {})
|
||||
|
||||
@ -255,8 +256,8 @@ class OSClientsTestCase(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(OSClientsTestCase, self).setUp()
|
||||
self.credential = objects.Credential("http://auth_url/v2.0", "user",
|
||||
"pass", "tenant")
|
||||
self.credential = oscredential.OpenStackCredential(
|
||||
"http://auth_url/v2.0", "user", "pass", "tenant")
|
||||
self.clients = osclients.Clients(self.credential, {})
|
||||
|
||||
self.fake_keystone = fakes.FakeKeystoneClient()
|
||||
|
Loading…
Reference in New Issue
Block a user