OSprofiler support

The OSprofiler is a distributed trace toolkit library.
It helps to trace internal calls of Openstack services including RPC, DB
and WSGI.

This patch integrates OSprofiler in Rally. Rally can trigger the
profiling on a per-iteration basis. To do so a secret key
(profiler_hmac_key) is stored alongside the credentials and used to
initialize the profiler in the constructor of the scenarios. A
configuration parameter (enable_profiler) can disabled the profiling.

Note that in this patch we don't embed the full osprofiler report but
only a trace id. This trace id can be used to retrieve the full trace
from the osprofiler tool later.

Change-Id: I7602856d094e073fde80d287b4d92b5750aacc3c
Co-Authored-By: rcherrueau <Ronan-Alexandre.Cherrueau@inria.fr>
Implements: spec osprofiler
This commit is contained in:
msimonin 2017-05-19 10:44:22 +02:00
parent 2b17411c2e
commit 755af67a02
27 changed files with 308 additions and 52 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -38,3 +38,4 @@ more complicated cases.
tutorial/step_8_discovering_more_plugins
tutorial/step_9_deploying_openstack
tutorial/step_10_verifying_cloud_via_tempest_verifier
tutorial/step_11_profiling_openstack_internals

View File

@ -0,0 +1,84 @@
..
Copyright 2017 Inria 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.
.. _tutorial_step_11_profiling_openstack_internals:
Step 11. Profiling OpenStack Internals
======================================
.. contents::
:local:
Rally leverage `OSprofiler <https://github.com/openstack/osprofiler>`_ to
generate traces of OpenStack internal calls happening during the run of a
scenario. Integration of OSProfiler in Rally can help to dig into concurrency
problems of OpenStack which is a huge ecosystem of cooperative services.
Workflow
--------
Enabling the profiler is based on a shared secret between the clients (here
Rally) and the various Openstack services : the HMAC key. In the following we
assume that your OpenStack services have been configured to enable OSprofiler
and that the secret HMAC key is ``SECRET_KEY``. This key is stored alongside
the credentials of your deployment. Once Rally is instructed about the HMAC
key, a new trace can be initialized for each iteration of the workload. Rally
will then store in its reports a profiler trace id. This id can be finally be
used to query OSprofiler in order to get the full trace of the iteration.
Registering the HMAC key
------------------------
You can store your HMAC key in the environment variable
``OSPROFILER_HMAC_KEY``. This variable will be loaded if you create your
deployment with the ``--from-env`` option.
Alternatively if you create your deployment using the ``--file`` option you can
add the HMAC key with the following :
.. code-block:: json
{
"type": "ExistingCloud",
"creds": {
"openstack": {
[...]
"profiler_hmac_key": "SECRET_KEY"
}
}
}
Getting the full trace
----------------------
A trace id is stored on a per-iteration basis and can be found in the JSON
report as-well as the HTML report :
.. image:: ../../images/Report-Task-Scenario-Data-Per-iteration-profiler.png
OSProfiler can be asked to generate the full trace using this trace id:
.. code-block:: shell
osprofiler trace show --html --out trace.html 941338f6-3d39-4f80-9dba-395d9dbd16bb
Disabling the profiler
------------------------
Setting ``enable_profiler = False`` under the ``benchmark`` group in the
configuration file will disabled the profiler.

View File

@ -580,6 +580,8 @@
# Neutron create loadbalancer poll interval (floating point value)
#neutron_create_loadbalancer_poll_interval = 2.0
# Enable or disable osprofiler to trace the scenarios
#enable_profiler = True
[cleanup]

View File

@ -109,7 +109,8 @@ def get_creds_from_env_vars():
"region_name": os.environ.get("OS_REGION_NAME", ""),
"https_cacert": os.environ.get("OS_CACERT", ""),
"https_insecure": strutils.bool_from_string(
os.environ.get("OS_INSECURE"))
os.environ.get("OS_INSECURE")),
"profiler_hmac_key": os.environ.get("OSPROFILER_HMAC_KEY")
}
user_domain_name = os.environ.get("OS_USER_DOMAIN_NAME")

View File

@ -152,6 +152,7 @@ class ExistingCloud(engine.Engine):
None]},
"https_insecure": {"type": "boolean"},
"https_cacert": {"type": "string"},
"profiler_hmac_key": {"type": ["string", "null"]},
"admin": USER_SCHEMA,
"users": {"type": "array", "items": USER_SCHEMA},
"extra": {"type": "object", "additionalProperties": True}

View File

@ -25,6 +25,7 @@ from rally.plugins.openstack.cfg import monasca
from rally.plugins.openstack.cfg import murano
from rally.plugins.openstack.cfg import neutron
from rally.plugins.openstack.cfg import nova
from rally.plugins.openstack.cfg import profiler
from rally.plugins.openstack.cfg import sahara
from rally.plugins.openstack.cfg import senlin
from rally.plugins.openstack.cfg import vm
@ -43,9 +44,10 @@ def list_opts():
opts = {}
for l_opts in (cinder.OPTS, ec2.OPTS, heat.OPTS, ironic.OPTS, magnum.OPTS,
manila.OPTS, mistral.OPTS, monasca.OPTS, murano.OPTS,
nova.OPTS, sahara.OPTS, vm.OPTS, glance.OPTS, watcher.OPTS,
tempest.OPTS, keystone_roles.OPTS, keystone_users.OPTS,
cleanup.OPTS, senlin.OPTS, neutron.OPTS):
nova.OPTS, profiler.OPTS, sahara.OPTS, vm.OPTS, glance.OPTS,
watcher.OPTS, tempest.OPTS, keystone_roles.OPTS,
keystone_users.OPTS, cleanup.OPTS, senlin.OPTS,
neutron.OPTS):
for category, opt in l_opts.items():
opts.setdefault(category, [])
opts[category].extend(opt)

View File

@ -0,0 +1,21 @@
# Copyright 2017: Inria.
# 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 oslo_config import cfg
OPTS = {"benchmark": [
cfg.BoolOpt("enable_profiler", default=True,
help="Enable or disable osprofiler to trace the scenarios")
]}

View File

@ -196,7 +196,8 @@ class UserGenerator(context.Context):
endpoint_type=self.credential.endpoint_type,
https_insecure=self.credential.https_insecure,
https_cacert=self.credential.https_cacert,
region_name=self.credential.region_name)
region_name=self.credential.region_name,
profiler_hmac_key=self.credential.profiler_hmac_key)
users.append({"id": user.id,
"credential": user_credential,
"tenant_id": tenant_id})

View File

@ -32,7 +32,8 @@ class OpenStackCredential(credential.Credential):
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):
https_insecure=False, https_cacert=None,
profiler_hmac_key=None):
self.auth_url = auth_url
self.username = username
self.password = password
@ -46,6 +47,7 @@ class OpenStackCredential(credential.Credential):
self.endpoint = endpoint
self.https_insecure = https_insecure
self.https_cacert = https_cacert
self.profiler_hmac_key = profiler_hmac_key
self._clients_cache = {}
@ -76,7 +78,8 @@ class OpenStackCredential(credential.Credential):
"https_cacert": self.https_cacert,
"user_domain_name": self.user_domain_name,
"project_domain_name": self.project_domain_name,
"permission": self.permission}
"permission": self.permission,
"profiler_hmac_key": self.profiler_hmac_key}
def verify_connection(self):
from keystoneclient import exceptions as keystone_exceptions
@ -152,6 +155,7 @@ class OpenStackCredentialBuilder(credential.CredentialBuilder):
None]},
"https_insecure": {"type": "boolean"},
"https_cacert": {"type": "string"},
"profiler_hmac_key": {"type": ["string", "null"]}
},
"required": ["auth_url", "admin"],
"additionalProperties": False
@ -171,7 +175,8 @@ class OpenStackCredentialBuilder(credential.CredentialBuilder):
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"))
https_cacert=common.get("https_cacert"),
profiler_hmac_key=common.get("profiler_hmac_key"))
return cred.to_dict()
def build_credentials(self):

View File

@ -16,11 +16,15 @@
import functools
import random
from oslo_config import cfg
from osprofiler import profiler
from rally import osclients
from rally.task import scenario
configure = functools.partial(scenario.configure, namespace="openstack")
CONF = cfg.CONF
class OpenStackScenario(scenario.Scenario):
"""Base class for all OpenStack scenarios."""
@ -54,6 +58,8 @@ class OpenStackScenario(scenario.Scenario):
if clients:
self._clients = clients
self._init_profiler(context)
def _choose_user(self, context):
"""Choose one user from users context
@ -104,3 +110,27 @@ class OpenStackScenario(scenario.Scenario):
client = getattr(self._admin_clients, client_type)
return client(version) if version is not None else client()
def _init_profiler(self, context):
"""Inits the profiler."""
if not CONF.benchmark.enable_profiler:
return
if context is not None:
cred = None
profiler_hmac_key = None
if "admin" in context:
cred = context["admin"]["credential"]
if cred.profiler_hmac_key is not None:
profiler_hmac_key = cred.profiler_hmac_key
if "user" in context:
cred = context["user"]["credential"]
if cred.profiler_hmac_key is not None:
profiler_hmac_key = cred.profiler_hmac_key
if profiler_hmac_key is None:
return
profiler.init(profiler_hmac_key)
trace_id = profiler.get().get_base_id()
self.add_output(complete={
"title": "OSProfiler Trace-ID",
"chart_plugin": "TextArea",
"data": [trace_id]})

View File

@ -30,6 +30,7 @@ boto>=2.32.1,<=2.46.1 # MIT
gnocchiclient>=2.7.0,<=3.1.1 # Apache Software License
keystoneauth1==2.20.0 # Apache Software License
os-faults>=0.1.5,<=0.1.12 # Apache Software License
osprofiler>=1.4.0 # Apache License, Version 2.0
python-ceilometerclient>=2.5.0,<=2.8.1 # Apache Software License
python-cinderclient==2.0.1 # Apache Software License
python-designateclient>=1.5.0,<=2.6.0 # Apache License, Version 2.0

View File

@ -0,0 +1,20 @@
{
"type": "ExistingCloud",
"creds": {
"openstack": {
"auth_url": "http://example.net:5000/v3/",
"region_name": "RegionOne",
"endpoint_type": "public",
"admin": {
"username": "admin",
"password": "myadminpass",
"user_domain_name": "admin",
"project_name": "admin",
"project_domain_name": "admin"
},
"https_insecure": false,
"https_cacert": "",
"profiler_hmac_key": "SECRET_KEY"
}
}
}

View File

@ -54,7 +54,8 @@ class DeploymentCommandsTestCase(test.TestCase):
"OS_ENDPOINT": "fake_endpoint",
"OS_INSECURE": "True",
"OS_CACERT": "fake_cacert",
"RALLY_DEPLOYMENT": "fake_deployment_id"})
"RALLY_DEPLOYMENT": "fake_deployment_id",
"OSPROFILER_HMAC_KEY": "fake_hmac_key"})
@mock.patch("rally.cli.commands.deployment.DeploymentCommands.list")
def test_createfromenv_keystonev2(self, mock_list):
self.deployment.create(self.fake_api, "from_env", True)
@ -73,7 +74,8 @@ class DeploymentCommandsTestCase(test.TestCase):
"tenant_name": "fake_tenant_name"
},
"https_insecure": True,
"https_cacert": "fake_cacert"
"https_cacert": "fake_cacert",
"profiler_hmac_key": "fake_hmac_key"
}
}
},
@ -91,7 +93,8 @@ class DeploymentCommandsTestCase(test.TestCase):
"OS_ENDPOINT": "fake_endpoint",
"OS_INSECURE": "True",
"OS_CACERT": "fake_cacert",
"RALLY_DEPLOYMENT": "fake_deployment_id"})
"RALLY_DEPLOYMENT": "fake_deployment_id",
"OSPROFILER_HMAC_KEY": "fake_hmac_key"})
@mock.patch("rally.cli.commands.deployment.DeploymentCommands.list")
def test_createfromenv_keystonev3(self, mock_list):
self.deployment.create(self.fake_api, "from_env", True)
@ -112,7 +115,8 @@ class DeploymentCommandsTestCase(test.TestCase):
"project_name": "fake_tenant_name"
},
"https_insecure": True,
"https_cacert": "fake_cacert"
"https_cacert": "fake_cacert",
"profiler_hmac_key": "fake_hmac_key"
}
}
},

View File

@ -112,6 +112,7 @@ class EnvUtilsTestCase(test.TestCase):
"OS_ENDPOINT_TYPE": "fake_endpoint_typeURL",
"OS_ENDPOINT": "fake_endpoint",
"OS_INSECURE": "True",
"OSPROFILER_HMAC_KEY": "fake_hmac_key",
"OS_CACERT": "fake_cacert"})
def test_get_creds_from_env_vars_keystone_v2(self):
expected_creds = {
@ -125,7 +126,8 @@ class EnvUtilsTestCase(test.TestCase):
"endpoint": "fake_endpoint",
"region_name": "fake_region_name",
"https_cacert": "fake_cacert",
"https_insecure": True
"https_insecure": True,
"profiler_hmac_key": "fake_hmac_key"
}
creds = envutils.get_creds_from_env_vars()
self.assertEqual(expected_creds, creds)
@ -140,6 +142,7 @@ class EnvUtilsTestCase(test.TestCase):
"OS_INSECURE": "True",
"OS_PROJECT_DOMAIN_NAME": "fake_pdn",
"OS_USER_DOMAIN_NAME": "fake_udn",
"OSPROFILER_HMAC_KEY": "fake_hmac_key",
"OS_CACERT": "fake_cacert"})
def test_get_creds_from_env_vars_keystone_v3(self):
expected_creds = {
@ -155,7 +158,8 @@ class EnvUtilsTestCase(test.TestCase):
"endpoint": "fake_endpoint",
"region_name": "fake_region_name",
"https_cacert": "fake_cacert",
"https_insecure": True
"https_insecure": True,
"profiler_hmac_key": "fake_hmac_key"
}
creds = envutils.get_creds_from_env_vars()
self.assertEqual(expected_creds, creds)
@ -165,6 +169,7 @@ class EnvUtilsTestCase(test.TestCase):
"OS_REGION_NAME": "fake_region_name",
"OS_ENDPOINT": "fake_endpoint",
"OS_INSECURE": "True",
"OSPROFILER_HMAC_KEY": "fake_hmac_key",
"OS_CACERT": "fake_cacert"})
def test_get_creds_from_env_vars_when_required_vars_missing(self):
if "OS_USERNAME" in os.environ:

View File

@ -39,7 +39,8 @@ class CredentialTestCase(test.TestCase):
"https_insecure": False,
"https_cacert": None,
"project_domain_name": None,
"user_domain_name": None})
"user_domain_name": None,
"profiler_hmac_key": None})
def test_to_dict_with_include_permission(self):
credential = objects.Credential(
@ -59,7 +60,8 @@ class CredentialTestCase(test.TestCase):
"https_insecure": False,
"https_cacert": None,
"project_domain_name": None,
"user_domain_name": None})
"user_domain_name": None,
"profiler_hmac_key": None})
def test_to_dict_with_kwarg_credential(self):
credential = objects.Credential(
@ -80,4 +82,5 @@ class CredentialTestCase(test.TestCase):
"https_insecure": False,
"https_cacert": None,
"project_domain_name": None,
"user_domain_name": None})
"user_domain_name": None,
"profiler_hmac_key": None})

View File

@ -37,6 +37,7 @@ class TestExistingCloud(test.TestCase):
"endpoint_type": consts.EndpointType.INTERNAL,
"https_insecure": False,
"https_cacert": "cacert",
"profiler_hmac_key": None,
"admin": {
"username": "admin",
"password": "myadminpass",
@ -52,6 +53,7 @@ class TestExistingCloud(test.TestCase):
"endpoint_type": consts.EndpointType.INTERNAL,
"https_insecure": False,
"https_cacert": "cacert",
"profiler_hmac_key": None,
"admin": {
"username": "admin",
"password": "myadminpass",
@ -72,6 +74,7 @@ class TestExistingCloud(test.TestCase):
"endpoint_type": consts.EndpointType.INTERNAL,
"https_insecure": False,
"https_cacert": "cacert",
"profiler_hmac_key": None,
"admin": {
"username": "admin",
"password": "myadminpass",
@ -159,6 +162,7 @@ class TestExistingCloud(test.TestCase):
"endpoint_type": "internal",
"https_cacert": "cacert",
"https_insecure": False,
"profiler_hmac_key": None,
"password": "myadminpass",
"permission": "admin",
"project_domain_name": None,

View File

@ -37,7 +37,7 @@ class EC2ServerGeneratorTestCase(test.TestCase):
for tenant_id in tenants.keys():
for i in range(users_per_tenant):
users.append({"id": i, "tenant_id": tenant_id,
"credential": "credential"})
"credential": mock.MagicMock()})
return tenants, users
def _get_context(self, users, tenants):

View File

@ -27,6 +27,8 @@ from tests.unit import test
MANILA_UTILS_PATH = ("rally.plugins.openstack.scenarios.manila.utils."
"ManilaScenario.")
MOCK_USER_CREDENTIAL = mock.MagicMock()
class Fake(object):
def __init__(self, **kwargs):
@ -71,8 +73,9 @@ class ShareNetworksTestCase(test.TestCase):
users = []
for t_id in tenants.keys():
for i in range(self.USERS_PER_TENANT):
users.append(
{"id": i, "tenant_id": t_id, "credential": "fake"})
users.append({
"id": i, "tenant_id": t_id,
"credential": MOCK_USER_CREDENTIAL})
context = {
"config": {
"users": {
@ -123,8 +126,8 @@ class ShareNetworksTestCase(test.TestCase):
"tenant_2_id": {"id": "tenant_2_id", "name": "tenant_2_name"},
},
"users": [
{"tenant_id": "tenant_1_id", "credential": {"c1": "foo"}},
{"tenant_id": "tenant_2_id", "credential": {"c2": "bar"}},
{"tenant_id": "tenant_1_id", "credential": mock.MagicMock()},
{"tenant_id": "tenant_2_id", "credential": mock.MagicMock()},
],
}
self.existing_sns = [
@ -288,8 +291,8 @@ class ShareNetworksTestCase(test.TestCase):
]
mock_manila_scenario__create_share_network.assert_has_calls(
expected_calls * (self.TENANTS_AMOUNT * networks_per_tenant))
mock_clients.assert_has_calls([
mock.call("fake", {}) for i in range(self.TENANTS_AMOUNT)])
mock_clients.assert_has_calls([mock.call(MOCK_USER_CREDENTIAL, {})
for i in range(self.TENANTS_AMOUNT)])
@ddt.data(True, False)
@mock.patch("rally.osclients.Clients")
@ -326,8 +329,8 @@ class ShareNetworksTestCase(test.TestCase):
expected_calls = [mock.call(**sn_args), mock.call().to_dict()]
mock_manila_scenario__create_share_network.assert_has_calls(
expected_calls * (self.TENANTS_AMOUNT * networks_per_tenant))
mock_clients.assert_has_calls([
mock.call("fake", {}) for i in range(self.TENANTS_AMOUNT)])
mock_clients.assert_has_calls([mock.call(MOCK_USER_CREDENTIAL, {})
for i in range(self.TENANTS_AMOUNT)])
@mock.patch("rally.osclients.Clients")
@mock.patch(MANILA_UTILS_PATH + "_create_share_network")
@ -351,8 +354,8 @@ class ShareNetworksTestCase(test.TestCase):
expected_calls = [mock.call(), mock.call().to_dict()]
mock_manila_scenario__create_share_network.assert_has_calls(
expected_calls * self.TENANTS_AMOUNT)
mock_clients.assert_has_calls([
mock.call("fake", {}) for i in range(self.TENANTS_AMOUNT)])
mock_clients.assert_has_calls([mock.call(MOCK_USER_CREDENTIAL, {})
for i in range(self.TENANTS_AMOUNT)])
@mock.patch("rally.osclients.Clients")
@mock.patch(MANILA_UTILS_PATH + "_delete_share_network")

View File

@ -56,8 +56,9 @@ class SharesTestCase(test.TestCase):
users = []
for t_id in sorted(list(tenants.keys())):
for i in range(self.USERS_PER_TENANT):
users.append(
{"id": i, "tenant_id": t_id, "credential": "fake"})
users.append({
"id": i, "tenant_id": t_id,
"credential": mock.MagicMock()})
context = {
"config": {
"users": {

View File

@ -50,12 +50,12 @@ class MuranoEnvironmentGeneratorTestCase(test.TestCase):
{
"id": "user_0",
"tenant_id": "tenant_0",
"credential": "credential"
"credential": mock.MagicMock()
},
{
"id": "user_1",
"tenant_id": "tenant_1",
"credential": "credential"
"credential": mock.MagicMock()
}
],
"tenants": {

View File

@ -41,8 +41,16 @@ class SwiftObjectGeneratorTestCase(test.TestCase):
"t2": {"name": "t2_name"}
},
"users": [
{"id": "u1", "tenant_id": "t1", "credential": "c1"},
{"id": "u2", "tenant_id": "t2", "credential": "c2"}
{
"id": "u1",
"tenant_id": "t1",
"credential": mock.MagicMock()
},
{
"id": "u2",
"tenant_id": "t2",
"credential": mock.MagicMock()
}
]
})
@ -122,8 +130,16 @@ class SwiftObjectGeneratorTestCase(test.TestCase):
"t2": {"name": "t2_name"}
},
"users": [
{"id": "u1", "tenant_id": "t1", "credential": "c1"},
{"id": "u2", "tenant_id": "t2", "credential": "c2"}
{
"id": "u1",
"tenant_id": "t1",
"credential": mock.MagicMock()
},
{
"id": "u2",
"tenant_id": "t2",
"credential": mock.MagicMock()
}
]
})
mock_swift = mock_clients.return_value.swift.return_value
@ -143,8 +159,16 @@ class SwiftObjectGeneratorTestCase(test.TestCase):
"t2": {"name": "t2_name"}
},
"users": [
{"id": "u1", "tenant_id": "t1", "credential": "c1"},
{"id": "u2", "tenant_id": "t2", "credential": "c2"}
{
"id": "u1",
"tenant_id": "t1",
"credential": mock.MagicMock()
},
{
"id": "u2",
"tenant_id": "t2",
"credential": mock.MagicMock()
}
]
})
mock_swift = mock_clients.return_value.swift.return_value
@ -163,7 +187,7 @@ class SwiftObjectGeneratorTestCase(test.TestCase):
"name": "t1_name",
"containers": [
{"user": {"id": "u1", "tenant_id": "t1",
"credential": "c1"},
"credential": mock.MagicMock()},
"container": "coooon",
"objects": []}] * 3
}
@ -184,7 +208,7 @@ class SwiftObjectGeneratorTestCase(test.TestCase):
"name": "t1_name",
"containers": [
{"user": {"id": "u1", "tenant_id": "t1",
"credential": "c1"},
"credential": mock.MagicMock()},
"container": "c1",
"objects": ["oooo"] * 3}
]

View File

@ -26,14 +26,15 @@ class SwiftObjectMixinTestCase(test.TestCase):
tenants = 2
containers_per_tenant = 2
context = test.get_test_context()
c = [mock.MagicMock(), mock.MagicMock()]
context.update({
"tenants": {
"1001": {"name": "t1_name"},
"1002": {"name": "t2_name"}
},
"users": [
{"id": "u1", "tenant_id": "1001", "credential": "c1"},
{"id": "u2", "tenant_id": "1002", "credential": "c2"}
{"id": "u1", "tenant_id": "1001", "credential": c[0]},
{"id": "u2", "tenant_id": "1002", "credential": c[1]}
]
})
@ -51,7 +52,7 @@ class SwiftObjectMixinTestCase(test.TestCase):
self.assertEqual(containers_per_tenant, len(containers))
for container in containers:
self.assertEqual("u%d" % index, container["user"]["id"])
self.assertEqual("c%d" % index,
self.assertEqual(c[index - 1],
container["user"]["credential"])
self.assertEqual(0, len(container["objects"]))
@ -68,7 +69,7 @@ class SwiftObjectMixinTestCase(test.TestCase):
"containers": [
{"user": {
"id": "u1", "tenant_id": "1001",
"credential": "c0"},
"credential": mock.MagicMock()},
"container": "c1",
"objects": []}
]
@ -78,7 +79,7 @@ class SwiftObjectMixinTestCase(test.TestCase):
"containers": [
{"user": {
"id": "u2", "tenant_id": "1002",
"credential": "c2"},
"credential": mock.MagicMock()},
"container": "c2",
"objects": []}
]
@ -114,7 +115,7 @@ class SwiftObjectMixinTestCase(test.TestCase):
"containers": [
{"user": {
"id": "u1", "tenant_id": "1001",
"credential": "c1"},
"credential": mock.MagicMock()},
"container": "c1",
"objects": []}
]
@ -124,7 +125,7 @@ class SwiftObjectMixinTestCase(test.TestCase):
"containers": [
{"user": {
"id": "u2", "tenant_id": "1002",
"credential": "c2"},
"credential": mock.MagicMock()},
"container": "c2",
"objects": []}
]
@ -154,7 +155,7 @@ class SwiftObjectMixinTestCase(test.TestCase):
"containers": [
{"user": {
"id": "u1", "tenant_id": "1001",
"credential": "c1"},
"credential": mock.MagicMock()},
"container": "c1",
"objects": ["o1", "o2", "o3"]}
]
@ -164,7 +165,7 @@ class SwiftObjectMixinTestCase(test.TestCase):
"containers": [
{"user": {
"id": "u2", "tenant_id": "1002",
"credential": "c2"},
"credential": mock.MagicMock()},
"container": "c2",
"objects": ["o4", "o5", "o6"]}
]

View File

@ -262,7 +262,7 @@ class VMTasksTestCase(test.ScenarioTestCase):
mock_heat.main.Stack.return_value = fake_stack
context = {
"user": {"keypair": {"name": "name", "private": "pk"},
"credential": "ok"},
"credential": mock.MagicMock()},
"tenant": {"networks": [{"router_id": "1"}]}
}
scenario = vmtasks.RuncommandHeat(context)

View File

@ -44,7 +44,9 @@ class OpenStackCredentialTestCase(test.TestCase):
"https_insecure": False,
"https_cacert": None,
"project_domain_name": None,
"user_domain_name": None}, self.credential.to_dict())
"user_domain_name": None,
"profiler_hmac_key": None},
self.credential.to_dict())
@mock.patch("rally.osclients.Clients")
def test_verify_connection_admin(self, mock_clients):
@ -127,6 +129,7 @@ class OpenStackCredentialBuilderTestCase(test.TestCase):
"endpoint_type": consts.EndpointType.INTERNAL,
"https_cacert": "cacert",
"https_insecure": False,
"profiler_hmac_key": None,
"project_domain_name": None,
"region_name": "RegionOne",
"tenant_name": "demo",
@ -143,6 +146,7 @@ class OpenStackCredentialBuilderTestCase(test.TestCase):
"endpoint_type": consts.EndpointType.INTERNAL,
"https_cacert": "cacert",
"https_insecure": False,
"profiler_hmac_key": None,
"project_domain_name": None,
"region_name": "RegionOne",
"tenant_name": "demo",

View File

@ -16,11 +16,23 @@
import ddt
import mock
from oslotest import mockpatch
from rally.plugins.openstack.credential import OpenStackCredential
from rally.plugins.openstack import scenario as base_scenario
from tests.unit import test
CREDENTIAL_WITHOUT_HMAC = OpenStackCredential(
"auth_url",
"username",
"password")
CREDENTIAL_WITH_HMAC = OpenStackCredential(
"auth_url",
"username",
"password",
profiler_hmac_key="test_profiler_hmac_key")
@ddt.ddt
class OpenStackScenarioTestCase(test.TestCase):
def setUp(self):
@ -80,6 +92,31 @@ class OpenStackScenarioTestCase(test.TestCase):
self.assertEqual("foobar", scenario._clients)
@ddt.data(([], 0),
([("admin", CREDENTIAL_WITHOUT_HMAC)], 0),
([("user", CREDENTIAL_WITHOUT_HMAC)], 0),
([("admin", CREDENTIAL_WITH_HMAC)], 1),
([("user", CREDENTIAL_WITH_HMAC)], 1),
([("admin", CREDENTIAL_WITH_HMAC),
("user", CREDENTIAL_WITH_HMAC)], 1),
([("admin", CREDENTIAL_WITHOUT_HMAC),
("user", CREDENTIAL_WITH_HMAC)], 1),
([("admin", CREDENTIAL_WITH_HMAC),
("user", CREDENTIAL_WITHOUT_HMAC)], 1),
([("admin", CREDENTIAL_WITHOUT_HMAC),
("user", CREDENTIAL_WITHOUT_HMAC)], 0))
@ddt.unpack
@mock.patch("rally.plugins.openstack.scenario.profiler.init")
def test_profiler_init(self, users_credentials,
expected_init_call_count,
mock_profiler_init):
for user, credential in users_credentials:
print(user, credential.profiler_hmac_key)
self.context.update({user: {"credential": credential}})
base_scenario.OpenStackScenario(self.context)
self.assertEqual(expected_init_call_count,
mock_profiler_init.call_count)
def test__choose_user_random(self):
users = [{"credential": mock.Mock(), "tenant_id": "foo"}
for _ in range(5)]

View File

@ -42,6 +42,7 @@ FAKE_DEPLOYMENT_CONFIG = {
"domain_name": None,
"project_domain_name": "Default",
"user_domain_name": "Default",
"profiler_hmac_key": None
},
"region_name": "RegionOne",
"endpoint_type": consts.EndpointType.INTERNAL,