diff --git a/rally-jobs/rally-neutron.yaml b/rally-jobs/rally-neutron.yaml index 2292d2621a..5c7b9ca94f 100644 --- a/rally-jobs/rally-neutron.yaml +++ b/rally-jobs/rally-neutron.yaml @@ -556,6 +556,23 @@ failure_rate: max: 0 + CinderVolumes.create_and_extend_volume: + - + args: + size: 1 + new_size: 2 + runner: + type: "constant" + times: 2 + concurrency: 2 + context: + users: + tenants: 1 + users_per_tenant: 1 + sla: + failure_rate: + max: 0 + CinderVolumes.create_and_delete_snapshot: - args: diff --git a/rally/benchmark/scenarios/cinder/utils.py b/rally/benchmark/scenarios/cinder/utils.py index ad9ba2b3d5..8229678e88 100644 --- a/rally/benchmark/scenarios/cinder/utils.py +++ b/rally/benchmark/scenarios/cinder/utils.py @@ -101,6 +101,24 @@ class CinderScenario(base.Scenario): check_interval=CONF.benchmark.cinder_volume_delete_poll_interval ) + @base.atomic_action_timer('cinder.extend_volume') + def _extend_volume(self, volume, new_size): + """Extend the given volume. + + Returns when the volume is actually extended. + + :param volume: volume object + :param new_size: new volume size in GB + """ + volume.extend(volume, new_size) + volume = bench_utils.wait_for( + volume, + is_ready=bench_utils.resource_is("available"), + update_resource=bench_utils.get_from_manager(), + timeout=CONF.benchmark.cinder_volume_create_timeout, + check_interval=CONF.benchmark.cinder_volume_create_poll_interval + ) + @base.atomic_action_timer('cinder.create_snapshot') def _create_snapshot(self, volume_id, force=False, **kwargs): """Create one snapshot. diff --git a/rally/benchmark/scenarios/cinder/volumes.py b/rally/benchmark/scenarios/cinder/volumes.py index 8955e9b5d4..b1993b71e6 100755 --- a/rally/benchmark/scenarios/cinder/volumes.py +++ b/rally/benchmark/scenarios/cinder/volumes.py @@ -104,6 +104,27 @@ class CinderVolumes(utils.CinderScenario, """ self._create_volume(size, **kwargs) + @validation.required_services(consts.Service.CINDER) + @validation.required_openstack(users=True) + @base.scenario(context={"cleanup": ["cinder"]}) + def create_and_extend_volume(self, size, new_size, min_sleep=0, + max_sleep=0, **kwargs): + """Create and extend a volume and then delete it. + + + :param size: volume size (in GB) + :param new_size: volume new size (in GB) to extend + :param min_sleep: minimum sleep time between volume extension and + deletion (in seconds) + :param max_sleep: maximum sleep time between volume extension and + deletion (in seconds) + :param kwargs: optinal args to extend the volume + """ + volume = self._create_volume(size, **kwargs) + self._extend_volume(volume, new_size) + self.sleep_between(min_sleep, max_sleep) + self._delete_volume(volume) + @validation.required_services(consts.Service.CINDER) @validation.required_contexts("volumes") @validation.required_openstack(users=True) diff --git a/samples/tasks/scenarios/cinder/create-and-extend-volume.json b/samples/tasks/scenarios/cinder/create-and-extend-volume.json new file mode 100644 index 0000000000..4794c96e28 --- /dev/null +++ b/samples/tasks/scenarios/cinder/create-and-extend-volume.json @@ -0,0 +1,21 @@ +{ + "CinderVolumes.create_and_extend_volume": [ + { + "args": { + "size": 1, + "new_size": 2 + }, + "runner": { + "type": "constant", + "times": 2, + "concurrency": 2 + }, + "context": { + "users": { + "tenants": 1, + "users_per_tenant": 1 + } + } + } + ] +} diff --git a/samples/tasks/scenarios/cinder/create-and-extend-volume.yaml b/samples/tasks/scenarios/cinder/create-and-extend-volume.yaml new file mode 100644 index 0000000000..781e692f0f --- /dev/null +++ b/samples/tasks/scenarios/cinder/create-and-extend-volume.yaml @@ -0,0 +1,14 @@ +--- + CinderVolumes.create_and_extend_volume: + - + args: + size: 1 + new_size: 2 + runner: + type: "constant" + times: 2 + concurrency: 2 + context: + users: + tenants: 1 + users_per_tenant: 1 diff --git a/tests/unit/benchmark/scenarios/cinder/test_utils.py b/tests/unit/benchmark/scenarios/cinder/test_utils.py index aef54513f9..685863299b 100644 --- a/tests/unit/benchmark/scenarios/cinder/test_utils.py +++ b/tests/unit/benchmark/scenarios/cinder/test_utils.py @@ -81,6 +81,23 @@ class CinderScenarioTestCase(test.TestCase): self._test_atomic_action_timer(self.scenario.atomic_actions(), 'cinder.delete_volume') + @mock.patch(CINDER_UTILS + '.CinderScenario.clients') + def test__extend_volume(self, mock_clients): + CONF = cfg.CONF + volume = mock.Mock() + mock_clients('cinder').volumes.extend.return_value = volume + self.scenario._extend_volume(volume, 2) + self.wait_for.mock.assert_called_once_with( + volume, + is_ready=self.res_is.mock(), + update_resource=self.gfm(), + timeout=CONF.benchmark.cinder_volume_create_timeout, + check_interval=CONF.benchmark.cinder_volume_create_poll_interval + ) + self.res_is.mock.assert_has_calls([mock.call('available')]) + self._test_atomic_action_timer(self.scenario.atomic_actions(), + 'cinder.extend_volume') + @mock.patch(CINDER_UTILS + '.CinderScenario.clients') def test__create_snapshot(self, mock_clients): snapshot = mock.Mock() diff --git a/tests/unit/benchmark/scenarios/cinder/test_volumes.py b/tests/unit/benchmark/scenarios/cinder/test_volumes.py index da3d0fc403..7d9f30d823 100644 --- a/tests/unit/benchmark/scenarios/cinder/test_volumes.py +++ b/tests/unit/benchmark/scenarios/cinder/test_volumes.py @@ -64,6 +64,21 @@ class CinderServersTestCase(test.TestCase): scenario.create_volume(1, fakearg="f") scenario._create_volume.assert_called_once_with(1, fakearg="f") + def test_create_and_extend_volume(self): + fake_volume = mock.MagicMock() + + scenario = volumes.CinderVolumes() + scenario._create_volume = mock.MagicMock(return_value=fake_volume) + scenario._extend_volume = mock.MagicMock(return_value=fake_volume) + scenario.sleep_between = mock.MagicMock() + scenario._delete_volume = mock.MagicMock() + + scenario.create_and_extend_volume(1, 2, 10, 20, fakearg="f") + scenario._create_volume.assert_called_once_with(1, fakearg="f") + self.assertTrue(scenario._extend_volume.called) + scenario.sleep_between.assert_called_once_with(10, 20) + scenario._delete_volume.assert_called_once_with(fake_volume) + def test_create_and_delete_snapshot(self): fake_snapshot = mock.MagicMock() scenario = volumes.CinderVolumes(