diff --git a/etc/rally/rally.conf.sample b/etc/rally/rally.conf.sample index 85b3058e3f..bd2df9666c 100644 --- a/etc/rally/rally.conf.sample +++ b/etc/rally/rally.conf.sample @@ -250,6 +250,16 @@ # Server reboot poll interval (floating point value) #nova_server_reboot_poll_interval = 2.0 +# Time to sleep after rebuild before polling for status (floating point +# value) +#nova_server_rebuild_prepoll_delay = 0.0 + +# Server rebuild timeout (floating point value) +#nova_server_rebuild_timeout = 300.0 + +# Server rebuild poll interval (floating point value) +#nova_server_rebuild_poll_interval = 1.0 + # Time to sleep after rescue before polling for status (floating point # value) #nova_server_rescue_prepoll_delay = 2.0 diff --git a/rally-jobs/rally.yaml b/rally-jobs/rally.yaml index 619cf32713..ab27062a3d 100755 --- a/rally-jobs/rally.yaml +++ b/rally-jobs/rally.yaml @@ -1134,6 +1134,27 @@ failure_rate: max: 0 + NovaServers.boot_and_rebuild_server: + - + args: + flavor: + name: "m1.tiny" + from_image: + name: {{image_name}} + to_image: + name: {{image_name}} + runner: + type: "constant" + times: 3 + concurrency: 3 + context: + users: + tenants: 3 + users_per_tenant: 1 + sla: + failure_rate: + max: 0 + NovaServers.list_servers: - args: diff --git a/rally/benchmark/scenarios/nova/servers.py b/rally/benchmark/scenarios/nova/servers.py index 1cef7608a6..70f4903232 100644 --- a/rally/benchmark/scenarios/nova/servers.py +++ b/rally/benchmark/scenarios/nova/servers.py @@ -497,3 +497,26 @@ class NovaServers(utils.NovaScenario, else: self._resize_revert(server, status="SHUTOFF") self._delete_server(server) + + @types.set(from_image=types.ImageResourceType, + to_image=types.ImageResourceType, + flavor=types.FlavorResourceType) + @validation.image_valid_on_flavor("flavor", "from_image") + @validation.image_valid_on_flavor("flavor", "to_image") + @validation.required_services(consts.Service.NOVA) + @validation.required_openstack(admin=True, users=True) + @base.scenario(context={"cleanup": ["nova"]}) + def boot_and_rebuild_server(self, from_image, to_image, flavor, **kwargs): + """Rebuild a server. + + This scenario launches a VM, then rebuilds that VM with a + different image. + + :param from_image: image to be used to boot an instance + :param to_image: image to be used to rebuild the instance + :param flavor: flavor to be used to boot an instance + :param kwargs: Optional additional arguments for server creation + """ + server = self._boot_server(from_image, flavor, **kwargs) + self._rebuild_server(server, to_image) + self._delete_server(server) diff --git a/rally/benchmark/scenarios/nova/utils.py b/rally/benchmark/scenarios/nova/utils.py index 2aadf82131..2fb414f2ff 100644 --- a/rally/benchmark/scenarios/nova/utils.py +++ b/rally/benchmark/scenarios/nova/utils.py @@ -32,6 +32,7 @@ option_names_and_defaults = [ ("boot", 1, 300, 1), ("delete", 2, 300, 2), ("reboot", 2, 300, 2), + ("rebuild", 1, 300, 1), ("rescue", 2, 300, 2), ("unrescue", 2, 300, 2), ("suspend", 2, 300, 2), @@ -163,6 +164,24 @@ class NovaScenario(base.Scenario): """ self._do_server_reboot(server, "HARD") + @base.atomic_action_timer("nova.rebuild_server") + def _rebuild_server(self, server, image, **kwargs): + """Rebuild a server with a new image. + + :param server: The server to rebuild. + :param image: The new image to rebuild the server with. + :param kwargs: Optional additional arguments to pass to the rebuild + """ + server.rebuild(image, **kwargs) + time.sleep(CONF.benchmark.nova_server_rebuild_prepoll_delay) + bench_utils.wait_for( + server, + is_ready=bench_utils.resource_is("ACTIVE"), + update_resource=bench_utils.get_from_manager(), + timeout=CONF.benchmark.nova_server_rebuild_timeout, + check_interval=CONF.benchmark.nova_server_rebuild_poll_interval + ) + @base.atomic_action_timer("nova.start_server") def _start_server(self, server): """Start the given server. diff --git a/samples/tasks/scenarios/nova/boot-and-rebuild.json b/samples/tasks/scenarios/nova/boot-and-rebuild.json new file mode 100644 index 0000000000..e6abb6e6b6 --- /dev/null +++ b/samples/tasks/scenarios/nova/boot-and-rebuild.json @@ -0,0 +1,28 @@ +{ + "NovaServers.boot_and_rebuild_server": [ + { + "args": { + "flavor": { + "name": "m1.nano" + }, + "from_image": { + "name": "cirros-0.3.1-x86_64-uec" + }, + "to_image": { + "name": "cirros-0.3.2-x86_64-uec" + } + }, + "runner": { + "type": "constant", + "times": 5, + "concurrency": 2 + }, + "context": { + "users": { + "tenants": 1, + "users_per_tenant": 1 + } + } + } + ] +} diff --git a/samples/tasks/scenarios/nova/boot-and-rebuild.yaml b/samples/tasks/scenarios/nova/boot-and-rebuild.yaml new file mode 100644 index 0000000000..3942b490a3 --- /dev/null +++ b/samples/tasks/scenarios/nova/boot-and-rebuild.yaml @@ -0,0 +1,17 @@ +--- +NovaServers.boot_and_rebuild_server: +- args: + flavor: + name: m1.nano + from_image: + name: "cirros-0.3.1-x86_64-uec" + to_image: + name: "cirros-0.3.2-x86_64-uec" + runner: + type: constant + times: 5 + concurrency: 2 + context: + users: + tenants: 1 + users_per_tenant: 1 diff --git a/tests/unit/benchmark/scenarios/nova/test_servers.py b/tests/unit/benchmark/scenarios/nova/test_servers.py index 96830a4c03..b8e5d851bb 100644 --- a/tests/unit/benchmark/scenarios/nova/test_servers.py +++ b/tests/unit/benchmark/scenarios/nova/test_servers.py @@ -500,3 +500,21 @@ class NovaServersTestCase(test.TestCase): def test_boot_and_migrate_server_with_revert(self): self._test_boot_and_migrate_server(confirm=False) + + def test_boot_and_rebuild_server(self): + scenario = servers.NovaServers() + scenario._boot_server = mock.Mock() + scenario._rebuild_server = mock.Mock() + scenario._delete_server = mock.Mock() + + from_image = "img1" + to_image = "img2" + flavor = "flavor" + scenario.boot_and_rebuild_server(from_image, to_image, flavor, + fakearg="fakearg") + + scenario._boot_server.assert_called_once_with(from_image, flavor, + fakearg="fakearg") + server = scenario._boot_server.return_value + scenario._rebuild_server.assert_called_once_with(server, to_image) + scenario._delete_server.assert_called_once_with(server) diff --git a/tests/unit/benchmark/scenarios/nova/test_utils.py b/tests/unit/benchmark/scenarios/nova/test_utils.py index 26429fc037..5c5335abb9 100644 --- a/tests/unit/benchmark/scenarios/nova/test_utils.py +++ b/tests/unit/benchmark/scenarios/nova/test_utils.py @@ -333,6 +333,18 @@ class NovaScenarioTestCase(test.TestCase): self._test_atomic_action_timer(nova_scenario.atomic_actions(), "nova.soft_reboot_server") + def test__rebuild_server(self): + nova_scenario = utils.NovaScenario() + nova_scenario._rebuild_server(self.server, "img", fakearg="fakearg") + self.server.rebuild.assert_called_once_with("img", fakearg="fakearg") + self._test_assert_called_once_with( + self.wait_for.mock, self.server, + CONF.benchmark.nova_server_rebuild_poll_interval, + CONF.benchmark.nova_server_rebuild_timeout) + self.res_is.mock.assert_has_calls([mock.call("ACTIVE")]) + self._test_atomic_action_timer(nova_scenario.atomic_actions(), + "nova.rebuild_server") + def test__start_server(self): nova_scenario = utils.NovaScenario() nova_scenario._start_server(self.server)