Add scenario to modify Cinder volume metadata
This performs multiple modifications of Cinder volume metadata and benchmarks metadata modifications and deletions. Change-Id: Ie5b0fa14a6988d4c37dbfdedbadcc562e3250f44
This commit is contained in:
parent
957c005909
commit
a8955b0005
@ -628,6 +628,23 @@
|
||||
failure_rate:
|
||||
max: 0
|
||||
|
||||
CinderVolumes.modify_volume_metadata:
|
||||
-
|
||||
args: {}
|
||||
runner:
|
||||
type: "constant"
|
||||
times: 3
|
||||
concurrency: 3
|
||||
context:
|
||||
volumes:
|
||||
size: 1
|
||||
users:
|
||||
tenants: 1
|
||||
users_per_tenant: 1
|
||||
sla:
|
||||
failure_rate:
|
||||
max: 0
|
||||
|
||||
CinderVolumes.list_volumes:
|
||||
-
|
||||
args:
|
||||
|
@ -20,7 +20,7 @@ from oslo_config import cfg
|
||||
|
||||
from rally.benchmark.scenarios import base
|
||||
from rally.benchmark import utils as bench_utils
|
||||
|
||||
from rally import exceptions
|
||||
|
||||
CINDER_BENCHMARK_OPTS = [
|
||||
cfg.FloatOpt("cinder_volume_create_prepoll_delay",
|
||||
@ -65,6 +65,55 @@ class CinderScenario(base.Scenario):
|
||||
|
||||
return self.clients("cinder").volume_snapshots.list(detailed)
|
||||
|
||||
def _set_metadata(self, volume, sets=10, set_size=3):
|
||||
"""Set volume metadata.
|
||||
|
||||
:param volume: The volume to set metadata on
|
||||
:param sets: how many operations to perform
|
||||
:param set_size: number of metadata keys to set in each operation
|
||||
:returns: A list of keys that were set
|
||||
"""
|
||||
key = "cinder.set_%s_metadatas_%s_times" % (set_size, sets)
|
||||
with base.AtomicAction(self, key):
|
||||
keys = []
|
||||
for i in range(sets):
|
||||
metadata = {}
|
||||
for j in range(set_size):
|
||||
key = self._generate_random_name()
|
||||
keys.append(key)
|
||||
metadata[key] = self._generate_random_name()
|
||||
|
||||
self.clients("cinder").volumes.set_metadata(volume, metadata)
|
||||
return keys
|
||||
|
||||
def _delete_metadata(self, volume, keys, deletes=10, delete_size=3):
|
||||
"""Delete volume metadata keys.
|
||||
|
||||
Note that ``len(keys)`` must be greater than or equal to
|
||||
``deletes * delete_size``.
|
||||
|
||||
:param volume: The volume to delete metadata from
|
||||
:param deletes: how many operations to perform
|
||||
:param delete_size: number of metadata keys to delete in each operation
|
||||
:param keys: a list of keys to choose deletion candidates from
|
||||
"""
|
||||
if len(keys) < deletes * delete_size:
|
||||
raise exceptions.InvalidArgumentsException(
|
||||
"Not enough metadata keys to delete: "
|
||||
"%(num_keys)s keys, but asked to delete %(num_deletes)s" %
|
||||
{"num_keys": len(keys),
|
||||
"num_deletes": deletes * delete_size})
|
||||
# make a shallow copy of the list of keys so that, when we pop
|
||||
# from it later, we don't modify the original list.
|
||||
keys = list(keys)
|
||||
random.shuffle(keys)
|
||||
action_name = "cinder.delete_%s_metadatas_%s_times" % (delete_size,
|
||||
deletes)
|
||||
with base.AtomicAction(self, action_name):
|
||||
for i in range(deletes):
|
||||
to_del = keys[i * delete_size:(i + 1) * delete_size]
|
||||
self.clients("cinder").volumes.delete_metadata(volume, to_del)
|
||||
|
||||
@base.atomic_action_timer("cinder.create_volume")
|
||||
def _create_volume(self, size, **kwargs):
|
||||
"""Create one volume.
|
||||
|
@ -20,6 +20,7 @@ from rally.benchmark import types as types
|
||||
from rally.benchmark import validation
|
||||
from rally.common import log as logging
|
||||
from rally import consts
|
||||
from rally import exceptions
|
||||
from rally.plugins.openstack.scenarios.cinder import utils
|
||||
from rally.plugins.openstack.scenarios.glance import utils as glance_utils
|
||||
from rally.plugins.openstack.scenarios.nova import utils as nova_utils
|
||||
@ -135,6 +136,36 @@ class CinderVolumes(utils.CinderScenario,
|
||||
|
||||
self._create_volume(size, **kwargs)
|
||||
|
||||
@validation.required_services(consts.Service.CINDER)
|
||||
@validation.required_openstack(users=True)
|
||||
@validation.required_contexts("volumes")
|
||||
@base.scenario(context={"cleanup": ["cinder"]})
|
||||
def modify_volume_metadata(self, sets=10, set_size=3,
|
||||
deletes=5, delete_size=3):
|
||||
"""Modify a volume's metadata.
|
||||
|
||||
This requires a volume to be created with the volumes
|
||||
context. Additionally, ``sets * set_size`` must be greater
|
||||
than or equal to ``deletes * delete_size``.
|
||||
|
||||
:param sets: how many set_metadata operations to perform
|
||||
:param set_size: number of metadata keys to set in each
|
||||
set_metadata operation
|
||||
:param deletes: how many delete_metadata operations to perform
|
||||
:param delete_size: number of metadata keys to delete in each
|
||||
delete_metadata operation
|
||||
"""
|
||||
if sets * set_size < deletes * delete_size:
|
||||
raise exceptions.InvalidArgumentsException(
|
||||
"Not enough metadata keys will be created: "
|
||||
"Setting %(num_keys)s keys, but deleting %(num_deletes)s" %
|
||||
{"num_keys": sets * set_size,
|
||||
"num_deletes": deletes * delete_size})
|
||||
|
||||
volume = random.choice(self.context["tenant"]["volumes"])
|
||||
keys = self._set_metadata(volume["id"], sets, set_size)
|
||||
self._delete_metadata(volume["id"], keys, deletes, delete_size)
|
||||
|
||||
@validation.required_services(consts.Service.CINDER)
|
||||
@validation.required_openstack(users=True)
|
||||
@base.scenario(context={"cleanup": ["cinder"]})
|
||||
|
21
samples/tasks/scenarios/cinder/modify-volume-metadata.json
Normal file
21
samples/tasks/scenarios/cinder/modify-volume-metadata.json
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"CinderVolumes.modify_volume_metadata": [
|
||||
{
|
||||
"args": {},
|
||||
"runner": {
|
||||
"type": "constant",
|
||||
"times": 10,
|
||||
"concurrency": 2
|
||||
},
|
||||
"context": {
|
||||
"volumes": {
|
||||
"size": 1
|
||||
},
|
||||
"users": {
|
||||
"tenants": 2,
|
||||
"users_per_tenant": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
14
samples/tasks/scenarios/cinder/modify-volume-metadata.yaml
Normal file
14
samples/tasks/scenarios/cinder/modify-volume-metadata.yaml
Normal file
@ -0,0 +1,14 @@
|
||||
---
|
||||
CinderVolumes.modify_volume_metadata:
|
||||
-
|
||||
args: {}
|
||||
runner:
|
||||
type: "constant"
|
||||
times: 10
|
||||
concurrency: 2
|
||||
context:
|
||||
volumes:
|
||||
size: 1
|
||||
users:
|
||||
tenants: 2
|
||||
users_per_tenant: 2
|
@ -17,7 +17,9 @@ import mock
|
||||
from oslo_config import cfg
|
||||
from oslotest import mockpatch
|
||||
|
||||
from rally import exceptions
|
||||
from rally.plugins.openstack.scenarios.cinder import utils
|
||||
from tests.unit import fakes
|
||||
from tests.unit import test
|
||||
|
||||
BM_UTILS = "rally.benchmark.utils"
|
||||
@ -59,6 +61,51 @@ class CinderScenarioTestCase(test.TestCase):
|
||||
self._test_atomic_action_timer(self.scenario.atomic_actions(),
|
||||
"cinder.list_snapshots")
|
||||
|
||||
@mock.patch(CINDER_UTILS + ".CinderScenario.clients")
|
||||
def test__set_metadata(self, mock_clients):
|
||||
volume = fakes.FakeVolume()
|
||||
|
||||
self.scenario._set_metadata(volume, sets=2, set_size=4)
|
||||
calls = mock_clients("cinder").volumes.set_metadata.call_args_list
|
||||
self.assertEqual(len(calls), 2)
|
||||
for call in calls:
|
||||
call_volume, metadata = call[0]
|
||||
self.assertEqual(call_volume, volume)
|
||||
self.assertEqual(len(metadata), 4)
|
||||
|
||||
self._test_atomic_action_timer(self.scenario.atomic_actions(),
|
||||
"cinder.set_4_metadatas_2_times")
|
||||
|
||||
@mock.patch(CINDER_UTILS + ".CinderScenario.clients")
|
||||
def test__delete_metadata(self, mock_clients):
|
||||
volume = fakes.FakeVolume()
|
||||
|
||||
keys = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"]
|
||||
self.scenario._delete_metadata(volume, keys, deletes=3, delete_size=4)
|
||||
calls = mock_clients("cinder").volumes.delete_metadata.call_args_list
|
||||
self.assertEqual(len(calls), 3)
|
||||
all_deleted = []
|
||||
for call in calls:
|
||||
call_volume, del_keys = call[0]
|
||||
self.assertEqual(call_volume, volume)
|
||||
self.assertEqual(len(del_keys), 4)
|
||||
for key in del_keys:
|
||||
self.assertIn(key, keys)
|
||||
self.assertNotIn(key, all_deleted)
|
||||
all_deleted.append(key)
|
||||
|
||||
self._test_atomic_action_timer(self.scenario.atomic_actions(),
|
||||
"cinder.delete_4_metadatas_3_times")
|
||||
|
||||
@mock.patch(CINDER_UTILS + ".CinderScenario.clients")
|
||||
def test__delete_metadata_not_enough_keys(self, mock_clients):
|
||||
volume = fakes.FakeVolume()
|
||||
|
||||
keys = ["a", "b", "c", "d", "e"]
|
||||
self.assertRaises(exceptions.InvalidArgumentsException,
|
||||
self.scenario._delete_metadata,
|
||||
volume, keys, deletes=2, delete_size=3)
|
||||
|
||||
@mock.patch(CINDER_UTILS + ".CinderScenario.clients")
|
||||
def test__create_volume(self, mock_clients):
|
||||
CONF = cfg.CONF
|
||||
|
@ -66,6 +66,21 @@ class CinderServersTestCase(test.TestCase):
|
||||
scenario.create_volume(1, fakearg="f")
|
||||
scenario._create_volume.assert_called_once_with(1, fakearg="f")
|
||||
|
||||
def test_create_volume_and_modify_metadata(self):
|
||||
scenario = volumes.CinderVolumes(
|
||||
context={"user": {"tenant_id": "fake"},
|
||||
"tenant": {"id": "fake", "name": "fake",
|
||||
"volumes": [{"id": "uuid"}]}})
|
||||
scenario._set_metadata = mock.Mock()
|
||||
scenario._delete_metadata = mock.Mock()
|
||||
|
||||
scenario.modify_volume_metadata(sets=5, set_size=4,
|
||||
deletes=3, delete_size=2)
|
||||
scenario._set_metadata.assert_called_once_with("uuid", 5, 4)
|
||||
scenario._delete_metadata.assert_called_once_with(
|
||||
"uuid",
|
||||
scenario._set_metadata.return_value, 3, 2)
|
||||
|
||||
def test_create_and_extend_volume(self):
|
||||
fake_volume = mock.MagicMock()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user