Search in sources :

Example 1 with QemuImgFile

use of org.apache.cloudstack.utils.qemu.QemuImgFile in project cloudstack by apache.

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 (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<String, Object>();
        params.put(StorageLayer.InstanceConfigKey, storage);
        final Processor qcow2Processor = new QCOW2Processor();
        qcow2Processor.configure("QCOW2 Processor", params);
        final FormatInfo 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());
        }
    }
}
Also used : StorageLayer(com.cloud.storage.StorageLayer) Processor(com.cloud.storage.template.Processor) QCOW2Processor(com.cloud.storage.template.QCOW2Processor) HashMap(java.util.HashMap) KVMStoragePool(com.cloud.hypervisor.kvm.storage.KVMStoragePool) ConfigurationException(javax.naming.ConfigurationException) CloudRuntimeException(com.cloud.utils.exception.CloudRuntimeException) TemplateLocation(com.cloud.storage.template.TemplateLocation) QemuImgException(org.apache.cloudstack.utils.qemu.QemuImgException) Script(com.cloud.utils.script.Script) KVMStoragePoolManager(com.cloud.hypervisor.kvm.storage.KVMStoragePoolManager) KVMPhysicalDisk(com.cloud.hypervisor.kvm.storage.KVMPhysicalDisk) IOException(java.io.IOException) InternalErrorException(com.cloud.exception.InternalErrorException) Date(java.util.Date) QemuImg(org.apache.cloudstack.utils.qemu.QemuImg) QCOW2Processor(com.cloud.storage.template.QCOW2Processor) QemuImgFile(org.apache.cloudstack.utils.qemu.QemuImgFile) SimpleDateFormat(java.text.SimpleDateFormat) DateFormat(java.text.DateFormat) FileOutputStream(java.io.FileOutputStream) CreatePrivateTemplateAnswer(com.cloud.agent.api.storage.CreatePrivateTemplateAnswer) FormatInfo(com.cloud.storage.template.Processor.FormatInfo) QemuImgFile(org.apache.cloudstack.utils.qemu.QemuImgFile) File(java.io.File) SimpleDateFormat(java.text.SimpleDateFormat)

Example 2 with QemuImgFile

use of org.apache.cloudstack.utils.qemu.QemuImgFile 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:" + 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());
    }
    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(new String("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(new String("virtual_size")));
                        newDisk.setVirtualSize(virtualSize);
                        newDisk.setSize(virtualSize);
                    } catch (QemuImgException e) {
                        s_logger.error("Failed to convert " + srcFile.getFileName() + " to " + destFile.getFileName() + " the error was: " + e.getMessage());
                        newDisk = null;
                    }
                }
            } catch (QemuImgException 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 " + rbdInfo.size + " bytes long");
            rbd.close(image);
            r.ioCtxDestroy(io);
        } catch (QemuImgException 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 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;
}
Also used : Rados(com.ceph.rados.Rados) RadosException(com.ceph.rados.exceptions.RadosException) RbdImageInfo(com.ceph.rbd.jna.RbdImageInfo) PhysicalDiskFormat(org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat) QemuImg(org.apache.cloudstack.utils.qemu.QemuImg) QemuImgFile(org.apache.cloudstack.utils.qemu.QemuImgFile) Rbd(com.ceph.rbd.Rbd) CloudRuntimeException(com.cloud.utils.exception.CloudRuntimeException) QemuImgException(org.apache.cloudstack.utils.qemu.QemuImgException) RbdImage(com.ceph.rbd.RbdImage) IoCTX(com.ceph.rados.IoCTX) RbdException(com.ceph.rbd.RbdException)

Example 3 with QemuImgFile

use of org.apache.cloudstack.utils.qemu.QemuImgFile in project cloudstack by apache.

the class LibvirtStorageAdaptor method createPhysicalDiskByQemuImg.

private KVMPhysicalDisk createPhysicalDiskByQemuImg(String name, KVMStoragePool pool, PhysicalDiskFormat format, Storage.ProvisioningType provisioningType, long size) {
    String volPath = pool.getLocalPath() + "/" + name;
    String volName = name;
    long virtualSize = 0;
    long actualSize = 0;
    final int timeout = 0;
    QemuImgFile destFile = new QemuImgFile(volPath);
    destFile.setFormat(format);
    destFile.setSize(size);
    QemuImg qemu = new QemuImg(timeout);
    Map<String, String> options = new HashMap<String, String>();
    if (pool.getType() == StoragePoolType.NetworkFilesystem) {
        options.put("preallocation", QemuImg.PreallocationType.getPreallocationType(provisioningType).toString());
    }
    try {
        qemu.create(destFile, options);
        Map<String, String> info = qemu.info(destFile);
        virtualSize = Long.parseLong(info.get(new String("virtual_size")));
        actualSize = new File(destFile.getFileName()).length();
    } catch (QemuImgException e) {
        s_logger.error("Failed to create " + volPath + " due to a failed executing of qemu-img: " + e.getMessage());
    }
    KVMPhysicalDisk disk = new KVMPhysicalDisk(volPath, volName, pool);
    disk.setFormat(format);
    disk.setSize(actualSize);
    disk.setVirtualSize(virtualSize);
    return disk;
}
Also used : QemuImgFile(org.apache.cloudstack.utils.qemu.QemuImgFile) HashMap(java.util.HashMap) QemuImgException(org.apache.cloudstack.utils.qemu.QemuImgException) QemuImgFile(org.apache.cloudstack.utils.qemu.QemuImgFile) File(java.io.File) QemuImg(org.apache.cloudstack.utils.qemu.QemuImg)

Example 4 with QemuImgFile

use of org.apache.cloudstack.utils.qemu.QemuImgFile 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 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 (" + disk.getVirtualSize() + " bytes)");
                    rbd.create(disk.getName(), disk.getVirtualSize(), rbdFeatures, 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(), rbdFeatures, 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 " + 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(), rbdFeatures, 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;
}
Also used : Rados(com.ceph.rados.Rados) RadosException(com.ceph.rados.exceptions.RadosException) QemuImg(org.apache.cloudstack.utils.qemu.QemuImg) RbdSnapInfo(com.ceph.rbd.jna.RbdSnapInfo) QemuImgFile(org.apache.cloudstack.utils.qemu.QemuImgFile) Rbd(com.ceph.rbd.Rbd) QemuImgException(org.apache.cloudstack.utils.qemu.QemuImgException) RbdImage(com.ceph.rbd.RbdImage) IoCTX(com.ceph.rados.IoCTX) RbdException(com.ceph.rbd.RbdException)

Example 5 with QemuImgFile

use of org.apache.cloudstack.utils.qemu.QemuImgFile in project cloudstack by apache.

the class KVMStorageProcessor method createTemplateFromVolume.

@Override
public Answer createTemplateFromVolume(final CopyCommand cmd) {
    final DataTO srcData = cmd.getSrcTO();
    final DataTO destData = cmd.getDestTO();
    final int wait = cmd.getWaitInMillSeconds();
    final TemplateObjectTO template = (TemplateObjectTO) destData;
    final DataStoreTO imageStore = template.getDataStore();
    final VolumeObjectTO volume = (VolumeObjectTO) srcData;
    final PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO) volume.getDataStore();
    if (!(imageStore instanceof NfsTO)) {
        return new CopyCmdAnswer("unsupported protocol");
    }
    final NfsTO nfsImageStore = (NfsTO) imageStore;
    KVMStoragePool secondaryStorage = null;
    KVMStoragePool primary = null;
    try {
        final String templateFolder = template.getPath();
        secondaryStorage = storagePoolMgr.getStoragePoolByURI(nfsImageStore.getUrl());
        primary = storagePoolMgr.getStoragePool(primaryStore.getPoolType(), primaryStore.getUuid());
        final KVMPhysicalDisk disk = storagePoolMgr.getPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), volume.getPath());
        final String tmpltPath = secondaryStorage.getLocalPath() + File.separator + templateFolder;
        storageLayer.mkdirs(tmpltPath);
        final String templateName = UUID.randomUUID().toString();
        if (primary.getType() != StoragePoolType.RBD) {
            final Script command = new Script(_createTmplPath, wait, s_logger);
            command.add("-f", disk.getPath());
            command.add("-t", tmpltPath);
            command.add("-n", templateName + ".qcow2");
            final String result = command.execute();
            if (result != null) {
                s_logger.debug("failed to create template: " + result);
                return new CopyCmdAnswer(result);
            }
        } else {
            s_logger.debug("Converting RBD disk " + disk.getPath() + " into template " + templateName);
            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 + "/" + templateName + ".qcow2");
            destFile.setFormat(PhysicalDiskFormat.QCOW2);
            final QemuImg q = new QemuImg(cmd.getWaitInMillSeconds());
            try {
                q.convert(srcFile, destFile);
            } catch (final QemuImgException e) {
                final String message = "Failed to create new template while converting " + srcFile.getFileName() + " to " + destFile.getFileName() + " the error was: " + e.getMessage();
                throw new QemuImgException(message);
            }
            final File templateProp = new File(tmpltPath + "/template.properties");
            if (!templateProp.exists()) {
                templateProp.createNewFile();
            }
            String templateContent = "filename=" + templateName + ".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 (FileOutputStream templFo = new FileOutputStream(templateProp)) {
                templFo.write(templateContent.getBytes());
                templFo.flush();
            } catch (final IOException e) {
                throw e;
            }
        }
        final Map<String, Object> params = new HashMap<String, Object>();
        params.put(StorageLayer.InstanceConfigKey, storageLayer);
        final Processor qcow2Processor = new QCOW2Processor();
        qcow2Processor.configure("QCOW2 Processor", params);
        final FormatInfo info = qcow2Processor.process(tmpltPath, null, templateName);
        final TemplateLocation loc = new TemplateLocation(storageLayer, tmpltPath);
        loc.create(1, true, templateName);
        loc.addFormat(info);
        loc.save();
        final TemplateObjectTO newTemplate = new TemplateObjectTO();
        newTemplate.setPath(templateFolder + File.separator + templateName + ".qcow2");
        newTemplate.setSize(info.virtualSize);
        newTemplate.setPhysicalSize(info.size);
        newTemplate.setFormat(ImageFormat.QCOW2);
        newTemplate.setName(templateName);
        return new CopyCmdAnswer(newTemplate);
    } catch (final QemuImgException e) {
        s_logger.error(e.getMessage());
        return new CopyCmdAnswer(e.toString());
    } catch (final IOException e) {
        s_logger.debug("Failed to createTemplateFromVolume: ", e);
        return new CopyCmdAnswer(e.toString());
    } catch (final Exception e) {
        s_logger.debug("Failed to createTemplateFromVolume: ", e);
        return new CopyCmdAnswer(e.toString());
    } finally {
        if (secondaryStorage != null) {
            secondaryStorage.delete();
        }
    }
}
Also used : QCOW2Processor(com.cloud.storage.template.QCOW2Processor) StorageProcessor(com.cloud.storage.resource.StorageProcessor) Processor(com.cloud.storage.template.Processor) HashMap(java.util.HashMap) DataTO(com.cloud.agent.api.to.DataTO) TemplateLocation(com.cloud.storage.template.TemplateLocation) QemuImgException(org.apache.cloudstack.utils.qemu.QemuImgException) VolumeObjectTO(org.apache.cloudstack.storage.to.VolumeObjectTO) Script(com.cloud.utils.script.Script) PrimaryDataStoreTO(org.apache.cloudstack.storage.to.PrimaryDataStoreTO) DataStoreTO(com.cloud.agent.api.to.DataStoreTO) IOException(java.io.IOException) NfsTO(com.cloud.agent.api.to.NfsTO) Date(java.util.Date) URISyntaxException(java.net.URISyntaxException) LibvirtException(org.libvirt.LibvirtException) RbdException(com.ceph.rbd.RbdException) QemuImgException(org.apache.cloudstack.utils.qemu.QemuImgException) FileNotFoundException(java.io.FileNotFoundException) InternalErrorException(com.cloud.exception.InternalErrorException) ConfigurationException(javax.naming.ConfigurationException) CloudRuntimeException(com.cloud.utils.exception.CloudRuntimeException) RadosException(com.ceph.rados.exceptions.RadosException) IOException(java.io.IOException) QemuImg(org.apache.cloudstack.utils.qemu.QemuImg) QCOW2Processor(com.cloud.storage.template.QCOW2Processor) PrimaryDataStoreTO(org.apache.cloudstack.storage.to.PrimaryDataStoreTO) QemuImgFile(org.apache.cloudstack.utils.qemu.QemuImgFile) DateFormat(java.text.DateFormat) SimpleDateFormat(java.text.SimpleDateFormat) FileOutputStream(java.io.FileOutputStream) TemplateObjectTO(org.apache.cloudstack.storage.to.TemplateObjectTO) FormatInfo(com.cloud.storage.template.Processor.FormatInfo) QemuImgFile(org.apache.cloudstack.utils.qemu.QemuImgFile) S3Utils.putFile(com.cloud.utils.storage.S3.S3Utils.putFile) File(java.io.File) SimpleDateFormat(java.text.SimpleDateFormat) CopyCmdAnswer(org.apache.cloudstack.storage.command.CopyCmdAnswer)

Aggregations

QemuImg (org.apache.cloudstack.utils.qemu.QemuImg)7 QemuImgException (org.apache.cloudstack.utils.qemu.QemuImgException)7 QemuImgFile (org.apache.cloudstack.utils.qemu.QemuImgFile)7 CloudRuntimeException (com.cloud.utils.exception.CloudRuntimeException)5 RadosException (com.ceph.rados.exceptions.RadosException)4 RbdException (com.ceph.rbd.RbdException)4 File (java.io.File)4 HashMap (java.util.HashMap)4 InternalErrorException (com.cloud.exception.InternalErrorException)3 Script (com.cloud.utils.script.Script)3 IOException (java.io.IOException)3 ConfigurationException (javax.naming.ConfigurationException)3 IoCTX (com.ceph.rados.IoCTX)2 Rados (com.ceph.rados.Rados)2 Rbd (com.ceph.rbd.Rbd)2 RbdImage (com.ceph.rbd.RbdImage)2 DataStoreTO (com.cloud.agent.api.to.DataStoreTO)2 DataTO (com.cloud.agent.api.to.DataTO)2 NfsTO (com.cloud.agent.api.to.NfsTO)2 Processor (com.cloud.storage.template.Processor)2