diff --git a/devstack/lib/rally b/devstack/lib/rally index 309eba04f2..8c36c30371 100644 --- a/devstack/lib/rally +++ b/devstack/lib/rally @@ -50,12 +50,16 @@ then cat >$1 <$1 < 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": , "tenant_id": , - "credential": + "credential": } :param superclass: The plugin superclass to perform cleanup for. E.g., this could be diff --git a/rally/plugins/openstack/context/keystone/existing_users.py b/rally/plugins/openstack/context/keystone/existing_users.py index cbcd9ccc4a..e1d8e30673 100644 --- a/rally/plugins/openstack/context/keystone/existing_users.py +++ b/rally/plugins/openstack/context/keystone/existing_users.py @@ -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 diff --git a/rally/plugins/openstack/context/keystone/users.py b/rally/plugins/openstack/context/keystone/users.py index 98596c94bd..380ce7e1a7 100644 --- a/rally/plugins/openstack/context/keystone/users.py +++ b/rally/plugins/openstack/context/keystone/users.py @@ -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, diff --git a/rally/plugins/openstack/credential.py b/rally/plugins/openstack/credential.py new file mode 100644 index 0000000000..1a34bf8f94 --- /dev/null +++ b/rally/plugins/openstack/credential.py @@ -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 diff --git a/rally/plugins/openstack/scenario.py b/rally/plugins/openstack/scenario.py index 3f54aae239..4389ff3afa 100644 --- a/rally/plugins/openstack/scenario.py +++ b/rally/plugins/openstack/scenario.py @@ -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) diff --git a/rally/plugins/openstack/verification/tempest/config.py b/rally/plugins/openstack/verification/tempest/config.py index dc861378f2..24f15ccd00 100644 --- a/rally/plugins/openstack/verification/tempest/config.py +++ b/rally/plugins/openstack/verification/tempest/config.py @@ -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', diff --git a/rally/plugins/openstack/verification/tempest/context.py b/rally/plugins/openstack/verification/tempest/context.py index c8a1022c1b..9375d51e86 100644 --- a/rally/plugins/openstack/verification/tempest/context.py +++ b/rally/plugins/openstack/verification/tempest/context.py @@ -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() diff --git a/rally/task/engine.py b/rally/task/engine.py index 0135a4795f..5a67f0ef21 100644 --- a/rally/task/engine.py +++ b/rally/task/engine.py @@ -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 } diff --git a/rally/task/validation.py b/rally/task/validation.py index dacdc4578d..e11186c859 100755 --- a/rally/task/validation.py +++ b/rally/task/validation.py @@ -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: diff --git a/tests/ci/osresources.py b/tests/ci/osresources.py index fea6402976..0c403aeb8b 100755 --- a/tests/ci/osresources.py +++ b/tests/ci/osresources.py @@ -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"] diff --git a/tests/ci/rally_gate_functions.sh b/tests/ci/rally_gate_functions.sh index 783e1830e8..8bdd249c7d 100644 --- a/tests/ci/rally_gate_functions.sh +++ b/tests/ci/rally_gate_functions.sh @@ -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",\ diff --git a/tests/ci/rally_verify.py b/tests/ci/rally_verify.py index 879678c995..e85cf05e59 100755 --- a/tests/ci/rally_verify.py +++ b/tests/ci/rally_verify.py @@ -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 diff --git a/tests/functional/test_task_samples.py b/tests/functional/test_task_samples.py index 58d12092ac..746ed27c69 100644 --- a/tests/functional/test_task_samples.py +++ b/tests/functional/test_task_samples.py @@ -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") diff --git a/tests/unit/cli/commands/test_deployment.py b/tests/unit/cli/commands/test_deployment.py index 3bd0fa6465..e216ba373e 100644 --- a/tests/unit/cli/commands/test_deployment.py +++ b/tests/unit/cli/commands/test_deployment.py @@ -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": []} diff --git a/tests/unit/common/objects/test_credential.py b/tests/unit/common/objects/test_credential.py index e49497d6f3..14afe51fbd 100644 --- a/tests/unit/common/objects/test_credential.py +++ b/tests/unit/common/objects/test_credential.py @@ -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): diff --git a/tests/unit/common/objects/test_deploy.py b/tests/unit/common/objects/test_deploy.py index f9e0c71047..249dbf389a 100644 --- a/tests/unit/common/objects/test_deploy.py +++ b/tests/unit/common/objects/test_deploy.py @@ -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) diff --git a/tests/unit/deployment/engines/test_devstack.py b/tests/unit/deployment/engines/test_devstack.py index b92422741f..b26bcd9774 100644 --- a/tests/unit/deployment/engines/test_devstack.py +++ b/tests/unit/deployment/engines/test_devstack.py @@ -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", diff --git a/tests/unit/deployment/engines/test_existing.py b/tests/unit/deployment/engines/test_existing.py index cecd4ddd6e..6b353cc0fa 100644 --- a/tests/unit/deployment/engines/test_existing.py +++ b/tests/unit/deployment/engines/test_existing.py @@ -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( diff --git a/tests/unit/deployment/serverprovider/providers/test_openstack.py b/tests/unit/deployment/serverprovider/providers/test_openstack.py index 51b4c0e67f..b23b87c5a7 100644 --- a/tests/unit/deployment/serverprovider/providers/test_openstack.py +++ b/tests/unit/deployment/serverprovider/providers/test_openstack.py @@ -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( diff --git a/tests/unit/deployment/test_credential.py b/tests/unit/deployment/test_credential.py new file mode 100644 index 0000000000..51837deff6 --- /dev/null +++ b/tests/unit/deployment/test_credential.py @@ -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"}) diff --git a/tests/unit/deployment/test_lxc.py b/tests/unit/deployment/test_lxc.py index a5d5d8dd0c..1e48d2fd38 100644 --- a/tests/unit/deployment/test_lxc.py +++ b/tests/unit/deployment/test_lxc.py @@ -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", diff --git a/tests/unit/doc/test_jsonschemas.py b/tests/unit/doc/test_jsonschemas.py index 9081766a33..c9421596d8 100644 --- a/tests/unit/doc/test_jsonschemas.py +++ b/tests/unit/doc/test_jsonschemas.py @@ -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"]) diff --git a/tests/unit/fakes.py b/tests/unit/fakes.py index 569d81139b..18145d39ff 100644 --- a/tests/unit/fakes.py +++ b/tests/unit/fakes.py @@ -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"}} diff --git a/tests/unit/plugins/openstack/cleanup/test_manager.py b/tests/unit/plugins/openstack/cleanup/test_manager.py index bfa7dd5a86..129871bcdd 100644 --- a/tests/unit/plugins/openstack/cleanup/test_manager.py +++ b/tests/unit/plugins/openstack/cleanup/test_manager.py @@ -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): diff --git a/tests/unit/plugins/openstack/context/keystone/test_existing_users.py b/tests/unit/plugins/openstack/context/keystone/test_existing_users.py index f7aad716d0..79aa2cb497 100644 --- a/tests/unit/plugins/openstack/context/keystone/test_existing_users.py +++ b/tests/unit/plugins/openstack/context/keystone/test_existing_users.py @@ -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(), diff --git a/tests/unit/plugins/openstack/context/keystone/test_users.py b/tests/unit/plugins/openstack/context/keystone/test_users.py index 59d687d7f7..3e68cf7dee 100644 --- a/tests/unit/plugins/openstack/context/keystone/test_users.py +++ b/tests/unit/plugins/openstack/context/keystone/test_users.py @@ -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": { diff --git a/tests/unit/plugins/openstack/context/sahara/test_sahara_output_data_sources.py b/tests/unit/plugins/openstack/context/sahara/test_sahara_output_data_sources.py index 00e3f74338..0659e1549d 100644 --- a/tests/unit/plugins/openstack/context/sahara/test_sahara_output_data_sources.py +++ b/tests/unit/plugins/openstack/context/sahara/test_sahara_output_data_sources.py @@ -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 diff --git a/tests/unit/plugins/openstack/test_credential.py b/tests/unit/plugins/openstack/test_credential.py new file mode 100644 index 0000000000..28e0d7f481 --- /dev/null +++ b/tests/unit/plugins/openstack/test_credential.py @@ -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) diff --git a/tests/unit/plugins/openstack/test_scenario.py b/tests/unit/plugins/openstack/test_scenario.py index aae42e82c5..d1fd0aa4d2 100644 --- a/tests/unit/plugins/openstack/test_scenario.py +++ b/tests/unit/plugins/openstack/test_scenario.py @@ -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"), - ]) diff --git a/tests/unit/plugins/openstack/verification/tempest/test_config.py b/tests/unit/plugins/openstack/verification/tempest/test_config.py index cdf641374d..081b7392ec 100644 --- a/tests/unit/plugins/openstack/verification/tempest/test_config.py +++ b/tests/unit/plugins/openstack/verification/tempest/test_config.py @@ -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) diff --git a/tests/unit/plugins/openstack/verification/tempest/test_context.py b/tests/unit/plugins/openstack/verification/tempest/test_context.py index 1aad9ac231..7e002110d5 100644 --- a/tests/unit/plugins/openstack/verification/tempest/test_context.py +++ b/tests/unit/plugins/openstack/verification/tempest/test_context.py @@ -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() diff --git a/tests/unit/task/test_engine.py b/tests/unit/task/test_engine.py index 71f64d92ef..05b54411eb 100644 --- a/tests/unit/task/test_engine.py +++ b/tests/unit/task/test_engine.py @@ -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) diff --git a/tests/unit/task/test_validation.py b/tests/unit/task/test_validation.py index 2d653bae74..398f738687 100755 --- a/tests/unit/task/test_validation.py +++ b/tests/unit/task/test_validation.py @@ -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( diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index 3d228afa0d..fb7d7be14e 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -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): diff --git a/tests/unit/test_osclients.py b/tests/unit/test_osclients.py index b8881a3197..b7962674d7 100644 --- a/tests/unit/test_osclients.py +++ b/tests/unit/test_osclients.py @@ -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()