You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ah...@apache.org on 2013/01/09 14:26:48 UTC

[9/50] [abbrv] Merge branch 'api_refactoring' into javelin

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/30f2565d/server/src/com/cloud/vm/UserVmManagerImpl.java
----------------------------------------------------------------------
diff --cc server/src/com/cloud/vm/UserVmManagerImpl.java
index e0454c3,f3aca68..0317643
--- a/server/src/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/com/cloud/vm/UserVmManagerImpl.java
@@@ -29,31 -29,21 +29,23 @@@ import java.util.concurrent.ScheduledEx
  import java.util.concurrent.TimeUnit;
  
  import javax.ejb.Local;
 +import javax.inject.Inject;
  import javax.naming.ConfigurationException;
  
- import org.apache.cloudstack.engine.cloud.entity.api.VirtualMachineEntity;
- import org.apache.cloudstack.engine.service.api.OrchestrationService;
+ 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 org.springframework.stereotype.Component;
  
- import com.cloud.acl.ControlledEntity.ACLType;
+ import org.apache.cloudstack.acl.ControlledEntity.ACLType;
+ import org.apache.cloudstack.acl.SecurityChecker.AccessType;
  import com.cloud.agent.AgentManager;
- import com.cloud.agent.api.Answer;
- import com.cloud.agent.api.AttachIsoCommand;
- import com.cloud.agent.api.AttachVolumeAnswer;
- import com.cloud.agent.api.AttachVolumeCommand;
- import com.cloud.agent.api.ComputeChecksumCommand;
- import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand;
- import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand;
- import com.cloud.agent.api.GetVmStatsAnswer;
- import com.cloud.agent.api.GetVmStatsCommand;
- import com.cloud.agent.api.SnapshotCommand;
- import com.cloud.agent.api.StartAnswer;
- import com.cloud.agent.api.StopAnswer;
- import com.cloud.agent.api.UpgradeSnapshotCommand;
- import com.cloud.agent.api.VmStatsEntry;
+ import com.cloud.agent.api.*;
  import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer;
  import com.cloud.agent.api.to.NicTO;
  import com.cloud.agent.api.to.VirtualMachineTO;
@@@ -215,8 -146,8 +148,7 @@@ import com.cloud.uservm.UserVm
  import com.cloud.utils.NumbersUtil;
  import com.cloud.utils.Pair;
  import com.cloud.utils.PasswordGenerator;
- import com.cloud.utils.Ternary;
  import com.cloud.utils.component.ComponentLocator;
 -import com.cloud.utils.component.Inject;
  import com.cloud.utils.component.Manager;
  import com.cloud.utils.concurrency.NamedThreadFactory;
  import com.cloud.utils.crypt.RSAHelper;
@@@ -232,4447 -163,3552 +164,4317 @@@ import com.cloud.utils.exception.Execut
  import com.cloud.utils.fsm.NoTransitionException;
  import com.cloud.utils.net.NetUtils;
  import com.cloud.vm.VirtualMachine.State;
- import com.cloud.vm.dao.InstanceGroupDao;
- import com.cloud.vm.dao.InstanceGroupVMMapDao;
- import com.cloud.vm.dao.NicDao;
- import com.cloud.vm.dao.UserVmDao;
- import com.cloud.vm.dao.UserVmDetailsDao;
- import com.cloud.vm.dao.VMInstanceDao;
+ import com.cloud.vm.dao.*;
  
 +@Component
  @Local(value = { UserVmManager.class, UserVmService.class })
  public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager {
 -    private static final Logger s_logger = Logger.getLogger(UserVmManagerImpl.class);
 -
 -    private static final int ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION = 3; // 3 seconds
 -
 -    @Inject
 -    protected HostDao _hostDao = null;
 -    @Inject
 -    protected ServiceOfferingDao _offeringDao = null;
 -    @Inject
 -    protected DiskOfferingDao _diskOfferingDao = null;
 -    @Inject
 -    protected VMTemplateDao _templateDao = null;
 -    @Inject
 -    protected VMTemplateDetailsDao _templateDetailsDao = null;
 -    @Inject
 -    protected VMTemplateHostDao _templateHostDao = null;
 -    @Inject
 -    protected VMTemplateZoneDao _templateZoneDao = null;
 -    @Inject
 -    protected DomainDao _domainDao = null;
 -    @Inject
 -    protected UserVmDao _vmDao = null;
 -    @Inject
 +	private static final Logger s_logger = Logger
 +			.getLogger(UserVmManagerImpl.class);
 +
 +	private static final int ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION = 3; // 3
 +																				// seconds
 +
 +	@Inject
 +	protected HostDao _hostDao = null;
 +	@Inject
 +	protected ServiceOfferingDao _offeringDao = null;
 +	@Inject
 +	protected DiskOfferingDao _diskOfferingDao = null;
 +	@Inject
 +	protected VMTemplateDao _templateDao = null;
 +	@Inject
 +	protected VMTemplateDetailsDao _templateDetailsDao = null;
 +	@Inject
 +	protected VMTemplateHostDao _templateHostDao = null;
 +	@Inject
 +	protected VMTemplateZoneDao _templateZoneDao = null;
 +	@Inject
 +	protected DomainDao _domainDao = null;
 +	@Inject
 +	protected UserVmDao _vmDao = null;
 +	@Inject
+     protected UserVmJoinDao _vmJoinDao = null;
+     @Inject
 -    protected VolumeDao _volsDao = null;
 -    @Inject
 -    protected DataCenterDao _dcDao = null;
 -    @Inject
 -    protected FirewallRulesDao _rulesDao = null;
 -    @Inject
 -    protected LoadBalancerVMMapDao _loadBalancerVMMapDao = null;
 -    @Inject
 -    protected PortForwardingRulesDao _portForwardingDao;
 -    @Inject
 -    protected IPAddressDao _ipAddressDao = null;
 -    @Inject
 -    protected HostPodDao _podDao = null;
 -    @Inject
 -    protected NetworkManager _networkMgr = null;
 -    @Inject
 -    protected StorageManager _storageMgr = null;
 -    @Inject
 -    protected SnapshotManager _snapshotMgr = null;
 -    @Inject
 -    protected AgentManager _agentMgr = null;
 -    @Inject
 -    protected ConfigurationManager _configMgr = null;
 -    @Inject
 -    protected AccountDao _accountDao = null;
 -    @Inject
 -    protected UserDao _userDao = null;
 -    @Inject
 -    protected SnapshotDao _snapshotDao = null;
 -    @Inject
 -    protected GuestOSDao _guestOSDao = null;
 -    @Inject
 -    protected HighAvailabilityManager _haMgr = null;
 -    @Inject
 -    protected AlertManager _alertMgr = null;
 -    @Inject
 -    protected AccountManager _accountMgr;
 -    @Inject
 -    protected AccountService _accountService;
 -    @Inject
 -    protected AsyncJobManager _asyncMgr;
 -    @Inject
 -    protected ClusterDao _clusterDao;
 -    @Inject
 -    protected StoragePoolDao _storagePoolDao;
 -    @Inject
 -    protected SecurityGroupManager _securityGroupMgr;
 -    @Inject
 -    protected ServiceOfferingDao _serviceOfferingDao;
 -    @Inject
 -    protected NetworkOfferingDao _networkOfferingDao;
 -    @Inject
 -    protected InstanceGroupDao _vmGroupDao;
 -    @Inject
 -    protected InstanceGroupVMMapDao _groupVMMapDao;
 -    @Inject
 -    protected VirtualMachineManager _itMgr;
 -    @Inject
 -    protected NetworkDao _networkDao;
 -    @Inject
 -    protected NicDao _nicDao;
 -    @Inject
 -    protected VpcDao _vpcDao;
 -    @Inject
 -    protected RulesManager _rulesMgr;
 -    @Inject
 -    protected LoadBalancingRulesManager _lbMgr;
 -    @Inject
 -    protected UsageEventDao _usageEventDao;
 -    @Inject
 -    protected SSHKeyPairDao _sshKeyPairDao;
 -    @Inject
 -    protected UserVmDetailsDao _vmDetailsDao;
 -    @Inject
 -    protected HypervisorCapabilitiesDao _hypervisorCapabilitiesDao;
 -    @Inject
 -    protected SecurityGroupDao _securityGroupDao;
 -    @Inject
 -    protected CapacityManager _capacityMgr;;
 -    @Inject
 -    protected VMInstanceDao _vmInstanceDao;
 -    @Inject
 -    protected ResourceLimitService _resourceLimitMgr;
 -    @Inject
 -    protected FirewallManager _firewallMgr;
 -    @Inject
 -    protected ProjectManager _projectMgr;
 -    @Inject
 -    protected ResourceManager _resourceMgr;
 -    @Inject
 -    protected NetworkServiceMapDao _ntwkSrvcDao;
 -    @Inject
 -    SecurityGroupVMMapDao _securityGroupVMMapDao;
 -    @Inject
 -    protected ItWorkDao _workDao;
 -    @Inject
 -    protected VolumeHostDao _volumeHostDao;
 -    @Inject
 -    ResourceTagDao _resourceTagDao;
 -    @Inject
 -    PhysicalNetworkDao _physicalNetworkDao;
 -    @Inject
 -    VpcManager _vpcMgr;
 -
 -    protected ScheduledExecutorService _executor = null;
 -    protected int _expungeInterval;
 -    protected int _expungeDelay;
 -
 -    protected String _name;
 -    protected String _instance;
 -    protected String _zone;
 +	protected VolumeDao _volsDao = null;
 +	@Inject
 +	protected DataCenterDao _dcDao = null;
 +	@Inject
 +	protected FirewallRulesDao _rulesDao = null;
 +	@Inject
 +	protected LoadBalancerVMMapDao _loadBalancerVMMapDao = null;
 +	@Inject
 +	protected PortForwardingRulesDao _portForwardingDao;
 +	@Inject
 +	protected IPAddressDao _ipAddressDao = null;
 +	@Inject
 +	protected HostPodDao _podDao = null;
 +	@Inject
 +	protected NetworkManager _networkMgr = null;
 +	@Inject
 +	protected StorageManager _storageMgr = null;
 +	@Inject
 +	protected SnapshotManager _snapshotMgr = null;
 +	@Inject
 +	protected AgentManager _agentMgr = null;
 +	@Inject
 +	protected ConfigurationManager _configMgr = null;
 +	@Inject
 +	protected AccountDao _accountDao = null;
 +	@Inject
 +	protected UserDao _userDao = null;
 +	@Inject
 +	protected SnapshotDao _snapshotDao = null;
 +	@Inject
 +	protected GuestOSDao _guestOSDao = null;
 +	@Inject
 +	protected HighAvailabilityManager _haMgr = null;
 +	@Inject
 +	protected AlertManager _alertMgr = null;
 +	@Inject
 +	protected AccountManager _accountMgr;
 +	@Inject
 +	protected AccountService _accountService;
 +	@Inject
 +	protected AsyncJobManager _asyncMgr;
 +	@Inject
 +	protected ClusterDao _clusterDao;
 +	@Inject
 +	protected StoragePoolDao _storagePoolDao;
 +	@Inject
 +	protected SecurityGroupManager _securityGroupMgr;
 +	@Inject
 +	protected ServiceOfferingDao _serviceOfferingDao;
 +	@Inject
 +	protected NetworkOfferingDao _networkOfferingDao;
 +	@Inject
 +	protected InstanceGroupDao _vmGroupDao;
 +	@Inject
 +	protected InstanceGroupVMMapDao _groupVMMapDao;
 +	@Inject
 +	protected VirtualMachineManager _itMgr;
 +	@Inject
 +	protected NetworkDao _networkDao;
 +	@Inject
 +	protected NicDao _nicDao;
 +	@Inject
 +	protected VpcDao _vpcDao;
 +	@Inject
 +	protected RulesManager _rulesMgr;
 +	@Inject
 +	protected LoadBalancingRulesManager _lbMgr;
 +	@Inject
 +	protected UsageEventDao _usageEventDao;
 +	@Inject
 +	protected SSHKeyPairDao _sshKeyPairDao;
 +	@Inject
 +	protected UserVmDetailsDao _vmDetailsDao;
 +	@Inject
 +	protected HypervisorCapabilitiesDao _hypervisorCapabilitiesDao;
 +	@Inject
 +	protected SecurityGroupDao _securityGroupDao;
 +	@Inject
 +	protected CapacityManager _capacityMgr;;
 +	@Inject
 +	protected VMInstanceDao _vmInstanceDao;
 +	@Inject
 +	protected ResourceLimitService _resourceLimitMgr;
 +	@Inject
 +	protected FirewallManager _firewallMgr;
 +	@Inject
 +	protected ProjectManager _projectMgr;
 +	@Inject
 +	protected ResourceManager _resourceMgr;
 +	@Inject
 +	protected NetworkServiceMapDao _ntwkSrvcDao;
 +	@Inject
 +	SecurityGroupVMMapDao _securityGroupVMMapDao;
 +	@Inject
 +	protected ItWorkDao _workDao;
 +	@Inject
 +	protected VolumeHostDao _volumeHostDao;
 +	@Inject
 +	ResourceTagDao _resourceTagDao;
 +	@Inject
 +	PhysicalNetworkDao _physicalNetworkDao;
 +	@Inject
 +	VpcManager _vpcMgr;
 +	@Inject 
 +	protected GuestOSCategoryDao _guestOSCategoryDao;
 +
 +	protected ScheduledExecutorService _executor = null;
 +	protected int _expungeInterval;
 +	protected int _expungeDelay;
 +
 +	protected String _name;
 +	protected String _instance;
 +	protected String _zone;
 +
 +	private ConfigurationDao _configDao;
 +	private int _createprivatetemplatefromvolumewait;
 +	private int _createprivatetemplatefromsnapshotwait;
 +
 +	@Inject
 +	protected OrchestrationService _orchSrvc;
 +
 +	@Override
 +	public UserVmVO getVirtualMachine(long vmId) {
 +		return _vmDao.findById(vmId);
 +	}
 +
 +	@Override
 +	public List<? extends UserVm> getVirtualMachines(long hostId) {
 +		return _vmDao.listByHostId(hostId);
 +	}
 +
 +	@Override
 +	@ActionEvent(eventType = EventTypes.EVENT_VM_RESETPASSWORD, eventDescription = "resetting Vm password", async = true)
 +	public UserVm resetVMPassword(ResetVMPasswordCmd cmd, String password)
 +			throws ResourceUnavailableException, InsufficientCapacityException {
 +		Account caller = UserContext.current().getCaller();
 +		Long vmId = cmd.getId();
 +		UserVmVO userVm = _vmDao.findById(cmd.getId());
 +		_vmDao.loadDetails(userVm);
 +
 +		// Do parameters input validation
 +		if (userVm == null) {
 +			throw new InvalidParameterValueException(
 +					"unable to find a virtual machine with id " + cmd.getId());
 +		}
 +
 +		VMTemplateVO template = _templateDao.findByIdIncludingRemoved(userVm
 +				.getTemplateId());
 +		if (template == null || !template.getEnablePassword()) {
 +			throw new InvalidParameterValueException(
 +					"Fail to reset password for the virtual machine, the template is not password enabled");
 +		}
 +
 +		if (userVm.getState() == State.Error
 +				|| userVm.getState() == State.Expunging) {
 +			s_logger.error("vm is not in the right state: " + vmId);
 +			throw new InvalidParameterValueException("Vm with id " + vmId
 +					+ " is not in the right state");
 +		}
 +
 +		_accountMgr.checkAccess(caller, null, true, userVm);
 +
 +		boolean result = resetVMPasswordInternal(cmd, password);
 +
 +		if (result) {
 +			userVm.setPassword(password);
 +			// update the password in vm_details table too
 +			// Check if an SSH key pair was selected for the instance and if so
 +			// use it to encrypt & save the vm password
 +			String sshPublicKey = userVm.getDetail("SSH.PublicKey");
 +			if (sshPublicKey != null && !sshPublicKey.equals("")
 +					&& password != null && !password.equals("saved_password")) {
 +				String encryptedPasswd = RSAHelper.encryptWithSSHPublicKey(
 +						sshPublicKey, password);
 +				if (encryptedPasswd == null) {
 +					throw new CloudRuntimeException("Error encrypting password");
 +				}
 +
 +				userVm.setDetail("Encrypted.Password", encryptedPasswd);
 +				_vmDao.saveDetails(userVm);
 +			}
 +		} else {
 +			throw new CloudRuntimeException(
 +					"Failed to reset password for the virtual machine ");
 +		}
 +
 +		return userVm;
 +	}
 +
 +	private boolean resetVMPasswordInternal(ResetVMPasswordCmd cmd,
 +			String password) throws ResourceUnavailableException,
 +			InsufficientCapacityException {
 +		Long vmId = cmd.getId();
 +		Long userId = UserContext.current().getCallerUserId();
 +		VMInstanceVO vmInstance = _vmDao.findById(vmId);
 +
 +		if (password == null || password.equals("")) {
 +			return false;
 +		}
 +
 +		VMTemplateVO template = _templateDao
 +				.findByIdIncludingRemoved(vmInstance.getTemplateId());
 +		if (template.getEnablePassword()) {
 +			Nic defaultNic = _networkMgr.getDefaultNic(vmId);
 +			if (defaultNic == null) {
 +				s_logger.error("Unable to reset password for vm " + vmInstance
 +						+ " as the instance doesn't have default nic");
 +				return false;
 +			}
 +
 +			Network defaultNetwork = _networkDao.findById(defaultNic
 +					.getNetworkId());
 +			NicProfile defaultNicProfile = new NicProfile(defaultNic,
 +					defaultNetwork, null, null, null,
 +					_networkMgr
 +							.isSecurityGroupSupportedInNetwork(defaultNetwork),
 +					_networkMgr.getNetworkTag(template.getHypervisorType(),
 +							defaultNetwork));
 +			VirtualMachineProfile<VMInstanceVO> vmProfile = new VirtualMachineProfileImpl<VMInstanceVO>(
 +					vmInstance);
 +			vmProfile.setParameter(VirtualMachineProfile.Param.VmPassword,
 +					password);
 +
 +			UserDataServiceProvider element = _networkMgr
 +					.getPasswordResetProvider(defaultNetwork);
 +			if (element == null) {
 +				throw new CloudRuntimeException(
 +						"Can't find network element for "
 +								+ Service.UserData.getName()
 +								+ " provider needed for password reset");
 +			}
 +
 +			boolean result = element.savePassword(defaultNetwork,
 +					defaultNicProfile, vmProfile);
 +
 +			// Need to reboot the virtual machine so that the password gets
 +			// redownloaded from the DomR, and reset on the VM
 +			if (!result) {
 +				s_logger.debug("Failed to reset password for the virutal machine; no need to reboot the vm");
 +				return false;
 +			} else {
 +				if (vmInstance.getState() == State.Stopped) {
 +					s_logger.debug("Vm "
 +							+ vmInstance
 +							+ " is stopped, not rebooting it as a part of password reset");
 +					return true;
 +				}
 +
 +				if (rebootVirtualMachine(userId, vmId) == null) {
 +					s_logger.warn("Failed to reboot the vm " + vmInstance);
 +					return false;
 +				} else {
 +					s_logger.debug("Vm "
 +							+ vmInstance
 +							+ " is rebooted successfully as a part of password reset");
 +					return true;
 +				}
 +			}
 +		} else {
 +			if (s_logger.isDebugEnabled()) {
 +				s_logger.debug("Reset password called for a vm that is not using a password enabled template");
 +			}
 +			return false;
 +		}
 +	}
 +
 +	@Override
 +	public boolean stopVirtualMachine(long userId, long vmId) {
 +		boolean status = false;
 +		if (s_logger.isDebugEnabled()) {
 +			s_logger.debug("Stopping vm=" + vmId);
 +		}
 +		UserVmVO vm = _vmDao.findById(vmId);
 +		if (vm == null || vm.getRemoved() != null) {
 +			if (s_logger.isDebugEnabled()) {
 +				s_logger.debug("VM is either removed or deleted.");
 +			}
 +			return true;
 +		}
 +
 +		User user = _userDao.findById(userId);
 +		Account account = _accountDao.findById(user.getAccountId());
 +
 +		try {
 +			status = _itMgr.stop(vm, user, account);
 +		} catch (ResourceUnavailableException e) {
 +			s_logger.debug("Unable to stop due to ", e);
 +			status = false;
 +		}
 +
 +		if (status) {
 +			return status;
 +		} else {
 +			return status;
 +		}
 +	}
 +
 +	private int getMaxDataVolumesSupported(UserVmVO vm) {
 +		Long hostId = vm.getHostId();
 +		if (hostId == null) {
 +			hostId = vm.getLastHostId();
 +		}
 +		HostVO host = _hostDao.findById(hostId);
 +		Integer maxDataVolumesSupported = null;
 +		if (host != null) {
 +			_hostDao.loadDetails(host);
 +			maxDataVolumesSupported = _hypervisorCapabilitiesDao
 +					.getMaxDataVolumesLimit(host.getHypervisorType(),
 +							host.getDetail("product_version"));
 +		}
 +		if (maxDataVolumesSupported == null) {
 +			maxDataVolumesSupported = 6; // 6 data disks by default if nothing
 +											// is specified in
 +											// 'hypervisor_capabilities' table
 +		}
 +
 +		return maxDataVolumesSupported.intValue();
 +	}
 +
 +	@Override
 +	@ActionEvent(eventType = EventTypes.EVENT_VOLUME_ATTACH, eventDescription = "attaching volume", async = true)
 +	public Volume attachVolumeToVM(AttachVolumeCmd command) {
 +		Long vmId = command.getVirtualMachineId();
 +		Long volumeId = command.getId();
 +		Long deviceId = command.getDeviceId();
 +		Account caller = UserContext.current().getCaller();
 +
 +		// Check that the volume ID is valid
 +		VolumeVO volume = _volsDao.findById(volumeId);
 +		// Check that the volume is a data volume
 +		if (volume == null || volume.getVolumeType() != Volume.Type.DATADISK) {
 +			throw new InvalidParameterValueException(
 +					"Please specify a valid data volume.");
 +		}
 +
 +		// Check that the volume is not currently attached to any VM
 +		if (volume.getInstanceId() != null) {
 +			throw new InvalidParameterValueException(
 +					"Please specify a volume that is not attached to any VM.");
 +		}
 +
 +		// Check that the volume is not destroyed
 +		if (volume.getState() == Volume.State.Destroy) {
 +			throw new InvalidParameterValueException(
 +					"Please specify a volume that is not destroyed.");
 +		}
 +
 +		// Check that the virtual machine ID is valid and it's a user vm
 +		UserVmVO vm = _vmDao.findById(vmId);
 +		if (vm == null || vm.getType() != VirtualMachine.Type.User) {
 +			throw new InvalidParameterValueException(
 +					"Please specify a valid User VM.");
 +		}
 +
 +		// Check that the VM is in the correct state
 +		if (vm.getState() != State.Running && vm.getState() != State.Stopped) {
 +			throw new InvalidParameterValueException(
 +					"Please specify a VM that is either running or stopped.");
 +		}
 +
 +		// Check that the device ID is valid
 +		if (deviceId != null) {
 +			if (deviceId.longValue() == 0) {
 +				throw new InvalidParameterValueException(
 +						"deviceId can't be 0, which is used by Root device");
 +			}
 +		}
 +
 +		// Check that the number of data volumes attached to VM is less than
 +		// that supported by hypervisor
 +		List<VolumeVO> existingDataVolumes = _volsDao.findByInstanceAndType(
 +				vmId, Volume.Type.DATADISK);
 +		int maxDataVolumesSupported = getMaxDataVolumesSupported(vm);
 +		if (existingDataVolumes.size() >= maxDataVolumesSupported) {
 +			throw new InvalidParameterValueException(
 +					"The specified VM already has the maximum number of data disks ("
 +							+ maxDataVolumesSupported
 +							+ "). Please specify another VM.");
 +		}
 +
 +		// Check that the VM and the volume are in the same zone
 +		if (vm.getDataCenterIdToDeployIn() != volume.getDataCenterId()) {
 +			throw new InvalidParameterValueException(
 +					"Please specify a VM that is in the same zone as the volume.");
 +		}
 +
 +		// If local storage is disabled then attaching a volume with local disk
 +		// offering not allowed
 +		DataCenterVO dataCenter = _dcDao.findById(volume.getDataCenterId());
 +		if (!dataCenter.isLocalStorageEnabled()) {
 +			DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume
 +					.getDiskOfferingId());
 +			if (diskOffering.getUseLocalStorage()) {
 +				throw new InvalidParameterValueException(
 +						"Zone is not configured to use local storage but volume's disk offering "
 +								+ diskOffering.getName() + " uses it");
 +			}
 +		}
 +
 +		// permission check
 +		_accountMgr.checkAccess(caller, null, true, volume, vm);
 +
 +		// Check if volume is stored on secondary Storage.
 +		boolean isVolumeOnSec = false;
 +		VolumeHostVO volHostVO = _volumeHostDao.findByVolumeId(volume.getId());
 +		if (volHostVO != null) {
 +			isVolumeOnSec = true;
 +			if (!(volHostVO.getDownloadState() == Status.DOWNLOADED)) {
 +				throw new InvalidParameterValueException(
 +						"Volume is not uploaded yet. Please try this operation once the volume is uploaded");
 +			}
 +		}
 +
 +		if (!(Volume.State.Allocated.equals(volume.getState())
 +				|| Volume.State.Ready.equals(volume.getState()) || Volume.State.UploadOp
 +					.equals(volume.getState()))) {
 +			throw new InvalidParameterValueException(
 +					"Volume state must be in Allocated, Ready or in Uploaded state");
 +		}
 +
 +		VolumeVO rootVolumeOfVm = null;
 +		List<VolumeVO> rootVolumesOfVm = _volsDao.findByInstanceAndType(vmId,
 +				Volume.Type.ROOT);
 +		if (rootVolumesOfVm.size() != 1) {
 +			throw new CloudRuntimeException(
 +					"The VM "
 +							+ vm.getHostName()
 +							+ " has more than one ROOT volume and is in an invalid state.");
 +		} else {
 +			rootVolumeOfVm = rootVolumesOfVm.get(0);
 +		}
 +
 +		HypervisorType rootDiskHyperType = vm.getHypervisorType();
 +
 +		HypervisorType dataDiskHyperType = _volsDao.getHypervisorType(volume
 +				.getId());
 +		if (dataDiskHyperType != HypervisorType.None
 +				&& rootDiskHyperType != dataDiskHyperType) {
 +			throw new InvalidParameterValueException(
 +					"Can't attach a volume created by: " + dataDiskHyperType
 +							+ " to a " + rootDiskHyperType + " vm");
 +		}
 +
 +		// allocate deviceId
 +		List<VolumeVO> vols = _volsDao.findByInstance(vmId);
 +		if (deviceId != null) {
 +			if (deviceId.longValue() > 15 || deviceId.longValue() == 0
 +					|| deviceId.longValue() == 3) {
 +				throw new RuntimeException("deviceId should be 1,2,4-15");
 +			}
 +			for (VolumeVO vol : vols) {
 +				if (vol.getDeviceId().equals(deviceId)) {
 +					throw new RuntimeException("deviceId " + deviceId
 +							+ " is used by VM " + vm.getHostName());
 +				}
 +			}
 +		} else {
 +			// allocate deviceId here
 +			List<String> devIds = new ArrayList<String>();
 +			for (int i = 1; i < 15; i++) {
 +				devIds.add(String.valueOf(i));
 +			}
 +			devIds.remove("3");
 +			for (VolumeVO vol : vols) {
 +				devIds.remove(vol.getDeviceId().toString().trim());
 +			}
 +			deviceId = Long.parseLong(devIds.iterator().next());
 +		}
 +
 +		boolean createVolumeOnBackend = true;
 +		if (rootVolumeOfVm.getState() == Volume.State.Allocated) {
 +			createVolumeOnBackend = false;
 +			if (isVolumeOnSec) {
 +				throw new CloudRuntimeException(
 +						"Cant attach uploaded volume to the vm which is not created. Please start it and then retry");
 +			}
 +		}
 +
 +		// create volume on the backend only when vm's root volume is allocated
 +		if (createVolumeOnBackend) {
 +			if (volume.getState().equals(Volume.State.Allocated)
 +					|| isVolumeOnSec) {
 +				/* Need to create the volume */
 +				VMTemplateVO rootDiskTmplt = _templateDao.findById(vm
 +						.getTemplateId());
 +				DataCenterVO dcVO = _dcDao.findById(vm
 +						.getDataCenterIdToDeployIn());
 +				HostPodVO pod = _podDao.findById(vm.getPodIdToDeployIn());
 +				StoragePoolVO rootDiskPool = _storagePoolDao
 +						.findById(rootVolumeOfVm.getPoolId());
 +				ServiceOfferingVO svo = _serviceOfferingDao.findById(vm
 +						.getServiceOfferingId());
 +				DiskOfferingVO diskVO = _diskOfferingDao.findById(volume
 +						.getDiskOfferingId());
 +				Long clusterId = (rootDiskPool == null ? null : rootDiskPool
 +						.getClusterId());
 +
 +				if (!isVolumeOnSec) {
 +					volume = _storageMgr.createVolume(volume, vm,
 +							rootDiskTmplt, dcVO, pod, clusterId, svo, diskVO,
 +							new ArrayList<StoragePoolVO>(), volume.getSize(),
 +							rootDiskHyperType);
 +				} else {
 +					try {
 +						// Format of data disk should be the same as root disk
 +						if (!volHostVO
 +								.getFormat()
 +								.getFileExtension()
 +								.equals(_storageMgr
 +										.getSupportedImageFormatForCluster(rootDiskPool
 +												.getClusterId()))) {
 +							throw new InvalidParameterValueException(
 +									"Failed to attach volume to VM since volumes format "
 +											+ volHostVO.getFormat()
 +													.getFileExtension()
 +											+ " is not compatible with the vm hypervisor type");
 +						}
 +
 +						// Check that there is some shared storage.
 +						StoragePoolVO vmRootVolumePool = _storagePoolDao
 +								.findById(rootVolumeOfVm.getPoolId());
 +						List<StoragePoolVO> sharedVMPools = _storagePoolDao
 +								.findPoolsByTags(
 +										vmRootVolumePool.getDataCenterId(),
 +										vmRootVolumePool.getPodId(),
 +										vmRootVolumePool.getClusterId(), null,
 +										true);
 +						if (sharedVMPools.size() == 0) {
 +							throw new CloudRuntimeException(
 +									"Cannot attach volume since there are no shared storage pools in the VM's cluster to copy the uploaded volume to.");
 +						}
 +
 +						volume = _storageMgr.copyVolumeFromSecToPrimary(volume,
 +								vm, rootDiskTmplt, dcVO, pod,
 +								rootDiskPool.getClusterId(), svo, diskVO,
 +								new ArrayList<StoragePoolVO>(),
 +								volume.getSize(), rootDiskHyperType);
 +					} catch (NoTransitionException e) {
 +						throw new CloudRuntimeException(
 +								"Unable to transition the volume ", e);
 +					}
 +				}
 +
 +				if (volume == null) {
 +					throw new CloudRuntimeException(
 +							"Failed to create volume when attaching it to VM: "
 +									+ vm.getHostName());
 +				}
 +			}
 +
 +			StoragePoolVO vmRootVolumePool = _storagePoolDao
 +					.findById(rootVolumeOfVm.getPoolId());
 +			DiskOfferingVO volumeDiskOffering = _diskOfferingDao
 +					.findById(volume.getDiskOfferingId());
 +			String[] volumeTags = volumeDiskOffering.getTagsArray();
 +
 +			boolean isVolumeOnSharedPool = !volumeDiskOffering
 +					.getUseLocalStorage();
 +			StoragePoolVO sourcePool = _storagePoolDao.findById(volume
 +					.getPoolId());
 +			List<StoragePoolVO> matchingVMPools = _storagePoolDao
 +					.findPoolsByTags(vmRootVolumePool.getDataCenterId(),
 +							vmRootVolumePool.getPodId(),
 +							vmRootVolumePool.getClusterId(), volumeTags,
 +							isVolumeOnSharedPool);
 +			boolean moveVolumeNeeded = true;
 +			if (matchingVMPools.size() == 0) {
 +				String poolType;
 +				if (vmRootVolumePool.getClusterId() != null) {
 +					poolType = "cluster";
 +				} else if (vmRootVolumePool.getPodId() != null) {
 +					poolType = "pod";
 +				} else {
 +					poolType = "zone";
 +				}
 +				throw new CloudRuntimeException(
 +						"There are no storage pools in the VM's " + poolType
 +								+ " with all of the volume's tags ("
 +								+ volumeDiskOffering.getTags() + ").");
 +			} else {
 +				long sourcePoolId = sourcePool.getId();
 +				Long sourcePoolDcId = sourcePool.getDataCenterId();
 +				Long sourcePoolPodId = sourcePool.getPodId();
 +				Long sourcePoolClusterId = sourcePool.getClusterId();
 +				for (StoragePoolVO vmPool : matchingVMPools) {
 +					long vmPoolId = vmPool.getId();
 +					Long vmPoolDcId = vmPool.getDataCenterId();
 +					Long vmPoolPodId = vmPool.getPodId();
 +					Long vmPoolClusterId = vmPool.getClusterId();
 +
 +					// Moving a volume is not required if storage pools belongs
 +					// to same cluster in case of shared volume or
 +					// identical storage pool in case of local
 +					if (sourcePoolDcId == vmPoolDcId
 +							&& sourcePoolPodId == vmPoolPodId
 +							&& sourcePoolClusterId == vmPoolClusterId
 +							&& (isVolumeOnSharedPool || sourcePoolId == vmPoolId)) {
 +						moveVolumeNeeded = false;
 +						break;
 +					}
 +				}
 +			}
 +
 +			if (moveVolumeNeeded) {
 +				if (isVolumeOnSharedPool) {
 +					// Move the volume to a storage pool in the VM's zone, pod,
 +					// or cluster
 +					try {
 +						volume = _storageMgr.moveVolume(volume,
 +								vmRootVolumePool.getDataCenterId(),
 +								vmRootVolumePool.getPodId(),
 +								vmRootVolumePool.getClusterId(),
 +								dataDiskHyperType);
 +					} catch (ConcurrentOperationException e) {
 +						throw new CloudRuntimeException(e.toString());
 +					}
 +				} else {
 +					throw new CloudRuntimeException(
 +							"Failed to attach local data volume "
 +									+ volume.getName()
 +									+ " to VM "
 +									+ vm.getDisplayName()
 +									+ " as migration of local data volume is not allowed");
 +				}
 +			}
 +		}
 +
 +		AsyncJobExecutor asyncExecutor = BaseAsyncJobExecutor
 +				.getCurrentExecutor();
 +		if (asyncExecutor != null) {
 +			AsyncJobVO job = asyncExecutor.getJob();
 +
 +			if (s_logger.isInfoEnabled()) {
 +				s_logger.info("Trying to attaching volume " + volumeId
 +						+ " to vm instance:" + vm.getId()
 +						+ ", update async job-" + job.getId()
 +						+ " progress status");
 +			}
 +
 +			_asyncMgr.updateAsyncJobAttachment(job.getId(), "volume", volumeId);
 +			_asyncMgr.updateAsyncJobStatus(job.getId(),
 +					BaseCmd.PROGRESS_INSTANCE_CREATED, volumeId);
 +		}
 +
 +		String errorMsg = "Failed to attach volume: " + volume.getName()
 +				+ " to VM: " + vm.getHostName();
 +		boolean sendCommand = (vm.getState() == State.Running);
 +		AttachVolumeAnswer answer = null;
 +		Long hostId = vm.getHostId();
 +		if (hostId == null) {
 +			hostId = vm.getLastHostId();
 +			HostVO host = _hostDao.findById(hostId);
 +			if (host != null
 +					&& host.getHypervisorType() == HypervisorType.VMware) {
 +				sendCommand = true;
 +			}
 +		}
 +
 +		if (sendCommand) {
 +			StoragePoolVO volumePool = _storagePoolDao.findById(volume
 +					.getPoolId());
 +			AttachVolumeCommand cmd = new AttachVolumeCommand(true,
 +					vm.getInstanceName(), volume.getPoolType(),
 +					volume.getFolder(), volume.getPath(), volume.getName(),
 +					deviceId, volume.getChainInfo());
 +			cmd.setPoolUuid(volumePool.getUuid());
 +
 +			try {
 +				answer = (AttachVolumeAnswer) _agentMgr.send(hostId, cmd);
 +			} catch (Exception e) {
 +				throw new CloudRuntimeException(errorMsg + " due to: "
 +						+ e.getMessage());
 +			}
 +		}
 +
 +		if (!sendCommand || (answer != null && answer.getResult())) {
 +			// Mark the volume as attached
 +			if (sendCommand) {
 +				_volsDao.attachVolume(volume.getId(), vmId,
 +						answer.getDeviceId());
 +			} else {
 +				_volsDao.attachVolume(volume.getId(), vmId, deviceId);
 +			}
 +			return _volsDao.findById(volumeId);
 +		} else {
 +			if (answer != null) {
 +				String details = answer.getDetails();
 +				if (details != null && !details.isEmpty()) {
 +					errorMsg += "; " + details;
 +				}
 +			}
 +			throw new CloudRuntimeException(errorMsg);
 +		}
 +	}
 +
 +	@Override
 +	@ActionEvent(eventType = EventTypes.EVENT_VOLUME_DETACH, eventDescription = "detaching volume", async = true)
 +	public Volume detachVolumeFromVM(DetachVolumeCmd cmmd) {
 +		Account caller = UserContext.current().getCaller();
 +		if ((cmmd.getId() == null && cmmd.getDeviceId() == null && cmmd
 +				.getVirtualMachineId() == null)
 +				|| (cmmd.getId() != null && (cmmd.getDeviceId() != null || cmmd
 +						.getVirtualMachineId() != null))
 +				|| (cmmd.getId() == null && (cmmd.getDeviceId() == null || cmmd
 +						.getVirtualMachineId() == null))) {
 +			throw new InvalidParameterValueException(
 +					"Please provide either a volume id, or a tuple(device id, instance id)");
 +		}
 +
 +		Long volumeId = cmmd.getId();
 +		VolumeVO volume = null;
 +
 +		if (volumeId != null) {
 +			volume = _volsDao.findById(volumeId);
 +		} else {
 +			volume = _volsDao.findByInstanceAndDeviceId(
 +					cmmd.getVirtualMachineId(), cmmd.getDeviceId()).get(0);
 +		}
 +
 +		Long vmId = null;
 +
 +		if (cmmd.getVirtualMachineId() == null) {
 +			vmId = volume.getInstanceId();
 +		} else {
 +			vmId = cmmd.getVirtualMachineId();
 +		}
 +
 +		// Check that the volume ID is valid
 +		if (volume == null) {
 +			throw new InvalidParameterValueException(
 +					"Unable to find volume with ID: " + volumeId);
 +		}
 +
 +		// Permissions check
 +		_accountMgr.checkAccess(caller, null, true, volume);
 +
 +		// Check that the volume is a data volume
 +		if (volume.getVolumeType() != Volume.Type.DATADISK) {
 +			throw new InvalidParameterValueException(
 +					"Please specify a data volume.");
 +		}
 +
 +		// Check that the volume is currently attached to a VM
 +		if (vmId == null) {
 +			throw new InvalidParameterValueException(
 +					"The specified volume is not attached to a VM.");
 +		}
 +
 +		// Check that the VM is in the correct state
 +		UserVmVO vm = _vmDao.findById(vmId);
 +		if (vm.getState() != State.Running && vm.getState() != State.Stopped
 +				&& vm.getState() != State.Destroyed) {
 +			throw new InvalidParameterValueException(
 +					"Please specify a VM that is either running or stopped.");
 +		}
 +
 +		AsyncJobExecutor asyncExecutor = BaseAsyncJobExecutor
 +				.getCurrentExecutor();
 +		if (asyncExecutor != null) {
 +			AsyncJobVO job = asyncExecutor.getJob();
 +
 +			if (s_logger.isInfoEnabled()) {
 +				s_logger.info("Trying to attaching volume " + volumeId
 +						+ "to vm instance:" + vm.getId()
 +						+ ", update async job-" + job.getId()
 +						+ " progress status");
 +			}
 +
 +			_asyncMgr.updateAsyncJobAttachment(job.getId(), "volume", volumeId);
 +			_asyncMgr.updateAsyncJobStatus(job.getId(),
 +					BaseCmd.PROGRESS_INSTANCE_CREATED, volumeId);
 +		}
 +
 +		String errorMsg = "Failed to detach volume: " + volume.getName()
 +				+ " from VM: " + vm.getHostName();
 +		boolean sendCommand = (vm.getState() == State.Running);
 +		Answer answer = null;
 +
 +		if (sendCommand) {
 +			AttachVolumeCommand cmd = new AttachVolumeCommand(false,
 +					vm.getInstanceName(), volume.getPoolType(),
 +					volume.getFolder(), volume.getPath(), volume.getName(),
 +					cmmd.getDeviceId() != null ? cmmd.getDeviceId() : volume
 +							.getDeviceId(), volume.getChainInfo());
 +
 +			StoragePoolVO volumePool = _storagePoolDao.findById(volume
 +					.getPoolId());
 +			cmd.setPoolUuid(volumePool.getUuid());
 +
 +			try {
 +				answer = _agentMgr.send(vm.getHostId(), cmd);
 +			} catch (Exception e) {
 +				throw new CloudRuntimeException(errorMsg + " due to: "
 +						+ e.getMessage());
 +			}
 +		}
 +
 +		if (!sendCommand || (answer != null && answer.getResult())) {
 +			// Mark the volume as detached
 +			_volsDao.detachVolume(volume.getId());
 +			if (answer != null && answer instanceof AttachVolumeAnswer) {
 +				volume.setChainInfo(((AttachVolumeAnswer) answer)
 +						.getChainInfo());
 +				_volsDao.update(volume.getId(), volume);
 +			}
 +
 +			return _volsDao.findById(volumeId);
 +		} else {
 +
 +			if (answer != null) {
 +				String details = answer.getDetails();
 +				if (details != null && !details.isEmpty()) {
 +					errorMsg += "; " + details;
 +				}
 +			}
 +
 +			throw new CloudRuntimeException(errorMsg);
 +		}
 +	}
 +
 +	@Override
 +	public boolean attachISOToVM(long vmId, long isoId, boolean attach) {
 +		UserVmVO vm = _vmDao.findById(vmId);
 +
 +		if (vm == null) {
 +			return false;
 +		} else if (vm.getState() != State.Running) {
 +			return true;
 +		}
 +		String isoPath;
 +		VMTemplateVO tmplt = _templateDao.findById(isoId);
 +		if (tmplt == null) {
 +			s_logger.warn("ISO: " + isoId + " does not exist");
 +			return false;
 +		}
 +		// Get the path of the ISO
 +		Pair<String, String> isoPathPair = null;
 +		if (tmplt.getTemplateType() == TemplateType.PERHOST) {
 +			isoPath = tmplt.getName();
 +		} else {
 +			isoPathPair = _storageMgr.getAbsoluteIsoPath(isoId,
 +					vm.getDataCenterIdToDeployIn());
 +			if (isoPathPair == null) {
 +				s_logger.warn("Couldn't get absolute iso path");
 +				return false;
 +			} else {
 +				isoPath = isoPathPair.first();
 +			}
 +		}
 +
 +		String vmName = vm.getInstanceName();
 +
 +		HostVO host = _hostDao.findById(vm.getHostId());
 +		if (host == null) {
 +			s_logger.warn("Host: " + vm.getHostId() + " does not exist");
 +			return false;
 +		}
 +		AttachIsoCommand cmd = new AttachIsoCommand(vmName, isoPath, attach);
 +		if (isoPathPair != null) {
 +			cmd.setStoreUrl(isoPathPair.second());
 +		}
 +		Answer a = _agentMgr.easySend(vm.getHostId(), cmd);
 +
 +		return (a != null && a.getResult());
 +	}
 +
 +	private UserVm rebootVirtualMachine(long userId, long vmId)
 +			throws InsufficientCapacityException, ResourceUnavailableException {
 +		UserVmVO vm = _vmDao.findById(vmId);
 +		User caller = _accountMgr.getActiveUser(userId);
 +		Account owner = _accountMgr.getAccount(vm.getAccountId());
 +
 +		if (vm == null || vm.getState() == State.Destroyed
 +				|| vm.getState() == State.Expunging || vm.getRemoved() != null) {
 +			s_logger.warn("Vm id=" + vmId + " doesn't exist");
 +			return null;
 +		}
 +
 +		if (vm.getState() == State.Running && vm.getHostId() != null) {
 +			return _itMgr.reboot(vm, null, caller, owner);
 +		} else {
 +			s_logger.error("Vm id=" + vmId
 +					+ " is not in Running state, failed to reboot");
 +			return null;
 +		}
 +	}
 +
 +	@Override
 +	@ActionEvent(eventType = EventTypes.EVENT_VM_UPGRADE, eventDescription = "upgrading Vm")
 +	/*
 +	 * TODO: cleanup eventually - Refactored API call
 +	 */
 +	public UserVm upgradeVirtualMachine(UpgradeVMCmd cmd) {
 +		Long vmId = cmd.getId();
 +		Long svcOffId = cmd.getServiceOfferingId();
 +		Account caller = UserContext.current().getCaller();
 +
 +		// Verify input parameters
 +		UserVmVO vmInstance = _vmDao.findById(vmId);
 +		if (vmInstance == null) {
 +			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);
 +
 +		_itMgr.upgradeVmDb(vmId, svcOffId);
 +
 +		return _vmDao.findById(vmInstance.getId());
 +	}
 +
 +	@Override
 +	public HashMap<Long, VmStatsEntry> getVirtualMachineStatistics(long hostId,
 +			String hostName, List<Long> vmIds) throws CloudRuntimeException {
 +		HashMap<Long, VmStatsEntry> vmStatsById = new HashMap<Long, VmStatsEntry>();
 +
 +		if (vmIds.isEmpty()) {
 +			return vmStatsById;
 +		}
 +
 +		List<String> vmNames = new ArrayList<String>();
 +
 +		for (Long vmId : vmIds) {
 +			UserVmVO vm = _vmDao.findById(vmId);
 +			vmNames.add(vm.getInstanceName());
 +		}
 +
 +		Answer answer = _agentMgr.easySend(hostId, new GetVmStatsCommand(
 +				vmNames, _hostDao.findById(hostId).getGuid(), hostName));
 +		if (answer == null || !answer.getResult()) {
 +			s_logger.warn("Unable to obtain VM statistics.");
 +			return null;
 +		} else {
 +			HashMap<String, VmStatsEntry> vmStatsByName = ((GetVmStatsAnswer) answer)
 +					.getVmStatsMap();
 +
 +			if (vmStatsByName == null) {
 +				s_logger.warn("Unable to obtain VM statistics.");
 +				return null;
 +			}
 +
 +			for (String vmName : vmStatsByName.keySet()) {
 +				vmStatsById.put(vmIds.get(vmNames.indexOf(vmName)),
 +						vmStatsByName.get(vmName));
 +			}
 +		}
 +
 +		return vmStatsById;
 +	}
 +
 +	@Override
 +	@DB
 +	public UserVm recoverVirtualMachine(RecoverVMCmd cmd)
 +			throws ResourceAllocationException, CloudRuntimeException {
 +
 +		Long vmId = cmd.getId();
 +		Account caller = UserContext.current().getCaller();
 +
 +		// Verify input parameters
 +		UserVmVO vm = _vmDao.findById(vmId.longValue());
 +
 +		if (vm == null) {
 +			throw new InvalidParameterValueException(
 +					"unable to find a virtual machine with id " + vmId);
 +		}
 +
 +		// check permissions
 +		_accountMgr.checkAccess(caller, null, true, vm);
 +
 +		if (vm.getRemoved() != null) {
 +			if (s_logger.isDebugEnabled()) {
 +				s_logger.debug("Unable to find vm or vm is removed: " + vmId);
 +			}
 +			throw new InvalidParameterValueException("Unable to find vm by id "
 +					+ vmId);
 +		}
 +
 +		if (vm.getState() != State.Destroyed) {
 +			if (s_logger.isDebugEnabled()) {
 +				s_logger.debug("vm is not in the right state: " + vmId);
 +			}
 +			throw new InvalidParameterValueException("Vm with id " + vmId
 +					+ " is not in the right state");
 +		}
 +
 +		if (s_logger.isDebugEnabled()) {
 +			s_logger.debug("Recovering vm " + vmId);
 +		}
 +
 +		Transaction txn = Transaction.currentTxn();
 +		AccountVO account = null;
 +		txn.start();
 +
 +		account = _accountDao.lockRow(vm.getAccountId(), true);
 +
 +		// if the account is deleted, throw error
 +		if (account.getRemoved() != null) {
 +			throw new CloudRuntimeException(
 +					"Unable to recover VM as the account is deleted");
 +		}
 +
 +		// First check that the maximum number of UserVMs for the given
 +		// accountId will not be exceeded
 +		_resourceLimitMgr.checkResourceLimit(account, ResourceType.user_vm);
 +
 +		_haMgr.cancelDestroy(vm, vm.getHostId());
 +
 +		try {
 +			if (!_itMgr.stateTransitTo(vm,
 +					VirtualMachine.Event.RecoveryRequested, null)) {
 +				s_logger.debug("Unable to recover the vm because it is not in the correct state: "
 +						+ vmId);
 +				throw new InvalidParameterValueException(
 +						"Unable to recover the vm because it is not in the correct state: "
 +								+ vmId);
 +			}
 +		} catch (NoTransitionException e) {
 +			throw new InvalidParameterValueException(
 +					"Unable to recover the vm because it is not in the correct state: "
 +							+ vmId);
 +		}
 +
 +		// Recover the VM's disks
 +		List<VolumeVO> volumes = _volsDao.findByInstance(vmId);
 +		for (VolumeVO volume : volumes) {
 +			if (volume.getVolumeType().equals(Volume.Type.ROOT)) {
 +				// Create an event
 +				Long templateId = volume.getTemplateId();
 +				Long diskOfferingId = volume.getDiskOfferingId();
 +				Long offeringId = null;
 +				if (diskOfferingId != null) {
 +					DiskOfferingVO offering = _diskOfferingDao
 +							.findById(diskOfferingId);
 +					if (offering != null
 +							&& (offering.getType() == DiskOfferingVO.Type.Disk)) {
 +						offeringId = offering.getId();
 +					}
 +				}
 +				UsageEventVO usageEvent = new UsageEventVO(
 +						EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(),
 +						volume.getDataCenterId(), volume.getId(),
 +						volume.getName(), offeringId, templateId,
 +						volume.getSize());
 +				_usageEventDao.persist(usageEvent);
 +			}
 +		}
 +
 +		_resourceLimitMgr.incrementResourceCount(account.getId(),
 +				ResourceType.volume, new Long(volumes.size()));
 +
 +		_resourceLimitMgr.incrementResourceCount(account.getId(),
 +				ResourceType.user_vm);
 +
 +		txn.commit();
 +
 +		return _vmDao.findById(vmId);
 +	}
 +
 +	@Override
 +	public boolean configure(String name, Map<String, Object> params)
 +			throws ConfigurationException {
 +		_name = name;
 +
 +		ComponentLocator locator = ComponentLocator.getCurrentLocator();
 +		_configDao = locator.getDao(ConfigurationDao.class);
 +		if (_configDao == null) {
 +			throw new ConfigurationException(
 +					"Unable to get the configuration dao.");
 +		}
 +
 +		Map<String, String> configs = _configDao.getConfiguration(
 +				"AgentManager", params);
 +
 +		_instance = configs.get("instance.name");
 +		if (_instance == null) {
 +			_instance = "DEFAULT";
 +		}
 +
 +		String value = _configDao
 +				.getValue(Config.CreatePrivateTemplateFromVolumeWait.toString());
 +		_createprivatetemplatefromvolumewait = NumbersUtil.parseInt(value,
 +				Integer.parseInt(Config.CreatePrivateTemplateFromVolumeWait
 +						.getDefaultValue()));
 +
 +		value = _configDao
 +				.getValue(Config.CreatePrivateTemplateFromSnapshotWait
 +						.toString());
 +		_createprivatetemplatefromsnapshotwait = NumbersUtil.parseInt(value,
 +				Integer.parseInt(Config.CreatePrivateTemplateFromSnapshotWait
 +						.getDefaultValue()));
 +
 +		String workers = configs.get("expunge.workers");
 +		int wrks = NumbersUtil.parseInt(workers, 10);
 +
 +		String time = configs.get("expunge.interval");
 +		_expungeInterval = NumbersUtil.parseInt(time, 86400);
 +		if (_expungeInterval < 600) {
 +			_expungeInterval = 600;
 +		}
 +		time = configs.get("expunge.delay");
 +		_expungeDelay = NumbersUtil.parseInt(time, _expungeInterval);
 +		if (_expungeDelay < 600) {
 +			_expungeDelay = 600;
 +		}
 +		_executor = Executors.newScheduledThreadPool(wrks,
 +				new NamedThreadFactory("UserVm-Scavenger"));
 +
 +		_itMgr.registerGuru(VirtualMachine.Type.User, this);
 +
 +		VirtualMachine.State.getStateMachine().registerListener(
 +				new UserVmStateListener(_usageEventDao, _networkDao, _nicDao));
 +
 +		s_logger.info("User VM Manager is configured.");
 +
 +		return true;
 +	}
 +
 +	@Override
 +	public String getName() {
 +		return _name;
 +	}
 +
 +	@Override
 +	public boolean start() {
 +		_executor.scheduleWithFixedDelay(new ExpungeTask(), _expungeInterval,
 +				_expungeInterval, TimeUnit.SECONDS);
 +		return true;
 +	}
 +
 +	@Override
 +	public boolean stop() {
 +		_executor.shutdown();
 +		return true;
 +	}
 +
 +	protected UserVmManagerImpl() {
 +	}
 +
 +	public String getRandomPrivateTemplateName() {
 +		return UUID.randomUUID().toString();
 +	}
 +
 +	@Override
 +	public Long convertToId(String vmName) {
 +		if (!VirtualMachineName.isValidVmName(vmName, _instance)) {
 +			return null;
 +		}
 +		return VirtualMachineName.getVmId(vmName);
 +	}
 +
 +	@Override
 +	public boolean expunge(UserVmVO vm, long callerUserId, Account caller) {
 +		UserContext ctx = UserContext.current();
 +		ctx.setAccountId(vm.getAccountId());
 +
 +		try {
 +			// expunge the vm
 +			if (!_itMgr.advanceExpunge(vm, _accountMgr.getSystemUser(), caller)) {
 +				s_logger.info("Did not expunge " + vm);
 +				return false;
 +			}
 +
 +			// Only if vm is not expunged already, cleanup it's resources
 +			if (vm != null && vm.getRemoved() == null) {
 +				// Cleanup vm resources - all the PF/LB/StaticNat rules
 +				// associated with vm
 +				s_logger.debug("Starting cleaning up vm " + vm
 +						+ " resources...");
 +				if (cleanupVmResources(vm.getId())) {
 +					s_logger.debug("Successfully cleaned up vm " + vm
 +							+ " resources as a part of expunge process");
 +				} else {
 +					s_logger.warn("Failed to cleanup resources as a part of vm "
 +							+ vm + " expunge");
 +					return false;
 +				}
 +
 +				_itMgr.remove(vm, _accountMgr.getSystemUser(), caller);
 +			}
 +
 +			return true;
 +
 +		} catch (ResourceUnavailableException e) {
 +			s_logger.warn("Unable to expunge  " + vm, e);
 +			return false;
 +		} catch (OperationTimedoutException e) {
 +			s_logger.warn("Operation time out on expunging " + vm, e);
 +			return false;
 +		} catch (ConcurrentOperationException e) {
 +			s_logger.warn("Concurrent operations on expunging " + vm, e);
 +			return false;
 +		}
 +	}
 +
 +	private boolean cleanupVmResources(long vmId) {
 +		boolean success = true;
 +		// Remove vm from security groups
 +		_securityGroupMgr.removeInstanceFromGroups(vmId);
 +
 +		// Remove vm from instance group
 +		removeInstanceFromInstanceGroup(vmId);
 +
 +		// cleanup firewall rules
 +		if (_firewallMgr.revokeFirewallRulesForVm(vmId)) {
 +			s_logger.debug("Firewall rules are removed successfully as a part of vm id="
 +					+ vmId + " expunge");
 +		} else {
 +			success = false;
 +			s_logger.warn("Fail to remove firewall rules as a part of vm id="
 +					+ vmId + " expunge");
 +		}
 +
 +		// cleanup port forwarding rules
 +		if (_rulesMgr.revokePortForwardingRulesForVm(vmId)) {
 +			s_logger.debug("Port forwarding rules are removed successfully as a part of vm id="
 +					+ vmId + " expunge");
 +		} else {
 +			success = false;
 +			s_logger.warn("Fail to remove port forwarding rules as a part of vm id="
 +					+ vmId + " expunge");
 +		}
 +
 +		// cleanup load balancer rules
 +		if (_lbMgr.removeVmFromLoadBalancers(vmId)) {
 +			s_logger.debug("Removed vm id=" + vmId
 +					+ " from all load balancers as a part of expunge process");
 +		} else {
 +			success = false;
 +			s_logger.warn("Fail to remove vm id=" + vmId
 +					+ " from load balancers as a part of expunge process");
 +		}
 +
 +		// If vm is assigned to static nat, disable static nat for the ip
 +		// address and disassociate ip if elasticIP is enabled
 +		IPAddressVO ip = _ipAddressDao.findByAssociatedVmId(vmId);
 +		try {
 +			if (ip != null) {
 +				if (_rulesMgr.disableStaticNat(ip.getId(),
 +						_accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM),
 +						User.UID_SYSTEM, true)) {
 +					s_logger.debug("Disabled 1-1 nat for ip address " + ip
 +							+ " as a part of vm id=" + vmId + " expunge");
 +				} else {
 +					s_logger.warn("Failed to disable static nat for ip address "
 +							+ ip + " as a part of vm id=" + vmId + " expunge");
 +					success = false;
 +				}
 +			}
 +		} catch (ResourceUnavailableException e) {
 +			success = false;
 +			s_logger.warn("Failed to disable static nat for ip address " + ip
 +					+ " as a part of vm id=" + vmId
 +					+ " expunge because resource is unavailable", e);
 +		}
 +
 +		return success;
 +	}
 +
 +	@Override
 +	public void deletePrivateTemplateRecord(Long templateId) {
 +		if (templateId != null) {
 +			_templateDao.remove(templateId);
 +		}
 +	}
 +
 +	@Override
 +	@ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating template", create = true)
 +	public VMTemplateVO createPrivateTemplateRecord(CreateTemplateCmd cmd,
 +			Account templateOwner) throws ResourceAllocationException {
 +		Long userId = UserContext.current().getCallerUserId();
 +
 +		Account caller = UserContext.current().getCaller();
 +		boolean isAdmin = (isAdmin(caller.getType()));
 +
 +		_accountMgr.checkAccess(caller, null, true, templateOwner);
 +
 +		String name = cmd.getTemplateName();
 +		if ((name == null) || (name.length() > 32)) {
 +			throw new InvalidParameterValueException(
 +					"Template name cannot be null and should be less than 32 characters");
 +		}
 +
 +		if (cmd.getTemplateTag() != null) {
 +			if (!_accountService.isRootAdmin(caller.getType())) {
 +				throw new PermissionDeniedException(
 +						"Parameter templatetag can only be specified by a Root Admin, permission denied");
 +			}
 +		}
 +
 +		// do some parameter defaulting
 +		Integer bits = cmd.getBits();
 +		Boolean requiresHvm = cmd.getRequiresHvm();
 +		Boolean passwordEnabled = cmd.isPasswordEnabled();
 +		Boolean isPublic = cmd.isPublic();
 +		Boolean featured = cmd.isFeatured();
 +		int bitsValue = ((bits == null) ? 64 : bits.intValue());
 +		boolean requiresHvmValue = ((requiresHvm == null) ? true : requiresHvm
 +				.booleanValue());
 +		boolean passwordEnabledValue = ((passwordEnabled == null) ? false
 +				: passwordEnabled.booleanValue());
 +		if (isPublic == null) {
 +			isPublic = Boolean.FALSE;
 +		}
 +		boolean allowPublicUserTemplates = Boolean.parseBoolean(_configDao
 +				.getValue("allow.public.user.templates"));
 +		if (!isAdmin && !allowPublicUserTemplates && isPublic) {
 +			throw new PermissionDeniedException("Failed to create template "
 +					+ name + ", only private templates can be created.");
 +		}
 +
 +		Long volumeId = cmd.getVolumeId();
 +		Long snapshotId = cmd.getSnapshotId();
 +		if ((volumeId == null) && (snapshotId == null)) {
 +			throw new InvalidParameterValueException(
 +					"Failed to create private template record, neither volume ID nor snapshot ID were specified.");
 +		}
 +		if ((volumeId != null) && (snapshotId != null)) {
 +			throw new InvalidParameterValueException(
 +					"Failed to create private template record, please specify only one of volume ID ("
 +							+ volumeId
 +							+ ") and snapshot ID ("
 +							+ snapshotId
 +							+ ")");
 +		}
 +
 +		HypervisorType hyperType;
 +		VolumeVO volume = null;
 +		VMTemplateVO privateTemplate = null;
 +		if (volumeId != null) { // create template from volume
 +			volume = _volsDao.findById(volumeId);
 +			if (volume == null) {
 +				throw new InvalidParameterValueException(
 +						"Failed to create private template record, unable to find volume "
 +								+ volumeId);
 +			}
 +			// check permissions
 +			_accountMgr.checkAccess(caller, null, true, volume);
 +
 +			// If private template is created from Volume, check that the volume
 +			// will not be active when the private template is
 +			// created
 +			if (!_storageMgr.volumeInactive(volume)) {
 +				String msg = "Unable to create private template for volume: "
 +						+ volume.getName()
 +						+ "; volume is attached to a non-stopped VM, please stop the VM first";
 +				if (s_logger.isInfoEnabled()) {
 +					s_logger.info(msg);
 +				}
 +				throw new CloudRuntimeException(msg);
 +			}
 +			hyperType = _volsDao.getHypervisorType(volumeId);
 +		} else { // create template from snapshot
 +			SnapshotVO snapshot = _snapshotDao.findById(snapshotId);
 +			if (snapshot == null) {
 +				throw new InvalidParameterValueException(
 +						"Failed to create private template record, unable to find snapshot "
 +								+ snapshotId);
 +			}
 +
 +			volume = _volsDao.findById(snapshot.getVolumeId());
 +			VolumeVO snapshotVolume = _volsDao
 +					.findByIdIncludingRemoved(snapshot.getVolumeId());
 +
 +			// check permissions
 +			_accountMgr.checkAccess(caller, null, true, snapshot);
 +
 +			if (snapshot.getStatus() != Snapshot.Status.BackedUp) {
 +				throw new InvalidParameterValueException("Snapshot id="
 +						+ snapshotId + " is not in " + Snapshot.Status.BackedUp
 +						+ " state yet and can't be used for template creation");
 +			}
 +
 +			/*
 +			 * // bug #11428. Operation not supported if vmware and snapshots
 +			 * parent volume = ROOT if(snapshot.getHypervisorType() ==
 +			 * HypervisorType.VMware && snapshotVolume.getVolumeType() ==
 +			 * Type.DATADISK){ throw new UnsupportedServiceException(
 +			 * "operation not supported, snapshot with id " + snapshotId +
 +			 * " is created from Data Disk"); }
 +			 */
 +
 +			hyperType = snapshot.getHypervisorType();
 +		}
 +
 +		_resourceLimitMgr.checkResourceLimit(templateOwner,
 +				ResourceType.template);
 +
 +		if (!isAdmin || featured == null) {
 +			featured = Boolean.FALSE;
 +		}
 +		Long guestOSId = cmd.getOsTypeId();
 +		GuestOSVO guestOS = _guestOSDao.findById(guestOSId);
 +		if (guestOS == null) {
 +			throw new InvalidParameterValueException("GuestOS with ID: "
 +					+ guestOSId + " does not exist.");
 +		}
 +
 +		String uniqueName = Long.valueOf((userId == null) ? 1 : userId)
 +				.toString()
 +				+ UUID.nameUUIDFromBytes(name.getBytes()).toString();
 +		Long nextTemplateId = _templateDao.getNextInSequence(Long.class, "id");
 +		String description = cmd.getDisplayText();
 +		boolean isExtractable = false;
 +		Long sourceTemplateId = null;
 +		if (volume != null) {
 +			VMTemplateVO template = ApiDBUtils.findTemplateById(volume
 +					.getTemplateId());
 +			isExtractable = template != null
 +					&& template.isExtractable()
 +					&& template.getTemplateType() != Storage.TemplateType.SYSTEM;
 +			if (template != null) {
 +				sourceTemplateId = template.getId();
 +			} else if (volume.getVolumeType() == Type.ROOT) { // vm created out
 +																// of blank
 +																// template
 +				UserVm userVm = ApiDBUtils.findUserVmById(volume
 +						.getInstanceId());
 +				sourceTemplateId = userVm.getIsoId();
 +			}
 +		}
 +		String templateTag = cmd.getTemplateTag();
 +		if (templateTag != null) {
 +			if (s_logger.isDebugEnabled()) {
 +				s_logger.debug("Adding template tag: " + templateTag);
 +			}
 +		}
 +		privateTemplate = new VMTemplateVO(nextTemplateId, uniqueName, name,
 +				ImageFormat.RAW, isPublic, featured, isExtractable,
 +				TemplateType.USER, null, null, requiresHvmValue, bitsValue,
 +				templateOwner.getId(), null, description, passwordEnabledValue,
 +				guestOS.getId(), true, hyperType, templateTag, cmd.getDetails());
 +		if (sourceTemplateId != null) {
 +			if (s_logger.isDebugEnabled()) {
 +				s_logger.debug("This template is getting created from other template, setting source template Id to: "
 +						+ sourceTemplateId);
 +			}
 +		}
 +		privateTemplate.setSourceTemplateId(sourceTemplateId);
 +
 +		VMTemplateVO template = _templateDao.persist(privateTemplate);
 +		// Increment the number of templates
 +		if (template != null) {
 +			if (cmd.getDetails() != null) {
 +				_templateDetailsDao.persist(template.getId(), cmd.getDetails());
 +			}
 +
 +			_resourceLimitMgr.incrementResourceCount(templateOwner.getId(),
 +					ResourceType.template);
 +		}
 +
 +		if (template != null) {
 +			return template;
 +		} else {
 +			throw new CloudRuntimeException("Failed to create a template");
 +		}
 +
 +	}
 +
 +	@Override
 +	@DB
 +	@ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating template", async = true)
 +	public VMTemplateVO createPrivateTemplate(CreateTemplateCmd command)
 +			throws CloudRuntimeException {
 +		Long userId = UserContext.current().getCallerUserId();
 +		if (userId == null) {
 +			userId = User.UID_SYSTEM;
 +		}
 +		long templateId = command.getEntityId();
 +		Long volumeId = command.getVolumeId();
 +		Long snapshotId = command.getSnapshotId();
 +		SnapshotCommand cmd = null;
 +		VMTemplateVO privateTemplate = null;
 +
 +		String uniqueName = getRandomPrivateTemplateName();
 +
 +		StoragePoolVO pool = null;
 +		HostVO secondaryStorageHost = null;
 +		Long zoneId = null;
 +		Long accountId = null;
 +		SnapshotVO snapshot = null;
 +		String secondaryStorageURL = null;
 +		try {
 +			if (snapshotId != null) { // create template from snapshot
 +				snapshot = _snapshotDao.findById(snapshotId);
 +				if (snapshot == null) {
 +					throw new CloudRuntimeException(
 +							"Unable to find Snapshot for Id " + snapshotId);
 +				}
 +				zoneId = snapshot.getDataCenterId();
 +				secondaryStorageHost = _snapshotMgr
 +						.getSecondaryStorageHost(snapshot);
 +				secondaryStorageURL = _snapshotMgr
 +						.getSecondaryStorageURL(snapshot);
 +				String name = command.getTemplateName();
 +				String backupSnapshotUUID = snapshot.getBackupSnapshotId();
 +				if (backupSnapshotUUID == null) {
 +					throw new CloudRuntimeException(
 +							"Unable to create private template from snapshot "
 +									+ snapshotId
 +									+ " due to there is no backupSnapshotUUID for this snapshot");
 +				}
 +
 +				Long dcId = snapshot.getDataCenterId();
 +				accountId = snapshot.getAccountId();
 +				volumeId = snapshot.getVolumeId();
 +
 +				String origTemplateInstallPath = null;
 +				List<StoragePoolVO> pools = _storageMgr
 +						.ListByDataCenterHypervisor(zoneId,
 +								snapshot.getHypervisorType());
 +				if (pools == null || pools.size() == 0) {
 +					throw new CloudRuntimeException(
 +							"Unable to find storage pools in zone " + zoneId);
 +				}
 +				pool = pools.get(0);
 +				if (snapshot.getVersion() != null
 +						&& snapshot.getVersion().equalsIgnoreCase("2.1")) {
 +					VolumeVO volume = _volsDao
 +							.findByIdIncludingRemoved(volumeId);
 +					if (volume == null) {
 +						throw new CloudRuntimeException(
 +								"failed to upgrade snapshot "
 +										+ snapshotId
 +										+ " due to unable to find orignal volume:"
 +										+ volumeId + ", try it later ");
 +					}
 +					if (volume.getTemplateId() == null) {
 +						_snapshotDao.updateSnapshotVersion(volumeId, "2.1",
 +								"2.2");
 +					} else {
 +						VMTemplateVO template = _templateDao
 +								.findByIdIncludingRemoved(volume
 +										.getTemplateId());
 +						if (template == null) {
 +							throw new CloudRuntimeException(
 +									"failed to upgrade snapshot "
 +											+ snapshotId
 +											+ " due to unalbe to find orignal template :"
 +											+ volume.getTemplateId()
 +											+ ", try it later ");
 +						}
 +						Long origTemplateId = template.getId();
 +						Long origTmpltAccountId = template.getAccountId();
 +						if (!_volsDao.lockInLockTable(volumeId.toString(), 10)) {
 +							throw new CloudRuntimeException(
 +									"failed to upgrade snapshot " + snapshotId
 +											+ " due to volume:" + volumeId
 +											+ " is being used, try it later ");
 +						}
 +						cmd = new UpgradeSnapshotCommand(null,
 +								secondaryStorageURL, dcId, accountId, volumeId,
 +								origTemplateId, origTmpltAccountId, null,
 +								snapshot.getBackupSnapshotId(),
 +								snapshot.getName(), "2.1");
 +						if (!_volsDao.lockInLockTable(volumeId.toString(), 10)) {
 +							throw new CloudRuntimeException(
 +									"Creating template failed due to volume:"
 +											+ volumeId
 +											+ " is being used, try it later ");
 +						}
 +						Answer answer = null;
 +						try {
 +							answer = _storageMgr.sendToPool(pool, cmd);
 +							cmd = null;
 +						} catch (StorageUnavailableException e) {
 +						} finally {
 +							_volsDao.unlockFromLockTable(volumeId.toString());
 +						}
 +						if ((answer != null) && answer.getResult()) {
 +							_snapshotDao.updateSnapshotVersion(volumeId, "2.1",
 +									"2.2");
 +						} else {
 +							throw new CloudRuntimeException(
 +									"Unable to upgrade snapshot");
 +						}
 +					}
 +				}
 +				if (snapshot.getSwiftId() != null && snapshot.getSwiftId() != 0) {
 +					_snapshotMgr.downloadSnapshotsFromSwift(snapshot);
 +				}
- 				cmd = new CreatePrivateTemplateFromSnapshotCommand(
- 						pool.getUuid(), secondaryStorageURL, dcId, accountId,
- 						snapshot.getVolumeId(), backupSnapshotUUID,
- 						snapshot.getName(), origTemplateInstallPath,
- 						templateId, name,
- 						_createprivatetemplatefromsnapshotwait);
++                cmd = new CreatePrivateTemplateFromSnapshotCommand(pool, secondaryStorageURL, dcId, accountId, snapshot.getVolumeId(), backupSnapshotUUID, snapshot.getName(),
++                        origTemplateInstallPath, templateId, name, _createprivatetemplatefromsnapshotwait);
 +			} else if (volumeId != null) {
 +				VolumeVO volume = _volsDao.findById(volumeId);
 +				if (volume == null) {
 +					throw new CloudRuntimeException(
 +							"Unable to find volume for Id " + volumeId);
 +				}
 +				accountId = volume.getAccountId();
 +
 +				if (volume.getPoolId() == null) {
 +					_templateDao.remove(templateId);
 +					throw new CloudRuntimeException("Volume " + volumeId
 +							+ " is empty, can't create template on it");
 +				}
 +				String vmName = _storageMgr.getVmNameOnVolume(volume);
 +				zoneId = volume.getDataCenterId();
 +				secondaryStorageHost = _storageMgr
 +						.getSecondaryStorageHost(zoneId);
 +				if (secondaryStorageHost == null) {
 +					throw new CloudRuntimeException(
 +							"Can not find the secondary storage for zoneId "
 +									+ zoneId);
 +				}
 +				secondaryStorageURL = secondaryStorageHost.getStorageUrl();
 +
 +				pool = _storagePoolDao.findById(volume.getPoolId());
- 				cmd = new CreatePrivateTemplateFromVolumeCommand(
- 						pool.getUuid(), secondaryStorageURL, templateId,
- 						accountId, command.getTemplateName(), uniqueName,
- 						volume.getPath(), vmName,
- 						_createprivatetemplatefromvolumewait);
++                cmd = new CreatePrivateTemplateFromVolumeCommand(pool, secondaryStorageURL, templateId, accountId, command.getTemplateName(), uniqueName, volume.getPath(), vmName, _createprivatetemplatefromvolumewait);
  
 -    private ConfigurationDao _configDao;
 -    private int _createprivatetemplatefromvolumewait;
 -    private int _createprivatetemplatefromsnapshotwait;
 -    @Override
 -    public UserVmVO getVirtualMachine(long vmId) {
 -        return _vmDao.findById(vmId);
 -    }
 +			} else {
 +				throw new CloudRuntimeException(
 +						"Creating private Template need to specify snapshotId or volumeId");
 +			}
 +			// FIXME: before sending the command, check if there's enough
 +			// capacity
 +			// on the storage server to create the template
 +
 +			// This can be sent to a KVM host too.
 +			CreatePrivateTemplateAnswer answer = null;
 +			if (snapshotId != null) {
 +				if (!_snapshotDao.lockInLockTable(snapshotId.toString(), 10)) {
 +					throw new CloudRuntimeException(
 +							"Creating template from snapshot failed due to snapshot:"
 +									+ snapshotId
 +									+ " is being used, try it later ");
 +				}
 +			} else {
 +				if (!_volsDao.lockInLockTable(volumeId.toString(), 10)) {
 +					throw new CloudRuntimeException(
 +							"Creating template from volume failed due to volume:"
 +									+ volumeId
 +									+ " is being used, try it later ");
 +				}
 +			}
 +			try {
 +				answer = (CreatePrivateTemplateAnswer) _storageMgr.sendToPool(
 +						pool, cmd);
 +			} catch (StorageUnavailableException e) {
 +			} finally {
 +				if (snapshotId != null) {
 +					_snapshotDao.unlockFromLockTable(snapshotId.toString());
 +				} else {
 +					_volsDao.unlockFromLockTable(volumeId.toString());
 +				}
 +			}
 +			if ((answer != null) && answer.getResult()) {
 +				privateTemplate = _templateDao.findById(templateId);
 +				String answerUniqueName = answer.getUniqueName();
 +				if (answerUniqueName != null) {
 +					privateTemplate.setUniqueName(answerUniqueName);
 +				} else {
 +					privateTemplate.setUniqueName(uniqueName);
 +				}
 +				ImageFormat format = answer.getImageFormat();
 +				if (format != null) {
 +					privateTemplate.setFormat(format);
 +				} else {
 +					// This never occurs.
 +					// Specify RAW format makes it unusable for snapshots.
 +					privateTemplate.setFormat(ImageFormat.RAW);
 +				}
 +
 +				String checkSum = getChecksum(secondaryStorageHost.getId(),
 +						answer.getPath());
 +
 +				Transaction txn = Transaction.currentTxn();
 +
 +				txn.start();
 +
 +				privateTemplate.setChecksum(checkSum);
 +				_templateDao.update(templateId, privateTemplate);
 +
 +				// add template zone ref for this template
 +				_templateDao.addTemplateToZone(privateTemplate, zoneId);
 +				VMTemplateHostVO templateHostVO = new VMTemplateHostVO(
 +						secondaryStorageHost.getId(), templateId);
 +				templateHostVO.setDownloadPercent(100);
 +				templateHostVO.setDownloadState(Status.DOWNLOADED);
 +				templateHostVO.setInstallPath(answer.getPath());
 +				templateHostVO.setLastUpdated(new Date());
 +				templateHostVO.setSize(answer.getVirtualSize());
 +				templateHostVO.setPhysicalSize(answer.getphysicalSize());
 +				_templateHostDao.persist(templateHostVO);
 +
 +				UsageEventVO usageEvent = new UsageEventVO(
 +						EventTypes.EVENT_TEMPLATE_CREATE,
 +						privateTemplate.getAccountId(),
 +						secondaryStorageHost.getDataCenterId(),
 +						privateTemplate.getId(), privateTemplate.getName(),
 +						null, privateTemplate.getSourceTemplateId(),
 +						templateHostVO.getSize());
 +				_usageEventDao.persist(usageEvent);
 +				txn.commit();
 +			}
 +		} finally {
 +			if (snapshot != null && snapshot.getSwiftId() != null
 +					&& secondaryStorageURL != null && zoneId != null
 +					&& accountId != null && volumeId != null) {
 +				_snapshotMgr.deleteSnapshotsForVolume(secondaryStorageURL,
 +						zoneId, accountId, volumeId);
 +			}
 +			if (privateTemplate == null) {
 +				Transaction txn = Transaction.currentTxn();
 +				txn.start();
 +				// Remove the template record
 +				_templateDao.expunge(templateId);
 +
 +				// decrement resource count
 +				if (accountId != null) {
 +					_resourceLimitMgr.decrementResourceCount(accountId,
 +							ResourceType.template);
 +				}
 +				txn.commit();
 +			}
 +		}
 +
 +		if (privateTemplate != null) {
 +			return privateTemplate;
 +		} else {
 +			throw new CloudRuntimeException("Failed to create a template");
 +		}
 +	}
 +
 +	@Override
 +	public String getChecksum(Long hostId, String templatePath) {
 +		HostVO ssHost = _hostDao.findById(hostId);
 +		Host.Type type = ssHost.getType();
 +		if (type != Host.Type.SecondaryStorage
 +				&& type != Host.Type.LocalSecondaryStorage) {
 +			return null;
 +		}
 +		String secUrl = ssHost.getStorageUrl();
 +		Answer answer;
 +		answer = _agentMgr.sendToSecStorage(ssHost, new ComputeChecksumCommand(
 +				secUrl, templatePath));
 +		if (answer != null && answer.getResult()) {
 +			return answer.getDetails();
 +		}
 +		return null;
 +	}
 +
 +	// used for vm transitioning to error state
 +	private void updateVmStateForFailedVmCreation(Long vmId) {
 +
 +		UserVmVO vm = _vmDao.findById(vmId);
 +
 +		if (vm != null) {
 +			if (vm.getState().equals(State.Stopped)) {
 +				s_logger.debug("Destroying vm " + vm
 +						+ " as it failed to create");
 +				try {
 +					_itMgr.stateTransitTo(vm,
 +							VirtualMachine.Event.OperationFailedToError, null);
 +				} catch (NoTransitionException e1) {
 +					s_logger.warn(e1.getMessage());
 +				}
 +				// destroy associated volumes for vm in error state
 +				// get all volumes in non destroyed state
 +				List<VolumeVO> volumesForThisVm = _volsDao
 +						.findUsableVolumesForInstance(vm.getId());
 +				for (VolumeVO volume : volumesForThisVm) {
 +					try {
 +						if (volume.getState() != Volume.State.Destroy) {
 +							_storageMgr.destroyVolume(volume);
 +						}
 +					} catch (ConcurrentOperationException e) {
 +						s_logger.warn("Unable to delete volume:"
 +								+ volume.getId() + " for vm:" + vmId
 +								+ " whilst transitioning to error state");
 +					}
 +				}
 +				String msg = "Failed to deploy Vm with Id: " + vmId;
 +				_alertMgr.sendAlert(AlertManager.ALERT_TYPE_USERVM,
 +						vm.getDataCenterIdToDeployIn(),
 +						vm.getPodIdToDeployIn(), msg, msg);
 +
 +				_resourceLimitMgr.decrementResourceCount(vm.getAccountId(),
 +						ResourceType.user_vm);
 +			}
 +		}
 +	}
 +
 +	protected class ExpungeTask implements Runnable {
 +		public ExpungeTask() {
 +		}
 +
 +		@Override
 +		public void run() {
 +			GlobalLock scanLock = GlobalLock.getInternLock("UserVMExpunge");
 +			try {
 +				if (scanLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION)) {
 +					try {
 +						List<UserVmVO> vms = _vmDao.findDestroyedVms(new Date(
 +								System.currentTimeMillis()
 +										- ((long) _expungeDelay << 10)));
 +						if (s_logger.isInfoEnabled()) {
 +							if (vms.size() == 0) {
 +								s_logger.trace("Found " + vms.size()
 +										+ " vms to expunge.");
 +							} else {
 +								s_logger.info("Found " + vms.size()
 +										+ " vms to expunge.");
 +							}
 +						}
 +						for (UserVmVO vm : vms) {
 +							try {
 +								expunge(vm,
 +										_accountMgr.getSystemUser().getId(),
 +										_accountMgr.getSystemAccount());
 +							} catch (Exception e) {
 +								s_logger.warn("Unable to expunge " + vm, e);
 +							}
 +						}
 +					} catch (Exception e) {
 +						s_logger.error("Caught the following Exception", e);
 +					} finally {
 +						scanLock.unlock();
 +					}
 +				}
 +			} finally {
 +				scanLock.releaseRef();
 +			}
 +		}
 +	}
 +
 +	private static boolean isAdmin(short accountType) {
 +		return ((accountType == Account.ACCOUNT_TYPE_ADMIN)
 +				|| (accountType == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN)
 +				|| (accountType == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) || (accountType == Account.ACCOUNT_TYPE_READ_ONLY_ADMIN));
 +	}
 +
 +	@Override
 +	@ActionEvent(eventType = EventTypes.EVENT_VM_UPDATE, eventDescription = "updating Vm")
- 	public UserVm updateVirtualMachine(UpdateVMCmd cmd) {
++    public UserVm updateVirtualMachine(UpdateVMCmd cmd)
++            throws ResourceUnavailableException, InsufficientCapacityException {
 +		String displayName = cmd.getDisplayName();
 +		String group = cmd.getGroup();
 +		Boolean ha = cmd.getHaEnable();
 +		Long id = cmd.getId();
 +		Long osTypeId = cmd.getOsTypeId();
 +		String userData = cmd.getUserData();
 +
 +		// Input validation
 +		UserVmVO vmInstance = null;
 +
 +		// Verify input parameters
 +		vmInstance = _vmDao.findById(id.longValue());
 +
 +		if (vmInstance == null) {
 +			throw new InvalidParameterValueException(
 +					"unable to find virtual machine with id " + id);
 +		}
 +
 +		ServiceOffering offering = _serviceOfferingDao.findById(vmInstance
 +				.getServiceOfferingId());
 +		if (!offering.getOfferHA() && ha != null && ha) {
 +			throw new InvalidParameterValueException(
 +					"Can't enable ha for the vm as it's created from the Service offering having HA disabled");
 +		}
 +
 +		_accountMgr.checkAccess(UserContext.current().getCaller(), null, true,
 +				vmInstance);
 +
 +		if (displayName == null) {
 +			displayName = vmInstance.getDisplayName();
 +		}
 +
 +		if (ha == null) {
 +			ha = vmInstance.isHaEnabled();
 +		}
 +
 +		UserVmVO vm = _vmDao.findById(id);
 +		if (vm == null) {
 +			throw new CloudRuntimeException(
 +					"Unable to find virual machine with id " + id);
 +		}
 +
 +		if (vm.getState() == State.Error || vm.getState() == State.Expunging) {
 +			s_logger.error("vm is not in the right state: " + id);
 +			throw new InvalidParameterValueException("Vm with id " + id
 +					+ " is not in the right state");
 +		}
  
 -    @Override
 -    public List<? extends UserVm> getVirtualMachines(long hostId) {
 -        return _vmDao.listByHostId(hostId);
 -    }
++        boolean updateUserdata = false;
 +		if (userData != null) {
++            // check and replace newlines
++            userData = userData.replace("\\n", "");
 +			validateUserData(userData);
 +			// update userData on domain router.
++            updateUserdata = true;
 +		} else {
 +			userData = vmInstance.getUserData();
 +		}
 +
 +		String description = "";
 +
 +		if (displayName != vmInstance.getDisplayName()) {
 +			description += "New display name: " + displayName + ". ";
 +		}
 +
 +		if (ha != vmInstance.isHaEnabled()) {
 +			if (ha) {
 +				description += "Enabled HA. ";
 +			} else {
 +				description += "Disabled HA. ";
 +			}
 +		}
 +		if (osTypeId == null) {
 +			osTypeId = vmInstance.getGuestOSId();
 +		} else {
 +			description += "Changed Guest OS Type to " + osTypeId + ". ";
 +		}
 +
 +		if (group != null) {
 +			if (addInstanceToGroup(id, group)) {
 +				description += "Added to group: " + group + ".";
 +			}
 +		}
 +
 +		_vmDao.updateVM(id, displayName, ha, osTypeId, userData);
  
 -    @Override
 -    @ActionEvent(eventType = EventTypes.EVENT_VM_RESETPASSWORD, eventDescription = "resetting Vm password", async = true)
 -    public UserVm resetVMPassword(ResetVMPasswordCmd cmd, String password) throws ResourceUnavailableException, InsufficientCapacityException {
 -        Account caller = UserContext.current().getCaller();
 -        Long vmId = cmd.getId();
 -        UserVmVO userVm = _vmDao.findById(cmd.getId());
 -        _vmDao.loadDetails(userVm);
 -
 -        // Do parameters input validation
 -        if (userVm == null) {
 -            throw new InvalidParameterValueException("unable to find a virtual machine with id " + cmd.getId());
++        if (updateUserdata) {
++            boolean result = updateUserDataInternal(_vmDao.findById(id));
++            if (result) {
++                s_logger.debug("User data successfully updated for vm id="+id);
++            } else {
++                throw new CloudRuntimeException("Failed to reset userdata for the virtual machine ");
++            }
+         }
+ 
 -        VMTemplateVO template = _templateDao.findByIdIncludingRemoved(userVm.getTemplateId());
 -        if (template == null || !template.getEnablePassword()) {
 -            throw new InvalidParameterValueException("Fail to reset password for the virtual machine, the template is not password enabled");
 -        }
 +		return _vmDao.findById(id);
 +	}
  
 -        if (userVm.getState() == State.Error || userVm.getState() == State.Expunging) {
 -            s_logger.error("vm is not in the right state: " + vmId);
 -            throw new InvalidParameterValueException("Vm with id " + vmId + " is not in the right state");
++    private boolean updateUserDataInternal(UserVm vm)
++            throws ResourceUnavailableException, InsufficientCapacityException {
++        VMTemplateVO template = _templateDao.findByIdIncludingRemoved(vm.getTemplateId());
++        Nic defaultNic = _networkMgr.getDefaultNic(vm.getId());
++        if (defaultNic == null) {
++            s_logger.error("Unable to update userdata for vm id=" + vm.getId() + " as the instance doesn't have default nic");
++            return false;
+         }
+ 
 -        _accountMgr.checkAccess(caller, null, true, userVm);
 -
 -        boolean result = resetVMPasswordInternal(cmd, password);
++        Network defaultNetwork = _networkDao.findById(defaultNic.getNetworkId());
++        NicProfile defaultNicProfile = new NicProfile(defaultNic, defaultNetwork, null, null, null,
++                _networkMgr.isSecurityGroupSupportedInNetwork(defaultNetwork),
++                _networkMgr.getNetworkTag(template.getHypervisorType(), defaultNetwork));
+ 
 -        if (result) {
 -            userVm.setPassword(password);
 -            //update the password in vm_details table too
 -            // Check if an SSH key pair was selected for the instance and if so use it to encrypt & save the vm password
 -            String sshPublicKey = userVm.getDetail("SSH.PublicKey");
 -            if (sshPublicKey != null && !sshPublicKey.equals("") && password != null && !password.equals("saved_password")) {
 -                String encryptedPasswd = RSAHelper.encryptWithSSHPublicKey(sshPublicKey, password);
 -                if (encryptedPasswd == null) {
 -                    throw new CloudRuntimeException("Error encrypting password");
 -                }
++        VirtualMachineProfile<VMInstanceVO> vmProfile = new VirtualMachineProfileImpl<VMInstanceVO>((VMInstanceVO)vm);
+ 
 -                userVm.setDetail("Encrypted.Password", encryptedPasswd);
 -                _vmDao.saveDetails(userVm);
 -            }
 -        } else {
 -            throw new CloudRuntimeException("Failed to reset password for the virtual machine ");
++        UserDataServiceProvider element = _networkMgr.getUserDataUpdateProvider(defaultNetwork);
++        if (element == null) {
++            throw new CloudRuntimeException("Can't find network element for " + Service.UserData.getName() + " provider needed for UserData update");
+         }
++        boolean result = element.saveUserData(defaultNetwork, defaultNicProfile, vmProfile);
+ 
 -        return userVm;
++        return true;
+     }
+ 
 -    private boolean resetVMPasswordInternal(ResetVMPasswordCmd cmd, String password) throws ResourceUnavailableException, InsufficientCapacityException {
 -        Long vmId = cmd.getId();
 -        Long userId = UserContext.current().getCallerUserId();
 -        VMInstanceVO vmInstance = _vmDao.findById(vmId);
 -
 -        if (password == null || password.equals("")) {
 -            return false;
 -        }
 -
 -        VMTemplateVO template = _templateDao.findByIdIncludingRemoved(vmInstance.getTemplateId());
 -        if (template.getEnablePassword()) {
 -            Nic defaultNic = _networkMgr.getDefaultNic(vmId);
 -            if (defaultNic == null) {
 -                s_logger.error("Unable to reset password for vm " + vmInstance + " as the instance doesn't have default nic");
 -                return false;
 -            }
 +	@Override
 +	@ActionEvent(eventType = EventTypes.EVENT_VM_START, eventDescription = "starting Vm", async = true)
 +	public UserVm startVirtualMachine(StartVMCmd cmd)
 +			throws ExecutionException, ConcurrentOperationException,
 +			ResourceUnavailableException, InsufficientCapacityException {
 +		return startVirtualMachine(cmd.getId(), cmd.getHostId(), null).first();
 +	}
 +
 +	@Override
 +	@ActionEvent(eventType = EventTypes.EVENT_VM_REBOOT, eventDescription = "rebooting Vm", async = true)
 +	public UserVm rebootVirtualMachine(RebootVMCmd cmd)
 +			throws InsufficientCapacityException, ResourceUnavailableException {
 +		Account caller = UserContext.current().getCaller();
 +		Long vmId = cmd.getId();
 +
 +		// Verify input parameters
 +		UserVmVO vmInstance = _vmDao.findById(vmId.longValue());
 +		if (vmInstance == null) {
 +			throw new InvalidParameterValueException(
 +					"unable to find a virtual machine with id " + vmId);
 +		}
 +
 +		_accountMgr.checkAccess(caller, null, true, vmInstance);
 +
 +		return rebootVirtualMachine(UserContext.current().getCallerUserId(),
 +				vmId);
 +	}
 +
 +	@Override
 +	@ActionEvent(eventType = EventTypes.EVENT_VM_DESTROY, eventDescription = "destroying Vm", async = true)
 +	public UserVm destroyVm(DestroyVMCmd cmd)
 +			throws ResourceUnavailableException, ConcurrentOperationException {
 +		return destroyVm(cmd.getId());
 +	}
 +
 +	@Override
 +	@DB
 +	public InstanceGroupVO createVmGroup(CreateVMGroupCmd cmd) {
 +		Account caller = UserContext.current().getCaller();
 +		Long domainId = cmd.getDomainId();
 +		String accountName = cmd.getAccountName();
 +		String groupName = cmd.getGroupName();
 +		Long projectId = cmd.getProjectId();
 +
 +		Account owner = _accountMgr.finalizeOwner(caller, accountName,
 +				domainId, projectId);
 +		long accountId = owner.getId();
 +
 +		// Check if name is already in use by this account
 +		boolean isNameInUse = _vmGroupDao.isNameInUse(accountId, groupName);
 +
 +		if (isNameInUse) {
 +			throw new InvalidParameterValueException(
 +					"Unable to create vm group, a group with name " + groupName
 +							+ " already exisits for account " + accountId);
 +		}
 +
 +		return createVmGroup(groupName, accountId);
 +	}
 +
 +	@DB
 +	protected InstanceGroupVO createVmGroup(String groupName, long accountId) {
 +		Account account = null;
 +		final Transaction txn = Transaction.currentTxn();
 +		txn.start();
 +		try {
 +			account = _accountDao.acquireInLockTable(accountId); // to ensure
 +																	// duplicate
 +																	// vm group
 +																	// names are
 +																	// not
 +																	// created.
 +			if (account == null) {
 +				s_logger.warn("Failed to acquire lock on account");
 +				return null;
 +			}
 +			InstanceGroupVO group = _vmGroupDao.findByAccountAndName(accountId,
 +					groupName);
 +			if (group == null) {
 +				group = new InstanceGroupVO(groupName, accountId);
 +				group = _vmGroupDao.persist(group);
 +			}
 +			return group;
 +		} finally {
 +			if (account != null) {
 +				_accountDao.releaseFromLockTable(accountId);
 +			}
 +			txn.commit();
 +		}
 +	}
 +
 +	@Override
 +	public boolean deleteVmGroup(DeleteVMGroupCmd cmd) {
 +		Account caller = UserContext.current().getCaller();
 +		Long groupId = cmd.getId();
 +
 +		// Verify input parameters
 +		InstanceGroupVO group = _vmGroupDao.findById(groupId);
 +		if ((group == null) || (group.getRemoved() != null)) {
 +			throw new InvalidParameterValueException(
 +					"unable to find a vm group with id " + groupId);
 +		}
 +
 +		_accountMgr.checkAccess(caller, null, true, group);
 +
 +		return deleteVmGroup(groupId);
 +	}
 +
 +	@Override
 +	public boolean deleteVmGroup(long groupId) {
 +		// delete all the mappings from group_vm_map table
 +		List<InstanceGroupVMMapVO> groupVmMaps = _groupVMMapDao
 +				.listByGroupId(groupId);
 +		for (InstanceGroupVMMapVO groupMap : groupVmMaps) {
 +			SearchCriteria<InstanceGroupVMMapVO> sc = _groupVMMapDao
 +					.createSearchCriteria();
 +			sc.addAnd("instanceId", SearchCriteria.Op.EQ,
 +					groupMap.getInstanceId());
 +			_groupVMMapDao.expunge(sc);
 +		}
 +
 +		if (_vmGroupDao.remove(groupId)) {
 +			return true;
 +		} else {
 +			return false;
 +		}
 +	}
 +
 +	@Override
 +	@DB
 +	public boolean addInstanceToGroup(long userVmId, String groupName) {
 +		UserVmVO vm = _vmDao.findById(userVmId);
 +
 +		InstanceGroupVO group = _vmGroupDao.findByAccountAndName(
 +				vm.getAccountId(), groupName);
 +		// Create vm group if the group doesn't exist for this account
 +		if (group == null) {
 +			group = createVmGroup(groupName, vm.getAccountId());
 +		}
 +
 +		if (group != null) {
 +			final Transaction txn = Transaction.currentTxn();
 +			txn.start();
 +			UserVm userVm = _vmDao.acquireInLockTable(userVmId);
 +			if (userVm == null) {
 +				s_logger.warn("Failed to acquire lock on user vm id="
 +						+ userVmId);
 +			}
 +			try {
 +				// don't let the group be deleted when we are assigning vm to
 +				// it.
 +				InstanceGroupVO ngrpLock = _vmGroupDao.lockRow(group.getId(),
 +						false);
 +				if (ngrpLock == null) {
 +					s_logger.warn("Failed to acquire lock on vm group id="
 +							+ group.getId() + " name=" + group.getName());
 +					txn.rollback();
 +					return false;
 +				}
 +
 +				// Currently don't allow to assign a vm to more than one group
 +				if (_groupVMMapDao.listByInstanceId(userVmId) != null) {
 +					// Delete all mappings from group_vm_map table
 +					List<InstanceGroupVMMapVO> groupVmMaps = _groupVMMapDao
 +							.listByInstanceId(userVmId);
 +					for (InstanceGroupVMMapVO groupMap : groupVmMaps) {
 +						SearchCriteria<InstanceGroupVMMapVO> sc = _groupVMMapDao
 +								.createSearchCriteria();
 +						sc.addAnd("instanceId", SearchCriteria.Op.EQ,
 +								groupMap.getInstanceId());
 +						_groupVMMapDao.expunge(sc);
 +					}
 +				}
 +				InstanceGroupVMMapVO groupVmMapVO = new InstanceGroupVMMapVO(
 +						group.getId(), userVmId);
 +				_groupVMMapDao.persist(groupVmMapVO);
 +
 +				txn.commit();
 +				return true;
 +			} finally {
 +				if (userVm != null) {
 +					_vmDao.releaseFromLockTable(userVmId);
 +				}
 +			}
 +		}
 +		return false;
 +	}
 +
 +	@Override
 +	public InstanceGroupVO getGroupForVm(long vmId) {
 +		// TODO - in future releases vm can be assigned to multiple groups; but
 +		// currently return just one group per vm
 +		try {
 +			List<InstanceGroupVMMapVO> groupsToVmMap = _groupVMMapDao
 +					.listByInstanceId(vmId);
 +
 +			if (groupsToVmMap != null && groupsToVmMap.size() != 0) {
 +				InstanceGroupVO group = _vmGroupDao.findById(groupsToVmMap.get(
 +						0).getGroupId());
 +				return group;
 +			} else {
 +				return null;
 +			}
 +		} catch (Exception e) {
 +			s_logger.warn("Error trying to get group for a vm: ", e);
 +			return null;
 +		}
 +	}
 +
 +	@Override
 +	public void removeInstanceFromInstanceGroup(long vmId) {
 +		try {
 +			List<InstanceGroupVMMapVO> groupVmMaps = _groupVMMapDao
 +					.listByInstanceId(vmId);
 +			for (InstanceGroupVMMapVO groupMap : groupVmMaps) {
 +				SearchCriteria<InstanceGroupVMMapVO> sc = _groupVMMapDao
 +						.createSearchCriteria();
 +				sc.addAnd("instanceId", SearchCriteria.Op.EQ,
 +						groupMap.getInstanceId());
 +				_groupVMMapDao.expunge(sc);
 +			}
 +		} catch (Exception e) {
 +			s_logger.warn("Error trying to remove vm from group: ", e);
 +		}
 +	}
 +
 +	protected boolean validPassword(String password) {
 +		if (password == null || password.length() == 0) {
 +			return false;
 +		}
 +		for (int i = 0; i < password.length(); i++) {
 +			if (password.charAt(i) == ' ') {
 +				return false;
 +			}
 +		}
 +		return true;
 +	}
 +
 +	@Override
 +	public UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone,
 +			ServiceOffering serviceOffering, VirtualMachineTemplate template,
 +			List<Long> securityGroupIdList, Account owner, String hostName,
 +			String displayName, Long diskOfferingId, Long diskSize,
 +			String group, HypervisorType hypervisor, String userData,
 +			String sshKeyPair, Map<Long, String> requestedIps,
 +			String defaultIp, String keyboard)
 +			throws InsufficientCapacityException, ConcurrentOperationException,
 +			ResourceUnavailableException, StorageUnavailableException,
 +			ResourceAllocationException {
 +
 +		Account caller = UserContext.current().getCaller();
 +		List<NetworkVO> networkList = new ArrayList<NetworkVO>();
 +
 +		// Verify that caller can perform actions in behalf of vm owner
 +		_accountMgr.checkAccess(caller, null, true, owner);
 +
 +		//

<TRUNCATED>
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/30f2565d/server/src/com/cloud/vm/VirtualMachineManagerImpl.java
----------------------------------------------------------------------