Skip to content

Commit 8089d32

Browse files
committed
Merge remote-tracking branch 'apache/4.20'
2 parents 3d6ec29 + 7044564 commit 8089d32

File tree

25 files changed

+390
-88
lines changed

25 files changed

+390
-88
lines changed

api/src/main/java/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotFromVMSnapshotCmd.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,4 +209,9 @@ public Long getSyncObjId() {
209209
}
210210
return null;
211211
}
212+
213+
@Override
214+
public Long getApiResourceId() {
215+
return getEntityId();
216+
}
212217
}

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

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,21 @@ protected boolean isValidProtocolAndVnetId(final String vNetId, final String pro
188188
return vNetId != null && protocol != null && !vNetId.equalsIgnoreCase("untagged");
189189
}
190190

191+
protected String createStorageVnetBridgeIfNeeded(NicTO nic, String trafficLabel,
192+
String storageBrName) throws InternalErrorException {
193+
if (!Networks.BroadcastDomainType.Storage.equals(nic.getBroadcastType()) || nic.getBroadcastUri() == null) {
194+
return storageBrName;
195+
}
196+
String vNetId = Networks.BroadcastDomainType.getValue(nic.getBroadcastUri());
197+
String protocol = Networks.BroadcastDomainType.Vlan.scheme();
198+
if (!isValidProtocolAndVnetId(vNetId, protocol)) {
199+
return storageBrName;
200+
}
201+
logger.debug(String.format("creating a vNet dev and bridge for %s traffic per traffic label %s",
202+
Networks.TrafficType.Storage.name(), trafficLabel));
203+
return createVnetBr(vNetId, storageBrName, protocol);
204+
}
205+
191206
@Override
192207
public LibvirtVMDef.InterfaceDef plug(NicTO nic, String guestOsType, String nicAdapter, Map<String, String> extraConfig) throws InternalErrorException, LibvirtException {
193208

@@ -254,15 +269,7 @@ public LibvirtVMDef.InterfaceDef plug(NicTO nic, String guestOsType, String nicA
254269
intf.defBridgeNet(_bridges.get("private"), null, nic.getMac(), getGuestNicModel(guestOsType, nicAdapter));
255270
} else if (nic.getType() == Networks.TrafficType.Storage) {
256271
String storageBrName = nic.getName() == null ? _bridges.get("private") : nic.getName();
257-
if (nic.getBroadcastType() == Networks.BroadcastDomainType.Storage) {
258-
vNetId = Networks.BroadcastDomainType.getValue(nic.getBroadcastUri());
259-
protocol = Networks.BroadcastDomainType.Vlan.scheme();
260-
}
261-
if (isValidProtocolAndVnetId(vNetId, protocol)) {
262-
logger.debug(String.format("creating a vNet dev and bridge for %s traffic per traffic label %s",
263-
Networks.TrafficType.Storage.name(), trafficLabel));
264-
storageBrName = createVnetBr(vNetId, storageBrName, protocol);
265-
}
272+
storageBrName = createStorageVnetBridgeIfNeeded(nic, trafficLabel, storageBrName);
266273
intf.defBridgeNet(storageBrName, null, nic.getMac(), getGuestNicModel(guestOsType, nicAdapter));
267274
}
268275
if (nic.getPxeDisable()) {
@@ -295,7 +302,7 @@ private String generateVxnetBrName(String pifName, String vnetId) {
295302
return "brvx-" + vnetId;
296303
}
297304

298-
private String createVnetBr(String vNetId, String pifKey, String protocol) throws InternalErrorException {
305+
protected String createVnetBr(String vNetId, String pifKey, String protocol) throws InternalErrorException {
299306
String nic = _pifs.get(pifKey);
300307
if (nic == null || isVxlanOrNetris(protocol)) {
301308
// if not found in bridge map, maybe traffic label refers to pif already?

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/BridgeVifDriverTest.java

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,29 @@
1616
// under the License.
1717
package com.cloud.hypervisor.kvm.resource;
1818

19+
import java.net.URI;
20+
import java.net.URISyntaxException;
21+
1922
import org.junit.Assert;
20-
import org.junit.Before;
2123
import org.junit.Test;
24+
import org.junit.runner.RunWith;
25+
import org.mockito.InjectMocks;
26+
import org.mockito.Mockito;
27+
import org.mockito.Spy;
28+
import org.mockito.junit.MockitoJUnitRunner;
2229

2330
import com.cloud.agent.api.to.NicTO;
31+
import com.cloud.exception.InternalErrorException;
2432
import com.cloud.network.Networks;
25-
import org.junit.runner.RunWith;
26-
import org.mockito.junit.MockitoJUnitRunner;
2733

2834
@RunWith(MockitoJUnitRunner.class)
2935
public class BridgeVifDriverTest {
3036

31-
private BridgeVifDriver driver;
37+
private static final String BRIDGE_NAME = "cloudbr1";
3238

33-
@Before
34-
public void setUp() throws Exception {
35-
driver = new BridgeVifDriver();
36-
}
39+
@Spy
40+
@InjectMocks
41+
private BridgeVifDriver driver = new BridgeVifDriver();
3742

3843
@Test
3944
public void isBroadcastTypeVlanOrVxlan() {
@@ -58,4 +63,41 @@ public void isValidProtocolAndVnetId() {
5863
Assert.assertTrue(driver.isValidProtocolAndVnetId("123", "vlan"));
5964
Assert.assertTrue(driver.isValidProtocolAndVnetId("456", "vxlan"));
6065
}
66+
67+
@Test
68+
public void createStorageVnetBridgeIfNeededReturnsStorageBrNameWhenBroadcastTypeIsNotStorageButValidValues() throws InternalErrorException {
69+
NicTO nic = new NicTO();
70+
nic.setBroadcastType(Networks.BroadcastDomainType.Storage);
71+
int vlan = 123;
72+
String newBridge = "br-" + vlan;
73+
nic.setBroadcastUri(Networks.BroadcastDomainType.Storage.toUri(vlan));
74+
Mockito.doReturn(newBridge).when(driver).createVnetBr(Mockito.anyString(), Mockito.anyString(), Mockito.anyString());
75+
String result = driver.createStorageVnetBridgeIfNeeded(nic, "trafficLabel", BRIDGE_NAME);
76+
Assert.assertEquals(newBridge, result);
77+
}
78+
79+
@Test
80+
public void createStorageVnetBridgeIfNeededReturnsStorageBrNameWhenBroadcastTypeIsNotStorage() throws InternalErrorException {
81+
NicTO nic = new NicTO();
82+
nic.setBroadcastType(Networks.BroadcastDomainType.Vlan);
83+
String result = driver.createStorageVnetBridgeIfNeeded(nic, "trafficLabel", BRIDGE_NAME);
84+
Assert.assertEquals(BRIDGE_NAME, result);
85+
}
86+
87+
@Test
88+
public void createStorageVnetBridgeIfNeededReturnsStorageBrNameWhenBroadcastUriIsNull() throws InternalErrorException {
89+
NicTO nic = new NicTO();
90+
nic.setBroadcastType(Networks.BroadcastDomainType.Storage);
91+
String result = driver.createStorageVnetBridgeIfNeeded(nic, "trafficLabel", BRIDGE_NAME);
92+
Assert.assertEquals(BRIDGE_NAME, result);
93+
}
94+
95+
@Test
96+
public void createStorageVnetBridgeIfNeededCreatesVnetBridgeWhenUntaggedVlan() throws InternalErrorException, URISyntaxException {
97+
NicTO nic = new NicTO();
98+
nic.setBroadcastType(Networks.BroadcastDomainType.Storage);
99+
nic.setBroadcastUri(new URI(Networks.BroadcastDomainType.Storage.scheme() + "://untagged"));
100+
String result = driver.createStorageVnetBridgeIfNeeded(nic, "trafficLabel", BRIDGE_NAME);
101+
Assert.assertEquals(BRIDGE_NAME, result);
102+
}
61103
}

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)