Search in sources :

Example 1 with RbdImage

use of com.ceph.rbd.RbdImage 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());
    }
}
Also used : SnapshotObjectTO(com.cloud.storage.to.SnapshotObjectTO) Script(com.cloud.utils.script.Script) LibvirtException(org.libvirt.LibvirtException) Connect(org.libvirt.Connect) Rados(com.ceph.rados.Rados) CreateObjectAnswer(com.cloud.storage.command.CreateObjectAnswer) URISyntaxException(java.net.URISyntaxException) LibvirtException(org.libvirt.LibvirtException) QemuImgException(com.cloud.utils.qemu.QemuImgException) FileNotFoundException(java.io.FileNotFoundException) InternalErrorException(com.cloud.exception.InternalErrorException) ConfigurationException(javax.naming.ConfigurationException) CloudRuntimeException(com.cloud.utils.exception.CloudRuntimeException) IOException(java.io.IOException) PrimaryDataStoreTO(com.cloud.storage.to.PrimaryDataStoreTO) DomainState(org.libvirt.DomainInfo.DomainState) Rbd(com.ceph.rbd.Rbd) RbdImage(com.ceph.rbd.RbdImage) VolumeObjectTO(com.cloud.storage.to.VolumeObjectTO) IoCTX(com.ceph.rados.IoCTX) Domain(org.libvirt.Domain)

Example 2 with RbdImage

use of com.ceph.rbd.RbdImage 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());
    }
}
Also used : Script(com.cloud.utils.script.Script) LibvirtException(org.libvirt.LibvirtException) KvmStoragePool(com.cloud.hypervisor.kvm.storage.KvmStoragePool) MessageFormat(java.text.MessageFormat) Connect(org.libvirt.Connect) DomainSnapshot(org.libvirt.DomainSnapshot) Rados(com.ceph.rados.Rados) ManageSnapshotAnswer(com.cloud.agent.api.ManageSnapshotAnswer) StorageFilerTO(com.cloud.agent.api.to.StorageFilerTO) LibvirtException(org.libvirt.LibvirtException) DomainState(org.libvirt.DomainInfo.DomainState) Rbd(com.ceph.rbd.Rbd) RbdImage(com.ceph.rbd.RbdImage) KvmStoragePoolManager(com.cloud.hypervisor.kvm.storage.KvmStoragePoolManager) IoCTX(com.ceph.rados.IoCTX) Domain(org.libvirt.Domain) KvmPhysicalDisk(com.cloud.hypervisor.kvm.storage.KvmPhysicalDisk)

Example 3 with RbdImage

use of com.ceph.rbd.RbdImage 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());
    }
}
Also used : RbdSnapInfo(com.ceph.rbd.jna.RbdSnapInfo) StorageVol(org.libvirt.StorageVol) LibvirtException(org.libvirt.LibvirtException) Rbd(com.ceph.rbd.Rbd) CloudRuntimeException(com.cloud.utils.exception.CloudRuntimeException) Rados(com.ceph.rados.Rados) RbdImage(com.ceph.rbd.RbdImage) IoCTX(com.ceph.rados.IoCTX) RadosException(com.ceph.rados.exceptions.RadosException) RbdException(com.ceph.rbd.RbdException)

Example 4 with RbdImage

use of com.ceph.rbd.RbdImage in project cosmic by MissionCriticalCloud.

the class LibvirtStorageAdaptor method createDiskFromTemplateOnRbd.

private KvmPhysicalDisk createDiskFromTemplateOnRbd(final KvmPhysicalDisk template, final String name, PhysicalDiskFormat format, final Storage.ProvisioningType provisioningType, 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 = null;
    final 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());
    }
    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) {
            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 */
                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();
                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 */
                    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(), rbdFeatures, rbdOrder);
                    final RbdImage destImage = rbd.open(disk.getName());
                    logger.debug("Starting to copy " + srcImage.getName() + " to " + destImage.getName() + " in Ceph pool " + srcPool.getSourceDir());
                    rbd.copy(srcImage, destImage);
                    logger.debug("Finished copying " + srcImage.getName() + " to " + destImage.getName() + " in Ceph pool " + srcPool.getSourceDir());
                    rbd.close(destImage);
                } else {
                    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) */
                    logger.debug("Checking if RBD snapshot " + srcPool.getSourceDir() + "/" + template.getName() + "@" + rbdTemplateSnapName + " exists prior to attempting a clone operation.");
                    final List<RbdSnapInfo> snaps = srcImage.snapList();
                    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)) {
                            logger.debug("RBD snapshot " + srcPool.getSourceDir() + "/" + template.getName() + "@" + rbdTemplateSnapName + " already exists.");
                            snapFound = true;
                            break;
                        }
                    }
                    if (!snapFound) {
                        logger.debug("Creating RBD snapshot " + rbdTemplateSnapName + " on image " + name);
                        srcImage.snapCreate(rbdTemplateSnapName);
                        logger.debug("Protecting RBD snapshot " + rbdTemplateSnapName + " on image " + name);
                        srcImage.snapProtect(rbdTemplateSnapName);
                    }
                    rbd.clone(template.getName(), rbdTemplateSnapName, io, disk.getName(), rbdFeatures, rbdOrder);
                    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);
                        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 */
                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();
                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();
                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);
                logger.debug("Creating " + disk.getName() + " on the destination cluster " + rDest.confGet("mon_host") + " in pool " + destPool.getSourceDir());
                destinationRbd.create(disk.getName(), disk.getVirtualSize(), rbdFeatures, rbdOrder);
                final RbdImage srcImage = sourceRbd.open(template.getName());
                final RbdImage destImage = destinationRbd.open(disk.getName());
                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) {
            logger.error("Failed to perform a RADOS action on the Ceph cluster, the error was: " + e.getMessage());
            disk = null;
        } catch (final RbdException e) {
            logger.error("Failed to perform a RBD action on the Ceph cluster, the error was: " + e.getMessage());
            disk = null;
        }
    }
    return disk;
}
Also used : Rados(com.ceph.rados.Rados) RadosException(com.ceph.rados.exceptions.RadosException) QemuImg(com.cloud.utils.qemu.QemuImg) RbdSnapInfo(com.ceph.rbd.jna.RbdSnapInfo) QemuImgFile(com.cloud.utils.qemu.QemuImgFile) Rbd(com.ceph.rbd.Rbd) QemuImgException(com.cloud.utils.qemu.QemuImgException) RbdImage(com.ceph.rbd.RbdImage) IoCTX(com.ceph.rados.IoCTX) RbdException(com.ceph.rbd.RbdException)

Example 5 with RbdImage

use of com.ceph.rbd.RbdImage in project cosmic by MissionCriticalCloud.

the class LibvirtStorageAdaptor method copyPhysicalDisk.

@Override
public KvmPhysicalDisk copyPhysicalDisk(final KvmPhysicalDisk disk, final String name, final KvmStoragePool destPool, final int timeout) {
    final KvmStoragePool srcPool = disk.getPool();
    final PhysicalDiskFormat sourceFormat = disk.getFormat();
    final String sourcePath = disk.getPath();
    KvmPhysicalDisk newDisk;
    logger.debug("copyPhysicalDisk: disk size:" + disk.getSize() + ", virtualsize:" + 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());
    }
    final String destPath = newDisk.getPath();
    final PhysicalDiskFormat destFormat = newDisk.getFormat();
    final 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 {
                final Map<String, String> info = qemu.info(srcFile);
                final String backingFile = info.get(new String("backing_file"));
                // qcow2 templates can just be copied into place
                if (sourceFormat.equals(destFormat) && backingFile == null && sourcePath.endsWith(".qcow2")) {
                    final 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);
                        final Map<String, String> destInfo = qemu.info(destFile);
                        final Long virtualSize = Long.parseLong(destInfo.get(new String("virtual_size")));
                        newDisk.setVirtualSize(virtualSize);
                        newDisk.setSize(virtualSize);
                    } catch (final QemuImgException e) {
                        logger.error("Failed to convert " + srcFile.getFileName() + " to " + destFile.getFileName() + " the error was: " + e.getMessage());
                        newDisk = null;
                    }
                }
            } catch (final QemuImgException e) {
                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)
         */
        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);
            final String rbdDestPath = destPool.getSourceDir() + "/" + name;
            final String rbdDestFile = KvmPhysicalDisk.rbdStringBuilder(destPool.getSourceHost(), destPool.getSourcePort(), destPool.getAuthUserName(), destPool.getAuthSecret(), rbdDestPath);
            destFile = new QemuImgFile(rbdDestFile, destFormat);
            logger.debug("Starting copy from source image " + srcFile.getFileName() + " to RBD image " + rbdDestPath);
            qemu.convert(srcFile, destFile);
            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 */
            final 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();
            logger.debug("Succesfully connected to Ceph cluster at " + r.confGet("mon_host"));
            final IoCTX io = r.ioCtxCreate(destPool.getSourceDir());
            final Rbd rbd = new Rbd(io);
            final RbdImage image = rbd.open(name);
            final RbdImageInfo rbdInfo = image.stat();
            newDisk.setSize(rbdInfo.size);
            newDisk.setVirtualSize(rbdInfo.size);
            logger.debug("After copy the resulting RBD image " + rbdDestPath + " is " + rbdInfo.size + " bytes long");
            rbd.close(image);
            r.ioCtxDestroy(io);
        } catch (final QemuImgException e) {
            logger.error("Failed to convert from " + srcFile.getFileName() + " to " + destFile.getFileName() + " the error was: " + e.getMessage());
            newDisk = null;
        } catch (final RadosException e) {
            logger.error("A Ceph RADOS operation failed (" + e.getReturnValue() + "). The error was: " + e.getMessage());
            newDisk = null;
        } catch (final RbdException e) {
            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 (final QemuImgException e) {
            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;
}
Also used : Rados(com.ceph.rados.Rados) RadosException(com.ceph.rados.exceptions.RadosException) RbdImageInfo(com.ceph.rbd.jna.RbdImageInfo) PhysicalDiskFormat(com.cloud.utils.qemu.QemuImg.PhysicalDiskFormat) QemuImg(com.cloud.utils.qemu.QemuImg) QemuImgFile(com.cloud.utils.qemu.QemuImgFile) Rbd(com.ceph.rbd.Rbd) CloudRuntimeException(com.cloud.utils.exception.CloudRuntimeException) QemuImgException(com.cloud.utils.qemu.QemuImgException) RbdImage(com.ceph.rbd.RbdImage) IoCTX(com.ceph.rados.IoCTX) RbdException(com.ceph.rbd.RbdException)

Aggregations

IoCTX (com.ceph.rados.IoCTX)15 Rados (com.ceph.rados.Rados)15 Rbd (com.ceph.rbd.Rbd)15 RbdImage (com.ceph.rbd.RbdImage)15 RadosException (com.ceph.rados.exceptions.RadosException)12 RbdException (com.ceph.rbd.RbdException)12 LibvirtException (org.libvirt.LibvirtException)11 CloudRuntimeException (com.cloud.utils.exception.CloudRuntimeException)10 Script (com.cloud.utils.script.Script)7 Connect (org.libvirt.Connect)6 Domain (org.libvirt.Domain)6 RbdSnapInfo (com.ceph.rbd.jna.RbdSnapInfo)5 IOException (java.io.IOException)5 DomainState (org.libvirt.DomainInfo.DomainState)5 MessageFormat (java.text.MessageFormat)4 InternalErrorException (com.cloud.exception.InternalErrorException)3 KVMPhysicalDisk (com.cloud.hypervisor.kvm.storage.KVMPhysicalDisk)3 KVMStoragePool (com.cloud.hypervisor.kvm.storage.KVMStoragePool)3 KVMStoragePoolManager (com.cloud.hypervisor.kvm.storage.KVMStoragePoolManager)3 QemuImgException (com.cloud.utils.qemu.QemuImgException)3