def test_update_perf_events_xml_remove_all_events(self): data = objects.LibvirtLiveMigrateData(supported_perf_events=[]) xml = """<domain> <perf> <event enabled="yes" name="cmt"/> </perf> </domain>""" doc = etree.fromstring(xml) res = etree.tostring(migration._update_perf_events_xml(doc, data), encoding='unicode') self.assertThat( res, matchers.XMLMatches("""<domain> <perf> </perf> </domain>"""))
def test_update_memory_backing_xml_add(self): data = objects.LibvirtLiveMigrateData( dst_wants_file_backed_memory=True) xml = """<domain/>""" doc = etree.fromstring(xml) res = etree.tostring(migration._update_memory_backing_xml(doc, data), encoding='unicode') self.assertThat( res, matchers.XMLMatches("""<domain> <memoryBacking> <source type="file"/> <access mode="shared"/> <allocation mode="immediate"/> </memoryBacking> </domain>"""))
def test_update_perf_events_xml_add_new_events1(self): data = objects.LibvirtLiveMigrateData( supported_perf_events=['cmt', 'mbml']) xml = """<domain> <perf> <event enabled="yes" name="cmt"/> </perf> </domain>""" doc = etree.fromstring(xml) res = etree.tostring(migration._update_perf_events_xml(doc, data)) self.assertThat( res, matchers.XMLMatches("""<domain> <perf> <event enabled="yes" name="cmt"/><event enabled="yes" name="mbml"/></perf> </domain>"""))
def test_update_serial_xml_serial(self): data = objects.LibvirtLiveMigrateData(serial_listen_addr='127.0.0.100', serial_listen_ports=[2001]) xml = """<domain> <devices> <serial type="tcp"> <source host="127.0.0.1" service="2000"/> <target type="serial" port="0"/> </serial> </devices> </domain>""" doc = etree.fromstring(xml) res = etree.tostring(migration._update_serial_xml(doc, data), encoding='unicode') new_xml = xml.replace("127.0.0.1", "127.0.0.100").replace("2000", "2001") self.assertThat(res, matchers.XMLMatches(new_xml))
def test_update_memory_backing_xml_remove(self): data = objects.LibvirtLiveMigrateData( dst_wants_file_backed_memory=False) xml = """<domain> <memoryBacking> <source type="file"/> <access mode="shared"/> <allocation mode="immediate"/> </memoryBacking> </domain>""" doc = etree.fromstring(xml) res = etree.tostring(migration._update_memory_backing_xml(doc, data), encoding='unicode') self.assertXmlEqual(res, """<domain> <memoryBacking/> </domain>""")
def test_update_perf_events_xml_add_new_events1(self): data = objects.LibvirtLiveMigrateData( supported_perf_events=['cmt', 'mbml']) xml = """<domain> <perf> <event enabled="yes" name="cmt"/> </perf> </domain>""" doc = etree.fromstring(xml) res = etree.tostring(migration._update_perf_events_xml(doc, data), encoding='unicode') self.assertXmlEqual( res, """<domain> <perf> <event enabled="yes" name="cmt"/><event enabled="yes" name="mbml"/></perf> </domain>""")
def test_live_migration(self): instance_ref, network_info = self._get_running_instance() instance_ref.info_cache = objects.InstanceInfoCache( network_info=network_info) fake_context = context.RequestContext('fake', 'fake') migration = objects.Migration(context=fake_context, id=1) migrate_data = objects.LibvirtLiveMigrateData( migration=migration, bdms=[], block_migration=False, serial_listen_addr='127.0.0.1') self.connection.live_migration(self.ctxt, instance_ref, 'otherhost', lambda *a: None, lambda *a: None, migrate_data=migrate_data)
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_update_graphics(self): data = objects.LibvirtLiveMigrateData( graphics_listen_addr_vnc='127.0.0.100', graphics_listen_addr_spice='127.0.0.200') xml = """<domain> <devices> <graphics type="vnc"> <listen type="address" address="127.0.0.1"/> </graphics> <graphics type="spice"> <listen type="address" address="127.0.0.2"/> </graphics> </devices> </domain>""" doc = etree.fromstring(xml) res = etree.tostring(migration._update_graphics_xml(doc, data)) self.assertIn('127.0.0.100', six.text_type(res)) self.assertIn('127.0.0.200', six.text_type(res))
def test_update_graphics(self): data = objects.LibvirtLiveMigrateData( graphics_listen_addr_vnc='127.0.0.100', graphics_listen_addr_spice='127.0.0.200') xml = """<domain> <devices> <graphics type="vnc"> <listen type="address" address="127.0.0.1"/> </graphics> <graphics type="spice"> <listen type="address" address="127.0.0.2"/> </graphics> </devices> </domain>""" doc = etree.fromstring(xml) res = etree.tostring(migration._update_graphics_xml(doc, data)) new_xml = xml.replace("127.0.0.1", "127.0.0.100") new_xml = new_xml.replace("127.0.0.2", "127.0.0.200") self.assertThat(res, matchers.XMLMatches(new_xml))
def test_live_migration(self): instance_ref, network_info = self._get_running_instance() fake_context = context.RequestContext('fake', 'fake') migration = objects.Migration(context=fake_context, id=1) migrate_data = objects.LibvirtLiveMigrateData( migration=migration, bdms=[], block_migration=False, serial_listen_addr='127.0.0.1') # WRS: Need to fake as _update_numa_xml now accesses migration_context def fake_update_numa_xml(xml_doc, driver_interface, instance): return xml_doc self.stubs.Set(libvirt.migration, '_update_numa_xml', fake_update_numa_xml) self.connection.live_migration(self.ctxt, instance_ref, 'otherhost', lambda *a: None, lambda *a, **kwargs: None, migrate_data=migrate_data)
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_call_livem_checks_on_host_bind_ports(self): data = objects.LibvirtLiveMigrateData() bindings = { uuids.port1: { 'host': 'dest-host' }, uuids.port2: { 'host': 'dest-host' } } @mock.patch.object(self.task, '_check_can_migrate_pci') @mock.patch.object(self.task.compute_rpcapi, 'check_can_live_migrate_destination', return_value=data) @mock.patch.object(self.task.network_api, 'supports_port_binding_extension', return_value=True) @mock.patch.object(self.task.network_api, 'bind_ports_to_host', return_value=bindings) def _test(mock_bind_ports_to_host, mock_supports_port_binding, mock_check_can_live_migrate_dest, mock_check_can_migrate_pci): nwinfo = network_model.NetworkInfo([ network_model.VIF(uuids.port1), network_model.VIF(uuids.port2) ]) self.instance.info_cache = objects.InstanceInfoCache( network_info=nwinfo) 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) self.assertEqual(2, len(data.vifs)) for vif in data.vifs: self.assertIn('source_vif', vif) self.assertEqual('dest-host', vif.host) self.assertEqual(vif.port_id, vif.source_vif['id']) _test()
def test_update_serial_xml_console(self): data = objects.LibvirtLiveMigrateData(serial_listen_addr='127.0.0.100', serial_listen_ports=[299, 300]) xml = """<domain> <devices> <console type="tcp"> <source host="127.0.0.1" service="2001"/> <target type="serial" port="0"/> </console> <console type="tcp"> <source host="127.0.0.1" service="2002"/> <target type="serial" port="1"/> </console> </devices> </domain>""" doc = etree.fromstring(xml) res = etree.tostring(migration._update_serial_xml(doc, data)) new_xml = xml.replace("127.0.0.1", "127.0.0.100").replace( "2001", "299").replace("2002", "300") self.assertThat(res, matchers.XMLMatches(new_xml))
def test_update_serial_xml_without_ports(self): # This test is for backwards compatibility when we don't # get the serial ports from the target node. data = objects.LibvirtLiveMigrateData(serial_listen_addr='127.0.0.100', serial_listen_ports=[]) xml = """<domain> <devices> <console type="tcp"> <source host="127.0.0.1" service="2001"/> <target type="serial" port="0"/> </console> <console type="tcp"> <source host="127.0.0.1" service="2002"/> <target type="serial" port="1"/> </console> </devices> </domain>""" doc = etree.fromstring(xml) res = etree.tostring(migration._update_serial_xml(doc, data)) new_xml = xml.replace("127.0.0.1", "127.0.0.100") self.assertThat(res, matchers.XMLMatches(new_xml))
def test_get_instance_path_at_destination(self): instance = fake_instance.fake_instance_obj(None, name='fake_inst', uuid=uuids.instance) migrate_data = None inst_path_at_dest = libvirt_utils.get_instance_path_at_destination( instance, migrate_data) expected_path = os.path.join(CONF.instances_path, instance['uuid']) self.assertEqual(expected_path, inst_path_at_dest) migrate_data = {} inst_path_at_dest = libvirt_utils.get_instance_path_at_destination( instance, migrate_data) expected_path = os.path.join(CONF.instances_path, instance['uuid']) self.assertEqual(expected_path, inst_path_at_dest) migrate_data = objects.LibvirtLiveMigrateData( instance_relative_path='fake_relative_path') inst_path_at_dest = libvirt_utils.get_instance_path_at_destination( instance, migrate_data) expected_path = os.path.join(CONF.instances_path, 'fake_relative_path') self.assertEqual(expected_path, inst_path_at_dest)
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_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_serial_listen_addr_None(self): data = objects.LibvirtLiveMigrateData() data.serial_listen_addr = None addr = migration.serial_listen_addr(data) self.assertIsNone(addr)
def test_serial_listen_addr(self): data = objects.LibvirtLiveMigrateData(serial_listen_addr='127.0.0.1') addr = migration.serial_listen_addr(data) self.assertEqual('127.0.0.1', addr)
def test_graphics_listen_addrs_vnc(self): data = objects.LibvirtLiveMigrateData( graphics_listen_addr_vnc='127.0.0.1') addrs = migration.graphics_listen_addrs(data) self.assertEqual({'vnc': '127.0.0.1', 'spice': None}, addrs)
def test_graphics_listen_addrs_empty(self): data = objects.LibvirtLiveMigrateData() addrs = migration.graphics_listen_addrs(data) self.assertIsNone(None, addrs)
def test_serial_listen_ports_emtpy(self): data = objects.LibvirtLiveMigrateData() ports = migration.serial_listen_ports(data) self.assertEqual([], ports)
def test_serial_listen_ports(self): data = objects.LibvirtLiveMigrateData(serial_listen_ports=[1, 2, 3]) ports = migration.serial_listen_ports(data) self.assertEqual([1, 2, 3], ports)
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))
def test_update_volume_xml_update_encryption(self): connection_info = { 'driver_volume_type': 'rbd', 'serial': 'd299a078-f0db-4993-bf03-f10fe44fd192', 'data': { 'access_mode': 'rw', 'secret_type': 'ceph', 'name': 'cinder-volumes/volume-d299a078', 'encrypted': False, 'discard': True, 'cluster_name': 'ceph', 'secret_uuid': '1a790a26-dd49-4825-8d16-3dd627cf05a9', 'qos_specs': None, 'auth_enabled': True, 'volume_id': 'd299a078-f0db-4993-bf03-f10fe44fd192', 'hosts': ['172.16.128.101', '172.16.128.121'], 'auth_username': '******', 'ports': ['6789', '6789', '6789'] } } bdm = objects.LibvirtLiveMigrateBDMInfo( serial='d299a078-f0db-4993-bf03-f10fe44fd192', bus='scsi', type='disk', dev='sdb', connection_info=connection_info, encryption_secret_uuid=uuids.encryption_secret_uuid_new) data = objects.LibvirtLiveMigrateData(target_connect_addr=None, bdms=[bdm], block_migration=False) xml = """<domain> <devices> <disk type='network' device='disk'> <driver name='qemu' type='raw' cache='writeback' discard='unmap'/> <auth username='******'> <secret type='ceph' uuid='1a790a26-dd49-4825-8d16-3dd627cf05a9'/> </auth> <source protocol='rbd' name='cinder-volumes/volume-d299a078'> <host name='172.16.128.101' port='6789'/> <host name='172.16.128.121' port='6789'/> </source> <backingStore/> <target dev='sdb' bus='scsi'/> <serial>d299a078-f0db-4993-bf03-f10fe44fd192</serial> <alias name='scsi0-0-0-1'/> <encryption format='luks'> <secret type='passphrase' uuid='%(encryption_secret_uuid)s'/> </encryption> <address type='drive' controller='0' bus='0' target='0' unit='1'/> </disk> </devices> </domain>""" % { 'encryption_secret_uuid': uuids.encryption_secret_uuid_old } conf = vconfig.LibvirtConfigGuestDisk() conf.source_device = bdm.type conf.driver_name = "qemu" conf.driver_format = "raw" conf.driver_cache = "writeback" conf.target_dev = bdm.dev conf.target_bus = bdm.bus conf.serial = bdm.connection_info.get('serial') conf.source_type = "network" conf.driver_discard = 'unmap' conf.device_addr = vconfig.LibvirtConfigGuestDeviceAddressDrive() conf.device_addr.controller = 0 get_volume_config = mock.MagicMock(return_value=conf) doc = etree.fromstring(xml) res = etree.tostring(migration._update_volume_xml( doc, data, get_volume_config), encoding='unicode') new_xml = xml.replace(uuids.encryption_secret_uuid_old, uuids.encryption_secret_uuid_new) self.assertThat(res, matchers.XMLMatches(new_xml))