diff --git a/api/src/com/cloud/api/commands/MoveUserVMCmd.java b/api/src/com/cloud/api/commands/MoveUserVMCmd.java new file mode 100644 index 00000000000..0ef59bd417d --- /dev/null +++ b/api/src/com/cloud/api/commands/MoveUserVMCmd.java @@ -0,0 +1,109 @@ +/** + * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. + * + * This software is licensed under the GNU General Public License v3 or later. + * + * It is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.cloud.api.commands; + + +import org.apache.log4j.Logger; + +import com.cloud.api.ApiConstants; +import com.cloud.api.BaseAsyncCmd; +import com.cloud.api.BaseCmd; +import com.cloud.api.Implementation; +import com.cloud.api.Parameter; +import com.cloud.api.ServerApiException; +import com.cloud.api.response.UserVmResponse; +import com.cloud.api.response.ZoneResponse; +import com.cloud.async.AsyncJob; +import com.cloud.event.EventTypes; +import com.cloud.user.Account; +import com.cloud.uservm.UserVm; + +@Implementation(description="Move a user VM to another user under same domain.", responseObject=UserVmResponse.class) +public class MoveUserVMCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(MoveUserVMCmd.class.getName()); + + private static final String s_name = "moveuservmresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.HOST_ID, type=CommandType.LONG, description="the host ID of the system VM to be moved") + private Long hostId; + + @Parameter(name=ApiConstants.ACCOUNT_ID, type=CommandType.LONG, description="the accopunt id of the new owner account") + private Long accountId; + + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getHostId() { + return hostId; + } + + public Long getAccountId() { + return accountId; + } + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public void execute(){ + try { + UserVm userVm = _userVmService.moveVMToUser(this); + if (userVm == null){ + throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Failed to move vm"); + } + UserVmResponse response = _responseGenerator.createUserVmResponse("virtualmachine", userVm).get(0); + response.setResponseName(DeployVMCmd.getResultObjectName()); + this.setResponseObject(response); + }catch (Exception e){ + e.printStackTrace(); + throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Failed to move vm " + e.getMessage()); + } + + } + + @Override + public long getEntityOwnerId() { + UserVm vm = _responseGenerator.findUserVmById(getHostId()); + if (vm != null) { + return vm.getAccountId(); + } + + return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked + } + + @Override + public String getEventDescription() { + return "moving user vm: " + getHostId(); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_VM_MOVE; + } +} diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index 096c56c6601..3b6bb30c4a6 100755 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -28,8 +28,9 @@ public class EventTypes { public static final String EVENT_VM_UPDATE = "VM.UPDATE"; public static final String EVENT_VM_UPGRADE = "VM.UPGRADE"; public static final String EVENT_VM_RESETPASSWORD = "VM.RESETPASSWORD"; - public static final String EVENT_VM_MIGRATE = "VM.MIGRATE"; - + public static final String EVENT_VM_MIGRATE = "VM.MIGRATE"; + public static final String EVENT_VM_MOVE = "VM.MOVE"; + // Domain Router public static final String EVENT_ROUTER_CREATE = "ROUTER.CREATE"; public static final String EVENT_ROUTER_DESTROY = "ROUTER.DESTROY"; diff --git a/api/src/com/cloud/uservm/UserVm.java b/api/src/com/cloud/uservm/UserVm.java index 323a989b985..c92bb6391e5 100755 --- a/api/src/com/cloud/uservm/UserVm.java +++ b/api/src/com/cloud/uservm/UserVm.java @@ -36,5 +36,7 @@ public interface UserVm extends VirtualMachine, ControlledEntity { void setUserData(String userData); String getDetail(String name); + + void setAccountId(long accountId); } diff --git a/api/src/com/cloud/vm/UserVmService.java b/api/src/com/cloud/vm/UserVmService.java index 83b783c093e..ad9f5a6e91f 100755 --- a/api/src/com/cloud/vm/UserVmService.java +++ b/api/src/com/cloud/vm/UserVmService.java @@ -29,6 +29,7 @@ import com.cloud.api.commands.DeployVMCmd; import com.cloud.api.commands.DestroyVMCmd; import com.cloud.api.commands.DetachVolumeCmd; import com.cloud.api.commands.ListVMsCmd; +import com.cloud.api.commands.MoveUserVMCmd; import com.cloud.api.commands.RebootVMCmd; import com.cloud.api.commands.RecoverVMCmd; import com.cloud.api.commands.ResetVMPasswordCmd; @@ -369,4 +370,6 @@ public interface UserVmService { * if the VM to be migrated is not in Running state */ UserVm migrateVirtualMachine(UserVm vm, Host destinationHost) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException; + + UserVm moveVMToUser(MoveUserVMCmd moveUserVMCmd) throws ResourceAllocationException, ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException ; } diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index 291d8f13df3..ee84b5352ba 100755 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -47,6 +47,7 @@ recoverVirtualMachine=com.cloud.api.commands.RecoverVMCmd;7 listVirtualMachines=com.cloud.api.commands.ListVMsCmd;15 getVMPassword=com.cloud.api.commands.GetVMPasswordCmd;15 migrateVirtualMachine=com.cloud.api.commands.MigrateVMCmd;1 +moveVirtualMachine=com.cloud.api.commands.MoveUserVMCmd;15 #### snapshot commands createSnapshot=com.cloud.api.commands.CreateSnapshotCmd;15 diff --git a/core/src/com/cloud/vm/UserVmVO.java b/core/src/com/cloud/vm/UserVmVO.java index 329d54eead7..f6d00247b53 100755 --- a/core/src/com/cloud/vm/UserVmVO.java +++ b/core/src/com/cloud/vm/UserVmVO.java @@ -139,5 +139,9 @@ public class UserVmVO extends VMInstanceVO implements UserVm { public void setDetails(Map details) { this.details = details; } + + public void setAccountId(long accountId){ + this.accountId = accountId; + } } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 32325f27740..8bcbeb3d4fa 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -63,6 +63,7 @@ import com.cloud.api.commands.DeployVMCmd; import com.cloud.api.commands.DestroyVMCmd; import com.cloud.api.commands.DetachVolumeCmd; import com.cloud.api.commands.ListVMsCmd; +import com.cloud.api.commands.MoveUserVMCmd; import com.cloud.api.commands.RebootVMCmd; import com.cloud.api.commands.RecoverVMCmd; import com.cloud.api.commands.ResetVMPasswordCmd; @@ -3200,5 +3201,46 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager UserVmVO migratedVm = _itMgr.migrate((UserVmVO) vm, srcHostId, dest); return migratedVm; } + + + @Override + @ActionEvent(eventType = EventTypes.EVENT_VM_MOVE, eventDescription = "move VM to another user", async = false) + public UserVm moveVMToUser(MoveUserVMCmd cmd) throws ResourceAllocationException, ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { + //verify the two users + Account oldOwner = UserContext.current().getCaller(); + Account newOwner = _accountService.getAccount(cmd.getAccountId()); + if (newOwner == null) { + throw new InvalidParameterValueException("Unable to find account " + newOwner + " in domain " + oldOwner.getDomainId()); + } + //get the VM + UserVmVO vm = _vmDao.findById(cmd.getHostId()); + // update the owner + vm.setAccountId(newOwner.getAccountId()); + + DomainVO domain = _domainDao.findById(oldOwner.getDomainId()); + // check that caller can operate with domain + _accountMgr.checkAccess(oldOwner, domain); + // check that vm owner can create vm in the domain + _accountMgr.checkAccess(newOwner, domain); + + // check if account/domain is with in resource limits to create a new vm + if (_accountMgr.resourceLimitExceeded(newOwner, ResourceType.user_vm)) { + ResourceAllocationException rae = new ResourceAllocationException("Maximum number of virtual machines for account: " + newOwner.getAccountName() + " has been exceeded."); + rae.setResourceType("vm"); + throw rae; + } + + this.stopVirtualMachine(cmd.getHostId(), true); + + //update ownership + vm.setAccountId(newOwner.getId()); + + _vmDao.persist(vm); + + this.startVirtualMachine(cmd.getHostId()); + + return vm; + } + }