This is an automated email from the ASF dual-hosted git repository.

rohit pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cloudstack.git

commit ffe86e1c17ca5bb0aac8ca4fb1544b6bd9b50285
Merge: d91e20e bd09595
Author: Rohit Yadav <[email protected]>
AuthorDate: Tue May 8 16:01:10 2018 +0530

    Merge branch '4.11'
    
    Signed-off-by: Rohit Yadav <[email protected]>

 debian/control                                                    | 2 +-
 .../com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java | 2 +-
 .../main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java | 8 ++++++--
 .../kvm/resource/wrapper/LibvirtStopCommandWrapper.java           | 2 +-
 .../com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java   | 3 ++-
 ui/scripts/system.js                                              | 4 ++++
 6 files changed, 15 insertions(+), 6 deletions(-)

diff --cc 
plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java
index 63f7872,0000000..d85b7c1
mode 100644,000000..100644
--- 
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java
+++ 
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java
@@@ -1,1353 -1,0 +1,1354 @@@
 +// Licensed to the Apache Software Foundation (ASF) under one
 +// or more contributor license agreements.  See the NOTICE file
 +// distributed with this work for additional information
 +// regarding copyright ownership.  The ASF licenses this file
 +// to you under the Apache License, Version 2.0 (the
 +// "License"); you may not use this file except in compliance
 +// with the License.  You may obtain a copy of the License at
 +//
 +//   http://www.apache.org/licenses/LICENSE-2.0
 +//
 +// Unless required by applicable law or agreed to in writing,
 +// software distributed under the License is distributed on an
 +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 +// KIND, either express or implied.  See the License for the
 +// specific language governing permissions and limitations
 +// under the License.
 +package com.cloud.hypervisor.kvm.storage;
 +
 +import java.io.File;
 +import java.nio.charset.Charset;
 +import java.util.ArrayList;
 +import java.util.HashMap;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.UUID;
 +
 +import org.apache.commons.codec.binary.Base64;
 +import org.apache.log4j.Logger;
 +import org.libvirt.Connect;
 +import org.libvirt.LibvirtException;
 +import org.libvirt.Secret;
 +import org.libvirt.StoragePool;
 +import org.libvirt.StoragePoolInfo.StoragePoolState;
 +import org.libvirt.StorageVol;
 +
 +import com.ceph.rados.IoCTX;
 +import com.ceph.rados.Rados;
 +import com.ceph.rados.exceptions.ErrorCode;
 +import com.ceph.rados.exceptions.RadosException;
 +import com.ceph.rbd.Rbd;
 +import com.ceph.rbd.RbdException;
 +import com.ceph.rbd.RbdImage;
 +import com.ceph.rbd.jna.RbdImageInfo;
 +import com.ceph.rbd.jna.RbdSnapInfo;
 +
 +import org.apache.cloudstack.utils.qemu.QemuImg;
 +import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
 +import org.apache.cloudstack.utils.qemu.QemuImgException;
 +import org.apache.cloudstack.utils.qemu.QemuImgFile;
 +
 +import com.cloud.exception.InternalErrorException;
 +import com.cloud.hypervisor.kvm.resource.LibvirtConnection;
 +import com.cloud.hypervisor.kvm.resource.LibvirtSecretDef;
 +import com.cloud.hypervisor.kvm.resource.LibvirtSecretDef.Usage;
 +import com.cloud.hypervisor.kvm.resource.LibvirtStoragePoolDef;
 +import 
com.cloud.hypervisor.kvm.resource.LibvirtStoragePoolDef.AuthenticationType;
 +import com.cloud.hypervisor.kvm.resource.LibvirtStoragePoolDef.PoolType;
 +import com.cloud.hypervisor.kvm.resource.LibvirtStoragePoolXMLParser;
 +import com.cloud.hypervisor.kvm.resource.LibvirtStorageVolumeDef;
 +import com.cloud.hypervisor.kvm.resource.LibvirtStorageVolumeDef.VolumeFormat;
 +import com.cloud.hypervisor.kvm.resource.LibvirtStorageVolumeXMLParser;
 +import com.cloud.storage.Storage;
 +import com.cloud.storage.Storage.StoragePoolType;
 +import com.cloud.storage.StorageLayer;
 +import com.cloud.utils.exception.CloudRuntimeException;
 +import com.cloud.utils.script.Script;
 +
 +public class LibvirtStorageAdaptor implements StorageAdaptor {
 +    private static final Logger s_logger = 
Logger.getLogger(LibvirtStorageAdaptor.class);
 +    private StorageLayer _storageLayer;
 +    private String _mountPoint = "/mnt";
 +    private String _manageSnapshotPath;
 +
 +    private String rbdTemplateSnapName = "cloudstack-base-snap";
 +    private int rbdFeatures = (1 << 0); /* Feature 1<<0 means layering in RBD 
format 2 */
 +    private int rbdOrder = 0; /* Order 0 means 4MB blocks (the default) */
 +
 +    public LibvirtStorageAdaptor(StorageLayer storage) {
 +        _storageLayer = storage;
 +        _manageSnapshotPath = Script.findScript("scripts/storage/qcow2/", 
"managesnapshot.sh");
 +    }
 +
 +    @Override
 +    public boolean createFolder(String uuid, String path) {
 +        String mountPoint = _mountPoint + File.separator + uuid;
 +        File f = new File(mountPoint + File.separator + path);
 +        if (!f.exists()) {
 +            f.mkdirs();
 +        }
 +        return true;
 +    }
 +
 +    public StorageVol getVolume(StoragePool pool, String volName) {
 +        StorageVol vol = null;
 +
 +        try {
 +            vol = pool.storageVolLookupByName(volName);
 +        } catch (LibvirtException e) {
 +            s_logger.debug("Could not find volume " + volName + ": " + 
e.getMessage());
 +        }
 +
 +        /**
 +         * The volume was not found in the storage pool
 +         * This can happen when a volume has just been created on a different 
host and
 +         * since then the libvirt storage pool has not been refreshed.
 +         */
 +        if (vol == null) {
 +            try {
 +                s_logger.debug("Refreshing storage pool " + pool.getName());
 +                refreshPool(pool);
 +            } catch (LibvirtException e) {
 +                s_logger.debug("Failed to refresh storage pool: " + 
e.getMessage());
 +            }
 +
 +            try {
 +                vol = pool.storageVolLookupByName(volName);
 +                s_logger.debug("Found volume " + volName + " in storage pool 
" + pool.getName() + " after refreshing the pool");
 +            } catch (LibvirtException e) {
 +                throw new CloudRuntimeException("Could not find volume " + 
volName + ": " + e.getMessage());
 +            }
 +        }
 +
 +        return vol;
 +    }
 +
 +    public StorageVol createVolume(Connect conn, StoragePool pool, String 
uuid, long size, VolumeFormat format) throws LibvirtException {
 +        LibvirtStorageVolumeDef volDef = new 
LibvirtStorageVolumeDef(UUID.randomUUID().toString(), size, format, null, null);
 +        s_logger.debug(volDef.toString());
 +
 +        return pool.storageVolCreateXML(volDef.toString(), 0);
 +    }
 +
 +    public void storagePoolRefresh(StoragePool pool) {
 +        try {
 +            synchronized (getStoragePool(pool.getUUIDString())) {
 +                refreshPool(pool);
 +            }
 +        } catch (LibvirtException e) {
 +            s_logger.debug("refresh storage pool failed: " + e.toString());
 +        }
 +    }
 +
 +    private StoragePool createNetfsStoragePool(PoolType fsType, Connect conn, 
String uuid, String host, String path) throws LibvirtException {
 +        String targetPath = _mountPoint + File.separator + uuid;
 +        LibvirtStoragePoolDef spd = new LibvirtStoragePoolDef(fsType, uuid, 
uuid, host, path, targetPath);
 +        _storageLayer.mkdir(targetPath);
 +        StoragePool sp = null;
 +        try {
 +            s_logger.debug(spd.toString());
 +            sp = conn.storagePoolCreateXML(spd.toString(), 0);
 +            return sp;
 +        } catch (LibvirtException e) {
 +            s_logger.error(e.toString());
 +            // if error is that pool is mounted, try to handle it
 +            if (e.toString().contains("already mounted")) {
 +                s_logger.error("Attempting to unmount old mount libvirt is 
unaware of at " + targetPath);
 +                String result = Script.runSimpleBashScript("umount -l " + 
targetPath);
 +                if (result == null) {
 +                    s_logger.error("Succeeded in unmounting " + targetPath);
 +                    try {
 +                        sp = conn.storagePoolCreateXML(spd.toString(), 0);
 +                        s_logger.error("Succeeded in redefining storage");
 +                        return sp;
 +                    } catch (LibvirtException l) {
 +                        s_logger.error("Target was already mounted, unmounted 
it but failed to redefine storage:" + l);
 +                    }
 +                } else {
 +                    s_logger.error("Failed in unmounting and redefining 
storage");
 +                }
 +            } else {
 +                s_logger.error("Internal error occurred when attempting to 
mount: specified path may be invalid");
 +                throw e;
 +            }
 +            if (sp != null) {
 +                try {
 +                    if (sp.isPersistent() == 1) {
 +                        sp.destroy();
 +                        sp.undefine();
 +                    } else {
 +                        sp.destroy();
 +                    }
 +                    sp.free();
 +                } catch (LibvirtException l) {
 +                    s_logger.debug("Failed to undefine " + fsType.toString() 
+ " storage pool with: " + l.toString());
 +                }
 +            }
 +            return null;
 +        }
 +    }
 +
 +    private StoragePool createSharedStoragePool(Connect conn, String uuid, 
String host, String path) {
 +        String mountPoint = path;
 +        if (!_storageLayer.exists(mountPoint)) {
 +            s_logger.error(mountPoint + " does not exists. Check 
local.storage.path in agent.properties.");
 +            return null;
 +        }
 +        LibvirtStoragePoolDef spd = new LibvirtStoragePoolDef(PoolType.DIR, 
uuid, uuid, host, path, path);
 +        StoragePool sp = null;
 +        try {
 +            s_logger.debug(spd.toString());
 +            sp = conn.storagePoolCreateXML(spd.toString(), 0);
 +            return sp;
 +        } catch (LibvirtException e) {
 +            s_logger.error(e.toString());
 +            if (sp != null) {
 +                try {
 +                    if (sp.isPersistent() == 1) {
 +                        sp.destroy();
 +                        sp.undefine();
 +                    } else {
 +                        sp.destroy();
 +                    }
 +                    sp.free();
 +                } catch (LibvirtException l) {
 +                    s_logger.debug("Failed to define shared mount point 
storage pool with: " + l.toString());
 +                }
 +            }
 +            return null;
 +        }
 +    }
 +
 +    private StoragePool createCLVMStoragePool(Connect conn, String uuid, 
String host, String path) {
 +
 +        String volgroupPath = "/dev/" + path;
 +        String volgroupName = path;
 +        volgroupName = volgroupName.replaceFirst("/", "");
 +
 +        LibvirtStoragePoolDef spd = new 
LibvirtStoragePoolDef(PoolType.LOGICAL, volgroupName, uuid, host, volgroupPath, 
volgroupPath);
 +        StoragePool sp = null;
 +        try {
 +            s_logger.debug(spd.toString());
 +            sp = conn.storagePoolCreateXML(spd.toString(), 0);
 +            return sp;
 +        } catch (LibvirtException e) {
 +            s_logger.error(e.toString());
 +            if (sp != null) {
 +                try {
 +                    if (sp.isPersistent() == 1) {
 +                        sp.destroy();
 +                        sp.undefine();
 +                    } else {
 +                        sp.destroy();
 +                    }
 +                    sp.free();
 +                } catch (LibvirtException l) {
 +                    s_logger.debug("Failed to define clvm storage pool with: 
" + l.toString());
 +                }
 +            }
 +            return null;
 +        }
 +
 +    }
 +
 +    private StoragePool createRBDStoragePool(Connect conn, String uuid, 
String host, int port, String userInfo, String path) {
 +
 +        LibvirtStoragePoolDef spd;
 +        StoragePool sp = null;
 +        Secret s = null;
 +
 +        String[] userInfoTemp = userInfo.split(":");
 +        if (userInfoTemp.length == 2) {
 +            LibvirtSecretDef sd = new LibvirtSecretDef(Usage.CEPH, uuid);
 +
 +            sd.setCephName(userInfoTemp[0] + "@" + host + ":" + port + "/" + 
path);
 +
 +            try {
 +                s_logger.debug(sd.toString());
 +                s = conn.secretDefineXML(sd.toString());
 +                s.setValue(Base64.decodeBase64(userInfoTemp[1]));
 +            } catch (LibvirtException e) {
 +                s_logger.error("Failed to define the libvirt secret: " + 
e.toString());
 +                if (s != null) {
 +                    try {
 +                        s.undefine();
 +                        s.free();
 +                    } catch (LibvirtException l) {
 +                        s_logger.error("Failed to undefine the libvirt 
secret: " + l.toString());
 +                    }
 +                }
 +                return null;
 +            }
 +            spd = new LibvirtStoragePoolDef(PoolType.RBD, uuid, uuid, host, 
port, path, userInfoTemp[0], AuthenticationType.CEPH, uuid);
 +        } else {
 +            spd = new LibvirtStoragePoolDef(PoolType.RBD, uuid, uuid, host, 
port, path, "");
 +        }
 +
 +        try {
 +            s_logger.debug(spd.toString());
 +            sp = conn.storagePoolCreateXML(spd.toString(), 0);
 +            return sp;
 +        } catch (LibvirtException e) {
 +            s_logger.error("Failed to create RBD storage pool: " + 
e.toString());
 +            if (sp != null) {
 +                try {
 +                    if (sp.isPersistent() == 1) {
 +                        sp.destroy();
 +                        sp.undefine();
 +                    } else {
 +                        sp.destroy();
 +                    }
 +                    sp.free();
 +                } catch (LibvirtException l) {
 +                    s_logger.error("Failed to undefine RBD storage pool: " + 
l.toString());
 +                }
 +            }
 +
 +            if (s != null) {
 +                try {
 +                    s_logger.error("Failed to create the RBD storage pool, 
cleaning up the libvirt secret");
 +                    s.undefine();
 +                    s.free();
 +                } catch (LibvirtException se) {
 +                    s_logger.error("Failed to remove the libvirt secret: " + 
se.toString());
 +                }
 +            }
 +
 +            return null;
 +        }
 +    }
 +
 +    public StorageVol copyVolume(StoragePool destPool, 
LibvirtStorageVolumeDef destVol, StorageVol srcVol, int timeout) throws 
LibvirtException {
 +        StorageVol vol = destPool.storageVolCreateXML(destVol.toString(), 0);
 +        String srcPath = srcVol.getKey();
 +        String destPath = vol.getKey();
 +        Script.runSimpleBashScript("cp " + srcPath + " " + destPath, timeout);
 +        return vol;
 +    }
 +
 +    public boolean copyVolume(String srcPath, String destPath, String 
volumeName, int timeout) throws InternalErrorException {
 +        _storageLayer.mkdirs(destPath);
 +        if (!_storageLayer.exists(srcPath)) {
 +            throw new InternalErrorException("volume:" + srcPath + " is not 
exits");
 +        }
 +        String result = Script.runSimpleBashScript("cp " + srcPath + " " + 
destPath + File.separator + volumeName, timeout);
 +        return result == null;
 +    }
 +
 +    public LibvirtStoragePoolDef getStoragePoolDef(Connect conn, StoragePool 
pool) throws LibvirtException {
 +        String poolDefXML = pool.getXMLDesc(0);
 +        LibvirtStoragePoolXMLParser parser = new 
LibvirtStoragePoolXMLParser();
 +        return parser.parseStoragePoolXML(poolDefXML);
 +    }
 +
 +    public LibvirtStorageVolumeDef getStorageVolumeDef(Connect conn, 
StorageVol vol) throws LibvirtException {
 +        String volDefXML = vol.getXMLDesc(0);
 +        LibvirtStorageVolumeXMLParser parser = new 
LibvirtStorageVolumeXMLParser();
 +        return parser.parseStorageVolumeXML(volDefXML);
 +    }
 +
 +    @Override
 +    public KVMStoragePool getStoragePool(String uuid) {
 +        return this.getStoragePool(uuid, false);
 +    }
 +
 +    @Override
 +    public KVMStoragePool getStoragePool(String uuid, boolean refreshInfo) {
 +        s_logger.info("Trying to fetch storage pool " + uuid + " from 
libvirt");
 +        StoragePool storage = null;
 +        try {
 +            Connect conn = LibvirtConnection.getConnection();
 +            storage = conn.storagePoolLookupByUUIDString(uuid);
 +
 +            if (storage.getInfo().state != 
StoragePoolState.VIR_STORAGE_POOL_RUNNING) {
 +                s_logger.warn("Storage pool " + uuid + " is not in running 
state. Attempting to start it.");
 +                storage.create(0);
 +            }
 +            LibvirtStoragePoolDef spd = getStoragePoolDef(conn, storage);
 +            if (spd == null) {
 +                throw new CloudRuntimeException("Unable to parse the storage 
pool definition for storage pool " + uuid);
 +            }
 +            StoragePoolType type = null;
 +            if (spd.getPoolType() == LibvirtStoragePoolDef.PoolType.NETFS) {
 +                type = StoragePoolType.NetworkFilesystem;
 +            } else if (spd.getPoolType() == 
LibvirtStoragePoolDef.PoolType.DIR) {
 +                type = StoragePoolType.Filesystem;
 +            } else if (spd.getPoolType() == 
LibvirtStoragePoolDef.PoolType.RBD) {
 +                type = StoragePoolType.RBD;
 +            } else if (spd.getPoolType() == 
LibvirtStoragePoolDef.PoolType.LOGICAL) {
 +                type = StoragePoolType.CLVM;
 +            } else if (spd.getPoolType() == 
LibvirtStoragePoolDef.PoolType.GLUSTERFS) {
 +                type = StoragePoolType.Gluster;
 +            }
 +
 +            LibvirtStoragePool pool = new LibvirtStoragePool(uuid, 
storage.getName(), type, this, storage);
 +
 +            if (pool.getType() != StoragePoolType.RBD)
 +                pool.setLocalPath(spd.getTargetPath());
 +            else
 +                pool.setLocalPath("");
 +
 +            if (pool.getType() == StoragePoolType.RBD
 +                    || pool.getType() == StoragePoolType.Gluster) {
 +                pool.setSourceHost(spd.getSourceHost());
 +                pool.setSourcePort(spd.getSourcePort());
 +                pool.setSourceDir(spd.getSourceDir());
 +                String authUsername = spd.getAuthUserName();
 +                if (authUsername != null) {
 +                    Secret secret = 
conn.secretLookupByUUIDString(spd.getSecretUUID());
 +                    String secretValue = new 
String(Base64.encodeBase64(secret.getByteValue()), Charset.defaultCharset());
 +                    pool.setAuthUsername(authUsername);
 +                    pool.setAuthSecret(secretValue);
 +                }
 +            }
 +
 +            /**
 +             * On large (RBD) storage pools it can take up to a couple of 
minutes
 +             * for libvirt to refresh the pool.
 +             *
 +             * Refreshing a storage pool means that libvirt will have to 
iterate the whole pool
 +             * and fetch information of each volume in there
 +             *
 +             * It is not always required to refresh a pool. So we can control 
if we want to or not
 +             *
 +             * By default only the getStorageStats call in the 
LibvirtComputingResource will ask to
 +             * refresh the pool
 +             */
 +            if (refreshInfo) {
 +                s_logger.info("Asking libvirt to refresh storage pool " + 
uuid);
 +                pool.refresh();
 +            }
 +            pool.setCapacity(storage.getInfo().capacity);
 +            pool.setUsed(storage.getInfo().allocation);
 +            pool.setAvailable(storage.getInfo().available);
 +
 +            s_logger.debug("Succesfully refreshed pool " + uuid +
 +                           " Capacity: " + storage.getInfo().capacity +
 +                           " Used: " + storage.getInfo().allocation +
 +                           " Available: " + storage.getInfo().available);
 +
 +            return pool;
 +        } catch (LibvirtException e) {
 +            s_logger.debug("Could not find storage pool " + uuid + " in 
libvirt");
 +            throw new CloudRuntimeException(e.toString(), e);
 +        }
 +    }
 +
 +    @Override
 +    public KVMPhysicalDisk getPhysicalDisk(String volumeUuid, KVMStoragePool 
pool) {
 +        LibvirtStoragePool libvirtPool = (LibvirtStoragePool)pool;
 +
 +        try {
 +            StorageVol vol = getVolume(libvirtPool.getPool(), volumeUuid);
 +            KVMPhysicalDisk disk;
 +            LibvirtStorageVolumeDef voldef = 
getStorageVolumeDef(libvirtPool.getPool().getConnect(), vol);
 +            disk = new KVMPhysicalDisk(vol.getPath(), vol.getName(), pool);
 +            disk.setSize(vol.getInfo().allocation);
 +            disk.setVirtualSize(vol.getInfo().capacity);
 +
 +            /**
 +             * libvirt returns format = 'unknow', so we have to force
 +             * the format to RAW for RBD storage volumes
 +             */
 +            if (pool.getType() == StoragePoolType.RBD) {
 +                disk.setFormat(PhysicalDiskFormat.RAW);
 +            } else if (voldef.getFormat() == null) {
 +                File diskDir = new File(disk.getPath());
 +                if (diskDir.exists() && diskDir.isDirectory()) {
 +                    disk.setFormat(PhysicalDiskFormat.DIR);
 +                } else if (volumeUuid.endsWith("tar") || 
volumeUuid.endsWith(("TAR"))) {
 +                    disk.setFormat(PhysicalDiskFormat.TAR);
 +                } else if (volumeUuid.endsWith("raw") || 
volumeUuid.endsWith(("RAW"))) {
 +                    disk.setFormat(PhysicalDiskFormat.RAW);
 +                } else {
 +                    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 (LibvirtException e) {
 +            s_logger.debug("Failed to get physical disk:", e);
 +            throw new CloudRuntimeException(e.toString());
 +        }
 +
 +    }
 +
 +    @Override
 +    public KVMStoragePool createStoragePool(String name, String host, int 
port, String path, String userInfo, StoragePoolType type) {
 +        s_logger.info("Attempting to create storage pool " + name + " (" + 
type.toString() + ") in libvirt");
 +
 +        StoragePool sp = null;
 +        Connect conn = null;
 +        try {
 +            conn = LibvirtConnection.getConnection();
 +        } catch (LibvirtException e) {
 +            throw new CloudRuntimeException(e.toString());
 +        }
 +
 +        try {
 +            sp = conn.storagePoolLookupByUUIDString(name);
 +            if (sp != null && sp.isActive() == 0) {
 +                sp.undefine();
 +                sp = null;
 +                s_logger.info("Found existing defined storage pool " + name + 
". It wasn't running, so we undefined it.");
 +            }
 +            if (sp != null) {
 +                s_logger.info("Found existing defined storage pool " + name + 
", using it.");
 +            }
 +        } catch (LibvirtException e) {
 +            sp = null;
 +            s_logger.warn("Storage pool " + name + " was not found running in 
libvirt. Need to create it.");
 +        }
 +
 +        // libvirt strips trailing slashes off of path, we will too in order 
to match
 +        // existing paths
 +        if (path.endsWith("/")) {
 +            path = path.substring(0, path.length() - 1);
 +        }
 +
 +        if (sp == null) {
 +            // see if any existing pool by another name is using our storage 
path.
 +            // if anyone is, undefine the pool so we can define it as 
requested.
 +            // This should be safe since a pool in use can't be removed, and 
no
 +            // volumes are affected by unregistering the pool with libvirt.
 +            s_logger.info("Didn't find an existing storage pool " + name + " 
by UUID, checking for pools with duplicate paths");
 +
 +            try {
 +                String[] poolnames = conn.listStoragePools();
 +                for (String poolname : poolnames) {
 +                    s_logger.debug("Checking path of existing pool " + 
poolname + " against pool we want to create");
 +                    StoragePool p = conn.storagePoolLookupByName(poolname);
 +                    LibvirtStoragePoolDef pdef = getStoragePoolDef(conn, p);
 +                    if (pdef == null) {
 +                        throw new CloudRuntimeException("Unable to parse the 
storage pool definition for storage pool " + poolname);
 +                    }
++
 +                    String targetPath = pdef.getTargetPath();
 +                    if (targetPath != null && targetPath.equals(path)) {
 +                        s_logger.debug("Storage pool utilizing path '" + path 
+ "' already exists as pool " + poolname +
 +                                ", undefining so we can re-define with 
correct name " + name);
 +                        if (p.isPersistent() == 1) {
 +                            p.destroy();
 +                            p.undefine();
 +                        } else {
 +                            p.destroy();
 +                        }
 +                    }
 +                }
 +            } catch (LibvirtException e) {
 +                s_logger.error("Failure in attempting to see if an existing 
storage pool might be using the path of the pool to be created:" + e);
 +            }
 +
 +            s_logger.debug("Attempting to create storage pool " + name);
 +
 +            if (type == StoragePoolType.NetworkFilesystem) {
 +                try {
 +                    sp = createNetfsStoragePool(PoolType.NETFS, conn, name, 
host, path);
 +                } catch (LibvirtException e) {
 +                    s_logger.error("Failed to create netfs mount: " + host + 
":" + path , e);
 +                    s_logger.error(e.getStackTrace());
 +                    throw new CloudRuntimeException(e.toString());
 +                }
 +            } else if (type == StoragePoolType.Gluster) {
 +                try {
 +                    sp = createNetfsStoragePool(PoolType.GLUSTERFS, conn, 
name, host, path);
 +                } catch (LibvirtException e) {
 +                    s_logger.error("Failed to create glusterfs mount: " + 
host + ":" + path , e);
 +                    s_logger.error(e.getStackTrace());
 +                    throw new CloudRuntimeException(e.toString());
 +                }
 +            } else if (type == StoragePoolType.SharedMountPoint || type == 
StoragePoolType.Filesystem) {
 +                sp = createSharedStoragePool(conn, name, host, path);
 +            } else if (type == StoragePoolType.RBD) {
 +                sp = createRBDStoragePool(conn, name, host, port, userInfo, 
path);
 +            } else if (type == StoragePoolType.CLVM) {
 +                sp = createCLVMStoragePool(conn, name, host, path);
 +            }
 +        }
 +
 +        if (sp == null) {
 +            throw new CloudRuntimeException("Failed to create storage pool: " 
+ name);
 +        }
 +
 +        try {
 +            if (sp.isActive() == 0) {
 +                s_logger.debug("Attempting to activate pool " + name);
 +                sp.create(0);
 +            }
 +
 +            return getStoragePool(name);
 +        } catch (LibvirtException e) {
 +            String error = e.toString();
 +            if (error.contains("Storage source conflict")) {
 +                throw new CloudRuntimeException("A pool matching this 
location already exists in libvirt, " +
 +                        " but has a different UUID/Name. Cannot create new 
pool without first " + " removing it. Check for inactive pools via 'virsh 
pool-list --all'. " +
 +                        error);
 +            } else {
 +                throw new CloudRuntimeException(error);
 +            }
 +        }
 +    }
 +
 +    @Override
 +    public boolean deleteStoragePool(String uuid) {
 +        s_logger.info("Attempting to remove storage pool " + uuid + " from 
libvirt");
 +        Connect conn = null;
 +        try {
 +            conn = LibvirtConnection.getConnection();
 +        } catch (LibvirtException e) {
 +            throw new CloudRuntimeException(e.toString());
 +        }
 +
 +        StoragePool sp = null;
 +        Secret s = null;
 +
 +        try {
 +            sp = conn.storagePoolLookupByUUIDString(uuid);
 +        } catch (LibvirtException e) {
 +            s_logger.warn("Storage pool " + uuid + " doesn't exist in 
libvirt. Assuming it is already removed");
 +            return true;
 +        }
 +
 +        /*
 +         * Some storage pools, like RBD also have 'secret' information stored 
in libvirt
 +         * Destroy them if they exist
 +         */
 +        try {
 +            s = conn.secretLookupByUUIDString(uuid);
 +        } catch (LibvirtException e) {
 +            s_logger.info("Storage pool " + uuid + " has no corresponding 
secret. Not removing any secret.");
 +        }
 +
 +        try {
 +            if (sp.isPersistent() == 1) {
 +                sp.destroy();
 +                sp.undefine();
 +            } else {
 +                sp.destroy();
 +            }
 +            sp.free();
 +            if (s != null) {
 +                s.undefine();
 +                s.free();
 +            }
 +
 +            s_logger.info("Storage pool " + uuid + " was succesfully removed 
from libvirt.");
 +
 +            return true;
 +        } catch (LibvirtException e) {
 +            // handle ebusy error when pool is quickly destroyed
 +            if (e.toString().contains("exit status 16")) {
 +                String targetPath = _mountPoint + File.separator + uuid;
 +                s_logger.error("deleteStoragePool removed pool from libvirt, 
but libvirt had trouble unmounting the pool. Trying umount location " + 
targetPath +
 +                        "again in a few seconds");
 +                String result = Script.runSimpleBashScript("sleep 5 && umount 
" + targetPath);
 +                if (result == null) {
 +                    s_logger.error("Succeeded in unmounting " + targetPath);
 +                    return true;
 +                }
 +                s_logger.error("Failed to unmount " + targetPath);
 +            }
 +            throw new CloudRuntimeException(e.toString(), e);
 +        }
 +    }
 +
 +    @Override
 +    public KVMPhysicalDisk createPhysicalDisk(String name, KVMStoragePool 
pool,
 +            PhysicalDiskFormat format, Storage.ProvisioningType 
provisioningType, long size) {
 +
 +        s_logger.info("Attempting to create volume " + name + " (" + 
pool.getType().toString() + ") in pool "
 +                + pool.getUuid() + " with size " + size);
 +
 +        switch (pool.getType()) {
 +            case RBD:
-                 return createPhysicalDiskByLibVirt(name, pool, format, 
provisioningType, size);
++                return createPhysicalDiskByLibVirt(name, pool, 
PhysicalDiskFormat.RAW, provisioningType, size);
 +            case NetworkFilesystem:
 +            case Filesystem:
 +                switch (format) {
 +                    case QCOW2:
 +                        return createPhysicalDiskByQemuImg(name, pool, 
format, provisioningType, size);
 +                    case RAW:
 +                        return createPhysicalDiskByQemuImg(name, pool, 
format, provisioningType, size);
 +                    case DIR:
 +                        return createPhysicalDiskByLibVirt(name, pool, 
format, provisioningType, size);
 +                    case TAR:
 +                        return createPhysicalDiskByLibVirt(name, pool, 
format, provisioningType, size);
 +                    default:
 +                        throw new CloudRuntimeException("Unexpected disk 
format is specified.");
 +                }
 +            default:
 +                return createPhysicalDiskByLibVirt(name, pool, format, 
provisioningType, size);
 +        }
 +    }
 +
 +    private KVMPhysicalDisk createPhysicalDiskByLibVirt(String name, 
KVMStoragePool pool,
 +            PhysicalDiskFormat format, Storage.ProvisioningType 
provisioningType, long size) {
 +        LibvirtStoragePool libvirtPool = (LibvirtStoragePool) pool;
 +        StoragePool virtPool = libvirtPool.getPool();
 +        LibvirtStorageVolumeDef.VolumeFormat libvirtformat = 
LibvirtStorageVolumeDef.VolumeFormat.getFormat(format);
 +
 +        String volPath = null;
 +        String volName = null;
 +        long volAllocation = 0;
 +        long volCapacity = 0;
 +
 +        LibvirtStorageVolumeDef volDef = new LibvirtStorageVolumeDef(name,
 +                size, libvirtformat, null, null);
 +        s_logger.debug(volDef.toString());
 +        try {
 +            StorageVol vol = virtPool.storageVolCreateXML(volDef.toString(), 
0);
 +            volPath = vol.getPath();
 +            volName = vol.getName();
 +            volAllocation = vol.getInfo().allocation;
 +            volCapacity = vol.getInfo().capacity;
 +        } catch (LibvirtException e) {
 +            throw new CloudRuntimeException(e.toString());
 +        }
 +
 +        KVMPhysicalDisk disk = new KVMPhysicalDisk(volPath, volName, pool);
 +        disk.setFormat(format);
 +        disk.setSize(volAllocation);
 +        disk.setVirtualSize(volCapacity);
 +        return disk;
 +    }
 +
 +
 +    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;
 +    }
 +
 +    @Override
 +    public boolean connectPhysicalDisk(String name, KVMStoragePool pool, 
Map<String, String> details) {
 +        // this is for managed storage that needs to prep disks prior to use
 +        return true;
 +    }
 +
 +    @Override
 +    public boolean disconnectPhysicalDisk(String uuid, KVMStoragePool pool) {
 +        // this is for managed storage that needs to cleanup disks after use
 +        return true;
 +    }
 +
 +    @Override
 +    public boolean disconnectPhysicalDisk(Map<String, String> 
volumeToDisconnect) {
 +        // this is for managed storage that needs to cleanup disks after use
 +        return false;
 +    }
 +
 +    @Override
 +    public boolean disconnectPhysicalDiskByPath(String localPath) {
 +        // we've only ever cleaned up ISOs that are NFS mounted
 +        String poolUuid = null;
 +        if (localPath != null && localPath.startsWith(_mountPoint) && 
localPath.endsWith(".iso")) {
 +            String[] token = localPath.split("/");
 +
 +            if (token.length > 3) {
 +                poolUuid = token[2];
 +            }
 +        } else {
 +            return false;
 +        }
 +
 +        if (poolUuid == null) {
 +            return false;
 +        }
 +
 +        try {
 +            Connect conn = LibvirtConnection.getConnection();
 +
 +            conn.storagePoolLookupByUUIDString(poolUuid);
 +
 +            deleteStoragePool(poolUuid);
 +
 +            return true;
 +        } catch (LibvirtException ex) {
 +            return false;
 +        } catch (CloudRuntimeException ex) {
 +            return false;
 +        }
 +    }
 +
 +    @Override
 +    public boolean deletePhysicalDisk(String uuid, KVMStoragePool pool, 
Storage.ImageFormat format) {
 +
 +        s_logger.info("Attempting to remove volume " + uuid + " from pool " + 
pool.getUuid());
 +
 +        /**
 +         * RBD volume can have snapshots and while they exist libvirt
 +         * can't remove the RBD volume
 +         *
 +         * We have to remove those snapshots first
 +         */
 +        if (pool.getType() == StoragePoolType.RBD) {
 +            try {
 +                s_logger.info("Unprotecting and Removing RBD snapshots of 
image " + pool.getSourceDir() + "/" + uuid + " prior to removing the image");
 +
 +                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();
 +                s_logger.debug("Succesfully connected to Ceph cluster at " + 
r.confGet("mon_host"));
 +
 +                IoCTX io = r.ioCtxCreate(pool.getSourceDir());
 +                Rbd rbd = new Rbd(io);
 +                RbdImage image = rbd.open(uuid);
 +                s_logger.debug("Fetching list of snapshots of RBD image " + 
pool.getSourceDir() + "/" + uuid);
 +                List<RbdSnapInfo> snaps = image.snapList();
 +                try {
 +                    for (RbdSnapInfo snap : snaps) {
 +                        if (image.snapIsProtected(snap.name)) {
 +                            s_logger.debug("Unprotecting snapshot " + 
pool.getSourceDir() + "/" + uuid + "@" + snap.name);
 +                            image.snapUnprotect(snap.name);
 +                        } else {
 +                            s_logger.debug("Snapshot " + pool.getSourceDir() 
+ "/" + uuid + "@" + snap.name + " is not protected.");
 +                        }
 +                        s_logger.debug("Removing snapshot " + 
pool.getSourceDir() + "/" + uuid + "@" + snap.name);
 +                        image.snapRemove(snap.name);
 +                    }
 +                    s_logger.info("Succesfully unprotected and removed any 
remaining snapshots (" + snaps.size() + ") of "
 +                        + pool.getSourceDir() + "/" + uuid + " Continuing to 
remove the RBD image");
 +                } catch (RbdException e) {
 +                    s_logger.error("Failed to remove snapshot with exception: 
" + e.toString() +
 +                        ", RBD error: " + 
ErrorCode.getErrorMessage(e.getReturnValue()));
 +                    throw new CloudRuntimeException(e.toString() + " - " + 
ErrorCode.getErrorMessage(e.getReturnValue()));
 +                } finally {
 +                    s_logger.debug("Closing image and destroying context");
 +                    rbd.close(image);
 +                    r.ioCtxDestroy(io);
 +                }
 +            } catch (RadosException e) {
 +                s_logger.error("Failed to remove snapshot with exception: " + 
e.toString() +
 +                    ", RBD error: " + 
ErrorCode.getErrorMessage(e.getReturnValue()));
 +                throw new CloudRuntimeException(e.toString() + " - " + 
ErrorCode.getErrorMessage(e.getReturnValue()));
 +            } catch (RbdException e) {
 +                s_logger.error("Failed to remove snapshot with exception: " + 
e.toString() +
 +                    ", RBD error: " + 
ErrorCode.getErrorMessage(e.getReturnValue()));
 +                throw new CloudRuntimeException(e.toString() + " - " + 
ErrorCode.getErrorMessage(e.getReturnValue()));
 +            }
 +        }
 +
 +        LibvirtStoragePool libvirtPool = (LibvirtStoragePool)pool;
 +        try {
 +            StorageVol vol = getVolume(libvirtPool.getPool(), uuid);
 +            s_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 (LibvirtException e) {
 +            throw new CloudRuntimeException(e.toString());
 +        }
 +    }
 +
 +    /**
 +     * This function copies a physical disk from Secondary Storage to Primary 
Storage
 +     * or from Primary to Primary Storage
 +     *
 +     * The first time a template is deployed in Primary Storage it will be 
copied from
 +     * Secondary to Primary.
 +     *
 +     * If it has been created on Primary Storage, it will be copied on the 
Primary Storage
 +     */
 +    @Override
 +    public KVMPhysicalDisk createDiskFromTemplate(KVMPhysicalDisk template,
 +            String name, PhysicalDiskFormat format, Storage.ProvisioningType 
provisioningType, long size, KVMStoragePool destPool, int timeout) {
 +
 +        s_logger.info("Creating volume " + name + " from template " + 
template.getName() + " in pool " + destPool.getUuid() +
 +                " (" + destPool.getType().toString() + ") with size " + size);
 +
 +        KVMPhysicalDisk disk = null;
 +
 +        if (destPool.getType() == StoragePoolType.RBD) {
 +            disk = createDiskFromTemplateOnRBD(template, name, format, 
provisioningType, size, destPool, timeout);
 +        } else {
 +            try {
 +                String newUuid = name;
 +                disk = destPool.createPhysicalDisk(newUuid, format, 
provisioningType, template.getVirtualSize());
 +                if (disk == null) {
 +                    throw new CloudRuntimeException("Failed to create disk 
from template " + template.getName());
 +                }
 +                if (template.getFormat() == PhysicalDiskFormat.TAR) {
 +                    Script.runSimpleBashScript("tar -x -f " + 
template.getPath() + " -C " + disk.getPath(), timeout); // TO BE FIXED to aware 
provisioningType
 +                } else if (template.getFormat() == PhysicalDiskFormat.DIR) {
 +                    Script.runSimpleBashScript("mkdir -p " + disk.getPath());
 +                    Script.runSimpleBashScript("chmod 755 " + disk.getPath());
 +                    Script.runSimpleBashScript("tar -x -f " + 
template.getPath() + "/*.tar -C " + disk.getPath(), timeout);
 +                } else if (format == PhysicalDiskFormat.QCOW2) {
 +                    QemuImg qemu = new QemuImg(timeout);
 +                    QemuImgFile destFile = new QemuImgFile(disk.getPath(), 
format);
 +                    if (size > template.getVirtualSize()) {
 +                        destFile.setSize(size);
 +                    } else {
 +                        destFile.setSize(template.getVirtualSize());
 +                    }
 +                    Map<String, String> options = new HashMap<String, 
String>();
 +                    options.put("preallocation", 
QemuImg.PreallocationType.getPreallocationType(provisioningType).toString());
 +                    switch(provisioningType){
 +                    case THIN:
 +                        QemuImgFile backingFile = new 
QemuImgFile(template.getPath(), template.getFormat());
 +                        qemu.create(destFile, backingFile, options);
 +                        break;
 +                    case SPARSE:
 +                    case FAT:
 +                        QemuImgFile srcFile = new 
QemuImgFile(template.getPath(), template.getFormat());
 +                        qemu.convert(srcFile, destFile, options);
 +                        break;
 +                    }
 +                } else if (format == PhysicalDiskFormat.RAW) {
 +                    QemuImgFile sourceFile = new 
QemuImgFile(template.getPath(), template.getFormat());
 +                    QemuImgFile destFile = new QemuImgFile(disk.getPath(), 
PhysicalDiskFormat.RAW);
 +                    if (size > template.getVirtualSize()) {
 +                        destFile.setSize(size);
 +                    } else {
 +                        destFile.setSize(template.getVirtualSize());
 +                    }
 +                    QemuImg qemu = new QemuImg(timeout);
 +                    Map<String, String> options = new HashMap<String, 
String>();
 +                    qemu.convert(sourceFile, destFile, options);
 +                }
 +            } catch (QemuImgException e) {
 +                s_logger.error("Failed to create " + disk.getPath() +
 +                        " due to a failed executing of qemu-img: " + 
e.getMessage());
 +            }
 +        }
 +
 +
 +        return disk;
 +    }
 +
 +    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 {
 +
 +            /**
 +             * We have to find out if the source file is in the same RBD pool 
and has
 +             * RBD format 2 before we can do a layering/clone operation on 
the RBD image
 +             *
 +             * This will be the case when the template is already on Primary 
Storage and
 +             * we want to copy it
 +             */
 +
 +            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;
 +    }
 +
 +    @Override
 +    public KVMPhysicalDisk createTemplateFromDisk(KVMPhysicalDisk disk, 
String name, PhysicalDiskFormat format, long size, KVMStoragePool destPool) {
 +        return null;
 +    }
 +
 +    @Override
 +    public List<KVMPhysicalDisk> listPhysicalDisks(String storagePoolUuid, 
KVMStoragePool pool) {
 +        LibvirtStoragePool libvirtPool = (LibvirtStoragePool)pool;
 +        StoragePool virtPool = libvirtPool.getPool();
 +        List<KVMPhysicalDisk> disks = new ArrayList<KVMPhysicalDisk>();
 +        try {
 +            String[] vols = virtPool.listVolumes();
 +            for (String volName : vols) {
 +                KVMPhysicalDisk disk = getPhysicalDisk(volName, pool);
 +                disks.add(disk);
 +            }
 +            return disks;
 +        } catch (LibvirtException e) {
 +            throw new CloudRuntimeException(e.toString());
 +        }
 +    }
 +
 +    /**
 +     * 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;
 +    }
 +
 +    @Override
 +    public KVMPhysicalDisk createDiskFromSnapshot(KVMPhysicalDisk snapshot, 
String snapshotName, String name, KVMStoragePool destPool) {
 +        return null;
 +    }
 +
 +    @Override
 +    public boolean refresh(KVMStoragePool pool) {
 +        LibvirtStoragePool libvirtPool = (LibvirtStoragePool)pool;
 +        StoragePool virtPool = libvirtPool.getPool();
 +        try {
 +            refreshPool(virtPool);
 +        } catch (LibvirtException e) {
 +            return false;
 +        }
 +        return true;
 +    }
 +
 +    @Override
 +    public boolean deleteStoragePool(KVMStoragePool pool) {
 +        return deleteStoragePool(pool.getUuid());
 +    }
 +
 +    private void refreshPool(StoragePool pool) throws LibvirtException {
 +        pool.refresh(0);
 +        return;
 +    }
 +
 +    private void deleteVol(LibvirtStoragePool pool, StorageVol vol) throws 
LibvirtException {
 +        vol.delete(0);
 +    }
 +
 +    private void deleteDirVol(LibvirtStoragePool pool, StorageVol vol) throws 
LibvirtException {
 +        Script.runSimpleBashScript("rm -r --interactive=never " + 
vol.getPath());
 +    }
 +
 +}

-- 
To stop receiving notification emails like this one, please contact
[email protected].

Reply via email to