use of org.apache.cloudstack.storage.command.CopyCmdAnswer in project cloudstack by apache.
the class StorageSystemDataMotionStrategy method handleCreateVolumeFromSnapshotBothOnStorageSystem.
private void handleCreateVolumeFromSnapshotBothOnStorageSystem(SnapshotInfo snapshotInfo, VolumeInfo volumeInfo, AsyncCompletionCallback<CopyCommandResult> callback) {
CopyCmdAnswer copyCmdAnswer = null;
String errMsg = null;
try {
HostVO hostVO = getHost(snapshotInfo);
boolean usingBackendSnapshot = usingBackendSnapshotFor(snapshotInfo);
boolean computeClusterSupportsResign = clusterDao.getSupportsResigning(hostVO.getClusterId());
if (usingBackendSnapshot && !computeClusterSupportsResign) {
String noSupportForResignErrMsg = "Unable to locate an applicable host with which to perform a resignature operation : Cluster ID = " + hostVO.getClusterId();
LOGGER.warn(noSupportForResignErrMsg);
throw new CloudRuntimeException(noSupportForResignErrMsg);
}
boolean canStorageSystemCreateVolumeFromVolume = canStorageSystemCreateVolumeFromVolume(snapshotInfo);
boolean useCloning = usingBackendSnapshot || (canStorageSystemCreateVolumeFromVolume && computeClusterSupportsResign);
VolumeDetailVO volumeDetail = null;
if (useCloning) {
volumeDetail = new VolumeDetailVO(volumeInfo.getId(), "cloneOfSnapshot", String.valueOf(snapshotInfo.getId()), false);
volumeDetail = volumeDetailsDao.persist(volumeDetail);
}
// at this point, the snapshotInfo and volumeInfo should have the same disk offering ID (so either one should be OK to get a DiskOfferingVO instance)
DiskOfferingVO diskOffering = _diskOfferingDao.findByIdIncludingRemoved(volumeInfo.getDiskOfferingId());
SnapshotVO snapshot = _snapshotDao.findById(snapshotInfo.getId());
// update the volume's hv_ss_reserve (hypervisor snapshot reserve) from a disk offering (used for managed storage)
_volumeService.updateHypervisorSnapshotReserveForVolume(diskOffering, volumeInfo.getId(), snapshot.getHypervisorType());
AsyncCallFuture<VolumeApiResult> future = _volumeService.createVolumeAsync(volumeInfo, volumeInfo.getDataStore());
VolumeApiResult result = future.get();
if (volumeDetail != null) {
volumeDetailsDao.remove(volumeDetail.getId());
}
if (result.isFailed()) {
LOGGER.warn("Failed to create a volume: " + result.getResult());
throw new CloudRuntimeException(result.getResult());
}
volumeInfo = _volumeDataFactory.getVolume(volumeInfo.getId(), volumeInfo.getDataStore());
volumeInfo.processEvent(Event.MigrationRequested);
volumeInfo = _volumeDataFactory.getVolume(volumeInfo.getId(), volumeInfo.getDataStore());
if (useCloning) {
copyCmdAnswer = performResignature(volumeInfo, hostVO);
} else {
// asking for a XenServer host here so we don't always prefer to use XenServer hosts that support resigning
// even when we don't need those hosts to do this kind of copy work
hostVO = getHost(snapshotInfo.getDataCenterId(), false);
copyCmdAnswer = performCopyOfVdi(volumeInfo, snapshotInfo, hostVO);
}
if (copyCmdAnswer == null || !copyCmdAnswer.getResult()) {
if (copyCmdAnswer != null && !StringUtils.isEmpty(copyCmdAnswer.getDetails())) {
errMsg = copyCmdAnswer.getDetails();
} else {
errMsg = "Unable to create volume from snapshot";
}
}
} catch (Exception ex) {
errMsg = ex.getMessage() != null ? ex.getMessage() : "Copy operation failed in 'StorageSystemDataMotionStrategy.handleCreateVolumeFromSnapshotBothOnStorageSystem'";
}
CopyCommandResult result = new CopyCommandResult(null, copyCmdAnswer);
result.setResult(errMsg);
callback.complete(result);
}
use of org.apache.cloudstack.storage.command.CopyCmdAnswer in project cloudstack by apache.
the class StorageSystemDataMotionStrategy method performResignature.
private CopyCmdAnswer performResignature(DataObject dataObj, HostVO hostVO, boolean keepGrantedAccess) {
long storagePoolId = dataObj.getDataStore().getId();
DataStore dataStore = dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary);
Map<String, String> details = getDetails(dataObj);
ResignatureCommand command = new ResignatureCommand(details);
ResignatureAnswer answer = null;
try {
_volumeService.grantAccess(dataObj, hostVO, dataStore);
answer = (ResignatureAnswer) _agentMgr.send(hostVO.getId(), command);
} catch (CloudRuntimeException | AgentUnavailableException | OperationTimedoutException ex) {
keepGrantedAccess = false;
String msg = "Failed to resign the DataObject with the following ID: " + dataObj.getId();
LOGGER.warn(msg, ex);
throw new CloudRuntimeException(msg + ex.getMessage());
} finally {
if (keepGrantedAccess == false) {
_volumeService.revokeAccess(dataObj, hostVO, dataStore);
}
}
if (answer == null || !answer.getResult()) {
final String errMsg;
if (answer != null && answer.getDetails() != null && !answer.getDetails().isEmpty()) {
errMsg = answer.getDetails();
} else {
errMsg = "Unable to perform resignature operation in 'StorageSystemDataMotionStrategy.performResignature'";
}
throw new CloudRuntimeException(errMsg);
}
VolumeObjectTO newVolume = new VolumeObjectTO();
newVolume.setSize(answer.getSize());
newVolume.setPath(answer.getPath());
newVolume.setFormat(answer.getFormat());
return new CopyCmdAnswer(newVolume);
}
use of org.apache.cloudstack.storage.command.CopyCmdAnswer in project cloudstack by apache.
the class StorageSystemDataMotionStrategy method handleCreateVolumeFromTemplateBothOnStorageSystem.
/**
* Clones a template present on the storage to a new volume and resignatures it.
*
* @param templateInfo source template
* @param volumeInfo destination ROOT volume
* @param callback for async
*/
private void handleCreateVolumeFromTemplateBothOnStorageSystem(TemplateInfo templateInfo, VolumeInfo volumeInfo, AsyncCompletionCallback<CopyCommandResult> callback) {
Preconditions.checkArgument(templateInfo != null, "Passing 'null' to templateInfo of handleCreateVolumeFromTemplateBothOnStorageSystem is not supported.");
Preconditions.checkArgument(volumeInfo != null, "Passing 'null' to volumeInfo of handleCreateVolumeFromTemplateBothOnStorageSystem is not supported.");
CopyCmdAnswer copyCmdAnswer = null;
String errMsg = null;
HostVO hostVO = getHost(volumeInfo.getDataCenterId(), true);
if (hostVO == null) {
throw new CloudRuntimeException("Unable to locate a host capable of resigning in the zone with the following ID: " + volumeInfo.getDataCenterId());
}
boolean computeClusterSupportsResign = clusterDao.getSupportsResigning(hostVO.getClusterId());
if (!computeClusterSupportsResign) {
String noSupportForResignErrMsg = "Unable to locate an applicable host with which to perform a resignature operation : Cluster ID = " + hostVO.getClusterId();
LOGGER.warn(noSupportForResignErrMsg);
throw new CloudRuntimeException(noSupportForResignErrMsg);
}
try {
VolumeDetailVO volumeDetail = new VolumeDetailVO(volumeInfo.getId(), "cloneOfTemplate", String.valueOf(templateInfo.getId()), false);
volumeDetail = volumeDetailsDao.persist(volumeDetail);
AsyncCallFuture<VolumeApiResult> future = _volumeService.createVolumeAsync(volumeInfo, volumeInfo.getDataStore());
int storagePoolMaxWaitSeconds = NumbersUtil.parseInt(_configDao.getValue(Config.StoragePoolMaxWaitSeconds.key()), 3600);
VolumeApiResult result = future.get(storagePoolMaxWaitSeconds, TimeUnit.SECONDS);
if (volumeDetail != null) {
volumeDetailsDao.remove(volumeDetail.getId());
}
if (result.isFailed()) {
LOGGER.warn("Failed to create a volume: " + result.getResult());
throw new CloudRuntimeException(result.getResult());
}
volumeInfo = _volumeDataFactory.getVolume(volumeInfo.getId(), volumeInfo.getDataStore());
volumeInfo.processEvent(Event.MigrationRequested);
volumeInfo = _volumeDataFactory.getVolume(volumeInfo.getId(), volumeInfo.getDataStore());
copyCmdAnswer = performResignature(volumeInfo, hostVO);
if (copyCmdAnswer == null || !copyCmdAnswer.getResult()) {
if (copyCmdAnswer != null && !StringUtils.isEmpty(copyCmdAnswer.getDetails())) {
throw new CloudRuntimeException(copyCmdAnswer.getDetails());
} else {
throw new CloudRuntimeException("Unable to create a volume from a template");
}
}
} catch (InterruptedException | ExecutionException | TimeoutException ex) {
volumeInfo.getDataStore().getDriver().deleteAsync(volumeInfo.getDataStore(), volumeInfo, null);
throw new CloudRuntimeException("Create volume from template (ID = " + templateInfo.getId() + ") failed " + ex.getMessage());
}
CopyCommandResult result = new CopyCommandResult(null, copyCmdAnswer);
result.setResult(errMsg);
callback.complete(result);
}
use of org.apache.cloudstack.storage.command.CopyCmdAnswer in project cloudstack by apache.
the class KVMStorageProcessor method backupSnapshot.
@Override
public Answer backupSnapshot(final CopyCommand cmd) {
final DataTO srcData = cmd.getSrcTO();
final DataTO destData = cmd.getDestTO();
final SnapshotObjectTO snapshot = (SnapshotObjectTO) srcData;
final PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO) snapshot.getDataStore();
final SnapshotObjectTO destSnapshot = (SnapshotObjectTO) destData;
final DataStoreTO imageStore = destData.getDataStore();
if (!(imageStore instanceof NfsTO)) {
return backupSnapshotForObjectStore(cmd);
}
final NfsTO nfsImageStore = (NfsTO) imageStore;
final String secondaryStoragePoolUrl = nfsImageStore.getUrl();
// NOTE: snapshot name is encoded in snapshot path
final int index = snapshot.getPath().lastIndexOf("/");
// -1 means the snapshot is created from existing vm snapshot
final boolean isCreatedFromVmSnapshot = (index == -1) ? true : false;
final String snapshotName = snapshot.getPath().substring(index + 1);
String descName = snapshotName;
final String volumePath = snapshot.getVolume().getPath();
String snapshotDestPath = null;
String snapshotRelPath = null;
final String vmName = snapshot.getVmName();
KVMStoragePool secondaryStoragePool = null;
Connect conn = null;
KVMPhysicalDisk snapshotDisk = null;
KVMStoragePool primaryPool = null;
try {
conn = LibvirtConnection.getConnectionByVmName(vmName);
secondaryStoragePool = storagePoolMgr.getStoragePoolByURI(secondaryStoragePoolUrl);
final String ssPmountPath = secondaryStoragePool.getLocalPath();
snapshotRelPath = destSnapshot.getPath();
snapshotDestPath = ssPmountPath + File.separator + snapshotRelPath;
snapshotDisk = storagePoolMgr.getPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), volumePath);
primaryPool = snapshotDisk.getPool();
long size = 0;
/**
* Since Ceph version Dumpling (0.67.X) librbd / Qemu supports converting RBD
* snapshots to RAW/QCOW2 files directly.
*
* This reduces the amount of time and storage it takes to back up a snapshot dramatically
*/
if (primaryPool.getType() == StoragePoolType.RBD) {
final String rbdSnapshot = snapshotDisk.getPath() + "@" + snapshotName;
final String snapshotFile = snapshotDestPath + "/" + snapshotName;
try {
s_logger.debug("Attempting to backup RBD snapshot " + rbdSnapshot);
final File snapDir = new File(snapshotDestPath);
s_logger.debug("Attempting to create " + snapDir.getAbsolutePath() + " recursively for snapshot storage");
FileUtils.forceMkdir(snapDir);
final QemuImgFile srcFile = new QemuImgFile(KVMPhysicalDisk.RBDStringBuilder(primaryPool.getSourceHost(), primaryPool.getSourcePort(), primaryPool.getAuthUserName(), primaryPool.getAuthSecret(), rbdSnapshot));
srcFile.setFormat(snapshotDisk.getFormat());
final QemuImgFile destFile = new QemuImgFile(snapshotFile);
destFile.setFormat(PhysicalDiskFormat.QCOW2);
s_logger.debug("Backing up RBD snapshot " + rbdSnapshot + " to " + snapshotFile);
final QemuImg q = new QemuImg(cmd.getWaitInMillSeconds());
q.convert(srcFile, destFile);
final File snapFile = new File(snapshotFile);
if (snapFile.exists()) {
size = snapFile.length();
}
s_logger.debug("Finished backing up RBD snapshot " + rbdSnapshot + " to " + snapshotFile + " Snapshot size: " + size);
} catch (final FileNotFoundException e) {
s_logger.error("Failed to open " + snapshotDestPath + ". The error was: " + e.getMessage());
return new CopyCmdAnswer(e.toString());
} catch (final IOException e) {
s_logger.error("Failed to create " + snapshotDestPath + ". The error was: " + e.getMessage());
return new CopyCmdAnswer(e.toString());
} catch (final QemuImgException e) {
s_logger.error("Failed to backup the RBD snapshot from " + rbdSnapshot + " to " + snapshotFile + " the error was: " + e.getMessage());
return new CopyCmdAnswer(e.toString());
}
} else {
final Script command = new Script(_manageSnapshotPath, cmd.getWaitInMillSeconds(), s_logger);
command.add("-b", snapshotDisk.getPath());
command.add("-n", snapshotName);
command.add("-p", snapshotDestPath);
if (isCreatedFromVmSnapshot) {
descName = UUID.randomUUID().toString();
}
command.add("-t", descName);
final String result = command.execute();
if (result != null) {
s_logger.debug("Failed to backup snaptshot: " + result);
return new CopyCmdAnswer(result);
}
final File snapFile = new File(snapshotDestPath + "/" + descName);
if (snapFile.exists()) {
size = snapFile.length();
}
}
final SnapshotObjectTO newSnapshot = new SnapshotObjectTO();
newSnapshot.setPath(snapshotRelPath + File.separator + descName);
newSnapshot.setPhysicalSize(size);
return new CopyCmdAnswer(newSnapshot);
} catch (final LibvirtException e) {
s_logger.debug("Failed to backup snapshot: ", e);
return new CopyCmdAnswer(e.toString());
} catch (final CloudRuntimeException e) {
s_logger.debug("Failed to backup snapshot: ", e);
return new CopyCmdAnswer(e.toString());
} finally {
if (isCreatedFromVmSnapshot) {
s_logger.debug("Ignoring removal of vm snapshot on primary as this snapshot is created from vm snapshot");
} else {
try {
/* Delete the snapshot on primary */
DomainInfo.DomainState state = null;
Domain vm = null;
if (vmName != null) {
try {
vm = resource.getDomain(conn, vmName);
state = vm.getInfo().state;
} catch (final LibvirtException e) {
s_logger.trace("Ignoring libvirt error.", e);
}
}
final KVMStoragePool primaryStorage = storagePoolMgr.getStoragePool(primaryStore.getPoolType(), primaryStore.getUuid());
if (state == DomainInfo.DomainState.VIR_DOMAIN_RUNNING && !primaryStorage.isExternalSnapshot()) {
final DomainSnapshot snap = vm.snapshotLookupByName(snapshotName);
snap.delete(0);
/*
* libvirt on RHEL6 doesn't handle resume event emitted from
* qemu
*/
vm = resource.getDomain(conn, vmName);
state = vm.getInfo().state;
if (state == DomainInfo.DomainState.VIR_DOMAIN_PAUSED) {
vm.resume();
}
} else {
if (primaryPool.getType() != StoragePoolType.RBD) {
final Script command = new Script(_manageSnapshotPath, _cmdsTimeout, s_logger);
command.add("-d", snapshotDisk.getPath());
command.add("-n", snapshotName);
final String result = command.execute();
if (result != null) {
s_logger.debug("Failed to delete snapshot on primary: " + result);
// return new CopyCmdAnswer("Failed to backup snapshot: " + result);
}
}
}
} catch (final Exception ex) {
s_logger.debug("Failed to delete snapshots on primary", ex);
}
}
try {
if (secondaryStoragePool != null) {
secondaryStoragePool.delete();
}
} catch (final Exception ex) {
s_logger.debug("Failed to delete secondary storage", ex);
}
}
}
use of org.apache.cloudstack.storage.command.CopyCmdAnswer in project cloudstack by apache.
the class KVMStorageProcessor method copyToObjectStore.
protected Answer copyToObjectStore(final CopyCommand cmd) {
final DataTO srcData = cmd.getSrcTO();
final DataTO destData = cmd.getDestTO();
final DataStoreTO imageStore = destData.getDataStore();
final NfsTO srcStore = (NfsTO) srcData.getDataStore();
final String srcPath = srcData.getPath();
final int index = srcPath.lastIndexOf(File.separator);
final String srcSnapshotDir = srcPath.substring(0, index);
final String srcFileName = srcPath.substring(index + 1);
KVMStoragePool srcStorePool = null;
File srcFile = null;
try {
srcStorePool = storagePoolMgr.getStoragePoolByURI(srcStore.getUrl() + File.separator + srcSnapshotDir);
if (srcStorePool == null) {
return new CopyCmdAnswer("Can't get store:" + srcStore.getUrl());
}
srcFile = new File(srcStorePool.getLocalPath() + File.separator + srcFileName);
if (!srcFile.exists()) {
return new CopyCmdAnswer("Can't find src file: " + srcPath);
}
String destPath = null;
if (imageStore instanceof S3TO) {
destPath = copyToS3(srcFile, (S3TO) imageStore, destData.getPath());
} else {
return new CopyCmdAnswer("Unsupported protocol");
}
final SnapshotObjectTO newSnapshot = new SnapshotObjectTO();
newSnapshot.setPath(destPath);
return new CopyCmdAnswer(newSnapshot);
} catch (final Exception e) {
s_logger.error("failed to upload" + srcPath, e);
return new CopyCmdAnswer("failed to upload" + srcPath + e.toString());
} finally {
try {
if (srcFile != null) {
srcFile.delete();
}
if (srcStorePool != null) {
srcStorePool.delete();
}
} catch (final Exception e) {
s_logger.debug("Failed to clean up:", e);
}
}
}
Aggregations