diff --git a/server/src/com/cloud/storage/dao/SnapshotDao.java b/server/src/com/cloud/storage/dao/SnapshotDao.java index 98f8904e08c..1a0609c737d 100644 --- a/server/src/com/cloud/storage/dao/SnapshotDao.java +++ b/server/src/com/cloud/storage/dao/SnapshotDao.java @@ -20,6 +20,7 @@ package com.cloud.storage.dao; import java.util.List; +import com.cloud.storage.Snapshot; import com.cloud.storage.SnapshotVO; import com.cloud.storage.Snapshot.Type; import com.cloud.utils.db.Filter; @@ -39,5 +40,6 @@ public interface SnapshotDao extends GenericDao { long updateSnapshotSecHost(long dcId, long secHostId); List listByHostId(Filter filter, long hostId); List listByHostId(long hostId); - public Long countSnapshotsForAccount(long accountId); + public Long countSnapshotsForAccount(long accountId); + List listByInstanceId(long instanceId, Snapshot.Status... status); } diff --git a/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java b/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java index 163314f382f..60ff9c51878 100644 --- a/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java +++ b/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java @@ -26,16 +26,24 @@ import javax.ejb.Local; import org.apache.log4j.Logger; +import com.cloud.host.dao.HostDetailsDaoImpl; import com.cloud.storage.Snapshot.Type; +import com.cloud.storage.Snapshot; import com.cloud.storage.SnapshotVO; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; +import com.cloud.storage.Volume; +import com.cloud.storage.VolumeVO; +import com.cloud.utils.component.ComponentLocator; import com.cloud.utils.db.Filter; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.GenericSearchBuilder; +import com.cloud.utils.db.JoinBuilder.JoinType; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria.Func; import com.cloud.utils.db.Transaction; +import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.dao.VMInstanceDaoImpl; @Local (value={SnapshotDao.class}) public class SnapshotDaoImpl extends GenericDaoBase implements SnapshotDao { @@ -52,7 +60,11 @@ public class SnapshotDaoImpl extends GenericDaoBase implements private final SearchBuilder VolumeIdVersionSearch; private final SearchBuilder HostIdSearch; private final SearchBuilder AccountIdSearch; + private final SearchBuilder InstanceIdSearch; private final GenericSearchBuilder CountSnapshotsByAccount; + + protected final VMInstanceDaoImpl _instanceDao = ComponentLocator.inject(VMInstanceDaoImpl.class); + protected final VolumeDaoImpl _volumeDao = ComponentLocator.inject(VolumeDaoImpl.class); @Override public SnapshotVO findNextSnapshot(long snapshotId) { @@ -162,6 +174,19 @@ public class SnapshotDaoImpl extends GenericDaoBase implements CountSnapshotsByAccount.and("account", CountSnapshotsByAccount.entity().getAccountId(), SearchCriteria.Op.EQ); CountSnapshotsByAccount.and("removed", CountSnapshotsByAccount.entity().getRemoved(), SearchCriteria.Op.NULL); CountSnapshotsByAccount.done(); + + InstanceIdSearch = createSearchBuilder(); + InstanceIdSearch.and("status", InstanceIdSearch.entity().getStatus(), SearchCriteria.Op.IN); + + SearchBuilder instanceSearch = _instanceDao.createSearchBuilder(); + instanceSearch.and("instanceId", instanceSearch.entity().getId(), SearchCriteria.Op.EQ); + + SearchBuilder volumeSearch = _volumeDao.createSearchBuilder(); + volumeSearch.and("state", volumeSearch.entity().getState(), SearchCriteria.Op.EQ); + volumeSearch.join("instanceVolumes", instanceSearch, instanceSearch.entity().getId(), volumeSearch.entity().getInstanceId(), JoinType.INNER); + + InstanceIdSearch.join("instanceSnapshots", volumeSearch, volumeSearch.entity().getId(), InstanceIdSearch.entity().getVolumeId(), JoinType.INNER); + InstanceIdSearch.done(); } @Override @@ -241,4 +266,13 @@ public class SnapshotDaoImpl extends GenericDaoBase implements sc.setParameters("account", accountId); return customSearch(sc, null).get(0); } + + @Override + public List listByInstanceId(long instanceId, Snapshot.Status... status) { + SearchCriteria sc = this.InstanceIdSearch.create(); + sc.setParameters("status", status); + sc.setJoinParameters("instanceSnapshots", "state", Volume.State.Ready); + sc.setJoinParameters("instanceVolumes", "instanceId", instanceId); + return listBy(sc, null); + } } diff --git a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java index 1a8be2bb219..3ca022f9dce 100755 --- a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java +++ b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java @@ -389,6 +389,12 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma throw new CloudRuntimeException("Creating snapshot failed due to volume:" + volumeId + " is associated with vm:" + userVm.getInstanceName() + " is in " + userVm.getState().toString() + " state"); } + + if(userVm.getHypervisorType() == HypervisorType.VMware) { + List activeSnapshots = _snapshotDao.listByInstanceId(v.getInstanceId(), Snapshot.Status.Creating, Snapshot.Status.CreatedOnPrimary, Snapshot.Status.BackingUp); + if(activeSnapshots.size() > 1) + throw new CloudRuntimeException("There is other active snapshot tasks on the instance to which the volume is attached, please try again later"); + } } } @@ -442,6 +448,10 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma } else { _resourceLimitMgr.incrementResourceCount(owner.getId(), ResourceType.snapshot); } + } else { + snapshot = _snapshotDao.findById(snapshotId); + snapshot.setStatus(Status.Error); + _snapshotDao.update(snapshotId, snapshot); } if ( volume != null ) { diff --git a/utils/src/com/cloud/utils/db/SearchCriteria.java b/utils/src/com/cloud/utils/db/SearchCriteria.java index 00abb3a1606..1bd1c7f077f 100755 --- a/utils/src/com/cloud/utils/db/SearchCriteria.java +++ b/utils/src/com/cloud/utils/db/SearchCriteria.java @@ -208,8 +208,26 @@ public class SearchCriteria { return _selects == null || _selects.size() == 0; } + protected JoinBuilder> findJoin(Map>> jbmap, String joinName) { + JoinBuilder> jb = jbmap.get(joinName); + if (jb != null) { + return jb; + } + + for (JoinBuilder> j2 : _joins.values()) { + SearchCriteria sc = j2.getT(); + jb = findJoin(sc._joins, joinName); + if (jb != null) { + return jb; + } + } + + assert (false) : "Unable to find a join by the name " + joinName; + return null; + } + public void setJoinParameters(String joinName, String conditionName, Object... params) { - JoinBuilder> join = _joins.get(joinName); + JoinBuilder> join = findJoin(_joins, joinName); assert (join != null) : "Incorrect join name specified: " + joinName; join.getT().setParameters(conditionName, params); diff --git a/utils/test/resources/log4j.xml b/utils/test/resources/log4j.xml index ea9fb4318df..70de00b6df0 100755 --- a/utils/test/resources/log4j.xml +++ b/utils/test/resources/log4j.xml @@ -11,7 +11,7 @@ - +