From cd291f6b4b5b851595ef11c5f14def9afddb6a1a Mon Sep 17 00:00:00 2001 From: frank Date: Mon, 25 Feb 2013 14:57:57 -0800 Subject: [PATCH] From c72615de97b007517fb324044cb4625258c5fc61 Mon Sep 17 00:00:00 2001 From: Vijayendra Date: Mon, 25 Feb 2013 14:37:27 -0800 Subject: [PATCH] CS-670: Configurable setting to use linked clones or not on VMware Description: Providing support for creation of user VMs as full clones on ESX. Putting in unit tests for VO and Dao classes introduced in this commit. Signed-off-by: Vijayendra --- core/src/com/cloud/vm/UserVmCloneSettingVO.java | 50 ++++++ .../hypervisor/vmware/manager/VmwareManager.java | 3 + .../vmware/manager/VmwareManagerImpl.java | 18 +- .../hypervisor/vmware/resource/VmwareResource.java | 117 +++++++++---- server/conf/migration-components.xml | 1 + server/src/com/cloud/configuration/Config.java | 1 + server/src/com/cloud/vm/UserVmManagerImpl.java | 184 ++++++++++----------- .../com/cloud/vm/dao/UserVmCloneSettingDao.java | 37 +++++ .../cloud/vm/dao/UserVmCloneSettingDaoImpl.java | 74 +++++++++ .../vm/dao/UserVmCloneSettingDaoImplTest.java | 62 +++++++ .../UserVmCloneSettingDaoTestConfiguration.java | 52 ++++++ .../test/resources/CloneSettingDaoTestContext.xml | 42 +++++ setup/db/db/schema-410to420.sql | 9 + 13 files changed, 527 insertions(+), 123 deletions(-) create mode 100755 core/src/com/cloud/vm/UserVmCloneSettingVO.java create mode 100755 server/src/com/cloud/vm/dao/UserVmCloneSettingDao.java create mode 100755 server/src/com/cloud/vm/dao/UserVmCloneSettingDaoImpl.java create mode 100644 server/test/com/cloud/vm/dao/UserVmCloneSettingDaoImplTest.java create mode 100644 server/test/com/cloud/vm/dao/UserVmCloneSettingDaoTestConfiguration.java create mode 100644 server/test/resources/CloneSettingDaoTestContext.xml --- .../com/cloud/vm/UserVmCloneSettingVO.java | 50 +++++ .../vmware/manager/VmwareManager.java | 3 + .../vmware/manager/VmwareManagerImpl.java | 18 +- .../vmware/resource/VmwareResource.java | 117 ++++++++--- server/conf/migration-components.xml | 1 + .../src/com/cloud/configuration/Config.java | 1 + .../src/com/cloud/vm/UserVmManagerImpl.java | 184 +++++++++--------- .../cloud/vm/dao/UserVmCloneSettingDao.java | 37 ++++ .../vm/dao/UserVmCloneSettingDaoImpl.java | 74 +++++++ .../vm/dao/UserVmCloneSettingDaoImplTest.java | 62 ++++++ ...serVmCloneSettingDaoTestConfiguration.java | 52 +++++ .../resources/CloneSettingDaoTestContext.xml | 42 ++++ setup/db/db/schema-410to420.sql | 9 + 13 files changed, 527 insertions(+), 123 deletions(-) create mode 100644 core/src/com/cloud/vm/UserVmCloneSettingVO.java create mode 100644 server/src/com/cloud/vm/dao/UserVmCloneSettingDao.java create mode 100644 server/src/com/cloud/vm/dao/UserVmCloneSettingDaoImpl.java create mode 100644 server/test/com/cloud/vm/dao/UserVmCloneSettingDaoImplTest.java create mode 100644 server/test/com/cloud/vm/dao/UserVmCloneSettingDaoTestConfiguration.java create mode 100644 server/test/resources/CloneSettingDaoTestContext.xml diff --git a/core/src/com/cloud/vm/UserVmCloneSettingVO.java b/core/src/com/cloud/vm/UserVmCloneSettingVO.java new file mode 100644 index 00000000000..24bb1e87c3b --- /dev/null +++ b/core/src/com/cloud/vm/UserVmCloneSettingVO.java @@ -0,0 +1,50 @@ +// 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. +package com.cloud.vm; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; + +@Entity +@Table(name="user_vm_clone_setting") +public class UserVmCloneSettingVO { + + @Column(name="vm_id") + private Long vmId; + + @Column(name="clone_type") + private String cloneType; + + public UserVmCloneSettingVO() { + + } + + public UserVmCloneSettingVO(long id, + String cloneType) { + this.vmId = id; + this.cloneType = cloneType; + } + + public long getVmId() { + return this.vmId; + } + + public String getCloneType() { + return this.cloneType; + } +} diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManager.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManager.java index 445b2f0debc..36fa0f338b1 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManager.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManager.java @@ -21,6 +21,7 @@ import java.util.List; import java.util.Map; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.hypervisor.vmware.manager.VmwareStorageManager; import com.cloud.hypervisor.vmware.mo.HostMO; import com.cloud.hypervisor.vmware.util.VmwareContext; import com.cloud.utils.Pair; @@ -60,6 +61,8 @@ public interface VmwareManager { boolean getNexusVSwitchGlobalParameter(); + boolean getFullCloneFlag(); + Map getNexusVSMCredentialsByClusterId(Long clusterId); String getPrivateVSwitchName(long dcId, HypervisorType hypervisorType); diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java index 6b6bf19af79..a0d9943b535 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java @@ -96,6 +96,7 @@ import com.vmware.vim25.AboutInfo; import com.vmware.vim25.HostConnectSpec; import com.vmware.vim25.ManagedObjectReference; + @Local(value = {VmwareManager.class}) public class VmwareManagerImpl extends ManagerBase implements VmwareManager, VmwareStorageMount, Listener { private static final Logger s_logger = Logger.getLogger(VmwareManagerImpl.class); @@ -130,6 +131,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw String _publicNetworkVSwitchName; String _guestNetworkVSwitchName; boolean _nexusVSwitchActive; + boolean _fullCloneFlag; String _serviceConsoleName; String _managemetPortGroupName; String _defaultSystemVmNicAdapterType = VirtualEthernetCardType.E1000.toString(); @@ -197,11 +199,17 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw if(value == null) { _nexusVSwitchActive = false; } - else - { + else { _nexusVSwitchActive = Boolean.parseBoolean(value); } + value = _configDao.getValue(Config.VmwareCreateFullClone.key()); + if (value == null) { + _fullCloneFlag = false; + } else { + _fullCloneFlag = Boolean.parseBoolean(value); + } + _privateNetworkVSwitchName = _configDao.getValue(Config.VmwarePrivateNetworkVSwitch.key()); if (_privateNetworkVSwitchName == null) { @@ -315,6 +323,11 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw return _nexusVSwitchActive; } + @Override + public boolean getFullCloneFlag() { + return _fullCloneFlag; + } + @Override public String composeWorkerName() { return UUID.randomUUID().toString().replace("-", ""); @@ -495,6 +508,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw params.put("public.network.vswitch.name", _publicNetworkVSwitchName); params.put("guest.network.vswitch.name", _guestNetworkVSwitchName); params.put("vmware.use.nexus.vswitch", _nexusVSwitchActive); + params.put("vmware.create.full.clone", _fullCloneFlag); params.put("service.console.name", _serviceConsoleName); params.put("management.portgroup.name", _managemetPortGroupName); params.put("vmware.reserve.cpu", _reserveCpu); diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index f754c58fecf..4839b35b91e 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -159,9 +159,9 @@ import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer; import com.cloud.agent.api.storage.DestroyCommand; import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer; import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand; -import com.cloud.agent.api.to.FirewallRuleTO; import com.cloud.agent.api.storage.ResizeVolumeAnswer; import com.cloud.agent.api.storage.ResizeVolumeCommand; +import com.cloud.agent.api.to.FirewallRuleTO; import com.cloud.agent.api.to.IpAddressTO; import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.PortForwardingRuleTO; @@ -192,6 +192,7 @@ import com.cloud.hypervisor.vmware.mo.VirtualSwitchType; import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost; import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHostNetworkSummary; import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHostResourceSummary; +import com.cloud.hypervisor.vmware.resource.VmwareContextFactory; import com.cloud.hypervisor.vmware.util.VmwareContext; import com.cloud.hypervisor.vmware.util.VmwareGuestOsMapper; import com.cloud.hypervisor.vmware.util.VmwareHelper; @@ -260,6 +261,7 @@ import com.vmware.vim25.VirtualMachinePowerState; import com.vmware.vim25.VirtualMachineRuntimeInfo; import com.vmware.vim25.VirtualSCSISharing; + public class VmwareResource implements StoragePoolResource, ServerResource, VmwareHostService { private static final Logger s_logger = Logger.getLogger(VmwareResource.class); @@ -288,6 +290,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa protected String _guestNetworkVSwitchName; protected VirtualSwitchType _vSwitchType = VirtualSwitchType.StandardVirtualSwitch; protected boolean _nexusVSwitch = false; + protected boolean _fullCloneFlag = false; protected boolean _reserveCpu = false; @@ -3695,9 +3698,17 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa dsMo.deleteFile(cmd.getVolume().getPath() + ".vmdk", morDc, true); // root volume may be created via linked-clone, delete the delta disk as well - if (s_logger.isInfoEnabled()) + if (_fullCloneFlag) { + if (s_logger.isInfoEnabled()) { + s_logger.info("Destroy volume by derived name: " + cmd.getVolume().getPath() + "-flat.vmdk"); + } + dsMo.deleteFile(cmd.getVolume().getPath() + "-flat.vmdk", morDc, true); + } else { + if (s_logger.isInfoEnabled()) { s_logger.info("Destroy volume by derived name: " + cmd.getVolume().getPath() + "-delta.vmdk"); + } dsMo.deleteFile(cmd.getVolume().getPath() + "-delta.vmdk", morDc, true); + } return new Answer(cmd, true, "Success"); } @@ -3799,6 +3810,70 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa } } + + + private boolean createVMFullClone(VirtualMachineMO vmTemplate, DatacenterMO dcMo, DatastoreMO dsMo, + String vmdkName, ManagedObjectReference morDatastore, ManagedObjectReference morPool) throws Exception { + + if(dsMo.folderExists(String.format("[%s]", dsMo.getName()), vmdkName)) + dsMo.deleteFile(String.format("[%s] %s/", dsMo.getName(), vmdkName), dcMo.getMor(), false); + + s_logger.info("creating full clone from template"); + if (!vmTemplate.createFullClone(vmdkName, dcMo.getVmFolder(), morPool, morDatastore)) { + String msg = "Unable to create full clone from the template"; + s_logger.error(msg); + throw new Exception(msg); + } + + // we can't rely on un-offical API (VirtualMachineMO.moveAllVmDiskFiles() any more, use hard-coded disk names that we know + // to move files + s_logger.info("Move volume out of volume-wrapper VM "); + dsMo.moveDatastoreFile(String.format("[%s] %s/%s.vmdk", dsMo.getName(), vmdkName, vmdkName), + dcMo.getMor(), dsMo.getMor(), + String.format("[%s] %s.vmdk", dsMo.getName(), vmdkName), dcMo.getMor(), true); + + dsMo.moveDatastoreFile(String.format("[%s] %s/%s-flat.vmdk", dsMo.getName(), vmdkName, vmdkName), + dcMo.getMor(), dsMo.getMor(), + String.format("[%s] %s-flat.vmdk", dsMo.getName(), vmdkName), dcMo.getMor(), true); + + return true; + } + + private boolean createVMLinkedClone(VirtualMachineMO vmTemplate, DatacenterMO dcMo, DatastoreMO dsMo, + String vmdkName, ManagedObjectReference morDatastore, ManagedObjectReference morPool) throws Exception { + + ManagedObjectReference morBaseSnapshot = vmTemplate.getSnapshotMor("cloud.template.base"); + if (morBaseSnapshot == null) { + String msg = "Unable to find template base snapshot, invalid template"; + s_logger.error(msg); + throw new Exception(msg); + } + + if(dsMo.folderExists(String.format("[%s]", dsMo.getName()), vmdkName)) + dsMo.deleteFile(String.format("[%s] %s/", dsMo.getName(), vmdkName), dcMo.getMor(), false); + + s_logger.info("creating linked clone from template"); + if (!vmTemplate.createLinkedClone(vmdkName, morBaseSnapshot, dcMo.getVmFolder(), morPool, morDatastore)) { + String msg = "Unable to clone from the template"; + s_logger.error(msg); + throw new Exception(msg); + } + + // we can't rely on un-offical API (VirtualMachineMO.moveAllVmDiskFiles() any more, use hard-coded disk names that we know + // to move files + s_logger.info("Move volume out of volume-wrapper VM "); + dsMo.moveDatastoreFile(String.format("[%s] %s/%s.vmdk", dsMo.getName(), vmdkName, vmdkName), + dcMo.getMor(), dsMo.getMor(), + String.format("[%s] %s.vmdk", dsMo.getName(), vmdkName), dcMo.getMor(), true); + + dsMo.moveDatastoreFile(String.format("[%s] %s/%s-delta.vmdk", dsMo.getName(), vmdkName, vmdkName), + dcMo.getMor(), dsMo.getMor(), + String.format("[%s] %s-delta.vmdk", dsMo.getName(), vmdkName), dcMo.getMor(), true); + + return true; + } + + @Override public synchronized CreateAnswer execute(CreateCommand cmd) { if (s_logger.isInfoEnabled()) { @@ -3858,37 +3933,16 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa ManagedObjectReference morPool = hyperHost.getHyperHostOwnerResourcePool(); ManagedObjectReference morCluster = hyperHost.getHyperHostCluster(); - ManagedObjectReference morBaseSnapshot = vmTemplate.getSnapshotMor("cloud.template.base"); - if (morBaseSnapshot == null) { - String msg = "Unable to find template base snapshot, invalid template"; - s_logger.error(msg); - throw new Exception(msg); - } - - if(dsMo.folderExists(String.format("[%s]", dsMo.getName()), vmdkName)) - dsMo.deleteFile(String.format("[%s] %s/", dsMo.getName(), vmdkName), dcMo.getMor(), false); - - s_logger.info("create linked clone from template"); - if (!vmTemplate.createLinkedClone(vmdkName, morBaseSnapshot, dcMo.getVmFolder(), morPool, morDatastore)) { - String msg = "Unable to clone from the template"; - s_logger.error(msg); - throw new Exception(msg); + //createVMLinkedClone(vmTemplate, dcMo, dsMo, vmdkName, morDatastore, morPool); + if (!_fullCloneFlag) { + createVMLinkedClone(vmTemplate, dcMo, dsMo, vmdkName, morDatastore, morPool); + } else { + createVMFullClone(vmTemplate, dcMo, dsMo, vmdkName, morDatastore, morPool); } VirtualMachineMO vmMo = new ClusterMO(context, morCluster).findVmOnHyperHost(vmdkName); assert (vmMo != null); - // we can't rely on un-offical API (VirtualMachineMO.moveAllVmDiskFiles() any more, use hard-coded disk names that we know - // to move files - s_logger.info("Move volume out of volume-wrapper VM "); - dsMo.moveDatastoreFile(String.format("[%s] %s/%s.vmdk", dsMo.getName(), vmdkName, vmdkName), - dcMo.getMor(), dsMo.getMor(), - String.format("[%s] %s.vmdk", dsMo.getName(), vmdkName), dcMo.getMor(), true); - - dsMo.moveDatastoreFile(String.format("[%s] %s/%s-delta.vmdk", dsMo.getName(), vmdkName, vmdkName), - dcMo.getMor(), dsMo.getMor(), - String.format("[%s] %s-delta.vmdk", dsMo.getName(), vmdkName), dcMo.getMor(), true); - s_logger.info("detach disks from volume-wrapper VM " + vmdkName); vmMo.detachAllDisks(); @@ -4888,6 +4942,13 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa if(value != null && value.equalsIgnoreCase("true")) _nexusVSwitch = true; + value = params.get("vmware.create.full.clone").toString(); + if (value != null && value.equalsIgnoreCase("true")) { + _fullCloneFlag = true; + } else { + _fullCloneFlag = false; + } + s_logger.info("VmwareResource network configuration info. private vSwitch: " + _privateNetworkVSwitchName + ", public vSwitch: " + _publicNetworkVSwitchName + ", guest network: " + _guestNetworkVSwitchName); diff --git a/server/conf/migration-components.xml b/server/conf/migration-components.xml index 90fbafa855a..2ba35c836c2 100644 --- a/server/conf/migration-components.xml +++ b/server/conf/migration-components.xml @@ -35,6 +35,7 @@ under the License. + diff --git a/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java index 1cea9aad933..eb6fb242983 100755 --- a/server/src/com/cloud/configuration/Config.java +++ b/server/src/com/cloud/configuration/Config.java @@ -255,6 +255,7 @@ public enum Config { VmwarePublicNetworkVSwitch("Hidden", ManagementServer.class, String.class, "vmware.public.vswitch", null, "Specify the vSwitch on host for public network", null), VmwareGuestNetworkVSwitch("Hidden", ManagementServer.class, String.class, "vmware.guest.vswitch", null, "Specify the vSwitch on host for guest network", null), VmwareUseNexusVSwitch("Network", ManagementServer.class, Boolean.class, "vmware.use.nexus.vswitch", "false", "Enable/Disable Cisco Nexus 1000v vSwitch in VMware environment", null), + VmwareCreateFullClone("Advanced", ManagementServer.class, Boolean.class, "vmware.create.full.clone", "false", "If set to true, creates guest VMs as full clones on ESX", null), VmwareServiceConsole("Advanced", ManagementServer.class, String.class, "vmware.service.console", "Service Console", "Specify the service console network name(for ESX hosts)", null), VmwareManagementPortGroup("Advanced", ManagementServer.class, String.class, "vmware.management.portgroup", "Management Network", "Specify the management network name(for ESXi hosts)", null), VmwareAdditionalVncPortRangeStart("Advanced", ManagementServer.class, Integer.class, "vmware.additional.vnc.portrange.start", "50000", "Start port number of additional VNC port range", null), diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 6cb3f1a70af..c2bba639015 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -210,7 +210,6 @@ import com.cloud.utils.Journal; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.PasswordGenerator; -import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.crypt.RSAHelper; @@ -226,35 +225,13 @@ import com.cloud.utils.exception.ExecutionException; import com.cloud.utils.fsm.NoTransitionException; import com.cloud.utils.net.NetUtils; import com.cloud.vm.VirtualMachine.State; -import com.cloud.vm.dao.*; -import org.apache.cloudstack.acl.ControlledEntity.ACLType; -import org.apache.cloudstack.acl.SecurityChecker.AccessType; -import org.apache.cloudstack.api.BaseCmd; -import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd; -import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd; -import org.apache.cloudstack.api.command.user.template.CreateTemplateCmd; -import org.apache.cloudstack.api.command.user.vm.*; -import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd; -import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd; -import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd; -import org.apache.commons.codec.binary.Base64; -import org.apache.log4j.Logger; - -import javax.ejb.Local; -import javax.naming.ConfigurationException; -import java.util.*; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - import com.cloud.vm.dao.InstanceGroupDao; import com.cloud.vm.dao.InstanceGroupVMMapDao; import com.cloud.vm.dao.NicDao; +import com.cloud.vm.dao.UserVmCloneSettingDao; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.UserVmDetailsDao; import com.cloud.vm.dao.VMInstanceDao; -import com.cloud.vm.snapshot.VMSnapshot; import com.cloud.vm.snapshot.VMSnapshotManager; import com.cloud.vm.snapshot.dao.VMSnapshotDao; @@ -266,6 +243,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use private static final int ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION = 3; // 3 // seconds + public enum UserVmCloneType { + full, + linked + } + @Inject protected HostDao _hostDao = null; @Inject @@ -283,6 +265,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use @Inject protected DomainDao _domainDao = null; @Inject + protected UserVmCloneSettingDao _vmCloneSettingDao = null; + @Inject protected UserVmDao _vmDao = null; @Inject protected UserVmJoinDao _vmJoinDao = null; @@ -398,10 +382,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use UsageEventDao _usageEventDao; @Inject protected VMSnapshotDao _vmSnapshotDao; - @Inject + @Inject protected VMSnapshotManager _vmSnapshotMgr; - - @Inject + + @Inject List plannerSelectors; protected ScheduledExecutorService _executor = null; @@ -420,7 +404,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use @Inject protected OrchestrationService _orchSrvc; - + @Inject VolumeManager volumeMgr; @Override @@ -724,7 +708,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } - + private void checkVMSnapshots(UserVmVO vm, Long volumeId, boolean attach) { // Check that if vm has any VM snapshot @@ -737,7 +721,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use }*/ } - + private UserVm rebootVirtualMachine(long userId, long vmId) throws InsufficientCapacityException, ResourceUnavailableException { @@ -776,14 +760,14 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use throw new InvalidParameterValueException( "unable to find a virtual machine with id " + vmId); } - + _accountMgr.checkAccess(caller, null, true, vmInstance); // Check that the specified service offering ID is valid _itMgr.checkIfCanUpgrade(vmInstance, svcOffId); // remove diskAndMemory VM snapshots - /* List vmSnapshots = _vmSnapshotDao.findByVm(vmId); + /* List vmSnapshots = _vmSnapshotDao.findByVm(vmId); for (VMSnapshotVO vmSnapshotVO : vmSnapshots) { if(vmSnapshotVO.getType() == VMSnapshot.Type.DiskAndMemory){ if(!_vmSnapshotMgr.deleteAllVMSnapshots(vmId, VMSnapshot.Type.DiskAndMemory)){ @@ -791,10 +775,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use s_logger.debug(errMsg); throw new CloudRuntimeException(errMsg); } - + } }*/ - + _itMgr.upgradeVmDb(vmId, svcOffId); return _vmDao.findById(vmInstance.getId()); @@ -817,7 +801,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } NicProfile profile = new NicProfile(null, null); if(ipAddress != null) { - profile = new NicProfile(ipAddress, null); + profile = new NicProfile(ipAddress, null); } // Perform permission check on VM @@ -837,7 +821,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use throw new PermissionDeniedException("Unable to modify a vm using network with id " + network.getId() + ", permission denied"); } } - + //ensure network belongs in zone if (network.getDataCenterId() != vmInstance.getDataCenterId()) { throw new CloudRuntimeException(vmInstance + " is in zone:" + vmInstance.getDataCenterId() + " but " + network + " is in zone:" + network.getDataCenterId()); @@ -853,7 +837,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use throw new CloudRuntimeException(network + " already has a vm with host name: '" + vmInstance.getHostName()); } } - + NicProfile guestNic = null; try { @@ -914,14 +898,14 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use throw new PermissionDeniedException("Unable to modify a vm using network with id " + network.getId() + ", permission denied"); } } - + boolean nicremoved = false; try { nicremoved = _itMgr.removeNicFromVm(vmInstance, nic); } catch (ResourceUnavailableException e) { throw new CloudRuntimeException("Unable to remove " + network + " from " + vmInstance +": " + e); - + } catch (ConcurrentOperationException e) { throw new CloudRuntimeException("Concurrent operations on removing " + network + " from " + vmInstance + ": " + e); } @@ -929,19 +913,19 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use if (!nicremoved) { throw new CloudRuntimeException("Unable to remove " + network + " from " + vmInstance ); } - + s_logger.debug("Successful removal of " + network + " from " + vmInstance); return _vmDao.findById(vmInstance.getId()); - + } - + @Override public UserVm updateDefaultNicForVirtualMachine(UpdateDefaultNicForVMCmd cmd) throws InvalidParameterValueException, CloudRuntimeException { Long vmId = cmd.getVmId(); Long nicId = cmd.getNicId(); Account caller = UserContext.current().getCaller(); - + UserVmVO vmInstance = _vmDao.findById(vmId); if (vmInstance == null){ throw new InvalidParameterValueException("unable to find a virtual machine with id " + vmId); @@ -954,7 +938,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use if (network == null){ throw new InvalidParameterValueException("unable to find a network with id " + nic.getNetworkId()); } - + // Perform permission check on VM _accountMgr.checkAccess(caller, null, true, vmInstance); @@ -966,7 +950,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use // no need to check permissions for network, we'll enumerate the ones they already have access to Network existingdefaultnet = _networkModel.getDefaultNetworkForVm(vmId); - + //check to see if nic is attached to VM if (nic.getInstanceId() != vmId) { throw new InvalidParameterValueException(nic + " is not a nic on " + vmInstance); @@ -980,7 +964,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use if ((vmInstance.getState() != State.Running) && (vmInstance.getState() != State.Stopped)) { throw new CloudRuntimeException("refusing to set default " + vmInstance + " is not Running or Stopped"); } - + NicProfile existing = null; List nicProfiles = _networkMgr.getNicProfiles(vmInstance); for (NicProfile nicProfile : nicProfiles) { @@ -1009,26 +993,26 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use Network newdefault = null; newdefault = _networkModel.getDefaultNetworkForVm(vmId); - - if (newdefault == null){ - nic.setDefaultNic(false); - nic.setDeviceId(chosenID); - existingVO.setDefaultNic(true); - existingVO.setDeviceId(existingID); - nic = _nicDao.persist(nic); - existingVO = _nicDao.persist(existingVO); - - newdefault = _networkModel.getDefaultNetworkForVm(vmId); - if (newdefault.getId() == existingdefaultnet.getId()) { - throw new CloudRuntimeException("Setting a default nic failed, and we had no default nic, but we were able to set it back to the original"); - } - throw new CloudRuntimeException("Failed to change default nic to " + nic + " and now we have no default"); + if (newdefault == null){ + nic.setDefaultNic(false); + nic.setDeviceId(chosenID); + existingVO.setDefaultNic(true); + existingVO.setDeviceId(existingID); + + nic = _nicDao.persist(nic); + existingVO = _nicDao.persist(existingVO); + + newdefault = _networkModel.getDefaultNetworkForVm(vmId); + if (newdefault.getId() == existingdefaultnet.getId()) { + throw new CloudRuntimeException("Setting a default nic failed, and we had no default nic, but we were able to set it back to the original"); + } + throw new CloudRuntimeException("Failed to change default nic to " + nic + " and now we have no default"); } else if (newdefault.getId() == nic.getNetworkId()) { s_logger.debug("successfully set default network to " + network + " for " + vmInstance); return _vmDao.findById(vmInstance.getId()); } - + throw new CloudRuntimeException("something strange happened, new default network(" + newdefault.getId() + ") is not null, and is not equal to the network(" + nic.getNetworkId() + ") of the chosen nic"); } @@ -1963,7 +1947,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use if (isSecurityGroupEnabled) { if (networkIdList.size() > 1) { throw new InvalidParameterValueException("Can't create a vm with multiple networks one of" + - " which is Security Group enabled"); + " which is Security Group enabled"); } isSecurityGroupEnabledNetworkUsed = true; @@ -1971,7 +1955,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use if (!(network.getTrafficType() == TrafficType.Guest && network.getGuestType() == Network.GuestType.Shared)) { throw new InvalidParameterValueException("Can specify only Shared Guest networks when" + - " deploy vm in Advance Security Group enabled zone"); + " deploy vm in Advance Security Group enabled zone"); } // Perform account permission check @@ -1984,8 +1968,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use // if network is security group enabled, and no security group is specified, then add the default security group automatically if (isSecurityGroupEnabledNetworkUsed && !isVmWare && _networkModel.canAddDefaultSecurityGroup()) { - - //add the default securityGroup only if no security group is specified + + //add the default securityGroup only if no security group is specified if(securityGroupIdList == null || securityGroupIdList.isEmpty()){ if (securityGroupIdList == null) { securityGroupIdList = new ArrayList(); @@ -2109,7 +2093,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } } - + _networkModel.checkNetworkPermissions(owner, network); // don't allow to use system networks @@ -2139,7 +2123,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use @DB @ActionEvent(eventType = EventTypes.EVENT_VM_CREATE, eventDescription = "deploying Vm", create = true) protected UserVm createVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, String hostName, String displayName, Account owner, Long diskOfferingId, Long diskSize, List networkList, List securityGroupIdList, String group, String userData, String sshKeyPair, HypervisorType hypervisor, Account caller, Map requestedIps, IpAddresses defaultIps, String keyboard) - throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, StorageUnavailableException, ResourceAllocationException { + throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, StorageUnavailableException, ResourceAllocationException { _accountMgr.checkAccess(caller, null, true, owner); @@ -2193,7 +2177,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } } } - + if (template.getHypervisorType() != null && template.getHypervisorType() != HypervisorType.BareMetal) { // check if we have available pools for vm deployment long availablePools = _storagePoolDao.countPoolsByStatus(StoragePoolStatus.Up); @@ -2246,7 +2230,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } List> networks = new ArrayList>(); - + Map networkNicMap = new HashMap(); short defaultNetworkNumber = 0; @@ -2263,20 +2247,20 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use if (requestedIps != null && !requestedIps.isEmpty()) { requestedIpPair = requestedIps.get(network.getId()); } - + if (requestedIpPair == null) { - requestedIpPair = new IpAddresses(null, null); + requestedIpPair = new IpAddresses(null, null); } else { - _networkModel.checkRequestedIpAddresses(network.getId(), requestedIpPair.getIp4Address(), requestedIpPair.getIp6Address()); + _networkModel.checkRequestedIpAddresses(network.getId(), requestedIpPair.getIp4Address(), requestedIpPair.getIp6Address()); } - + NicProfile profile = new NicProfile(requestedIpPair.getIp4Address(), requestedIpPair.getIp6Address()); if (defaultNetworkNumber == 0) { defaultNetworkNumber++; // if user requested specific ip for default network, add it if (defaultIps.getIp4Address() != null || defaultIps.getIp6Address() != null) { - _networkModel.checkRequestedIpAddresses(network.getId(), defaultIps.getIp4Address(), defaultIps.getIp6Address()); + _networkModel.checkRequestedIpAddresses(network.getId(), defaultIps.getIp4Address(), defaultIps.getIp6Address()); profile = new NicProfile(defaultIps.getIp4Address(), defaultIps.getIp6Address()); } @@ -2405,6 +2389,20 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use vm.setIsoId(template.getId()); } + // If hypervisor is vSphere, check for clone type setting. + if (hypervisorType.equals(HypervisorType.VMware)) { + // retrieve clone flag. + UserVmCloneType cloneType = UserVmCloneType.linked; + String value = _configDao.getValue(Config.VmwareCreateFullClone.key()); + if (value != null) { + if (Boolean.parseBoolean(value) == true) + cloneType = UserVmCloneType.full; + } + UserVmCloneSettingVO vmCloneSettingVO = new UserVmCloneSettingVO(id, cloneType.toString()); + _vmCloneSettingDao.persist(vmCloneSettingVO); + } + + _vmDao.persist(vm); _vmDao.saveDetails(vm); @@ -2429,7 +2427,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use VirtualMachineEntity vmEntity = _orchSrvc.createVirtualMachine(vm.getUuid(), new Long(owner.getAccountId()).toString(), new Long(template.getId()).toString(), hostName, displayName, hypervisor.name(), offering.getCpu(), offering.getSpeed(), offering.getRamSize(), diskSize, computeTags, rootDiskTags, networkNicMap, plan); } - + if (s_logger.isDebugEnabled()) { s_logger.debug("Successfully allocated DB entry for " + vm); @@ -2465,7 +2463,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use return vm; } - private void validateUserData(String userData) { + private void validateUserData(String userData) { byte[] decodedUserData = null; if (userData != null) { if (!Base64.isBase64(userData)) { @@ -2499,7 +2497,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use protected UserVm startVirtualMachine(DeployVMCmd cmd, Map additonalParams) throws ResourceUnavailableException, InsufficientCapacityException, - ConcurrentOperationException { + ConcurrentOperationException { long vmId = cmd.getEntityId(); Long hostId = cmd.getHostId(); @@ -2896,18 +2894,18 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } VirtualMachineEntity vmEntity = _orchSrvc.getVirtualMachine(vm.getUuid()); - - String plannerName = null; - for (DeployPlannerSelector dps : plannerSelectors) { - plannerName = dps.selectPlanner(vm); - if (plannerName != null) { + + String plannerName = null; + for (DeployPlannerSelector dps : plannerSelectors) { + plannerName = dps.selectPlanner(vm); + if (plannerName != null) { break; } - } - if (plannerName == null) { + } + if (plannerName == null) { throw new CloudRuntimeException(String.format("cannot find DeployPlannerSelector for vm[uuid:%s, hypervisorType:%s]", vm.getUuid(), vm.getHypervisorType())); - } - + } + String reservationId = vmEntity.reserve(plannerName, plan, new ExcludeList(), new Long(callerUser.getId()).toString()); vmEntity.deploy(reservationId, new Long(callerUser.getId()).toString()); @@ -3069,7 +3067,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use if (tags != null && !tags.isEmpty()) { int count = 0; - for (String key : tags.keySet()) { + for (String key : tags.keySet()) { sc.setParameters("key" + String.valueOf(count), key); sc.setParameters("value" + String.valueOf(count), tags.get(key)); count++; @@ -3189,7 +3187,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use public UserVm createVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, StorageUnavailableException, - ResourceAllocationException { + ResourceAllocationException { // TODO Auto-generated method stub return null; } @@ -3557,12 +3555,12 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use List securityGroupIdList = cmd.getSecurityGroupIdList(); if (zone.getNetworkType() == NetworkType.Basic) { - if (networkIdList != null && !networkIdList.isEmpty()) { + if (networkIdList != null && !networkIdList.isEmpty()) { throw new InvalidParameterValueException( "Can't move vm with network Ids; this is a basic zone VM"); - } + } // cleanup the old security groups - _securityGroupMgr.removeInstanceFromGroups(cmd.getVmId()); + _securityGroupMgr.removeInstanceFromGroups(cmd.getVmId()); // cleanup the network for the oldOwner _networkMgr.cleanupNics(vmOldProfile); _networkMgr.expungeNics(vmOldProfile); @@ -3700,7 +3698,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use throw new InvalidParameterValueException("Unable to find physical network with id: "+physicalNetworkId + " and tag: " +requiredOfferings.get(0).getTags()); } s_logger.debug("Creating network for account " + newAccount + " from the network offering id=" + - requiredOfferings.get(0).getId() + " as a part of deployVM process"); + requiredOfferings.get(0).getId() + " as a part of deployVM process"); Network newNetwork = _networkMgr.createGuestNetwork(requiredOfferings.get(0).getId(), newAccount.getAccountName() + "-network", newAccount.getAccountName() + "-network", null, null, null, null, newAccount, null, physicalNetwork, zone.getId(), ACLType.Account, null, null, null, null); @@ -3909,7 +3907,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use public boolean plugNic(Network network, NicTO nic, VirtualMachineTO vm, ReservationContext context, DeployDestination dest) throws ConcurrentOperationException, ResourceUnavailableException, - InsufficientCapacityException { + InsufficientCapacityException { UserVmVO vmVO = _vmDao.findById(vm.getId()); if (vmVO.getState() == State.Running) { try { diff --git a/server/src/com/cloud/vm/dao/UserVmCloneSettingDao.java b/server/src/com/cloud/vm/dao/UserVmCloneSettingDao.java new file mode 100644 index 00000000000..44a1bf32f8c --- /dev/null +++ b/server/src/com/cloud/vm/dao/UserVmCloneSettingDao.java @@ -0,0 +1,37 @@ +// 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. +package com.cloud.vm.dao; + +import java.util.List; + +import com.cloud.utils.db.GenericDao; +import com.cloud.vm.UserVmCloneSettingVO; + +public interface UserVmCloneSettingDao extends GenericDao { + + /* + * Returns a User VM clone type record by vm id. + */ + UserVmCloneSettingVO findByVmId(long id); + + /* + * Returns a list of VMs by clone type. + * cloneType can be full/linked. + */ + List listByCloneType(String cloneType); + +} diff --git a/server/src/com/cloud/vm/dao/UserVmCloneSettingDaoImpl.java b/server/src/com/cloud/vm/dao/UserVmCloneSettingDaoImpl.java new file mode 100644 index 00000000000..174f28350d1 --- /dev/null +++ b/server/src/com/cloud/vm/dao/UserVmCloneSettingDaoImpl.java @@ -0,0 +1,74 @@ +// 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. +package com.cloud.vm.dao; + + +import java.util.List; + +import javax.annotation.PostConstruct; +import javax.ejb.Local; + +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria.Op; +import com.cloud.vm.UserVmCloneSettingVO; +import com.cloud.utils.db.DB; + + +@Component +@Local(value= { UserVmCloneSettingDao.class }) +@DB(txn = false) +public class UserVmCloneSettingDaoImpl extends GenericDaoBase implements UserVmCloneSettingDao { + public static final Logger s_logger = Logger.getLogger(UserVmCloneSettingDaoImpl.class); + + protected SearchBuilder vmIdSearch; + protected SearchBuilder cloneTypeSearch; + + public UserVmCloneSettingDaoImpl() { + } + + @PostConstruct + public void init() { + // Initialize the search builders. + vmIdSearch = createSearchBuilder(); + vmIdSearch.and("vmId", vmIdSearch.entity().getCloneType(), Op.EQ); + vmIdSearch.done(); + + cloneTypeSearch = createSearchBuilder(); + cloneTypeSearch.and("cloneType", cloneTypeSearch.entity().getCloneType(), Op.EQ); + cloneTypeSearch.done(); + } + + @Override + public UserVmCloneSettingVO findByVmId(long vmId) { + SearchCriteria sc = vmIdSearch.create(); + sc.setParameters("vmId", vmId); + return findOneBy(sc); + } + + @Override + public List listByCloneType(String cloneType) { + SearchCriteria sc = cloneTypeSearch.create(); + sc.setParameters("cloneType", cloneType); + return search(sc, null); + } + +} diff --git a/server/test/com/cloud/vm/dao/UserVmCloneSettingDaoImplTest.java b/server/test/com/cloud/vm/dao/UserVmCloneSettingDaoImplTest.java new file mode 100644 index 00000000000..c96ba3656fc --- /dev/null +++ b/server/test/com/cloud/vm/dao/UserVmCloneSettingDaoImplTest.java @@ -0,0 +1,62 @@ +// 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. +package com.cloud.vm.dao; + +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; + +import junit.framework.TestCase; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.cloud.vm.UserVmCloneSettingVO; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = "classpath:/CloneSettingDaoTestContext.xml") +public class UserVmCloneSettingDaoImplTest extends TestCase { + @Inject UserVmCloneSettingDaoImpl _vmcsdao; + + public void makeEntry(Long vmId, String cloneType) { + UserVmCloneSettingVO vo = new UserVmCloneSettingVO(vmId, cloneType); + _vmcsdao.persist(vo); + vo = _vmcsdao.findById(vmId); + assert (vo.getCloneType().equalsIgnoreCase(cloneType)) : "Unexpected Clone Type retrieved from table! Retrieved: " + vo.getCloneType() + " while expected was: " + cloneType; + + // Next test whether the record is retrieved by clone type. + List voList = new ArrayList(); + voList = _vmcsdao.listByCloneType(cloneType); + assert (voList != null && !voList.isEmpty()) : "Failed to retrieve any record of VMs by clone type!"; + + // If a vo list is indeed retrieved, also check whether the vm id retrieved matches what we put in there. + assert (voList.get(0).getVmId() == vmId) : "Retrieved vmId " + voList.get(0).getVmId() + " does not match input vmId: " + vmId; + } + @Test + public void testPersist() { + + Long vmId = 2222l; + String[] arr = {"full", "linked"}; + for (String cloneType : arr) { + _vmcsdao.expunge(vmId); + makeEntry(vmId, cloneType); + } + } +} diff --git a/server/test/com/cloud/vm/dao/UserVmCloneSettingDaoTestConfiguration.java b/server/test/com/cloud/vm/dao/UserVmCloneSettingDaoTestConfiguration.java new file mode 100644 index 00000000000..8bb2a4de902 --- /dev/null +++ b/server/test/com/cloud/vm/dao/UserVmCloneSettingDaoTestConfiguration.java @@ -0,0 +1,52 @@ +// 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 +// 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. + +package com.cloud.storage.dao; + +import java.io.IOException; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.ComponentScan.Filter; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.core.type.filter.TypeFilter; + +import com.cloud.utils.component.SpringComponentScanUtils; +import com.cloud.vm.dao.UserVmCloneSettingDaoImpl; + +@Configuration +@ComponentScan(basePackageClasses={ + UserVmCloneSettingDaoImpl.class}, + includeFilters={@Filter(value=UserVmCloneSettingDaoTestConfiguration.Library.class, type=FilterType.CUSTOM)}, + useDefaultFilters=false + ) +public class UserVmCloneSettingDaoTestConfiguration { + + + public static class Library implements TypeFilter { + + @Override + public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException { + mdr.getClassMetadata().getClassName(); + ComponentScan cs = UserVmCloneSettingDaoTestConfiguration.class.getAnnotation(ComponentScan.class); + return SpringComponentScanUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); + } + + } +} diff --git a/server/test/resources/CloneSettingDaoTestContext.xml b/server/test/resources/CloneSettingDaoTestContext.xml new file mode 100644 index 00000000000..1d13500a2e9 --- /dev/null +++ b/server/test/resources/CloneSettingDaoTestContext.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql index be8e7f543a0..6c831f0580c 100644 --- a/setup/db/db/schema-410to420.sql +++ b/setup/db/db/schema-410to420.sql @@ -100,3 +100,12 @@ CREATE TABLE `vpc_service_map` ( SET foreign_key_checks = 1; INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'vm.instancename.flag', 'false', 'Append guest VM display Name (if set) to the internal name of the VM'); + +CREATE TABLE `cloud`.`user_vm_clone_setting` ( + `vm_id` bigint unsigned NOT NULL COMMENT 'guest VM id', + `clone_type` varchar(10) NOT NULL COMMENT 'Full or Linked Clone (applicable to VMs on ESX)', + PRIMARY KEY (`vm_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + +INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'UserVmManager', 'vmware.create.full.clone' , 'false', 'If set to true, creates VMs as full clones on ESX hypervisor');