bug 11531: while taking snapshot on volume, if volume is attached to a VM instance and under VMware, check if there are other ongoing snapshot tasks for the VM instance.

This commit is contained in:
Kelven Yang 2011-09-22 16:19:30 -07:00
parent 4557b5d54e
commit 2a6de104e2
5 changed files with 70 additions and 6 deletions

View File

@ -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<SnapshotVO, Long> {
long updateSnapshotSecHost(long dcId, long secHostId);
List<SnapshotVO> listByHostId(Filter filter, long hostId);
List<SnapshotVO> listByHostId(long hostId);
public Long countSnapshotsForAccount(long accountId);
public Long countSnapshotsForAccount(long accountId);
List<SnapshotVO> listByInstanceId(long instanceId, Snapshot.Status... status);
}

View File

@ -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<SnapshotVO, Long> implements SnapshotDao {
@ -52,7 +60,11 @@ public class SnapshotDaoImpl extends GenericDaoBase<SnapshotVO, Long> implements
private final SearchBuilder<SnapshotVO> VolumeIdVersionSearch;
private final SearchBuilder<SnapshotVO> HostIdSearch;
private final SearchBuilder<SnapshotVO> AccountIdSearch;
private final SearchBuilder<SnapshotVO> InstanceIdSearch;
private final GenericSearchBuilder<SnapshotVO, Long> 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<SnapshotVO, Long> 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<VMInstanceVO> instanceSearch = _instanceDao.createSearchBuilder();
instanceSearch.and("instanceId", instanceSearch.entity().getId(), SearchCriteria.Op.EQ);
SearchBuilder<VolumeVO> 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<SnapshotVO, Long> implements
sc.setParameters("account", accountId);
return customSearch(sc, null).get(0);
}
@Override
public List<SnapshotVO> listByInstanceId(long instanceId, Snapshot.Status... status) {
SearchCriteria<SnapshotVO> sc = this.InstanceIdSearch.create();
sc.setParameters("status", status);
sc.setJoinParameters("instanceSnapshots", "state", Volume.State.Ready);
sc.setJoinParameters("instanceVolumes", "instanceId", instanceId);
return listBy(sc, null);
}
}

View File

@ -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<SnapshotVO> 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 ) {

View File

@ -208,8 +208,26 @@ public class SearchCriteria<K> {
return _selects == null || _selects.size() == 0;
}
protected JoinBuilder<SearchCriteria<?>> findJoin(Map<String, JoinBuilder<SearchCriteria<?>>> jbmap, String joinName) {
JoinBuilder<SearchCriteria<?>> jb = jbmap.get(joinName);
if (jb != null) {
return jb;
}
for (JoinBuilder<SearchCriteria<?>> 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<SearchCriteria<?>> join = _joins.get(joinName);
JoinBuilder<SearchCriteria<?>> join = findJoin(_joins, joinName);
assert (join != null) : "Incorrect join name specified: " + joinName;
join.getT().setParameters(conditionName, params);

View File

@ -11,7 +11,7 @@
<!-- A regular appender FIXME implement code that will close/reopen logs on SIGHUP by logrotate FIXME make the paths configurable using the build system -->
<!-- <appender name="FILE" class="org.apache.log4j.rolling.RollingFileAppender">
<param name="Append" value="true"/>
<param name="Threshold" value="DEBUG"/>
<param name="Threshold" value="TRACE"/>
<rollingPolicy class="org.apache.log4j.rolling.TimeBasedRollingPolicy">
<param name="FileNamePattern" value="@MSLOG@.%d{yyyy-MM-dd}.gz"/>
<param name="ActiveFileName" value="@MSLOG@"/>
@ -24,7 +24,7 @@
<!--
<appender name="APISERVER" class="org.apache.log4j.rolling.RollingFileAppender">
<param name="Append" value="true"/>
<param name="Threshold" value="DEBUG"/>
<param name="Threshold" value="TRACE"/>
<rollingPolicy class="org.apache.log4j.rolling.TimeBasedRollingPolicy">
<param name="FileNamePattern" value="@APISERVERLOG@.%d{yyyy-MM-dd}.gz"/>
<param name="ActiveFileName" value="@APISERVERLOG@"/>
@ -55,7 +55,7 @@
<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out"/>
<param name="Threshold" value="DEBUG"/>
<param name="Threshold" value="TRACE"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{ISO8601} %-5p [%c{3}] (%t:%x) %m%n"/>
</layout>
@ -66,7 +66,7 @@
<!-- ================ -->
<category name="com.cloud">
<priority value="DEBUG"/>
<priority value="TRACE"/>
</category>
<!-- Limit the org.apache category to INFO as its DEBUG is verbose -->