use of com.ceph.rados.Rados 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.rados.Rados 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());
}
}
use of com.ceph.rados.Rados in project cosmic by MissionCriticalCloud.
the class LibvirtManageSnapshotCommandWrapper method execute.
@Override
public Answer execute(final ManageSnapshotCommand command, final LibvirtComputingResource libvirtComputingResource) {
final String snapshotName = command.getSnapshotName();
final String snapshotPath = command.getSnapshotPath();
final String vmName = command.getVmName();
try {
final LibvirtUtilitiesHelper libvirtUtilitiesHelper = libvirtComputingResource.getLibvirtUtilitiesHelper();
final Connect conn = libvirtUtilitiesHelper.getConnectionByVmName(vmName);
DomainState state = null;
Domain vm = null;
if (vmName != null) {
try {
vm = libvirtComputingResource.getDomain(conn, command.getVmName());
state = vm.getInfo().state;
} catch (final LibvirtException e) {
s_logger.trace("Ignoring libvirt error.", e);
}
}
final KvmStoragePoolManager storagePoolMgr = libvirtComputingResource.getStoragePoolMgr();
final StorageFilerTO pool = command.getPool();
final KvmStoragePool primaryPool = storagePoolMgr.getStoragePool(pool.getType(), pool.getUuid());
final KvmPhysicalDisk disk = primaryPool.getPhysicalDisk(command.getVolumePath());
if (state == DomainState.VIR_DOMAIN_RUNNING && !primaryPool.isExternalSnapshot()) {
final MessageFormat snapshotXml = new MessageFormat(" <domainsnapshot>" + " <name>{0}</name>" + " <domain>" + " <uuid>{1}</uuid>" + " </domain>" + " </domainsnapshot>");
final String vmUuid = vm.getUUIDString();
final Object[] args = new Object[] { snapshotName, vmUuid };
final String snapshot = snapshotXml.format(args);
s_logger.debug(snapshot);
if (command.getCommandSwitch().equalsIgnoreCase(ManageSnapshotCommand.CREATE_SNAPSHOT)) {
vm.snapshotCreateXML(snapshot);
} else {
final DomainSnapshot snap = vm.snapshotLookupByName(snapshotName);
snap.delete(0);
}
/*
* libvirt on RHEL6 doesn't handle resume event emitted from qemu
*/
vm = libvirtComputingResource.getDomain(conn, command.getVmName());
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();
s_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());
if (command.getCommandSwitch().equalsIgnoreCase(ManageSnapshotCommand.CREATE_SNAPSHOT)) {
s_logger.debug("Attempting to create RBD snapshot " + disk.getName() + "@" + snapshotName);
image.snapCreate(snapshotName);
} else {
s_logger.debug("Attempting to remove RBD snapshot " + disk.getName() + "@" + snapshotName);
image.snapRemove(snapshotName);
}
rbd.close(image);
r.ioCtxDestroy(io);
} catch (final Exception e) {
s_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 int cmdsTimeout = libvirtComputingResource.getCmdsTimeout();
final String manageSnapshotPath = libvirtComputingResource.manageSnapshotPath();
final Script scriptCommand = new Script(manageSnapshotPath, cmdsTimeout, s_logger);
if (command.getCommandSwitch().equalsIgnoreCase(ManageSnapshotCommand.CREATE_SNAPSHOT)) {
scriptCommand.add("-c", disk.getPath());
} else {
scriptCommand.add("-d", snapshotPath);
}
scriptCommand.add("-n", snapshotName);
final String result = scriptCommand.execute();
if (result != null) {
s_logger.debug("Failed to manage snapshot: " + result);
return new ManageSnapshotAnswer(command, false, "Failed to manage snapshot: " + result);
}
}
}
return new ManageSnapshotAnswer(command, command.getSnapshotId(), disk.getPath() + File.separator + snapshotName, true, null);
} catch (final LibvirtException e) {
s_logger.debug("Failed to manage snapshot: " + e.toString());
return new ManageSnapshotAnswer(command, false, "Failed to manage snapshot: " + e.toString());
}
}
use of com.ceph.rados.Rados in project cosmic by MissionCriticalCloud.
the class LibvirtStorageAdaptor method createPhysicalDiskOnRbd.
private KvmPhysicalDisk createPhysicalDiskOnRbd(final String name, final KvmStoragePool pool, final PhysicalDiskFormat format, final Storage.ProvisioningType provisioningType, final long size) {
String volPath = null;
try {
logger.info("Creating RBD image " + pool.getSourceDir() + "/" + name + " with size " + size);
final Rados r = new Rados(pool.getAuthUserName());
r.confSet("mon_host", pool.getSourceHost() + ":" + pool.getSourcePort());
r.confSet("key", pool.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(pool.getSourceDir());
final Rbd rbd = new Rbd(io);
rbd.create(name, size, rbdFeatures, rbdOrder);
r.ioCtxDestroy(io);
} catch (final RadosException e) {
throw new CloudRuntimeException(e.toString());
} catch (final RbdException e) {
throw new CloudRuntimeException(e.toString());
}
volPath = pool.getSourceDir() + "/" + name;
final KvmPhysicalDisk disk = new KvmPhysicalDisk(volPath, name, pool);
disk.setFormat(PhysicalDiskFormat.RAW);
disk.setSize(size);
disk.setVirtualSize(size);
return disk;
}
use of com.ceph.rados.Rados in project cosmic by MissionCriticalCloud.
the class LibvirtStorageAdaptor method deletePhysicalDisk.
@Override
public boolean deletePhysicalDisk(final String uuid, final KvmStoragePool pool, final Storage.ImageFormat format) {
logger.info("Attempting to remove volume " + uuid + " from pool " + pool.getUuid());
if (pool.getType() == StoragePoolType.RBD) {
try {
logger.info("Unprotecting and Removing RBD snapshots of image " + pool.getSourceDir() + "/" + uuid + " prior to removing the image");
final Rados r = new Rados(pool.getAuthUserName());
r.confSet("mon_host", pool.getSourceHost() + ":" + pool.getSourcePort());
r.confSet("key", pool.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(pool.getSourceDir());
final Rbd rbd = new Rbd(io);
final RbdImage image = rbd.open(uuid);
logger.debug("Fetching list of snapshots of RBD image " + pool.getSourceDir() + "/" + uuid);
final List<RbdSnapInfo> snaps = image.snapList();
for (final RbdSnapInfo snap : snaps) {
if (image.snapIsProtected(snap.name)) {
logger.debug("Unprotecting snapshot " + pool.getSourceDir() + "/" + uuid + "@" + snap.name);
image.snapUnprotect(snap.name);
} else {
logger.debug("Snapshot " + pool.getSourceDir() + "/" + uuid + "@" + snap.name + " is not protected.");
}
logger.debug("Removing snapshot " + pool.getSourceDir() + "/" + uuid + "@" + snap.name);
image.snapRemove(snap.name);
}
rbd.close(image);
r.ioCtxDestroy(io);
logger.info("Succesfully unprotected and removed any remaining snapshots (" + snaps.size() + ") of " + pool.getSourceDir() + "/" + uuid + " Continuing to remove the RBD image");
} catch (final RadosException e) {
throw new CloudRuntimeException(e.toString());
} catch (final RbdException e) {
throw new CloudRuntimeException(e.toString());
}
}
final LibvirtStoragePool libvirtPool = (LibvirtStoragePool) pool;
try {
final StorageVol vol = getVolume(libvirtPool.getPool(), uuid);
logger.debug("Instructing libvirt to remove volume " + uuid + " from pool " + pool.getUuid());
if (Storage.ImageFormat.DIR.equals(format)) {
deleteDirVol(libvirtPool, vol);
} else {
deleteVol(libvirtPool, vol);
}
vol.free();
return true;
} catch (final LibvirtException e) {
throw new CloudRuntimeException(e.toString());
}
}
Aggregations