Bug 11481 - get manual live migration working with all VMs

Changes:
- Added a new API  'migrateSystemVm'  backed by MigrateSystemVMCmd.java to migrate system VMs (SSVM, consoleproxy, domain routers(router, LB, DHCP))
- This is Admin only action
- The existing API 'migratevirtualmachine' is only for user VMs
This commit is contained in:
prachi 2011-09-29 17:46:23 -07:00
parent fbc19041ab
commit 9bd5e5871b
11 changed files with 284 additions and 26 deletions

View File

@ -55,6 +55,7 @@ import com.cloud.api.response.ServiceOfferingResponse;
import com.cloud.api.response.SnapshotPolicyResponse;
import com.cloud.api.response.SnapshotResponse;
import com.cloud.api.response.StoragePoolResponse;
import com.cloud.api.response.SystemVmInstanceResponse;
import com.cloud.api.response.SystemVmResponse;
import com.cloud.api.response.TemplatePermissionsResponse;
import com.cloud.api.response.TemplateResponse;
@ -230,4 +231,6 @@ public interface ResponseGenerator {
ProjectInvitationResponse createProjectInvitationResponse(ProjectInvitation invite);
SystemVmInstanceResponse createSystemVmInstanceResponse(VirtualMachine systemVM);
}

View File

@ -30,9 +30,7 @@ import com.cloud.api.Parameter;
import com.cloud.api.response.HostResponse;
import com.cloud.api.response.ListResponse;
import com.cloud.async.AsyncJob;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.host.Host;
import com.cloud.uservm.UserVm;
import com.cloud.utils.Pair;
@Implementation(description="Lists hosts.", responseObject=HostResponse.class)
@ -130,11 +128,7 @@ public class ListHostsCmd extends BaseListCmd {
List<? extends Host> hostsWithCapacity = new ArrayList<Host>();
if(getVirtualMachineId() != null){
UserVm userVm = _userVmService.getUserVm(getVirtualMachineId());
if (userVm == null) {
throw new InvalidParameterValueException("Unable to find the VM by id=" + getVirtualMachineId());
}
Pair<List<? extends Host>, List<? extends Host>> hostsForMigration = _mgr.listHostsForMigrationOfVM(userVm, this.getStartIndex(), this.getPageSizeVal());
Pair<List<? extends Host>, List<? extends Host>> hostsForMigration = _mgr.listHostsForMigrationOfVM(getVirtualMachineId(), this.getStartIndex(), this.getPageSizeVal());
result = hostsForMigration.first();
hostsWithCapacity = hostsForMigration.second();
}else{

View File

@ -0,0 +1,132 @@
/**
* Copyright (C) 2011 Citrix Systems, 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 <http://www.gnu.org/licenses/>.
*
*/
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.SystemVmInstanceResponse;
import com.cloud.event.EventTypes;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.ManagementServerException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.exception.VirtualMachineMigrationException;
import com.cloud.host.Host;
import com.cloud.user.Account;
import com.cloud.user.UserContext;
import com.cloud.vm.VirtualMachine;
@Implementation(description="Attempts Migration of a system virtual machine to the host specified.", responseObject=SystemVmInstanceResponse.class)
public class MigrateSystemVMCmd extends BaseAsyncCmd {
public static final Logger s_logger = Logger.getLogger(MigrateSystemVMCmd.class.getName());
private static final String s_name = "migratesystemvmresponse";
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name=ApiConstants.HOST_ID, type=CommandType.LONG, required=true, description="destination Host ID to migrate VM to")
private Long hostId;
@Parameter(name=ApiConstants.VIRTUAL_MACHINE_ID, type=CommandType.LONG, required=true, description="the ID of the virtual machine")
private Long virtualMachineId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getHostId() {
return hostId;
}
public Long getVirtualMachineId() {
return virtualMachineId;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public String getCommandName() {
return s_name;
}
@Override
public long getEntityOwnerId() {
Account account = UserContext.current().getCaller();
if (account != null) {
return account.getId();
}
return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked
}
@Override
public String getEventType() {
return EventTypes.EVENT_VM_MIGRATE;
}
@Override
public String getEventDescription() {
return "Attempting to migrate VM Id: " + getVirtualMachineId() + " to host Id: "+ getHostId();
}
@Override
public void execute(){
Host destinationHost = _resourceService.getHost(getHostId());
if (destinationHost == null) {
throw new InvalidParameterValueException("Unable to find the host to migrate the VM, host id=" + getHostId());
}
try{
UserContext.current().setEventDetails("VM Id: " + getVirtualMachineId() + " to host Id: "+ getHostId());
//FIXME : Should not be calling UserVmService to migrate all types of VMs - need a generic VM layer
VirtualMachine migratedVm = _userVmService.migrateVirtualMachine(getVirtualMachineId(), destinationHost);
if (migratedVm != null) {
// return the generic system VM instance response
SystemVmInstanceResponse response = _responseGenerator.createSystemVmInstanceResponse(migratedVm);
response.setResponseName(getCommandName());
this.setResponseObject(response);
} else {
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Failed to migrate the system vm");
}
} catch (ResourceUnavailableException ex) {
s_logger.warn("Exception: ", ex);
throw new ServerApiException(BaseCmd.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage());
} catch (ConcurrentOperationException e) {
s_logger.warn("Exception: ", e);
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, e.getMessage());
} catch (ManagementServerException e) {
s_logger.warn("Exception: ", e);
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, e.getMessage());
} catch (VirtualMachineMigrationException e) {
s_logger.warn("Exception: ", e);
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, e.getMessage());
}
}
}

View File

@ -36,8 +36,9 @@ import com.cloud.host.Host;
import com.cloud.user.Account;
import com.cloud.user.UserContext;
import com.cloud.uservm.UserVm;
import com.cloud.vm.VirtualMachine;
@Implementation(description="Attempts Migration of a virtual machine to the host specified.", responseObject=UserVmResponse.class)
@Implementation(description="Attempts Migration of a user virtual machine to the host specified.", responseObject=UserVmResponse.class)
public class MigrateVMCmd extends BaseAsyncCmd {
public static final Logger s_logger = Logger.getLogger(MigrateVMCmd.class.getName());
@ -109,11 +110,11 @@ public class MigrateVMCmd extends BaseAsyncCmd {
}
try{
UserContext.current().setEventDetails("VM Id: " + getVirtualMachineId() + " to host Id: "+ getHostId());
UserVm migratedVm = _userVmService.migrateVirtualMachine(userVm, destinationHost);
VirtualMachine migratedVm = _userVmService.migrateVirtualMachine(getVirtualMachineId(), destinationHost);
if (migratedVm != null) {
UserVmResponse response = _responseGenerator.createUserVmResponse("virtualmachine", migratedVm).get(0);
response.setResponseName(getCommandName());
this.setResponseObject(response);
UserVmResponse response = _responseGenerator.createUserVmResponse("virtualmachine", (UserVm)migratedVm).get(0);
response.setResponseName(getCommandName());
this.setResponseObject(response);
} else {
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Failed to migrate vm");
}

View File

@ -0,0 +1,98 @@
/**
* Copyright (C) 2011 Citrix Systems, 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 <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.api.response;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
/*
* This is the generic response for all types of System VMs (SSVM, consoleproxy, domain routers(router, LB, DHCP))
*/
public class SystemVmInstanceResponse extends BaseResponse {
@SerializedName("id") @Param(description="the ID of the system VM")
private Long id;
@SerializedName("systemvmtype") @Param(description="the system VM type")
private String systemVmType;
@SerializedName("name") @Param(description="the name of the system VM")
private String name;
@SerializedName("hostid") @Param(description="the host ID for the system VM")
private Long hostId;
@SerializedName("state") @Param(description="the state of the system VM")
private String state;
@SerializedName("role") @Param(description="the role of the system VM")
private String role;
public Long getObjectId() {
return getId();
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getSystemVmType() {
return systemVmType;
}
public void setSystemVmType(String systemVmType) {
this.systemVmType = systemVmType;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getHostId() {
return hostId;
}
public void setHostId(Long hostId) {
this.hostId = hostId;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
}

View File

@ -100,7 +100,6 @@ import com.cloud.template.VirtualMachineTemplate;
import com.cloud.user.Account;
import com.cloud.user.SSHKeyPair;
import com.cloud.user.UserAccount;
import com.cloud.uservm.UserVm;
import com.cloud.utils.Pair;
import com.cloud.vm.InstanceGroup;
import com.cloud.vm.VirtualMachine;
@ -479,11 +478,11 @@ public interface ManagementService {
* List hosts for migrating the given VM. The API returns list of all hosts in the VM's cluster minus the current host and
* also a list of hosts that seem to have enough CPU and RAM capacity to host this VM.
*
* @param UserVm
* vm The VM to migrate
* @param Long vmId
* Id of The VM to migrate
* @return Pair<List<? extends Host>, List<? extends Host>> List of all Hosts in VM's cluster and list of Hosts with enough capacity
*/
Pair<List<? extends Host>, List<? extends Host>> listHostsForMigrationOfVM(UserVm vm, Long startIndex, Long pageSize);
Pair<List<? extends Host>, List<? extends Host>> listHostsForMigrationOfVM(Long vmId, Long startIndex, Long pageSize);
String[] listEventTypes();

View File

@ -359,11 +359,11 @@ public interface UserVmService {
* Migrate the given VM to the destination host provided. The API returns the migrated VM if migration succeeds. Only Root
* Admin can migrate a VM.
*
* @param UserVm
* vm The VM to migrate
* @param Long vmId
* vmId of The VM to migrate
* @param Host
* destinationHost to migrate the VM
* @return UserVm migrated VM
* @return VirtualMachine migrated VM
* @throws ManagementServerException
* in case we get error finding the VM or host or access errors or other internal errors.
* @throws ConcurrentOperationException
@ -373,7 +373,7 @@ public interface UserVmService {
* @throws VirtualMachineMigrationException
* if the VM to be migrated is not in Running state
*/
UserVm migrateVirtualMachine(UserVm vm, Host destinationHost) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException;
VirtualMachine migrateVirtualMachine(Long vmId, Host destinationHost) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException;
UserVm moveVMToUser(MoveUserVMCmd moveUserVMCmd) throws ResourceAllocationException, ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException ;
}

View File

@ -145,6 +145,7 @@ rebootSystemVm=com.cloud.api.commands.RebootSystemVmCmd;1
stopSystemVm=com.cloud.api.commands.StopSystemVmCmd;1
destroySystemVm=com.cloud.api.commands.DestroySystemVmCmd;1
listSystemVms=com.cloud.api.commands.ListSystemVMsCmd;3
migrateSystemVm=com.cloud.api.commands.MigrateSystemVMCmd;1
#### configuration commands
updateConfiguration=com.cloud.api.commands.UpdateCfgCmd;1

View File

@ -76,6 +76,7 @@ import com.cloud.api.response.ServiceResponse;
import com.cloud.api.response.SnapshotPolicyResponse;
import com.cloud.api.response.SnapshotResponse;
import com.cloud.api.response.StoragePoolResponse;
import com.cloud.api.response.SystemVmInstanceResponse;
import com.cloud.api.response.SystemVmResponse;
import com.cloud.api.response.TemplatePermissionsResponse;
import com.cloud.api.response.TemplateResponse;
@ -2539,4 +2540,24 @@ public class ApiResponseHelper implements ResponseGenerator {
return response;
}
@Override
public SystemVmInstanceResponse createSystemVmInstanceResponse(VirtualMachine vm){
SystemVmInstanceResponse vmResponse = new SystemVmInstanceResponse();
vmResponse.setId(vm.getId());
vmResponse.setSystemVmType(vm.getType().toString().toLowerCase());
vmResponse.setName(vm.getHostName());
if (vm.getHostId() != null) {
vmResponse.setHostId(vm.getHostId());
}
if (vm.getState() != null) {
vmResponse.setState(vm.getState().toString());
}
if (vm.getType() == Type.DomainRouter) {
VirtualRouter router = (VirtualRouter)vm;
if(router.getRole() != null){
vmResponse.setRole(router.getRole().toString());
}
}
return vmResponse;
}
}

View File

@ -212,7 +212,6 @@ import com.cloud.user.dao.AccountDao;
import com.cloud.user.dao.SSHKeyPairDao;
import com.cloud.user.dao.UserAccountDao;
import com.cloud.user.dao.UserDao;
import com.cloud.uservm.UserVm;
import com.cloud.utils.EnumUtils;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.Pair;
@ -950,7 +949,7 @@ public class ManagementServerImpl implements ManagementServer {
}
@Override
public Pair<List<? extends Host>, List<? extends Host>> listHostsForMigrationOfVM(UserVm vm, Long startIndex, Long pageSize) {
public Pair<List<? extends Host>, List<? extends Host>> listHostsForMigrationOfVM(Long vmId, Long startIndex, Long pageSize) {
// access check - only root admin can migrate VM
Account caller = UserContext.current().getCaller();
if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN) {
@ -959,6 +958,11 @@ public class ManagementServerImpl implements ManagementServer {
}
throw new PermissionDeniedException("No permission to migrate VM, Only Root Admin can migrate a VM!");
}
VMInstanceVO vm = _vmInstanceDao.findById(vmId);
if (vm == null) {
throw new InvalidParameterValueException("Unable to find the VM by id=" + vmId);
}
// business logic
if (vm.getState() != State.Running) {
if (s_logger.isDebugEnabled()) {
@ -1009,8 +1013,8 @@ public class ManagementServerImpl implements ManagementServer {
List<Host> suitableHosts = new ArrayList<Host>();
Enumeration<HostAllocator> enHost = _hostAllocators.enumeration();
UserVmVO vmVO = (UserVmVO)vm;
VirtualMachineProfile<VMInstanceVO> vmProfile = new VirtualMachineProfileImpl<VMInstanceVO>(vmVO);
VirtualMachineProfile<VMInstanceVO> vmProfile = new VirtualMachineProfileImpl<VMInstanceVO>(vm);
DataCenterDeployment plan = new DataCenterDeployment(srcHost.getDataCenterId(), srcHost.getPodId(), srcHost.getClusterId(), null, null);
ExcludeList excludes = new ExcludeList();

View File

@ -3187,7 +3187,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
@Override
@ActionEvent(eventType = EventTypes.EVENT_VM_MIGRATE, eventDescription = "migrating VM", async = true)
public UserVm migrateVirtualMachine(UserVm vm, Host destinationHost) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException {
public VirtualMachine migrateVirtualMachine(Long vmId, Host destinationHost) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException {
// access check - only root admin can migrate VM
Account caller = UserContext.current().getCaller();
if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN) {
@ -3196,6 +3196,11 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
}
throw new PermissionDeniedException("No permission to migrate VM, Only Root Admin can migrate a VM!");
}
VMInstanceVO vm = _vmInstanceDao.findById(vmId);
if (vm == null) {
throw new InvalidParameterValueException("Unable to find the VM by id=" + vmId);
}
// business logic
if (vm.getState() != State.Running) {
if (s_logger.isDebugEnabled()) {
@ -3237,7 +3242,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
throw new VirtualMachineMigrationException("Destination host, hostId: "+ destinationHost.getId() +" already has max Running VMs(count includes system VMs), limit is: " + maxGuestLimit + " , cannot migrate to this host");
}
UserVmVO migratedVm = _itMgr.migrate((UserVmVO) vm, srcHostId, dest);
VMInstanceVO migratedVm = _itMgr.migrate(vm, srcHostId, dest);
return migratedVm;
}