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():

Reply via email to