use of com.ceph.rbd.Rbd in project cloudstack by apache.
the class KVMStorageProcessor method deleteSnapshot.
@Override
public Answer deleteSnapshot(final DeleteCommand cmd) {
String snap_full_name = "";
try {
SnapshotObjectTO snapshotTO = (SnapshotObjectTO) cmd.getData();
PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO) snapshotTO.getDataStore();
VolumeObjectTO volume = snapshotTO.getVolume();
KVMStoragePool primaryPool = storagePoolMgr.getStoragePool(primaryStore.getPoolType(), primaryStore.getUuid());
KVMPhysicalDisk disk = storagePoolMgr.getPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), volume.getPath());
String snapshotFullPath = snapshotTO.getPath();
String snapshotName = snapshotFullPath.substring(snapshotFullPath.lastIndexOf("/") + 1);
snap_full_name = disk.getName() + "@" + snapshotName;
if (primaryPool.getType() == StoragePoolType.RBD) {
Rados r = radosConnect(primaryPool);
IoCTX io = r.ioCtxCreate(primaryPool.getSourceDir());
Rbd rbd = new Rbd(io);
RbdImage image = rbd.open(disk.getName());
try {
s_logger.info("Attempting to remove RBD snapshot " + snap_full_name);
if (image.snapIsProtected(snapshotName)) {
s_logger.debug("Unprotecting RBD snapshot " + snap_full_name);
image.snapUnprotect(snapshotName);
}
image.snapRemove(snapshotName);
s_logger.info("Snapshot " + snap_full_name + " successfully removed from " + primaryPool.getType().toString() + " pool.");
} catch (RbdException e) {
s_logger.error("Failed to remove snapshot " + snap_full_name + ", with exception: " + e.toString() + ", RBD error: " + ErrorCode.getErrorMessage(e.getReturnValue()));
} finally {
rbd.close(image);
r.ioCtxDestroy(io);
}
} else if (primaryPool.getType() == StoragePoolType.NetworkFilesystem || primaryPool.getType() == StoragePoolType.Filesystem) {
s_logger.info(String.format("Deleting snapshot (id=%s, name=%s, path=%s, storage type=%s) on primary storage", snapshotTO.getId(), snapshotTO.getName(), snapshotTO.getPath(), primaryPool.getType()));
deleteSnapshotViaManageSnapshotScript(snapshotName, disk);
} else {
s_logger.warn("Operation not implemented for storage pool type of " + primaryPool.getType().toString());
throw new InternalErrorException("Operation not implemented for storage pool type of " + primaryPool.getType().toString());
}
return new Answer(cmd, true, "Snapshot " + snap_full_name + " removed successfully.");
} catch (RadosException e) {
s_logger.error("Failed to remove snapshot " + snap_full_name + ", with exception: " + e.toString() + ", RBD error: " + ErrorCode.getErrorMessage(e.getReturnValue()));
return new Answer(cmd, false, "Failed to remove snapshot " + snap_full_name);
} catch (RbdException e) {
s_logger.error("Failed to remove snapshot " + snap_full_name + ", with exception: " + e.toString() + ", RBD error: " + ErrorCode.getErrorMessage(e.getReturnValue()));
return new Answer(cmd, false, "Failed to remove snapshot " + snap_full_name);
} catch (Exception e) {
s_logger.error("Failed to remove snapshot " + snap_full_name + ", with exception: " + e.toString());
return new Answer(cmd, false, "Failed to remove snapshot " + snap_full_name);
}
}
use of com.ceph.rbd.Rbd in project cloudstack by apache.
the class KVMStorageProcessor method createRBDvolumeFromRBDSnapshot.
private KVMPhysicalDisk createRBDvolumeFromRBDSnapshot(KVMPhysicalDisk volume, String snapshotName, String name, PhysicalDiskFormat format, long size, KVMStoragePool destPool, int timeout) {
KVMStoragePool srcPool = volume.getPool();
KVMPhysicalDisk disk = null;
String newUuid = name;
disk = new KVMPhysicalDisk(destPool.getSourceDir() + "/" + newUuid, newUuid, destPool);
disk.setFormat(format);
disk.setSize(size > volume.getVirtualSize() ? size : volume.getVirtualSize());
disk.setVirtualSize(size > volume.getVirtualSize() ? size : disk.getSize());
try {
Rados r = new Rados(srcPool.getAuthUserName());
r.confSet("mon_host", srcPool.getSourceHost() + ":" + srcPool.getSourcePort());
r.confSet("key", srcPool.getAuthSecret());
r.confSet("client_mount_timeout", "30");
r.connect();
IoCTX io = r.ioCtxCreate(srcPool.getSourceDir());
Rbd rbd = new Rbd(io);
RbdImage srcImage = rbd.open(volume.getName());
List<RbdSnapInfo> snaps = srcImage.snapList();
boolean snapFound = false;
for (RbdSnapInfo snap : snaps) {
if (snapshotName.equals(snap.name)) {
snapFound = true;
break;
}
}
if (!snapFound) {
s_logger.debug(String.format("Could not find snapshot %s on RBD", snapshotName));
return null;
}
srcImage.snapProtect(snapshotName);
s_logger.debug(String.format("Try to clone snapshot %s on RBD", snapshotName));
rbd.clone(volume.getName(), snapshotName, io, disk.getName(), LibvirtStorageAdaptor.RBD_FEATURES, 0);
RbdImage diskImage = rbd.open(disk.getName());
if (disk.getVirtualSize() > volume.getVirtualSize()) {
diskImage.resize(disk.getVirtualSize());
}
diskImage.flatten();
rbd.close(diskImage);
srcImage.snapUnprotect(snapshotName);
rbd.close(srcImage);
r.ioCtxDestroy(io);
} catch (RadosException | RbdException e) {
s_logger.error(String.format("Failed due to %s", e.getMessage()), e);
disk = null;
}
return disk;
}
use of com.ceph.rbd.Rbd in project cloudstack by apache.
the class LibvirtStorageAdaptor method createDiskFromTemplateOnRBD.
private KVMPhysicalDisk createDiskFromTemplateOnRBD(KVMPhysicalDisk template, String name, PhysicalDiskFormat format, Storage.ProvisioningType provisioningType, long size, KVMStoragePool destPool, int timeout) {
/*
With RBD you can't run qemu-img convert with an existing RBD image as destination
qemu-img will exit with the error that the destination already exists.
So for RBD we don't create the image, but let qemu-img do that for us.
We then create a KVMPhysicalDisk object that we can return
*/
KVMStoragePool srcPool = template.getPool();
KVMPhysicalDisk disk = null;
String newUuid = name;
format = PhysicalDiskFormat.RAW;
disk = new KVMPhysicalDisk(destPool.getSourceDir() + "/" + newUuid, newUuid, destPool);
disk.setFormat(format);
if (size > template.getVirtualSize()) {
disk.setSize(size);
disk.setVirtualSize(size);
} else {
// leave these as they were if size isn't applicable
disk.setSize(template.getVirtualSize());
disk.setVirtualSize(disk.getSize());
}
QemuImg qemu = new QemuImg(timeout);
QemuImgFile srcFile;
QemuImgFile destFile = new QemuImgFile(KVMPhysicalDisk.RBDStringBuilder(destPool.getSourceHost(), destPool.getSourcePort(), destPool.getAuthUserName(), destPool.getAuthSecret(), disk.getPath()));
destFile.setFormat(format);
if (srcPool.getType() != StoragePoolType.RBD) {
srcFile = new QemuImgFile(template.getPath(), template.getFormat());
try {
qemu.convert(srcFile, destFile);
} catch (QemuImgException | LibvirtException e) {
s_logger.error("Failed to create " + disk.getPath() + " due to a failed executing of qemu-img: " + e.getMessage());
}
} else {
try {
if ((srcPool.getSourceHost().equals(destPool.getSourceHost())) && (srcPool.getSourceDir().equals(destPool.getSourceDir()))) {
/* We are on the same Ceph cluster, but we require RBD format 2 on the source image */
s_logger.debug("Trying to perform a RBD clone (layering) since we are operating in the same storage pool");
Rados r = new Rados(srcPool.getAuthUserName());
r.confSet("mon_host", srcPool.getSourceHost() + ":" + srcPool.getSourcePort());
r.confSet("key", srcPool.getAuthSecret());
r.confSet("client_mount_timeout", "30");
r.connect();
s_logger.debug("Succesfully connected to Ceph cluster at " + r.confGet("mon_host"));
IoCTX io = r.ioCtxCreate(srcPool.getSourceDir());
Rbd rbd = new Rbd(io);
RbdImage srcImage = rbd.open(template.getName());
if (srcImage.isOldFormat()) {
/* The source image is RBD format 1, we have to do a regular copy */
s_logger.debug("The source image " + srcPool.getSourceDir() + "/" + template.getName() + " is RBD format 1. We have to perform a regular copy (" + toHumanReadableSize(disk.getVirtualSize()) + " bytes)");
rbd.create(disk.getName(), disk.getVirtualSize(), RBD_FEATURES, rbdOrder);
RbdImage destImage = rbd.open(disk.getName());
s_logger.debug("Starting to copy " + srcImage.getName() + " to " + destImage.getName() + " in Ceph pool " + srcPool.getSourceDir());
rbd.copy(srcImage, destImage);
s_logger.debug("Finished copying " + srcImage.getName() + " to " + destImage.getName() + " in Ceph pool " + srcPool.getSourceDir());
rbd.close(destImage);
} else {
s_logger.debug("The source image " + srcPool.getSourceDir() + "/" + template.getName() + " is RBD format 2. We will perform a RBD clone using snapshot " + rbdTemplateSnapName);
/* The source image is format 2, we can do a RBD snapshot+clone (layering) */
s_logger.debug("Checking if RBD snapshot " + srcPool.getSourceDir() + "/" + template.getName() + "@" + rbdTemplateSnapName + " exists prior to attempting a clone operation.");
List<RbdSnapInfo> snaps = srcImage.snapList();
s_logger.debug("Found " + snaps.size() + " snapshots on RBD image " + srcPool.getSourceDir() + "/" + template.getName());
boolean snapFound = false;
for (RbdSnapInfo snap : snaps) {
if (rbdTemplateSnapName.equals(snap.name)) {
s_logger.debug("RBD snapshot " + srcPool.getSourceDir() + "/" + template.getName() + "@" + rbdTemplateSnapName + " already exists.");
snapFound = true;
break;
}
}
if (!snapFound) {
s_logger.debug("Creating RBD snapshot " + rbdTemplateSnapName + " on image " + name);
srcImage.snapCreate(rbdTemplateSnapName);
s_logger.debug("Protecting RBD snapshot " + rbdTemplateSnapName + " on image " + name);
srcImage.snapProtect(rbdTemplateSnapName);
}
rbd.clone(template.getName(), rbdTemplateSnapName, io, disk.getName(), RBD_FEATURES, rbdOrder);
s_logger.debug("Succesfully cloned " + template.getName() + "@" + rbdTemplateSnapName + " to " + disk.getName());
/* We also need to resize the image if the VM was deployed with a larger root disk size */
if (disk.getVirtualSize() > template.getVirtualSize()) {
RbdImage diskImage = rbd.open(disk.getName());
diskImage.resize(disk.getVirtualSize());
rbd.close(diskImage);
s_logger.debug("Resized " + disk.getName() + " to " + toHumanReadableSize(disk.getVirtualSize()));
}
}
rbd.close(srcImage);
r.ioCtxDestroy(io);
} else {
/* The source pool or host is not the same Ceph cluster, we do a simple copy with Qemu-Img */
s_logger.debug("Both the source and destination are RBD, but not the same Ceph cluster. Performing a copy");
Rados rSrc = new Rados(srcPool.getAuthUserName());
rSrc.confSet("mon_host", srcPool.getSourceHost() + ":" + srcPool.getSourcePort());
rSrc.confSet("key", srcPool.getAuthSecret());
rSrc.confSet("client_mount_timeout", "30");
rSrc.connect();
s_logger.debug("Succesfully connected to source Ceph cluster at " + rSrc.confGet("mon_host"));
Rados rDest = new Rados(destPool.getAuthUserName());
rDest.confSet("mon_host", destPool.getSourceHost() + ":" + destPool.getSourcePort());
rDest.confSet("key", destPool.getAuthSecret());
rDest.confSet("client_mount_timeout", "30");
rDest.connect();
s_logger.debug("Succesfully connected to source Ceph cluster at " + rDest.confGet("mon_host"));
IoCTX sIO = rSrc.ioCtxCreate(srcPool.getSourceDir());
Rbd sRbd = new Rbd(sIO);
IoCTX dIO = rDest.ioCtxCreate(destPool.getSourceDir());
Rbd dRbd = new Rbd(dIO);
s_logger.debug("Creating " + disk.getName() + " on the destination cluster " + rDest.confGet("mon_host") + " in pool " + destPool.getSourceDir());
dRbd.create(disk.getName(), disk.getVirtualSize(), RBD_FEATURES, rbdOrder);
RbdImage srcImage = sRbd.open(template.getName());
RbdImage destImage = dRbd.open(disk.getName());
s_logger.debug("Copying " + template.getName() + " from Ceph cluster " + rSrc.confGet("mon_host") + " to " + disk.getName() + " on cluster " + rDest.confGet("mon_host"));
sRbd.copy(srcImage, destImage);
sRbd.close(srcImage);
dRbd.close(destImage);
rSrc.ioCtxDestroy(sIO);
rDest.ioCtxDestroy(dIO);
}
} catch (RadosException e) {
s_logger.error("Failed to perform a RADOS action on the Ceph cluster, the error was: " + e.getMessage());
disk = null;
} catch (RbdException e) {
s_logger.error("Failed to perform a RBD action on the Ceph cluster, the error was: " + e.getMessage());
disk = null;
}
}
return disk;
}
use of com.ceph.rbd.Rbd in project cloudstack by apache.
the class LibvirtStorageAdaptor method copyPhysicalDisk.
/**
* This copies a volume from Primary Storage to Secondary Storage
*
* In theory it could also do it the other way around, but the current implementation
* in ManagementServerImpl shows that the destPool is always a Secondary Storage Pool
*/
@Override
public KVMPhysicalDisk copyPhysicalDisk(KVMPhysicalDisk disk, String name, KVMStoragePool destPool, int timeout) {
/**
* With RBD you can't run qemu-img convert with an existing RBD image as destination
* qemu-img will exit with the error that the destination already exists.
* So for RBD we don't create the image, but let qemu-img do that for us.
*
* We then create a KVMPhysicalDisk object that we can return
*
* It is however very unlikely that the destPool will be RBD, since it isn't supported
* for Secondary Storage
*/
KVMStoragePool srcPool = disk.getPool();
PhysicalDiskFormat sourceFormat = disk.getFormat();
String sourcePath = disk.getPath();
KVMPhysicalDisk newDisk;
s_logger.debug("copyPhysicalDisk: disk size:" + toHumanReadableSize(disk.getSize()) + ", virtualsize:" + toHumanReadableSize(disk.getVirtualSize()) + " format:" + disk.getFormat());
if (destPool.getType() != StoragePoolType.RBD) {
if (disk.getFormat() == PhysicalDiskFormat.TAR) {
newDisk = destPool.createPhysicalDisk(name, PhysicalDiskFormat.DIR, Storage.ProvisioningType.THIN, disk.getVirtualSize());
} else {
newDisk = destPool.createPhysicalDisk(name, Storage.ProvisioningType.THIN, disk.getVirtualSize());
}
} else {
newDisk = new KVMPhysicalDisk(destPool.getSourceDir() + "/" + name, name, destPool);
newDisk.setFormat(PhysicalDiskFormat.RAW);
newDisk.setSize(disk.getVirtualSize());
newDisk.setVirtualSize(disk.getSize());
}
String destPath = newDisk.getPath();
PhysicalDiskFormat destFormat = newDisk.getFormat();
QemuImg qemu = new QemuImg(timeout);
QemuImgFile srcFile = null;
QemuImgFile destFile = null;
if ((srcPool.getType() != StoragePoolType.RBD) && (destPool.getType() != StoragePoolType.RBD)) {
if (sourceFormat == PhysicalDiskFormat.TAR && destFormat == PhysicalDiskFormat.DIR) {
// LXC template
Script.runSimpleBashScript("cp " + sourcePath + " " + destPath);
} else if (sourceFormat == PhysicalDiskFormat.TAR) {
Script.runSimpleBashScript("tar -x -f " + sourcePath + " -C " + destPath, timeout);
} else if (sourceFormat == PhysicalDiskFormat.DIR) {
Script.runSimpleBashScript("mkdir -p " + destPath);
Script.runSimpleBashScript("chmod 755 " + destPath);
Script.runSimpleBashScript("cp -p -r " + sourcePath + "/* " + destPath, timeout);
} else {
srcFile = new QemuImgFile(sourcePath, sourceFormat);
try {
Map<String, String> info = qemu.info(srcFile);
String backingFile = info.get(QemuImg.BACKING_FILE);
// qcow2 templates can just be copied into place
if (sourceFormat.equals(destFormat) && backingFile == null && sourcePath.endsWith(".qcow2")) {
String result = Script.runSimpleBashScript("cp -f " + sourcePath + " " + destPath, timeout);
if (result != null) {
throw new CloudRuntimeException("Failed to create disk: " + result);
}
} else {
destFile = new QemuImgFile(destPath, destFormat);
try {
qemu.convert(srcFile, destFile);
Map<String, String> destInfo = qemu.info(destFile);
Long virtualSize = Long.parseLong(destInfo.get(QemuImg.VIRTUAL_SIZE));
newDisk.setVirtualSize(virtualSize);
newDisk.setSize(virtualSize);
} catch (QemuImgException | LibvirtException e) {
s_logger.error("Failed to convert " + srcFile.getFileName() + " to " + destFile.getFileName() + " the error was: " + e.getMessage());
newDisk = null;
}
}
} catch (QemuImgException | LibvirtException e) {
s_logger.error("Failed to fetch the information of file " + srcFile.getFileName() + " the error was: " + e.getMessage());
newDisk = null;
}
}
} else if ((srcPool.getType() != StoragePoolType.RBD) && (destPool.getType() == StoragePoolType.RBD)) {
/**
* Using qemu-img we copy the QCOW2 disk to RAW (on RBD) directly.
* To do so it's mandatory that librbd on the system is at least 0.67.7 (Ceph Dumpling)
*/
s_logger.debug("The source image is not RBD, but the destination is. We will convert into RBD format 2");
try {
srcFile = new QemuImgFile(sourcePath, sourceFormat);
String rbdDestPath = destPool.getSourceDir() + "/" + name;
String rbdDestFile = KVMPhysicalDisk.RBDStringBuilder(destPool.getSourceHost(), destPool.getSourcePort(), destPool.getAuthUserName(), destPool.getAuthSecret(), rbdDestPath);
destFile = new QemuImgFile(rbdDestFile, destFormat);
s_logger.debug("Starting copy from source image " + srcFile.getFileName() + " to RBD image " + rbdDestPath);
qemu.convert(srcFile, destFile);
s_logger.debug("Succesfully converted source image " + srcFile.getFileName() + " to RBD image " + rbdDestPath);
/* We have to stat the RBD image to see how big it became afterwards */
Rados r = new Rados(destPool.getAuthUserName());
r.confSet("mon_host", destPool.getSourceHost() + ":" + destPool.getSourcePort());
r.confSet("key", destPool.getAuthSecret());
r.confSet("client_mount_timeout", "30");
r.connect();
s_logger.debug("Succesfully connected to Ceph cluster at " + r.confGet("mon_host"));
IoCTX io = r.ioCtxCreate(destPool.getSourceDir());
Rbd rbd = new Rbd(io);
RbdImage image = rbd.open(name);
RbdImageInfo rbdInfo = image.stat();
newDisk.setSize(rbdInfo.size);
newDisk.setVirtualSize(rbdInfo.size);
s_logger.debug("After copy the resulting RBD image " + rbdDestPath + " is " + toHumanReadableSize(rbdInfo.size) + " bytes long");
rbd.close(image);
r.ioCtxDestroy(io);
} catch (QemuImgException | LibvirtException e) {
s_logger.error("Failed to convert from " + srcFile.getFileName() + " to " + destFile.getFileName() + " the error was: " + e.getMessage());
newDisk = null;
} catch (RadosException e) {
s_logger.error("A Ceph RADOS operation failed (" + e.getReturnValue() + "). The error was: " + e.getMessage());
newDisk = null;
} catch (RbdException e) {
s_logger.error("A Ceph RBD operation failed (" + e.getReturnValue() + "). The error was: " + e.getMessage());
newDisk = null;
}
} else {
/**
* We let Qemu-Img do the work here. Although we could work with librbd and have that do the cloning
* it doesn't benefit us. It's better to keep the current code in place which works
*/
srcFile = new QemuImgFile(KVMPhysicalDisk.RBDStringBuilder(srcPool.getSourceHost(), srcPool.getSourcePort(), srcPool.getAuthUserName(), srcPool.getAuthSecret(), sourcePath));
srcFile.setFormat(sourceFormat);
destFile = new QemuImgFile(destPath);
destFile.setFormat(destFormat);
try {
qemu.convert(srcFile, destFile);
} catch (QemuImgException | LibvirtException e) {
s_logger.error("Failed to convert " + srcFile.getFileName() + " to " + destFile.getFileName() + " the error was: " + e.getMessage());
newDisk = null;
}
}
if (newDisk == null) {
throw new CloudRuntimeException("Failed to copy " + disk.getPath() + " to " + name);
}
return newDisk;
}
use of com.ceph.rbd.Rbd in project cosmic by MissionCriticalCloud.
the class KvmStorageProcessor method createSnapshot.
@Override
public Answer createSnapshot(final CreateObjectCommand cmd) {
final SnapshotObjectTO snapshotTo = (SnapshotObjectTO) cmd.getData();
final PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO) snapshotTo.getDataStore();
final VolumeObjectTO volume = snapshotTo.getVolume();
final String snapshotName = UUID.randomUUID().toString();
final String vmName = volume.getVmName();
try {
final Connect conn = LibvirtConnection.getConnectionByVmName(vmName);
DomainState state = null;
Domain vm = null;
if (vmName != null) {
try {
vm = resource.getDomain(conn, vmName);
state = vm.getInfo().state;
} catch (final LibvirtException e) {
logger.trace("Ignoring libvirt error.", e);
}
}
final KvmStoragePool primaryPool = storagePoolMgr.getStoragePool(primaryStore.getPoolType(), primaryStore.getUuid());
final KvmPhysicalDisk disk = storagePoolMgr.getPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), volume.getPath());
if (state == DomainState.VIR_DOMAIN_RUNNING && !primaryPool.isExternalSnapshot()) {
final String vmUuid = vm.getUUIDString();
final Object[] args = new Object[] { snapshotName, vmUuid };
final String snapshot = SnapshotXML.format(args);
final long start = System.currentTimeMillis();
vm.snapshotCreateXML(snapshot);
final long total = (System.currentTimeMillis() - start) / 1000;
logger.debug("snapshot takes " + total + " seconds to finish");
/*
* libvirt on RHEL6 doesn't handle resume event emitted from qemu
*/
vm = resource.getDomain(conn, vmName);
state = vm.getInfo().state;
if (state == DomainState.VIR_DOMAIN_PAUSED) {
vm.resume();
}
} else {
if (primaryPool.getType() == StoragePoolType.RBD) {
try {
final Rados r = new Rados(primaryPool.getAuthUserName());
r.confSet("mon_host", primaryPool.getSourceHost() + ":" + primaryPool.getSourcePort());
r.confSet("key", primaryPool.getAuthSecret());
r.confSet("client_mount_timeout", "30");
r.connect();
logger.debug("Succesfully connected to Ceph cluster at " + r.confGet("mon_host"));
final IoCTX io = r.ioCtxCreate(primaryPool.getSourceDir());
final Rbd rbd = new Rbd(io);
final RbdImage image = rbd.open(disk.getName());
logger.debug("Attempting to create RBD snapshot " + disk.getName() + "@" + snapshotName);
image.snapCreate(snapshotName);
rbd.close(image);
r.ioCtxDestroy(io);
} catch (final Exception e) {
logger.error("A RBD snapshot operation on " + disk.getName() + " failed. The error was: " + e.getMessage());
}
} else {
/* VM is not running, create a snapshot by ourself */
final Script command = new Script(manageSnapshotPath, cmdsTimeout, logger);
command.add("-c", disk.getPath());
command.add("-n", snapshotName);
final String result = command.execute();
if (result != null) {
logger.debug("Failed to manage snapshot: " + result);
return new CreateObjectAnswer("Failed to manage snapshot: " + result);
}
}
}
final SnapshotObjectTO newSnapshot = new SnapshotObjectTO();
// NOTE: sort of hack, we'd better just put snapshtoName
newSnapshot.setPath(disk.getPath() + File.separator + snapshotName);
return new CreateObjectAnswer(newSnapshot);
} catch (final LibvirtException e) {
logger.debug("Failed to manage snapshot: ", e);
return new CreateObjectAnswer("Failed to manage snapshot: " + e.toString());
}
}
Aggregations