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
acebc9e2e7
commit
c8def8766b
@ -628,6 +628,23 @@
|
|||||||
failure_rate:
|
failure_rate:
|
||||||
max: 0
|
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:
|
CinderVolumes.list_volumes:
|
||||||
-
|
-
|
||||||
args:
|
args:
|
||||||
|
@ -20,7 +20,7 @@ from oslo_config import cfg
|
|||||||
|
|
||||||
from rally.benchmark.scenarios import base
|
from rally.benchmark.scenarios import base
|
||||||
from rally.benchmark import utils as bench_utils
|
from rally.benchmark import utils as bench_utils
|
||||||
|
from rally import exceptions
|
||||||
|
|
||||||
CINDER_BENCHMARK_OPTS = [
|
CINDER_BENCHMARK_OPTS = [
|
||||||
cfg.FloatOpt("cinder_volume_create_prepoll_delay",
|
cfg.FloatOpt("cinder_volume_create_prepoll_delay",
|
||||||
@ -65,6 +65,55 @@ class CinderScenario(base.Scenario):
|
|||||||
|
|
||||||
return self.clients("cinder").volume_snapshots.list(detailed)
|
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")
|
@base.atomic_action_timer("cinder.create_volume")
|
||||||
def _create_volume(self, size, **kwargs):
|
def _create_volume(self, size, **kwargs):
|
||||||
"""Create one volume.
|
"""Create one volume.
|
||||||
|
@ -20,6 +20,7 @@ from rally.benchmark import types as types
|
|||||||
from rally.benchmark import validation
|
from rally.benchmark import validation
|
||||||
from rally.common import log as logging
|
from rally.common import log as logging
|
||||||
from rally import consts
|
from rally import consts
|
||||||
|
from rally import exceptions
|
||||||
from rally.plugins.openstack.scenarios.cinder import utils
|
from rally.plugins.openstack.scenarios.cinder import utils
|
||||||
from rally.plugins.openstack.scenarios.glance import utils as glance_utils
|
from rally.plugins.openstack.scenarios.glance import utils as glance_utils
|
||||||
from rally.plugins.openstack.scenarios.nova import utils as nova_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)
|
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_services(consts.Service.CINDER)
|
||||||
@validation.required_openstack(users=True)
|
@validation.required_openstack(users=True)
|
||||||
@base.scenario(context={"cleanup": ["cinder"]})
|
@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 oslo_config import cfg
|
||||||
from oslotest import mockpatch
|
from oslotest import mockpatch
|
||||||
|
|
||||||
|
from rally import exceptions
|
||||||
from rally.plugins.openstack.scenarios.cinder import utils
|
from rally.plugins.openstack.scenarios.cinder import utils
|
||||||
|
from tests.unit import fakes
|
||||||
from tests.unit import test
|
from tests.unit import test
|
||||||
|
|
||||||
BM_UTILS = "rally.benchmark.utils"
|
BM_UTILS = "rally.benchmark.utils"
|
||||||
@ -59,6 +61,51 @@ class CinderScenarioTestCase(test.TestCase):
|
|||||||
self._test_atomic_action_timer(self.scenario.atomic_actions(),
|
self._test_atomic_action_timer(self.scenario.atomic_actions(),
|
||||||
"cinder.list_snapshots")
|
"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")
|
@mock.patch(CINDER_UTILS + ".CinderScenario.clients")
|
||||||
def test__create_volume(self, mock_clients):
|
def test__create_volume(self, mock_clients):
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
|
@ -66,6 +66,21 @@ class CinderServersTestCase(test.TestCase):
|
|||||||
scenario.create_volume(1, fakearg="f")
|
scenario.create_volume(1, fakearg="f")
|
||||||
scenario._create_volume.assert_called_once_with(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):
|
def test_create_and_extend_volume(self):
|
||||||
fake_volume = mock.MagicMock()
|
fake_volume = mock.MagicMock()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user