From 0993e8f42a87d510863d208857bb9df89e060000 Mon Sep 17 00:00:00 2001 From: zhangzhang Date: Fri, 21 Apr 2017 13:04:46 -0400 Subject: [PATCH] Add cinder.CreateAndSetQos scenario Create a qos, then Add/Update keys in qos specs. Change-Id: I26fe73d1b4833ca23023698e22ee8387d358d786 --- rally-jobs/cinder.yaml | 23 +++++++- .../openstack/scenarios/cinder/qos_specs.py | 57 +++++++++++++++++-- .../openstack/services/storage/block.py | 13 ++++- .../services/storage/cinder_common.py | 25 +++++++- .../scenarios/cinder/create-and-get-qos.json | 8 +-- .../scenarios/cinder/create-and-get-qos.yaml | 7 +-- .../scenarios/cinder/create-and-list-qos.json | 8 +-- .../scenarios/cinder/create-and-list-qos.yaml | 7 +-- .../scenarios/cinder/create-and-set-qos.json | 30 ++++++++++ .../scenarios/cinder/create-and-set-qos.yaml | 21 +++++++ .../scenarios/cinder/test_qos_specs.py | 25 +++++++- .../openstack/services/storage/test_block.py | 8 +++ .../services/storage/test_cinder_common.py | 26 ++++++++- 13 files changed, 226 insertions(+), 32 deletions(-) create mode 100644 samples/tasks/scenarios/cinder/create-and-set-qos.json create mode 100644 samples/tasks/scenarios/cinder/create-and-set-qos.yaml diff --git a/rally-jobs/cinder.yaml b/rally-jobs/cinder.yaml index e45bd503..dcda13eb 100755 --- a/rally-jobs/cinder.yaml +++ b/rally-jobs/cinder.yaml @@ -1081,7 +1081,6 @@ CinderQos.create_and_list_qos: - args: - specs: consumer: "both" write_iops_sec: "10" read_iops_sec: "1000" @@ -1100,7 +1099,6 @@ CinderQos.create_and_get_qos: - args: - specs: consumer: "both" write_iops_sec: "10" read_iops_sec: "1000" @@ -1169,3 +1167,24 @@ sla: failure_rate: max: 0 + + CinderQos.create_and_set_qos: + - + args: + consumer: "back-end" + write_iops_sec: "10" + read_iops_sec: "1000" + set_consumer: "both" + set_write_iops_sec: "11" + set_read_iops_sec: "1001" + runner: + type: "constant" + times: 5 + concurrency: 2 + context: + users: + tenants: 2 + users_per_tenant: 2 + sla: + failure_rate: + max: 0 diff --git a/rally/plugins/openstack/scenarios/cinder/qos_specs.py b/rally/plugins/openstack/scenarios/cinder/qos_specs.py index 4a3bb14a..b3a99c09 100644 --- a/rally/plugins/openstack/scenarios/cinder/qos_specs.py +++ b/rally/plugins/openstack/scenarios/cinder/qos_specs.py @@ -27,11 +27,19 @@ from rally.task import validation @scenario.configure(context={"admin_cleanup": ["cinder"]}, name="CinderQos.create_and_list_qos") class CreateAndListQos(cinder_utils.CinderBasic): - def run(self, specs): - """create a qos, then list all qos. + def run(self, consumer, write_iops_sec, read_iops_sec): + """Create a qos, then list all qos. - :param specs: A dict of key/value pairs to create qos + :param consumer: Consumer behavior + :param write_iops_sec: random write limitation + :param read_iops_sec: random read limitation """ + specs = { + "consumer": consumer, + "write_iops_sec": write_iops_sec, + "read_iops_sec": read_iops_sec + } + qos = self.admin_cinder.create_qos(specs) pool_list = self.admin_cinder.list_qos() @@ -47,10 +55,49 @@ class CreateAndListQos(cinder_utils.CinderBasic): @scenario.configure(context={"admin_cleanup": ["cinder"]}, name="CinderQos.create_and_get_qos") class CreateAndGetQos(cinder_utils.CinderBasic): - def run(self, specs): + def run(self, consumer, write_iops_sec, read_iops_sec): """Create a qos, then get details of the qos. - :param specs: A dict of key/value pairs to create qos + :param consumer: Consumer behavior + :param write_iops_sec: random write limitation + :param read_iops_sec: random read limitation """ + specs = { + "consumer": consumer, + "write_iops_sec": write_iops_sec, + "read_iops_sec": read_iops_sec + } + qos = self.admin_cinder.create_qos(specs) self.admin_cinder.get_qos(qos.id) + + +@validation.add("required_services", services=[consts.Service.CINDER]) +@validation.add("required_platform", platform="openstack", admin=True) +@scenario.configure(context={"admin_cleanup": ["cinder"]}, + name="CinderQos.create_and_set_qos") +class CreateAndSetQos(cinder_utils.CinderBasic): + def run(self, consumer, write_iops_sec, read_iops_sec, + set_consumer, set_write_iops_sec, set_read_iops_sec): + """Create a qos, then Add/Update keys in qos specs. + + :param consumer: Consumer behavior + :param write_iops_sec: random write limitation + :param read_iops_sec: random read limitation + :param set_consumer: update Consumer behavior + :param set_write_iops_sec: update random write limitation + :param set_read_iops_sec: update random read limitation + """ + create_specs = { + "consumer": consumer, + "write_iops_sec": write_iops_sec, + "read_iops_sec": read_iops_sec + } + set_specs = { + "consumer": set_consumer, + "write_iops_sec": set_write_iops_sec, + "read_iops_sec": set_read_iops_sec + } + + qos = self.admin_cinder.create_qos(create_specs) + self.admin_cinder.set_qos(qos=qos, set_specs_args=set_specs) diff --git a/rally/plugins/openstack/services/storage/block.py b/rally/plugins/openstack/services/storage/block.py index d8c2e8c1..df3ced05 100644 --- a/rally/plugins/openstack/services/storage/block.py +++ b/rally/plugins/openstack/services/storage/block.py @@ -34,7 +34,7 @@ VolumeTransfer = collections.namedtuple("VolumeTransfer", ["id", "name", "auth_key"]) VolumeEncryptionType = collections.namedtuple("VolumeEncryptionType", ["id", "volume_type_id"]) -QoSSpecs = collections.namedtuple("QoSSpecs", ["id", "name"]) +QoSSpecs = collections.namedtuple("QoSSpecs", ["id", "name", "specs"]) class BlockStorage(service.UnifiedService): @@ -217,6 +217,17 @@ class BlockStorage(service.UnifiedService): """ return self._impl.get_qos(qos_id) + @service.should_be_overridden + def set_qos(self, qos, set_specs_args): + """Add/Update keys in qos specs. + + :param qos: The instance of the :class:`QoSSpecs` to set + :param set_specs_args: A dict of key/value pairs to be set + :rtype: :class:`QoSSpecs` + """ + return self._impl.set_qos(qos=qos, + set_specs_args=set_specs_args) + @service.should_be_overridden def create_snapshot(self, volume_id, force=False, name=None, description=None, metadata=None): diff --git a/rally/plugins/openstack/services/storage/cinder_common.py b/rally/plugins/openstack/services/storage/cinder_common.py index e8f150e0..ae982104 100644 --- a/rally/plugins/openstack/services/storage/cinder_common.py +++ b/rally/plugins/openstack/services/storage/cinder_common.py @@ -235,6 +235,19 @@ class CinderMixin(object): with atomic.ActionTimer(self, aname): return self._get_client().qos_specs.get(qos_id) + def set_qos(self, qos_id, set_specs_args): + """Add/Update keys in qos specs. + + :param qos_id: The ID of the :class:`QoSSpecs` to get + :param set_specs_args: A dict of key/value pairs to be set + :rtype: class 'cinderclient.apiclient.base.DictWithMeta' + {"qos_specs": set_specs_args} + """ + aname = "cinder_v%s.set_qos" % self.version + with atomic.ActionTimer(self, aname): + return self._get_client().qos_specs.set_keys(qos_id, + set_specs_args) + def delete_snapshot(self, snapshot): """Delete the given snapshot. @@ -444,7 +457,7 @@ class UnifiedCinderMixin(object): @staticmethod def _unify_qos(qos): - return block.QoSSpecs(id=qos.id, name=qos.name) + return block.QoSSpecs(id=qos.id, name=qos.name, specs=qos.specs) @staticmethod def _unify_encryption_type(encryption_type): @@ -534,6 +547,16 @@ class UnifiedCinderMixin(object): """ return self._unify_qos(self._impl.get_qos(qos_id)) + def set_qos(self, qos, set_specs_args): + """Add/Update keys in qos specs. + + :param qos: The instance of the :class:`QoSSpecs` to set + :param set_specs_args: A dict of key/value pairs to be set + :rtype: :class: 'QoSSpecs' + """ + self._impl.set_qos(qos.id, set_specs_args) + return self._unify_qos(qos) + def delete_snapshot(self, snapshot): """Delete the given backup. diff --git a/samples/tasks/scenarios/cinder/create-and-get-qos.json b/samples/tasks/scenarios/cinder/create-and-get-qos.json index c9c08f2e..6a10f111 100644 --- a/samples/tasks/scenarios/cinder/create-and-get-qos.json +++ b/samples/tasks/scenarios/cinder/create-and-get-qos.json @@ -2,11 +2,9 @@ "CinderQos.create_and_get_qos": [ { "args": { - "specs": { - "consumer": "both", - "write_iops_sec": "10", - "read_iops_sec": "1000" - } + "consumer": "both", + "write_iops_sec": "10", + "read_iops_sec": "1000" }, "runner": { "type": "constant", diff --git a/samples/tasks/scenarios/cinder/create-and-get-qos.yaml b/samples/tasks/scenarios/cinder/create-and-get-qos.yaml index 40d1c48e..1ba83b49 100644 --- a/samples/tasks/scenarios/cinder/create-and-get-qos.yaml +++ b/samples/tasks/scenarios/cinder/create-and-get-qos.yaml @@ -2,10 +2,9 @@ CinderQos.create_and_get_qos: - args: - specs: - consumer: "both" - write_iops_sec: "10" - read_iops_sec: "1000" + consumer: "both" + write_iops_sec: "10" + read_iops_sec: "1000" runner: type: "constant" times: 5 diff --git a/samples/tasks/scenarios/cinder/create-and-list-qos.json b/samples/tasks/scenarios/cinder/create-and-list-qos.json index 0caeeec0..e48d4a8c 100644 --- a/samples/tasks/scenarios/cinder/create-and-list-qos.json +++ b/samples/tasks/scenarios/cinder/create-and-list-qos.json @@ -2,11 +2,9 @@ "CinderQos.create_and_list_qos": [ { "args": { - "specs": { - "consumer": "both", - "write_iops_sec": "10", - "read_iops_sec": "1000" - } + "consumer": "both", + "write_iops_sec": "10", + "read_iops_sec": "1000" }, "runner": { "type": "constant", diff --git a/samples/tasks/scenarios/cinder/create-and-list-qos.yaml b/samples/tasks/scenarios/cinder/create-and-list-qos.yaml index 9c30966c..294199a0 100644 --- a/samples/tasks/scenarios/cinder/create-and-list-qos.yaml +++ b/samples/tasks/scenarios/cinder/create-and-list-qos.yaml @@ -2,10 +2,9 @@ CinderQos.create_and_list_qos: - args: - specs: - consumer: "both" - write_iops_sec: "10" - read_iops_sec: "1000" + consumer: "both" + write_iops_sec: "10" + read_iops_sec: "1000" runner: type: "constant" times: 5 diff --git a/samples/tasks/scenarios/cinder/create-and-set-qos.json b/samples/tasks/scenarios/cinder/create-and-set-qos.json new file mode 100644 index 00000000..b206e133 --- /dev/null +++ b/samples/tasks/scenarios/cinder/create-and-set-qos.json @@ -0,0 +1,30 @@ +{ + "CinderQos.create_and_set_qos": [ + { + "args": { + "consumer": "back-end", + "write_iops_sec": "10", + "read_iops_sec": "1000", + "set_consumer": "both", + "set_write_iops_sec": "11", + "set_read_iops_sec": "1001" + }, + "runner": { + "type": "constant", + "times": 5, + "concurrency": 2 + }, + "context": { + "users": { + "tenants": 2, + "users_per_tenant": 2 + } + }, + "sla": { + "failure_rate": { + "max": 0 + } + } + } + ] +} diff --git a/samples/tasks/scenarios/cinder/create-and-set-qos.yaml b/samples/tasks/scenarios/cinder/create-and-set-qos.yaml new file mode 100644 index 00000000..285b6472 --- /dev/null +++ b/samples/tasks/scenarios/cinder/create-and-set-qos.yaml @@ -0,0 +1,21 @@ +--- + CinderQos.create_and_set_qos: + - + args: + consumer: "back-end" + write_iops_sec: "10" + read_iops_sec: "1000" + set_consumer: "both" + set_write_iops_sec: "11" + set_read_iops_sec: "1001" + runner: + type: "constant" + times: 5 + concurrency: 2 + context: + users: + tenants: 2 + users_per_tenant: 2 + sla: + failure_rate: + max: 0 diff --git a/tests/unit/plugins/openstack/scenarios/cinder/test_qos_specs.py b/tests/unit/plugins/openstack/scenarios/cinder/test_qos_specs.py index d2825155..8df5535a 100644 --- a/tests/unit/plugins/openstack/scenarios/cinder/test_qos_specs.py +++ b/tests/unit/plugins/openstack/scenarios/cinder/test_qos_specs.py @@ -55,7 +55,7 @@ class CinderQosTestCase(test.ScenarioTestCase): mock_service.create_qos.return_value = qos mock_service.list_qos.return_value = list_qos - scenario.run(specs) + scenario.run("both", "10", "1000") mock_service.create_qos.assert_called_once_with(specs) mock_service.list_qos.assert_called_once_with() @@ -74,7 +74,7 @@ class CinderQosTestCase(test.ScenarioTestCase): mock_service.list_qos.return_value = list_qos self.assertRaises(rally_exceptions.RallyAssertionError, - scenario.run, specs) + scenario.run, "both", "10", "1000") mock_service.create_qos.assert_called_once_with(specs) mock_service.list_qos.assert_called_once_with() @@ -88,6 +88,25 @@ class CinderQosTestCase(test.ScenarioTestCase): scenario = qos_specs.CreateAndGetQos(self._get_context()) mock_service.create_qos.return_value = qos - scenario.run(specs) + scenario.run("both", "10", "1000") mock_service.create_qos.assert_called_once_with(specs) mock_service.get_qos.assert_called_once_with(qos.id) + + def test_create_and_set_qos(self): + mock_service = self.mock_cinder.return_value + qos = mock.MagicMock() + create_specs_args = {"consumer": "back-end", + "write_iops_sec": "10", + "read_iops_sec": "1000"} + + set_specs_args = {"consumer": "both", + "write_iops_sec": "11", + "read_iops_sec": "1001"} + scenario = qos_specs.CreateAndSetQos(self._get_context()) + mock_service.create_qos.return_value = qos + + scenario.run("back-end", "10", "1000", + "both", "11", "1001") + mock_service.create_qos.assert_called_once_with(create_specs_args) + mock_service.set_qos.assert_called_once_with( + qos=qos, set_specs_args=set_specs_args) diff --git a/tests/unit/plugins/openstack/services/storage/test_block.py b/tests/unit/plugins/openstack/services/storage/test_block.py index 2010f3e4..0049cee4 100644 --- a/tests/unit/plugins/openstack/services/storage/test_block.py +++ b/tests/unit/plugins/openstack/services/storage/test_block.py @@ -137,6 +137,14 @@ class BlockTestCase(test.TestCase): self.service.get_qos("qos")) self.service._impl.get_qos.assert_called_once_with("qos") + def test_set_qos(self): + set_specs_args = {"test": "foo"} + self.assertEqual( + self.service._impl.set_qos.return_value, + self.service.set_qos(qos="qos", set_specs_args=set_specs_args)) + self.service._impl.set_qos.assert_called_once_with( + qos="qos", set_specs_args=set_specs_args) + def test_create_snapshot(self): self.assertEqual( self.service._impl.create_snapshot.return_value, diff --git a/tests/unit/plugins/openstack/services/storage/test_cinder_common.py b/tests/unit/plugins/openstack/services/storage/test_cinder_common.py index 169b4689..bc993b4c 100644 --- a/tests/unit/plugins/openstack/services/storage/test_cinder_common.py +++ b/tests/unit/plugins/openstack/services/storage/test_cinder_common.py @@ -258,6 +258,15 @@ class CinderMixinTestCase(test.ScenarioTestCase): result) self.cinder.qos_specs.get.assert_called_once_with("qos") + def test_set_qos(self): + set_specs_args = {"test": "foo"} + result = self.service.set_qos("qos", set_specs_args) + self.assertEqual( + self.cinder.qos_specs.set_keys.return_value, + result) + self.cinder.qos_specs.set_keys.assert_called_once_with("qos", + set_specs_args) + def test_delete_snapshot(self): snapshot = mock.Mock() self.service.delete_snapshot(snapshot) @@ -466,10 +475,12 @@ class UnifiedCinderMixinTestCase(test.TestCase): def test__unify_qos(self): class Qos(object): id = 1 - name = "transfer" + name = "qos" + specs = {"key1": "value1"} qos = self.service._unify_qos(Qos()) self.assertEqual(1, qos.id) - self.assertEqual("transfer", qos.name) + self.assertEqual("qos", qos.name) + self.assertEqual({"key1": "value1"}, qos.specs) def test__unify_encryption_type(self): class SomeEncryptionType(object): @@ -549,6 +560,17 @@ class UnifiedCinderMixinTestCase(test.TestCase): self.service._impl.get_qos.return_value ) + def test_set_qos(self): + set_specs_args = {"test": "foo"} + self.service._unify_qos = mock.MagicMock() + qos = mock.MagicMock() + self.assertEqual( + self.service._unify_qos.return_value, + self.service.set_qos(qos, set_specs_args)) + self.service._impl.set_qos.assert_called_once_with(qos.id, + set_specs_args) + self.service._unify_qos.assert_called_once_with(qos) + def test_delete_snapshot(self): self.service.delete_snapshot("snapshot") self.service._impl.delete_snapshot.assert_called_once_with("snapshot")