Skip to content

Commit 37e570f

Browse files
committed
server: Optional destination host when migrate a vm
1 parent 0f3f2a0 commit 37e570f

4 files changed

Lines changed: 94 additions & 24 deletions

File tree

api/src/main/java/org/apache/cloudstack/api/command/admin/vm/MigrateVMCmd.java

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public class MigrateVMCmd extends BaseAsyncCmd {
6060
type = CommandType.UUID,
6161
entityType = HostResponse.class,
6262
required = false,
63-
description = "Destination Host ID to migrate VM to. Required for live migrating a VM from host to host")
63+
description = "Destination Host ID to migrate VM to.")
6464
private Long hostId;
6565

6666
@Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID,
@@ -132,10 +132,6 @@ public String getEventDescription() {
132132

133133
@Override
134134
public void execute() {
135-
if (getHostId() == null && getStoragePoolId() == null) {
136-
throw new InvalidParameterValueException("Either hostId or storageId must be specified");
137-
}
138-
139135
if (getHostId() != null && getStoragePoolId() != null) {
140136
throw new InvalidParameterValueException("Only one of hostId and storageId can be specified");
141137
}
@@ -169,9 +165,9 @@ public void execute() {
169165

170166
try {
171167
VirtualMachine migratedVm = null;
172-
if (getHostId() != null) {
168+
if (getStoragePoolId() == null) {
173169
migratedVm = _userVmService.migrateVirtualMachine(getVirtualMachineId(), destinationHost);
174-
} else if (getStoragePoolId() != null) {
170+
} else {
175171
migratedVm = _userVmService.vmStorageMigration(getVirtualMachineId(), destStoragePool);
176172
}
177173
if (migratedVm != null) {

server/src/main/java/com/cloud/vm/UserVmManagerImpl.java

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -176,11 +176,13 @@
176176
import com.cloud.event.UsageEventUtils;
177177
import com.cloud.event.UsageEventVO;
178178
import com.cloud.event.dao.UsageEventDao;
179+
import com.cloud.exception.AffinityConflictException;
179180
import com.cloud.exception.AgentUnavailableException;
180181
import com.cloud.exception.CloudException;
181182
import com.cloud.exception.ConcurrentOperationException;
182183
import com.cloud.exception.InsufficientAddressCapacityException;
183184
import com.cloud.exception.InsufficientCapacityException;
185+
import com.cloud.exception.InsufficientServerCapacityException;
184186
import com.cloud.exception.InvalidParameterValueException;
185187
import com.cloud.exception.ManagementServerException;
186188
import com.cloud.exception.OperationTimedoutException;
@@ -5627,6 +5629,50 @@ public VirtualMachine migrateVirtualMachine(Long vmId, Host destinationHost) thr
56275629

56285630
// check if migrating to same host
56295631
long srcHostId = vm.getHostId();
5632+
5633+
DeployDestination dest = null;
5634+
if (destinationHost == null) {
5635+
vm.setLastHostId(null); // Do not check last host
5636+
final VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm);
5637+
final Host host = _hostDao.findById(srcHostId);
5638+
final DataCenterDeployment plan = new DataCenterDeployment(host.getDataCenterId(), null, null, null, null, null);
5639+
ExcludeList excludes = new ExcludeList();
5640+
excludes.addHost(srcHostId);
5641+
try {
5642+
dest = _planningMgr.planDeployment(profile, plan, excludes, null);
5643+
} catch (final AffinityConflictException e2) {
5644+
s_logger.warn("Unable to create deployment, affinity rules associted to the VM conflict", e2);
5645+
throw new CloudRuntimeException("Unable to create deployment, affinity rules associted to the VM conflict");
5646+
} catch (final InsufficientServerCapacityException e3) {
5647+
throw new CloudRuntimeException("Unable to find a server to migrate the vm to");
5648+
}
5649+
} else {
5650+
dest = checkVmMigrationDestination(vm, srcHostId, destinationHost);
5651+
}
5652+
5653+
// If no suitable destination found then throw exception
5654+
if (dest == null) {
5655+
throw new RuntimeException("Unable to find suitable destination to migrate VM " + vm.getInstanceName());
5656+
}
5657+
5658+
UserVmVO uservm = _vmDao.findById(vmId);
5659+
if (uservm != null) {
5660+
collectVmDiskStatistics(uservm);
5661+
collectVmNetworkStatistics(uservm);
5662+
}
5663+
_itMgr.migrate(vm.getUuid(), srcHostId, dest);
5664+
VMInstanceVO vmInstance = _vmInstanceDao.findById(vmId);
5665+
if (vmInstance.getType().equals(VirtualMachine.Type.User)) {
5666+
return _vmDao.findById(vmId);
5667+
} else {
5668+
return vmInstance;
5669+
}
5670+
}
5671+
5672+
private DeployDestination checkVmMigrationDestination(VMInstanceVO vm, Long srcHostId, Host destinationHost) throws VirtualMachineMigrationException {
5673+
if (destinationHost == null) {
5674+
return null;
5675+
}
56305676
if (destinationHost.getId() == srcHostId) {
56315677
throw new InvalidParameterValueException("Cannot migrate VM, VM is already present on this host, please specify valid destination host to migrate the VM");
56325678
}
@@ -5671,24 +5717,13 @@ public VirtualMachine migrateVirtualMachine(Long vmId, Host destinationHost) thr
56715717
+ " already has max Running VMs(count includes system VMs), cannot migrate to this host");
56725718
}
56735719
//check if there are any ongoing volume snapshots on the volumes associated with the VM.
5720+
Long vmId = vm.getId();
56745721
s_logger.debug("Checking if there are any ongoing snapshots volumes associated with VM with ID " + vmId);
56755722
if (checkStatusOfVolumeSnapshots(vmId, null)) {
56765723
throw new CloudRuntimeException("There is/are unbacked up snapshot(s) on volume(s) attached to this VM, VM Migration is not permitted, please try again later.");
56775724
}
56785725
s_logger.debug("Found no ongoing snapshots on volumes associated with the vm with id " + vmId);
5679-
5680-
UserVmVO uservm = _vmDao.findById(vmId);
5681-
if (uservm != null) {
5682-
collectVmDiskStatistics(uservm);
5683-
collectVmNetworkStatistics(uservm);
5684-
}
5685-
_itMgr.migrate(vm.getUuid(), srcHostId, dest);
5686-
VMInstanceVO vmInstance = _vmInstanceDao.findById(vmId);
5687-
if (vmInstance.getType().equals(VirtualMachine.Type.User)) {
5688-
return _vmDao.findById(vmId);
5689-
} else {
5690-
return vmInstance;
5691-
}
5726+
return dest;
56925727
}
56935728

56945729
private boolean isOnSupportedHypevisorForMigration(VMInstanceVO vm) {

ui/scripts/instances.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2529,6 +2529,26 @@
25292529
}
25302530
});
25312531
}
2532+
} else {
2533+
$.ajax({
2534+
url: createURL("migrateVirtualMachine&virtualmachineid=" + args.context.instances[0].id),
2535+
dataType: "json",
2536+
async: true,
2537+
success: function(json) {
2538+
var jid = json.migratevirtualmachineresponse.jobid;
2539+
args.response.success({
2540+
_custom: {
2541+
jobId: jid,
2542+
getUpdatedItem: function(json) {
2543+
return json.queryasyncjobresultresponse.jobresult.virtualmachine;
2544+
},
2545+
getActionFilter: function() {
2546+
return vmActionfilter;
2547+
}
2548+
}
2549+
});
2550+
}
2551+
});
25322552
}
25332553
}
25342554
})

ui/scripts/ui-custom/migrate.js

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,29 @@
102102
$('div.overlay').remove();
103103
$(':ui-dialog').dialog('destroy');
104104
});
105-
}
106-
else {
107-
cloudStack.dialog.notice({
108-
message: _l('message.migrate.instance.select.host')
105+
} else {
106+
$dataList.fadeOut(function() {
107+
action({
108+
context: $.extend(true, {}, context, {}),
109+
response: {
110+
success: function(args) {
111+
complete({
112+
_custom: args._custom,
113+
$item: $('<div>'),
114+
});
115+
},
116+
error: function(args) {
117+
cloudStack.dialog.notice({
118+
message: args
119+
});
120+
}
121+
}
122+
});
123+
});
124+
125+
$('div.overlay').fadeOut(function() {
126+
$('div.overlay').remove();
127+
$(':ui-dialog').dialog('destroy');
109128
});
110129
}
111130
}

0 commit comments

Comments
 (0)