use of com.cloud.model.enumeration.PhysicalDiskFormat in project cosmic by MissionCriticalCloud.
the class LibvirtStorageAdaptor method createDiskFromTemplateOnRbd.
private KvmPhysicalDisk createDiskFromTemplateOnRbd(final KvmPhysicalDisk template, final String name, final long size, final KvmStoragePool destPool, final 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
*/
final KvmStoragePool srcPool = template.getPool();
KvmPhysicalDisk disk;
final PhysicalDiskFormat format = PhysicalDiskFormat.RAW;
disk = new KvmPhysicalDisk(destPool.getSourceDir() + "/" + name, name, 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());
}
final QemuImg qemu = new QemuImg(timeout);
final QemuImgFile srcFile;
final 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 (final QemuImgException e) {
this.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 */
this.logger.debug("Trying to perform a RBD clone (layering) since we are operating in the same storage pool");
final 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();
this.logger.debug("Succesfully connected to Ceph cluster at " + r.confGet("mon_host"));
final IoCTX io = r.ioCtxCreate(srcPool.getSourceDir());
final Rbd rbd = new Rbd(io);
final RbdImage srcImage = rbd.open(template.getName());
if (srcImage.isOldFormat()) {
/* The source image is RBD format 1, we have to do a regular copy */
this.logger.debug("The source image " + srcPool.getSourceDir() + "/" + template.getName() + " is RBD format 1. We have to perform a regular copy (" + disk.getVirtualSize() + " bytes)");
rbd.create(disk.getName(), disk.getVirtualSize(), this.rbdFeatures, this.rbdOrder);
final RbdImage destImage = rbd.open(disk.getName());
this.logger.debug("Starting to copy " + srcImage.getName() + " to " + destImage.getName() + " in Ceph pool " + srcPool.getSourceDir());
rbd.copy(srcImage, destImage);
this.logger.debug("Finished copying " + srcImage.getName() + " to " + destImage.getName() + " in Ceph pool " + srcPool.getSourceDir());
rbd.close(destImage);
} else {
final String rbdTemplateSnapName = "cloudstack-base-snap";
this.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) */
this.logger.debug("Checking if RBD snapshot " + srcPool.getSourceDir() + "/" + template.getName() + "@" + rbdTemplateSnapName + " exists prior to attempting a clone operation.");
final List<RbdSnapInfo> snaps = srcImage.snapList();
this.logger.debug("Found " + snaps.size() + " snapshots on RBD image " + srcPool.getSourceDir() + "/" + template.getName());
boolean snapFound = false;
for (final RbdSnapInfo snap : snaps) {
if (rbdTemplateSnapName.equals(snap.name)) {
this.logger.debug("RBD snapshot " + srcPool.getSourceDir() + "/" + template.getName() + "@" + rbdTemplateSnapName + " already exists.");
snapFound = true;
break;
}
}
if (!snapFound) {
this.logger.debug("Creating RBD snapshot " + rbdTemplateSnapName + " on image " + name);
srcImage.snapCreate(rbdTemplateSnapName);
this.logger.debug("Protecting RBD snapshot " + rbdTemplateSnapName + " on image " + name);
srcImage.snapProtect(rbdTemplateSnapName);
}
rbd.clone(template.getName(), rbdTemplateSnapName, io, disk.getName(), this.rbdFeatures, this.rbdOrder);
this.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()) {
final RbdImage diskImage = rbd.open(disk.getName());
diskImage.resize(disk.getVirtualSize());
rbd.close(diskImage);
this.logger.debug("Resized " + disk.getName() + " to " + 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 */
this.logger.debug("Both the source and destination are RBD, but not the same Ceph cluster. Performing a copy");
final 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();
this.logger.debug("Succesfully connected to source Ceph cluster at " + rSrc.confGet("mon_host"));
final 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();
this.logger.debug("Succesfully connected to source Ceph cluster at " + rDest.confGet("mon_host"));
final IoCTX sourceIo = rSrc.ioCtxCreate(srcPool.getSourceDir());
final Rbd sourceRbd = new Rbd(sourceIo);
final IoCTX destinationIo = rDest.ioCtxCreate(destPool.getSourceDir());
final Rbd destinationRbd = new Rbd(destinationIo);
this.logger.debug("Creating " + disk.getName() + " on the destination cluster " + rDest.confGet("mon_host") + " in pool " + destPool.getSourceDir());
destinationRbd.create(disk.getName(), disk.getVirtualSize(), this.rbdFeatures, this.rbdOrder);
final RbdImage srcImage = sourceRbd.open(template.getName());
final RbdImage destImage = destinationRbd.open(disk.getName());
this.logger.debug("Copying " + template.getName() + " from Ceph cluster " + rSrc.confGet("mon_host") + " to " + disk.getName() + " on cluster " + rDest.confGet("mon_host"));
sourceRbd.copy(srcImage, destImage);
sourceRbd.close(srcImage);
destinationRbd.close(destImage);
rSrc.ioCtxDestroy(sourceIo);
rDest.ioCtxDestroy(destinationIo);
}
} catch (final RadosException e) {
this.logger.error("Failed to perform a RADOS action on the Ceph cluster, the error was: " + e.getMessage());
disk = null;
} catch (final RbdException e) {
this.logger.error("Failed to perform a RBD action on the Ceph cluster, the error was: " + e.getMessage());
disk = null;
}
}
return disk;
}
Aggregations