Add support for Keystone API v3
bp keystone-v3-support Change-Id: Iffdff6ee2e79b7052f7a58af933e398090879224
This commit is contained in:
parent
d139166104
commit
ed571ece7a
@ -19,6 +19,7 @@ from neutronclient.common import exceptions as neutron_exceptions
|
||||
|
||||
from rally.benchmark.scenarios.keystone import utils as kutils
|
||||
from rally.benchmark import utils as bench_utils
|
||||
from rally.benchmark.wrappers import keystone as keystone_wrapper
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@ -39,14 +40,15 @@ def delete_heat_resources(heat):
|
||||
|
||||
|
||||
def delete_keystone_resources(keystone):
|
||||
for resource in ["users", "tenants", "services", "roles"]:
|
||||
keystone = keystone_wrapper.wrap(keystone)
|
||||
for resource in ["user", "project", "service", "role"]:
|
||||
_delete_single_keystone_resource_type(keystone, resource)
|
||||
|
||||
|
||||
def _delete_single_keystone_resource_type(keystone, resource_name):
|
||||
for resource in getattr(keystone, resource_name).list():
|
||||
for resource in getattr(keystone, "list_%ss" % resource_name)():
|
||||
if kutils.is_temporary(resource):
|
||||
resource.delete()
|
||||
getattr(keystone, "delete_%s" % resource_name)(resource.id)
|
||||
|
||||
|
||||
def delete_images(glance, project_uuid):
|
||||
|
@ -17,6 +17,7 @@ from oslo.config import cfg
|
||||
|
||||
from rally.benchmark.context import base
|
||||
from rally.benchmark import utils
|
||||
from rally.benchmark.wrappers import keystone
|
||||
from rally import consts
|
||||
from rally.objects import endpoint
|
||||
from rally.openstack.common.gettextutils import _
|
||||
@ -31,7 +32,13 @@ context_opts = [
|
||||
cfg.IntOpt("concurrent",
|
||||
default=30,
|
||||
help="How many concurrent threads use for serving users "
|
||||
"context")
|
||||
"context"),
|
||||
cfg.StrOpt("project_domain",
|
||||
default="default",
|
||||
help="ID of domain in which projects will be created."),
|
||||
cfg.StrOpt("user_domain",
|
||||
default="default",
|
||||
help="ID of domain in which users will be created."),
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
@ -63,6 +70,12 @@ class UserGenerator(base.Context):
|
||||
"type": "integer",
|
||||
"minimum": 1
|
||||
},
|
||||
"project_domain": {
|
||||
"type": "string",
|
||||
},
|
||||
"user_domain": {
|
||||
"type": "string",
|
||||
},
|
||||
},
|
||||
"additionalProperties": False
|
||||
}
|
||||
@ -75,6 +88,10 @@ class UserGenerator(base.Context):
|
||||
self.config.setdefault("users_per_tenant", 1)
|
||||
self.config.setdefault("concurrent",
|
||||
cfg.CONF.users_context.concurrent)
|
||||
self.config.setdefault("project_domain",
|
||||
cfg.CONF.users_context.project_domain)
|
||||
self.config.setdefault("user_domain",
|
||||
cfg.CONF.users_context.user_domain)
|
||||
self.context["users"] = []
|
||||
self.context["tenants"] = []
|
||||
self.endpoint = self.context["admin"]["endpoint"]
|
||||
@ -93,24 +110,27 @@ class UserGenerator(base.Context):
|
||||
:returns: tuple (dict tenant, list users)
|
||||
"""
|
||||
|
||||
admin_endpoint, users_num, task_id, i = args
|
||||
admin_endpoint, users_num, project_dom, user_dom, task_id, i = args
|
||||
users = []
|
||||
|
||||
client = osclients.Clients(admin_endpoint).keystone()
|
||||
tenant = client.tenants.create(
|
||||
cls.PATTERN_TENANT % {"task_id": task_id, "iter": i})
|
||||
client = keystone.wrap(osclients.Clients(admin_endpoint).keystone())
|
||||
tenant = client.create_project(
|
||||
cls.PATTERN_TENANT % {"task_id": task_id, "iter": i}, project_dom)
|
||||
|
||||
LOG.debug("Creating %d users for tenant %s" % (users_num, tenant.id))
|
||||
|
||||
for user_id in range(users_num):
|
||||
username = cls.PATTERN_USER % {"tenant_id": tenant.id,
|
||||
"uid": user_id}
|
||||
user = client.users.create(username, "password",
|
||||
"%s@email.me" % username, tenant.id)
|
||||
user = client.create_user(username, "password",
|
||||
"%s@email.me" % username, tenant.id,
|
||||
user_dom)
|
||||
user_endpoint = endpoint.Endpoint(client.auth_url, user.name,
|
||||
"password", tenant.name,
|
||||
consts.EndpointPermission.USER,
|
||||
client.region_name)
|
||||
client.region_name,
|
||||
project_domain_name=project_dom,
|
||||
user_domain_name=user_dom)
|
||||
users.append({"id": user.id,
|
||||
"endpoint": user_endpoint,
|
||||
"tenant_id": tenant.id})
|
||||
@ -124,11 +144,11 @@ class UserGenerator(base.Context):
|
||||
:param args: tuple arguments, for Pool.imap()
|
||||
"""
|
||||
admin_endpoint, tenants = args
|
||||
client = osclients.Clients(admin_endpoint).keystone()
|
||||
client = keystone.wrap(osclients.Clients(admin_endpoint).keystone())
|
||||
|
||||
for tenant in tenants:
|
||||
try:
|
||||
client.tenants.delete(tenant["id"])
|
||||
client.delete_project(tenant["id"])
|
||||
except Exception as ex:
|
||||
LOG.warning("Failed to delete tenant: %(tenant_id)s. "
|
||||
"Exception: %(ex)s" %
|
||||
@ -141,11 +161,11 @@ class UserGenerator(base.Context):
|
||||
:param args: tuple arguments, for Pool.imap()
|
||||
"""
|
||||
admin_endpoint, users = args
|
||||
client = osclients.Clients(admin_endpoint).keystone()
|
||||
client = keystone.wrap(osclients.Clients(admin_endpoint).keystone())
|
||||
|
||||
for user in users:
|
||||
try:
|
||||
client.users.delete(user["id"])
|
||||
client.delete_user(user["id"])
|
||||
except Exception as ex:
|
||||
LOG.warning("Failed to delete user: %(user_id)s. "
|
||||
"Exception: %(ex)s" %
|
||||
@ -157,11 +177,12 @@ class UserGenerator(base.Context):
|
||||
|
||||
users_num = self.config["users_per_tenant"]
|
||||
|
||||
args = [(self.endpoint, users_num, self.task["uuid"], i)
|
||||
args = [(self.endpoint, users_num, self.config["project_domain"],
|
||||
self.config["user_domain"], self.task["uuid"], i)
|
||||
for i in range(self.config["tenants"])]
|
||||
|
||||
LOG.debug("Creating %d users using %s threads" % (
|
||||
users_num * self.config["tenants"], self.config["concurrent"]))
|
||||
users_num * self.config["tenants"], self.config["concurrent"]))
|
||||
|
||||
for tenant, users in utils.run_concurrent(
|
||||
self.config["concurrent"],
|
||||
|
0
rally/benchmark/wrappers/__init__.py
Normal file
0
rally/benchmark/wrappers/__init__.py
Normal file
215
rally/benchmark/wrappers/keystone.py
Normal file
215
rally/benchmark/wrappers/keystone.py
Normal file
@ -0,0 +1,215 @@
|
||||
# Copyright 2014: 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 collections
|
||||
|
||||
from keystoneclient import exceptions
|
||||
import six
|
||||
|
||||
|
||||
Project = collections.namedtuple('Project', ['id', 'name', 'domain_id'])
|
||||
User = collections.namedtuple('User',
|
||||
['id', 'name', 'project_id', 'domain_id'])
|
||||
Service = collections.namedtuple('Service', ['id', 'name'])
|
||||
Role = collections.namedtuple('Role', ['id', 'name'])
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class KeystoneWrapper(object):
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
|
||||
def __getattr__(self, attr_name):
|
||||
return getattr(self.client, attr_name)
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_project(self, project_name, domain_name='Default'):
|
||||
"""Creates new project/tenant and return project object.
|
||||
|
||||
:param project_name: Name of project to be created.
|
||||
:param domain_name: Name or id of domain where to create project, for
|
||||
implementations that don't support domains this
|
||||
argument must be None or 'Default'.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_project(self, project_id):
|
||||
"""Deletes project."""
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_user(self, username, password, email=None, project_id=None,
|
||||
domain_name='Default'):
|
||||
"""Creates user that have Mamber role in given project.
|
||||
|
||||
:param username: name of user
|
||||
:param password: user password
|
||||
:param project: user's default project
|
||||
:param domain_name: Name or id of domain where to create project, for
|
||||
implementations that don't support domains this
|
||||
argument must be None or 'Default'.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_user(self, user_id):
|
||||
"""Deletes user."""
|
||||
|
||||
@abc.abstractmethod
|
||||
def list_users(self):
|
||||
"""List all users."""
|
||||
|
||||
@abc.abstractmethod
|
||||
def list_projects(self):
|
||||
"""List all projects/tenants."""
|
||||
|
||||
def delete_service(self, service_id):
|
||||
"""Deletes service."""
|
||||
self.client.services.delete(service_id)
|
||||
|
||||
def list_services(self):
|
||||
"""List all services."""
|
||||
return map(KeystoneWrapper._wrap_service, self.client.services.list())
|
||||
|
||||
def delete_role(self, role_id):
|
||||
"""Deletes role."""
|
||||
self.client.roles.delete(role_id)
|
||||
|
||||
def list_roles(self):
|
||||
"""List all roles."""
|
||||
return map(KeystoneWrapper._wrap_role, self.client.roles.list())
|
||||
|
||||
@staticmethod
|
||||
def _wrap_service(service):
|
||||
return Service(id=service.id, name=service.name)
|
||||
|
||||
@staticmethod
|
||||
def _wrap_role(role):
|
||||
return Role(id=role.id, name=role.name)
|
||||
|
||||
|
||||
class KeystoneV2Wrapper(KeystoneWrapper):
|
||||
def _check_domain(self, domain_name):
|
||||
if domain_name.lower() != 'default':
|
||||
raise NotImplementedError('Domain functionality not implemented '
|
||||
'in Keystone v2')
|
||||
|
||||
@staticmethod
|
||||
def _wrap_v2_tenant(tenant):
|
||||
return Project(id=tenant.id, name=tenant.name, domain_id='default')
|
||||
|
||||
@staticmethod
|
||||
def _wrap_v2_user(user):
|
||||
return User(id=user.id, name=user.name, project_id=user.tenantId,
|
||||
domain_id='default')
|
||||
|
||||
def create_project(self, project_name, domain_name='Default'):
|
||||
self._check_domain(domain_name)
|
||||
tenant = self.client.tenants.create(project_name)
|
||||
return KeystoneV2Wrapper._wrap_v2_tenant(tenant)
|
||||
|
||||
def delete_project(self, project_id):
|
||||
self.client.tenants.delete(project_id)
|
||||
|
||||
def create_user(self, username, password, email=None, project_id=None,
|
||||
domain_name='Default'):
|
||||
self._check_domain(domain_name)
|
||||
user = self.client.users.create(username, password, email, project_id)
|
||||
return KeystoneV2Wrapper._wrap_v2_user(user)
|
||||
|
||||
def delete_user(self, user_id):
|
||||
self.client.users.delete(user_id)
|
||||
|
||||
def list_users(self):
|
||||
return map(KeystoneV2Wrapper._wrap_v2_user, self.client.users.list())
|
||||
|
||||
def list_projects(self):
|
||||
return map(KeystoneV2Wrapper._wrap_v2_tenant,
|
||||
self.client.tenants.list())
|
||||
|
||||
|
||||
class KeystoneV3Wrapper(KeystoneWrapper):
|
||||
def _get_domain_id(self, domain_name_or_id):
|
||||
try:
|
||||
# First try to find domain by ID
|
||||
return self.client.domains.get(domain_name_or_id).id
|
||||
except exceptions.NotFound:
|
||||
# Domain not found by ID, try to find it by name
|
||||
domains = self.client.domains.list(name=domain_name_or_id)
|
||||
if domains:
|
||||
return domains[0].id
|
||||
# Domain not found by name, raise original NotFound exception
|
||||
raise
|
||||
|
||||
@staticmethod
|
||||
def _wrap_v3_project(project):
|
||||
return Project(id=project.id, name=project.name,
|
||||
domain_id=project.domain_id)
|
||||
|
||||
@staticmethod
|
||||
def _wrap_v3_user(user):
|
||||
# When user has default_project_id that is None user.default_project_id
|
||||
# will raise AttributeError
|
||||
project_id = getattr(user, 'default_project_id', None)
|
||||
return User(id=user.id, name=user.name, project_id=project_id,
|
||||
domain_id=user.domain_id)
|
||||
|
||||
def create_project(self, project_name, domain_name='Default'):
|
||||
domain_id = self._get_domain_id(domain_name)
|
||||
project = self.client.projects.create(
|
||||
name=project_name, domain=domain_id)
|
||||
return KeystoneV3Wrapper._wrap_v3_project(project)
|
||||
|
||||
def delete_project(self, project_id):
|
||||
self.client.projects.delete(project_id)
|
||||
|
||||
def create_user(self, username, password, email=None, project_id=None,
|
||||
domain_name='Default'):
|
||||
domain_id = self._get_domain_id(domain_name)
|
||||
client = self.client
|
||||
|
||||
# Create user
|
||||
user = client.users.create(name=username, password=password,
|
||||
email=email, default_project=project_id,
|
||||
domain=domain_id)
|
||||
|
||||
# Grant member role to user in project or domain
|
||||
# TODO(Anton Frolov): replace hard-coded 'Member' role with role name
|
||||
# gained via deployment
|
||||
member_role = client.roles.list(name='Member')[0].id
|
||||
client.roles.grant(member_role, user=user.id, project=project_id)
|
||||
|
||||
return KeystoneV3Wrapper._wrap_v3_user(user)
|
||||
|
||||
def delete_user(self, user_id):
|
||||
self.client.users.delete(user_id)
|
||||
|
||||
def list_users(self):
|
||||
return map(KeystoneV3Wrapper._wrap_v3_user, self.client.users.list())
|
||||
|
||||
def list_projects(self):
|
||||
return map(KeystoneV3Wrapper._wrap_v3_project,
|
||||
self.client.projects.list())
|
||||
|
||||
|
||||
def wrap(client):
|
||||
"""Returns keystone wrapper based on keystone client version."""
|
||||
|
||||
if client.version == 'v2.0':
|
||||
return KeystoneV2Wrapper(client)
|
||||
elif client.version == 'v3':
|
||||
return KeystoneV3Wrapper(client)
|
||||
else:
|
||||
raise NotImplemented(
|
||||
'Wrapper for version %s is not implemented.' % client.version)
|
@ -181,8 +181,8 @@ class DeploymentCommands(object):
|
||||
client = clients.verified_keystone()
|
||||
print("keystone endpoints are valid and following "
|
||||
"services are available:")
|
||||
for service in client.service_catalog.get_data():
|
||||
data = [service['name'], service['type'], 'Available']
|
||||
for service in client.services.list():
|
||||
data = [service.name, service.type, 'Available']
|
||||
table_rows.append(utils.Struct(**dict(zip(headers, data))))
|
||||
except exceptions.InvalidArgumentsException:
|
||||
data = ['keystone', 'identity', 'Error']
|
||||
|
@ -36,6 +36,22 @@ class ExistingCloud(engine.EngineFactory):
|
||||
}
|
||||
}
|
||||
|
||||
Or using keystone v3 API endpoint:
|
||||
|
||||
{
|
||||
"type": "ExistingCloud",
|
||||
"endpoint": {
|
||||
"auth_url": "http://localhost:5000/v3/",
|
||||
"username": "engineer1",
|
||||
"user_domain_name": "qa",
|
||||
"project_name": "qa_admin_project",
|
||||
"project_domain_name": "qa",
|
||||
"password": "password",
|
||||
"region_name": "RegionOne",
|
||||
"use_public_urls": False,
|
||||
"admin_port": 35357,
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
CONFIG_SCHEMA = {
|
||||
@ -48,17 +64,34 @@ class ExistingCloud(engine.EngineFactory):
|
||||
'auth_url': {'type': 'string'},
|
||||
'username': {'type': 'string'},
|
||||
'password': {'type': 'string'},
|
||||
'tenant_name': {'type': 'string'},
|
||||
'region_name': {'type': 'string'},
|
||||
'use_public_urls': {'type': 'boolean'},
|
||||
'admin_port': {
|
||||
'type': 'integer',
|
||||
'minimum': 2,
|
||||
'maximum': 65535
|
||||
}
|
||||
},
|
||||
},
|
||||
'required': ['auth_url', 'username', 'password',
|
||||
'tenant_name'],
|
||||
'oneOf': [
|
||||
{
|
||||
# v2.0 authentication
|
||||
'properties': {
|
||||
'tenant_name': {'type': 'string'},
|
||||
},
|
||||
'required': ['auth_url', 'username', 'password',
|
||||
'tenant_name'],
|
||||
},
|
||||
{
|
||||
# Authentication in project scope
|
||||
'properties': {
|
||||
'user_domain_name': {'type': 'string'},
|
||||
'project_name': {'type': 'string'},
|
||||
'project_domain_name': {'type': 'string'},
|
||||
},
|
||||
'required': ['auth_url', 'username', 'password',
|
||||
'project_name'],
|
||||
},
|
||||
]
|
||||
},
|
||||
},
|
||||
'required': ['type', 'endpoint'],
|
||||
@ -66,16 +99,23 @@ class ExistingCloud(engine.EngineFactory):
|
||||
|
||||
def deploy(self):
|
||||
endpoint_dict = self.deployment['config']['endpoint']
|
||||
admin_endpoint = objects.Endpoint(endpoint_dict['auth_url'],
|
||||
endpoint_dict['username'],
|
||||
endpoint_dict['password'],
|
||||
endpoint_dict['tenant_name'],
|
||||
consts.EndpointPermission.ADMIN,
|
||||
endpoint_dict.get('region_name'),
|
||||
endpoint_dict.get('use_public_urls',
|
||||
True),
|
||||
endpoint_dict.get('admin_port',
|
||||
35357))
|
||||
project_name = endpoint_dict.get('project_name',
|
||||
endpoint_dict.get('tenant_name'))
|
||||
|
||||
admin_endpoint = objects.Endpoint(
|
||||
endpoint_dict['auth_url'], endpoint_dict['username'],
|
||||
endpoint_dict['password'],
|
||||
tenant_name=project_name,
|
||||
permission=consts.EndpointPermission.ADMIN,
|
||||
region_name=endpoint_dict.get('region_name'),
|
||||
use_public_urls=endpoint_dict.get('use_public_urls', False),
|
||||
admin_port=endpoint_dict.get('admin_port', 35357),
|
||||
domain_name=endpoint_dict.get('domain_name'),
|
||||
user_domain_name=endpoint_dict.get('user_domain_name',
|
||||
'Default'),
|
||||
project_domain_name=endpoint_dict.get('project_domain_name',
|
||||
'Default')
|
||||
)
|
||||
return [admin_endpoint]
|
||||
|
||||
def cleanup(self):
|
||||
|
@ -18,9 +18,11 @@ from rally import consts
|
||||
|
||||
class Endpoint(object):
|
||||
|
||||
def __init__(self, auth_url, username, password, tenant_name,
|
||||
def __init__(self, auth_url, username, password, tenant_name=None,
|
||||
permission=consts.EndpointPermission.USER,
|
||||
region_name=None, use_public_urls=False, admin_port=35357):
|
||||
region_name=None, use_public_urls=False, admin_port=35357,
|
||||
domain_name=None, user_domain_name='Default',
|
||||
project_domain_name='Default'):
|
||||
self.auth_url = auth_url
|
||||
self.username = username
|
||||
self.password = password
|
||||
@ -29,13 +31,19 @@ class Endpoint(object):
|
||||
self.region_name = region_name
|
||||
self.use_public_urls = use_public_urls
|
||||
self.admin_port = admin_port
|
||||
self.domain_name = domain_name
|
||||
self.user_domain_name = user_domain_name
|
||||
self.project_domain_name = project_domain_name
|
||||
|
||||
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,
|
||||
"use_public_urls": self.use_public_urls,
|
||||
"admin_port": self.admin_port}
|
||||
"admin_port": self.admin_port,
|
||||
"domain_name": self.domain_name,
|
||||
"user_domain_name": self.user_domain_name,
|
||||
"project_domain_name": self.project_domain_name}
|
||||
if include_permission:
|
||||
dct["permission"] = self.permission
|
||||
return dct
|
||||
|
@ -20,8 +20,10 @@ from cinderclient import client as cinder
|
||||
import glanceclient as glance
|
||||
from heatclient import client as heat
|
||||
from ironicclient import client as ironic
|
||||
from keystoneclient import discover as keystone_discover
|
||||
from keystoneclient import exceptions as keystone_exceptions
|
||||
from keystoneclient.v2_0 import client as keystone
|
||||
from keystoneclient.v2_0 import client as keystone_v2
|
||||
from keystoneclient.v3 import client as keystone_v3
|
||||
from neutronclient.neutron import client as neutron
|
||||
from novaclient import client as nova
|
||||
from oslo.config import cfg
|
||||
@ -60,6 +62,18 @@ def cached(func):
|
||||
return wrapper
|
||||
|
||||
|
||||
def create_keystone_client(args):
|
||||
discover = keystone_discover.Discover(**args)
|
||||
for version_data in discover.version_data():
|
||||
version = version_data['version']
|
||||
if version[0] <= 2:
|
||||
return keystone_v2.Client(**args)
|
||||
elif version[0] == 3:
|
||||
return keystone_v3.Client(**args)
|
||||
raise exceptions.RallyException(
|
||||
'Failed to discover keystone version for url %(auth_url)s.', **args)
|
||||
|
||||
|
||||
class Clients(object):
|
||||
"""This class simplify and unify work with openstack python clients."""
|
||||
|
||||
@ -90,7 +104,7 @@ class Clients(object):
|
||||
)
|
||||
else:
|
||||
kw["endpoint"] = kw["auth_url"]
|
||||
client = keystone.Client(**kw)
|
||||
client = create_keystone_client(kw)
|
||||
client.authenticate()
|
||||
return client
|
||||
|
||||
@ -102,8 +116,7 @@ class Clients(object):
|
||||
try:
|
||||
# Ensure that user is admin
|
||||
client = self.keystone()
|
||||
roles = client.auth_ref['user']['roles']
|
||||
if not any('admin' == role['name'] for role in roles):
|
||||
if 'admin' not in client.auth_ref.role_names:
|
||||
raise exceptions.InvalidAdminException(
|
||||
username=self.endpoint.username)
|
||||
except keystone_exceptions.Unauthorized:
|
||||
@ -116,28 +129,29 @@ class Clients(object):
|
||||
@cached
|
||||
def nova(self, version='2'):
|
||||
"""Return nova client."""
|
||||
kc = self.keystone()
|
||||
compute_api_url = kc.service_catalog.url_for(
|
||||
service_type='compute', endpoint_type='public',
|
||||
region_name=self.endpoint.region_name)
|
||||
client = nova.Client(version,
|
||||
self.endpoint.username,
|
||||
self.endpoint.password,
|
||||
self.endpoint.tenant_name,
|
||||
auth_url=self.endpoint.auth_url,
|
||||
region_name=self.endpoint.region_name,
|
||||
service_type='compute',
|
||||
auth_token=kc.auth_token,
|
||||
http_log_debug=CONF.debug,
|
||||
timeout=CONF.openstack_client_http_timeout,
|
||||
insecure=CONF.https_insecure,
|
||||
cacert=CONF.https_cacert)
|
||||
client.set_management_url(compute_api_url)
|
||||
return client
|
||||
|
||||
@cached
|
||||
def neutron(self, version='2.0'):
|
||||
"""Return neutron client."""
|
||||
kc = self.keystone()
|
||||
network_api_url = kc.service_catalog.url_for(
|
||||
service_type='network', endpoint_type='public',
|
||||
region_name=self.endpoint.region_name)
|
||||
client = neutron.Client(version,
|
||||
username=self.endpoint.username,
|
||||
password=self.endpoint.password,
|
||||
tenant_name=self.endpoint.tenant_name,
|
||||
auth_url=self.endpoint.auth_url,
|
||||
region_name=self.endpoint.region_name,
|
||||
token=kc.auth_token,
|
||||
endpoint_url=network_api_url,
|
||||
timeout=CONF.openstack_client_http_timeout,
|
||||
insecure=CONF.https_insecure,
|
||||
cacert=CONF.https_cacert)
|
||||
@ -147,11 +161,12 @@ class Clients(object):
|
||||
def glance(self, version='1'):
|
||||
"""Return glance client."""
|
||||
kc = self.keystone()
|
||||
endpoint = kc.service_catalog.get_endpoints()['image'][0]
|
||||
image_api_url = kc.service_catalog.url_for(
|
||||
service_type='image', endpoint_type='public',
|
||||
region_name=self.endpoint.region_name)
|
||||
client = glance.Client(version,
|
||||
endpoint=endpoint['publicURL'],
|
||||
endpoint=image_api_url,
|
||||
token=kc.auth_token,
|
||||
region_name=self.endpoint.region_name,
|
||||
timeout=CONF.openstack_client_http_timeout,
|
||||
insecure=CONF.https_insecure,
|
||||
cacert=CONF.https_cacert)
|
||||
@ -161,12 +176,12 @@ class Clients(object):
|
||||
def heat(self, version='1'):
|
||||
"""Return heat client."""
|
||||
kc = self.keystone()
|
||||
endpoint = kc.service_catalog.get_endpoints()['orchestration'][0]
|
||||
|
||||
orchestration_api_url = kc.service_catalog.url_for(
|
||||
service_type='orchestration', endpoint_type='public',
|
||||
region_name=self.endpoint.region_name)
|
||||
client = heat.Client(version,
|
||||
endpoint=endpoint['publicURL'],
|
||||
endpoint=orchestration_api_url,
|
||||
token=kc.auth_token,
|
||||
region_name=self.endpoint.region_name,
|
||||
timeout=CONF.openstack_client_http_timeout,
|
||||
insecure=CONF.https_insecure,
|
||||
cacert=CONF.https_cacert)
|
||||
@ -175,33 +190,34 @@ class Clients(object):
|
||||
@cached
|
||||
def cinder(self, version='1'):
|
||||
"""Return cinder client."""
|
||||
client = cinder.Client(version,
|
||||
self.endpoint.username,
|
||||
self.endpoint.password,
|
||||
self.endpoint.tenant_name,
|
||||
auth_url=self.endpoint.auth_url,
|
||||
region_name=self.endpoint.region_name,
|
||||
service_type='volume',
|
||||
client = cinder.Client(version, None, None,
|
||||
http_log_debug=CONF.debug,
|
||||
timeout=CONF.openstack_client_http_timeout,
|
||||
insecure=CONF.https_insecure,
|
||||
cacert=CONF.https_cacert)
|
||||
kc = self.keystone()
|
||||
volume_api_url = kc.service_catalog.url_for(
|
||||
service_type='volume', endpoint_type='public',
|
||||
region_name=self.endpoint.region_name)
|
||||
client.client.management_url = volume_api_url
|
||||
client.client.auth_token = kc.auth_token
|
||||
return client
|
||||
|
||||
@cached
|
||||
def ceilometer(self, version='2'):
|
||||
"""Return ceilometer client."""
|
||||
kc = self.keystone()
|
||||
endpoint = kc.service_catalog.get_endpoints()['metering'][0]
|
||||
metering_api_url = kc.service_catalog.url_for(
|
||||
service_type='metering', endpoint_type='public',
|
||||
region_name=self.endpoint.region_name)
|
||||
auth_token = kc.auth_token
|
||||
if not hasattr(auth_token, '__call__'):
|
||||
# python-ceilometerclient requires auth_token to be a callable
|
||||
auth_token = lambda: kc.auth_token
|
||||
|
||||
client = ceilometer.Client(version,
|
||||
endpoint=endpoint['publicURL'],
|
||||
endpoint=metering_api_url,
|
||||
token=auth_token,
|
||||
region_name=self.endpoint.region_name,
|
||||
timeout=CONF.openstack_client_http_timeout,
|
||||
insecure=CONF.https_insecure,
|
||||
cacert=CONF.https_cacert)
|
||||
@ -210,14 +226,16 @@ class Clients(object):
|
||||
@cached
|
||||
def ironic(self, version='1.0'):
|
||||
"""Return Ironic client."""
|
||||
client = ironic.Client(version,
|
||||
username=self.endpoint.username,
|
||||
password=self.endpoint.password,
|
||||
tenant_name=self.endpoint.tenant_name,
|
||||
auth_url=self.endpoint.auth_url,
|
||||
timeout=CONF.openstack_client_http_timeout,
|
||||
insecure=CONF.https_insecure,
|
||||
cacert=CONF.https_cacert)
|
||||
kc = self.keystone()
|
||||
baremetal_api_url = kc.service_catalog.url_for(
|
||||
service_type='baremetal', endpoint_type='public',
|
||||
region_name=self.endpoint.region_name)
|
||||
client = ironic.get_client(version,
|
||||
os_auth_token=kc.auth_token,
|
||||
ironic_url=baremetal_api_url,
|
||||
timeout=CONF.openstack_client_http_timeout,
|
||||
insecure=CONF.https_insecure,
|
||||
cacert=CONF.https_cacert)
|
||||
return client
|
||||
|
||||
@cached
|
||||
|
@ -19,7 +19,6 @@ import mock
|
||||
|
||||
from rally.benchmark.context import users
|
||||
from rally.benchmark import utils
|
||||
from tests import fakes
|
||||
from tests import test
|
||||
|
||||
|
||||
@ -49,12 +48,26 @@ class UserGeneratorTestCase(test.TestCase):
|
||||
"task": mock.MagicMock()
|
||||
}
|
||||
|
||||
@mock.patch("rally.benchmark.context.users.osclients")
|
||||
def test_create_tenant_users(self, mock_osclients):
|
||||
users_num = 5
|
||||
args = (mock.MagicMock(), users_num,
|
||||
'ad325aec-f7b4-4a62-832a-bb718e465bb7', 1)
|
||||
def setUp(self):
|
||||
super(UserGeneratorTestCase, self).setUp()
|
||||
self.osclients_patcher = mock.patch(
|
||||
"rally.benchmark.context.users.osclients")
|
||||
self.osclients = self.osclients_patcher.start()
|
||||
|
||||
self.keystone_wrapper_patcher = mock.patch(
|
||||
"rally.benchmark.context.users.keystone")
|
||||
self.keystone_wrapper = self.keystone_wrapper_patcher.start()
|
||||
self.wrapped_keystone = self.keystone_wrapper.wrap.return_value
|
||||
|
||||
def tearDown(self):
|
||||
self.keystone_wrapper_patcher.stop()
|
||||
self.osclients_patcher.stop()
|
||||
super(UserGeneratorTestCase, self).tearDown()
|
||||
|
||||
def test_create_tenant_users(self):
|
||||
users_num = 5
|
||||
args = (mock.MagicMock(), users_num, 'default', 'default',
|
||||
'ad325aec-f7b4-4a62-832a-bb718e465bb7', 1)
|
||||
result = users.UserGenerator._create_tenant_users(args)
|
||||
|
||||
self.assertEqual(len(result), 2)
|
||||
@ -66,55 +79,55 @@ class UserGeneratorTestCase(test.TestCase):
|
||||
self.assertIn("id", user)
|
||||
self.assertIn("endpoint", user)
|
||||
|
||||
@mock.patch("rally.benchmark.context.users.osclients")
|
||||
def test_delete_tenants(self, mock_osclients):
|
||||
def test_delete_tenants(self):
|
||||
tenant1 = mock.MagicMock()
|
||||
tenant2 = mock.MagicMock()
|
||||
args = (mock.MagicMock(), [tenant1, tenant2])
|
||||
users.UserGenerator._delete_tenants(args)
|
||||
mock_osclients.Clients().keystone().tenants.delete.assert_has_calls([
|
||||
self.keystone_wrapper.wrap.assert_called_once()
|
||||
self.wrapped_keystone.delete_project.assert_has_calls([
|
||||
mock.call(tenant1["id"]),
|
||||
mock.call(tenant2["id"])])
|
||||
|
||||
@mock.patch("rally.benchmark.context.users.osclients")
|
||||
def test_delete_users(self, mock_osclients):
|
||||
def test_delete_users(self):
|
||||
user1 = mock.MagicMock()
|
||||
user2 = mock.MagicMock()
|
||||
args = (mock.MagicMock(), [user1, user2])
|
||||
users.UserGenerator._delete_users(args)
|
||||
mock_osclients.Clients().keystone().users.delete.assert_has_calls([
|
||||
self.wrapped_keystone.delete_user.assert_has_calls([
|
||||
mock.call(user1["id"]),
|
||||
mock.call(user2["id"])])
|
||||
|
||||
@mock.patch("rally.benchmark.context.users.osclients")
|
||||
def test_setup_and_cleanup(self, mock_osclients):
|
||||
fc = fakes.FakeClients()
|
||||
mock_osclients.Clients.return_value = fc
|
||||
|
||||
def test_setup_and_cleanup(self):
|
||||
with users.UserGenerator(self.context) as ctx:
|
||||
self.assertEqual(len(fc.keystone().users.list()), 0)
|
||||
self.assertEqual(len(fc.keystone().tenants.list()), 0)
|
||||
self.assertEqual(self.wrapped_keystone.create_user.call_count, 0)
|
||||
self.assertEqual(self.wrapped_keystone.create_project.call_count,
|
||||
0)
|
||||
|
||||
ctx.setup()
|
||||
|
||||
self.assertEqual(len(ctx.context["users"]),
|
||||
self.users_num)
|
||||
self.assertEqual(len(fc.keystone().users.list()),
|
||||
self.assertEqual(self.wrapped_keystone.create_user.call_count,
|
||||
self.users_num)
|
||||
self.assertEqual(len(ctx.context["tenants"]),
|
||||
self.tenants_num)
|
||||
self.assertEqual(len(fc.keystone().tenants.list()),
|
||||
self.assertEqual(self.wrapped_keystone.create_project.call_count,
|
||||
self.tenants_num)
|
||||
|
||||
# Assert nothing is deleted yet
|
||||
self.assertEqual(self.wrapped_keystone.delete_user.call_count,
|
||||
0)
|
||||
self.assertEqual(self.wrapped_keystone.delete_project.call_count,
|
||||
0)
|
||||
|
||||
# Cleanup (called by content manager)
|
||||
self.assertEqual(len(fc.keystone().users.list()), 0)
|
||||
self.assertEqual(len(fc.keystone().tenants.list()), 0)
|
||||
|
||||
@mock.patch("rally.benchmark.context.users.osclients")
|
||||
def test_users_and_tenants_in_context(self, mock_osclients):
|
||||
fc = fakes.FakeClients()
|
||||
mock_osclients.Clients.return_value = fc
|
||||
self.assertEqual(self.wrapped_keystone.delete_user.call_count,
|
||||
self.users_num)
|
||||
self.assertEqual(self.wrapped_keystone.delete_project.call_count,
|
||||
self.tenants_num)
|
||||
|
||||
def test_users_and_tenants_in_context(self):
|
||||
task = {"uuid": "abcdef"}
|
||||
|
||||
config = {
|
||||
@ -129,30 +142,32 @@ class UserGeneratorTestCase(test.TestCase):
|
||||
"task": task
|
||||
}
|
||||
|
||||
user_list = [mock.MagicMock(id='id_%d' % i)
|
||||
for i in range(self.users_num)]
|
||||
self.wrapped_keystone.create_user.side_effect = user_list
|
||||
|
||||
with users.UserGenerator(config) as ctx:
|
||||
ctx.setup()
|
||||
|
||||
tenants = []
|
||||
for i, t in enumerate(fc.keystone().tenants.list()):
|
||||
create_tenant_calls = []
|
||||
for i, t in enumerate(ctx.context["tenants"]):
|
||||
pattern = users.UserGenerator.PATTERN_TENANT
|
||||
tenants.append({
|
||||
"id": t.id,
|
||||
"name": pattern % {"task_id": task["uuid"], "iter": i}
|
||||
})
|
||||
create_tenant_calls.append(
|
||||
mock.call(pattern % {"task_id": task["uuid"], "iter": i},
|
||||
ctx.config["project_domain"]))
|
||||
|
||||
self.assertEqual(ctx.context["tenants"], tenants)
|
||||
self.wrapped_keystone.create_project.assert_has_calls(
|
||||
create_tenant_calls, any_order=True)
|
||||
|
||||
for user in ctx.context["users"]:
|
||||
self.assertEqual(set(["id", "endpoint", "tenant_id"]),
|
||||
set(user.keys()))
|
||||
|
||||
tenants_ids = []
|
||||
for t in tenants:
|
||||
for t in ctx.context["tenants"]:
|
||||
tenants_ids.extend([t["id"], t["id"]])
|
||||
|
||||
users_ids = [user.id for user in fc.keystone().users.list()]
|
||||
|
||||
for (user, tenant_id, user_id) in zip(ctx.context["users"],
|
||||
tenants_ids, users_ids):
|
||||
self.assertEqual(user["id"], user_id)
|
||||
for (user, tenant_id, orig_user) in zip(ctx.context["users"],
|
||||
tenants_ids, user_list):
|
||||
self.assertEqual(user["id"], orig_user.id)
|
||||
self.assertEqual(user["tenant_id"], tenant_id)
|
||||
|
0
tests/benchmark/wrappers/__init__.py
Normal file
0
tests/benchmark/wrappers/__init__.py
Normal file
204
tests/benchmark/wrappers/test_keystone.py
Normal file
204
tests/benchmark/wrappers/test_keystone.py
Normal file
@ -0,0 +1,204 @@
|
||||
# Copyright 2014: 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 keystoneclient import exceptions
|
||||
import mock
|
||||
|
||||
from rally.benchmark.wrappers import keystone
|
||||
from tests import test
|
||||
|
||||
|
||||
class KeystoneWrapperTestBase(object):
|
||||
def test_list_services(self):
|
||||
service = mock.MagicMock()
|
||||
service.id = 'fake_id'
|
||||
service.name = 'Foobar'
|
||||
service.extra_field = 'extra_field'
|
||||
self.client.services.list.return_value = [service]
|
||||
result = self.wrapped_client.list_services()
|
||||
self.assertEqual([('fake_id', 'Foobar')], result)
|
||||
self.assertEqual('fake_id', result[0].id)
|
||||
self.assertEqual('Foobar', result[0].name)
|
||||
self.assertFalse(hasattr(result[0], 'extra_field'))
|
||||
|
||||
def test_delete_service(self):
|
||||
self.wrapped_client.delete_service('fake_id')
|
||||
self.client.services.delete.assert_called_once_with('fake_id')
|
||||
|
||||
def test_list_roles(self):
|
||||
role = mock.MagicMock()
|
||||
role.id = 'fake_id'
|
||||
role.name = 'Foobar'
|
||||
role.extra_field = 'extra_field'
|
||||
self.client.roles.list.return_value = [role]
|
||||
result = self.wrapped_client.list_roles()
|
||||
self.assertEqual([('fake_id', 'Foobar')], result)
|
||||
self.assertEqual('fake_id', result[0].id)
|
||||
self.assertEqual('Foobar', result[0].name)
|
||||
self.assertFalse(hasattr(result[0], 'extra_field'))
|
||||
|
||||
def test_delete_role(self):
|
||||
self.wrapped_client.delete_role('fake_id')
|
||||
self.client.roles.delete.assert_called_once_with('fake_id')
|
||||
|
||||
|
||||
class KeystoneV2WrapperTestCase(test.TestCase, KeystoneWrapperTestBase):
|
||||
def setUp(self):
|
||||
super(KeystoneV2WrapperTestCase, self).setUp()
|
||||
self.client = mock.MagicMock()
|
||||
self.client.version = 'v2.0'
|
||||
self.wrapped_client = keystone.wrap(self.client)
|
||||
|
||||
def test_create_project(self):
|
||||
self.wrapped_client.create_project('Foobar')
|
||||
self.client.tenants.create.assert_called_once_with('Foobar')
|
||||
|
||||
def test_create_project_in_non_default_domain_fail(self):
|
||||
self.assertRaises(
|
||||
NotImplementedError, self.wrapped_client.create_project,
|
||||
'Foobar', 'non-default-domain')
|
||||
|
||||
def test_delete_project(self):
|
||||
self.wrapped_client.delete_project('fake_id')
|
||||
self.client.tenants.delete.assert_called_once_with('fake_id')
|
||||
|
||||
def test_list_projects(self):
|
||||
tenant = mock.MagicMock()
|
||||
tenant.id = 'fake_id'
|
||||
tenant.name = 'Foobar'
|
||||
tenant.extra_field = 'extra_field'
|
||||
self.client.tenants.list.return_value = [tenant]
|
||||
result = self.wrapped_client.list_projects()
|
||||
self.assertEqual([('fake_id', 'Foobar', 'default')], result)
|
||||
self.assertEqual('fake_id', result[0].id)
|
||||
self.assertEqual('Foobar', result[0].name)
|
||||
self.assertEqual('default', result[0].domain_id)
|
||||
self.assertFalse(hasattr(result[0], 'extra_field'))
|
||||
|
||||
def test_create_user(self):
|
||||
self.wrapped_client.create_user('foo', 'bar', email='foo@bar.com',
|
||||
project_id='tenant_id',
|
||||
domain_name='default')
|
||||
self.client.users.create.assert_called_once_with(
|
||||
'foo', 'bar', 'foo@bar.com', 'tenant_id')
|
||||
|
||||
def test_create_user_in_non_default_domain_fail(self):
|
||||
self.assertRaises(
|
||||
NotImplementedError, self.wrapped_client.create_user,
|
||||
'foo', 'bar', email='foo@bar.com', project_id='tenant_id',
|
||||
domain_name='non-default-domain')
|
||||
|
||||
def test_delete_user(self):
|
||||
self.wrapped_client.delete_user('fake_id')
|
||||
self.client.users.delete.assert_called_once_with('fake_id')
|
||||
|
||||
def test_list_users(self):
|
||||
user = mock.MagicMock()
|
||||
user.id = 'fake_id'
|
||||
user.name = 'foo'
|
||||
user.tenantId = 'tenant_id'
|
||||
user.extra_field = 'extra_field'
|
||||
self.client.users.list.return_value = [user]
|
||||
result = self.wrapped_client.list_users()
|
||||
self.assertEqual([('fake_id', 'foo', 'tenant_id', 'default')], result)
|
||||
self.assertEqual('fake_id', result[0].id)
|
||||
self.assertEqual('foo', result[0].name)
|
||||
self.assertEqual('tenant_id', result[0].project_id)
|
||||
self.assertEqual('default', result[0].domain_id)
|
||||
self.assertFalse(hasattr(result[0], 'extra_field'))
|
||||
|
||||
|
||||
class KeystoneV3WrapperTestCase(test.TestCase, KeystoneWrapperTestBase):
|
||||
def setUp(self):
|
||||
super(KeystoneV3WrapperTestCase, self).setUp()
|
||||
self.client = mock.MagicMock()
|
||||
self.client.version = 'v3'
|
||||
self.wrapped_client = keystone.wrap(self.client)
|
||||
self.client.domains.get.side_effect = exceptions.NotFound
|
||||
self.client.domains.list.return_value = [
|
||||
mock.MagicMock(id='domain_id')]
|
||||
|
||||
def test_create_project(self):
|
||||
self.wrapped_client.create_project('Foobar', 'domain')
|
||||
self.client.projects.create.assert_called_once_with(
|
||||
name='Foobar', domain='domain_id')
|
||||
|
||||
def test_create_project_with_non_existing_domain_fail(self):
|
||||
self.client.domains.list.return_value = []
|
||||
self.assertRaises(exceptions.NotFound,
|
||||
self.wrapped_client.create_project,
|
||||
'Foobar', 'non-existing-domain')
|
||||
|
||||
def test_delete_project(self):
|
||||
self.wrapped_client.delete_project('fake_id')
|
||||
self.client.projects.delete.assert_called_once_with('fake_id')
|
||||
|
||||
def test_list_projects(self):
|
||||
project = mock.MagicMock()
|
||||
project.id = 'fake_id'
|
||||
project.name = 'Foobar'
|
||||
project.domain_id = 'domain_id'
|
||||
project.extra_field = 'extra_field'
|
||||
self.client.projects.list.return_value = [project]
|
||||
result = self.wrapped_client.list_projects()
|
||||
self.assertEqual([('fake_id', 'Foobar', 'domain_id')], result)
|
||||
self.assertEqual('fake_id', result[0].id)
|
||||
self.assertEqual('Foobar', result[0].name)
|
||||
self.assertEqual('domain_id', result[0].domain_id)
|
||||
self.assertFalse(hasattr(result[0], 'extra_field'))
|
||||
|
||||
def test_create_user(self):
|
||||
self.client.roles.list.return_value = [
|
||||
mock.MagicMock(id='fake_role_id')]
|
||||
self.client.users.create.return_value = mock.MagicMock(
|
||||
id='fake_user_id')
|
||||
|
||||
self.wrapped_client.create_user(
|
||||
'foo', 'bar', email='foo@bar.com',
|
||||
project_id='project_id', domain_name='domain')
|
||||
self.client.users.create.assert_called_once_with(
|
||||
name='foo', password='bar',
|
||||
email='foo@bar.com', default_project='project_id',
|
||||
domain='domain_id')
|
||||
self.client.roles.grant.assert_called_once_with(
|
||||
'fake_role_id', user='fake_user_id', project='project_id')
|
||||
|
||||
def test_create_user_with_non_existing_domain_fail(self):
|
||||
self.client.domains.list.return_value = []
|
||||
self.assertRaises(exceptions.NotFound,
|
||||
self.wrapped_client.create_user, 'foo', 'bar',
|
||||
email='foo@bar.com', project_id='project_id',
|
||||
domain_name='non-existing-domain')
|
||||
|
||||
def test_delete_user(self):
|
||||
self.wrapped_client.delete_user('fake_id')
|
||||
self.client.users.delete.assert_called_once_with('fake_id')
|
||||
|
||||
def test_list_users(self):
|
||||
user = mock.MagicMock()
|
||||
user.id = 'fake_id'
|
||||
user.name = 'foo'
|
||||
user.default_project_id = 'project_id'
|
||||
user.domain_id = 'domain_id'
|
||||
user.extra_field = 'extra_field'
|
||||
self.client.users.list.return_value = [user]
|
||||
result = self.wrapped_client.list_users()
|
||||
self.assertEqual(
|
||||
[('fake_id', 'foo', 'project_id', 'domain_id')], result)
|
||||
self.assertEqual('fake_id', result[0].id)
|
||||
self.assertEqual('foo', result[0].name)
|
||||
self.assertEqual('project_id', result[0].project_id)
|
||||
self.assertEqual('domain_id', result[0].domain_id)
|
||||
self.assertFalse(hasattr(result[0], 'extra_field'))
|
@ -33,8 +33,11 @@ class TestExistingCloud(test.TestCase):
|
||||
'password': 'myadminpass',
|
||||
'tenant_name': 'demo',
|
||||
'region_name': 'RegionOne',
|
||||
'use_public_urls': True,
|
||||
'admin_port': 35357
|
||||
'use_public_urls': False,
|
||||
'admin_port': 35357,
|
||||
'domain_name': None,
|
||||
'project_domain_name': 'Default',
|
||||
'user_domain_name': 'Default',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -88,9 +88,9 @@ class OpenStackProviderTestCase(test.TestCase):
|
||||
self.assertEqual('nova', os_provider.nova)
|
||||
self.assertEqual('glance', os_provider.glance)
|
||||
|
||||
@mock.patch('rally.osclients.Clients.glance')
|
||||
def test_init_no_glance(self, mock_glance):
|
||||
mock_glance.side_effect = KeyError('image')
|
||||
@mock.patch('rally.osclients.Clients')
|
||||
def test_init_no_glance(self, mock_clients):
|
||||
mock_clients.return_value.glance.side_effect = KeyError('image')
|
||||
cfg = self._get_valid_config()
|
||||
provider = OSProvider(mock.MagicMock(), cfg)
|
||||
self.assertEqual(provider.glance, None)
|
||||
|
@ -546,6 +546,9 @@ class FakeServiceCatalog(object):
|
||||
return {'image': [{'publicURL': 'http://fake.to'}],
|
||||
'metering': [{'publicURL': 'http://fake.to'}]}
|
||||
|
||||
def url_for(self, **kwargs):
|
||||
return 'http://fake.to'
|
||||
|
||||
|
||||
class FakeGlanceClient(object):
|
||||
|
||||
@ -583,6 +586,7 @@ class FakeNovaClient(object):
|
||||
self.security_groups = FakeSecurityGroupManager(
|
||||
rule_manager=self.security_group_rules)
|
||||
self.quotas = FakeNovaQuotasManager()
|
||||
self.set_management_url = mock.MagicMock()
|
||||
|
||||
|
||||
class FakeKeystoneClient(object):
|
||||
@ -598,7 +602,11 @@ class FakeKeystoneClient(object):
|
||||
self.auth_tenant_id = generate_uuid()
|
||||
self.service_catalog = FakeServiceCatalog()
|
||||
self.region_name = 'RegionOne'
|
||||
self.auth_ref = {'user': {'roles': [{'name': 'admin'}]}}
|
||||
self.auth_ref = mock.Mock()
|
||||
self.auth_ref.role_names = ['admin']
|
||||
self.version = 'v2.0'
|
||||
self.session = mock.Mock()
|
||||
self.authenticate = mock.MagicMock()
|
||||
|
||||
def authenticate(self):
|
||||
return True
|
||||
|
@ -25,4 +25,7 @@ class EndpointTestCase(test.TestCase):
|
||||
{"auth_url": "url", "username": "user",
|
||||
"password": "pwd", "tenant_name": "tenant",
|
||||
"region_name": None, "permission": "admin",
|
||||
"use_public_urls": False, 'admin_port': 35357})
|
||||
"domain_name": None, "use_public_urls": False,
|
||||
"project_domain_name": "Default",
|
||||
"user_domain_name": "Default",
|
||||
'admin_port': 35357})
|
||||
|
@ -36,6 +36,9 @@ FAKE_DEPLOY_CONFIG = {
|
||||
'region_name': 'RegionOne',
|
||||
'use_public_urls': False,
|
||||
'admin_port': 35357,
|
||||
'domain_name': None,
|
||||
'project_domain_name': 'Default',
|
||||
'user_domain_name': 'Default',
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -33,24 +33,33 @@ class OSClientsTestCase(test.TestCase):
|
||||
"tenant")
|
||||
self.clients = osclients.Clients(self.endpoint)
|
||||
|
||||
self.fake_keystone = fakes.FakeKeystoneClient()
|
||||
self.fake_keystone.auth_token = mock.MagicMock()
|
||||
self.service_catalog = self.fake_keystone.service_catalog
|
||||
self.service_catalog.url_for = mock.MagicMock()
|
||||
|
||||
keystone_patcher = mock.patch("rally.osclients.create_keystone_client")
|
||||
self.mock_create_keystone_client = keystone_patcher.start()
|
||||
self.addCleanup(keystone_patcher.stop)
|
||||
self.mock_create_keystone_client.return_value = self.fake_keystone
|
||||
|
||||
def tearDown(self):
|
||||
super(OSClientsTestCase, self).tearDown()
|
||||
|
||||
def test_keystone(self):
|
||||
with mock.patch("rally.osclients.keystone") as mock_keystone:
|
||||
fake_keystone = fakes.FakeKeystoneClient()
|
||||
mock_keystone.Client = mock.MagicMock(return_value=fake_keystone)
|
||||
self.assertTrue("keystone" not in self.clients.cache)
|
||||
client = self.clients.keystone()
|
||||
self.assertEqual(client, fake_keystone)
|
||||
endpoint = {"timeout": cfg.CONF.openstack_client_http_timeout,
|
||||
"insecure": False, "cacert": None}
|
||||
kwargs = dict(self.endpoint.to_dict().items() + endpoint.items())
|
||||
mock_keystone.Client.assert_called_once_with(**kwargs)
|
||||
self.assertEqual(self.clients.cache["keystone"], fake_keystone)
|
||||
self.assertTrue("keystone" not in self.clients.cache)
|
||||
client = self.clients.keystone()
|
||||
self.assertEqual(client, self.fake_keystone)
|
||||
endpoint = {"timeout": cfg.CONF.openstack_client_http_timeout,
|
||||
"insecure": False, "cacert": None}
|
||||
kwargs = dict(self.endpoint.to_dict().items() + endpoint.items())
|
||||
self.mock_create_keystone_client.assert_called_once_with(kwargs)
|
||||
self.assertEqual(self.clients.cache["keystone"], self.fake_keystone)
|
||||
|
||||
@mock.patch("rally.osclients.Clients.keystone")
|
||||
def test_verified_keystone_user_not_admin(self, mock_keystone):
|
||||
mock_keystone.return_value = fakes.FakeKeystoneClient()
|
||||
mock_keystone.return_value.auth_ref["user"]["roles"] = [{"name":
|
||||
"notadmin"}]
|
||||
mock_keystone.return_value.auth_ref.role_names = ["notadmin"]
|
||||
self.assertRaises(exceptions.InvalidAdminException,
|
||||
self.clients.verified_keystone)
|
||||
|
||||
@ -75,14 +84,17 @@ class OSClientsTestCase(test.TestCase):
|
||||
self.assertTrue("nova" not in self.clients.cache)
|
||||
client = self.clients.nova()
|
||||
self.assertEqual(client, fake_nova)
|
||||
self.service_catalog.url_for.assert_called_once_with(
|
||||
service_type='compute', endpoint_type='public',
|
||||
region_name=self.endpoint.region_name)
|
||||
mock_nova.Client.assert_called_once_with(
|
||||
"2", self.endpoint.username, self.endpoint.password,
|
||||
self.endpoint.tenant_name, auth_url=self.endpoint.auth_url,
|
||||
region_name=self.endpoint.region_name,
|
||||
service_type="compute",
|
||||
"2",
|
||||
auth_token=self.fake_keystone.auth_token,
|
||||
http_log_debug=False,
|
||||
timeout=cfg.CONF.openstack_client_http_timeout,
|
||||
insecure=False, cacert=None)
|
||||
client.set_management_url.assert_called_once_with(
|
||||
self.service_catalog.url_for.return_value)
|
||||
self.assertEqual(self.clients.cache["nova"], fake_nova)
|
||||
|
||||
@mock.patch("rally.osclients.neutron")
|
||||
@ -93,15 +105,15 @@ class OSClientsTestCase(test.TestCase):
|
||||
client = self.clients.neutron()
|
||||
self.assertEqual(client, fake_neutron)
|
||||
kw = {
|
||||
"username": self.endpoint.username,
|
||||
"password": self.endpoint.password,
|
||||
"tenant_name": self.endpoint.tenant_name,
|
||||
"auth_url": self.endpoint.auth_url,
|
||||
"region_name": self.endpoint.region_name,
|
||||
"token": self.fake_keystone.auth_token,
|
||||
"endpoint_url": self.service_catalog.url_for.return_value,
|
||||
"timeout": cfg.CONF.openstack_client_http_timeout,
|
||||
"insecure": cfg.CONF.https_insecure,
|
||||
"cacert": cfg.CONF.https_cacert
|
||||
}
|
||||
self.service_catalog.url_for.assert_called_once_with(
|
||||
service_type='network', endpoint_type='public',
|
||||
region_name=self.endpoint.region_name)
|
||||
mock_neutron.Client.assert_called_once_with("2.0", **kw)
|
||||
self.assertEqual(self.clients.cache["neutron"], fake_neutron)
|
||||
|
||||
@ -109,36 +121,38 @@ class OSClientsTestCase(test.TestCase):
|
||||
with mock.patch("rally.osclients.glance") as mock_glance:
|
||||
fake_glance = fakes.FakeGlanceClient()
|
||||
mock_glance.Client = mock.MagicMock(return_value=fake_glance)
|
||||
kc = fakes.FakeKeystoneClient()
|
||||
self.clients.keystone = mock.MagicMock(return_value=kc)
|
||||
self.assertTrue("glance" not in self.clients.cache)
|
||||
client = self.clients.glance()
|
||||
self.assertEqual(client, fake_glance)
|
||||
endpoint = kc.service_catalog.get_endpoints()["image"][0]
|
||||
|
||||
kw = {"endpoint": endpoint["publicURL"],
|
||||
"token": kc.auth_token,
|
||||
kw = {"endpoint": self.service_catalog.url_for.return_value,
|
||||
"token": self.fake_keystone.auth_token,
|
||||
"timeout": cfg.CONF.openstack_client_http_timeout,
|
||||
"insecure": False, "cacert": None,
|
||||
"region_name": None}
|
||||
"insecure": False, "cacert": None}
|
||||
self.service_catalog.url_for.assert_called_once_with(
|
||||
service_type='image', endpoint_type='public',
|
||||
region_name=self.endpoint.region_name)
|
||||
mock_glance.Client.assert_called_once_with("1", **kw)
|
||||
self.assertEqual(self.clients.cache["glance"], fake_glance)
|
||||
|
||||
def test_cinder(self):
|
||||
with mock.patch("rally.osclients.cinder") as mock_cinder:
|
||||
fake_cinder = fakes.FakeCinderClient()
|
||||
fake_cinder.client = mock.MagicMock()
|
||||
mock_cinder.Client = mock.MagicMock(return_value=fake_cinder)
|
||||
self.assertTrue("cinder" not in self.clients.cache)
|
||||
client = self.clients.cinder()
|
||||
self.assertEqual(client, fake_cinder)
|
||||
self.service_catalog.url_for.assert_called_once_with(
|
||||
service_type='volume', endpoint_type='public',
|
||||
region_name=self.endpoint.region_name)
|
||||
mock_cinder.Client.assert_called_once_with(
|
||||
"1", self.endpoint.username, self.endpoint.password,
|
||||
self.endpoint.tenant_name, auth_url=self.endpoint.auth_url,
|
||||
region_name=self.endpoint.region_name,
|
||||
service_type="volume",
|
||||
http_log_debug=False,
|
||||
"1", None, None, http_log_debug=False,
|
||||
timeout=cfg.CONF.openstack_client_http_timeout,
|
||||
insecure=False, cacert=None)
|
||||
self.assertEqual(fake_cinder.client.management_url,
|
||||
self.service_catalog.url_for.return_value)
|
||||
self.assertEqual(fake_cinder.client.auth_token,
|
||||
self.fake_keystone.auth_token)
|
||||
self.assertEqual(self.clients.cache["cinder"], fake_cinder)
|
||||
|
||||
def test_ceilometer(self):
|
||||
@ -146,19 +160,16 @@ class OSClientsTestCase(test.TestCase):
|
||||
fake_ceilometer = fakes.FakeCeilometerClient()
|
||||
mock_ceilometer.Client = mock.MagicMock(
|
||||
return_value=fake_ceilometer)
|
||||
kc = fakes.FakeKeystoneClient()
|
||||
self.clients.keystone = mock.MagicMock(return_value=kc)
|
||||
self.assertTrue("ceilometer" not in self.clients.cache)
|
||||
kc.auth_token = mock.MagicMock()
|
||||
client = self.clients.ceilometer()
|
||||
self.assertEqual(client, fake_ceilometer)
|
||||
endpoint = kc.service_catalog.get_endpoints()["metering"][0]
|
||||
|
||||
kw = {"endpoint": endpoint["publicURL"],
|
||||
"token": kc.auth_token,
|
||||
self.service_catalog.url_for.assert_called_once_with(
|
||||
service_type='metering', endpoint_type='public',
|
||||
region_name=self.endpoint.region_name)
|
||||
kw = {"endpoint": self.service_catalog.url_for.return_value,
|
||||
"token": self.fake_keystone.auth_token,
|
||||
"timeout": cfg.CONF.openstack_client_http_timeout,
|
||||
"insecure": False, "cacert": None,
|
||||
"region_name": None}
|
||||
"insecure": False, "cacert": None}
|
||||
mock_ceilometer.Client.assert_called_once_with("2", **kw)
|
||||
self.assertEqual(self.clients.cache["ceilometer"],
|
||||
fake_ceilometer)
|
||||
@ -166,20 +177,21 @@ class OSClientsTestCase(test.TestCase):
|
||||
@mock.patch("rally.osclients.ironic")
|
||||
def test_ironic(self, mock_ironic):
|
||||
fake_ironic = fakes.FakeIronicClient()
|
||||
mock_ironic.Client = mock.MagicMock(return_value=fake_ironic)
|
||||
mock_ironic.get_client = mock.MagicMock(return_value=fake_ironic)
|
||||
self.assertTrue("ironic" not in self.clients.cache)
|
||||
client = self.clients.ironic()
|
||||
self.assertEqual(client, fake_ironic)
|
||||
self.service_catalog.url_for.assert_called_once_with(
|
||||
service_type='baremetal', endpoint_type='public',
|
||||
region_name=self.endpoint.region_name)
|
||||
kw = {
|
||||
"username": self.endpoint.username,
|
||||
"password": self.endpoint.password,
|
||||
"tenant_name": self.endpoint.tenant_name,
|
||||
"auth_url": self.endpoint.auth_url,
|
||||
"os_auth_token": self.fake_keystone.auth_token,
|
||||
"ironic_url": self.service_catalog.url_for.return_value,
|
||||
"timeout": cfg.CONF.openstack_client_http_timeout,
|
||||
"insecure": cfg.CONF.https_insecure,
|
||||
"cacert": cfg.CONF.https_cacert
|
||||
}
|
||||
mock_ironic.Client.assert_called_once_with("1.0", **kw)
|
||||
mock_ironic.get_client.assert_called_once_with("1.0", **kw)
|
||||
self.assertEqual(self.clients.cache["ironic"], fake_ironic)
|
||||
|
||||
@mock.patch("rally.osclients.sahara")
|
||||
|
@ -43,6 +43,10 @@ class ConfigTestCase(test.TestCase):
|
||||
self.deploy_id = "fake_deploy_id"
|
||||
self.conf_generator = config.TempestConf(self.deploy_id)
|
||||
|
||||
keystone_patcher = mock.patch("rally.osclients.create_keystone_client")
|
||||
keystone_patcher.start()
|
||||
self.addCleanup(keystone_patcher.stop)
|
||||
|
||||
def _remove_default_section(self, items):
|
||||
# getting items from configparser by specified section name
|
||||
# retruns also values from DEFAULT section
|
||||
@ -149,8 +153,7 @@ class ConfigTestCase(test.TestCase):
|
||||
self.conf_generator._set_compute_flavors)
|
||||
|
||||
@mock.patch("rally.osclients.glance")
|
||||
@mock.patch("rally.osclients.keystone")
|
||||
def test__set_compute_images(self, mock_keystone, mock_glance):
|
||||
def test__set_compute_images(self, mock_glance):
|
||||
mock_glanceclient = mock.MagicMock()
|
||||
mock_glanceclient.images.list.return_value = [
|
||||
fakes.FakeImage(id="id1", name="cirros1"),
|
||||
@ -163,10 +166,8 @@ class ConfigTestCase(test.TestCase):
|
||||
self.assertEqual(sorted(expected), sorted(results))
|
||||
|
||||
@mock.patch("rally.osclients.glance")
|
||||
@mock.patch("rally.osclients.keystone")
|
||||
@mock.patch("six.moves.builtins.open")
|
||||
def test__set_compute_images_create(self, mock_open, mock_keystone,
|
||||
mock_glance):
|
||||
def test__set_compute_images_create(self, mock_open, mock_glance):
|
||||
mock_glanceclient = mock.MagicMock()
|
||||
mock_glanceclient.images.list.return_value = []
|
||||
mock_glanceclient.images.create.side_effect = [
|
||||
@ -180,9 +181,7 @@ class ConfigTestCase(test.TestCase):
|
||||
self.assertEqual(sorted(expected), sorted(results))
|
||||
|
||||
@mock.patch("rally.osclients.glance")
|
||||
@mock.patch("rally.osclients.keystone")
|
||||
def test__set_compute_images_create_fails(self, mock_keystone,
|
||||
mock_glance):
|
||||
def test__set_compute_images_create_fails(self, mock_glance):
|
||||
mock_glanceclient = mock.MagicMock()
|
||||
mock_glanceclient.images.list.return_value = []
|
||||
mock_glanceclient.images.create.side_effect = Exception()
|
||||
|
Loading…
x
Reference in New Issue
Block a user