Skip to content

Commit 3ec5280

Browse files
committed
CLOUDSTACK-2593: fix migrate volume between pools through secondary storage
1 parent 98af424 commit 3ec5280

9 files changed

Lines changed: 98 additions & 36 deletions

File tree

api/src/com/cloud/storage/VolumeApiService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public interface VolumeApiService {
5858
*/
5959
Volume resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationException;
6060

61-
Volume migrateVolume(MigrateVolumeCmd cmd) throws ConcurrentOperationException;
61+
Volume migrateVolume(MigrateVolumeCmd cmd);
6262

6363
/**
6464
* Uploads the volume to secondary storage

api/src/org/apache/cloudstack/api/command/user/volume/MigrateVolumeCmd.java

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -98,18 +98,15 @@ public String getEventDescription() {
9898

9999
@Override
100100
public void execute(){
101-
Volume result;
102-
try {
103-
result = _volumeService.migrateVolume(this);
104-
if (result != null) {
105-
VolumeResponse response = _responseGenerator.createVolumeResponse(result);
106-
response.setResponseName(getCommandName());
107-
this.setResponseObject(response);
108-
}
109-
} catch (ConcurrentOperationException e) {
110-
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to migrate volume: ");
111-
}
112-
101+
Volume result;
102+
result = _volumeService.migrateVolume(this);
103+
if (result != null) {
104+
VolumeResponse response = _responseGenerator.createVolumeResponse(result);
105+
response.setResponseName(getCommandName());
106+
this.setResponseObject(response);
107+
} else {
108+
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to migrate volume");
109+
}
113110
}
114111

115112
}

engine/schema/src/com/cloud/storage/VolumeVO.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ public VolumeVO(Type type, String name, long dcId, long domainId, long accountId
154154
this.uuid = UUID.randomUUID().toString();
155155
}
156156

157-
public VolumeVO(String name, long dcId, long podId, long accountId, long domainId, Long instanceId, String folder, String path, long size, Volume.Type vType) {
157+
public VolumeVO(String name, Long dcId, Long podId, long accountId, long domainId, Long instanceId, String folder, String path, long size, Volume.Type vType) {
158158
this.name = name;
159159
this.accountId = accountId;
160160
this.domainId = domainId;

engine/storage/cache/src/org/apache/cloudstack/storage/cache/allocator/StorageCacheRandomAllocator.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,26 +25,30 @@
2525
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
2626
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
2727
import org.apache.cloudstack.engine.subsystem.api.storage.Scope;
28+
import org.apache.log4j.Logger;
2829
import org.springframework.stereotype.Component;
2930

3031
import com.cloud.storage.ScopeType;
31-
import com.cloud.utils.exception.CloudRuntimeException;
3232

3333
import edu.emory.mathcs.backport.java.util.Collections;
3434

3535
@Component
3636
public class StorageCacheRandomAllocator implements StorageCacheAllocator {
37+
private static final Logger s_logger = Logger
38+
.getLogger(StorageCacheRandomAllocator.class);
3739
@Inject
3840
DataStoreManager dataStoreMgr;
3941
@Override
4042
public DataStore getCacheStore(Scope scope) {
4143
if (scope.getScopeType() != ScopeType.ZONE) {
42-
throw new CloudRuntimeException("Can only support zone wide cache storage");
44+
s_logger.debug("Can only support zone wide cache storage");
45+
return null;
4346
}
4447

4548
List<DataStore> cacheStores = dataStoreMgr.getImageCacheStores(scope);
4649
if (cacheStores.size() <= 0) {
47-
throw new CloudRuntimeException("Can't find cache storage in zone: " + scope.getScopeId());
50+
s_logger.debug("Can't find cache storage in zone: " + scope.getScopeId());
51+
return null;
4852
}
4953

5054
Collections.shuffle(cacheStores);

engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java

Lines changed: 71 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
3232
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
3333
import org.apache.cloudstack.engine.subsystem.api.storage.HostScope;
34+
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event;
3435
import org.apache.cloudstack.engine.subsystem.api.storage.Scope;
3536
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
3637
import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
@@ -39,11 +40,13 @@
3940
import org.apache.cloudstack.engine.subsystem.api.storage.StorageCacheManager;
4041
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
4142
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
43+
import org.apache.cloudstack.storage.command.CopyCmdAnswer;
4244
import org.apache.cloudstack.storage.command.CopyCommand;
4345
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
4446
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
4547
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
4648
import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao;
49+
import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity;
4750

4851
import com.cloud.agent.api.Answer;
4952
import com.cloud.agent.api.to.DataObjectType;
@@ -57,6 +60,7 @@
5760
import com.cloud.host.Host;
5861
import com.cloud.host.dao.HostDao;
5962
import com.cloud.storage.DataStoreRole;
63+
import com.cloud.storage.ImageStore;
6064
import com.cloud.storage.StorageManager;
6165
import com.cloud.storage.StoragePool;
6266
import com.cloud.storage.VolumeManager;
@@ -136,6 +140,20 @@ protected boolean needCacheStorage(DataObject srcData, DataObject destData) {
136140
}
137141
return true;
138142
}
143+
144+
private Scope getZoneScope(Scope destScope) {
145+
ZoneScope zoneScope = null;
146+
if (destScope instanceof ClusterScope) {
147+
ClusterScope clusterScope = (ClusterScope) destScope;
148+
zoneScope = new ZoneScope(clusterScope.getZoneId());
149+
} else if (destScope instanceof HostScope) {
150+
HostScope hostScope = (HostScope) destScope;
151+
zoneScope = new ZoneScope(hostScope.getZoneId());
152+
} else {
153+
zoneScope = (ZoneScope)destScope;
154+
}
155+
return zoneScope;
156+
}
139157

140158
protected Answer copyObject(DataObject srcData, DataObject destData) {
141159
String value = configDao.getValue(Config.PrimaryStorageDownloadWait.toString());
@@ -145,14 +163,7 @@ protected Answer copyObject(DataObject srcData, DataObject destData) {
145163
try {
146164
if (needCacheStorage(srcData, destData)) {
147165
// need to copy it to image cache store
148-
Scope destScope = destData.getDataStore().getScope();
149-
if (destScope instanceof ClusterScope) {
150-
ClusterScope clusterScope = (ClusterScope) destScope;
151-
destScope = new ZoneScope(clusterScope.getZoneId());
152-
} else if (destScope instanceof HostScope) {
153-
HostScope hostScope = (HostScope) destScope;
154-
destScope = new ZoneScope(hostScope.getZoneId());
155-
}
166+
Scope destScope = getZoneScope(destData.getDataStore().getScope());
156167
cacheData = cacheMgr.createCacheObject(srcData, destScope);
157168
CopyCommand cmd = new CopyCommand(cacheData.getTO(), destData.getTO(), _primaryStorageDownloadWait);
158169
EndPoint ep = selector.select(cacheData, destData);
@@ -248,11 +259,57 @@ protected Answer copyVolumeBetweenPools(DataObject srcData, DataObject destData)
248259
int _copyvolumewait = NumbersUtil.parseInt(value,
249260
Integer.parseInt(Config.CopyVolumeWait.getDefaultValue()));
250261

251-
DataObject cacheData = cacheMgr.createCacheObject(srcData, destData.getDataStore().getScope());
252-
CopyCommand cmd = new CopyCommand(cacheData.getTO(), destData.getTO(), _copyvolumewait);
253-
EndPoint ep = selector.select(cacheData, destData);
254-
Answer answer = ep.sendMessage(cmd);
255-
return answer;
262+
Scope destScope = getZoneScope(destData.getDataStore().getScope());
263+
DataStore cacheStore = cacheMgr.getCacheStorage(destScope);
264+
if (cacheStore == null) {
265+
//need to find a nfs image store, assuming that can't copy volume directly to s3
266+
ImageStoreEntity imageStore = (ImageStoreEntity)this.dataStoreMgr.getImageStore(destScope.getScopeId());
267+
if (!imageStore.getProtocol().equalsIgnoreCase("nfs")) {
268+
s_logger.debug("can't find a nfs image store");
269+
return null;
270+
}
271+
272+
DataObject objOnImageStore = imageStore.create(srcData);
273+
objOnImageStore.processEvent(Event.CreateOnlyRequested);
274+
275+
Answer answer = this.copyObject(srcData, objOnImageStore);
276+
if (answer == null || !answer.getResult()) {
277+
if (answer != null) {
278+
s_logger.debug("copy to image store failed: " + answer.getDetails());
279+
}
280+
objOnImageStore.processEvent(Event.OperationFailed);
281+
imageStore.delete(objOnImageStore);
282+
return answer;
283+
}
284+
285+
objOnImageStore.processEvent(Event.OperationSuccessed, answer);
286+
287+
objOnImageStore.processEvent(Event.CopyingRequested);
288+
289+
CopyCommand cmd = new CopyCommand(objOnImageStore.getTO(), destData.getTO(), _copyvolumewait);
290+
EndPoint ep = selector.select(objOnImageStore, destData);
291+
answer = ep.sendMessage(cmd);
292+
293+
if (answer == null || !answer.getResult()) {
294+
if (answer != null) {
295+
s_logger.debug("copy to primary store failed: " + answer.getDetails());
296+
}
297+
objOnImageStore.processEvent(Event.OperationFailed);
298+
imageStore.delete(objOnImageStore);
299+
return answer;
300+
}
301+
302+
objOnImageStore.processEvent(Event.OperationSuccessed);
303+
imageStore.delete(objOnImageStore);
304+
return answer;
305+
} else {
306+
DataObject cacheData = cacheMgr.createCacheObject(srcData, destScope);
307+
CopyCommand cmd = new CopyCommand(cacheData.getTO(), destData.getTO(), _copyvolumewait);
308+
EndPoint ep = selector.select(cacheData, destData);
309+
Answer answer = ep.sendMessage(cmd);
310+
return answer;
311+
}
312+
256313
}
257314

258315
@Override
@@ -273,7 +330,7 @@ public Void copyAsync(DataObject srcData, DataObject destData,
273330
answer = cloneVolume(srcData, destData);
274331
} else if (destData.getType() == DataObjectType.VOLUME
275332
&& srcData.getType() == DataObjectType.VOLUME && srcData.getDataStore().getRole() == DataStoreRole.Primary && destData.getDataStore().getRole() == DataStoreRole.Primary) {
276-
answer = copyVolumeBetweenPools(srcData, destData);
333+
answer = copyVolumeBetweenPools(srcData, destData);
277334
} else if (srcData.getType() == DataObjectType.SNAPSHOT &&
278335
destData.getType() == DataObjectType.SNAPSHOT) {
279336
answer = copySnapshot(srcData, destData);

engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,9 @@ public void processEvent(
193193
}
194194
if (this.dataStore.getRole() == DataStoreRole.Image) {
195195
objectInStoreMgr.update(this, event);
196+
if (this.volumeVO.getState() == Volume.State.Migrating) {
197+
return;
198+
}
196199
if (event == ObjectInDataStoreStateMachine.Event.CreateRequested) {
197200
volEvent = Volume.Event.UploadRequested;
198201
} else if (event == ObjectInDataStoreStateMachine.Event.OperationSuccessed) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -615,7 +615,7 @@ public AsyncCallFuture<VolumeApiResult> copyVolume(VolumeInfo srcVolume,
615615
.setContext(context);
616616
motionSrv.copyAsync(srcVolume, destVolume, caller);
617617
} catch (Exception e) {
618-
s_logger.debug("Failed to copy volume", e);
618+
s_logger.debug("Failed to copy volume" + e);
619619
res.setResult(e.toString());
620620
future.complete(res);
621621
}

plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -957,7 +957,8 @@ public Answer copyVolumeFromImageCacheToPrimary(CopyCommand cmd) {
957957
try {
958958
SR primaryStoragePool = hypervisorResource.getStorageRepository(conn, primaryStore.getUuid());
959959
String srUuid = primaryStoragePool.getUuid(conn);
960-
String volumePath = nfsStore.getUrl() + ":" + srcVolume.getPath();
960+
URI uri = new URI(nfsStore.getUrl());
961+
String volumePath = uri.getHost() + ":" + uri.getPath() + File.separator + srcVolume.getPath();
961962
String uuid = copy_vhd_from_secondarystorage(conn, volumePath, srUuid, wait );
962963
VolumeObjectTO newVol = new VolumeObjectTO();
963964
newVol.setPath(uuid);

server/src/com/cloud/storage/VolumeManagerImpl.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -719,7 +719,7 @@ private VolumeVO persistVolume(Account caller, long ownerId, Long zoneId,
719719
Transaction txn = Transaction.currentTxn();
720720
txn.start();
721721

722-
VolumeVO volume = new VolumeVO(volumeName, zoneId, -1, -1, -1,
722+
VolumeVO volume = new VolumeVO(volumeName, zoneId, -1L, -1L, -1,
723723
new Long(-1), null, null, 0, Volume.Type.DATADISK);
724724
Account owner = (caller.getId() == ownerId) ? caller : _accountMgr
725725
.getActiveAccountById(ownerId);
@@ -965,7 +965,7 @@ public VolumeVO allocVolume(CreateVolumeCmd cmd)
965965
Transaction txn = Transaction.currentTxn();
966966
txn.start();
967967

968-
VolumeVO volume = new VolumeVO(userSpecifiedName, -1, -1, -1, -1,
968+
VolumeVO volume = new VolumeVO(userSpecifiedName, -1L, -1L, -1, -1,
969969
new Long(-1), null, null, 0, Volume.Type.DATADISK);
970970
volume.setPoolId(null);
971971
volume.setDataCenterId(zoneId);
@@ -2095,7 +2095,7 @@ protected Volume migrateVolume(Volume volume, StoragePool destPool) {
20952095
try {
20962096
VolumeApiResult result = future.get();
20972097
if (result.isFailed()) {
2098-
s_logger.debug("migrate volume failed:" + result.getResult());
2098+
s_logger.error("migrate volume failed:" + result.getResult());
20992099
return null;
21002100
}
21012101
return result.getVolume();

0 commit comments

Comments
 (0)