use of com.cloud.agent.resource.kvm.storage.utils.QemuImg 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;
}
use of com.cloud.agent.resource.kvm.storage.utils.QemuImg in project cosmic by MissionCriticalCloud.
the class LibvirtStorageAdaptor method getPhysicalDisk.
@Override
public KvmPhysicalDisk getPhysicalDisk(final String volumeUuid, final KvmStoragePool pool) {
final LibvirtStoragePool libvirtPool = (LibvirtStoragePool) pool;
try {
final StorageVol vol = getVolume(libvirtPool.getPool(), volumeUuid);
final KvmPhysicalDisk disk;
final LibvirtStorageVolumeDef voldef = getStorageVolumeDef(vol);
disk = new KvmPhysicalDisk(vol.getPath(), vol.getName(), pool);
disk.setSize(vol.getInfo().allocation);
disk.setVirtualSize(vol.getInfo().capacity);
if (pool.getType() == StoragePoolType.RBD) {
disk.setFormat(PhysicalDiskFormat.RAW);
} else if (pool.getType() == StoragePoolType.NetworkFilesystem) {
final QemuImg qemuImg = new QemuImg(60000);
final Map<String, String> info = qemuImg.info(new QemuImgFile(disk.getPath()));
disk.setFormat(PhysicalDiskFormat.valueOf(info.get("file_format").toUpperCase()));
} else if (voldef.getFormat() == null) {
disk.setFormat(pool.getDefaultFormat());
} else if (voldef.getFormat() == LibvirtStorageVolumeDef.VolumeFormat.QCOW2) {
disk.setFormat(PhysicalDiskFormat.QCOW2);
} else if (voldef.getFormat() == LibvirtStorageVolumeDef.VolumeFormat.RAW) {
disk.setFormat(PhysicalDiskFormat.RAW);
}
return disk;
} catch (final LibvirtException | QemuImgException e) {
this.logger.debug("Failed to get physical disk:", e);
throw new CloudRuntimeException(e.toString());
}
}
use of com.cloud.agent.resource.kvm.storage.utils.QemuImg in project cosmic by MissionCriticalCloud.
the class LibvirtCreatePrivateTemplateFromVolumeCommandWrapper method execute.
@Override
public Answer execute(final CreatePrivateTemplateFromVolumeCommand command, final LibvirtComputingResource libvirtComputingResource) {
final String secondaryStorageUrl = command.getSecondaryStorageUrl();
KvmStoragePool secondaryStorage = null;
KvmStoragePool primary = null;
final KvmStoragePoolManager storagePoolMgr = libvirtComputingResource.getStoragePoolMgr();
try {
final String templateFolder = command.getAccountId() + File.separator + command.getTemplateId() + File.separator;
final String templateInstallFolder = "/template/tmpl/" + templateFolder;
secondaryStorage = storagePoolMgr.getStoragePoolByUri(secondaryStorageUrl);
try {
primary = storagePoolMgr.getStoragePool(command.getPool().getType(), command.getPrimaryStoragePoolNameLabel());
} catch (final CloudRuntimeException e) {
if (e.getMessage().contains("not found")) {
primary = storagePoolMgr.createStoragePool(command.getPool().getUuid(), command.getPool().getHost(), command.getPool().getPort(), command.getPool().getPath(), command.getPool().getUserInfo(), command.getPool().getType());
} else {
return new CreatePrivateTemplateAnswer(command, false, e.getMessage());
}
}
final KvmPhysicalDisk disk = primary.getPhysicalDisk(command.getVolumePath());
final String tmpltPath = secondaryStorage.getLocalPath() + File.separator + templateInstallFolder;
final StorageLayer storage = libvirtComputingResource.getStorage();
storage.mkdirs(tmpltPath);
if (primary.getType() != StoragePoolType.RBD) {
final String createTmplPath = libvirtComputingResource.createTmplPath();
final int cmdsTimeout = libvirtComputingResource.getCmdsTimeout();
final Script scriptCommand = new Script(createTmplPath, cmdsTimeout, s_logger);
scriptCommand.add("-f", disk.getPath());
scriptCommand.add("-t", tmpltPath);
scriptCommand.add("-n", command.getUniqueName() + ".qcow2");
final String result = scriptCommand.execute();
if (result != null) {
s_logger.debug("failed to create template: " + result);
return new CreatePrivateTemplateAnswer(command, false, result);
}
} else {
s_logger.debug("Converting RBD disk " + disk.getPath() + " into template " + command.getUniqueName());
final QemuImgFile srcFile = new QemuImgFile(KvmPhysicalDisk.rbdStringBuilder(primary.getSourceHost(), primary.getSourcePort(), primary.getAuthUserName(), primary.getAuthSecret(), disk.getPath()));
srcFile.setFormat(PhysicalDiskFormat.RAW);
final QemuImgFile destFile = new QemuImgFile(tmpltPath + "/" + command.getUniqueName() + ".qcow2");
destFile.setFormat(PhysicalDiskFormat.QCOW2);
final QemuImg q = new QemuImg(0);
try {
q.convert(srcFile, destFile);
} catch (final QemuImgException e) {
s_logger.error("Failed to create new template while converting " + srcFile.getFileName() + " to " + destFile.getFileName() + " the error was: " + e.getMessage());
}
final File templateProp = new File(tmpltPath + "/template.properties");
if (!templateProp.exists()) {
templateProp.createNewFile();
}
String templateContent = "filename=" + command.getUniqueName() + ".qcow2" + System.getProperty("line.separator");
final DateFormat dateFormat = new SimpleDateFormat("MM_dd_yyyy");
final Date date = new Date();
templateContent += "snapshot.name=" + dateFormat.format(date) + System.getProperty("line.separator");
try (final FileOutputStream templFo = new FileOutputStream(templateProp)) {
templFo.write(templateContent.getBytes("UTF-8"));
templFo.flush();
} catch (final IOException ex) {
s_logger.error("CreatePrivateTemplateAnswer:Exception:" + ex.getMessage());
}
}
final Map<String, Object> params = new HashMap<>();
params.put(StorageLayer.InstanceConfigKey, storage);
final Processor qcow2Processor = new QCOW2Processor();
qcow2Processor.configure("QCOW2 Processor", params);
final TemplateFormatInfo info = qcow2Processor.process(tmpltPath, null, command.getUniqueName());
final TemplateLocation loc = new TemplateLocation(storage, tmpltPath);
loc.create(1, true, command.getUniqueName());
loc.addFormat(info);
loc.save();
return new CreatePrivateTemplateAnswer(command, true, null, templateInstallFolder + command.getUniqueName() + ".qcow2", info.virtualSize, info.size, command.getUniqueName(), ImageFormat.QCOW2);
} catch (final InternalErrorException e) {
return new CreatePrivateTemplateAnswer(command, false, e.toString());
} catch (final IOException e) {
return new CreatePrivateTemplateAnswer(command, false, e.toString());
} catch (final ConfigurationException e) {
return new CreatePrivateTemplateAnswer(command, false, e.toString());
} catch (final CloudRuntimeException e) {
return new CreatePrivateTemplateAnswer(command, false, e.toString());
} finally {
if (secondaryStorage != null) {
storagePoolMgr.deleteStoragePool(secondaryStorage.getType(), secondaryStorage.getUuid());
}
}
}
Aggregations