This is an automated email from the ASF dual-hosted git repository.
rohit pushed a commit to branch 4.15
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/4.15 by this push:
new 52c36ca kvm: Fix deploy VM from ISOs with UEFI (#4773)
52c36ca is described below
commit 52c36cadf0d27fc04ccf292f47aacf4d758b631d
Author: slavkap <[email protected]>
AuthorDate: Tue Apr 6 12:30:21 2021 +0300
kvm: Fix deploy VM from ISOs with UEFI (#4773)
This PR fixes #4244
deploying of VMs from ISOs and from templates with UEFI boot type
deploying of VMs from ISOs and from templates with UEFI boot type with
volumes in RAW format
---
.../cloudstack/storage/command/DettachCommand.java | 18 ++
.../kvm/resource/LibvirtComputingResource.java | 30 ++-
.../hypervisor/kvm/resource/LibvirtVMDef.java | 27 +--
.../kvm/storage/KVMStorageProcessor.java | 12 +-
.../com/cloud/template/TemplateManagerImpl.java | 15 +-
.../cloud/template/TemplateManagerImplTest.java | 8 +
test/integration/smoke/test_deploy_vm_iso_uefi.py | 235 +++++++++++++++++++++
tools/marvin/marvin/config/test_data.py | 10 +
tools/marvin/marvin/lib/base.py | 8 +-
9 files changed, 326 insertions(+), 37 deletions(-)
diff --git
a/core/src/main/java/org/apache/cloudstack/storage/command/DettachCommand.java
b/core/src/main/java/org/apache/cloudstack/storage/command/DettachCommand.java
index 8d89dd5..1d805b5 100644
---
a/core/src/main/java/org/apache/cloudstack/storage/command/DettachCommand.java
+++
b/core/src/main/java/org/apache/cloudstack/storage/command/DettachCommand.java
@@ -19,6 +19,8 @@
package org.apache.cloudstack.storage.command;
+import java.util.Map;
+
import com.cloud.agent.api.to.DiskTO;
public class DettachCommand extends StorageSubSystemCommand {
@@ -28,6 +30,7 @@ public class DettachCommand extends StorageSubSystemCommand {
private String _iScsiName;
private String _storageHost;
private int _storagePort;
+ private Map<String, String> params;
public DettachCommand(final DiskTO disk, final String vmName) {
super();
@@ -35,6 +38,13 @@ public class DettachCommand extends StorageSubSystemCommand {
this.vmName = vmName;
}
+ public DettachCommand(final DiskTO disk, final String vmName, Map<String,
String> params) {
+ super();
+ this.disk = disk;
+ this.vmName = vmName;
+ this.params = params;
+ }
+
@Override
public boolean executeInSequence() {
return false;
@@ -88,6 +98,14 @@ public class DettachCommand extends StorageSubSystemCommand {
return _storagePort;
}
+ public Map<String, String> getParams() {
+ return params;
+ }
+
+ public void setParams(Map<String, String> params) {
+ this.params = params;
+ }
+
@Override
public void setExecuteInSequence(final boolean inSeq) {
diff --git
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
index 7b4872b..82dd51f 100644
---
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
+++
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
@@ -2405,7 +2405,7 @@ public class LibvirtComputingResource extends
ServerResourceBase implements Serv
DiskDef.DiskBus busT = getDiskModelFromVMDetail(vmTO);
if (busT == null) {
- busT = getGuestDiskModel(vmTO.getPlatformEmulator());
+ busT = getGuestDiskModel(vmTO.getPlatformEmulator(),
isUefiEnabled);
}
// If we're using virtio scsi, then we need to add a virtual scsi
controller
@@ -2490,7 +2490,8 @@ public class LibvirtComputingResource extends
ServerResourceBase implements Serv
}
});
- if (MapUtils.isNotEmpty(details) &&
details.containsKey(GuestDef.BootType.UEFI.toString())) {
+ boolean isUefiEnabled = MapUtils.isNotEmpty(details) &&
details.containsKey(GuestDef.BootType.UEFI.toString());
+ if (isUefiEnabled) {
isSecureBoot =
isSecureMode(details.get(GuestDef.BootType.UEFI.toString()));
}
if (vmSpec.getOs().toLowerCase().contains("window")) {
@@ -2554,7 +2555,7 @@ public class LibvirtComputingResource extends
ServerResourceBase implements Serv
// if params contains a rootDiskController key, use its value
(this is what other HVs are doing)
DiskDef.DiskBus diskBusType = getDiskModelFromVMDetail(vmSpec);
if (diskBusType == null) {
- diskBusType = getGuestDiskModel(vmSpec.getPlatformEmulator());
+ diskBusType = getGuestDiskModel(vmSpec.getPlatformEmulator(),
isUefiEnabled);
}
// I'm not sure why previously certain DATADISKs were hard-coded
VIRTIO and others not, however this
@@ -2564,16 +2565,9 @@ public class LibvirtComputingResource extends
ServerResourceBase implements Serv
final DiskDef disk = new DiskDef();
int devId = volume.getDiskSeq().intValue();
if (volume.getType() == Volume.Type.ISO) {
- if (volPath == null) {
- if (isSecureBoot) {
- disk.defISODisk(null,
devId,isSecureBoot,isWindowsTemplate);
- } else {
- /* Add iso as placeholder */
- disk.defISODisk(null, devId);
- }
- } else {
- disk.defISODisk(volPath, devId);
- }
+
+ disk.defISODisk(volPath, devId, isUefiEnabled);
+
if (_guestCpuArch != null && _guestCpuArch.equals("aarch64")) {
disk.setBusType(DiskDef.DiskBus.SCSI);
}
@@ -2598,14 +2592,14 @@ public class LibvirtComputingResource extends
ServerResourceBase implements Serv
disk.defNetworkBasedDisk(glusterVolume +
path.replace(mountpoint, ""), pool.getSourceHost(), pool.getSourcePort(), null,
null, devId, diskBusType, DiskProtocol.GLUSTER,
DiskDef.DiskFmtType.QCOW2);
} else if (pool.getType() == StoragePoolType.CLVM ||
physicalDisk.getFormat() == PhysicalDiskFormat.RAW) {
- if (volume.getType() == Volume.Type.DATADISK) {
+ if (volume.getType() == Volume.Type.DATADISK &&
!(isWindowsTemplate && isUefiEnabled)) {
disk.defBlockBasedDisk(physicalDisk.getPath(), devId,
diskBusTypeData);
}
else {
disk.defBlockBasedDisk(physicalDisk.getPath(), devId,
diskBusType);
}
} else {
- if (volume.getType() == Volume.Type.DATADISK) {
+ if (volume.getType() == Volume.Type.DATADISK &&
!(isWindowsTemplate && isUefiEnabled)) {
disk.defFileBasedDisk(physicalDisk.getPath(), devId,
diskBusTypeData, DiskDef.DiskFmtType.QCOW2);
} else {
if (isSecureBoot) {
@@ -3410,7 +3404,7 @@ public class LibvirtComputingResource extends
ServerResourceBase implements Serv
}
boolean isGuestPVEnabled(final String guestOSName) {
- DiskDef.DiskBus db = getGuestDiskModel(guestOSName);
+ DiskDef.DiskBus db = getGuestDiskModel(guestOSName, false);
return db != DiskDef.DiskBus.IDE;
}
@@ -3445,7 +3439,7 @@ public class LibvirtComputingResource extends
ServerResourceBase implements Serv
return null;
}
- private DiskDef.DiskBus getGuestDiskModel(final String platformEmulator) {
+ private DiskDef.DiskBus getGuestDiskModel(final String platformEmulator,
boolean isUefiEnabled) {
if (_guestCpuArch != null && _guestCpuArch.equals("aarch64")) {
return DiskDef.DiskBus.SCSI;
}
@@ -3454,6 +3448,8 @@ public class LibvirtComputingResource extends
ServerResourceBase implements Serv
return DiskDef.DiskBus.IDE;
} else if (platformEmulator.startsWith("Other PV Virtio-SCSI")) {
return DiskDef.DiskBus.SCSI;
+ } else if (isUefiEnabled && platformEmulator.startsWith("Windows")) {
+ return DiskDef.DiskBus.SATA;
} else if (platformEmulator.contains("Ubuntu") ||
platformEmulator.startsWith("Fedora") ||
platformEmulator.startsWith("CentOS") ||
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 e2d506c..1927ddd 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
@@ -716,16 +716,14 @@ public class LibvirtVMDef {
} else if (bus == DiskBus.VIRTIO) {
return "vd" + getDevLabelSuffix(devId);
} else if (bus == DiskBus.SATA){
- if (!forIso) {
- return "sda";
- }
+ return "sd" + getDevLabelSuffix(devId);
}
if (forIso) {
devId --;
} else if(devId >= 2) {
devId += 2;
}
- return (DiskBus.SATA == bus) ? "sdb" : "hd" +
getDevLabelSuffix(devId);
+ return "hd" + getDevLabelSuffix(devId);
}
@@ -784,6 +782,16 @@ public class LibvirtVMDef {
_bus = DiskBus.IDE;
}
+ public void defISODisk(String volPath, boolean isUefiEnabled) {
+ _diskType = DiskType.FILE;
+ _deviceType = DeviceType.CDROM;
+ _sourcePath = volPath;
+ _bus = isUefiEnabled ? DiskBus.SATA : DiskBus.IDE;
+ _diskLabel = getDevLabel(3, _bus, true);
+ _diskFmtType = DiskFmtType.RAW;
+ _diskCacheMode = DiskCacheMode.NONE;
+ }
+
public void defISODisk(String volPath, Integer devId) {
if (devId == null) {
defISODisk(volPath);
@@ -798,20 +806,15 @@ public class LibvirtVMDef {
}
}
- public void defISODisk(String volPath, Integer devId,boolean isSecure,
boolean isWindowOs) {
+ public void defISODisk(String volPath, Integer devId,boolean isSecure)
{
if (!isSecure) {
defISODisk(volPath, devId);
} else {
_diskType = DiskType.FILE;
_deviceType = DeviceType.CDROM;
_sourcePath = volPath;
- if (isWindowOs) {
- _diskLabel = getDevLabel(devId, DiskBus.SATA, true);
- _bus = DiskBus.SATA;
- } else {
- _diskLabel = getDevLabel(devId, DiskBus.SCSI, true);
- _bus = DiskBus.SCSI;
- }
+ _diskLabel = getDevLabel(devId, DiskBus.SATA, true);
+ _bus = DiskBus.SATA;
_diskFmtType = DiskFmtType.RAW;
_diskCacheMode = DiskCacheMode.NONE;
diff --git
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
index 016a13e..a395575 100644
---
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
+++
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
@@ -68,6 +68,7 @@ import org.apache.cloudstack.utils.qemu.QemuImg;
import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
import org.apache.cloudstack.utils.qemu.QemuImgException;
import org.apache.cloudstack.utils.qemu.QemuImgFile;
+import org.apache.commons.collections.MapUtils;
import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.libvirt.Connect;
@@ -1055,9 +1056,10 @@ public class KVMStorageProcessor implements
StorageProcessor {
}
}
- protected synchronized String attachOrDetachISO(final Connect conn, final
String vmName, String isoPath, final boolean isAttach) throws LibvirtException,
URISyntaxException,
+ protected synchronized String attachOrDetachISO(final Connect conn, final
String vmName, String isoPath, final boolean isAttach, Map<String, String>
params) throws LibvirtException, URISyntaxException,
InternalErrorException {
String isoXml = null;
+ boolean isUefiEnabled = MapUtils.isNotEmpty(params) &&
params.containsKey("UEFI");
if (isoPath != null && isAttach) {
final int index = isoPath.lastIndexOf("/");
final String path = isoPath.substring(0, index);
@@ -1067,11 +1069,11 @@ public class KVMStorageProcessor implements
StorageProcessor {
isoPath = isoVol.getPath();
final DiskDef iso = new DiskDef();
- iso.defISODisk(isoPath);
+ iso.defISODisk(isoPath, isUefiEnabled);
isoXml = iso.toString();
} else {
final DiskDef iso = new DiskDef();
- iso.defISODisk(null);
+ iso.defISODisk(null, isUefiEnabled);
isoXml = iso.toString();
}
@@ -1097,7 +1099,7 @@ public class KVMStorageProcessor implements
StorageProcessor {
try {
String dataStoreUrl = getDataStoreUrlFromStore(store);
final Connect conn =
LibvirtConnection.getConnectionByVmName(cmd.getVmName());
- attachOrDetachISO(conn, cmd.getVmName(), dataStoreUrl +
File.separator + isoTO.getPath(), true);
+ attachOrDetachISO(conn, cmd.getVmName(), dataStoreUrl +
File.separator + isoTO.getPath(), true, cmd.getControllerInfo());
} catch (final LibvirtException e) {
return new Answer(cmd, false, e.toString());
} catch (final URISyntaxException e) {
@@ -1120,7 +1122,7 @@ public class KVMStorageProcessor implements
StorageProcessor {
try {
String dataStoreUrl = getDataStoreUrlFromStore(store);
final Connect conn =
LibvirtConnection.getConnectionByVmName(cmd.getVmName());
- attachOrDetachISO(conn, cmd.getVmName(), dataStoreUrl +
File.separator + isoTO.getPath(), false);
+ attachOrDetachISO(conn, cmd.getVmName(), dataStoreUrl +
File.separator + isoTO.getPath(), false, cmd.getParams());
} catch (final LibvirtException e) {
return new Answer(cmd, false, e.toString());
} catch (final URISyntaxException e) {
diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java
b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java
index fd98615..57a8fdf 100755
--- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java
+++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java
@@ -112,6 +112,7 @@ import com.cloud.agent.api.to.DataTO;
import com.cloud.agent.api.to.DatadiskTO;
import com.cloud.agent.api.to.DiskTO;
import com.cloud.agent.api.to.NfsTO;
+import com.cloud.agent.api.to.VirtualMachineTO;
import com.cloud.api.ApiDBUtils;
import com.cloud.api.ApiResponseHelper;
import com.cloud.api.query.dao.UserVmJoinDao;
@@ -136,6 +137,8 @@ import com.cloud.exception.StorageUnavailableException;
import com.cloud.host.HostVO;
import com.cloud.host.dao.HostDao;
import com.cloud.hypervisor.Hypervisor;
+import com.cloud.hypervisor.HypervisorGuru;
+import com.cloud.hypervisor.HypervisorGuruManager;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.projects.Project;
import com.cloud.projects.ProjectManager;
@@ -199,6 +202,7 @@ import com.cloud.vm.UserVmVO;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine.State;
import com.cloud.vm.VirtualMachineProfile;
+import com.cloud.vm.VirtualMachineProfileImpl;
import com.cloud.vm.VmDetailConstants;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.VMInstanceDao;
@@ -283,6 +287,8 @@ public class TemplateManagerImpl extends ManagerBase
implements TemplateManager,
MessageBus _messageBus;
@Inject
private VMTemplateDetailsDao _tmpltDetailsDao;
+ @Inject
+ private HypervisorGuruManager _hvGuruMgr;
private boolean _disableExtraction = false;
private List<TemplateAdapter> _adapters;
@@ -1289,11 +1295,16 @@ public class TemplateManagerImpl extends ManagerBase
implements TemplateManager,
DataTO isoTO = tmplt.getTO();
DiskTO disk = new DiskTO(isoTO, null, null, Volume.Type.ISO);
+
+ HypervisorGuru hvGuru = _hvGuruMgr.getGuru(vm.getHypervisorType());
+ VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm);
+ VirtualMachineTO vmTO = hvGuru.implement(profile);
+
Command cmd = null;
if (attach) {
- cmd = new AttachCommand(disk, vmName);
+ cmd = new AttachCommand(disk, vmName, vmTO.getDetails());
} else {
- cmd = new DettachCommand(disk, vmName);
+ cmd = new DettachCommand(disk, vmName, vmTO.getDetails());
}
Answer a = _agentMgr.easySend(vm.getHostId(), cmd);
return (a != null && a.getResult());
diff --git
a/server/src/test/java/com/cloud/template/TemplateManagerImplTest.java
b/server/src/test/java/com/cloud/template/TemplateManagerImplTest.java
index 47180cd..e6171bb 100755
--- a/server/src/test/java/com/cloud/template/TemplateManagerImplTest.java
+++ b/server/src/test/java/com/cloud/template/TemplateManagerImplTest.java
@@ -30,6 +30,7 @@ import com.cloud.exception.ResourceAllocationException;
import com.cloud.host.Status;
import com.cloud.host.dao.HostDao;
import com.cloud.hypervisor.Hypervisor;
+import com.cloud.hypervisor.HypervisorGuruManager;
import com.cloud.storage.Storage;
import com.cloud.storage.TemplateProfile;
import com.cloud.projects.ProjectManager;
@@ -180,6 +181,8 @@ public class TemplateManagerImplTest {
@Inject
private VMTemplateDao _tmpltDao;
+ @Inject
+ HypervisorGuruManager _hvGuruMgr;
public class CustomThreadPoolExecutor extends ThreadPoolExecutor {
AtomicInteger ai = new AtomicInteger(0);
@@ -697,6 +700,11 @@ public class TemplateManagerImplTest {
return Mockito.mock(VMTemplateDetailsDao.class);
}
+ @Bean
+ public HypervisorGuruManager hypervisorGuruManager() {
+ return Mockito.mock(HypervisorGuruManager.class);
+ }
+
public static class Library implements TypeFilter {
@Override
public boolean match(MetadataReader mdr, MetadataReaderFactory
arg1) throws IOException {
diff --git a/test/integration/smoke/test_deploy_vm_iso_uefi.py
b/test/integration/smoke/test_deploy_vm_iso_uefi.py
new file mode 100644
index 0000000..7a9f32a
--- /dev/null
+++ b/test/integration/smoke/test_deploy_vm_iso_uefi.py
@@ -0,0 +1,235 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+""" Deploy VM from ISO with UEFI
+"""
+# Import Local Modules
+from nose.plugins.attrib import attr
+from marvin.cloudstackTestCase import cloudstackTestCase, unittest
+from marvin.lib.utils import cleanup_resources
+from marvin.lib.base import (Account,
+ VirtualMachine,
+ ServiceOffering,
+ Iso,
+ DiskOffering,
+ Host,
+ )
+from marvin.lib.common import (get_zone,
+ get_domain,
+ list_hosts,
+ )
+from marvin.codes import PASS
+from marvin.sshClient import SshClient
+import xml.etree.ElementTree as ET
+from lxml import etree
+
+class TestDeployVMFromISOWithUefi(cloudstackTestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ cls.testClient = super(TestDeployVMFromISOWithUefi,
cls).getClsTestClient()
+ cls.apiclient = cls.testClient.getApiClient()
+
+ cls.hypervisor = cls.testClient.getHypervisorInfo()
+
+ if cls.hypervisor != 'kvm':
+ raise unittest.SkipTest("Those tests can be run only for KVM
hypervisor")
+
+ cls.testdata = cls.testClient.getParsedTestDataConfig()
+ # Get Zone, Domain and templates
+ cls.domain = get_domain(cls.apiclient)
+ cls.zone = get_zone(cls.apiclient, cls.testClient.getZoneForTests())
+
+ hosts = list_hosts(cls.apiclient, zoneid = cls.zone.id, type="Routing")
+
+ if not cls.isUefiEnabledOnAtLeastOnHost(hosts):
+ raise unittest.SkipTest("At least one host should support UEFI")
+
+ cls.hostConfig =
cls.config.__dict__["zones"][0].__dict__["pods"][0].__dict__["clusters"][0].__dict__["hosts"][0].__dict__
+
+ # Create service, disk offerings etc
+ cls.service_offering = ServiceOffering.create(
+ cls.apiclient,
+ cls.testdata["service_offering"]
+ )
+
+ cls.disk_offering = DiskOffering.create(
+ cls.apiclient,
+ cls.testdata["disk_offering"]
+ )
+
+ cls.testdata["virtual_machine"]["zoneid"] = cls.zone.id
+ cls.testdata["iso1"]["zoneid"] = cls.zone.id
+ cls.testdata["iso3"]["zoneid"] = cls.zone.id
+ cls.account = Account.create(
+ cls.apiclient,
+ cls.testdata["account"],
+ domainid=cls.domain.id
+ )
+ cls._cleanup = [cls.account, cls.service_offering, cls.disk_offering]
+
+ cls.centos_iso = Iso.create(
+ cls.apiclient,
+ cls.testdata["iso1"],
+ account=cls.account.name,
+ domainid=cls.account.domainid,
+ zoneid=cls.zone.id
+ )
+ try:
+ # Download the ISO
+ cls.centos_iso.download(cls.apiclient)
+ except Exception as e:
+ raise Exception("Exception while downloading ISO %s: %s"
+ % (cls.centos_iso.id, e))
+
+ cls.windows_iso = Iso.create(
+ cls.apiclient,
+ cls.testdata["iso3"],
+ account=cls.account.name,
+ domainid=cls.account.domainid,
+ zoneid=cls.zone.id
+ )
+ try:
+ # Download the ISO
+ cls.windows_iso.download(cls.apiclient)
+ except Exception as e:
+ raise Exception("Exception while downloading ISO %s: %s"
+ % (cls.windows_iso.id, e))
+
+ return
+
+ @classmethod
+ def tearDownClass(cls):
+ try:
+ cleanup_resources(cls.apiclient, cls._cleanup)
+ except Exception as e:
+ raise Exception("Warning: Exception during cleanup : %s" % e)
+
+ def setUp(self):
+ self.hypervisor = self.testClient.getHypervisorInfo()
+ if self.hypervisor != 'kvm':
+ raise self.skipTest("Skipping test case for non-kvm hypervisor")
+ return
+
+
+ @attr(tags=["advanced", "eip", "advancedns", "basic", "sg"],
required_hardware="true")
+ def test_01_deploy_vm_from_iso_uefi_secure(self):
+ """Test Deploy CentOS Virtual Machine from ISO with UEFI Secure
+ """
+
+ self.deployVmAndTestUefi(self.centos_iso, 'Secure', 'yes')
+
+ return
+
+ @attr(tags=["advanced", "eip", "advancedns", "basic", "sg"],
required_hardware="true")
+ def test_02_deploy_vm_from_iso_uefi_legacy(self):
+ """Test Deploy CentOS Virtual Machine from ISO with UEFI Legacy mode
+ """
+ self.deployVmAndTestUefi(self.centos_iso, 'Legacy', 'no')
+
+ return
+
+ @attr(tags=["advanced", "eip", "advancedns", "basic", "sg"],
required_hardware="true")
+ def test_03_deploy_windows_vm_from_iso_uefi_legacy(self):
+ """Test Deploy Windows Virtual Machine from ISO with UEFI Legacy mode
+ """
+ self.deployVmAndTestUefi(self.windows_iso, 'Legacy', 'no')
+
+ return
+
+ @attr(tags=["advanced", "eip", "advancedns", "basic", "sg"],
required_hardware="true")
+ def test_04_deploy_windows_vm_from_iso_uefi_secure(self):
+ """Test Deploy Windows Virtual Machine from ISO with UEFI Secure mode
+ """
+ self.deployVmAndTestUefi(self.windows_iso, 'Secure', 'yes')
+
+ return
+
+ def getVirshXML(self, host, instancename):
+ self.assertIsNotNone(host, "Host should not be None")
+
+ self.assertIsNotNone(instancename, "Instance name should not be None")
+
+ sshc = SshClient(
+ host=host.ipaddress,
+ port=22,
+ user=self.hostConfig['username'],
+ passwd=self.hostConfig['password'])
+
+ virsh_cmd = 'virsh dumpxml %s' % instancename
+ xml_res = sshc.execute(virsh_cmd)
+ xml_as_str = ''.join(xml_res)
+ parser = etree.XMLParser(remove_blank_text=True)
+ return ET.fromstring(xml_as_str, parser=parser)
+
+ def checkBootTypeAndMode(self, root, bootmodesecure, isWindowsIso):
+
+ machine = root.find(".os/type").get("machine")
+
+ self.assertEqual(("q35" in machine), True, "The virtual machine is not
with UEFI boot type")
+
+ bootmode = root.find(".os/loader").get("secure")
+
+ self.assertEqual((bootmode == bootmodesecure), True, "The VM is not in
the right boot mode")
+
+ if isWindowsIso:
+ disks = root.findall("devices/disk")
+ for disk in disks:
+ bus = disk.find("target").get("bus")
+ self.debug("bus is %s" % bus)
+ self.assertEqual(bus == 'sata', True, "All disks of the VM
should be with bus SATA")
+
+ def deployVmAndTestUefi(self, iso, bootmode, bootmodesecure):
+ self.virtual_machine = VirtualMachine.create(
+ self.apiclient,
+ self.testdata["virtual_machine"],
+ accountid=self.account.name,
+ domainid=self.account.domainid,
+ templateid=iso.id,
+ serviceofferingid=self.service_offering.id,
+ diskofferingid=self.disk_offering.id,
+ hypervisor=self.hypervisor,
+ boottype='UEFI',
+ bootmode=bootmode,
+ zoneid=self.zone.id
+ )
+
+ response = self.virtual_machine.getState(
+ self.apiclient,
+ VirtualMachine.RUNNING)
+ self.assertEqual(response[0], PASS, response[1])
+
+ hosts = Host.list(self.apiclient, id=self.virtual_machine.hostid)
+ if len(hosts) != 1:
+ assert False, "Could not find host with id " +
self.virtual_machine.hostid
+
+ host = hosts[0]
+
+ isWindowsIso = False
+ if "Windows" in iso.ostypename:
+ isWindowsIso = True
+
+ instancename = self.virtual_machine.instancename
+ virshxml = self.getVirshXML(host, instancename)
+ self.checkBootTypeAndMode(virshxml, bootmodesecure, isWindowsIso)
+
+ @classmethod
+ def isUefiEnabledOnAtLeastOnHost(cls, hosts):
+ for h in hosts:
+ if h.ueficapability:
+ return True
+ return False
diff --git a/tools/marvin/marvin/config/test_data.py
b/tools/marvin/marvin/config/test_data.py
index 436c656..503bc1e 100644
--- a/tools/marvin/marvin/config/test_data.py
+++ b/tools/marvin/marvin/config/test_data.py
@@ -928,6 +928,16 @@ test_data = {
"ostype": "CentOS 5.6 (64-bit)",
"mode": 'HTTP_DOWNLOAD',
},
+ "iso3": {
+ "displaytext": "Test ISO 3",
+ "name": "ISO 3",
+ "url": "http://people.apache.org/~tsp/dummy.iso",
+ "isextractable": True,
+ "isfeatured": True,
+ "ispublic": True,
+ "ostype": "Windows Server 2012 (64-bit)",
+ "mode": 'HTTP_DOWNLOAD',
+ },
"isfeatured": True,
"ispublic": True,
"isextractable": True,
diff --git a/tools/marvin/marvin/lib/base.py b/tools/marvin/marvin/lib/base.py
index 6bb7b66..3de64ef 100755
--- a/tools/marvin/marvin/lib/base.py
+++ b/tools/marvin/marvin/lib/base.py
@@ -522,7 +522,7 @@ class VirtualMachine:
method='GET', hypervisor=None, customcpunumber=None,
customcpuspeed=None, custommemory=None, rootdisksize=None,
rootdiskcontroller=None, vpcid=None, macaddress=None,
datadisktemplate_diskoffering_list={},
- properties=None, nicnetworklist=None):
+ properties=None, nicnetworklist=None, bootmode=None,
boottype=None):
"""Create the instance"""
cmd = deployVirtualMachine.deployVirtualMachineCmd()
@@ -657,6 +657,12 @@ class VirtualMachine:
if nicnetworklist:
cmd.nicnetworklist = nicnetworklist
+ if bootmode:
+ cmd.bootmode = bootmode
+
+ if boottype:
+ cmd.boottype = boottype
+
virtual_machine = apiclient.deployVirtualMachine(cmd, method=method)
if 'password' in virtual_machine.__dict__.keys():