in plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/driver/StorPoolPrimaryDataStoreDriver.java [607:976]
public void copyAsync(DataObject srcData, DataObject dstData, AsyncCompletionCallback<CopyCommandResult> callback) {
StorPoolUtil.spLog("StorpoolPrimaryDataStoreDriverImpl.copyAsnc:");
logDataObject("SRC", srcData);
logDataObject("DST", dstData);
final DataObjectType srcType = srcData.getType();
final DataObjectType dstType = dstData.getType();
String err = null;
Answer answer = null;
StorageSubSystemCommand cmd = null;
try {
if (srcType == DataObjectType.SNAPSHOT && dstType == DataObjectType.VOLUME) {
SnapshotInfo sinfo = (SnapshotInfo)srcData;
final String snapshotName = StorPoolHelper.getSnapshotName(srcData.getId(), srcData.getUuid(), snapshotDataStoreDao, snapshotDetailsDao);
VolumeInfo vinfo = (VolumeInfo)dstData;
final String volumeName = vinfo.getUuid();
final Long size = vinfo.getSize();
SpConnectionDesc conn = StorPoolUtil.getSpConnection(vinfo.getDataStore().getUuid(), vinfo.getDataStore().getId(), storagePoolDetailsDao, primaryStoreDao);
SpApiResponse resp = StorPoolUtil.volumeCreate(volumeName, snapshotName, size, null, null, "volume", sinfo.getBaseVolume().getMaxIops(), conn);
if (resp.getError() == null) {
updateStoragePool(dstData.getDataStore().getId(), size);
VolumeObjectTO to = (VolumeObjectTO)dstData.getTO();
to.setPath(StorPoolUtil.devPath(StorPoolUtil.getNameFromResponse(resp, false)));
to.setSize(size);
answer = new CopyCmdAnswer(to);
StorPoolUtil.spLog("Created volume=%s with uuid=%s from snapshot=%s with uuid=%s", StorPoolUtil.getNameFromResponse(resp, false), to.getUuid(), snapshotName, sinfo.getUuid());
} else if (resp.getError().getName().equals("objectDoesNotExist")) {
//check if snapshot is on secondary storage
StorPoolUtil.spLog("Snapshot %s does not exists on StorPool, will try to create a volume from a snapshot on secondary storage", snapshotName);
SnapshotDataStoreVO snap = getSnapshotImageStoreRef(sinfo.getId(), vinfo.getDataCenterId());
SnapshotDetailsVO snapshotDetail = snapshotDetailsDao.findDetail(sinfo.getId(), StorPoolUtil.SP_DELAY_DELETE);
if (snapshotDetail != null) {
err = String.format("Could not create volume from snapshot due to: %s. The snapshot was created with the delayDelete option.", resp.getError());
} else if (snap != null && StorPoolStorageAdaptor.getVolumeNameFromPath(snap.getInstallPath(), false) == null) {
SpApiResponse emptyVolumeCreateResp = StorPoolUtil.volumeCreate(volumeName, null, size, null, null, "volume", null, conn);
if (emptyVolumeCreateResp.getError() == null) {
answer = createVolumeFromSnapshot(srcData, dstData, size, emptyVolumeCreateResp);
} else {
answer = new Answer(cmd, false, String.format("Could not create Storpool volume %s from snapshot %s. Error: %s", volumeName, snapshotName, emptyVolumeCreateResp.getError()));
}
} else {
answer = new Answer(cmd, false, String.format("The snapshot %s does not exists neither on primary, neither on secondary storage. Cannot create volume from snapshot", snapshotName));
}
} else {
err = String.format("Could not create Storpool volume %s from snapshot %s. Error: %s", volumeName, snapshotName, resp.getError());
}
} else if (srcType == DataObjectType.SNAPSHOT && dstType == DataObjectType.SNAPSHOT) {
SnapshotInfo sinfo = (SnapshotInfo)srcData;
SnapshotDetailsVO snapshotDetail = snapshotDetailsDao.findDetail(sinfo.getId(), StorPoolUtil.SP_DELAY_DELETE);
// bypass secondary storage
if (StorPoolConfigurationManager.BypassSecondaryStorage.value() || snapshotDetail != null) {
SnapshotObjectTO snapshot = (SnapshotObjectTO) srcData.getTO();
answer = new CopyCmdAnswer(snapshot);
} else {
// copy snapshot to secondary storage (backup snapshot)
cmd = new StorPoolBackupSnapshotCommand(srcData.getTO(), dstData.getTO(), StorPoolHelper.getTimeout(StorPoolHelper.BackupSnapshotWait, configDao), VirtualMachineManager.ExecuteInSequence.value());
final String snapName = StorPoolStorageAdaptor.getVolumeNameFromPath(((SnapshotInfo) srcData).getPath(), true);
SpConnectionDesc conn = StorPoolUtil.getSpConnection(srcData.getDataStore().getUuid(), srcData.getDataStore().getId(), storagePoolDetailsDao, primaryStoreDao);
try {
Long clusterId = StorPoolHelper.findClusterIdByGlobalId(snapName, clusterDao);
EndPoint ep = clusterId != null ? RemoteHostEndPoint.getHypervisorHostEndPoint(StorPoolHelper.findHostByCluster(clusterId, hostDao)) : selector.select(srcData, dstData);
if (ep == null) {
err = "No remote endpoint to send command, check if host or ssvm is down?";
} else {
answer = ep.sendMessage(cmd);
// if error during snapshot backup, cleanup the StorPool snapshot
if (answer != null && !answer.getResult()) {
StorPoolUtil.spLog(String.format("Error while backing-up snapshot '%s' - cleaning up StorPool snapshot. Error: %s", snapName, answer.getDetails()));
SpApiResponse resp = StorPoolUtil.snapshotDelete(snapName, conn);
if (resp.getError() != null) {
final String err2 = String.format("Failed to cleanup StorPool snapshot '%s'. Error: %s.", snapName, resp.getError());
logger.error(err2);
StorPoolUtil.spLog(err2);
}
}
}
} catch (CloudRuntimeException e) {
err = e.getMessage();
}
}
} else if (srcType == DataObjectType.VOLUME && dstType == DataObjectType.TEMPLATE) {
// create template from volume
VolumeObjectTO volume = (VolumeObjectTO) srcData.getTO();
TemplateObjectTO template = (TemplateObjectTO) dstData.getTO();
SpConnectionDesc conn = StorPoolUtil.getSpConnection(srcData.getDataStore().getUuid(), srcData.getDataStore().getId(), storagePoolDetailsDao, primaryStoreDao);
String volumeName = StorPoolStorageAdaptor.getVolumeNameFromPath(volume.getPath(), true);
cmd = new StorPoolBackupTemplateFromSnapshotCommand(volume, template,
StorPoolHelper.getTimeout(StorPoolHelper.PrimaryStorageDownloadWait, configDao), VirtualMachineManager.ExecuteInSequence.value());
try {
Long clusterId = StorPoolHelper.findClusterIdByGlobalId(volumeName, clusterDao);
EndPoint ep2 = clusterId != null ? RemoteHostEndPoint.getHypervisorHostEndPoint(StorPoolHelper.findHostByCluster(clusterId, hostDao)) : selector.select(srcData, dstData);
if (ep2 == null) {
err = "No remote endpoint to send command, check if host or ssvm is down?";
} else {
answer = ep2.sendMessage(cmd);
if (answer != null && answer.getResult()) {
SpApiResponse resSnapshot = StorPoolUtil.volumeSnapshot(volumeName, template.getUuid(), null, "template", "no", conn);
if (resSnapshot.getError() != null) {
logger.debug(String.format("Could not snapshot volume with ID=%s", volume.getId()));
StorPoolUtil.spLog("Volume snapshot failed with error=%s", resSnapshot.getError().getDescr());
err = resSnapshot.getError().getDescr();
}
else {
StorPoolHelper.updateVmStoreTemplate(template.getId(), template.getDataStore().getRole(), StorPoolUtil.devPath(StorPoolUtil.getSnapshotNameFromResponse(resSnapshot, false, StorPoolUtil.GLOBAL_ID)), vmTemplateDataStoreDao);
vmTemplateDetailsDao.persist(new VMTemplateDetailVO(template.getId(), StorPoolUtil.SP_STORAGE_POOL_ID, String.valueOf(srcData.getDataStore().getId()), false));
}
}else {
err = "Could not copy template to secondary " + answer.getResult();
}
}
}catch (CloudRuntimeException e) {
err = e.getMessage();
}
} else if (srcType == DataObjectType.TEMPLATE && dstType == DataObjectType.TEMPLATE) {
// copy template to primary storage
TemplateInfo tinfo = (TemplateInfo)dstData;
Long size = tinfo.getSize();
if(size == null || size == 0)
size = 1L*1024*1024*1024;
SpConnectionDesc conn = StorPoolUtil.getSpConnection(dstData.getDataStore().getUuid(), dstData.getDataStore().getId(), storagePoolDetailsDao, primaryStoreDao);
TemplateDataStoreVO templDataStoreVO = vmTemplateDataStoreDao.findByTemplate(tinfo.getId(), DataStoreRole.Image);
String snapshotName = (templDataStoreVO != null && templDataStoreVO.getLocalDownloadPath() != null)
? StorPoolStorageAdaptor.getVolumeNameFromPath(templDataStoreVO.getLocalDownloadPath(), true)
: null;
String name = tinfo.getUuid();
SpApiResponse resp = null;
if (snapshotName != null) {
//no need to copy volume from secondary, because we have it already on primary. Just need to create a child snapshot from it.
//The child snapshot is needed when configuration "storage.cleanup.enabled" is true, not to clean the base snapshot and to lose everything
resp = StorPoolUtil.volumeCreate(name, snapshotName, size, null, "no", "template", null, conn);
if (resp.getError() != null) {
err = String.format("Could not create Storpool volume for CS template %s. Error: %s", name, resp.getError());
} else {
String volumeNameToSnapshot = StorPoolUtil.getNameFromResponse(resp, true);
TemplateObjectTO dstTO = (TemplateObjectTO) dstData.getTO();
answer = createVolumeSnapshot(cmd, size, conn, volumeNameToSnapshot, dstTO);
StorPoolUtil.volumeDelete(volumeNameToSnapshot, conn);
}
} else {
resp = StorPoolUtil.volumeCreate(name, null, size, null, "no", "template", null, conn);
if (resp.getError() != null) {
err = String.format("Could not create Storpool volume for CS template %s. Error: %s", name, resp.getError());
} else {
String volName = StorPoolUtil.getNameFromResponse(resp, true);
TemplateObjectTO dstTO = (TemplateObjectTO)dstData.getTO();
dstTO.setPath(StorPoolUtil.devPath(StorPoolUtil.getNameFromResponse(resp, false)));
dstTO.setSize(size);
cmd = new StorPoolDownloadTemplateCommand(srcData.getTO(), dstTO, StorPoolHelper.getTimeout(StorPoolHelper.PrimaryStorageDownloadWait, configDao), VirtualMachineManager.ExecuteInSequence.value(), "volume");
EndPoint ep = selector.select(srcData, dstData);
if (ep == null) {
err = "No remote endpoint to send command, check if host or ssvm is down?";
} else {
answer = ep.sendMessage(cmd);
}
if (answer != null && answer.getResult()) {
// successfully downloaded template to primary storage
TemplateObjectTO templ = (TemplateObjectTO) ((CopyCmdAnswer) answer).getNewData();
answer = createVolumeSnapshot(cmd, size, conn, volName, templ);
} else {
err = answer != null ? answer.getDetails() : "Unknown error while downloading template. Null answer returned.";
}
StorPoolUtil.volumeDelete(volName, conn);
}
}
} else if (srcType == DataObjectType.TEMPLATE && dstType == DataObjectType.VOLUME) {
// create volume from template on Storpool PRIMARY
TemplateInfo tinfo = (TemplateInfo)srcData;
VolumeInfo vinfo = (VolumeInfo) dstData;
VMTemplateStoragePoolVO templStoragePoolVO = StorPoolHelper.findByPoolTemplate(vinfo.getPoolId(),
tinfo.getId());
final String parentName = templStoragePoolVO.getLocalDownloadPath() != null
? StorPoolStorageAdaptor.getVolumeNameFromPath(templStoragePoolVO.getLocalDownloadPath(), true)
: StorPoolStorageAdaptor.getVolumeNameFromPath(templStoragePoolVO.getInstallPath(), true);
final String name = vinfo.getUuid();
SpConnectionDesc conn = StorPoolUtil.getSpConnection(vinfo.getDataStore().getUuid(),
vinfo.getDataStore().getId(), storagePoolDetailsDao, primaryStoreDao);
Long snapshotSize = templStoragePoolVO.getTemplateSize();
boolean withoutEncryption = vinfo.getPassphraseId() == null;
long size = withoutEncryption ? vinfo.getSize() : vinfo.getSize() + 2097152;
if (snapshotSize != null && size < snapshotSize) {
StorPoolUtil.spLog(String.format("provided size is too small for snapshot. Provided %d, snapshot %d. Using snapshot size", size, snapshotSize));
size = withoutEncryption ? snapshotSize : snapshotSize + 2097152;
}
StorPoolUtil.spLog(String.format("volume size is: %d", size));
Long vmId = vinfo.getInstanceId();
String template = null;
String tier = null;
SpApiResponse resp = new SpApiResponse();
if (vinfo.getDiskOfferingId() != null) {
tier = getTierFromOfferingDetail(vinfo.getDiskOfferingId());
if (tier == null) {
template = getTemplateFromOfferingDetail(vinfo.getDiskOfferingId());
}
}
if (tier != null || template != null) {
Map<String, String> tags = StorPoolHelper.addStorPoolTags(name, getVMInstanceUUID(vmId), "volume", getVcPolicyTag(vmId), tier);
StorPoolUtil.spLog(
"Creating volume [%s] with template [%s] or tier tags [%s] described in disk/service offerings details",
vinfo.getUuid(), template, tier);
resp = StorPoolUtil.volumeCreate(size, parentName, template, tags, conn);
} else {
resp = StorPoolUtil.volumeCreate(name, parentName, size, getVMInstanceUUID(vmId),
getVcPolicyTag(vmId), "volume", vinfo.getMaxIops(), conn);
}
if (resp.getError() == null) {
updateStoragePool(dstData.getDataStore().getId(), vinfo.getSize());
updateVolumePoolType(vinfo);
if (withoutEncryption) {
VolumeObjectTO to = updateVolumeObjectTO(vinfo, resp);
answer = new CopyCmdAnswer(to);
} else {
VolumeObjectTO volume = updateVolumeObjectTO(vinfo, resp);
String snapshotPath = StorPoolUtil.devPath(parentName.split("~")[1]);
answer = createEncryptedVolume(dstData.getDataStore(), dstData, vinfo, size, volume, snapshotPath, false);
if (answer.getResult()) {
answer = new CopyCmdAnswer(((StorPoolSetVolumeEncryptionAnswer) answer).getVolume());
}
}
} else {
err = String.format("Could not create Storpool volume %s. Error: %s", name, resp.getError());
}
} else if (srcType == DataObjectType.VOLUME && dstType == DataObjectType.VOLUME) {
StorPoolUtil.spLog("StorpoolPrimaryDataStoreDriver.copyAsync src Data Store=%s", srcData.getDataStore().getDriver());
VolumeInfo dstInfo = (VolumeInfo)dstData;
VolumeInfo srcInfo = (VolumeInfo) srcData;
if( !(srcData.getDataStore().getDriver() instanceof StorPoolPrimaryDataStoreDriver ) ) {
// copy "VOLUME" to primary storage
String name = dstInfo.getUuid();
Long size = dstInfo.getSize();
if(size == null || size == 0)
size = 1L*1024*1024*1024;
SpConnectionDesc conn = StorPoolUtil.getSpConnection(dstData.getDataStore().getUuid(), dstData.getDataStore().getId(), storagePoolDetailsDao, primaryStoreDao);
Long vmId = srcInfo.getInstanceId();
SpApiResponse resp = StorPoolUtil.volumeCreate(name, null, size, getVMInstanceUUID(vmId), getVcPolicyTag(vmId), "volume", dstInfo.getMaxIops(), conn);
if (resp.getError() != null) {
err = String.format("Could not create Storpool volume for CS template %s. Error: %s", name, resp.getError());
} else {
//updateVolume(dstData.getId());
VolumeObjectTO dstTO = (VolumeObjectTO)dstData.getTO();
dstTO.setPath(StorPoolUtil.devPath(StorPoolUtil.getNameFromResponse(resp, false)));
dstTO.setSize(size);
cmd = new StorPoolDownloadVolumeCommand(srcData.getTO(), dstTO, StorPoolHelper.getTimeout(StorPoolHelper.PrimaryStorageDownloadWait, configDao), VirtualMachineManager.ExecuteInSequence.value());
EndPoint ep = selector.select(srcData, dstData);
if (ep == null || storagePoolHostDao.findByPoolHost(dstData.getId(), ep.getId()) == null) {
StorPoolUtil.spLog("select(srcData, dstData) returned NULL or the destination pool is not connected to the selected host. Trying dstData");
ep = selector.select(dstData); // Storpool is zone
}
if (ep == null) {
err = "No remote endpoint to send command, check if host or ssvm is down?";
} else {
StorPoolUtil.spLog("Sending command to %s", ep.getHostAddr());
answer = ep.sendMessage(cmd);
if (answer != null && answer.getResult()) {
// successfully downloaded volume to primary storage
} else {
err = answer != null ? answer.getDetails() : "Unknown error while downloading volume. Null answer returned.";
}
}
if (err != null) {
SpApiResponse resp3 = StorPoolUtil.volumeDelete(name, conn);
if (resp3.getError() != null) {
logger.warn(String.format("Could not clean-up Storpool volume %s. Error: %s", name, resp3.getError()));
}
}
}
} else {
// download volume - first copies to secondary
VolumeObjectTO srcTO = (VolumeObjectTO)srcData.getTO();
StorPoolUtil.spLog("StorpoolPrimaryDataStoreDriverImpl.copyAsnc SRC path=%s DST canonicalName=%s ", srcTO.getPath(), dstData.getDataStore().getClass().getCanonicalName());
PrimaryDataStoreTO checkStoragePool = dstData.getTO().getDataStore() instanceof PrimaryDataStoreTO ? (PrimaryDataStoreTO)dstData.getTO().getDataStore() : null;
final String volumeName = StorPoolStorageAdaptor.getVolumeNameFromPath(srcTO.getPath(), true);
if (checkStoragePool != null && checkStoragePool.getPoolType().equals(StoragePoolType.StorPool)) {
answer = migrateVolumeToStorPool(srcData, dstData, srcInfo, srcTO, volumeName);
} else {
SpConnectionDesc conn = StorPoolUtil.getSpConnection(srcData.getDataStore().getUuid(), srcData.getDataStore().getId(), storagePoolDetailsDao, primaryStoreDao);
final SpApiResponse resp = StorPoolUtil.volumeSnapshot(volumeName, srcTO.getUuid(), srcInfo.getInstanceId() != null ? getVMInstanceUUID(srcInfo.getInstanceId()) : null, "temporary", null, conn);
String snapshotName = StorPoolUtil.getSnapshotNameFromResponse(resp, true, StorPoolUtil.GLOBAL_ID);
if (resp.getError() == null) {
srcTO.setPath(StorPoolUtil.devPath(
StorPoolUtil.getSnapshotNameFromResponse(resp, false, StorPoolUtil.GLOBAL_ID)));
cmd = new StorPoolCopyVolumeToSecondaryCommand(srcTO, dstData.getTO(), StorPoolHelper.getTimeout(StorPoolHelper.CopyVolumeWait, configDao), VirtualMachineManager.ExecuteInSequence.value());
StorPoolUtil.spLog("StorpoolPrimaryDataStoreDriverImpl.copyAsnc command=%s ", cmd);
try {
Long clusterId = StorPoolHelper.findClusterIdByGlobalId(snapshotName, clusterDao);
EndPoint ep = clusterId != null ? RemoteHostEndPoint.getHypervisorHostEndPoint(StorPoolHelper.findHostByCluster(clusterId, hostDao)) : selector.select(srcData, dstData);
StorPoolUtil.spLog("selector.select(srcData, dstData) ", ep);
if (ep == null) {
ep = selector.select(dstData);
StorPoolUtil.spLog("selector.select(srcData) ", ep);
}
if (ep == null) {
err = "No remote endpoint to send command, check if host or ssvm is down?";
} else {
answer = ep.sendMessage(cmd);
StorPoolUtil.spLog("Answer: details=%s, result=%s", answer.getDetails(), answer.getResult());
}
} catch (CloudRuntimeException e) {
err = e.getMessage();
}
} else {
err = String.format("Failed to create temporary StorPool snapshot while trying to download volume %s (uuid %s). Error: %s", srcTO.getName(), srcTO.getUuid(), resp.getError());
}
final SpApiResponse resp2 = StorPoolUtil.snapshotDelete(snapshotName, conn);
if (resp2.getError() != null) {
final String err2 = String.format("Failed to delete temporary StorPool snapshot %s. Error: %s", StorPoolUtil.getNameFromResponse(resp, true), resp2.getError());
logger.error(err2);
StorPoolUtil.spLog(err2);
}
}
}
} else {
err = String.format("Unsupported copy operation from %s (type %s) to %s (type %s)", srcData.getUuid(), srcType, dstData.getUuid(), dstType);
}
} catch (Exception e) {
StorPoolUtil.spLog("Caught exception: %s", e.toString());
err = e.toString();
}
if (answer != null && !answer.getResult()) {
err = answer.getDetails();
}
if (err != null) {
StorPoolUtil.spLog("Failed due to %s", err);
logger.error(err);
answer = new Answer(cmd, false, err);
}
CopyCommandResult res = new CopyCommandResult(null, answer);
res.setResult(err);
callback.complete(res);
}