From 87ee88f10a7cb3c7ce08c6bb9bb88cc8af25dd96 Mon Sep 17 00:00:00 2001 From: Balazs Gibizer Date: Tue, 23 Jan 2024 11:55:32 +0100 Subject: [PATCH] [libvirt]log XML if nova fails to parse it In case nova fails to parse the XML from libvirt the lxml exception is dumped to the log but it only states the location of the error in the XML string like lxml.etree.XMLSyntaxError: StartTag: invalid element name, line 40, column 35 To be able to troubleshoot the actual XML error we need to see the invalid XML as well. So this patch makes sure that if nova fails to parse the XML then the XML itself is dumped to DEBUG log. Change-Id: I14cce6db4c86f663e61d3668d081858741e88add --- nova/tests/unit/virt/libvirt/test_config.py | 13 +++++++++++++ nova/virt/libvirt/config.py | 8 +++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/nova/tests/unit/virt/libvirt/test_config.py b/nova/tests/unit/virt/libvirt/test_config.py index 2c96bd2a67..01c5e43485 100644 --- a/nova/tests/unit/virt/libvirt/test_config.py +++ b/nova/tests/unit/virt/libvirt/test_config.py @@ -13,6 +13,8 @@ # under the License. import ddt +from unittest import mock + from lxml import etree from oslo_utils.fixture import uuidsentinel as uuids from oslo_utils import units @@ -80,6 +82,17 @@ class LibvirtConfigTest(LibvirtConfigBaseTest): obj = config.LibvirtConfigObject(root_name="demo") obj.parse_str(inxml) + @mock.patch.object(config.LOG, 'debug') + def test_config_parse_error_xml_logged(self, mock_debug): + inxml = "6<1" + obj = config.LibvirtConfigObject(root_name="demo") + + self.assertRaises(etree.XMLSyntaxError, obj.parse_str, inxml) + + mock_debug.assert_called_once_with( + 'Failed to parse the libvirt XML: %s', + "6<1") + def test_parse_on_off_str(self): obj = config.LibvirtConfigObject(root_name="demo") self.assertTrue(obj.parse_on_off_str('on')) diff --git a/nova/virt/libvirt/config.py b/nova/virt/libvirt/config.py index 76657231d5..a4395b4d28 100644 --- a/nova/virt/libvirt/config.py +++ b/nova/virt/libvirt/config.py @@ -28,6 +28,7 @@ import typing as ty from collections import OrderedDict from lxml import etree +from oslo_log import log as logging from oslo_utils import strutils from oslo_utils import units @@ -37,6 +38,7 @@ from nova.objects import fields from nova.pci import utils as pci_utils from nova.virt import hardware +LOG = logging.getLogger(__name__) # Namespace to use for Nova specific metadata items in XML NOVA_NS = "http://openstack.org/xmlns/libvirt/nova/1.1" @@ -83,7 +85,11 @@ class LibvirtConfigObject(object): return self._new_node(self.root_name) def parse_str(self, xmlstr): - self.parse_dom(etree.fromstring(xmlstr)) + try: + self.parse_dom(etree.fromstring(xmlstr)) + except etree.Error: + LOG.debug("Failed to parse the libvirt XML: %s", xmlstr) + raise def parse_dom(self, xmldoc): if self.root_name != xmldoc.tag: