From 10567e0145ce651c327267d8f4ea31d82bc7e239 Mon Sep 17 00:00:00 2001 From: Manuel Bentele Date: Fri, 29 Jan 2021 12:22:05 +0100 Subject: Add base classes and utilites to represent Libvirt XML documents --- .../libvirt/xml/LibvirtXmlDocumentTest.java | 262 +++++++++++++++++++++ .../libvirt/xml/LibvirtXmlTestResources.java | 29 +++ 2 files changed, 291 insertions(+) create mode 100644 src/test/java/org/openslx/libvirt/xml/LibvirtXmlDocumentTest.java create mode 100644 src/test/java/org/openslx/libvirt/xml/LibvirtXmlTestResources.java (limited to 'src/test/java/org/openslx/libvirt/xml') diff --git a/src/test/java/org/openslx/libvirt/xml/LibvirtXmlDocumentTest.java b/src/test/java/org/openslx/libvirt/xml/LibvirtXmlDocumentTest.java new file mode 100644 index 0000000..1b6e5a5 --- /dev/null +++ b/src/test/java/org/openslx/libvirt/xml/LibvirtXmlDocumentTest.java @@ -0,0 +1,262 @@ +package org.openslx.libvirt.xml; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.fail; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamSource; + +import org.apache.commons.io.FileUtils; +import org.apache.log4j.Level; +import org.apache.log4j.LogManager; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.function.Executable; + +class LibvirtXmlDocumentStub extends LibvirtXmlDocument +{ + public LibvirtXmlDocumentStub( File xml ) + throws LibvirtXmlDocumentException, LibvirtXmlSerializationException, LibvirtXmlValidationException + { + super( xml ); + } + + public LibvirtXmlDocumentStub( File xml, Source rngSchema ) + throws LibvirtXmlDocumentException, LibvirtXmlSerializationException, LibvirtXmlValidationException + { + super( xml, rngSchema ); + } +} + +public class LibvirtXmlDocumentTest +{ + private static final String EMPTY = new String(); + + @BeforeAll + public static void setUp() + { + // disable logging with log4j + LogManager.getRootLogger().setLevel( Level.OFF ); + } + + private LibvirtXmlDocument newLibvirtXmlDocumentInstance( String xmlFileName ) + { + LibvirtXmlDocument document = null; + + try { + File xmlFile = LibvirtXmlTestResources.getLibvirtXmlFile( xmlFileName ); + document = new LibvirtXmlDocumentStub( xmlFile ); + } catch ( LibvirtXmlDocumentException | LibvirtXmlSerializationException | LibvirtXmlValidationException e ) { + String errorMsg = new String( "Cannot prepare requested Libvirt XML file from the resources folder" ); + fail( errorMsg ); + } + + return document; + } + + private LibvirtXmlDocument newLibvirtXmlDocumentValidationInstance( String xmlFileName, String rngSchemaFileName ) + throws LibvirtXmlValidationException + { + LibvirtXmlDocument document = null; + + try { + File xmlFile = LibvirtXmlTestResources.getLibvirtXmlFile( xmlFileName ); + Source rngSchemaSource = new StreamSource( LibvirtXmlResources.getLibvirtRng( rngSchemaFileName ) ); + document = new LibvirtXmlDocumentStub( xmlFile, rngSchemaSource ); + } catch ( LibvirtXmlDocumentException | LibvirtXmlSerializationException e ) { + String errorMsg = new String( "Cannot prepare requested Libvirt XML file from the resources folder" ); + fail( errorMsg ); + } + + return document; + } + + @Test + @DisplayName( "Read libvirt XML file to String" ) + public void testReadXmlFileToString() throws LibvirtXmlSerializationException, IOException + { + LibvirtXmlDocument vm = this.newLibvirtXmlDocumentInstance( "qemu-kvm_default-ubuntu-20-04-vm.xml" ); + File originalXmlFile = LibvirtXmlTestResources.getLibvirtXmlFile( "qemu-kvm_default-ubuntu-20-04-vm.xml" ); + + final String readXmlContent = vm.toXml(); + final String originalXmlContent = FileUtils.readFileToString( originalXmlFile, StandardCharsets.UTF_8 ); + + assertNotNull( readXmlContent ); + + final int lengthReadXmlContent = readXmlContent.split( System.lineSeparator() ).length; + final int lengthOriginalXmlContent = originalXmlContent.split( System.lineSeparator() ).length; + + assertEquals( lengthOriginalXmlContent, lengthReadXmlContent ); + } + + @Test + @DisplayName( "Read libvirt XML file to file" ) + public void testReadXmlFileToFile() throws LibvirtXmlSerializationException, IOException + { + LibvirtXmlDocument vm = this.newLibvirtXmlDocumentInstance( "qemu-kvm_default-ubuntu-20-04-vm.xml" ); + File originalXmlFile = LibvirtXmlTestResources.getLibvirtXmlFile( "qemu-kvm_default-ubuntu-20-04-vm.xml" ); + File readXmlFile = LibvirtXmlTestResources.createLibvirtXmlTempFile(); + + vm.toXml( readXmlFile ); + + final String readXmlContent = FileUtils.readFileToString( readXmlFile, StandardCharsets.UTF_8 ); + final String originalXmlContent = FileUtils.readFileToString( originalXmlFile, StandardCharsets.UTF_8 ); + + assertNotNull( readXmlContent ); + + final int lengthReadXmlContent = readXmlContent.split( System.lineSeparator() ).length; + final int lengthOriginalXmlContent = originalXmlContent.split( System.lineSeparator() ).length; + + assertEquals( lengthOriginalXmlContent, lengthReadXmlContent ); + } + + @Test + @DisplayName( "Validate correct libvirt XML file" ) + public void testValidateCorrectXmlFile() + { + Executable validateXmlDocument = () -> { + this.newLibvirtXmlDocumentValidationInstance( "qemu-kvm_default-ubuntu-20-04-vm.xml", "domain.rng" ); + }; + + assertDoesNotThrow( validateXmlDocument ); + } + + @Test + @DisplayName( "Validate incorrect libvirt XML file" ) + public void testValidateIncorrectXmlFile() + { + Executable validateXmlDocument = () -> { + this.newLibvirtXmlDocumentValidationInstance( "qemu-kvm_default-ubuntu-20-04-vm-invalid.xml", "domain.rng" ); + }; + + assertThrows( LibvirtXmlValidationException.class, validateXmlDocument ); + } + + @Test + @DisplayName( "Get non-existent node from libvirt XML file" ) + public void testGetNonExistentElement() + { + LibvirtXmlDocument vm = this.newLibvirtXmlDocumentInstance( "qemu-kvm_default-ubuntu-20-04-vm.xml" ); + assertNull( vm.getRootXmlNode().getXmlElement( "info" ) ); + } + + @Test + @DisplayName( "Set non-existent node in libvirt XML file" ) + public void testSetNonExistentElement() + { + LibvirtXmlDocument vm = this.newLibvirtXmlDocumentInstance( "qemu-kvm_default-ubuntu-20-04-vm.xml" ); + vm.getRootXmlNode().setXmlElement( "info" ); + assertNotNull( vm.getRootXmlNode().getXmlElement( "info" ) ); + } + + @Test + @DisplayName( "Get non-existent element's value in libvirt XML file" ) + public void testGetNonExistentElementValue() + { + LibvirtXmlDocument vm = this.newLibvirtXmlDocumentInstance( "qemu-kvm_default-ubuntu-20-04-vm.xml" ); + assertNull( vm.getRootXmlNode().getXmlElementValue( "info" ) ); + } + + @Test + @DisplayName( "Set non-existent element's value in libvirt XML file" ) + public void testSetNonExistentElementValue() + { + LibvirtXmlDocument vm = this.newLibvirtXmlDocumentInstance( "qemu-kvm_default-ubuntu-20-04-vm.xml" ); + vm.getRootXmlNode().setXmlElementValue( "info", "content" ); + assertEquals( "content", vm.getRootXmlNode().getXmlElementValue( "info" ) ); + } + + @Test + @DisplayName( "Get empty element from libvirt XML file" ) + public void testGetEmptyElement() + { + LibvirtXmlDocument vm = this.newLibvirtXmlDocumentInstance( "qemu-kvm_default-ubuntu-20-04-vm.xml" ); + assertNotNull( vm.getRootXmlNode().getXmlElement( "features/acpi" ) ); + } + + @Test + @DisplayName( "Set empty element in libvirt XML file" ) + public void testSetEmptyElement() + { + LibvirtXmlDocument vm = this.newLibvirtXmlDocumentInstance( "qemu-kvm_default-ubuntu-20-04-vm.xml" ); + vm.getRootXmlNode().setXmlElement( "features/acpi" ); + assertNotNull( vm.getRootXmlNode().getXmlElement( "features/acpi" ) ); + } + + @Test + @DisplayName( "Get empty element's value from libvirt XML file" ) + public void testGetEmptyElementValue() + { + LibvirtXmlDocument vm = this.newLibvirtXmlDocumentInstance( "qemu-kvm_default-ubuntu-20-04-vm.xml" ); + assertEquals( EMPTY, vm.getRootXmlNode().getXmlElementValue( "features/acpi" ) ); + } + + @Test + @DisplayName( "Set empty element's value in libvirt XML file" ) + public void testSetEmptyElementValue() + { + LibvirtXmlDocument vm = this.newLibvirtXmlDocumentInstance( "qemu-kvm_default-ubuntu-20-04-vm.xml" ); + vm.getRootXmlNode().setXmlElementValue( "features/acpi", "content" ); + assertEquals( "content", vm.getRootXmlNode().getXmlElementValue( "features/acpi" ) ); + } + + @Test + @DisplayName( "Get non-existent element's attribute value from libvirt XML file" ) + public void testGetNonExistentElementAttributeValue() + { + LibvirtXmlDocument vm = this.newLibvirtXmlDocumentInstance( "qemu-kvm_default-ubuntu-20-04-vm.xml" ); + assertNull( vm.getRootXmlNode().getXmlElementAttributeValue( "info", "test" ) ); + } + + @Test + @DisplayName( "Set non-existent element's attribute value from libvirt XML file" ) + public void testSetNonExistentElementAttributeValue() + { + LibvirtXmlDocument vm = this.newLibvirtXmlDocumentInstance( "qemu-kvm_default-ubuntu-20-04-vm.xml" ); + vm.getRootXmlNode().setXmlElementAttributeValue( "info", "test", "info" ); + assertEquals( "info", vm.getRootXmlNode().getXmlElementAttributeValue( "info", "test" ) ); + } + + @Test + @DisplayName( "Get element's non-existent attribute value from libvirt XML file" ) + public void testGetElementNonExistentAttributeValue() + { + LibvirtXmlDocument vm = this.newLibvirtXmlDocumentInstance( "qemu-kvm_default-ubuntu-20-04-vm.xml" ); + assertNull( vm.getRootXmlNode().getXmlElementAttributeValue( "features/acpi", "test" ) ); + } + + @Test + @DisplayName( "Set element's non-existent attribute value from libvirt XML file" ) + public void testSetElementNonExistentAttributeValue() + { + LibvirtXmlDocument vm = this.newLibvirtXmlDocumentInstance( "qemu-kvm_default-ubuntu-20-04-vm.xml" ); + vm.getRootXmlNode().setXmlElementAttributeValue( "features/acpi", "test", "info" ); + assertEquals( "info", vm.getRootXmlNode().getXmlElementAttributeValue( "features/acpi", "test" ) ); + } + + @Test + @DisplayName( "Get element's attribute value from libvirt XML file" ) + public void testGetElementAttributeValue() + { + LibvirtXmlDocument vm = this.newLibvirtXmlDocumentInstance( "qemu-kvm_default-ubuntu-20-04-vm.xml" ); + assertEquals( "partial", vm.getRootXmlNode().getXmlElementAttributeValue( "cpu", "check" ) ); + } + + @Test + @DisplayName( "Set element's attribute value from libvirt XML file" ) + public void testSetElementAttributeValue() + { + LibvirtXmlDocument vm = this.newLibvirtXmlDocumentInstance( "qemu-kvm_default-ubuntu-20-04-vm.xml" ); + vm.getRootXmlNode().setXmlElementAttributeValue( "cpu", "check", "full" ); + assertEquals( "full", vm.getRootXmlNode().getXmlElementAttributeValue( "cpu", "check" ) ); + } +} diff --git a/src/test/java/org/openslx/libvirt/xml/LibvirtXmlTestResources.java b/src/test/java/org/openslx/libvirt/xml/LibvirtXmlTestResources.java new file mode 100644 index 0000000..6cc0360 --- /dev/null +++ b/src/test/java/org/openslx/libvirt/xml/LibvirtXmlTestResources.java @@ -0,0 +1,29 @@ +package org.openslx.libvirt.xml; + +import java.io.File; +import java.io.IOException; +import java.net.URL; + +public final class LibvirtXmlTestResources +{ + private static final String LIBVIRT_PREFIX_PATH = File.separator + "libvirt"; + private static final String LIBVIRT_PREFIX_PATH_XML = LIBVIRT_PREFIX_PATH + File.separator + "xml"; + + private static final String LIBVIRT_TEMP_PREFIX = "libvirt-"; + private static final String LIBVIRT_TEMP_SUFFIX = ".xml"; + + public static File getLibvirtXmlFile( String libvirtXmlFileName ) + { + String libvirtXmlPath = LibvirtXmlTestResources.LIBVIRT_PREFIX_PATH_XML + File.separator + libvirtXmlFileName; + URL libvirtXml = LibvirtXmlTestResources.class.getResource( libvirtXmlPath ); + return new File( libvirtXml.getFile() ); + } + + public static File createLibvirtXmlTempFile() throws IOException + { + File tempFile = File.createTempFile( LibvirtXmlTestResources.LIBVIRT_TEMP_PREFIX, + LibvirtXmlTestResources.LIBVIRT_TEMP_SUFFIX ); + tempFile.deleteOnExit(); + return tempFile; + } +} -- cgit v1.2.3-55-g7522 From 4317a82d74d8b8518a5dbb6b3675aec3f912802e Mon Sep 17 00:00:00 2001 From: Manuel Bentele Date: Sat, 30 Jan 2021 12:00:35 +0100 Subject: Add automatic RelaxNG schema validation for Libvirt domain XML documents --- src/main/java/org/openslx/libvirt/domain/Domain.java | 9 +++++---- src/main/java/org/openslx/libvirt/xml/LibvirtXmlDocument.java | 11 +++++------ .../org/openslx/libvirt/xml/LibvirtXmlSchemaValidator.java | 7 +++---- .../java/org/openslx/libvirt/xml/LibvirtXmlDocumentTest.java | 10 ++++------ 4 files changed, 17 insertions(+), 20 deletions(-) (limited to 'src/test/java/org/openslx/libvirt/xml') diff --git a/src/main/java/org/openslx/libvirt/domain/Domain.java b/src/main/java/org/openslx/libvirt/domain/Domain.java index 35cd012..4e15ec1 100644 --- a/src/main/java/org/openslx/libvirt/domain/Domain.java +++ b/src/main/java/org/openslx/libvirt/domain/Domain.java @@ -33,6 +33,7 @@ import org.openslx.libvirt.domain.device.Video; import org.openslx.libvirt.xml.LibvirtXmlDocument; import org.openslx.libvirt.xml.LibvirtXmlDocumentException; import org.openslx.libvirt.xml.LibvirtXmlNode; +import org.openslx.libvirt.xml.LibvirtXmlResources; import org.openslx.libvirt.xml.LibvirtXmlSerializationException; import org.openslx.libvirt.xml.LibvirtXmlValidationException; import org.w3c.dom.Node; @@ -61,7 +62,7 @@ public class Domain extends LibvirtXmlDocument public Domain( String xml ) throws LibvirtXmlDocumentException, LibvirtXmlSerializationException, LibvirtXmlValidationException { - super( xml ); + super( xml, LibvirtXmlResources.getLibvirtRng( "domain.rng" ) ); } /** @@ -76,7 +77,7 @@ public class Domain extends LibvirtXmlDocument public Domain( File xml ) throws LibvirtXmlDocumentException, LibvirtXmlSerializationException, LibvirtXmlValidationException { - super( xml ); + super( xml, LibvirtXmlResources.getLibvirtRng( "domain.rng" ) ); } /** @@ -92,7 +93,7 @@ public class Domain extends LibvirtXmlDocument public Domain( InputStream xml ) throws LibvirtXmlDocumentException, LibvirtXmlSerializationException, LibvirtXmlValidationException { - super( xml ); + super( xml, LibvirtXmlResources.getLibvirtRng( "domain.rng" ) ); } /** @@ -108,7 +109,7 @@ public class Domain extends LibvirtXmlDocument public Domain( InputSource xml ) throws LibvirtXmlDocumentException, LibvirtXmlSerializationException, LibvirtXmlValidationException { - super( xml ); + super( xml, LibvirtXmlResources.getLibvirtRng( "domain.rng" ) ); } /** diff --git a/src/main/java/org/openslx/libvirt/xml/LibvirtXmlDocument.java b/src/main/java/org/openslx/libvirt/xml/LibvirtXmlDocument.java index abab162..8fe642b 100644 --- a/src/main/java/org/openslx/libvirt/xml/LibvirtXmlDocument.java +++ b/src/main/java/org/openslx/libvirt/xml/LibvirtXmlDocument.java @@ -9,7 +9,6 @@ import java.io.StringWriter; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; @@ -66,7 +65,7 @@ public abstract class LibvirtXmlDocument implements LibvirtXmlSerializable, Libv * @throws LibvirtXmlDocumentException error occured during setup of the XML context to read and * write from/to a Libvirt XML file. */ - private void createXmlContext( Source rngSchema ) throws LibvirtXmlDocumentException + private void createXmlContext( InputStream rngSchema ) throws LibvirtXmlDocumentException { // used for XML input try { @@ -134,7 +133,7 @@ public abstract class LibvirtXmlDocument implements LibvirtXmlSerializable, Libv * @throws LibvirtXmlSerializationException serialization of the XML content failed. * @throws LibvirtXmlValidationException XML content is not a valid Libvirt XML. */ - public LibvirtXmlDocument( String xml, Source rngSchema ) + public LibvirtXmlDocument( String xml, InputStream rngSchema ) throws LibvirtXmlDocumentException, LibvirtXmlSerializationException, LibvirtXmlValidationException { this.createXmlContext( rngSchema ); @@ -167,7 +166,7 @@ public abstract class LibvirtXmlDocument implements LibvirtXmlSerializable, Libv * @throws LibvirtXmlSerializationException serialization of the XML content failed. * @throws LibvirtXmlValidationException XML content is not a valid Libvirt XML. */ - public LibvirtXmlDocument( File xml, Source rngSchema ) + public LibvirtXmlDocument( File xml, InputStream rngSchema ) throws LibvirtXmlDocumentException, LibvirtXmlSerializationException, LibvirtXmlValidationException { this.createXmlContext( rngSchema ); @@ -200,7 +199,7 @@ public abstract class LibvirtXmlDocument implements LibvirtXmlSerializable, Libv * @throws LibvirtXmlSerializationException serialization of the XML content failed. * @throws LibvirtXmlValidationException XML content is not a valid Libvirt XML. */ - public LibvirtXmlDocument( InputStream xml, Source rngSchema ) + public LibvirtXmlDocument( InputStream xml, InputStream rngSchema ) throws LibvirtXmlDocumentException, LibvirtXmlSerializationException, LibvirtXmlValidationException { this.createXmlContext( rngSchema ); @@ -233,7 +232,7 @@ public abstract class LibvirtXmlDocument implements LibvirtXmlSerializable, Libv * @throws LibvirtXmlSerializationException serialization of the XML content failed. * @throws LibvirtXmlValidationException XML content is not a valid Libvirt XML. */ - public LibvirtXmlDocument( InputSource xml, Source rngSchema ) + public LibvirtXmlDocument( InputSource xml, InputStream rngSchema ) throws LibvirtXmlDocumentException, LibvirtXmlSerializationException, LibvirtXmlValidationException { this.createXmlContext( rngSchema ); diff --git a/src/main/java/org/openslx/libvirt/xml/LibvirtXmlSchemaValidator.java b/src/main/java/org/openslx/libvirt/xml/LibvirtXmlSchemaValidator.java index 01e8adb..e074948 100644 --- a/src/main/java/org/openslx/libvirt/xml/LibvirtXmlSchemaValidator.java +++ b/src/main/java/org/openslx/libvirt/xml/LibvirtXmlSchemaValidator.java @@ -8,7 +8,6 @@ import java.io.InputStream; import java.io.Reader; import javax.xml.XMLConstants; -import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; @@ -200,7 +199,7 @@ public class LibvirtXmlSchemaValidator * @param rngSchema * @throws SAXException */ - public LibvirtXmlSchemaValidator( Source rngSchema ) throws SAXException + public LibvirtXmlSchemaValidator( InputStream rngSchema ) throws SAXException { this.createValidationContext( rngSchema ); } @@ -212,7 +211,7 @@ public class LibvirtXmlSchemaValidator * * @throws SAXException Loading, creation and processing of rngSchema has failed. */ - private void createValidationContext( Source rngSchema ) throws SAXException + private void createValidationContext( InputStream rngSchema ) throws SAXException { // use hack to load specific schema factory implementation for RelaxNG schemas System.setProperty( SchemaFactory.class.getName() + ":" + XMLConstants.RELAXNG_NS_URI, @@ -224,7 +223,7 @@ public class LibvirtXmlSchemaValidator // create schema factory to be able to create a RelaxNG schema validator SchemaFactory factory = SchemaFactory.newInstance( XMLConstants.RELAXNG_NS_URI ); factory.setResourceResolver( schemaResolver ); - Schema schema = factory.newSchema( rngSchema ); + Schema schema = factory.newSchema( new StreamSource( rngSchema ) ); // create the RelaxNG schema validator this.rngSchemaValidator = schema.newValidator(); diff --git a/src/test/java/org/openslx/libvirt/xml/LibvirtXmlDocumentTest.java b/src/test/java/org/openslx/libvirt/xml/LibvirtXmlDocumentTest.java index 1b6e5a5..75b934e 100644 --- a/src/test/java/org/openslx/libvirt/xml/LibvirtXmlDocumentTest.java +++ b/src/test/java/org/openslx/libvirt/xml/LibvirtXmlDocumentTest.java @@ -9,11 +9,9 @@ import static org.junit.jupiter.api.Assertions.fail; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.nio.charset.StandardCharsets; -import javax.xml.transform.Source; -import javax.xml.transform.stream.StreamSource; - import org.apache.commons.io.FileUtils; import org.apache.log4j.Level; import org.apache.log4j.LogManager; @@ -30,7 +28,7 @@ class LibvirtXmlDocumentStub extends LibvirtXmlDocument super( xml ); } - public LibvirtXmlDocumentStub( File xml, Source rngSchema ) + public LibvirtXmlDocumentStub( File xml, InputStream rngSchema ) throws LibvirtXmlDocumentException, LibvirtXmlSerializationException, LibvirtXmlValidationException { super( xml, rngSchema ); @@ -70,8 +68,8 @@ public class LibvirtXmlDocumentTest try { File xmlFile = LibvirtXmlTestResources.getLibvirtXmlFile( xmlFileName ); - Source rngSchemaSource = new StreamSource( LibvirtXmlResources.getLibvirtRng( rngSchemaFileName ) ); - document = new LibvirtXmlDocumentStub( xmlFile, rngSchemaSource ); + InputStream rngSchema = LibvirtXmlResources.getLibvirtRng( rngSchemaFileName ); + document = new LibvirtXmlDocumentStub( xmlFile, rngSchema ); } catch ( LibvirtXmlDocumentException | LibvirtXmlSerializationException e ) { String errorMsg = new String( "Cannot prepare requested Libvirt XML file from the resources folder" ); fail( errorMsg ); -- cgit v1.2.3-55-g7522