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 8d89dd501e9..1d805b582e9 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 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 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 getParams() { + return params; + } + + public void setParams(Map 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 83abdb9b43f..00f705195bb 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 @@ -2426,7 +2426,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 @@ -2521,7 +2521,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")) { @@ -2589,7 +2590,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); } DiskDef.DiskBus diskBusTypeData = getDataDiskModelFromVMDetail(vmSpec); @@ -2600,16 +2601,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); } @@ -2636,14 +2630,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) { @@ -3429,7 +3423,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; } @@ -3483,7 +3477,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; } @@ -3492,6 +3486,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 e2d506ce09f..1927ddd3569 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 8c997ea8e8d..c037f79cc72 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 @@ -67,6 +67,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; @@ -1081,9 +1082,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 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); @@ -1093,11 +1095,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(); } @@ -1123,7 +1125,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) { @@ -1146,7 +1148,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/pom.xml b/pom.xml index cd7c18b7a02..324b94d835b 100644 --- a/pom.xml +++ b/pom.xml @@ -112,7 +112,7 @@ 1.0-20081010.060147 1.0.1 7.1.0 - 2.11.0 + 2.27.2 2.12.0 diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java index fd98615a9e7..57a8fdfe10c 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 _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 47180cda0a1..e6171bb468a 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 00000000000..7a9f32a02eb --- /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 116ec1f0d70..1e3f64061b4 100644 --- a/tools/marvin/marvin/config/test_data.py +++ b/tools/marvin/marvin/config/test_data.py @@ -940,6 +940,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 a05f18b824e..9cd88b28c7e 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():