diff --git a/rally-jobs/rally-neutron.yaml b/rally-jobs/rally-neutron.yaml index 58a782ff..7ca3fc41 100644 --- a/rally-jobs/rally-neutron.yaml +++ b/rally-jobs/rally-neutron.yaml @@ -856,6 +856,42 @@ failure_rate: max: 0 + CinderVolumes.create_and_restore_volume_backup: + - + args: + size: 1 + do_delete: True + runner: + type: "constant" + times: 2 + concurrency: 2 + context: + users: + tenants: 1 + users_per_tenant: 1 + roles: + - "Member" + sla: + failure_rate: + max: 0 + - + args: + size: 1 + do_delete: False + runner: + type: "constant" + times: 2 + concurrency: 2 + context: + users: + tenants: 1 + users_per_tenant: 1 + roles: + - "Member" + sla: + failure_rate: + max: 0 + VMTasks.boot_runcommand_delete: - args: diff --git a/rally/plugins/openstack/scenarios/cinder/utils.py b/rally/plugins/openstack/scenarios/cinder/utils.py index 2b4acda4..c20116cf 100644 --- a/rally/plugins/openstack/scenarios/cinder/utils.py +++ b/rally/plugins/openstack/scenarios/cinder/utils.py @@ -256,6 +256,23 @@ class CinderScenario(base.Scenario): check_interval=CONF.benchmark.cinder_volume_delete_poll_interval ) + @base.atomic_action_timer("cinder.restore_backup") + def _restore_backup(self, backup_id, volume_id=None): + """Restore the given backup. + + :param backup_id: The ID of the backup to restore. + :param volume_id: The ID of the volume to restore the backup to. + """ + restore = self.clients("cinder").restores.restore(backup_id, volume_id) + restored_volume = self.clients("cinder").volumes.get(restore.volume_id) + return bench_utils.wait_for( + restored_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 + ) + def get_random_server(self): server_id = random.choice(self.context["tenant"]["servers"]) return self.clients("nova").servers.get(server_id) diff --git a/rally/plugins/openstack/scenarios/cinder/volumes.py b/rally/plugins/openstack/scenarios/cinder/volumes.py index 8e762c64..9fa5937e 100644 --- a/rally/plugins/openstack/scenarios/cinder/volumes.py +++ b/rally/plugins/openstack/scenarios/cinder/volumes.py @@ -431,3 +431,31 @@ class CinderVolumes(utils.CinderScenario, if do_delete: self._delete_volume(volume) self._delete_backup(backup) + + @validation.required_cinder_services("cinder-backup") + @validation.required_services(consts.Service.CINDER) + @validation.required_openstack(users=True) + @base.scenario(context={"cleanup": ["cinder"]}) + def create_and_restore_volume_backup(self, size, do_delete=True, + create_volume_kwargs=None, + create_backup_kwargs=None): + """Restore volume backup. + + :param size: volume size in GB + :param do_delete: if True, the volume and the volume backup will + be deleted after creation. + :param create_volume_kwargs: optional args to create a volume + :param create_backup_kwargs: optional args to create a volume backup + """ + if create_volume_kwargs is None: + create_volume_kwargs = {} + if create_backup_kwargs is None: + create_backup_kwargs = {} + + volume = self._create_volume(size, **create_volume_kwargs) + backup = self._create_backup(volume.id, **create_backup_kwargs) + self._restore_backup(backup.id) + + if do_delete: + self._delete_volume(volume) + self._delete_backup(backup) \ No newline at end of file diff --git a/samples/tasks/scenarios/cinder/create-and-restore-volume-backup.json b/samples/tasks/scenarios/cinder/create-and-restore-volume-backup.json new file mode 100644 index 00000000..fc0f334a --- /dev/null +++ b/samples/tasks/scenarios/cinder/create-and-restore-volume-backup.json @@ -0,0 +1,22 @@ +{ + "CinderVolumes.create_and_restore_volume_backup": [ + { + "args": { + "size": 1, + "do_delete": true + }, + "runner": { + "type": "constant", + "times": 2, + "concurrency": 1 + }, + "context": { + "users": { + "tenants": 1, + "users_per_tenant": 1 + }, + "roles": ["Member"] + } + } + ] +} diff --git a/samples/tasks/scenarios/cinder/create-and-restore-volume-backup.yaml b/samples/tasks/scenarios/cinder/create-and-restore-volume-backup.yaml new file mode 100644 index 00000000..d51ff534 --- /dev/null +++ b/samples/tasks/scenarios/cinder/create-and-restore-volume-backup.yaml @@ -0,0 +1,16 @@ +--- + CinderVolumes.create_and_restore_volume_backup: + - + args: + size: 1 + do_delete: True + runner: + type: "constant" + times: 2 + concurrency: 1 + context: + users: + tenants: 1 + users_per_tenant: 1 + roles: + - "Member" \ No newline at end of file diff --git a/tests/unit/plugins/openstack/scenarios/cinder/test_utils.py b/tests/unit/plugins/openstack/scenarios/cinder/test_utils.py index ba3e5360..bd357ba2 100644 --- a/tests/unit/plugins/openstack/scenarios/cinder/test_utils.py +++ b/tests/unit/plugins/openstack/scenarios/cinder/test_utils.py @@ -237,6 +237,27 @@ class CinderScenarioTestCase(test.TestCase): self._test_atomic_action_timer(self.scenario.atomic_actions(), "cinder.delete_backup") + @mock.patch(CINDER_UTILS + ".CinderScenario.clients") + def test__restore_backup(self, mock_clients): + backup = mock.Mock() + restore = mock.Mock() + mock_clients("cinder").restores.restore.return_value = backup + mock_clients("cinder").volumes.get.return_value = restore + + return_restore = self.scenario._restore_backup(backup.id, None) + + self.wait_for.mock.assert_called_once_with( + restore, + is_ready=self.res_is.mock(), + update_resource=self.gfm(), + timeout=cfg.CONF.benchmark.cinder_volume_create_timeout, + check_interval=cfg.CONF.benchmark + .cinder_volume_create_poll_interval) + self.res_is.mock.assert_has_calls([mock.call("available")]) + self.assertEqual(self.wait_for.mock(), return_restore) + self._test_atomic_action_timer(self.scenario.atomic_actions(), + "cinder.restore_backup") + def test__get_random_server(self): servers = [1, 2, 3] context = {"user": {"tenant_id": "fake"}, diff --git a/tests/unit/plugins/openstack/scenarios/cinder/test_volumes.py b/tests/unit/plugins/openstack/scenarios/cinder/test_volumes.py index 09c7b3f7..cc732c57 100644 --- a/tests/unit/plugins/openstack/scenarios/cinder/test_volumes.py +++ b/tests/unit/plugins/openstack/scenarios/cinder/test_volumes.py @@ -397,3 +397,44 @@ class CinderServersTestCase(test.TestCase): fakearg="f") self.assertFalse(scenario._delete_volume.called) self.assertFalse(scenario._delete_backup.called) + + def _get_scenario(self, fake_volume, fake_backup, fake_restore): + scenario = volumes.CinderVolumes() + + scenario._create_volume = mock.MagicMock(return_value=fake_volume) + scenario._create_backup = mock.MagicMock(return_value=fake_backup) + scenario._restore_backup = mock.MagicMock(return_value=fake_restore) + scenario._delete_volume = mock.MagicMock() + scenario._delete_backup = mock.MagicMock() + + return scenario + + def test_create_and_restore_volume_backup(self): + fake_volume = mock.MagicMock() + fake_backup = mock.MagicMock() + fake_restore = mock.MagicMock() + scenario = self._get_scenario(fake_volume, fake_backup, fake_restore) + + volume_kwargs = {"some_var": "zaq"} + scenario.create_and_restore_volume_backup( + 1, do_delete=True, create_volume_kwargs=volume_kwargs) + scenario._create_volume.assert_called_once_with(1, **volume_kwargs) + scenario._create_backup.assert_called_once_with(fake_volume.id) + scenario._restore_backup.assert_called_once_with(fake_backup.id) + scenario._delete_volume.assert_called_once_with(fake_volume) + scenario._delete_backup.assert_called_once_with(fake_backup) + + def test_create_and_restore_volume_backup_no_delete(self): + fake_volume = mock.MagicMock() + fake_backup = mock.MagicMock() + fake_restore = mock.MagicMock() + scenario = self._get_scenario(fake_volume, fake_backup, fake_restore) + + volume_kwargs = {"some_var": "zaq"} + scenario.create_and_restore_volume_backup( + 1, do_delete=False, create_volume_kwargs=volume_kwargs) + scenario._create_volume.assert_called_once_with(1, **volume_kwargs) + scenario._create_backup.assert_called_once_with(fake_volume.id) + scenario._restore_backup.assert_called_once_with(fake_backup.id) + self.assertFalse(scenario._delete_volume.called) + self.assertFalse(scenario._delete_backup.called)