Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand All @@ -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;
Expand Down Expand Up @@ -388,6 +391,7 @@ public boolean parseDomainXML(String domXML) {
}
extractCpuTuneDef(rootElement);
extractCpuModeDef(rootElement);
extractBootDef(rootElement);
return true;
} catch (ParserConfigurationException e) {
logger.debug(e.toString());
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public String toString() {
}
}

enum BootType {
public enum BootType {
UEFI("UEFI"), BIOS("BIOS");

String _type;
Expand All @@ -80,7 +80,7 @@ public String toString() {
}
}

enum BootMode {
public enum BootMode {
LEGACY("LEGACY"), SECURE("SECURE");

String _mode;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {
Expand Down Expand Up @@ -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 = "<domain type='kvm'>" +
"<os>" +
"<loader type='pflash' secure='yes'>/path/to/uefi/loader</loader>" +
"</os>" +
"</domain>";

LibvirtDomainXMLParser parser = parseElementFromXML(xml);

assertEquals(LibvirtVMDef.GuestDef.BootType.UEFI, parser.getBootType());
assertEquals(LibvirtVMDef.GuestDef.BootMode.SECURE, parser.getBootMode());
}

@Test
public void extractBootDefParsesUEFILegacyBootCorrectly() {
String xml = "<domain type='kvm'>" +
"<os>" +
"<loader type='pflash' secure='no'>/path/to/uefi/loader</loader>" +
"</os>" +
"</domain>";

LibvirtDomainXMLParser parser = parseElementFromXML(xml);

assertEquals(LibvirtVMDef.GuestDef.BootType.UEFI, parser.getBootType());
assertEquals(LibvirtVMDef.GuestDef.BootMode.LEGACY, parser.getBootMode());
}

@Test
public void extractBootDefDefaultsToBIOSLegacyWhenNoLoaderPresent() {
String xml = "<domain type='kvm'>" +
"<os>" +
"<type arch='x86_64'>hvm</type>" +
"</os>" +
"</domain>";

LibvirtDomainXMLParser parser = parseElementFromXML(xml);

assertEquals(LibvirtVMDef.GuestDef.BootType.BIOS, parser.getBootType());
assertEquals(LibvirtVMDef.GuestDef.BootMode.LEGACY, parser.getBootMode());
}

@Test
public void extractBootDefHandlesEmptyOSSection() {
String xml = "<domain type='kvm'>" +
"<os></os>" +
"</domain>";

LibvirtDomainXMLParser parser = parseElementFromXML(xml);

assertEquals(LibvirtVMDef.GuestDef.BootType.BIOS, parser.getBootType());
assertEquals(LibvirtVMDef.GuestDef.BootMode.LEGACY, parser.getBootMode());
}

@Test
public void extractBootDefHandlesMissingOSSection() {
String xml = "<domain type='kvm'></domain>";

LibvirtDomainXMLParser parser = parseElementFromXML(xml);

assertEquals(LibvirtVMDef.GuestDef.BootType.BIOS, parser.getBootType());
assertEquals(LibvirtVMDef.GuestDef.BootMode.LEGACY, parser.getBootMode());
}
}
Loading