diff --git a/ovm/scripts/vm/hypervisor/ovm/OvmFaultConstants.py b/ovm/scripts/vm/hypervisor/ovm/OvmFaultConstants.py index 4ed10984623..1344c44fe9d 100755 --- a/ovm/scripts/vm/hypervisor/ovm/OvmFaultConstants.py +++ b/ovm/scripts/vm/hypervisor/ovm/OvmFaultConstants.py @@ -40,6 +40,7 @@ errCode = { "OvmStoragePool.prepareOCFS2Nodes":OvmStoragePoolErrCodeStub+4, "OvmStoragePool.createTemplateFromVolume":OvmStoragePoolErrCodeStub+5, "OvmStoragePool._umount":OvmStoragePoolErrCodeStub+6, + "OvmStoragePool.copyVolume":OvmStoragePoolErrCodeStub+7, "OvmNetwork.createBridge":OvmNetworkErrCodeStub+1, "OvmNetwork.deleteBridge":OvmNetworkErrCodeStub+2, diff --git a/ovm/scripts/vm/hypervisor/ovm/OvmStoragePoolModule.py b/ovm/scripts/vm/hypervisor/ovm/OvmStoragePoolModule.py index ad97861094a..658f7c5400f 100755 --- a/ovm/scripts/vm/hypervisor/ovm/OvmStoragePoolModule.py +++ b/ovm/scripts/vm/hypervisor/ovm/OvmStoragePoolModule.py @@ -351,6 +351,8 @@ if this doesn't resolve the problem, please check oracle manual to see how to of OvmStoragePool()._mount(secStorageMountPath, secMountPoint) installPath = installPath.lstrip('/') destPath = join(secMountPoint, installPath) + #This prevent us deleting whole secondary in case we got a wrong installPath + if destPath == secMountPoint: raise Exception("Install path equals to root of secondary storage(%s)"%destPath) if exists(destPath): logger.warning("%s is already here, delete it since it is most likely stale"%destPath) doCmd(['rm', '-rf', destPath]) @@ -376,5 +378,60 @@ if this doesn't resolve the problem, please check oracle manual to see how to of errmsg = fmt_err_msg(e) logger.error(OvmStoragePool.createTemplateFromVolume, errmsg) raise XmlRpcFault(toErrCode(OvmStoragePool, OvmStoragePool.createTemplateFromVolume), errmsg) + + @staticmethod + def copyVolume(secStorageMountPath, volumeFolderOnSecStorage, volumePath, storagePoolUuid, toSec): + def copyToSecStorage(secMountPoint, volumeFolderOnSecStorage, volumePath): + if not isfile(volumePath): raise Exception("Cannot find volume at %s"%volumePath) + OvmStoragePool()._checkDirSizeForImage(secMountPoint, volumePath) + volumeFolderOnSecStorage = volumeFolderOnSecStorage.lstrip("/") + destPath = join(secMountPoint, volumeFolderOnSecStorage) + #This prevent us deleting whole secondary in case we got a wrong volumeFolderOnSecStorage + if destPath == secMountPoint: raise Exception("volume path equals to root of secondary storage(%s)"%destPath) + if exists(destPath): + logger.warning("%s already exists, delete it first"%destPath) + doCmd(['rm', '-rf', destPath]) + os.makedirs(destPath) + newName = get_uuid() + ".raw" + destName = join(destPath, newName) + doCmd(['cp', volumePath, destName]) + return destName + + def copyToPrimary(secMountPoint, volumeFolderOnSecStorage, volumePath, primaryMountPath): + srcPath = join(secMountPoint, volumeFolderOnSecStorage.lstrip("/"), volumePath.lstrip("/")) + if not isfile(srcPath): raise Exception("Cannot find volume at %s"%srcPath) + if not exists(primaryMountPath): raise Exception("Primary storage(%s) seems to have gone"%primaryMountPath) + OvmStoragePool()._checkDirSizeForImage(primaryMountPath, srcPath) + destPath = join(primaryMountPath, "sharedDisk") + newName = get_uuid() + ".raw" + destName = join(destPath, newName) + doCmd(['cp', srcPath, destName]) + return destName + + secMountPoint = "" + try: + tmpUuid = get_uuid() + secMountPoint = join("/var/cloud/", tmpUuid) + OvmStoragePool()._mount(secStorageMountPath, secMountPoint) + if toSec: + resultPath = copyToSecStorage(secMountPoint, volumeFolderOnSecStorage, volumePath) + else: + sr = OvmStoragePool()._getSrByNameLable(storagePoolUuid) + primaryStoragePath = sr.mountpoint + resultPath = copyToPrimary(secMountPoint, volumeFolderOnSecStorage, volumePath, primaryStoragePath) + OvmStoragePool()._umount(secMountPoint) + rs = toGson({"installPath":resultPath}) + return rs + except Exception, e: + try: + if exists(secMountPoint): + OvmStoragePool()._umount(secMountPoint) + except Exception, e: + logger.warning(OvmStoragePool.copyVolume, "umount %s failed"%secMountPoint) + + errmsg = fmt_err_msg(e) + logger.error(OvmStoragePool.copyVolume, errmsg) + raise XmlRpcFault(toErrCode(OvmStoragePool, OvmStoragePool.copyVolume), errmsg) + \ No newline at end of file diff --git a/ovm/src/com/cloud/ovm/hypervisor/OvmResourceBase.java b/ovm/src/com/cloud/ovm/hypervisor/OvmResourceBase.java index adb0c193ab5..ce030230216 100755 --- a/ovm/src/com/cloud/ovm/hypervisor/OvmResourceBase.java +++ b/ovm/src/com/cloud/ovm/hypervisor/OvmResourceBase.java @@ -64,6 +64,8 @@ import com.cloud.agent.api.StartupRoutingCommand; import com.cloud.agent.api.StopAnswer; import com.cloud.agent.api.StopCommand; import com.cloud.agent.api.VmStatsEntry; +import com.cloud.agent.api.storage.CopyVolumeAnswer; +import com.cloud.agent.api.storage.CopyVolumeCommand; import com.cloud.agent.api.storage.CreateAnswer; import com.cloud.agent.api.storage.CreateCommand; import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer; @@ -1191,6 +1193,28 @@ public class OvmResourceBase implements ServerResource, HypervisorResource { } } + protected CopyVolumeAnswer execute(CopyVolumeCommand cmd) { + String volumePath = cmd.getVolumePath(); + String secondaryStorageURL = cmd.getSecondaryStorageURL(); + int wait = cmd.getWait(); + if (wait == 0) { + wait = 7200; + } + + try { + URI uri = new URI(secondaryStorageURL); + String secStorageMountPath = uri.getHost() + ":" + uri.getPath(); + String volumeFolderOnSecStorage = "volumes/" + String.valueOf(cmd.getVolumeId()); + String storagePoolUuid = cmd.getPool().getUuid(); + Boolean toSec = cmd.toSecondaryStorage(); + String res = OvmStoragePool.copyVolume(_conn, secStorageMountPath, volumeFolderOnSecStorage, volumePath, storagePoolUuid, toSec, wait); + return new CopyVolumeAnswer(cmd, true, null, null, res); + } catch (Exception e) { + s_logger.debug("Copy volume failed", e); + return new CopyVolumeAnswer(cmd, false, e.getMessage(), null, null); + } + } + @Override public Answer executeRequest(Command cmd) { Class clazz = cmd.getClass(); @@ -1244,6 +1268,8 @@ public class OvmResourceBase implements ServerResource, HypervisorResource { return execute((PrepareOCFS2NodesCommand)cmd); } else if (clazz == CreatePrivateTemplateFromVolumeCommand.class) { return execute((CreatePrivateTemplateFromVolumeCommand)cmd); + } else if (clazz == CopyVolumeCommand.class) { + return execute((CopyVolumeCommand)cmd); }else { return Answer.createUnsupportedCommandAnswer(cmd); } diff --git a/ovm/src/com/cloud/ovm/object/OvmStoragePool.java b/ovm/src/com/cloud/ovm/object/OvmStoragePool.java index fc196929c80..a9af7520b56 100755 --- a/ovm/src/com/cloud/ovm/object/OvmStoragePool.java +++ b/ovm/src/com/cloud/ovm/object/OvmStoragePool.java @@ -74,4 +74,11 @@ public class OvmStoragePool extends OvmObject { Map info = Coder.mapFromJson(res); return info; } + + public static String copyVolume(Connection c, String secStorageMountPath, String volumeFolderOnSecStorage, String volumePath, String storagePoolUuid, Boolean toSec, int timeout) throws XmlRpcException { + Object[] params = {secStorageMountPath, volumeFolderOnSecStorage, volumePath, storagePoolUuid, toSec}; + String res = (String) c.callTimeoutInSec("OvmStoragePool.copyVolume", params, timeout); + Map info = Coder.mapFromJson(res); + return (String) info.get("installPath"); + } }