Add cold migrate scenario for Nova test
Current Rally provides "boot_and_live_migrate_server" scenario, but doesn't provide cold migration scenario. This patch adds the scenario named "boot_and_migrate_server". Change-Id: I681b66475f1a455e33d78e63abd73f67d3960e52
This commit is contained in:
parent
930394d3e9
commit
4635a212e6
@ -349,3 +349,33 @@ class NovaServers(utils.NovaScenario,
|
|||||||
block_migration, disk_over_commit)
|
block_migration, disk_over_commit)
|
||||||
|
|
||||||
self._delete_server(server)
|
self._delete_server(server)
|
||||||
|
|
||||||
|
@types.set(image=types.ImageResourceType,
|
||||||
|
flavor=types.FlavorResourceType)
|
||||||
|
@validation.image_valid_on_flavor("flavor", "image")
|
||||||
|
@validation.required_services(consts.Service.NOVA)
|
||||||
|
@validation.required_openstack(admin=True, users=True)
|
||||||
|
@base.scenario(context={"cleanup": ["nova"]})
|
||||||
|
def boot_and_migrate_server(self, image, flavor, **kwargs):
|
||||||
|
"""Migrate a server.
|
||||||
|
|
||||||
|
This scenario launches a VM on a compute node available in
|
||||||
|
the availability zone and stops the VM, and then migrates the VM
|
||||||
|
to another compute node on the same availability zone.
|
||||||
|
|
||||||
|
:param image: image to be used to boot an instance
|
||||||
|
:param flavor: flavor to be used to boot an instance
|
||||||
|
:param kwargs: Optional additional arguments for server creation
|
||||||
|
"""
|
||||||
|
server = self._boot_server(self._generate_random_name(),
|
||||||
|
image, flavor, **kwargs)
|
||||||
|
self._stop_server(server)
|
||||||
|
self._migrate(server)
|
||||||
|
# NOTE(wtakase): This is required because cold migration and resize
|
||||||
|
# share same code path.
|
||||||
|
confirm = kwargs.get("confirm", True)
|
||||||
|
if confirm:
|
||||||
|
self._resize_confirm(server, status="SHUTOFF")
|
||||||
|
else:
|
||||||
|
self._resize_revert(server, status="SHUTOFF")
|
||||||
|
self._delete_server(server)
|
||||||
|
@ -41,6 +41,7 @@ option_names_and_defaults = [
|
|||||||
('resize_confirm', 0, 200, 2),
|
('resize_confirm', 0, 200, 2),
|
||||||
('resize_revert', 0, 200, 2),
|
('resize_revert', 0, 200, 2),
|
||||||
('live_migrate', 1, 400, 2),
|
('live_migrate', 1, 400, 2),
|
||||||
|
('migrate', 1, 400, 2),
|
||||||
]
|
]
|
||||||
|
|
||||||
for action, prepoll, timeout, poll in option_names_and_defaults:
|
for action, prepoll, timeout, poll in option_names_and_defaults:
|
||||||
@ -454,11 +455,11 @@ class NovaScenario(base.Scenario):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@base.atomic_action_timer('nova.resize_confirm')
|
@base.atomic_action_timer('nova.resize_confirm')
|
||||||
def _resize_confirm(self, server):
|
def _resize_confirm(self, server, status="ACTIVE"):
|
||||||
server.confirm_resize()
|
server.confirm_resize()
|
||||||
bench_utils.wait_for(
|
bench_utils.wait_for(
|
||||||
server,
|
server,
|
||||||
is_ready=bench_utils.resource_is("ACTIVE"),
|
is_ready=bench_utils.resource_is(status),
|
||||||
update_resource=bench_utils.get_from_manager(),
|
update_resource=bench_utils.get_from_manager(),
|
||||||
timeout=CONF.benchmark.nova_server_resize_confirm_timeout,
|
timeout=CONF.benchmark.nova_server_resize_confirm_timeout,
|
||||||
check_interval=(
|
check_interval=(
|
||||||
@ -466,11 +467,11 @@ class NovaScenario(base.Scenario):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@base.atomic_action_timer('nova.resize_revert')
|
@base.atomic_action_timer('nova.resize_revert')
|
||||||
def _resize_revert(self, server):
|
def _resize_revert(self, server, status="ACTIVE"):
|
||||||
server.revert_resize()
|
server.revert_resize()
|
||||||
bench_utils.wait_for(
|
bench_utils.wait_for(
|
||||||
server,
|
server,
|
||||||
is_ready=bench_utils.resource_is("ACTIVE"),
|
is_ready=bench_utils.resource_is(status),
|
||||||
update_resource=bench_utils.get_from_manager(),
|
update_resource=bench_utils.get_from_manager(),
|
||||||
timeout=CONF.benchmark.nova_server_resize_revert_timeout,
|
timeout=CONF.benchmark.nova_server_resize_revert_timeout,
|
||||||
check_interval=(
|
check_interval=(
|
||||||
@ -565,6 +566,33 @@ class NovaScenario(base.Scenario):
|
|||||||
raise exceptions.InvalidHostException(
|
raise exceptions.InvalidHostException(
|
||||||
"No valid host found to migrate")
|
"No valid host found to migrate")
|
||||||
|
|
||||||
|
@base.atomic_action_timer('nova.migrate')
|
||||||
|
def _migrate(self, server, skip_host_check=False):
|
||||||
|
"""Run migration of the given server.
|
||||||
|
|
||||||
|
:param server: Server object
|
||||||
|
:param skip_host_check: Specifies whether to verify the targeted host
|
||||||
|
availability
|
||||||
|
"""
|
||||||
|
server_admin = self.admin_clients("nova").servers.get(server.id)
|
||||||
|
host_pre_migrate = getattr(server_admin, "OS-EXT-SRV-ATTR:host")
|
||||||
|
server_admin.migrate()
|
||||||
|
bench_utils.wait_for(
|
||||||
|
server,
|
||||||
|
is_ready=bench_utils.resource_is("VERIFY_RESIZE"),
|
||||||
|
update_resource=bench_utils.get_from_manager(),
|
||||||
|
timeout=CONF.benchmark.nova_server_migrate_timeout,
|
||||||
|
check_interval=(
|
||||||
|
CONF.benchmark.nova_server_migrate_poll_interval)
|
||||||
|
)
|
||||||
|
if not skip_host_check:
|
||||||
|
server_admin = self.admin_clients("nova").servers.get(server.id)
|
||||||
|
host_after_migrate = getattr(server_admin, "OS-EXT-SRV-ATTR:host")
|
||||||
|
if host_pre_migrate == host_after_migrate:
|
||||||
|
raise exceptions.MigrateException(
|
||||||
|
"Migration complete but instance did not change host: %s" %
|
||||||
|
host_pre_migrate)
|
||||||
|
|
||||||
def _create_security_groups(self, security_group_count):
|
def _create_security_groups(self, security_group_count):
|
||||||
security_groups = []
|
security_groups = []
|
||||||
with base.AtomicAction(self, "nova.create_%s_security_groups" %
|
with base.AtomicAction(self, "nova.create_%s_security_groups" %
|
||||||
|
@ -260,5 +260,9 @@ class LiveMigrateException(RallyException):
|
|||||||
msg_fmt = _("Live Migration failed: %(message)s")
|
msg_fmt = _("Live Migration failed: %(message)s")
|
||||||
|
|
||||||
|
|
||||||
|
class MigrateException(RallyException):
|
||||||
|
msg_fmt = _("Migration failed: %(message)s")
|
||||||
|
|
||||||
|
|
||||||
class InvalidHostException(RallyException):
|
class InvalidHostException(RallyException):
|
||||||
msg_fmt = _("Live Migration failed: %(message)s")
|
msg_fmt = _("Live Migration failed: %(message)s")
|
||||||
|
25
samples/tasks/scenarios/nova/boot-and-migrate.json
Normal file
25
samples/tasks/scenarios/nova/boot-and-migrate.json
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"NovaServers.boot_and_migrate_server": [
|
||||||
|
{
|
||||||
|
"args": {
|
||||||
|
"flavor": {
|
||||||
|
"name": "m1.nano"
|
||||||
|
},
|
||||||
|
"image": {
|
||||||
|
"name": "^cirros.*uec$"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"runner": {
|
||||||
|
"type": "constant",
|
||||||
|
"times": 10,
|
||||||
|
"concurrency": 2
|
||||||
|
},
|
||||||
|
"context": {
|
||||||
|
"users": {
|
||||||
|
"tenants": 1,
|
||||||
|
"users_per_tenant": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
15
samples/tasks/scenarios/nova/boot-and-migrate.yaml
Normal file
15
samples/tasks/scenarios/nova/boot-and-migrate.yaml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
NovaServers.boot_and_migrate_server:
|
||||||
|
- args:
|
||||||
|
flavor:
|
||||||
|
name: m1.nano
|
||||||
|
image:
|
||||||
|
name: "^cirros.*uec$"
|
||||||
|
runner:
|
||||||
|
type: constant
|
||||||
|
times: 10
|
||||||
|
concurrency: 2
|
||||||
|
context:
|
||||||
|
users:
|
||||||
|
tenants: 1
|
||||||
|
users_per_tenant: 1
|
@ -350,3 +350,42 @@ class NovaServersTestCase(test.TestCase):
|
|||||||
"host_name",
|
"host_name",
|
||||||
False, False)
|
False, False)
|
||||||
scenario._delete_server.assert_called_once_with(fake_server)
|
scenario._delete_server.assert_called_once_with(fake_server)
|
||||||
|
|
||||||
|
def _test_boot_and_migrate_server(self, confirm=False):
|
||||||
|
fake_server = mock.MagicMock()
|
||||||
|
|
||||||
|
scenario = servers.NovaServers()
|
||||||
|
scenario._generate_random_name = mock.MagicMock(return_value="name")
|
||||||
|
scenario._boot_server = mock.MagicMock(return_value=fake_server)
|
||||||
|
scenario._stop_server = mock.MagicMock()
|
||||||
|
scenario._migrate = mock.MagicMock()
|
||||||
|
scenario._resize_confirm = mock.MagicMock()
|
||||||
|
scenario._resize_revert = mock.MagicMock()
|
||||||
|
scenario._delete_server = mock.MagicMock()
|
||||||
|
|
||||||
|
kwargs = {"confirm": confirm}
|
||||||
|
scenario.boot_and_migrate_server("img", 0,
|
||||||
|
fakearg="fakearg", **kwargs)
|
||||||
|
|
||||||
|
scenario._boot_server.assert_called_once_with("name", "img", 0,
|
||||||
|
fakearg="fakearg",
|
||||||
|
confirm=confirm)
|
||||||
|
|
||||||
|
scenario._stop_server.assert_called_once_with(fake_server)
|
||||||
|
|
||||||
|
scenario._migrate.assert_called_once_with(fake_server)
|
||||||
|
|
||||||
|
if confirm:
|
||||||
|
scenario._resize_confirm.assert_called_once_with(fake_server,
|
||||||
|
status="SHUTOFF")
|
||||||
|
else:
|
||||||
|
scenario._resize_revert.assert_called_once_with(fake_server,
|
||||||
|
status="SHUTOFF")
|
||||||
|
|
||||||
|
scenario._delete_server.assert_called_once_with(fake_server)
|
||||||
|
|
||||||
|
def test_boot_and_migrate_server_with_confirm(self):
|
||||||
|
self._test_boot_and_migrate_server(confirm=True)
|
||||||
|
|
||||||
|
def test_boot_and_migrate_server_with_revert(self):
|
||||||
|
self._test_boot_and_migrate_server(confirm=False)
|
||||||
|
@ -567,6 +567,26 @@ class NovaScenarioTestCase(test.TestCase):
|
|||||||
self.assertIn(
|
self.assertIn(
|
||||||
nova_scenario._find_host_to_migrate(fake_server), ["b1", "b3"])
|
nova_scenario._find_host_to_migrate(fake_server), ["b1", "b3"])
|
||||||
|
|
||||||
|
@mock.patch(NOVA_UTILS + '.NovaScenario.clients')
|
||||||
|
def test__migrate_server(self, mock_clients):
|
||||||
|
fake_server = self.server
|
||||||
|
setattr(fake_server, "OS-EXT-SRV-ATTR:host", "a1")
|
||||||
|
mock_clients("nova").servers.get(return_value=fake_server)
|
||||||
|
nova_scenario = utils.NovaScenario(admin_clients=mock_clients)
|
||||||
|
nova_scenario._migrate(fake_server, skip_host_check=True)
|
||||||
|
|
||||||
|
self._test_assert_called_once_with(
|
||||||
|
self.wait_for.mock, fake_server,
|
||||||
|
CONF.benchmark.nova_server_migrate_poll_interval,
|
||||||
|
CONF.benchmark.nova_server_migrate_timeout)
|
||||||
|
self.res_is.mock.assert_has_calls([mock.call("VERIFY_RESIZE")])
|
||||||
|
self._test_atomic_action_timer(nova_scenario.atomic_actions(),
|
||||||
|
"nova.migrate")
|
||||||
|
|
||||||
|
self.assertRaises(rally_exceptions.MigrateException,
|
||||||
|
nova_scenario._migrate,
|
||||||
|
fake_server, skip_host_check=False)
|
||||||
|
|
||||||
def test__create_security_groups(self):
|
def test__create_security_groups(self):
|
||||||
clients = mock.MagicMock()
|
clients = mock.MagicMock()
|
||||||
nova_scenario = utils.NovaScenario()
|
nova_scenario = utils.NovaScenario()
|
||||||
|
Loading…
Reference in New Issue
Block a user