Skip to content

Commit ec20fd1

Browse files
authored
FR562: Flexible cluster migration (#22)
https://shapeblue.atlassian.net/browse/FRO-910
1 parent 723edf3 commit ec20fd1

File tree

21 files changed

+1387
-595
lines changed

21 files changed

+1387
-595
lines changed

api/src/com/cloud/hypervisor/HypervisorGuru.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,14 @@
1919
import java.util.List;
2020
import java.util.Map;
2121

22-
import com.cloud.storage.StoragePool;
2322
import org.apache.cloudstack.framework.config.ConfigKey;
2423

2524
import com.cloud.agent.api.Command;
2625
import com.cloud.agent.api.to.NicTO;
2726
import com.cloud.agent.api.to.VirtualMachineTO;
2827
import com.cloud.hypervisor.Hypervisor.HypervisorType;
28+
import com.cloud.storage.StoragePool;
29+
import com.cloud.storage.Volume;
2930
import com.cloud.utils.Pair;
3031
import com.cloud.utils.component.Adapter;
3132
import com.cloud.vm.NicProfile;
@@ -93,5 +94,5 @@ public interface HypervisorGuru extends Adapter {
9394
* @param destination the primary storage pool to migrate to
9495
* @return a list of commands to perform for a successful migration
9596
*/
96-
List<Command> finalizeMigrate(VirtualMachine vm, StoragePool destination);
97+
List<Command> finalizeMigrate(VirtualMachine vm, Map<Volume, StoragePool> volumeToPool);
9798
}

api/src/com/cloud/vm/UserVmService.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,8 @@ UserVm moveVMToUser(AssignVMCmd moveUserVMCmd) throws ResourceAllocationExceptio
461461

462462
VirtualMachine vmStorageMigration(Long vmId, StoragePool destPool);
463463

464+
VirtualMachine vmStorageMigration(Long vmId, Map<String, String> volumeToPool);
465+
464466
UserVm restoreVM(RestoreVMCmd cmd) throws InsufficientCapacityException, ResourceUnavailableException;
465467

466468
UserVm upgradeVirtualMachine(ScaleVMCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException,

api/src/org/apache/cloudstack/api/command/admin/vm/MigrateVirtualMachineWithVolumeCmd.java

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@
2121
import java.util.Iterator;
2222
import java.util.Map;
2323

24-
import org.apache.log4j.Logger;
25-
2624
import org.apache.cloudstack.api.APICommand;
2725
import org.apache.cloudstack.api.ApiConstants;
2826
import org.apache.cloudstack.api.ApiErrorCode;
@@ -32,6 +30,8 @@
3230
import org.apache.cloudstack.api.ServerApiException;
3331
import org.apache.cloudstack.api.response.HostResponse;
3432
import org.apache.cloudstack.api.response.UserVmResponse;
33+
import org.apache.commons.collections.MapUtils;
34+
import org.apache.log4j.Logger;
3535

3636
import com.cloud.event.EventTypes;
3737
import com.cloud.exception.ConcurrentOperationException;
@@ -61,7 +61,6 @@ public class MigrateVirtualMachineWithVolumeCmd extends BaseAsyncCmd {
6161
@Parameter(name = ApiConstants.HOST_ID,
6262
type = CommandType.UUID,
6363
entityType = HostResponse.class,
64-
required = true,
6564
description = "Destination Host ID to migrate VM to.")
6665
private Long hostId;
6766

@@ -97,7 +96,7 @@ public Long getVirtualMachineId() {
9796

9897
public Map<String, String> getVolumeToPool() {
9998
Map<String, String> volumeToPoolMap = new HashMap<String, String>();
100-
if (migrateVolumeTo != null && !migrateVolumeTo.isEmpty()) {
99+
if (MapUtils.isNotEmpty(migrateVolumeTo)) {
101100
Collection<?> allValues = migrateVolumeTo.values();
102101
Iterator<?> iter = allValues.iterator();
103102
while (iter.hasNext()) {
@@ -141,19 +140,35 @@ public String getEventDescription() {
141140

142141
@Override
143142
public void execute() {
143+
if (hostId == null && MapUtils.isEmpty(migrateVolumeTo)) {
144+
throw new InvalidParameterValueException(String.format("Either %s or %s must be passed for migrating the VM", ApiConstants.HOST_ID, ApiConstants.MIGRATE_TO));
145+
}
146+
144147
UserVm userVm = _userVmService.getUserVm(getVirtualMachineId());
145148
if (userVm == null) {
146149
throw new InvalidParameterValueException("Unable to find the VM by id=" + getVirtualMachineId());
147150
}
148151

149-
Host destinationHost = _resourceService.getHost(getHostId());
150-
// OfflineVmwareMigration: destination host would have to not be a required parameter for stopped VMs
151-
if (destinationHost == null) {
152-
throw new InvalidParameterValueException("Unable to find the host to migrate the VM, host id =" + getHostId());
152+
if (!VirtualMachine.State.Running.equals(userVm.getState()) && hostId != null) {
153+
throw new InvalidParameterValueException(String.format("VM ID: %s is not in Running state to migrate it to new host", userVm.getUuid()));
154+
}
155+
156+
if (!VirtualMachine.State.Stopped.equals(userVm.getState()) && hostId == null) {
157+
throw new InvalidParameterValueException(String.format("VM ID: %s is not in Stopped state to migrate, use %s parameter to migrate it to a new host", userVm.getUuid(), ApiConstants.HOST_ID));
153158
}
154159

155160
try {
156-
VirtualMachine migratedVm = _userVmService.migrateVirtualMachineWithVolume(getVirtualMachineId(), destinationHost, getVolumeToPool());
161+
VirtualMachine migratedVm = null;
162+
if (hostId != null) {
163+
Host destinationHost = _resourceService.getHost(getHostId());
164+
// OfflineVmwareMigration: destination host would have to not be a required parameter for stopped VMs
165+
if (destinationHost == null) {
166+
throw new InvalidParameterValueException("Unable to find the host to migrate the VM, host id =" + getHostId());
167+
}
168+
migratedVm = _userVmService.migrateVirtualMachineWithVolume(getVirtualMachineId(), destinationHost, getVolumeToPool());
169+
} else if (MapUtils.isNotEmpty(migrateVolumeTo)) {
170+
migratedVm = _userVmService.vmStorageMigration(getVirtualMachineId(), getVolumeToPool());
171+
}
157172
if (migratedVm != null) {
158173
UserVmResponse response = _responseGenerator.createUserVmResponse(ResponseView.Full, "virtualmachine", (UserVm)migratedVm).get(0);
159174
response.setResponseName(getCommandName());

core/src/com/cloud/agent/api/MigrateVmToPoolCommand.java

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,48 +18,50 @@
1818
//
1919
package com.cloud.agent.api;
2020

21-
import com.cloud.agent.api.to.VolumeTO;
21+
import java.util.List;
2222

23-
import java.util.Collection;
23+
import com.cloud.agent.api.to.StorageFilerTO;
24+
import com.cloud.agent.api.to.VolumeTO;
25+
import com.cloud.utils.Pair;
2426

2527
/**
2628
* used to tell the agent to migrate a vm to a different primary storage pool.
2729
* It is for now only implemented on Vmware and is supposed to work irrespective of whether the VM is started or not.
2830
*
2931
*/
3032
public class MigrateVmToPoolCommand extends Command {
31-
private Collection<VolumeTO> volumes;
3233
private String vmName;
33-
private String destinationPool;
3434
private boolean executeInSequence = false;
35+
private List<Pair<VolumeTO, StorageFilerTO>> volumeToFilerAsList;
36+
private String hostGuidInTargetCluster;
3537

3638
protected MigrateVmToPoolCommand() {
3739
}
3840

3941
/**
4042
*
4143
* @param vmName the name of the VM to migrate
42-
* @param volumes used to supply feedback on vmware generated names
43-
* @param destinationPool the primary storage pool to migrate the VM to
44+
* @param volumeToFilerTo the volume to primary storage pool map to migrate the VM to
45+
* @param hostGuidInTargetCluster GUID for host in target cluster when migrating across clusters
4446
* @param executeInSequence
4547
*/
46-
public MigrateVmToPoolCommand(String vmName, Collection<VolumeTO> volumes, String destinationPool, boolean executeInSequence) {
48+
public MigrateVmToPoolCommand(String vmName, List<Pair<VolumeTO, StorageFilerTO>> volumeToFilerTo, String hostGuidInTargetCluster, boolean executeInSequence) {
4749
this.vmName = vmName;
48-
this.volumes = volumes;
49-
this.destinationPool = destinationPool;
50+
this.hostGuidInTargetCluster = hostGuidInTargetCluster;
5051
this.executeInSequence = executeInSequence;
52+
this.volumeToFilerAsList = volumeToFilerTo;
5153
}
5254

53-
public Collection<VolumeTO> getVolumes() {
54-
return volumes;
55+
public String getVmName() {
56+
return vmName;
5557
}
5658

57-
public String getDestinationPool() {
58-
return destinationPool;
59+
public List<Pair<VolumeTO, StorageFilerTO>> getVolumeToFilerAsList() {
60+
return volumeToFilerAsList;
5961
}
6062

61-
public String getVmName() {
62-
return vmName;
63+
public String getHostGuidInTargetCluster() {
64+
return hostGuidInTargetCluster;
6365
}
6466

6567
@Override

core/src/com/cloud/agent/api/storage/MigrateVolumeCommand.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public class MigrateVolumeCommand extends Command {
3232
StorageFilerTO sourcePool;
3333
String attachedVmName;
3434
Volume.Type volumeType;
35+
String hostGuidInTargetCluster;
3536

3637
public MigrateVolumeCommand(long volumeId, String volumePath, StoragePool pool, int timeout) {
3738
this.volumeId = volumeId;
@@ -51,6 +52,11 @@ public MigrateVolumeCommand(long volumeId, String volumePath, StoragePool source
5152
this.sourcePool = new StorageFilerTO(sourcePool);
5253
}
5354

55+
public MigrateVolumeCommand(long volumeId, String volumePath, StoragePool sourcePool, StoragePool targetPool, String hostGuidInTargetCluster) {
56+
this(volumeId, volumePath, sourcePool, targetPool);
57+
this.hostGuidInTargetCluster = hostGuidInTargetCluster;
58+
}
59+
5460
@Override
5561
public boolean executeInSequence() {
5662
return true;
@@ -83,4 +89,8 @@ public String getAttachedVmName() {
8389
public Volume.Type getVolumeType() {
8490
return volumeType;
8591
}
92+
93+
public String getHostGuidInTargetCluster() {
94+
return hostGuidInTargetCluster;
95+
}
8696
}

core/src/org/apache/cloudstack/storage/to/VolumeObjectTO.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@
1919

2020
package org.apache.cloudstack.storage.to;
2121

22-
import com.cloud.storage.MigrationOptions;
2322
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
2423

2524
import com.cloud.agent.api.to.DataObjectType;
2625
import com.cloud.agent.api.to.DataStoreTO;
2726
import com.cloud.agent.api.to.DataTO;
2827
import com.cloud.hypervisor.Hypervisor;
2928
import com.cloud.offering.DiskOffering.DiskCacheMode;
29+
import com.cloud.storage.MigrationOptions;
3030
import com.cloud.storage.Storage;
3131
import com.cloud.storage.Volume;
3232

@@ -53,6 +53,7 @@ public class VolumeObjectTO implements DataTO {
5353
private DiskCacheMode cacheMode;
5454
private Hypervisor.HypervisorType hypervisorType;
5555
private MigrationOptions migrationOptions;
56+
private String dataStoreUuid;
5657

5758
public VolumeObjectTO() {
5859

@@ -259,4 +260,12 @@ public DiskCacheMode getCacheMode() {
259260
public MigrationOptions getMigrationOptions() {
260261
return migrationOptions;
261262
}
263+
264+
public String getDataStoreUuid() {
265+
return dataStoreUuid;
266+
}
267+
268+
public void setDataStoreUuid(String dataStoreUuid) {
269+
this.dataStoreUuid = dataStoreUuid;
270+
}
262271
}

engine/api/src/com/cloud/vm/VirtualMachineManager.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
import com.cloud.network.Network;
3939
import com.cloud.offering.DiskOfferingInfo;
4040
import com.cloud.offering.ServiceOffering;
41-
import com.cloud.storage.StoragePool;
4241
import com.cloud.template.VirtualMachineTemplate;
4342
import com.cloud.utils.component.Manager;
4443
import com.cloud.utils.fsm.NoTransitionException;
@@ -134,7 +133,7 @@ void advanceReboot(String vmUuid, Map<VirtualMachineProfile.Param, Object> param
134133

135134
VirtualMachine findById(long vmId);
136135

137-
void storageMigration(String vmUuid, StoragePool storagePoolId);
136+
void storageMigration(String vmUuid, Map<Long, Long> volumeToPool);
138137

139138
/**
140139
* @param vmInstance

engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ VolumeInfo moveVolume(VolumeInfo volume, long destPoolDcId, Long destPoolPodId,
104104

105105
void migrateVolumes(VirtualMachine vm, VirtualMachineTO vmTo, Host srcHost, Host destHost, Map<Volume, StoragePool> volumeToPool);
106106

107-
boolean storageMigration(VirtualMachineProfile vm, StoragePool destPool) throws StorageUnavailableException;
107+
boolean storageMigration(VirtualMachineProfile vm, Map<Volume, StoragePool> volumeToPool) throws StorageUnavailableException;
108108

109109
void prepareForMigration(VirtualMachineProfile vm, DeployDestination dest);
110110

0 commit comments

Comments
 (0)