Skip to content

Commit 6e6a092

Browse files
committed
enable canHandle and implement detached volume migration for vmware
1 parent 7195837 commit 6e6a092

File tree

10 files changed

+433
-53
lines changed

10 files changed

+433
-53
lines changed

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,11 @@ public interface HypervisorGuru extends Adapter {
8787
Map<String, String> getClusterSettings(long vmId);
8888

8989
/**
90-
* will migrate a vm to a pool. For now this will ony work for stopped VMs on Vmware.
90+
* will generate commands to migrate a vm to a pool. For now this will ony work for stopped VMs on Vmware.
91+
*
9192
* @param vm the stopped vm to migrate
9293
* @param destination the primary storage pool to migrate to
93-
* @return all data pertaining to the 'new' vm
94+
* @return a list of commands to perform for a succesful migration
9495
*/
9596
List<Command> migrate(VirtualMachine vm, StoragePool destination);
9697
}

core/src/main/java/com/cloud/agent/api/MigrateToPoolCommand.java

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,61 @@
1+
//
2+
// Licensed to the Apache Software Foundation (ASF) under one
3+
// or more contributor license agreements. See the NOTICE file
4+
// distributed with this work for additional information
5+
// regarding copyright ownership. The ASF licenses this file
6+
// to you under the Apache License, Version 2.0 (the
7+
// "License"); you may not use this file except in compliance
8+
// with the License. You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing,
13+
// software distributed under the License is distributed on an
14+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
// KIND, either express or implied. See the License for the
16+
// specific language governing permissions and limitations
17+
// under the License.
18+
//
119
package com.cloud.agent.api;
220

21+
import com.cloud.agent.api.to.VolumeTO;
22+
23+
import java.util.Collection;
24+
325
/**
426
* used to tell the agent to migrate a vm to a different primare storage pool.
527
* It is for now only mplemented on Vmware and is supposed to work irrespective of whether the VM is started or not.
628
*
729
*/
830
public class MigrateToPoolCommand extends Command {
9-
String vmName;
10-
String destPool;
11-
boolean executeInSequence = false;
31+
private Collection<VolumeTO> volumes;
32+
private String vmName;
33+
private String destinationPool;
34+
private boolean executeInSequence = false;
1235

1336
protected MigrateToPoolCommand() {
1437
}
1538

1639
/**
1740
*
1841
* @param vmName the name of the VM to migrate
19-
* @param destPool the primare storage pool to migrate the VM to
42+
* @param volumes used to suplly feedback on vmware generated names
43+
* @param destinationPool the primare storage pool to migrate the VM to
2044
* @param executeInSequence
2145
*/
22-
public MigrateToPoolCommand(String vmName, String destPool, boolean executeInSequence) {
46+
public MigrateToPoolCommand(String vmName, Collection<VolumeTO> volumes, String destinationPool, boolean executeInSequence) {
2347
this.vmName = vmName;
24-
this.destPool = destPool;
48+
this.volumes = volumes;
49+
this.destinationPool = destinationPool;
2550
this.executeInSequence = executeInSequence;
2651
}
2752

53+
public Collection<VolumeTO> getVolumes() {
54+
return volumes;
55+
}
56+
2857
public String getDestinationPool() {
29-
return destPool;
58+
return destinationPool;
3059
}
3160

3261
public String getVmName() {

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

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public class MigrateVolumeCommand extends Command {
3131
long volumeId;
3232
String volumePath;
3333
StorageFilerTO pool;
34+
StorageFilerTO sourcePool;
3435
String attachedVmName;
3536
Volume.Type volumeType;
3637

@@ -47,14 +48,17 @@ public MigrateVolumeCommand(long volumeId, String volumePath, StoragePool pool,
4748
}
4849

4950
public MigrateVolumeCommand(long volumeId, String volumePath, StoragePool pool, String attachedVmName, Volume.Type volumeType, int timeout) {
50-
this.volumeId = volumeId;
51-
this.volumePath = volumePath;
52-
this.pool = new StorageFilerTO(pool);
51+
this(volumeId,volumePath,pool,timeout);
5352
this.attachedVmName = attachedVmName;
5453
this.volumeType = volumeType;
5554
this.setWait(timeout);
5655
}
5756

57+
public MigrateVolumeCommand(long volumeId, String volumePath, StoragePool sourcePool, StoragePool targetPool) {
58+
this(volumeId,volumePath,targetPool, null, Volume.Type.UNKNOWN, -1);
59+
this.sourcePool = new StorageFilerTO(sourcePool);
60+
}
61+
5862
public MigrateVolumeCommand(DataTO srcData, DataTO destData, Map<String, String> srcDetails, Map<String, String> destDetails, int timeout) {
5963
this.srcData = srcData;
6064
this.destData = destData;
@@ -81,6 +85,14 @@ public StorageFilerTO getPool() {
8185
return pool;
8286
}
8387

88+
public StorageFilerTO getSourcePool() {
89+
return sourcePool;
90+
}
91+
92+
public StorageFilerTO getTargetPool() {
93+
return pool;
94+
}
95+
8496
public String getAttachedVmName() {
8597
return attachedVmName;
8698
}

engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/DataMotionStrategy.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,28 @@
2525
import com.cloud.agent.api.to.VirtualMachineTO;
2626
import com.cloud.host.Host;
2727

28+
/**
29+
* interface to query how to move data around and to commision the moving
30+
*/
2831
public interface DataMotionStrategy {
32+
/**
33+
* reports whether this instance can do a move from source to destination
34+
* @param srcData object to move
35+
* @param destData location to move it to
36+
* @return the expertise level with which this instance knows how to handle the move
37+
*/
2938
StrategyPriority canHandle(DataObject srcData, DataObject destData);
3039

3140
StrategyPriority canHandle(Map<VolumeInfo, DataStore> volumeMap, Host srcHost, Host destHost);
3241

42+
/**
43+
* copy the source volume to its destination (on a host if not null)
44+
*
45+
* @param srcData volume to move
46+
* @param destData volume description as intended after the move
47+
* @param destHost if not null destData should be reachable from here
48+
* @param callback where to report completion or failure to
49+
*/
3350
void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback);
3451

3552
void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback);

engine/storage/volume/src/main/java/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1408,6 +1408,13 @@ protected Void copyVolumeFromPrimaryToImageCallback(AsyncCallbackDispatcher<Volu
14081408

14091409
@Override
14101410
public AsyncCallFuture<VolumeApiResult> copyVolume(VolumeInfo srcVolume, DataStore destStore) {
1411+
if (s_logger.isDebugEnabled()) {
1412+
DataStoreRole srcRole = srcVolume.getDataStore().getRole();
1413+
DataStoreRole destRole = destStore.getRole();
1414+
1415+
String msg = String.format("copying %s(id=%d, role=%s) to %s (id=%d, role=%s)", srcVolume.getName(), srcVolume.getId(), srcRole, destStore.getName(), destStore.getId(), destRole);
1416+
s_logger.debug(msg);
1417+
}
14111418

14121419
if (srcVolume.getState() == Volume.State.Uploaded) {
14131420
return copyVolumeFromImageToPrimary(srcVolume, destStore);
@@ -1417,6 +1424,8 @@ public AsyncCallFuture<VolumeApiResult> copyVolume(VolumeInfo srcVolume, DataSto
14171424
return copyVolumeFromPrimaryToImage(srcVolume, destStore);
14181425
}
14191426

1427+
// OfflineVmwareMigration: aren't we missing secondary to secondary in this logic?
1428+
14201429
AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
14211430
VolumeApiResult res = new VolumeApiResult(srcVolume);
14221431
try {
@@ -1438,7 +1447,10 @@ public AsyncCallFuture<VolumeApiResult> copyVolume(VolumeInfo srcVolume, DataSto
14381447
caller.setCallback(caller.getTarget().copyVolumeCallBack(null, null)).setContext(context);
14391448
motionSrv.copyAsync(srcVolume, destVolume, caller);
14401449
} catch (Exception e) {
1441-
s_logger.debug("Failed to copy volume" + e);
1450+
s_logger.error("Failed to copy volume:" + e);
1451+
if(s_logger.isDebugEnabled()) {
1452+
s_logger.debug("Failed to copy volume.", e);
1453+
}
14421454
res.setResult(e.toString());
14431455
future.complete(res);
14441456
}
@@ -1461,27 +1473,25 @@ protected Void copyVolumeCallBack(AsyncCallbackDispatcher<VolumeServiceImpl, Cop
14611473
AsyncCallFuture<VolumeApiResult> destroyFuture = expungeVolumeAsync(destVolume);
14621474
destroyFuture.get();
14631475
future.complete(res);
1464-
return null;
1465-
}
1466-
srcVolume.processEvent(Event.OperationSuccessed);
1467-
destVolume.processEvent(Event.MigrationCopySucceeded, result.getAnswer());
1468-
volDao.updateUuid(srcVolume.getId(), destVolume.getId());
1469-
_volumeStoreDao.updateVolumeId(srcVolume.getId(), destVolume.getId());
1470-
try {
1471-
destroyVolume(srcVolume.getId());
1472-
srcVolume = volFactory.getVolume(srcVolume.getId());
1473-
AsyncCallFuture<VolumeApiResult> destroyFuture = expungeVolumeAsync(srcVolume);
1474-
// If volume destroy fails, this could be because of vdi is still in use state, so wait and retry.
1475-
if (destroyFuture.get().isFailed()) {
1476-
Thread.sleep(5 * 1000);
1477-
destroyFuture = expungeVolumeAsync(srcVolume);
1478-
destroyFuture.get();
1476+
} else {
1477+
srcVolume.processEvent(Event.OperationSuccessed);
1478+
destVolume.processEvent(Event.MigrationCopySucceeded, result.getAnswer());
1479+
volDao.updateUuid(srcVolume.getId(), destVolume.getId());
1480+
try {
1481+
destroyVolume(srcVolume.getId());
1482+
srcVolume = volFactory.getVolume(srcVolume.getId());
1483+
AsyncCallFuture<VolumeApiResult> destroyFuture = expungeVolumeAsync(srcVolume);
1484+
// If volume destroy fails, this could be because of vdi is still in use state, so wait and retry.
1485+
if (destroyFuture.get().isFailed()) {
1486+
Thread.sleep(5 * 1000);
1487+
destroyFuture = expungeVolumeAsync(srcVolume);
1488+
destroyFuture.get();
1489+
}
1490+
future.complete(res);
1491+
} catch (Exception e) {
1492+
s_logger.debug("failed to clean up volume on storage", e);
14791493
}
1480-
future.complete(res);
1481-
} catch (Exception e) {
1482-
s_logger.debug("failed to clean up volume on storage", e);
14831494
}
1484-
return null;
14851495
} catch (Exception e) {
14861496
s_logger.debug("Failed to process copy volume callback", e);
14871497
res.setResult(e.toString());

plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VMwareGuru.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
import com.cloud.agent.api.MigrateToPoolCommand;
3030
import com.cloud.agent.api.UnregisterVMCommand;
31+
import com.cloud.agent.api.to.VolumeTO;
3132
import com.cloud.dc.ClusterDetailsDao;
3233
import com.cloud.storage.StoragePool;
3334
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore;
@@ -646,12 +647,19 @@ public Map<String, String> getClusterSettings(long vmId) {
646647
details.put(VmwareReserveMemory.key(), VmwareReserveMemory.valueIn(clusterId).toString());
647648
return details;
648649
}
650+
649651
@Override
650652
public List<Command> migrate(VirtualMachine vm, StoragePool destination) {
651653
List<Command> commands = new ArrayList<Command>();
652654

653655
// OfflineVmwareMigration: specialised migration command
654-
MigrateToPoolCommand migrateToPoolCommand = new MigrateToPoolCommand(vm.getInstanceName(), destination.getUuid(), true);
656+
List<VolumeVO> volumes = _volumeDao.findByInstance(vm.getId());
657+
List<VolumeTO> vols = new ArrayList<>();
658+
for (Volume volume : volumes) {
659+
VolumeTO vol = new VolumeTO(volume,destination);
660+
vols.add(vol);
661+
}
662+
MigrateToPoolCommand migrateToPoolCommand = new MigrateToPoolCommand(vm.getInstanceName(), vols, destination.getUuid(), true);
655663
commands.add(migrateToPoolCommand);
656664

657665
// OfflineVmwareMigration: cleanup if needed

0 commit comments

Comments
 (0)