From 3b9e7c5dec88c56e55f31cd1909d48fc5b00f082 Mon Sep 17 00:00:00 2001 From: Eli Qiao Date: Mon, 6 Jun 2016 17:26:59 +0800 Subject: [PATCH] libvirt: Add migration support for perf event support Update xml per dest host's perf event configration when doing live migration. Co-Authored-By: Qiaowei Ren Implement blueprint: support-perf-event Change-Id: Ifdd7a4283d27ff64809d4a52ed9a4381a8cfaf99 --- nova/objects/migrate_data.py | 7 ++- nova/tests/unit/objects/test_objects.py | 2 +- nova/tests/unit/virt/libvirt/test_driver.py | 16 +++++ .../tests/unit/virt/libvirt/test_migration.py | 63 +++++++++++++++++++ nova/virt/libvirt/driver.py | 1 + nova/virt/libvirt/migration.py | 35 +++++++++++ 6 files changed, 122 insertions(+), 2 deletions(-) diff --git a/nova/objects/migrate_data.py b/nova/objects/migrate_data.py index 04c7ab192cac..020638ea470b 100644 --- a/nova/objects/migrate_data.py +++ b/nova/objects/migrate_data.py @@ -109,7 +109,8 @@ class LibvirtLiveMigrateData(LiveMigrateData): # Version 1.1: Added target_connect_addr # Version 1.2: Added 'serial_listen_ports' to allow live migration with # serial console. - VERSION = '1.2' + # Version 1.3: Added 'supported_perf_events' + VERSION = '1.3' fields = { 'filename': fields.StringField(), @@ -127,12 +128,16 @@ class LibvirtLiveMigrateData(LiveMigrateData): 'serial_listen_ports': fields.ListOfIntegersField(), 'bdms': fields.ListOfObjectsField('LibvirtLiveMigrateBDMInfo'), 'target_connect_addr': fields.StringField(nullable=True), + 'supported_perf_events': fields.ListOfStringsField(), } def obj_make_compatible(self, primitive, target_version): super(LibvirtLiveMigrateData, self).obj_make_compatible( primitive, target_version) target_version = versionutils.convert_version_to_tuple(target_version) + if target_version < (1, 3): + if 'supported_perf_events' in primitive: + del primitive['supported_perf_events'] if target_version < (1, 2): if 'serial_listen_ports' in primitive: del primitive['serial_listen_ports'] diff --git a/nova/tests/unit/objects/test_objects.py b/nova/tests/unit/objects/test_objects.py index ea20d972262f..29fe173623d1 100644 --- a/nova/tests/unit/objects/test_objects.py +++ b/nova/tests/unit/objects/test_objects.py @@ -1153,7 +1153,7 @@ object_data = { 'Inventory': '1.0-84131c00c84a27ee6930d01b329c9a9d', 'InventoryList': '1.0-de53f0fd078c27cc1d43400f4e8bcef8', 'LibvirtLiveMigrateBDMInfo': '1.0-252aabb723ca79d5469fa56f64b57811', - 'LibvirtLiveMigrateData': '1.2-c489f63478d13eace828128ea3dfa57c', + 'LibvirtLiveMigrateData': '1.3-2795e5646ee21e8c7f1c3e64fb6c80a3', 'KeyPair': '1.4-1244e8d1b103cc69d038ed78ab3a8cc6', 'KeyPairList': '1.2-58b94f96e776bedaf1e192ddb2a24c4e', 'Migration': '1.4-17979b9f2ae7f28d97043a220b2a8350', diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index 11fa02636cfe..5aba40c21b91 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -9185,6 +9185,22 @@ class LibvirtConnTestCase(test.NoDBTestCase): write_to_file.assert_called_with(disk_info_path, jsonutils.dumps(image_disk_info)) + def test_pre_live_migration_with_perf_events(self): + + drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False) + drvr._supported_perf_events = ['cmt'] + + migrate_data = {} + + instance = objects.Instance(**self.test_instance) + + res = drvr.pre_live_migration(self.context, instance, + block_device_info=None, + network_info=[], + disk_info=None, + migrate_data=migrate_data) + self.assertEqual(['cmt'], res.supported_perf_events) + def test_get_instance_disk_info_works_correctly(self): # Test data instance = objects.Instance(**self.test_instance) diff --git a/nova/tests/unit/virt/libvirt/test_migration.py b/nova/tests/unit/virt/libvirt/test_migration.py index 4f455134d8c3..b6849b3f7612 100644 --- a/nova/tests/unit/virt/libvirt/test_migration.py +++ b/nova/tests/unit/virt/libvirt/test_migration.py @@ -19,6 +19,8 @@ from oslo_utils import units import six +from oslo_utils import encodeutils + from nova.compute import power_state from nova import objects from nova import test @@ -189,6 +191,67 @@ class UtilityMigrationTestCase(test.NoDBTestCase): self.assertIn('ip-1.2.3.4:3260-iqn.cde.67890.opst-lun-Z', six.text_type(res)) + def test_update_perf_events_xml(self): + data = objects.LibvirtLiveMigrateData( + supported_perf_events=['cmt']) + xml = """ + + + + +""" + doc = etree.fromstring(xml) + res = etree.tostring(migration._update_perf_events_xml(doc, data)) + + self.assertEqual(""" + + +""", encodeutils.safe_decode(res)) + + def test_update_perf_events_xml_add_new_events(self): + data = objects.LibvirtLiveMigrateData( + supported_perf_events=['cmt']) + xml = """ +""" + doc = etree.fromstring(xml) + res = etree.tostring(migration._update_perf_events_xml(doc, data)) + + self.assertEqual(""" +""", + encodeutils.safe_decode(res)) + + def test_update_perf_events_xml_add_new_events1(self): + data = objects.LibvirtLiveMigrateData( + supported_perf_events=['cmt', 'mbml']) + xml = """ + + + +""" + doc = etree.fromstring(xml) + res = etree.tostring(migration._update_perf_events_xml(doc, data)) + + self.assertEqual(""" + + +""", encodeutils.safe_decode(res)) + + def test_update_perf_events_xml_remove_all_events(self): + data = objects.LibvirtLiveMigrateData( + supported_perf_events=[]) + xml = """ + + + +""" + doc = etree.fromstring(xml) + res = etree.tostring(migration._update_perf_events_xml(doc, data)) + + self.assertEqual(""" + + +""", encodeutils.safe_decode(res)) + class MigrationMonitorTestCase(test.NoDBTestCase): diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index 57ee3b3ca671..8119dbe4ee34 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -6486,6 +6486,7 @@ class LibvirtDriver(driver.ComputeDriver): # Store live_migration_inbound_addr migrate_data.target_connect_addr = \ CONF.libvirt.live_migration_inbound_addr + migrate_data.supported_perf_events = self._supported_perf_events for vol in block_device_mapping: connection_info = vol['connection_info'] diff --git a/nova/virt/libvirt/migration.py b/nova/virt/libvirt/migration.py index 170f85e0b8fd..676335900a7a 100644 --- a/nova/virt/libvirt/migration.py +++ b/nova/virt/libvirt/migration.py @@ -60,6 +60,7 @@ def get_updated_guest_xml(guest, migrate_data, get_volume_config): xml_doc = _update_graphics_xml(xml_doc, migrate_data) xml_doc = _update_serial_xml(xml_doc, migrate_data) xml_doc = _update_volume_xml(xml_doc, migrate_data, get_volume_config) + xml_doc = _update_perf_events_xml(xml_doc, migrate_data) return etree.tostring(xml_doc) @@ -132,6 +133,40 @@ def _update_volume_xml(xml_doc, migrate_data, get_volume_config): return xml_doc +def _update_perf_events_xml(xml_doc, migrate_data): + """Update XML by the supported events of destination host.""" + + supported_perf_events = [] + old_xml_has_perf = True + + if 'supported_perf_events' in migrate_data: + supported_perf_events = migrate_data.supported_perf_events + + perf_events = xml_doc.findall('./perf') + + # remove perf events from xml + if not perf_events: + perf_events = etree.Element("perf") + old_xml_has_perf = False + else: + perf_events = perf_events[0] + for _, event in enumerate(perf_events): + perf_events.remove(event) + + if not supported_perf_events: + return xml_doc + + # add supported perf events + for e in supported_perf_events: + new_event = etree.Element("event", enabled="yes", name=e) + perf_events.append(new_event) + + if not old_xml_has_perf: + xml_doc.append(perf_events) + + return xml_doc + + def find_job_type(guest, instance): """Determine the (likely) current migration job type