def test_supports_os_vif_delegation(self): # first try setting on a object without 'profile' defined migrate_vif = objects.VIFMigrateData( port_id=uuids.port_id, vnic_type=network_model.VNIC_TYPE_NORMAL, vif_type=network_model.VIF_TYPE_OVS, vif_details={}, host='fake-dest-host') migrate_vif.supports_os_vif_delegation = True self.assertTrue(migrate_vif.supports_os_vif_delegation) self.assertEqual(migrate_vif.profile, {'os_vif_delegation': True}) # now do the same but with profile defined migrate_vif = objects.VIFMigrateData( port_id=uuids.port_id, vnic_type=network_model.VNIC_TYPE_NORMAL, vif_type=network_model.VIF_TYPE_OVS, vif_details={}, host='fake-dest-host', profile={'interface_name': 'eth0'}) migrate_vif.supports_os_vif_delegation = True self.assertTrue(migrate_vif.supports_os_vif_delegation) self.assertEqual(migrate_vif.profile, { 'os_vif_delegation': True, 'interface_name': 'eth0' })
def _bind_ports_on_destination(self, destination): LOG.debug('Start binding ports on destination host: %s', destination, instance=self.instance) # Bind ports on the destination host; returns a dict, keyed by # port ID, of a new destination host port binding dict per port # that was bound. This information is then stuffed into the # migrate_data. try: bindings = self.network_api.bind_ports_to_host( self.context, self.instance, destination) except exception.PortBindingFailed as e: # Port binding failed for that host, try another one. raise exception.MigrationPreCheckError( reason=e.format_message()) source_vif_map = { vif['id']: vif for vif in self.instance.get_network_info() } migrate_vifs = [] for port_id, binding in bindings.items(): migrate_vif = objects.VIFMigrateData( port_id=port_id, **binding) migrate_vif.source_vif = source_vif_map[port_id] migrate_vifs.append(migrate_vif) return migrate_vifs
def test_update_vif_xml_no_mac_address_in_xml(self): """Tests that the <mac address> is not found in the <interface> XML which results in an error. """ data = objects.LibvirtLiveMigrateData(vifs=[ objects.VIFMigrateData(source_vif=network_model.VIF( address="DE:AD:BE:EF:CA:FE")) ]) original_xml = """<domain> <uuid>3de6550a-8596-4937-8046-9d862036bca5</uuid> <devices> <interface type='direct'> <source dev='eth0' mode='private'/> <virtualport type='802.1Qbh'> <parameters profileid='finance'/> </virtualport> </interface> </devices> </domain>""" get_vif_config = mock.MagicMock(new_callable=mock.NonCallableMock) doc = etree.fromstring(original_xml) ex = self.assertRaises(exception.NovaException, migration._update_vif_xml, doc, data, get_vif_config) self.assertIn('Unable to find MAC address in interface XML', six.text_type(ex))
def test_vif_migrate_data(self): source_vif = network_model.VIF( id=uuids.port_id, network=network_model.Network(id=uuids.network_id), type=network_model.VIF_TYPE_OVS, vnic_type=network_model.VNIC_TYPE_NORMAL, active=True, profile={'migrating_to': 'dest-host'}) vif_details_dict = {'port_filter': True} profile_dict = {'trusted': False} vif_data = objects.VIFMigrateData( port_id=uuids.port_id, vnic_type=network_model.VNIC_TYPE_NORMAL, vif_type=network_model.VIF_TYPE_BRIDGE, vif_details=vif_details_dict, profile=profile_dict, host='dest-host', source_vif=source_vif) # Make sure the vif_details and profile fields are converted and # stored properly. self.assertEqual(jsonutils.dumps(vif_details_dict), vif_data.vif_details_json) self.assertEqual(jsonutils.dumps(profile_dict), vif_data.profile_json) self.assertDictEqual(vif_details_dict, vif_data.vif_details) self.assertDictEqual(profile_dict, vif_data.profile) obj = migrate_data.LibvirtLiveMigrateData( file_backed_memory_discard=False) obj.vifs = [vif_data] manifest = ovo_base.obj_tree_get_versions(obj.obj_name()) primitive = obj.obj_to_primitive(target_version='1.8', version_manifest=manifest) self.assertIn('file_backed_memory_discard', primitive['nova_object.data']) self.assertNotIn('vifs', primitive['nova_object.data'])
def test_get_dest_vif_source_vif_not_set(self): migrate_vif = objects.VIFMigrateData( port_id=uuids.port_id, vnic_type=network_model.VNIC_TYPE_NORMAL, vif_type=network_model.VIF_TYPE_OVS, vif_details={}, profile={}, host='fake-dest-host') self.assertRaises( exception.ObjectActionError, migrate_vif.get_dest_vif)
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' } })
def _test_update_vif_xml(self, conf, original_xml, expected_xml): """Simulates updating the guest xml for live migrating from a host using OVS to a host using vhostuser as the networking backend. """ vif_ovs = network_model.VIF(id=uuids.vif, address='DE:AD:BE:EF:CA:FE', details={'port_filter': False}, devname='tap-xxx-yyy-zzz', ovs_interfaceid=uuids.ovs) source_vif = vif_ovs migrate_vifs = [ objects.VIFMigrateData( port_id=uuids.port_id, vnic_type=network_model.VNIC_TYPE_NORMAL, vif_type=network_model.VIF_TYPE_VHOSTUSER, vif_details={'vhostuser_socket': '/vhost-user/test.sock'}, profile={}, host='dest.host', source_vif=source_vif) ] data = objects.LibvirtLiveMigrateData(vifs=migrate_vifs) get_vif_config = mock.MagicMock(return_value=conf) doc = etree.fromstring(original_xml) updated_xml = etree.tostring(migration._update_vif_xml( doc, data, get_vif_config), encoding='unicode') self.assertThat(updated_xml, matchers.XMLMatches(expected_xml))
def test_get_dest_vif(self): source_vif = network_model.VIF( id=uuids.port_id, type=network_model.VIF_TYPE_OVS, details={}, vnic_type=network_model.VNIC_TYPE_DIRECT, profile={'foo': 'bar'}, ovs_interfaceid=uuids.ovs_interfaceid) migrate_vif = objects.VIFMigrateData( port_id=uuids.port_id, vnic_type=network_model.VNIC_TYPE_NORMAL, vif_type=network_model.VIF_TYPE_BRIDGE, vif_details={'bar': 'baz'}, profile={}, host='fake-dest-host', source_vif=source_vif) dest_vif = migrate_vif.get_dest_vif() self.assertEqual(migrate_vif.port_id, dest_vif['id']) self.assertEqual(migrate_vif.vnic_type, dest_vif['vnic_type']) self.assertEqual(migrate_vif.vif_type, dest_vif['type']) self.assertEqual(migrate_vif.vif_details, dest_vif['details']) self.assertEqual(migrate_vif.profile, dest_vif['profile']) self.assertEqual(uuids.ovs_interfaceid, dest_vif['ovs_interfaceid'])
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}})
def test_bind_ports_on_destination_merges_profiles_extended_res_req( self, mock_bind_ports, mock_get_binding_profile_alloc): """Assert that if both the migration_data and the provider mapping contains binding profile related information and the port has extended resource request 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.bw_group: [uuids.dest_bw_rp], uuids.pps_group: [uuids.dest_pps_rp], uuids.accel_group: [uuids.cyborg_rp], } mock_get_binding_profile_alloc.return_value = { uuids.bw_group: uuids.dest_bw_rp, uuids.pps_group: uuids.dest_pps_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.bw_group: uuids.dest_bw_rp, uuids.pps_group: uuids.dest_pps_rp, }, 'some-key': 'value' } }) mock_get_binding_profile_alloc.assert_called_once_with( self.context, uuids.port1, provider_mappings)
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'}})
def test_update_vif_xml_no_matching_vif(self): """Tests that the vif in the migrate data is not found in the existing guest interfaces. """ data = objects.LibvirtLiveMigrateData(vifs=[ objects.VIFMigrateData(source_vif=network_model.VIF( address="DE:AD:BE:EF:CA:FE"))]) original_xml = """<domain> <uuid>3de6550a-8596-4937-8046-9d862036bca5</uuid> <devices> <interface type="bridge"> <mac address="CA:FE:DE:AD:BE:EF"/> <model type="virtio"/> <source bridge="qbra188171c-ea"/> <target dev="tapa188171c-ea"/> </interface> </devices> </domain>""" get_vif_config = mock.MagicMock(new_callable=mock.NonCallableMock) doc = etree.fromstring(original_xml) ex = self.assertRaises(KeyError, migration._update_vif_xml, doc, data, get_vif_config) self.assertIn("CA:FE:DE:AD:BE:EF", six.text_type(ex))
def test_update_vif_xml(self): """Simulates updating the guest xml for live migrating from a host using OVS to a host using vhostuser as the networking backend. """ vif_ovs = network_model.VIF(id=uuids.vif, address='DE:AD:BE:EF:CA:FE', details={'port_filter': False}, devname='tap-xxx-yyy-zzz', ovs_interfaceid=uuids.ovs) source_vif = vif_ovs migrate_vifs = [ objects.VIFMigrateData( port_id=uuids.port_id, vnic_type=network_model.VNIC_TYPE_NORMAL, vif_type=network_model.VIF_TYPE_VHOSTUSER, vif_details={'vhostuser_socket': '/vhost-user/test.sock'}, profile={}, host='dest.host', source_vif=source_vif) ] data = objects.LibvirtLiveMigrateData(vifs=migrate_vifs) original_xml = """<domain> <uuid>3de6550a-8596-4937-8046-9d862036bca5</uuid> <devices> <interface type="bridge"> <mac address="DE:AD:BE:EF:CA:FE"/> <model type="virtio"/> <source bridge="qbra188171c-ea"/> <target dev="tapa188171c-ea"/> <virtualport type="openvswitch"> <parameters interfaceid="%s"/> </virtualport> <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> </interface> </devices> </domain>""" % uuids.ovs conf = vconfig.LibvirtConfigGuestInterface() conf.net_type = "vhostuser" conf.vhostuser_type = "unix" conf.vhostuser_mode = "server" conf.mac_addr = "DE:AD:BE:EF:CA:FE" conf.vhostuser_path = "/vhost-user/test.sock" conf.model = "virtio" get_vif_config = mock.MagicMock(return_value=conf) doc = etree.fromstring(original_xml) updated_xml = etree.tostring(migration._update_vif_xml( doc, data, get_vif_config), encoding='unicode') # Note that <target> and <virtualport> are dropped from the ovs source # interface xml since they aren't applicable to the vhostuser # destination interface xml. The type attribute value changes and the # hardware address element is retained. expected_xml = """<domain> <uuid>3de6550a-8596-4937-8046-9d862036bca5</uuid> <devices> <interface type="vhostuser"> <mac address="DE:AD:BE:EF:CA:FE"/> <model type="virtio"/> <source mode="server" path="/vhost-user/test.sock" type="unix"/> <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> </interface> </devices> </domain>""" self.assertThat(updated_xml, matchers.XMLMatches(expected_xml))