summaryrefslogtreecommitdiff
path: root/nova/tests/unit/conductor
diff options
context:
space:
mode:
authorBalazs Gibizer <balazs.gibizer@est.tech>2019-11-25 15:03:10 +0100
committerBalazs Gibizer <balazs.gibizer@est.tech>2019-12-19 14:20:08 +0100
commitbd8e2fe9c80dbe39bdd03fb213148b30a9dfd36e (patch)
tree20c3a436faeb02bc5687bf9a9617b81087c6a5ea /nova/tests/unit/conductor
parentb96bc9d6758e12e11176a0fcb108235622825e75 (diff)
downloadnova-bd8e2fe9c80dbe39bdd03fb213148b30a9dfd36e.tar.gz
Support live migration with qos ports
This patch enhances the live_migration task in the conductor to support qos ports during live migration. The high level sequence of events are the following: * when request spec is gathered before the scheduler call the resource requests are collected from neutron ports and the request spec is updated * after a successful scheduling the request group - resource provider mapping is calculated * the instance pci requests are updated to drive the pci claim on the target host to allocate VFs from the same PCI PF the bandwidth is allocated from * the inactive port binding on the target host is updated to have the RP UUID in the allocation key according to the resource allocation on the destination host. As the port binding is already updated in the conductor the late check about the allocation key in the binding profile is turned off for live migration in the neutronv2 api. Note that this patch only handles the live migration without target host subsequent patches will add support for migration with target host and other edge case like reschedule. blueprint: support-move-ops-with-qos-ports-ussuri Change-Id: Ibb84ea210795634f02997d4627e0beec5fea36ee
Diffstat (limited to 'nova/tests/unit/conductor')
-rw-r--r--nova/tests/unit/conductor/tasks/test_live_migrate.py136
1 files changed, 129 insertions, 7 deletions
diff --git a/nova/tests/unit/conductor/tasks/test_live_migrate.py b/nova/tests/unit/conductor/tasks/test_live_migrate.py
index b1cf177bea..45678c12a1 100644
--- a/nova/tests/unit/conductor/tasks/test_live_migrate.py
+++ b/nova/tests/unit/conductor/tasks/test_live_migrate.py
@@ -12,6 +12,7 @@
import mock
import oslo_messaging as messaging
+from oslo_serialization import jsonutils
from oslo_utils.fixture import uuidsentinel as uuids
import six
@@ -74,6 +75,13 @@ class LiveMigrationTaskTestCase(test.NoDBTestCase):
self.ensure_network_metadata_mock = _p.start()
self.addCleanup(_p.stop)
+ _p = mock.patch(
+ 'nova.network.neutronv2.api.API.'
+ 'get_requested_resource_for_instance',
+ return_value=[])
+ self.mock_get_res_req = _p.start()
+ self.addCleanup(_p.stop)
+
def _generate_task(self):
self.task = live_migrate.LiveMigrationTask(self.context,
self.instance, self.destination, self.block_migration,
@@ -438,7 +446,7 @@ class LiveMigrationTaskTestCase(test.NoDBTestCase):
mock_select.assert_called_once_with(self.context, self.fake_spec,
[self.instance.uuid], return_objects=True, return_alternates=False)
mock_check.assert_called_once_with('host1')
- mock_call.assert_called_once_with('host1')
+ mock_call.assert_called_once_with('host1', {})
@mock.patch.object(live_migrate.LiveMigrationTask,
'_call_livem_checks_on_host')
@@ -459,7 +467,7 @@ class LiveMigrationTaskTestCase(test.NoDBTestCase):
self.context, self.fake_spec, [self.instance.uuid],
return_objects=True, return_alternates=False)
mock_check.assert_called_once_with('host1')
- mock_call.assert_called_once_with('host1')
+ mock_call.assert_called_once_with('host1', {})
@mock.patch.object(live_migrate.LiveMigrationTask,
'_remove_host_allocations')
@@ -486,7 +494,7 @@ class LiveMigrationTaskTestCase(test.NoDBTestCase):
mock.call(self.context, self.fake_spec, [self.instance.uuid],
return_objects=True, return_alternates=False)])
mock_check.assert_has_calls([mock.call('host1'), mock.call('host2')])
- mock_call.assert_called_once_with('host2')
+ mock_call.assert_called_once_with('host2', {})
def test_find_destination_retry_with_old_hypervisor(self):
self._test_find_destination_retry_hypervisor_raises(
@@ -521,7 +529,8 @@ class LiveMigrationTaskTestCase(test.NoDBTestCase):
mock.call(self.context, self.fake_spec, [self.instance.uuid],
return_objects=True, return_alternates=False)])
mock_check.assert_has_calls([mock.call('host1'), mock.call('host2')])
- mock_call.assert_has_calls([mock.call('host1'), mock.call('host2')])
+ mock_call.assert_has_calls(
+ [mock.call('host1', {}), mock.call('host2', {})])
@mock.patch.object(live_migrate.LiveMigrationTask,
'_remove_host_allocations')
@@ -549,7 +558,8 @@ class LiveMigrationTaskTestCase(test.NoDBTestCase):
mock.call(self.context, self.fake_spec, [self.instance.uuid],
return_objects=True, return_alternates=False)])
mock_check.assert_has_calls([mock.call('host1'), mock.call('host2')])
- mock_call.assert_has_calls([mock.call('host1'), mock.call('host2')])
+ mock_call.assert_has_calls(
+ [mock.call('host1', {}), mock.call('host2', {})])
@mock.patch.object(objects.Migration, 'save')
@mock.patch.object(live_migrate.LiveMigrationTask,
@@ -612,7 +622,7 @@ class LiveMigrationTaskTestCase(test.NoDBTestCase):
side_effect=messaging.MessagingTimeout),
mock.patch.object(self.task, '_check_can_migrate_pci')):
self.assertRaises(exception.MigrationPreCheckError,
- self.task._call_livem_checks_on_host, {})
+ self.task._call_livem_checks_on_host, {}, {})
def test_call_livem_checks_on_host_bind_ports(self):
data = objects.LibvirtLiveMigrateData()
@@ -639,7 +649,7 @@ class LiveMigrationTaskTestCase(test.NoDBTestCase):
network_model.VIF(uuids.port2)])
self.instance.info_cache = objects.InstanceInfoCache(
network_info=nwinfo)
- self.task._call_livem_checks_on_host('dest-host')
+ self.task._call_livem_checks_on_host('dest-host', {})
# Assert the migrate_data set on the task based on the port
# bindings created.
self.assertIn('vifs', data)
@@ -651,6 +661,118 @@ class LiveMigrationTaskTestCase(test.NoDBTestCase):
_test()
+ @mock.patch('nova.network.neutronv2.api.API.bind_ports_to_host')
+ def test_bind_ports_on_destination_merges_profiles(self, mock_bind_ports):
+ """Assert that if both the migration_data and the provider mapping
+ contains binding profile related information then such information is
+ merged in the resulting profile.
+ """
+
+ self.task.migrate_data = objects.LibvirtLiveMigrateData(
+ vifs=[
+ objects.VIFMigrateData(
+ port_id=uuids.port1,
+ profile_json=jsonutils.dumps(
+ {'some-key': 'value'}))
+ ])
+ provider_mappings = {uuids.port1: [uuids.dest_bw_rp]}
+
+ self.task._bind_ports_on_destination('dest-host', provider_mappings)
+
+ mock_bind_ports.assert_called_once_with(
+ context=self.context, instance=self.instance, host='dest-host',
+ vnic_types=None,
+ port_profiles={uuids.port1: {'allocation': uuids.dest_bw_rp,
+ 'some-key': 'value'}})
+
+ @mock.patch('nova.network.neutronv2.api.API.bind_ports_to_host')
+ def test_bind_ports_on_destination_migration_data(self, mock_bind_ports):
+ """Assert that if only the migration_data contains binding profile
+ related information then that is sent to neutron.
+ """
+
+ self.task.migrate_data = objects.LibvirtLiveMigrateData(
+ vifs=[
+ objects.VIFMigrateData(
+ port_id=uuids.port1,
+ profile_json=jsonutils.dumps(
+ {'some-key': 'value'}))
+ ])
+ provider_mappings = {}
+
+ self.task._bind_ports_on_destination('dest-host', provider_mappings)
+
+ mock_bind_ports.assert_called_once_with(
+ context=self.context, instance=self.instance, host='dest-host',
+ vnic_types=None,
+ port_profiles={uuids.port1: {'some-key': 'value'}})
+
+ @mock.patch('nova.network.neutronv2.api.API.bind_ports_to_host')
+ def test_bind_ports_on_destination_provider_mapping(self, mock_bind_ports):
+ """Assert that if only the provider mapping contains binding
+ profile related information then that is sent to neutron.
+ """
+
+ self.task.migrate_data = objects.LibvirtLiveMigrateData(
+ vifs=[
+ objects.VIFMigrateData(
+ port_id=uuids.port1)
+ ])
+ provider_mappings = {uuids.port1: [uuids.dest_bw_rp]}
+
+ self.task._bind_ports_on_destination('dest-host', provider_mappings)
+
+ mock_bind_ports.assert_called_once_with(
+ context=self.context, instance=self.instance, host='dest-host',
+ vnic_types=None,
+ port_profiles={uuids.port1: {'allocation': uuids.dest_bw_rp}})
+
+ @mock.patch(
+ 'nova.compute.utils.'
+ 'update_pci_request_spec_with_allocated_interface_name')
+ @mock.patch('nova.scheduler.utils.fill_provider_mapping')
+ @mock.patch.object(live_migrate.LiveMigrationTask,
+ '_call_livem_checks_on_host')
+ @mock.patch.object(live_migrate.LiveMigrationTask,
+ '_check_compatible_with_source_hypervisor')
+ @mock.patch.object(query.SchedulerQueryClient, 'select_destinations',
+ return_value=[[fake_selection1]])
+ @mock.patch.object(objects.RequestSpec, 'reset_forced_destinations')
+ @mock.patch.object(scheduler_utils, 'setup_instance_group')
+ def test_find_destination_with_resource_request(
+ self, mock_setup, mock_reset, mock_select, mock_check, mock_call,
+ mock_fill_provider_mapping, mock_update_pci_req):
+ resource_req = [objects.RequestGroup(requester_id=uuids.port_id)]
+ self.mock_get_res_req.return_value = resource_req
+
+ self.assertEqual(("host1", "node1", fake_limits1),
+ self.task._find_destination())
+
+ # Make sure the request_spec was updated to include the cell
+ # mapping.
+ self.assertIsNotNone(self.fake_spec.requested_destination.cell)
+ # Make sure the spec was updated to include the project_id.
+ self.assertEqual(self.fake_spec.project_id, self.instance.project_id)
+ # Make sure that requested_resources are added to the request spec
+ self.assertEqual(
+ resource_req, self.task.request_spec.requested_resources)
+
+ mock_setup.assert_called_once_with(self.context, self.fake_spec)
+ mock_reset.assert_called_once_with()
+ self.ensure_network_metadata_mock.assert_called_once_with(
+ self.instance)
+ self.heal_reqspec_is_bfv_mock.assert_called_once_with(
+ self.context, self.fake_spec, self.instance)
+ mock_select.assert_called_once_with(self.context, self.fake_spec,
+ [self.instance.uuid], return_objects=True, return_alternates=False)
+ mock_check.assert_called_once_with('host1')
+ mock_call.assert_called_once_with('host1', {uuids.port_id: []})
+ mock_fill_provider_mapping.assert_called_once_with(
+ self.task.request_spec, fake_selection1)
+ mock_update_pci_req.assert_called_once_with(
+ self.context, self.task.report_client, self.instance,
+ {uuids.port_id: []})
+
@mock.patch.object(objects.InstanceMapping, 'get_by_instance_uuid',
side_effect=exception.InstanceMappingNotFound(
uuid=uuids.instance))