diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java
index c4d5ac48f6f8..8b26bc94e218 100644
--- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java
+++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java
@@ -48,6 +48,7 @@
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.WatchDogDef;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.WatchDogDef.WatchDogAction;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.WatchDogDef.WatchDogModel;
+import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.GuestDef;
public class LibvirtDomainXMLParser {
protected Logger logger = LogManager.getLogger(getClass());
@@ -63,6 +64,8 @@ public class LibvirtDomainXMLParser {
private LibvirtVMDef.CpuTuneDef cpuTuneDef;
private LibvirtVMDef.CpuModeDef cpuModeDef;
private String name;
+ private GuestDef.BootType bootType;
+ private GuestDef.BootMode bootMode;
public boolean parseDomainXML(String domXML) {
DocumentBuilder builder;
@@ -388,6 +391,7 @@ public boolean parseDomainXML(String domXML) {
}
extractCpuTuneDef(rootElement);
extractCpuModeDef(rootElement);
+ extractBootDef(rootElement);
return true;
} catch (ParserConfigurationException e) {
logger.debug(e.toString());
@@ -516,6 +520,14 @@ public LibvirtVMDef.CpuModeDef getCpuModeDef() {
return cpuModeDef;
}
+ public GuestDef.BootType getBootType() {
+ return bootType;
+ }
+
+ public GuestDef.BootMode getBootMode() {
+ return bootMode;
+ }
+
private void extractCpuTuneDef(final Element rootElement) {
NodeList cpuTunesList = rootElement.getElementsByTagName("cputune");
if (cpuTunesList.getLength() > 0) {
@@ -569,4 +581,26 @@ private void extractCpuModeDef(final Element rootElement){
}
}
}
+
+ protected void extractBootDef(final Element rootElement) {
+ bootType = GuestDef.BootType.BIOS;
+ bootMode = GuestDef.BootMode.LEGACY;
+ Element osElement = (Element) rootElement.getElementsByTagName("os").item(0);
+ if (osElement == null) {
+ return;
+ }
+ NodeList loaderList = osElement.getElementsByTagName("loader");
+ if (loaderList.getLength() == 0) {
+ return;
+ }
+ Element loader = (Element) loaderList.item(0);
+ String type = loader.getAttribute("type");
+ String secure = loader.getAttribute("secure");
+ if ("pflash".equalsIgnoreCase(type) || loader.getTextContent().toLowerCase().contains("uefi")) {
+ bootType = GuestDef.BootType.UEFI;
+ }
+ if ("yes".equalsIgnoreCase(secure)) {
+ bootMode = GuestDef.BootMode.SECURE;
+ }
+ }
}
diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
index 93ad084b4379..5174563f675a 100644
--- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
+++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
@@ -65,7 +65,7 @@ public String toString() {
}
}
- enum BootType {
+ public enum BootType {
UEFI("UEFI"), BIOS("BIOS");
String _type;
@@ -80,7 +80,7 @@ public String toString() {
}
}
- enum BootMode {
+ public enum BootMode {
LEGACY("LEGACY"), SECURE("SECURE");
String _mode;
diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetUnmanagedInstancesCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetUnmanagedInstancesCommandWrapper.java
index 70b1715cc20a..e807bf3c8211 100644
--- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetUnmanagedInstancesCommandWrapper.java
+++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetUnmanagedInstancesCommandWrapper.java
@@ -135,6 +135,12 @@ private UnmanagedInstanceTO getUnmanagedInstance(LibvirtComputingResource libvir
instance.setNics(getUnmanagedInstanceNics(parser.getInterfaces()));
instance.setDisks(getUnmanagedInstanceDisks(parser.getDisks(),libvirtComputingResource, conn, domain.getName()));
instance.setVncPassword(getFormattedVncPassword(parser.getVncPasswd()));
+ if (parser.getBootType() != null) {
+ instance.setBootType(parser.getBootType().toString());
+ }
+ if (parser.getBootMode() != null) {
+ instance.setBootMode(parser.getBootMode().toString());
+ }
return instance;
} catch (Exception e) {
diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParserTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParserTest.java
index 921bbf0c9a87..de50cf342024 100644
--- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParserTest.java
+++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParserTest.java
@@ -20,8 +20,13 @@
package com.cloud.hypervisor.kvm.resource;
import java.io.File;
+import java.io.IOException;
+import java.io.StringReader;
import java.util.List;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.ParserConfigurationException;
+
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.ChannelDef;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef;
@@ -31,10 +36,15 @@
import junit.framework.TestCase;
import org.apache.cloudstack.utils.qemu.QemuObject;
+import org.apache.cloudstack.utils.security.ParserUtils;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
@RunWith(MockitoJUnitRunner.class)
public class LibvirtDomainXMLParserTest extends TestCase {
@@ -386,4 +396,84 @@ public void testDomainXMLParserWithoutModelName() {
Assert.assertEquals("CPU cores count is parsed", 4, libvirtDomainXMLParser.getCpuModeDef().getCoresPerSocket());
Assert.assertEquals("CPU threads count is parsed", 2, libvirtDomainXMLParser.getCpuModeDef().getThreadsPerCore());
}
+
+ private LibvirtDomainXMLParser parseElementFromXML(String xml) {
+ LibvirtDomainXMLParser parser = new LibvirtDomainXMLParser();
+ DocumentBuilder builder;
+ try {
+ builder = ParserUtils.getSaferDocumentBuilderFactory().newDocumentBuilder();
+ InputSource is = new InputSource();
+ is.setCharacterStream(new StringReader(xml));
+ Document doc = builder.parse(is);
+ Element element = doc.getDocumentElement();
+ parser.extractBootDef(element);
+ } catch (ParserConfigurationException | IOException | SAXException e) {
+ Assert.fail("Failed to parse XML: " + e.getMessage());
+ }
+ return parser;
+ }
+
+ @Test
+ public void extractBootDefParsesUEFISecureBootCorrectly() {
+ String xml = "" +
+ "" +
+ "/path/to/uefi/loader" +
+ "" +
+ "";
+
+ LibvirtDomainXMLParser parser = parseElementFromXML(xml);
+
+ assertEquals(LibvirtVMDef.GuestDef.BootType.UEFI, parser.getBootType());
+ assertEquals(LibvirtVMDef.GuestDef.BootMode.SECURE, parser.getBootMode());
+ }
+
+ @Test
+ public void extractBootDefParsesUEFILegacyBootCorrectly() {
+ String xml = "" +
+ "" +
+ "/path/to/uefi/loader" +
+ "" +
+ "";
+
+ LibvirtDomainXMLParser parser = parseElementFromXML(xml);
+
+ assertEquals(LibvirtVMDef.GuestDef.BootType.UEFI, parser.getBootType());
+ assertEquals(LibvirtVMDef.GuestDef.BootMode.LEGACY, parser.getBootMode());
+ }
+
+ @Test
+ public void extractBootDefDefaultsToBIOSLegacyWhenNoLoaderPresent() {
+ String xml = "" +
+ "" +
+ "hvm" +
+ "" +
+ "";
+
+ LibvirtDomainXMLParser parser = parseElementFromXML(xml);
+
+ assertEquals(LibvirtVMDef.GuestDef.BootType.BIOS, parser.getBootType());
+ assertEquals(LibvirtVMDef.GuestDef.BootMode.LEGACY, parser.getBootMode());
+ }
+
+ @Test
+ public void extractBootDefHandlesEmptyOSSection() {
+ String xml = "" +
+ "" +
+ "";
+
+ LibvirtDomainXMLParser parser = parseElementFromXML(xml);
+
+ assertEquals(LibvirtVMDef.GuestDef.BootType.BIOS, parser.getBootType());
+ assertEquals(LibvirtVMDef.GuestDef.BootMode.LEGACY, parser.getBootMode());
+ }
+
+ @Test
+ public void extractBootDefHandlesMissingOSSection() {
+ String xml = "";
+
+ LibvirtDomainXMLParser parser = parseElementFromXML(xml);
+
+ assertEquals(LibvirtVMDef.GuestDef.BootType.BIOS, parser.getBootType());
+ assertEquals(LibvirtVMDef.GuestDef.BootMode.LEGACY, parser.getBootMode());
+ }
}