diff --git a/agent/src/com/cloud/agent/resource/computing/LibvirtComputingResource.java b/agent/src/com/cloud/agent/resource/computing/LibvirtComputingResource.java index fa346e79b1f..6ae752fd200 100644 --- a/agent/src/com/cloud/agent/resource/computing/LibvirtComputingResource.java +++ b/agent/src/com/cloud/agent/resource/computing/LibvirtComputingResource.java @@ -1228,21 +1228,46 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv protected ManageSnapshotAnswer execute(final ManageSnapshotCommand cmd) { String snapshotName = cmd.getSnapshotName(); String VolPath = cmd.getVolumePath(); + String snapshotPath = cmd.getSnapshotPath(); + String vmName = cmd.getVmName(); try { - StorageVol vol = getVolume(VolPath); - if (vol == null) { - return new ManageSnapshotAnswer(cmd, false, null); + DomainInfo.DomainState state = null; + Domain vm = null; + if (vmName != null) { + try { + vm = getDomain(cmd.getVmName()); + state = vm.getInfo().state; + } catch (LibvirtException e) { + + } } - Domain vm = getDomain(cmd.getVmName()); - String vmUuid = vm.getUUIDString(); - Object[] args = new Object[] {snapshotName, vmUuid}; - String snapshot = SnapshotXML.format(args); - s_logger.debug(snapshot); - if (cmd.getCommandSwitch().equalsIgnoreCase(ManageSnapshotCommand.CREATE_SNAPSHOT)) { - vm.snapshotCreateXML(snapshot); + + if (state == DomainInfo.DomainState.VIR_DOMAIN_RUNNING) { + String vmUuid = vm.getUUIDString(); + Object[] args = new Object[] {snapshotName, vmUuid}; + String snapshot = SnapshotXML.format(args); + s_logger.debug(snapshot); + if (cmd.getCommandSwitch().equalsIgnoreCase(ManageSnapshotCommand.CREATE_SNAPSHOT)) { + vm.snapshotCreateXML(snapshot); + } else { + DomainSnapshot snap = vm.snapshotLookupByName(snapshotName); + snap.delete(0); + } } else { - DomainSnapshot snap = vm.snapshotLookupByName(snapshotName); - snap.delete(0); + /*VM is not running, create a snapshot by ourself*/ + final Script command = new Script(_manageSnapshotPath, _timeout, s_logger); + if (cmd.getCommandSwitch().equalsIgnoreCase(ManageSnapshotCommand.CREATE_SNAPSHOT)) { + command.add("-c", VolPath); + } else { + command.add("-d", snapshotPath); + } + + command.add("-n", snapshotName); + String result = command.execute(); + if (result != null) { + s_logger.debug("Failed to manage snapshot: " + result); + return new ManageSnapshotAnswer(cmd, false, "Failed to manage snapshot: " + result); + } } } catch (LibvirtException e) { s_logger.debug("Failed to manage snapshot: " + e.toString()); @@ -1259,28 +1284,52 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv String snapshotName = cmd.getSnapshotName(); String snapshotPath = cmd.getSnapshotUuid(); String snapshotDestPath = null; + String vmName = cmd.getVmName(); try { StoragePool secondaryStoragePool = getNfsSPbyURI(_conn, new URI(secondaryStoragePoolURL)); String ssPmountPath = _mountPoint + File.separator + secondaryStoragePool.getUUIDString(); snapshotDestPath = ssPmountPath + File.separator + dcId + File.separator + "snapshots" + File.separator + accountId + File.separator + volumeId; - final Script command = new Script(_manageSnapshotPath, _timeout, s_logger); + Script command = new Script(_manageSnapshotPath, _timeout, s_logger); command.add("-b", snapshotPath); command.add("-n", snapshotName); command.add("-p", snapshotDestPath); + command.add("-t", snapshotName); String result = command.execute(); if (result != null) { s_logger.debug("Failed to backup snaptshot: " + result); return new BackupSnapshotAnswer(cmd, false, result, null); } /*Delete the snapshot on primary*/ - Domain vm = getDomain(cmd.getVmName()); - String vmUuid = vm.getUUIDString(); - Object[] args = new Object[] {snapshotName, vmUuid}; - String snapshot = SnapshotXML.format(args); - s_logger.debug(snapshot); - DomainSnapshot snap = vm.snapshotLookupByName(snapshotName); - snap.delete(0); + + DomainInfo.DomainState state = null; + Domain vm = null; + if (vmName != null) { + try { + vm = getDomain(cmd.getVmName()); + state = vm.getInfo().state; + } catch (LibvirtException e) { + + } + } + + if (state == DomainInfo.DomainState.VIR_DOMAIN_RUNNING) { + String vmUuid = vm.getUUIDString(); + Object[] args = new Object[] {snapshotName, vmUuid}; + String snapshot = SnapshotXML.format(args); + s_logger.debug(snapshot); + DomainSnapshot snap = vm.snapshotLookupByName(snapshotName); + snap.delete(0); + } else { + command = new Script(_manageSnapshotPath, _timeout, s_logger); + command.add("-d", snapshotPath); + command.add("-n", snapshotName); + result = command.execute(); + if (result != null) { + s_logger.debug("Failed to backup snapshot: " + result); + return new BackupSnapshotAnswer(cmd, false, "Failed to backup snapshot: " + result, null); + } + } } catch (LibvirtException e) { return new BackupSnapshotAnswer(cmd, false, e.toString(), null); } catch (URISyntaxException e) { @@ -1356,7 +1405,11 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv try { secondaryPool = getNfsSPbyURI(_conn, new URI(cmd.getSecondaryStoragePoolURL())); /*TODO: assuming all the storage pools mounted under _mountPoint, the mount point should be got from pool.dumpxml*/ - String templatePath = _mountPoint + File.separator + secondaryPool.getUUIDString() + File.separator + templateInstallFolder; + String templatePath = _mountPoint + File.separator + secondaryPool.getUUIDString() + File.separator + templateInstallFolder; + File f = new File(templatePath); + if (!f.exists()) { + f.mkdir(); + } String tmplPath = templateInstallFolder + File.separator + tmplFileName; Script command = new Script(_createTmplPath, _timeout, s_logger); command.add("-t", templatePath); @@ -1403,38 +1456,58 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv } protected CreatePrivateTemplateAnswer execute(CreatePrivateTemplateCommand cmd) { String secondaryStorageURL = cmd.getSecondaryStorageURL(); - String snapshotUUID = cmd.getSnapshotPath(); StoragePool secondaryStorage = null; - StoragePool privateTemplStorage = null; - StorageVol privateTemplateVol = null; - StorageVol snapshotVol = null; try { String templateFolder = cmd.getAccountId() + File.separator + cmd.getTemplateId() + File.separator; String templateInstallFolder = "/template/tmpl/" + templateFolder; - + secondaryStorage = getNfsSPbyURI(_conn, new URI(secondaryStorageURL)); /*TODO: assuming all the storage pools mounted under _mountPoint, the mount point should be got from pool.dumpxml*/ - String mountPath = _mountPoint + File.separator + secondaryStorage.getUUIDString() + templateInstallFolder; - File mpfile = new File(mountPath); + String tmpltPath = _mountPoint + File.separator + secondaryStorage.getUUIDString() + templateInstallFolder; + File mpfile = new File(tmpltPath); if (!mpfile.exists()) { mpfile.mkdir(); } + + Script command = new Script(_createTmplPath, _timeout, s_logger); + command.add("-f", cmd.getSnapshotPath()); + command.add("-c", cmd.getSnapshotName()); + command.add("-t", tmpltPath); + command.add("-n", cmd.getUniqueName() + ".qcow2"); + command.add("-s"); + String result = command.execute(); - // Create a SR for the secondary storage installation folder - privateTemplStorage = getNfsSPbyURI(_conn, new URI(secondaryStorageURL + templateInstallFolder)); - snapshotVol = getVolume(snapshotUUID); - - LibvirtStorageVolumeDef vol = new LibvirtStorageVolumeDef(UUID.randomUUID().toString(), snapshotVol.getInfo().capacity, volFormat.QCOW2, null, null); - s_logger.debug(vol.toString()); - privateTemplateVol = copyVolume(privateTemplStorage, vol, snapshotVol); + if (result != null) { + s_logger.debug("failed to create template: " + result); + return new CreatePrivateTemplateAnswer(cmd, + false, + result, + null, + 0, + null, + null); + } + + Map params = new HashMap(); + params.put(StorageLayer.InstanceConfigKey, _storage); + Processor qcow2Processor = new QCOW2Processor(); + + qcow2Processor.configure("QCOW2 Processor", params); + + FormatInfo info = qcow2Processor.process(tmpltPath, null, cmd.getUniqueName()); + + TemplateLocation loc = new TemplateLocation(_storage, tmpltPath); + loc.create(1, true, cmd.getUniqueName()); + loc.addFormat(info); + loc.save(); return new CreatePrivateTemplateAnswer(cmd, true, null, - templateInstallFolder + privateTemplateVol.getName(), - privateTemplateVol.getInfo().capacity/1024*1024, /*in Mega unit*/ - privateTemplateVol.getName(), + templateInstallFolder + cmd.getUniqueName() + ".qcow2", + info.virtualSize, + cmd.getUniqueName(), ImageFormat.QCOW2); } catch (URISyntaxException e) { return new CreatePrivateTemplateAnswer(cmd, @@ -1453,7 +1526,31 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv 0, null, null); - } + } catch (InternalErrorException e) { + return new CreatePrivateTemplateAnswer(cmd, + false, + e.toString(), + null, + 0, + null, + null); + } catch (IOException e) { + return new CreatePrivateTemplateAnswer(cmd, + false, + e.toString(), + null, + 0, + null, + null); + } catch (ConfigurationException e) { + return new CreatePrivateTemplateAnswer(cmd, + false, + e.toString(), + null, + 0, + null, + null); + } } private StoragePool getNfsSPbyURI(Connect conn, URI uri) throws LibvirtException { @@ -3165,7 +3262,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv String datadiskPath = tmplVol.getKey(); diskDef hda = new diskDef(); - hda.defFileBasedDisk(rootkPath, "vda", diskDef.diskBus.IDE, diskDef.diskFmtType.QCOW2); + hda.defFileBasedDisk(rootkPath, "hda", diskDef.diskBus.IDE, diskDef.diskFmtType.QCOW2); disks.add(hda); diskDef hdb = new diskDef(); diff --git a/scripts/storage/qcow2/createtmplt.sh b/scripts/storage/qcow2/createtmplt.sh index 55efe952af5..ef75c6270e9 100755 --- a/scripts/storage/qcow2/createtmplt.sh +++ b/scripts/storage/qcow2/createtmplt.sh @@ -80,6 +80,20 @@ create_from_file() { fi } +create_from_snapshot() { + local tmpltImg=$1 + local snapshotName=$2 + local tmpltfs=$3 + local tmpltname=$4 + + cloud-qemu-img convert -f qcow2 -O qcow2 -s $snapshotName $tmpltImg /$tmpltfs/$tmpltname >& /dev/null + if [ $? -gt 0 ] + then + printf "Failed to create template /$tmplfs/$tmpltname from snapshot $snapshotName on disk $tmpltImg " + exit 2 + fi +} + tflag= nflag= fflag= @@ -89,8 +103,9 @@ hvm=false cleanup=false dflag= cflag= +snapshotName= -while getopts 'uht:n:f:s:c:d:' OPTION +while getopts 'uht:n:f:sc:d:' OPTION do case $OPTION in t) tflag=1 @@ -103,10 +118,10 @@ do tmpltimg="$OPTARG" ;; s) sflag=1 - volsize="$OPTARG" + sflag=1 ;; c) cflag=1 - cksum="$OPTARG" + snapshotName="$OPTARG" ;; d) dflag=1 descr="$OPTARG" @@ -119,12 +134,6 @@ do esac done -if [ "$tflag$nflag$fflag" != "111" ] -then - usage - exit 2 -fi - if [ ! -d /$tmpltfs ] then @@ -148,7 +157,12 @@ then printf "failed to uncompress $tmpltimg\n" fi -create_from_file $tmpltfs $tmpltimg $tmpltname +if [ "$sflag" == "1" ] +then + create_from_snapshot $tmpltimg $snapshotName $tmpltfs $tmpltname +else + create_from_file $tmpltfs $tmpltimg $tmpltname +fi touch /$tmpltfs/template.properties echo -n "" > /$tmpltfs/template.properties diff --git a/scripts/storage/qcow2/managesnapshot.sh b/scripts/storage/qcow2/managesnapshot.sh index 3c7692161d6..d9b339267a0 100755 --- a/scripts/storage/qcow2/managesnapshot.sh +++ b/scripts/storage/qcow2/managesnapshot.sh @@ -16,13 +16,20 @@ create_snapshot() { local snapshotname=$2 local failed=0 - qemu-img snapshot -c $snapshotname $disk + if [ ! -f $disk ] + then + failed=1 + printf "No disk $disk exist\n" >&2 + return $failed + fi + + cloud-qemu-img snapshot -c $snapshotname $disk if [ $? -gt 0 ] then - failed=1 + failed=2 printf "***Failed to create snapshot $snapshotname for path $disk\n" >&2 - qemu-img snapshot -d $snapshotname $disk + cloud-qemu-img snapshot -d $snapshotname $disk if [ $? -gt 0 ] then @@ -34,21 +41,24 @@ create_snapshot() { } destroy_snapshot() { - local backupSnapDir=$1 + local disk=$1 local snapshotname=$2 local failed=0 - if [ -f $backupSnapDir/$snapshotname ] + if [ ! -f $disk ] then - rm -f $backupSnapDir/$snapshotname - - if [ $? -gt 0 ] - then - printf "***Failed to delete snapshot $snapshotname for path $backupSnapDir\n" >&2 - failed=1 - fi + failed=1 + printf "No disk $disk exist\n" >&2 + return $failed fi + cloud-qemu-img snapshot -d $snapshotname $disk + if [ $? -gt 0 ] + then + failed=2 + printf "Failed to delete snapshot $snapshotname for path $disk\n" >&2 + fi + return $failed } @@ -71,6 +81,7 @@ backup_snapshot() { local disk=$1 local snapshotname=$2 local destPath=$3 + local destName=$4 if [ ! -d $destPath ] then @@ -90,7 +101,7 @@ backup_snapshot() { return 1 fi - cloud-qemu-img convert -f qcow2 -O qcow2 -s $snapshotname $disk $destPath/$snapshotname >& /dev/null + cloud-qemu-img convert -f qcow2 -O qcow2 -s $snapshotname $disk $destPath/$destName >& /dev/null if [ $? -gt 0 ] then printf "Failed to backup $snapshotname for disk $disk to $destPath" >&2 @@ -107,8 +118,9 @@ bflag= nflag= pathval= snapshot= +tmplName= -while getopts 'c:d:r:n:b:p:' OPTION +while getopts 'c:d:r:n:b:p:t:' OPTION do case $OPTION in c) cflag=1 @@ -128,6 +140,8 @@ do ;; p) destPath="$OPTARG" ;; + t) tmplName="$OPTARG" + ;; ?) usage ;; esac @@ -144,7 +158,7 @@ then exit $? elif [ "$bflag" == "1" ] then - backup_snapshot $pathval $snapshot $destPath + backup_snapshot $pathval $snapshot $destPath $tmplName exit $? elif [ "$rflag" == "1" ] then diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index d3f2156f79d..53395a5a130 100644 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -939,10 +939,12 @@ public class StorageManagerImpl implements StorageManager { if (vmId != null) { VMInstanceVO vmInstance = _vmInstanceDao.findById(vmId); if (vmInstance != null) { - return vmInstance.getHostId(); + Long hostId = vmInstance.getHostId(); + if (hostId != null && !avoidHosts.contains(vmInstance.getHostId())) + return hostId; } } - return null; + /*Can't find the vm where host resides on(vm is destroyed? or volume is detached from vm), randomly choose a host to send the cmd */ } List poolHosts = _poolHostDao.listByHostStatus(poolVO.getId(), Status.Up); Collections.shuffle(poolHosts); diff --git a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java index a372e17b6e8..c6f82d2f567 100644 --- a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java +++ b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java @@ -287,7 +287,7 @@ public class SnapshotManagerImpl implements SnapshotManager { } txn.commit(); - VolumeVO volume = _volsDao.findById(volumeId); + VolumeVO volume = _volsDao.lock(volumeId, true); if (!shouldRunSnapshot(userId, volume, policyIds)) { // A null snapshot is interpreted as snapshot creation failed which is what we want to indicate @@ -477,7 +477,7 @@ public class SnapshotManagerImpl implements SnapshotManager { _snapshotDao.update(snapshot.getId(), snapshot); long volumeId = snapshot.getVolumeId(); - VolumeVO volume = _volsDao.findById(volumeId); + VolumeVO volume = _volsDao.lock(volumeId, true); String primaryStoragePoolNameLabel = _storageMgr.getPrimaryStorageNameLabel(volume); Long dcId = volume.getDataCenterId(); diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 7a26cc7d100..721f73e3eb4 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -686,6 +686,7 @@ public class UserVmManagerImpl implements UserVmManager { } boolean started = false; + Transaction txn = Transaction.currentTxn(); try { @@ -736,6 +737,11 @@ public class UserVmManagerImpl implements UserVmManager { VolumeVO vol = rootVols.get(0); List vols = _volsDao.findCreatedByInstance(vm.getId()); + List vos = new ArrayList(); + /*compete with take snapshot*/ + for (VolumeVO userVmVol : vols) { + vos.add(_volsDao.lock(userVmVol.getId(), true)); + } Answer answer = null; int retry = _retry; @@ -2215,7 +2221,7 @@ public class UserVmManagerImpl implements UserVmManager { @Override @DB public SnapshotVO createTemplateSnapshot(long userId, long volumeId) { SnapshotVO createdSnapshot = null; - VolumeVO volume = _volsDao.findById(volumeId); + VolumeVO volume = _volsDao.lock(volumeId, true); Long id = null;