Merge "Add scenarios for live migration of an instance with volumes"
This commit is contained in:
commit
64e210db2d
@ -341,6 +341,94 @@ class NovaServers(utils.NovaScenario,
|
||||
|
||||
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, consts.Service.CINDER)
|
||||
@validation.required_openstack(admin=True, users=True)
|
||||
@base.scenario(context={"cleanup": ["nova", "cinder"]})
|
||||
def boot_server_from_volume_and_live_migrate(self, image, flavor,
|
||||
volume_size,
|
||||
block_migration=False,
|
||||
disk_over_commit=False,
|
||||
force_delete=False, **kwargs):
|
||||
"""Boot a server from volume and then migrate it.
|
||||
|
||||
The scenario first creates a volume and a server booted from
|
||||
the volume on a compute node available in the availability zone 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 volume_size: volume size (in GB)
|
||||
:param block_migration: Specifies the migration type
|
||||
:param disk_over_commit: Specifies whether to allow overcommit
|
||||
on migrated instance or not
|
||||
:param force_delete: True if force_delete should be used
|
||||
:param kwargs: Optional additional arguments for server creation
|
||||
"""
|
||||
volume = self._create_volume(volume_size, imageRef=image)
|
||||
block_device_mapping = {"vda": "%s:::1" % volume.id}
|
||||
server = self._boot_server(image, flavor,
|
||||
block_device_mapping=block_device_mapping,
|
||||
**kwargs)
|
||||
|
||||
new_host = self._find_host_to_migrate(server)
|
||||
self._live_migrate(server, new_host,
|
||||
block_migration, disk_over_commit)
|
||||
|
||||
self._delete_server(server, force=force_delete)
|
||||
|
||||
@types.set(image=types.ImageResourceType,
|
||||
flavor=types.FlavorResourceType)
|
||||
@validation.image_valid_on_flavor("flavor", "image")
|
||||
@validation.required_services(consts.Service.NOVA, consts.Service.CINDER)
|
||||
@validation.required_openstack(admin=True, users=True)
|
||||
@base.scenario(context={"cleanup": ["cinder", "nova"]})
|
||||
def boot_server_attach_created_volume_and_live_migrate(
|
||||
self,
|
||||
image,
|
||||
flavor,
|
||||
size,
|
||||
block_migration=False,
|
||||
disk_over_commit=False,
|
||||
boot_server_kwargs=None,
|
||||
create_volume_kwargs=None):
|
||||
"""Create a VM, attach a volume to it amd live migrate.
|
||||
|
||||
Simple test to create a VM and attach a volume, then migrate the VM,
|
||||
detach the volume and delete volume/VM.
|
||||
|
||||
:param image: Glance image name to use for the VM
|
||||
:param flavor: VM flavor name
|
||||
:param size: volume size (in GB)
|
||||
:param block_migration: Specifies the migration type
|
||||
:param disk_over_commit: Specifies whether to allow overcommit
|
||||
on migrated instance or not
|
||||
:param boot_server_kwargs: optional arguments for VM creation
|
||||
:param create_volume_kwargs: optional arguments for volume creation
|
||||
"""
|
||||
|
||||
if boot_server_kwargs is None:
|
||||
boot_server_kwargs = {}
|
||||
if create_volume_kwargs is None:
|
||||
create_volume_kwargs = {}
|
||||
|
||||
server = self._boot_server(image, flavor, boot_server_kwargs)
|
||||
volume = self._create_volume(size, create_volume_kwargs)
|
||||
|
||||
self._attach_volume(server, volume)
|
||||
|
||||
new_host = self._find_host_to_migrate(server)
|
||||
self._live_migrate(server, new_host,
|
||||
block_migration, disk_over_commit)
|
||||
|
||||
self._detach_volume(server, volume)
|
||||
|
||||
self._delete_volume(volume)
|
||||
self._delete_server(server)
|
||||
|
||||
@types.set(image=types.ImageResourceType,
|
||||
flavor=types.FlavorResourceType)
|
||||
@validation.image_valid_on_flavor("flavor", "image")
|
||||
|
@ -0,0 +1,27 @@
|
||||
{
|
||||
"NovaServers.boot_server_attach_created_volume_and_live_migrate": [
|
||||
{
|
||||
"args": {
|
||||
"size": 10,
|
||||
"block_migration": false,
|
||||
"image": {
|
||||
"name": "^cirros.*uec$"
|
||||
},
|
||||
"flavor": {
|
||||
"name": "m1.nano"
|
||||
}
|
||||
},
|
||||
"runner": {
|
||||
"type": "constant",
|
||||
"times": 5,
|
||||
"concurrency": 1
|
||||
},
|
||||
"context": {
|
||||
"users": {
|
||||
"tenants": 2,
|
||||
"users_per_tenant": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
---
|
||||
NovaServers.boot_server_attach_created_volume_and_live_migrate:
|
||||
- args:
|
||||
flavor:
|
||||
name: m1.nano
|
||||
image:
|
||||
name: "^cirros.*uec$"
|
||||
size: 10
|
||||
block_migration: false
|
||||
runner:
|
||||
type: constant
|
||||
times: 5
|
||||
concurrency: 1
|
||||
context:
|
||||
users:
|
||||
tenants: 2
|
||||
users_per_tenant: 2
|
@ -0,0 +1,28 @@
|
||||
{
|
||||
"NovaServers.boot_server_from_volume_and_live_migrate": [
|
||||
{
|
||||
"args": {
|
||||
"flavor": {
|
||||
"name": "m1.nano"
|
||||
},
|
||||
"image": {
|
||||
"name": "^cirros.*uec$"
|
||||
},
|
||||
"block_migration": false,
|
||||
"volume_size": 10,
|
||||
"force_delete": false
|
||||
},
|
||||
"runner": {
|
||||
"type": "constant",
|
||||
"times": 10,
|
||||
"concurrency": 2
|
||||
},
|
||||
"context": {
|
||||
"users": {
|
||||
"tenants": 1,
|
||||
"users_per_tenant": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
---
|
||||
NovaServers.boot_server_from_volume_and_live_migrate:
|
||||
- args:
|
||||
flavor:
|
||||
name: m1.nano
|
||||
image:
|
||||
name: "^cirros.*uec$"
|
||||
block_migration: false
|
||||
volume_size: 10
|
||||
force_delete: false
|
||||
runner:
|
||||
type: constant
|
||||
times: 10
|
||||
concurrency: 2
|
||||
context:
|
||||
users:
|
||||
tenants: 1
|
||||
users_per_tenant: 1
|
@ -351,6 +351,72 @@ class NovaServersTestCase(test.TestCase):
|
||||
False, False)
|
||||
scenario._delete_server.assert_called_once_with(fake_server)
|
||||
|
||||
def test_boot_server_from_volume_and_live_migrate(self):
|
||||
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._find_host_to_migrate = mock.MagicMock(
|
||||
return_value="host_name")
|
||||
scenario._live_migrate = mock.MagicMock()
|
||||
scenario._delete_server = mock.MagicMock()
|
||||
|
||||
fake_volume = fakes.FakeVolumeManager().create()
|
||||
fake_volume.id = "volume_id"
|
||||
scenario._create_volume = mock.MagicMock(return_value=fake_volume)
|
||||
|
||||
scenario.boot_server_from_volume_and_live_migrate("img", 0, 5,
|
||||
fakearg="f")
|
||||
|
||||
scenario._create_volume.assert_called_once_with(5, imageRef="img")
|
||||
|
||||
scenario._boot_server.assert_called_once_with(
|
||||
"img", 0,
|
||||
block_device_mapping={"vda": "volume_id:::1"},
|
||||
fakearg="f")
|
||||
|
||||
scenario._find_host_to_migrate.assert_called_once_with(fake_server)
|
||||
|
||||
scenario._live_migrate.assert_called_once_with(fake_server,
|
||||
"host_name",
|
||||
False, False)
|
||||
scenario._delete_server.assert_called_once_with(fake_server,
|
||||
force=False)
|
||||
|
||||
def test_boot_server_attach_created_volume_and_live_migrate(self):
|
||||
fake_volume = mock.MagicMock()
|
||||
fake_server = mock.MagicMock()
|
||||
|
||||
scenario = servers.NovaServers()
|
||||
|
||||
scenario._attach_volume = mock.MagicMock()
|
||||
scenario._detach_volume = mock.MagicMock()
|
||||
|
||||
scenario._find_host_to_migrate = mock.MagicMock(
|
||||
return_value="host_name")
|
||||
scenario._live_migrate = mock.MagicMock()
|
||||
|
||||
scenario._boot_server = mock.MagicMock(return_value=fake_server)
|
||||
scenario._delete_server = mock.MagicMock()
|
||||
scenario._create_volume = mock.MagicMock(return_value=fake_volume)
|
||||
scenario._delete_volume = mock.MagicMock()
|
||||
|
||||
scenario.boot_server_attach_created_volume_and_live_migrate(
|
||||
"img",
|
||||
0,
|
||||
5)
|
||||
scenario._attach_volume.assert_called_once_with(fake_server,
|
||||
fake_volume)
|
||||
scenario._detach_volume.assert_called_once_with(fake_server,
|
||||
fake_volume)
|
||||
scenario._live_migrate.assert_called_once_with(fake_server,
|
||||
"host_name",
|
||||
False, False)
|
||||
|
||||
scenario._delete_volume.assert_called_once_with(fake_volume)
|
||||
scenario._delete_server.assert_called_once_with(fake_server)
|
||||
|
||||
def _test_boot_and_migrate_server(self, confirm=False):
|
||||
fake_server = mock.MagicMock()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user