Skip to content

Commit 9349b69

Browse files
authored
server,kvm: detect boot options for vm import (#11218)
* server,kvm: detect boot options for vm import Fixes #11184 Signed-off-by: Abhishek Kumar <[email protected]> * tests and changes Signed-off-by: Abhishek Kumar <[email protected]> --------- Signed-off-by: Abhishek Kumar <[email protected]>
1 parent 6868f05 commit 9349b69

File tree

4 files changed

+132
-2
lines changed

4 files changed

+132
-2
lines changed

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.WatchDogDef;
4949
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.WatchDogDef.WatchDogAction;
5050
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.WatchDogDef.WatchDogModel;
51+
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.GuestDef;
5152

5253
public class LibvirtDomainXMLParser {
5354
protected Logger logger = LogManager.getLogger(getClass());
@@ -63,6 +64,8 @@ public class LibvirtDomainXMLParser {
6364
private LibvirtVMDef.CpuTuneDef cpuTuneDef;
6465
private LibvirtVMDef.CpuModeDef cpuModeDef;
6566
private String name;
67+
private GuestDef.BootType bootType;
68+
private GuestDef.BootMode bootMode;
6669

6770
public boolean parseDomainXML(String domXML) {
6871
DocumentBuilder builder;
@@ -388,6 +391,7 @@ public boolean parseDomainXML(String domXML) {
388391
}
389392
extractCpuTuneDef(rootElement);
390393
extractCpuModeDef(rootElement);
394+
extractBootDef(rootElement);
391395
return true;
392396
} catch (ParserConfigurationException e) {
393397
logger.debug(e.toString());
@@ -516,6 +520,14 @@ public LibvirtVMDef.CpuModeDef getCpuModeDef() {
516520
return cpuModeDef;
517521
}
518522

523+
public GuestDef.BootType getBootType() {
524+
return bootType;
525+
}
526+
527+
public GuestDef.BootMode getBootMode() {
528+
return bootMode;
529+
}
530+
519531
private void extractCpuTuneDef(final Element rootElement) {
520532
NodeList cpuTunesList = rootElement.getElementsByTagName("cputune");
521533
if (cpuTunesList.getLength() > 0) {
@@ -569,4 +581,26 @@ private void extractCpuModeDef(final Element rootElement){
569581
}
570582
}
571583
}
584+
585+
protected void extractBootDef(final Element rootElement) {
586+
bootType = GuestDef.BootType.BIOS;
587+
bootMode = GuestDef.BootMode.LEGACY;
588+
Element osElement = (Element) rootElement.getElementsByTagName("os").item(0);
589+
if (osElement == null) {
590+
return;
591+
}
592+
NodeList loaderList = osElement.getElementsByTagName("loader");
593+
if (loaderList.getLength() == 0) {
594+
return;
595+
}
596+
Element loader = (Element) loaderList.item(0);
597+
String type = loader.getAttribute("type");
598+
String secure = loader.getAttribute("secure");
599+
if ("pflash".equalsIgnoreCase(type) || loader.getTextContent().toLowerCase().contains("uefi")) {
600+
bootType = GuestDef.BootType.UEFI;
601+
}
602+
if ("yes".equalsIgnoreCase(secure)) {
603+
bootMode = GuestDef.BootMode.SECURE;
604+
}
605+
}
572606
}

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public String toString() {
6565
}
6666
}
6767

68-
enum BootType {
68+
public enum BootType {
6969
UEFI("UEFI"), BIOS("BIOS");
7070

7171
String _type;
@@ -80,7 +80,7 @@ public String toString() {
8080
}
8181
}
8282

83-
enum BootMode {
83+
public enum BootMode {
8484
LEGACY("LEGACY"), SECURE("SECURE");
8585

8686
String _mode;

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetUnmanagedInstancesCommandWrapper.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,12 @@ private UnmanagedInstanceTO getUnmanagedInstance(LibvirtComputingResource libvir
135135
instance.setNics(getUnmanagedInstanceNics(parser.getInterfaces()));
136136
instance.setDisks(getUnmanagedInstanceDisks(parser.getDisks(),libvirtComputingResource, conn, domain.getName()));
137137
instance.setVncPassword(getFormattedVncPassword(parser.getVncPasswd()));
138+
if (parser.getBootType() != null) {
139+
instance.setBootType(parser.getBootType().toString());
140+
}
141+
if (parser.getBootMode() != null) {
142+
instance.setBootMode(parser.getBootMode().toString());
143+
}
138144

139145
return instance;
140146
} catch (Exception e) {

plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParserTest.java

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,13 @@
2020
package com.cloud.hypervisor.kvm.resource;
2121

2222
import java.io.File;
23+
import java.io.IOException;
24+
import java.io.StringReader;
2325
import java.util.List;
2426

27+
import javax.xml.parsers.DocumentBuilder;
28+
import javax.xml.parsers.ParserConfigurationException;
29+
2530
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.ChannelDef;
2631
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef;
2732
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef;
@@ -31,10 +36,15 @@
3136

3237
import junit.framework.TestCase;
3338
import org.apache.cloudstack.utils.qemu.QemuObject;
39+
import org.apache.cloudstack.utils.security.ParserUtils;
3440
import org.junit.Assert;
3541
import org.junit.Test;
3642
import org.junit.runner.RunWith;
3743
import org.mockito.junit.MockitoJUnitRunner;
44+
import org.w3c.dom.Document;
45+
import org.w3c.dom.Element;
46+
import org.xml.sax.InputSource;
47+
import org.xml.sax.SAXException;
3848

3949
@RunWith(MockitoJUnitRunner.class)
4050
public class LibvirtDomainXMLParserTest extends TestCase {
@@ -386,4 +396,84 @@ public void testDomainXMLParserWithoutModelName() {
386396
Assert.assertEquals("CPU cores count is parsed", 4, libvirtDomainXMLParser.getCpuModeDef().getCoresPerSocket());
387397
Assert.assertEquals("CPU threads count is parsed", 2, libvirtDomainXMLParser.getCpuModeDef().getThreadsPerCore());
388398
}
399+
400+
private LibvirtDomainXMLParser parseElementFromXML(String xml) {
401+
LibvirtDomainXMLParser parser = new LibvirtDomainXMLParser();
402+
DocumentBuilder builder;
403+
try {
404+
builder = ParserUtils.getSaferDocumentBuilderFactory().newDocumentBuilder();
405+
InputSource is = new InputSource();
406+
is.setCharacterStream(new StringReader(xml));
407+
Document doc = builder.parse(is);
408+
Element element = doc.getDocumentElement();
409+
parser.extractBootDef(element);
410+
} catch (ParserConfigurationException | IOException | SAXException e) {
411+
Assert.fail("Failed to parse XML: " + e.getMessage());
412+
}
413+
return parser;
414+
}
415+
416+
@Test
417+
public void extractBootDefParsesUEFISecureBootCorrectly() {
418+
String xml = "<domain type='kvm'>" +
419+
"<os>" +
420+
"<loader type='pflash' secure='yes'>/path/to/uefi/loader</loader>" +
421+
"</os>" +
422+
"</domain>";
423+
424+
LibvirtDomainXMLParser parser = parseElementFromXML(xml);
425+
426+
assertEquals(LibvirtVMDef.GuestDef.BootType.UEFI, parser.getBootType());
427+
assertEquals(LibvirtVMDef.GuestDef.BootMode.SECURE, parser.getBootMode());
428+
}
429+
430+
@Test
431+
public void extractBootDefParsesUEFILegacyBootCorrectly() {
432+
String xml = "<domain type='kvm'>" +
433+
"<os>" +
434+
"<loader type='pflash' secure='no'>/path/to/uefi/loader</loader>" +
435+
"</os>" +
436+
"</domain>";
437+
438+
LibvirtDomainXMLParser parser = parseElementFromXML(xml);
439+
440+
assertEquals(LibvirtVMDef.GuestDef.BootType.UEFI, parser.getBootType());
441+
assertEquals(LibvirtVMDef.GuestDef.BootMode.LEGACY, parser.getBootMode());
442+
}
443+
444+
@Test
445+
public void extractBootDefDefaultsToBIOSLegacyWhenNoLoaderPresent() {
446+
String xml = "<domain type='kvm'>" +
447+
"<os>" +
448+
"<type arch='x86_64'>hvm</type>" +
449+
"</os>" +
450+
"</domain>";
451+
452+
LibvirtDomainXMLParser parser = parseElementFromXML(xml);
453+
454+
assertEquals(LibvirtVMDef.GuestDef.BootType.BIOS, parser.getBootType());
455+
assertEquals(LibvirtVMDef.GuestDef.BootMode.LEGACY, parser.getBootMode());
456+
}
457+
458+
@Test
459+
public void extractBootDefHandlesEmptyOSSection() {
460+
String xml = "<domain type='kvm'>" +
461+
"<os></os>" +
462+
"</domain>";
463+
464+
LibvirtDomainXMLParser parser = parseElementFromXML(xml);
465+
466+
assertEquals(LibvirtVMDef.GuestDef.BootType.BIOS, parser.getBootType());
467+
assertEquals(LibvirtVMDef.GuestDef.BootMode.LEGACY, parser.getBootMode());
468+
}
469+
470+
@Test
471+
public void extractBootDefHandlesMissingOSSection() {
472+
String xml = "<domain type='kvm'></domain>";
473+
474+
LibvirtDomainXMLParser parser = parseElementFromXML(xml);
475+
476+
assertEquals(LibvirtVMDef.GuestDef.BootType.BIOS, parser.getBootType());
477+
assertEquals(LibvirtVMDef.GuestDef.BootMode.LEGACY, parser.getBootMode());
478+
}
389479
}

0 commit comments

Comments
 (0)