refactor snapshot

This commit is contained in:
Edison Su 2013-04-29 09:31:52 -07:00 committed by Edison Su
parent 35264f7087
commit 37cbe8890f
43 changed files with 775 additions and 682 deletions

View File

@ -18,12 +18,13 @@ package com.cloud.storage;
import java.util.Date;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.utils.fsm.StateObject;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.api.Identity;
import org.apache.cloudstack.api.InternalIdentity;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.utils.fsm.StateObject;
public interface Snapshot extends ControlledEntity, Identity, InternalIdentity, StateObject<Snapshot.State> {
public enum Type {
MANUAL,
@ -85,8 +86,6 @@ public interface Snapshot extends ControlledEntity, Identity, InternalIdentity,
long getVolumeId();
String getPath();
String getName();
Date getCreated();

View File

@ -79,4 +79,7 @@ public interface VolumeApiService {
Volume attachVolumeToVM(AttachVolumeCmd command);
Volume detachVolumeFromVM(DetachVolumeCmd cmmd);
Snapshot takeSnapshot(Long volumeId, Long policyId)
throws ResourceAllocationException;
}

View File

@ -48,10 +48,6 @@ public class SnapshotVO implements Snapshot {
@Column(name="disk_offering_id")
Long diskOfferingId;
@Expose
@Column(name="path")
String path;
@Expose
@Column(name="name")
String name;
@ -76,18 +72,6 @@ public class SnapshotVO implements Snapshot {
@Column(name=GenericDao.REMOVED_COLUMN)
Date removed;
@Column(name="backup_snap_id")
String backupSnapshotId;
@Column(name="swift_id")
Long swiftId;
@Column(name="s3_id")
Long s3Id;
@Column(name="prev_snap_id")
long prevSnapshotId;
@Column(name="hypervisor_type")
@Enumerated(value=EnumType.STRING)
HypervisorType hypervisorType;
@ -103,19 +87,17 @@ public class SnapshotVO implements Snapshot {
this.uuid = UUID.randomUUID().toString();
}
public SnapshotVO(long dcId, long accountId, long domainId, Long volumeId, Long diskOfferingId, String path, String name, short snapshotType, String typeDescription, long size, HypervisorType hypervisorType ) {
public SnapshotVO(long dcId, long accountId, long domainId, Long volumeId, Long diskOfferingId, String name, short snapshotType, String typeDescription, long size, HypervisorType hypervisorType ) {
this.dataCenterId = dcId;
this.accountId = accountId;
this.domainId = domainId;
this.volumeId = volumeId;
this.diskOfferingId = diskOfferingId;
this.path = path;
this.name = name;
this.snapshotType = snapshotType;
this.typeDescription = typeDescription;
this.size = size;
this.state = State.Allocated;
this.prevSnapshotId = 0;
this.hypervisorType = hypervisorType;
this.version = "2.2";
this.uuid = UUID.randomUUID().toString();
@ -153,14 +135,6 @@ public class SnapshotVO implements Snapshot {
this.volumeId = volumeId;
}
@Override
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
@Override
public String getName() {
@ -179,14 +153,6 @@ public class SnapshotVO implements Snapshot {
return Type.values()[snapshotType];
}
public Long getSwiftId() {
return swiftId;
}
public void setSwiftId(Long swiftId) {
this.swiftId = swiftId;
}
@Override
public HypervisorType getHypervisorType() {
return hypervisorType;
@ -242,22 +208,6 @@ public class SnapshotVO implements Snapshot {
this.state = state;
}
public String getBackupSnapshotId(){
return backupSnapshotId;
}
public long getPrevSnapshotId(){
return prevSnapshotId;
}
public void setBackupSnapshotId(String backUpSnapshotId){
this.backupSnapshotId = backUpSnapshotId;
}
public void setPrevSnapshotId(long prevSnapshotId){
this.prevSnapshotId = prevSnapshotId;
}
public static Type getSnapshotType(String snapshotType) {
for ( Type type : Type.values()) {
if ( type.equals(snapshotType)) {
@ -275,13 +225,4 @@ public class SnapshotVO implements Snapshot {
public void setUuid(String uuid) {
this.uuid = uuid;
}
public Long getS3Id() {
return s3Id;
}
public void setS3Id(Long s3Id) {
this.s3Id = s3Id;
}
}

View File

@ -31,6 +31,7 @@ import javax.persistence.TemporalType;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.State;
import com.cloud.utils.db.GenericDaoBase;
@ -329,5 +330,10 @@ public class VMTemplateHostVO implements VMTemplateStorageResourceAssoc, DataObj
return this.getHostId();
}
@Override
public State getObjectInStoreState() {
return this.state;
}
}

View File

@ -281,5 +281,10 @@ public class VMTemplateStoragePoolVO implements VMTemplateStorageResourceAssoc,
return this.getPoolId();
}
@Override
public State getObjectInStoreState() {
return this.state;
}
}

View File

@ -32,6 +32,7 @@ import javax.persistence.TemporalType;
import org.apache.cloudstack.api.InternalIdentity;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.State;
import com.cloud.storage.Storage.ImageFormat;
import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
@ -354,5 +355,10 @@ public class VolumeHostVO implements InternalIdentity, DataObjectInStore {
return this.getHostId();
}
@Override
public State getObjectInStoreState() {
return this.state;
}
}

View File

@ -26,4 +26,5 @@ public interface DataObjectInStore extends StateObject<ObjectInDataStoreStateMac
public void setInstallPath(String path);
public long getObjectId();
public long getDataStoreId();
public ObjectInDataStoreStateMachine.State getObjectInStoreState();
}

View File

@ -18,9 +18,11 @@
*/
package org.apache.cloudstack.engine.subsystem.api.storage;
import com.cloud.storage.DataStoreRole;
public interface SnapshotDataFactory {
public SnapshotInfo getSnapshot(long snapshotId, DataStore store);
public SnapshotInfo getSnapshot(DataObject obj, DataStore store);
public SnapshotInfo getSnapshot(long snapshotId);
public SnapshotInfo getSnapshot(long snapshotId, DataStoreRole role);
}

View File

@ -21,8 +21,11 @@ import com.cloud.storage.Snapshot;
public interface SnapshotInfo extends DataObject, Snapshot {
public SnapshotInfo getParent();
public String getPath();
public SnapshotInfo getChild();
public VolumeInfo getBaseVolume();
public void addPayload(Object data);
Long getDataCenterId();
public Long getPrevSnapshotId();
ObjectInDataStoreStateMachine.State getStatus();
}

View File

@ -0,0 +1,25 @@
package org.apache.cloudstack.engine.subsystem.api.storage;
import com.cloud.agent.api.Answer;
public class SnapshotResult extends CommandResult {
private SnapshotInfo snashot;
private Answer answer;
public SnapshotResult(SnapshotInfo snapshot, Answer answer) {
this.setSnashot(snapshot);
this.setAnswer(answer);
}
public SnapshotInfo getSnashot() {
return snashot;
}
public void setSnashot(SnapshotInfo snashot) {
this.snashot = snashot;
}
public Answer getAnswer() {
return answer;
}
public void setAnswer(Answer answer) {
this.answer = answer;
}
}

View File

@ -18,8 +18,9 @@
package org.apache.cloudstack.engine.subsystem.api.storage;
public interface SnapshotService {
public SnapshotInfo takeSnapshot(VolumeInfo volume, Long snapshotId);
public SnapshotResult takeSnapshot(SnapshotInfo snapshot);
public SnapshotInfo backupSnapshot(SnapshotInfo snapshot);
public boolean deleteSnapshot(SnapshotInfo snapshot);
public boolean revertSnapshot(SnapshotInfo snapshot);

View File

@ -0,0 +1,11 @@
package org.apache.cloudstack.engine.subsystem.api.storage;
import com.cloud.storage.Snapshot;
public interface SnapshotStrategy {
public SnapshotInfo takeSnapshot(SnapshotInfo snapshot);
public SnapshotInfo backupSnapshot(SnapshotInfo snapshot);
public boolean deleteSnapshot(Long snapshotId);
public boolean canHandle(Snapshot snapshot);
}

View File

@ -79,4 +79,6 @@ public interface VolumeService {
void handleVolumeSync(DataStore store);
SnapshotInfo takeSnapshot(VolumeInfo volume);
}

View File

@ -18,31 +18,26 @@
*/
package org.apache.cloudstack.storage.command;
import org.apache.cloudstack.engine.subsystem.api.storage.DataTO;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
public class CreateObjectAnswer extends Answer {
private String path;
private Long size;
private DataTO data;
protected CreateObjectAnswer() {
super();
}
public CreateObjectAnswer(Command cmd, String path, Long size) {
super(cmd);
this.path = path;
this.size = size;
public CreateObjectAnswer(DataTO data) {
super();
this.data = data;
}
public CreateObjectAnswer(Command cmd, boolean status, String result) {
super(cmd, status, result);
}
public String getPath() {
return this.path;
public DataTO getData() {
return this.data;
}
public Long getSize() {
return this.size;
}
public CreateObjectAnswer(String errMsg) {
super(null, false, errMsg);
}
}

View File

@ -18,14 +18,16 @@
*/
package org.apache.cloudstack.storage.command;
import org.apache.cloudstack.engine.subsystem.api.storage.DataTO;
import com.cloud.agent.api.Command;
public class CreateObjectCommand extends Command implements StorageSubSystemCommand {
protected String objectUri;
private DataTO data;
public CreateObjectCommand(String objectUri) {
public CreateObjectCommand(DataTO obj) {
super();
this.objectUri = objectUri;
this.data = obj;
}
protected CreateObjectCommand() {
@ -38,8 +40,8 @@ public class CreateObjectCommand extends Command implements StorageSubSystemComm
return false;
}
public String getObjectUri() {
return this.objectUri;
public DataTO getData() {
return this.data;
}
}

View File

@ -23,20 +23,19 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
import com.cloud.storage.DataStoreRole;
import com.cloud.utils.db.GenericDao;
import com.cloud.utils.fsm.StateDao;
public interface SnapshotDataStoreDao extends GenericDao<SnapshotDataStoreVO, Long>, StateDao<ObjectInDataStoreStateMachine.State, ObjectInDataStoreStateMachine.Event, DataObjectInStore> {
public List<SnapshotDataStoreVO> listByStoreId(long id);
public List<SnapshotDataStoreVO> listByStoreId(long id, DataStoreRole role);
public void deletePrimaryRecordsForStore(long id);
public SnapshotDataStoreVO findByStoreSnapshot(long storeId, long snapshotId);
public SnapshotDataStoreVO findByStoreSnapshot(DataStoreRole role, long storeId, long snapshotId);
public SnapshotDataStoreVO findByStoreSnapshot(long storeId, long snapshotId, boolean lock);
public SnapshotDataStoreVO findBySnapshot(long snapshotId);
public List<SnapshotDataStoreVO> listDestroyed(long storeId);
public SnapshotDataStoreVO findBySnapshot(long snapshotId, DataStoreRole role);
}

View File

@ -31,10 +31,10 @@ import javax.persistence.TemporalType;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.State;
import com.cloud.storage.Storage;
import com.cloud.storage.Storage.ImageFormat;
import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
import com.cloud.storage.DataStoreRole;
import com.cloud.utils.db.GenericDao;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.fsm.StateObject;
@ -51,6 +51,10 @@ public class SnapshotDataStoreVO implements StateObject<ObjectInDataStoreStateMa
@Column(name="store_id")
private long dataStoreId;
@Column(name="store_role")
@Enumerated(EnumType.STRING)
private DataStoreRole role;
@Column(name="snapshot_id")
private long snapshotId;
@ -62,23 +66,23 @@ public class SnapshotDataStoreVO implements StateObject<ObjectInDataStoreStateMa
@Temporal(value=TemporalType.TIMESTAMP)
private Date lastUpdated = null;
@Column (name="size")
private long size;
@Column (name="physical_size")
private long physicalSize;
@Column(name="parent_snapshot_id")
private long parentSnapshotId;
@Column (name="job_id")
private String jobId;
@Column (name="install_path")
private String installPath;
@Column(name="destroyed")
boolean destroyed = false;
@Column(name = GenericDao.REMOVED_COLUMN)
Date removed;
@Column(name="update_count", updatable = true, nullable=false)
protected long updatedCount;
@ -201,14 +205,6 @@ public class SnapshotDataStoreVO implements StateObject<ObjectInDataStoreStateMa
return physicalSize;
}
public void setDestroyed(boolean destroyed) {
this.destroyed = destroyed;
}
public boolean getDestroyed() {
return destroyed;
}
public long getVolumeSize() {
return -1;
}
@ -245,5 +241,24 @@ public class SnapshotDataStoreVO implements StateObject<ObjectInDataStoreStateMa
return this.getSnapshotId();
}
public DataStoreRole getRole() {
return role;
}
public void setRole(DataStoreRole role) {
this.role = role;
}
@Override
public State getObjectInStoreState() {
return this.state;
}
public long getParentSnapshotId() {
return parentSnapshotId;
}
public void setParentSnapshotId(long parentSnapshotId) {
this.parentSnapshotId = parentSnapshotId;
}
}

View File

@ -31,6 +31,7 @@ import javax.persistence.TemporalType;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.State;
import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
@ -320,5 +321,8 @@ public class TemplateDataStoreVO implements StateObject<ObjectInDataStoreStateMa
return this.getTemplateId();
}
@Override
public State getObjectInStoreState() {
return this.state;
}
}

View File

@ -31,6 +31,7 @@ import javax.persistence.TemporalType;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.State;
import com.cloud.storage.Storage;
import com.cloud.storage.Storage.ImageFormat;
@ -351,5 +352,10 @@ public class VolumeDataStoreVO implements StateObject<ObjectInDataStoreStateMach
return this.getVolumeId();
}
@Override
public State getObjectInStoreState() {
return this.state;
}
}

View File

@ -0,0 +1,30 @@
package org.apache.cloudstack.storage.to;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType;
import org.apache.cloudstack.engine.subsystem.api.storage.DataTO;
import com.cloud.agent.api.to.DataStoreTO;
public class SnapshotObjectTO implements DataTO {
private String path;
@Override
public DataObjectType getObjectType() {
// TODO Auto-generated method stub
return null;
}
@Override
public DataStoreTO getDataStore() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getPath() {
return this.path;
}
public void setPath(String path) {
this.path = path;
}
}

View File

@ -398,62 +398,7 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
StoragePoolVO poolvo = pools.get(0);
StoragePool pool = (StoragePool) this.dataStoreMgr.getDataStore(
poolvo.getId(), DataStoreRole.Primary);
if (snapshot.getVersion() != null
&& snapshot.getVersion().equalsIgnoreCase("2.1")) {
VolumeVO volume = this.volDao.findByIdIncludingRemoved(volumeId);
if (volume == null) {
throw new CloudRuntimeException("failed to upgrade snapshot "
+ snapshotId + " due to unable to find orignal volume:"
+ volumeId + ", try it later ");
}
if (volume.getTemplateId() == null) {
snapshotDao.updateSnapshotVersion(volumeId, "2.1", "2.2");
} else {
template = templateDao.findByIdIncludingRemoved(volume
.getTemplateId());
if (template == null) {
throw new CloudRuntimeException(
"failed to upgrade snapshot "
+ snapshotId
+ " due to unalbe to find orignal template :"
+ volume.getTemplateId()
+ ", try it later ");
}
Long origTemplateId = template.getId();
Long origTmpltAccountId = template.getAccountId();
if (!this.volDao.lockInLockTable(volumeId.toString(), 10)) {
throw new CloudRuntimeException(
"failed to upgrade snapshot " + snapshotId
+ " due to volume:" + volumeId
+ " is being used, try it later ");
}
UpgradeSnapshotCommand cmd = new UpgradeSnapshotCommand(null,
secondaryStorageURL, dcId, accountId, volumeId,
origTemplateId, origTmpltAccountId, null,
snapshot.getBackupSnapshotId(), snapshot.getName(),
"2.1");
if (!this.volDao.lockInLockTable(volumeId.toString(), 10)) {
throw new CloudRuntimeException(
"Creating template failed due to volume:"
+ volumeId
+ " is being used, try it later ");
}
Answer answer = null;
try {
answer = this.storageMgr.sendToPool(pool, cmd);
cmd = null;
} catch (StorageUnavailableException e) {
} finally {
this.volDao.unlockFromLockTable(volumeId.toString());
}
if ((answer != null) && answer.getResult()) {
snapshotDao.updateSnapshotVersion(volumeId, "2.1", "2.2");
} else {
throw new CloudRuntimeException(
"Unable to upgrade snapshot");
}
}
}
if (snapshot.getSwiftId() != null && snapshot.getSwiftId() != 0) {
snapshotMgr.downloadSnapshotsFromSwift(snapshot);
}

View File

@ -25,6 +25,11 @@
<artifactId>cloud-engine-storage</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>

View File

@ -35,6 +35,9 @@ import com.cloud.storage.DataStoreRole;
import com.cloud.storage.Snapshot;
import com.cloud.storage.SnapshotVO;
import com.cloud.storage.dao.SnapshotDao;
import com.cloud.utils.db.SearchCriteria2;
import com.cloud.utils.db.SearchCriteriaService;
import com.cloud.utils.db.SearchCriteria.Op;
import com.cloud.utils.exception.CloudRuntimeException;
@Component
@ -49,36 +52,30 @@ public class SnapshotDataFactoryImpl implements SnapshotDataFactory {
VolumeDataFactory volumeFactory;
@Override
public SnapshotInfo getSnapshot(long snapshotId, DataStore store) {
SnapshotVO snapshot = snapshotDao.findByIdIncludingRemoved(snapshotId);
SnapshotVO snapshot = snapshotDao.findById(snapshotId);
SnapshotObject so = SnapshotObject.getSnapshotObject(snapshot, store);
return so;
}
@Override
public SnapshotInfo getSnapshot(long snapshotId) {
SnapshotVO snapshot = snapshotDao.findByIdIncludingRemoved(snapshotId);
SnapshotObject so = null;
if (snapshot.getState() == Snapshot.State.BackedUp) {
DataStore store = null;
SnapshotDataStoreVO snapshotStore = snapshotStoreDao.findBySnapshot(snapshotId);
if ( snapshotStore != null ){
store = this.storeMgr.getDataStore(snapshotStore.getDataStoreId(), DataStoreRole.Image);
}
so = SnapshotObject.getSnapshotObject(snapshot, store);
} else {
VolumeInfo volume = this.volumeFactory.getVolume(snapshot.getVolumeId());
so = SnapshotObject.getSnapshotObject(snapshot, volume.getDataStore());
}
return so;
}
@Override
public SnapshotInfo getSnapshot(DataObject obj, DataStore store) {
SnapshotVO snapshot = snapshotDao.findByIdIncludingRemoved(obj.getId());
SnapshotVO snapshot = snapshotDao.findById(obj.getId());
if (snapshot == null) {
throw new CloudRuntimeException("Can't find snapshot: " + obj.getId());
}
SnapshotObject so = SnapshotObject.getSnapshotObject(snapshot, store);
return so;
}
@Override
public SnapshotInfo getSnapshot(long snapshotId, DataStoreRole role) {
SnapshotVO snapshot = snapshotDao.findById(snapshotId);
SnapshotDataStoreVO snapshotStore = snapshotStoreDao.findBySnapshot(snapshotId, role);
if (snapshotStore == null) {
return null;
}
DataStore store = this.storeMgr.getDataStore(snapshotStore.getDataStoreId(), role);
SnapshotObject so = SnapshotObject.getSnapshotObject(snapshot, store);
return so;
}
}

View File

@ -30,7 +30,11 @@ import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.disktype.DiskFormat;
import org.apache.cloudstack.storage.command.CreateObjectAnswer;
import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager;
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
import org.apache.cloudstack.storage.to.SnapshotObjectTO;
import org.apache.log4j.Logger;
import com.cloud.agent.api.Answer;
@ -55,6 +59,8 @@ public class SnapshotObject implements SnapshotInfo {
@Inject protected SnapshotStateMachineManager stateMachineMgr;
@Inject
ObjectInDataStoreManager ojbectInStoreMgr;
@Inject
SnapshotDataStoreDao snapshotStore;
public SnapshotObject() {
}
@ -76,6 +82,7 @@ public class SnapshotObject implements SnapshotInfo {
@Override
public SnapshotInfo getParent() {
// TODO Auto-generated method stub
return null;
}
@ -149,11 +156,7 @@ public class SnapshotObject implements SnapshotInfo {
@Override
public String getPath() {
return this.snapshot.getPath();
}
public void setPath(String path) {
this.snapshot.setPath(path);
return this.ojbectInStoreMgr.findObject(this, getDataStore()).getInstallPath();
}
@Override
@ -196,9 +199,6 @@ public class SnapshotObject implements SnapshotInfo {
return this.snapshot.getDomainId();
}
public void setPrevSnapshotId(Long id) {
this.snapshot.setPrevSnapshotId(id);
}
@Override
public Long getDataCenterId() {
@ -212,15 +212,8 @@ public class SnapshotObject implements SnapshotInfo {
@Override
public Long getPrevSnapshotId() {
return this.snapshot.getPrevSnapshotId();
}
public void setBackupSnapshotId(String id) {
this.snapshot.setBackupSnapshotId(id);
}
public String getBackupSnapshotId() {
return this.snapshot.getBackupSnapshotId();
SnapshotDataStoreVO snapshotStoreVO = this.snapshotStore.findBySnapshot(this.getId(), this.getDataStore().getRole());
return snapshotStoreVO.getParentSnapshotId();
}
public SnapshotVO getSnapshotVO(){
@ -234,8 +227,28 @@ public class SnapshotObject implements SnapshotInfo {
}
@Override
public void processEvent(org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event event, Answer answer) {
// TODO Auto-generated method stub
public void processEvent(ObjectInDataStoreStateMachine.Event event, Answer answer) {
SnapshotDataStoreVO snapshotStore = this.snapshotStore.findByStoreSnapshot(this.getDataStore().getRole(),
this.getDataStore().getId(), this.getId());
if (answer instanceof CreateObjectAnswer) {
SnapshotObjectTO snapshotTO = (SnapshotObjectTO)((CreateObjectAnswer) answer).getData();
snapshotStore.setInstallPath(snapshotTO.getPath());
this.snapshotStore.update(snapshotStore.getId(), snapshotStore);
} else {
throw new CloudRuntimeException("Unknown answer: " + answer.getClass());
}
this.processEvent(event);
}
@Override
public ObjectInDataStoreStateMachine.State getStatus() {
return this.ojbectInStoreMgr.findObject(this, store).getObjectInStoreState();
}
@Override
public void addPayload(Object data) {
// TODO Auto-generated method stub
}
}

View File

@ -27,7 +27,6 @@ import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionService;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
@ -38,6 +37,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotService;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotResult;
import org.apache.cloudstack.framework.async.AsyncCallFuture;
import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher;
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
@ -51,30 +51,19 @@ import org.springframework.stereotype.Component;
import com.cloud.agent.api.BackupSnapshotAnswer;
import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.dc.ClusterVO;
import com.cloud.dc.dao.ClusterDao;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.host.HostVO;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.resource.ResourceManager;
import com.cloud.storage.DataStoreRole;
import com.cloud.storage.Snapshot;
import com.cloud.storage.SnapshotVO;
import com.cloud.storage.StoragePool;
import com.cloud.storage.VolumeManager;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.SnapshotDao;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.storage.snapshot.SnapshotManager;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.db.DB;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.fsm.NoTransitionException;
import com.cloud.vm.UserVmVO;
import com.cloud.vm.VirtualMachine.State;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.snapshot.VMSnapshot;
import com.cloud.vm.snapshot.VMSnapshotVO;
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
@Component
@ -92,8 +81,7 @@ public class SnapshotServiceImpl implements SnapshotService {
protected SnapshotDao _snapshotDao;
@Inject
protected SnapshotDataStoreDao _snapshotStoreDao;
@Inject
private ResourceManager _resourceMgr;
@Inject
protected SnapshotManager snapshotMgr;
@Inject
@ -164,81 +152,24 @@ public class SnapshotServiceImpl implements SnapshotService {
CreateSnapshotContext<CreateCmdResult> context) {
CreateCmdResult result = callback.getResult();
SnapshotObject snapshot = (SnapshotObject)context.snapshot;
VolumeInfo volume = context.volume;
AsyncCallFuture<SnapshotResult> future = context.future;
SnapshotResult snapResult = new SnapshotResult(snapshot);
SnapshotResult snapResult = new SnapshotResult(snapshot, result.getAnswer());
if (result.isFailed()) {
s_logger.debug("create snapshot " + context.snapshot.getName() + " failed: " + result.getResult());
try {
snapshot.processEvent(Snapshot.Event.OperationFailed);
} catch (NoTransitionException nte) {
s_logger.debug("Failed to update snapshot state due to " + nte.getMessage());
snapshot.processEvent(Event.OperationFailed);
} catch (Exception e) {
s_logger.debug("Failed to update snapshot state due to " + e.getMessage());
}
snapResult.setResult(result.getResult());
future.complete(snapResult);
return null;
}
try {
SnapshotVO preSnapshotVO = this.snapshotMgr.getParentSnapshot(volume, snapshot);
String preSnapshotPath = null;
if (preSnapshotVO != null) {
preSnapshotPath = preSnapshotVO.getPath();
}
SnapshotVO snapshotVO = this._snapshotDao.findById(snapshot.getId());
// The snapshot was successfully created
if (preSnapshotPath != null && preSnapshotPath.equals(result.getPath())) {
// empty snapshot
s_logger.debug("CreateSnapshot: this is empty snapshot ");
snapshotVO.setPath(preSnapshotPath);
snapshotVO.setBackupSnapshotId(preSnapshotVO.getBackupSnapshotId());
snapshotVO.setPrevSnapshotId(preSnapshotVO.getId());
snapshot.processEvent(Snapshot.Event.OperationNotPerformed);
} else {
long preSnapshotId = 0;
if (preSnapshotVO != null && preSnapshotVO.getBackupSnapshotId() != null) {
preSnapshotId = preSnapshotVO.getId();
int _deltaSnapshotMax = NumbersUtil.parseInt(_configDao.getValue("snapshot.delta.max"), SnapshotManager.DELTAMAX);
int deltaSnap = _deltaSnapshotMax;
int i;
for (i = 1; i < deltaSnap; i++) {
String prevBackupUuid = preSnapshotVO.getBackupSnapshotId();
// previous snapshot doesn't have backup, create a full snapshot
if (prevBackupUuid == null) {
preSnapshotId = 0;
break;
}
long preSSId = preSnapshotVO.getPrevSnapshotId();
if (preSSId == 0) {
break;
}
preSnapshotVO = _snapshotDao.findByIdIncludingRemoved(preSSId);
}
if (i >= deltaSnap) {
preSnapshotId = 0;
}
}
//If the volume is moved around, backup a full snapshot to secondary storage
if (volume.getLastPoolId() != null && !volume.getLastPoolId().equals(volume.getPoolId())) {
preSnapshotId = 0;
//TODO: fix this hack
VolumeVO volumeVO = this.volumeDao.findById(volume.getId());
volumeVO.setLastPoolId(volume.getPoolId());
this.volumeDao.update(volume.getId(), volumeVO);
}
snapshot.setPath(result.getPath());
snapshot.setPrevSnapshotId(preSnapshotId);
snapshot.processEvent(Snapshot.Event.OperationSucceeded);
snapResult = new SnapshotResult(this.snapshotfactory.getSnapshot(snapshot.getId()));
}
snapshot.processEvent(Event.OperationSuccessed, result.getAnswer());
} catch (Exception e) {
s_logger.debug("Failed to create snapshot: ", e);
snapResult.setResult(e.toString());
@ -253,36 +184,49 @@ public class SnapshotServiceImpl implements SnapshotService {
return null;
}
class SnapshotResult extends CommandResult {
SnapshotInfo snashot;
public SnapshotResult(SnapshotInfo snapshot) {
this.snashot = snapshot;
}
}
protected SnapshotInfo createSnapshotOnPrimary(VolumeInfo volume, Long snapshotId) {
SnapshotObject snapshot = (SnapshotObject)this.snapshotfactory.getSnapshot(snapshotId);
if (snapshot == null) {
throw new CloudRuntimeException("Can not find snapshot " + snapshotId);
@Override
public SnapshotResult takeSnapshot(SnapshotInfo snap) {
SnapshotObject snapshot = (SnapshotObject)snap;
SnapshotObject snapshotOnPrimary = null;
try {
snapshotOnPrimary = (SnapshotObject)snap.getDataStore().create(snapshot);
} catch(Exception e) {
s_logger.debug("Failed to create snapshot state on data store due to " + e.getMessage());
throw new CloudRuntimeException(e);
}
try {
snapshot.processEvent(Snapshot.Event.CreateRequested);
} catch (NoTransitionException nte) {
s_logger.debug("Failed to update snapshot state due to " + nte.getMessage());
throw new CloudRuntimeException("Failed to update snapshot state due to " + nte.getMessage());
snapshotOnPrimary.processEvent(Snapshot.Event.CreateRequested);
} catch (NoTransitionException e) {
s_logger.debug("Failed to change snapshot state: " + e.toString());
throw new CloudRuntimeException(e);
}
try {
snapshotOnPrimary.processEvent(Event.CreateOnlyRequested);
} catch (Exception e) {
s_logger.debug("Failed to change snapshot state: " + e.toString());
try {
snapshotOnPrimary.processEvent(Snapshot.Event.OperationFailed);
} catch (NoTransitionException e1) {
s_logger.debug("Failed to change snapshot state: " + e1.toString());
}
throw new CloudRuntimeException(e);
}
AsyncCallFuture<SnapshotResult> future = new AsyncCallFuture<SnapshotResult>();
try {
CreateSnapshotContext<CommandResult> context = new CreateSnapshotContext<CommandResult>(
null, volume, snapshot, future);
null, snap.getBaseVolume(), snapshotOnPrimary, future);
AsyncCallbackDispatcher<SnapshotServiceImpl, CreateCmdResult> caller = AsyncCallbackDispatcher
.create(this);
caller.setCallback(
caller.getTarget().createSnapshotAsyncCallback(null, null))
.setContext(context);
PrimaryDataStoreDriver primaryStore = (PrimaryDataStoreDriver)volume.getDataStore().getDriver();
PrimaryDataStoreDriver primaryStore = (PrimaryDataStoreDriver)snapshotOnPrimary.getDataStore().getDriver();
primaryStore.takeSnapshot(snapshot, caller);
} catch (Exception e) {
s_logger.debug("Failed to take snapshot: " + snapshot.getId(), e);
@ -302,7 +246,7 @@ public class SnapshotServiceImpl implements SnapshotService {
s_logger.debug("Failed to create snapshot:" + result.getResult());
throw new CloudRuntimeException(result.getResult());
}
return result.snashot;
return result;
} catch (InterruptedException e) {
s_logger.debug("Failed to create snapshot", e);
throw new CloudRuntimeException("Failed to create snapshot", e);
@ -313,78 +257,11 @@ public class SnapshotServiceImpl implements SnapshotService {
}
private boolean hostSupportSnapsthot(HostVO host) {
if (host.getHypervisorType() != HypervisorType.KVM) {
return true;
}
// Determine host capabilities
String caps = host.getCapabilities();
if (caps != null) {
String[] tokens = caps.split(",");
for (String token : tokens) {
if (token.contains("snapshot")) {
return true;
}
}
}
return false;
}
protected boolean supportedByHypervisor(VolumeInfo volume) {
if (volume.getHypervisorType().equals(HypervisorType.KVM)) {
StoragePool storagePool = (StoragePool)volume.getDataStore();
ClusterVO cluster = _clusterDao.findById(storagePool.getClusterId());
List<HostVO> hosts = _resourceMgr.listAllHostsInCluster(cluster.getId());
if (hosts != null && !hosts.isEmpty()) {
HostVO host = hosts.get(0);
if (!hostSupportSnapsthot(host)) {
throw new CloudRuntimeException("KVM Snapshot is not supported on cluster: " + host.getId());
}
}
}
// if volume is attached to a vm in destroyed or expunging state; disallow
if (volume.getInstanceId() != null) {
UserVmVO userVm = _vmDao.findById(volume.getInstanceId());
if (userVm != null) {
if (userVm.getState().equals(State.Destroyed) || userVm.getState().equals(State.Expunging)) {
throw new CloudRuntimeException("Creating snapshot failed due to volume:" + volume.getId() + " is associated with vm:" + userVm.getInstanceName() + " is in "
+ userVm.getState().toString() + " state");
}
if(userVm.getHypervisorType() == HypervisorType.VMware || userVm.getHypervisorType() == HypervisorType.KVM) {
List<SnapshotVO> activeSnapshots = _snapshotDao.listByInstanceId(volume.getInstanceId(), Snapshot.State.Creating, Snapshot.State.CreatedOnPrimary, Snapshot.State.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");
}
List<VMSnapshotVO> activeVMSnapshots = _vmSnapshotDao.listByInstanceId(userVm.getId(),
VMSnapshot.State.Creating, VMSnapshot.State.Reverting, VMSnapshot.State.Expunging);
if (activeVMSnapshots.size() > 0) {
throw new CloudRuntimeException(
"There is other active vm snapshot tasks on the instance to which the volume is attached, please try again later");
}
}
}
return true;
}
@Override
public SnapshotInfo takeSnapshot(VolumeInfo volume, Long snapshotId) {
supportedByHypervisor(volume);
SnapshotInfo snapshot = createSnapshotOnPrimary(volume, snapshotId);
return snapshot;
}
@Override
public SnapshotInfo backupSnapshot(SnapshotInfo snapshot) {
SnapshotObject snapObj = (SnapshotObject)snapshot;
AsyncCallFuture<SnapshotResult> future = new AsyncCallFuture<SnapshotResult>();
SnapshotResult result = new SnapshotResult(snapshot);
SnapshotResult result = new SnapshotResult(snapshot, null);
try {
snapObj.processEvent(Snapshot.Event.BackupToSecondary);
@ -420,7 +297,7 @@ public class SnapshotServiceImpl implements SnapshotService {
try {
SnapshotResult res = future.get();
SnapshotInfo destSnapshot = res.snashot;
SnapshotInfo destSnapshot = res.getSnashot();
return destSnapshot;
} catch (InterruptedException e) {
s_logger.debug("failed copy snapshot", e);
@ -438,7 +315,7 @@ public class SnapshotServiceImpl implements SnapshotService {
SnapshotInfo destSnapshot = context.destSnapshot;
SnapshotObject srcSnapshot = (SnapshotObject)context.srcSnapshot;
AsyncCallFuture<SnapshotResult> future = context.future;
SnapshotResult snapResult = new SnapshotResult(destSnapshot);
SnapshotResult snapResult = new SnapshotResult(destSnapshot, result.getAnswer());
if (result.isFailed()) {
snapResult.setResult(result.getResult());
future.complete(snapResult);
@ -453,7 +330,7 @@ public class SnapshotServiceImpl implements SnapshotService {
objInStoreMgr.update(destSnapshot, Event.OperationSuccessed);
srcSnapshot.processEvent(Snapshot.Event.OperationSucceeded);
snapResult = new SnapshotResult(this.snapshotfactory.getSnapshot(destSnapshot.getId()));
snapResult = new SnapshotResult(this.snapshotfactory.getSnapshot(destSnapshot.getId(), destSnapshot.getDataStore()), answer);
future.complete(snapResult);
} catch (Exception e) {
s_logger.debug("Failed to update snapshot state", e);
@ -465,7 +342,7 @@ public class SnapshotServiceImpl implements SnapshotService {
@DB
protected boolean destroySnapshotBackUp(SnapshotVO snapshot) {
SnapshotDataStoreVO snapshotStore = this._snapshotStoreDao.findBySnapshot(snapshot.getId());
SnapshotDataStoreVO snapshotStore = this._snapshotStoreDao.findBySnapshot(snapshot.getId(), DataStoreRole.Image);
if ( snapshotStore == null ){
s_logger.debug("Can't find snapshot" + snapshot.getId() + " backed up into image store");
return false;
@ -510,81 +387,19 @@ public class SnapshotServiceImpl implements SnapshotService {
if (result.isFailed()) {
s_logger.debug("delete snapshot failed" + result.getResult());
snapshot.processEvent(ObjectInDataStoreStateMachine.Event.OperationFailed);
SnapshotResult res = new SnapshotResult(context.snapshot);
SnapshotResult res = new SnapshotResult(context.snapshot, null);
future.complete(res);
return null;
}
snapshot.processEvent(ObjectInDataStoreStateMachine.Event.OperationSuccessed);
SnapshotResult res = new SnapshotResult(context.snapshot);
SnapshotResult res = new SnapshotResult(context.snapshot, null);
future.complete(res);
return null;
}
@Override
public boolean deleteSnapshot(SnapshotInfo snapInfo) {
Long snapshotId = snapInfo.getId();
SnapshotObject snapshot = (SnapshotObject)snapInfo;
if (!Snapshot.State.BackedUp.equals(snapshot.getState())) {
throw new InvalidParameterValueException("Can't delete snapshotshot " + snapshotId + " due to it is not in BackedUp Status");
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("Calling deleteSnapshot for snapshotId: " + snapshotId);
}
SnapshotVO lastSnapshot = null;
if (snapshot.getBackupSnapshotId() != null) {
List<SnapshotVO> snaps = _snapshotDao.listByBackupUuid(snapshot.getVolumeId(), snapshot.getBackupSnapshotId());
if (snaps != null && snaps.size() > 1) {
snapshot.setBackupSnapshotId(null);
SnapshotVO snapshotVO = this._snapshotDao.findById(snapshotId);
_snapshotDao.update(snapshot.getId(), snapshotVO);
}
}
_snapshotDao.remove(snapshotId);
long lastId = snapshotId;
boolean destroy = false;
while (true) {
lastSnapshot = _snapshotDao.findNextSnapshot(lastId);
if (lastSnapshot == null) {
// if all snapshots after this snapshot in this chain are removed, remove those snapshots.
destroy = true;
break;
}
if (lastSnapshot.getRemoved() == null) {
// if there is one child not removed, then can not remove back up snapshot.
break;
}
lastId = lastSnapshot.getId();
}
if (destroy) {
lastSnapshot = _snapshotDao.findByIdIncludingRemoved(lastId);
while (lastSnapshot.getRemoved() != null) {
String BackupSnapshotId = lastSnapshot.getBackupSnapshotId();
if (BackupSnapshotId != null) {
List<SnapshotVO> snaps = _snapshotDao.listByBackupUuid(lastSnapshot.getVolumeId(), BackupSnapshotId);
if (snaps != null && snaps.size() > 1) {
lastSnapshot.setBackupSnapshotId(null);
_snapshotDao.update(lastSnapshot.getId(), lastSnapshot);
} else {
if (destroySnapshotBackUp(lastSnapshot)) {
} else {
s_logger.debug("Destroying snapshot backup failed " + lastSnapshot);
break;
}
}
}
lastId = lastSnapshot.getPrevSnapshotId();
if (lastId == 0) {
break;
}
lastSnapshot = _snapshotDao.findByIdIncludingRemoved(lastId);
}
}
return true;
}

View File

@ -0,0 +1,24 @@
package org.apache.cloudstack.storage.snapshot;
import javax.inject.Inject;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotService;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotStrategy;
public abstract class SnapshotStrategyBase implements SnapshotStrategy {
@Inject
SnapshotService snapshotSvr;
//the default strategy is:
//create snapshot,
//backup, then delete snapshot on primary storage
@Override
public SnapshotInfo takeSnapshot(SnapshotInfo snapshot) {
return snapshotSvr.takeSnapshot(snapshot).getSnashot();
}
@Override
public SnapshotInfo backupSnapshot(SnapshotInfo snapshot) {
return snapshotSvr.backupSnapshot(snapshot);
}
}

View File

@ -0,0 +1,200 @@
package org.apache.cloudstack.storage.snapshot;
import java.util.List;
import javax.inject.Inject;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.State;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotResult;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotService;
import org.apache.cloudstack.storage.command.CreateObjectAnswer;
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
import org.apache.cloudstack.storage.to.SnapshotObjectTO;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.storage.DataStoreRole;
import com.cloud.storage.Snapshot;
import com.cloud.storage.SnapshotVO;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.snapshot.SnapshotManager;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.fsm.NoTransitionException;
@Component
public class XenserverSnapshotStrategy extends SnapshotStrategyBase {
private static final Logger s_logger = Logger
.getLogger(XenserverSnapshotStrategy.class);
@Inject
SnapshotManager snapshotMgr;
@Inject
SnapshotService snapshotSvr;
@Inject
DataStoreManager dataStoreMgr;
@Inject
SnapshotDataStoreDao snapshotStoreDao;
@Inject
ConfigurationDao configDao;
@Inject
SnapshotDataFactory snapshotDataFactory;
@Override
public SnapshotInfo backupSnapshot(SnapshotInfo snapshot) {
SnapshotInfo parentSnapshot = snapshot.getParent();
if (parentSnapshot.getPath().equalsIgnoreCase(snapshot.getPath())) {
s_logger.debug("backup an empty snapshot");
//don't need to backup this snapshot
SnapshotDataStoreVO parentSnapshotOnBackupStore = this.snapshotStoreDao.findBySnapshot(parentSnapshot.getId(), DataStoreRole.Image);
if (parentSnapshotOnBackupStore != null &&
parentSnapshotOnBackupStore.getState() == State.Ready) {
DataStore store = dataStoreMgr.getDataStore(parentSnapshotOnBackupStore.getDataStoreId(),
parentSnapshotOnBackupStore.getRole());
SnapshotInfo snapshotOnImageStore = (SnapshotInfo)store.create(snapshot);
snapshotOnImageStore.processEvent(Event.CreateOnlyRequested);
SnapshotObjectTO snapTO = new SnapshotObjectTO();
snapTO.setPath(parentSnapshotOnBackupStore.getInstallPath());
CreateObjectAnswer createSnapshotAnswer = new CreateObjectAnswer(snapTO);
snapshotOnImageStore.processEvent(Event.OperationSuccessed, createSnapshotAnswer);
SnapshotObject snapObj = (SnapshotObject)snapshot;
try {
snapObj.processEvent(Snapshot.Event.OperationNotPerformed);
} catch (NoTransitionException e) {
s_logger.debug("Failed to change state: " + snapshot.getId() + ": " +e.toString());
throw new CloudRuntimeException(e.toString());
}
return this.snapshotDataFactory.getSnapshot(snapObj.getId(), store);
} else {
s_logger.debug("parent snapshot hasn't been backed up yet");
}
}
//determine full snapshot backup or not
boolean fullBackup = false;
long preSnapshotId = 0;
if (parentSnapshot != null) {
preSnapshotId = parentSnapshot.getId();
int _deltaSnapshotMax = NumbersUtil.parseInt(configDao.getValue("snapshot.delta.max"), SnapshotManager.DELTAMAX);
int deltaSnap = _deltaSnapshotMax;
int i;
SnapshotDataStoreVO parentSnapshotOnBackupStore = null;
for (i = 1; i < deltaSnap; i++) {
parentSnapshotOnBackupStore = this.snapshotStoreDao.findBySnapshot(parentSnapshot.getId(), DataStoreRole.Image);
Long prevBackupId = parentSnapshotOnBackupStore.getParentSnapshotId();
if (prevBackupId == 0) {
break;
}
parentSnapshotOnBackupStore = this.snapshotStoreDao.findBySnapshot(prevBackupId, DataStoreRole.Image);
}
if (i >= deltaSnap) {
fullBackup = true;
}
}
snapshot.addPayload(fullBackup);
return this.snapshotSvr.backupSnapshot(snapshot);
}
@Override
public boolean deleteSnapshot(SnapshotInfo snapshot) {
Long snapshotId = snapshot.getId();
SnapshotObject snapObj = (SnapshotObject)snapshot;
if (!Snapshot.State.BackedUp.equals(snapshot.getState()) || !Snapshot) {
throw new InvalidParameterValueException("Can't delete snapshotshot " + snapshotId + " due to it is not in BackedUp Status");
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("Calling deleteSnapshot for snapshotId: " + snapshotId);
}
SnapshotVO lastSnapshot = null;
if (snapshot.getPrevSnapshotId() != null) {
List<SnapshotVO> snaps = _snapshotDao.listByBackupUuid(snapshot.getVolumeId(), snapshot.getBackupSnapshotId());
if (snaps != null && snaps.size() > 1) {
snapshot.setBackupSnapshotId(null);
SnapshotVO snapshotVO = this._snapshotDao.findById(snapshotId);
_snapshotDao.update(snapshot.getId(), snapshotVO);
}
}
_snapshotDao.remove(snapshotId);
long lastId = snapshotId;
boolean destroy = false;
while (true) {
lastSnapshot = _snapshotDao.findNextSnapshot(lastId);
if (lastSnapshot == null) {
// if all snapshots after this snapshot in this chain are removed, remove those snapshots.
destroy = true;
break;
}
if (lastSnapshot.getRemoved() == null) {
// if there is one child not removed, then can not remove back up snapshot.
break;
}
lastId = lastSnapshot.getId();
}
if (destroy) {
lastSnapshot = _snapshotDao.findByIdIncludingRemoved(lastId);
while (lastSnapshot.getRemoved() != null) {
String BackupSnapshotId = lastSnapshot.getBackupSnapshotId();
if (BackupSnapshotId != null) {
List<SnapshotVO> snaps = _snapshotDao.listByBackupUuid(lastSnapshot.getVolumeId(), BackupSnapshotId);
if (snaps != null && snaps.size() > 1) {
lastSnapshot.setBackupSnapshotId(null);
_snapshotDao.update(lastSnapshot.getId(), lastSnapshot);
} else {
if (destroySnapshotBackUp(lastSnapshot)) {
} else {
s_logger.debug("Destroying snapshot backup failed " + lastSnapshot);
break;
}
}
}
lastId = lastSnapshot.getPrevSnapshotId();
if (lastId == 0) {
break;
}
lastSnapshot = _snapshotDao.findByIdIncludingRemoved(lastId);
}
}
return true;
}
@Override
public boolean canHandle(SnapshotInfo snapshot) {
if (snapshot.getHypervisorType() == HypervisorType.XenServer) {
return true;
} else {
return false;
}
}
@Override
public SnapshotInfo takeSnapshot(SnapshotInfo snapshot) {
snapshot = snapshotSvr.takeSnapshot(snapshot).getSnashot();
//TODO: add async
return this.backupSnapshot(snapshot);
}
}

View File

@ -120,6 +120,12 @@ public class ObjectInDataStoreManagerImpl implements ObjectInDataStoreManager {
if ( obj.getType() == DataObjectType.TEMPLATE){
VMTemplateStoragePoolVO vo = new VMTemplateStoragePoolVO(dataStore.getId(), obj.getId());
vo = templatePoolDao.persist(vo);
} else if (obj.getType() == DataObjectType.SNAPSHOT) {
SnapshotDataStoreVO ss = new SnapshotDataStoreVO();
ss.setSnapshotId(obj.getId());
ss.setDataStoreId(dataStore.getId());
ss.setRole(dataStore.getRole());
ss = snapshotDataStoreDao.persist(ss);
}
} else {
// Image store
@ -137,6 +143,7 @@ public class ObjectInDataStoreManagerImpl implements ObjectInDataStoreManager {
SnapshotDataStoreVO ss = new SnapshotDataStoreVO();
ss.setSnapshotId(obj.getId());
ss.setDataStoreId(dataStore.getId());
ss.setRole(dataStore.getRole());
if (dataStore.getRole() == DataStoreRole.ImageCache) {
ss.setInstallPath("/snapshots/" + snapshotDao.findById(obj.getId()).getAccountId() + "/" + obj.getId());
}
@ -185,7 +192,7 @@ public class ObjectInDataStoreManagerImpl implements ObjectInDataStoreManager {
return true;
}
case SNAPSHOT:
SnapshotDataStoreVO destSnapshotStore = snapshotDataStoreDao.findByStoreSnapshot(dataStore.getId(), objId);
SnapshotDataStoreVO destSnapshotStore = snapshotDataStoreDao.findByStoreSnapshot(dataStore.getRole(), dataStore.getId(), objId);
if ( destSnapshotStore != null ){
return snapshotDataStoreDao.remove(destSnapshotStore.getId());
}
@ -262,24 +269,17 @@ public class ObjectInDataStoreManagerImpl implements ObjectInDataStoreManager {
public DataObjectInStore findObject(long objId, DataObjectType type,
long dataStoreId, DataStoreRole role) {
DataObjectInStore vo = null;
if (role == DataStoreRole.Image) {
if (role == DataStoreRole.Image || role == DataStoreRole.ImageCache) {
switch (type){
case TEMPLATE:
vo = templateDataStoreDao.findByStoreTemplate(dataStoreId, objId);
case SNAPSHOT:
vo = snapshotDataStoreDao.findByStoreSnapshot(dataStoreId, objId);
vo = snapshotDataStoreDao.findByStoreSnapshot(role, dataStoreId, objId);
case VOLUME:
vo = volumeDataStoreDao.findByStoreVolume(dataStoreId, objId);
}
} else if (type == DataObjectType.TEMPLATE && role == DataStoreRole.Primary) {
vo = templatePoolDao.findByPoolTemplate(dataStoreId, objId);
} else if (role == DataStoreRole.ImageCache) {
SearchCriteriaService<ObjectInDataStoreVO, ObjectInDataStoreVO> sc = SearchCriteria2.create(ObjectInDataStoreVO.class);
sc.addAnd(sc.getEntity().getObjectId(), Op.EQ, objId);
sc.addAnd(sc.getEntity().getObjectType(), Op.EQ, type);
sc.addAnd(sc.getEntity().getDataStoreId(), Op.EQ, dataStoreId);
sc.addAnd(sc.getEntity().getDataStoreRole(), Op.EQ, role);
vo = sc.find();
} else {
s_logger.debug("Invalid data or store type: " + type + " " + role);
throw new CloudRuntimeException("Invalid data or store type: " + type + " " + role);
@ -298,7 +298,7 @@ public class ObjectInDataStoreManagerImpl implements ObjectInDataStoreManager {
case TEMPLATE:
vo = templateDataStoreDao.findByTemplate(objId);
case SNAPSHOT:
vo = snapshotDataStoreDao.findBySnapshot(objId);
vo = snapshotDataStoreDao.findBySnapshot(objId, role);
case VOLUME:
vo = volumeDataStoreDao.findByVolume(objId);
}

View File

@ -32,6 +32,7 @@ import javax.persistence.TemporalType;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.State;
import com.cloud.storage.DataStoreRole;
import com.cloud.storage.Storage;
@ -191,4 +192,9 @@ public class ObjectInDataStoreVO implements StateObject<ObjectInDataStoreStateMa
public void setDataStoreId(long dataStoreId) {
this.dataStoreId = dataStoreId;
}
@Override
public State getObjectInStoreState() {
return this.state;
}
}

View File

@ -30,6 +30,7 @@ import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import com.cloud.storage.DataStoreRole;
import com.cloud.storage.StoragePoolHostVO;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
@ -52,7 +53,8 @@ public class SnapshotDataStoreDaoImpl extends GenericDaoBase<SnapshotDataStoreVO
storeSearch = createSearchBuilder();
storeSearch.and("store_id", storeSearch.entity().getDataStoreId(), SearchCriteria.Op.EQ);
storeSearch.and("destroyed", storeSearch.entity().getDestroyed(), SearchCriteria.Op.EQ);
storeSearch.and("store_role", storeSearch.entity().getRole(), SearchCriteria.Op.EQ);
storeSearch.done();
updateStateSearch = this.createSearchBuilder();
@ -63,13 +65,13 @@ public class SnapshotDataStoreDaoImpl extends GenericDaoBase<SnapshotDataStoreVO
snapshotSearch = createSearchBuilder();
snapshotSearch.and("snapshot_id", snapshotSearch.entity().getSnapshotId(), SearchCriteria.Op.EQ);
snapshotSearch.and("destroyed", snapshotSearch.entity().getDestroyed(), SearchCriteria.Op.EQ);
snapshotSearch.and("store_role", storeSearch.entity().getRole(), SearchCriteria.Op.EQ);
snapshotSearch.done();
storeSnapshotSearch = createSearchBuilder();
storeSnapshotSearch.and("snapshot_id", storeSnapshotSearch.entity().getSnapshotId(), SearchCriteria.Op.EQ);
storeSnapshotSearch.and("store_id", storeSnapshotSearch.entity().getDataStoreId(), SearchCriteria.Op.EQ);
storeSnapshotSearch.and("destroyed", storeSnapshotSearch.entity().getDestroyed(), SearchCriteria.Op.EQ);
storeSnapshotSearch.and("store_role", storeSearch.entity().getRole(), SearchCriteria.Op.EQ);
storeSnapshotSearch.done();
return true;
@ -114,11 +116,11 @@ public class SnapshotDataStoreDaoImpl extends GenericDaoBase<SnapshotDataStoreVO
@Override
public List<SnapshotDataStoreVO> listByStoreId(long id) {
public List<SnapshotDataStoreVO> listByStoreId(long id, DataStoreRole role) {
SearchCriteria<SnapshotDataStoreVO> sc = storeSearch.create();
sc.setParameters("store_id", id);
sc.setParameters("destroyed", false);
return listIncludingRemovedBy(sc);
sc.setParameters("store_role", role);
return listBy(sc);
}
@Override
@ -132,40 +134,19 @@ public class SnapshotDataStoreDaoImpl extends GenericDaoBase<SnapshotDataStoreVO
}
@Override
public SnapshotDataStoreVO findByStoreSnapshot(long storeId, long snapshotId) {
public SnapshotDataStoreVO findByStoreSnapshot(DataStoreRole role, long storeId, long snapshotId) {
SearchCriteria<SnapshotDataStoreVO> sc = storeSnapshotSearch.create();
sc.setParameters("store_id", storeId);
sc.setParameters("snapshot_id", snapshotId);
sc.setParameters("destroyed", false);
sc.setParameters("store_role", role);
return findOneIncludingRemovedBy(sc);
}
@Override
public SnapshotDataStoreVO findByStoreSnapshot(long storeId, long snapshotId, boolean lock) {
SearchCriteria<SnapshotDataStoreVO> sc = storeSnapshotSearch.create();
sc.setParameters("store_id", storeId);
sc.setParameters("snapshot_id", snapshotId);
sc.setParameters("destroyed", false);
if (!lock)
return findOneIncludingRemovedBy(sc);
else
return lockOneRandomRow(sc, true);
}
@Override
public SnapshotDataStoreVO findBySnapshot(long snapshotId) {
public SnapshotDataStoreVO findBySnapshot(long snapshotId, DataStoreRole role) {
SearchCriteria<SnapshotDataStoreVO> sc = snapshotSearch.create();
sc.setParameters("snapshot_id", snapshotId);
sc.setParameters("destroyed", false);
return findOneIncludingRemovedBy(sc);
}
@Override
public List<SnapshotDataStoreVO> listDestroyed(long id) {
SearchCriteria<SnapshotDataStoreVO> sc = storeSearch.create();
sc.setParameters("store_id", id);
sc.setParameters("destroyed", true);
return listIncludingRemovedBy(sc);
sc.setParameters("store_role", role);
return findOneBy(sc);
}
}

View File

@ -1,27 +0,0 @@
// 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 org.apache.cloudstack.storage.snapshot;
import org.apache.cloudstack.engine.cloud.entity.api.SnapshotEntity;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
public interface SnapshotService {
public SnapshotEntity getSnapshotEntity(long snapshotId);
public boolean takeSnapshot(SnapshotInfo snapshot);
public boolean revertSnapshot(SnapshotInfo snapshot);
public boolean deleteSnapshot(SnapshotInfo snapshot);
}

View File

@ -245,7 +245,8 @@ public class PrimaryDataStoreImpl implements PrimaryDataStore {
}
}
}
} else if (obj.getType() == DataObjectType.SNAPSHOT) {
return objectInStoreMgr.create(obj, this);
}
return objectInStoreMgr.get(obj, this);

View File

@ -840,5 +840,26 @@ public class VolumeServiceImpl implements VolumeService {
return null;
}
@Override
public SnapshotInfo takeSnapshot(VolumeInfo volume) {
VolumeObject vol = (VolumeObject)volume;
vol.stateTransit(Volume.Event.SnapshotRequested);
SnapshotInfo snapshot = null;
try {
snapshot = this.snapshotMgr.takeSnapshot(volume);
} catch (Exception e) {
s_logger.debug("Take snapshot: " + volume.getId() + " failed: " + e.toString());
} finally {
if (snapshot != null) {
vol.stateTransit(Volume.Event.OperationSucceeded);
} else {
vol.stateTransit(Volume.Event.OperationFailed);
}
}
return snapshot;
}
}

View File

@ -141,58 +141,22 @@ public class XenServerStorageResource {
}
protected CreateObjectAnswer getTemplateSize(CreateObjectCommand cmd, String templateUrl) {
Connection conn = hypervisorResource.getConnection();
/*Connection conn = hypervisorResource.getConnection();
long size = this.getTemplateSize(conn, templateUrl);
return new CreateObjectAnswer(cmd, templateUrl, size);
return new CreateObjectAnswer(cmd, templateUrl, size);*/
return null;
}
protected CreateObjectAnswer execute(CreateObjectCommand cmd) {
String uriString = cmd.getObjectUri();
DecodedDataObject obj = null;
Connection conn = hypervisorResource.getConnection();
VDI vdi = null;
boolean result = false;
String errorMsg = null;
try {
obj = Decoder.decode(uriString);
DecodedDataStore store = obj.getStore();
if (obj.getObjType().equalsIgnoreCase("template") && store.getRole().equalsIgnoreCase("image")) {
return getTemplateSize(cmd, obj.getPath());
}
long size = obj.getSize();
String name = obj.getName();
String storeUuid = store.getUuid();
SR primaryDataStoreSR = getSRByNameLabel(conn, storeUuid);
vdi = createVdi(conn, name, primaryDataStoreSR, size);
VDI.Record record = vdi.getRecord(conn);
result = true;
return new CreateObjectAnswer(cmd, record.uuid, record.virtualSize);
} catch (BadServerResponse e) {
s_logger.debug("Failed to create volume", e);
errorMsg = e.toString();
} catch (XenAPIException e) {
s_logger.debug("Failed to create volume", e);
errorMsg = e.toString();
} catch (XmlRpcException e) {
s_logger.debug("Failed to create volume", e);
errorMsg = e.toString();
} catch (URISyntaxException e) {
s_logger.debug("Failed to create volume", e);
errorMsg = e.toString();
} finally {
if (!result && vdi != null) {
try {
deleteVDI(conn, vdi);
} catch (Exception e) {
s_logger.debug("Faled to delete vdi: " + vdi.toString());
}
}
}
return new CreateObjectAnswer(cmd, false, errorMsg);
DataTO data = cmd.getData();
try {
if (data.getObjectType() == DataObjectType.VOLUME) {
return createVolume(data);
}
return new CreateObjectAnswer("not supported type");
} catch (Exception e) {
s_logger.debug("Failed to create object: " + data.getObjectType() + ": " + e.toString());
return new CreateObjectAnswer(e.toString());
}
}
protected Answer execute(DeleteVolumeCommand cmd) {
@ -735,20 +699,30 @@ public class XenServerStorageResource {
return new CopyCmdAnswer("not implemented yet");
}
protected CreateObjectAnswer createVolume(DataTO data) {
/*
protected CreateObjectAnswer createVolume(DataTO data) throws BadServerResponse, XenAPIException, XmlRpcException {
VolumeObjectTO volume = (VolumeObjectTO)data;
Connection conn = hypervisorResource.getConnection();
PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)data.getDataStore();
SR poolSr = hypervisorResource.getStorageRepository(conn, primaryStore.getUuid());
VDI.Record vdir = new VDI.Record();
vdir.nameLabel = dskch.getName();
vdir.nameLabel = volume.getName();
vdir.SR = poolSr;
vdir.type = Types.VdiType.USER;
vdir.virtualSize = dskch.getSize();
vdir.virtualSize = volume.getSize();
VDI vdi;
vdi = VDI.create(conn, vdir);
VDI.Record vdir;
vdir = vdi.getRecord(conn);
s_logger.debug("Succesfully created VDI for " + cmd + ". Uuid = " + vdir.uuid);*/
return null;
VolumeObjectTO newVol = new VolumeObjectTO();
newVol.setName(vdir.nameLabel);
newVol.setSize(vdir.virtualSize);
newVol.setPath(vdir.uuid);
return new CreateObjectAnswer(newVol);
}
protected CopyCmdAnswer cloneVolumeFromBaseTemplate(DataTO srcData, DataTO destData) {
Connection conn = hypervisorResource.getConnection();
PrimaryDataStoreTO pool = (PrimaryDataStoreTO)destData.getDataStore();

View File

@ -96,12 +96,12 @@ public class SampleImageStoreDriverImpl implements ImageStoreDriver {
callback.complete(result);
return;
}
CreateObjectCommand createCmd = new CreateObjectCommand(data.getUri());
CreateObjectCommand createCmd = new CreateObjectCommand(data.getTO());
CreateObjectAnswer answer = (CreateObjectAnswer)ep.sendMessage(createCmd);
if (answer.getResult()) {
//update imagestorevo
result = new CreateCmdResult(answer.getPath(), null);
result = new CreateCmdResult(null, null);
} else {
result.setResult(answer.getDetails());
}

View File

@ -34,6 +34,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
import org.apache.cloudstack.storage.command.CreateObjectCommand;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.volume.VolumeObject;
import org.apache.log4j.Logger;
@ -108,46 +109,15 @@ public class CloudStackPrimaryDataStoreDriverImpl implements PrimaryDataStoreDri
return null;
}
public boolean createVolume(
public Answer createVolume(
VolumeInfo volume) throws StorageUnavailableException {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Creating volume: " + volume);
}
DiskOfferingVO offering = diskOfferingDao.findById(volume.getDiskOfferingId());
DiskProfile diskProfile = new DiskProfile(volume, offering,
null);
StoragePool pool = (StoragePool)volume.getDataStore();
VolumeVO vol = volumeDao.findById(volume.getId());
if (pool != null) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Trying to create in " + pool);
}
vol.setPoolId(pool.getId());
CreateCommand cmd = new CreateCommand(diskProfile, new StorageFilerTO(
pool));
Answer answer = storageMgr.sendToPool(pool, null, cmd);
if (answer.getResult()) {
CreateAnswer createAnswer = (CreateAnswer) answer;
vol.setFolder(pool.getPath());
vol.setPath(createAnswer.getVolume().getPath());
vol.setSize(createAnswer.getVolume().getSize());
vol.setPoolType(pool.getPoolType());
vol.setPoolId(pool.getId());
vol.setPodId(pool.getPodId());
this.volumeDao.update(vol.getId(), vol);
return true;
}
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("Unable to create volume " + volume.getId());
}
return false;
CreateObjectCommand cmd = new CreateObjectCommand(volume.getTO());
Answer answer = storageMgr.sendToPool((StoragePool)volume.getDataStore(), null, cmd);
return answer;
}
@Override
@ -155,9 +125,10 @@ public class CloudStackPrimaryDataStoreDriverImpl implements PrimaryDataStoreDri
AsyncCompletionCallback<CreateCmdResult> callback) {
// TODO Auto-generated method stub
String errMsg = null;
Answer answer = null;
if (data.getType() == DataObjectType.VOLUME) {
try {
createVolume((VolumeInfo)data);
answer = createVolume((VolumeInfo)data);
} catch (StorageUnavailableException e) {
s_logger.debug("failed to create volume", e);
errMsg = e.toString();
@ -166,13 +137,12 @@ public class CloudStackPrimaryDataStoreDriverImpl implements PrimaryDataStoreDri
errMsg = e.toString();
}
}
CreateCmdResult result = new CreateCmdResult(null, null);
CreateCmdResult result = new CreateCmdResult(null, answer);
if (errMsg != null) {
result.setResult(errMsg);
}
callback.complete(result);
}
@Override

View File

@ -0,0 +1,14 @@
package com.cloud.storage;
public class CreateSnapshotPayload {
private Long snapshotPolicyId;
public Long getSnapshotPolicyId() {
return snapshotPolicyId;
}
public void setSnapshotPolicyId(Long snapshotPolicyId) {
this.snapshotPolicyId = snapshotPolicyId;
}
}

View File

@ -1931,7 +1931,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
_accountMgr.checkAccessAndSpecifyAuthority(UserContext.current().getCaller(), store.getDataCenterId());
// Verify that there are no live snapshot, template, volume on the image store to be deleted
List<SnapshotDataStoreVO> snapshots = _snapshotStoreDao.listByStoreId(storeId);
List<SnapshotDataStoreVO> snapshots = _snapshotStoreDao.listByStoreId(storeId, DataStoreRole.Image);
if ( snapshots != null && snapshots.size() > 0 ){
throw new CloudRuntimeException("Cannot delete image store with active snapshots backup!");
}

View File

@ -85,6 +85,7 @@ import com.cloud.configuration.Resource.ResourceType;
import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.consoleproxy.ConsoleProxyManager;
import com.cloud.dc.ClusterVO;
import com.cloud.dc.DataCenter;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.HostPodVO;
import com.cloud.dc.dao.ClusterDao;
@ -166,6 +167,7 @@ import com.cloud.vm.dao.DomainRouterDao;
import com.cloud.vm.dao.SecondaryStorageVmDao;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.VMInstanceDao;
import com.cloud.vm.snapshot.VMSnapshot;
import com.cloud.vm.snapshot.VMSnapshotVO;
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
@ -2463,5 +2465,47 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
throw new CloudRuntimeException("Failed to destroy volume" + volume.getId(), e);
}
}
@Override
public Snapshot takeSnapshot(Long volumeId, Long policyId) throws ResourceAllocationException {
Account caller = UserContext.current().getCaller();
VolumeInfo volume = this.volFactory.getVolume(volumeId);
if (volume == null) {
throw new InvalidParameterValueException("Creating snapshot failed due to volume:" + volumeId + " doesn't exist");
}
DataCenter zone = _dcDao.findById(volume.getDataCenterId());
if (zone == null) {
throw new InvalidParameterValueException("Can't find zone by id " + volume.getDataCenterId());
}
if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getType())) {
throw new PermissionDeniedException("Cannot perform this operation, Zone is currently disabled: " + zone.getName());
}
if (volume.getState() != Volume.State.Ready) {
throw new InvalidParameterValueException("VolumeId: " + volumeId + " is not in " + Volume.State.Ready + " state but " + volume.getState() + ". Cannot take snapshot.");
}
if ( volume.getTemplateId() != null ) {
VMTemplateVO template = _templateDao.findById(volume.getTemplateId());
if( template != null && template.getTemplateType() == Storage.TemplateType.SYSTEM ) {
throw new InvalidParameterValueException("VolumeId: " + volumeId + " is for System VM , Creating snapshot against System VM volumes is not supported");
}
}
StoragePool storagePool = (StoragePool)volume.getDataStore();
if (storagePool == null) {
throw new InvalidParameterValueException("VolumeId: " + volumeId + " please attach this volume to a VM before create snapshot for it");
}
CreateSnapshotPayload payload = new CreateSnapshotPayload();
payload.setSnapshotPolicyId(policyId);
return this.volService.takeSnapshot(volume);
}
}

View File

@ -16,6 +16,7 @@
// under the License.
package com.cloud.storage.dao;
import com.cloud.storage.DataStoreRole;
import com.cloud.storage.Snapshot;
import com.cloud.storage.Snapshot.Type;
import com.cloud.storage.SnapshotVO;
@ -29,7 +30,7 @@ public interface SnapshotDao extends GenericDao<SnapshotVO, Long>, StateDao<Snap
List<SnapshotVO> listByVolumeId(long volumeId);
List<SnapshotVO> listByVolumeId(Filter filter, long volumeId);
SnapshotVO findNextSnapshot(long parentSnapId);
long getLastSnapshot(long volumeId, long snapId);
long getLastSnapshot(long volumeId, DataStoreRole role);
List<SnapshotVO> listByVolumeIdType(long volumeId, Type type);
List<SnapshotVO> listByVolumeIdIncludingRemoved(long volumeId);
List<SnapshotVO> listByBackupUuid(long volumeId, String backupUuid);

View File

@ -28,6 +28,7 @@ import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import com.cloud.server.ResourceTag.TaggedResourceType;
import com.cloud.storage.DataStoreRole;
import com.cloud.storage.Snapshot;
import com.cloud.storage.Snapshot.Event;
import com.cloud.storage.Snapshot.State;
@ -55,7 +56,7 @@ import com.cloud.vm.dao.VMInstanceDao;
public class SnapshotDaoImpl extends GenericDaoBase<SnapshotVO, Long> implements SnapshotDao {
public static final Logger s_logger = Logger.getLogger(SnapshotDaoImpl.class.getName());
//TODO: we should remove these direct sqls
private static final String GET_LAST_SNAPSHOT = "SELECT id FROM snapshots where volume_id = ? AND id != ? AND path IS NOT NULL ORDER BY created DESC";
private static final String GET_LAST_SNAPSHOT = "SELECT snapshots.id FROM snapshot_store_ref, snapshots where snapshots.id = snapshot_store_ref.snapshot_id AND snapshosts.volume_id = ? AND snapshot_store_ref.role = ? ORDER BY created DESC";
private static final String UPDATE_SNAPSHOT_VERSION = "UPDATE snapshots SET version = ? WHERE volume_id = ? AND version = ?";
private static final String GET_SECHOST_ID = "SELECT store_id FROM snapshots, snapshot_store_ref where snapshots.id = snapshot_store_ref.snapshot_id AND volume_id = ? AND backup_snap_id IS NOT NULL AND sechost_id IS NOT NULL LIMIT 1";
private static final String UPDATE_SECHOST_ID = "UPDATE snapshots SET sechost_id = ? WHERE data_center_id = ?";
@ -212,14 +213,14 @@ public class SnapshotDaoImpl extends GenericDaoBase<SnapshotVO, Long> implements
return null;
}
@Override
public long getLastSnapshot(long volumeId, long snapId) {
public long getLastSnapshot(long volumeId, DataStoreRole role) {
Transaction txn = Transaction.currentTxn();
PreparedStatement pstmt = null;
String sql = GET_LAST_SNAPSHOT;
try {
pstmt = txn.prepareAutoCloseStatement(sql);
pstmt.setLong(1, volumeId);
pstmt.setLong(2, snapId);
pstmt.setString(2, role.toString());
ResultSet rs = pstmt.executeQuery();
if (rs.next()) {
return rs.getLong(1);

View File

@ -18,6 +18,7 @@ package com.cloud.storage.snapshot;
import java.util.List;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import com.cloud.agent.api.Answer;
@ -68,7 +69,10 @@ public interface SnapshotManager {
Answer sendToPool(Volume vol, Command cmd);
SnapshotVO getParentSnapshot(VolumeInfo volume, Snapshot snapshot);
SnapshotVO getParentSnapshot(VolumeInfo volume);
Snapshot backupSnapshot(Long snapshotId);
SnapshotInfo takeSnapshot(VolumeInfo volume)
throws ResourceAllocationException;
}

View File

@ -38,6 +38,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotService;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotStrategy;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
@ -82,7 +83,9 @@ import com.cloud.host.dao.HostDao;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.org.Grouping;
import com.cloud.projects.Project.ListProjectResourcesCriteria;
import com.cloud.resource.ResourceManager;
import com.cloud.server.ResourceTag.TaggedResourceType;
import com.cloud.storage.CreateSnapshotPayload;
import com.cloud.storage.Snapshot;
import com.cloud.storage.Snapshot.Type;
import com.cloud.storage.DataStoreRole;
@ -128,8 +131,12 @@ import com.cloud.utils.db.JoinBuilder;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.vm.UserVmVO;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine.State;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.snapshot.VMSnapshot;
import com.cloud.vm.snapshot.VMSnapshotVO;
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
@Component
@ -202,6 +209,10 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
@Inject VolumeDataFactory volFactory;
@Inject SnapshotDataFactory snapshotFactory;
@Inject EndPointSelector _epSelector;
@Inject
private ResourceManager _resourceMgr;
@Inject
protected List<SnapshotStrategy> snapshotStrategies;
private int _totalRetries;
@ -278,32 +289,25 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
throw new InvalidParameterValueException("Volume is not in ready state");
}
SnapshotInfo snapshot = null;
boolean backedUp = false;
// does the caller have the authority to act on this volume
_accountMgr.checkAccess(UserContext.current().getCaller(), null, true, volume);
SnapshotInfo snap = this.snapshotFactory.getSnapshot(snapshotId);
SnapshotInfo snapshot = this.snapshotFactory.getSnapshot(snapshotId, DataStoreRole.Primary);
try {
snapshot = this.snapshotSrv.takeSnapshot(volume, snapshotId);
if (snapshot != null) {
postCreateSnapshot(volumeId, snapshot.getId(), policyId);
//Check if the snapshot was removed while backingUp. If yes, do not log snapshot create usage event
SnapshotVO freshSnapshot = _snapshotDao.findById(snapshot.getId());
if ((freshSnapshot != null) && backedUp) {
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_CREATE, snapshot.getAccountId(),
snapshot.getDataCenterId(), snapshotId, snapshot.getName(), null, null,
volume.getSize(), snapshot.getClass().getName(), snapshot.getUuid());
}
postCreateSnapshot(volumeId, snapshot.getId(), policyId);
//Check if the snapshot was removed while backingUp. If yes, do not log snapshot create usage event
SnapshotVO freshSnapshot = _snapshotDao.findById(snapshot.getId());
if ((freshSnapshot != null) && backedUp) {
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_CREATE, snapshot.getAccountId(),
snapshot.getDataCenterId(), snapshotId, snapshot.getName(), null, null,
volume.getSize(), snapshot.getClass().getName(), snapshot.getUuid());
}
_resourceLimitMgr.incrementResourceCount(snapshotOwner.getId(), ResourceType.snapshot);
_resourceLimitMgr.incrementResourceCount(snapshotOwner.getId(), ResourceType.snapshot);
}
if (backup) {
this.backupSnapshot(snapshotId);
}
} catch(Exception e) {
s_logger.debug("Failed to create snapshot", e);
if (backup) {
@ -337,16 +341,11 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
@Override
public Snapshot backupSnapshot(Long snapshotId) {
SnapshotInfo snapshot = this.snapshotFactory.getSnapshot(snapshotId);
if (snapshot == null) {
throw new CloudRuntimeException("Can't find snapshot:" + snapshotId);
SnapshotInfo snapshot = this.snapshotFactory.getSnapshot(snapshotId, DataStoreRole.Image);
if (snapshot != null) {
throw new CloudRuntimeException("Already in the backup snapshot:" + snapshotId);
}
if (snapshot.getState() == Snapshot.State.BackedUp) {
return snapshot;
}
return this.snapshotSrv.backupSnapshot(snapshot);
}
@ -436,8 +435,8 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
}
@Override
public SnapshotVO getParentSnapshot(VolumeInfo volume, Snapshot snapshot) {
long preId = _snapshotDao.getLastSnapshot(volume.getId(), snapshot.getId());
public SnapshotVO getParentSnapshot(VolumeInfo volume) {
long preId = _snapshotDao.getLastSnapshot(volume.getId(), DataStoreRole.Primary);
SnapshotVO preSnapshotVO = null;
if (preId != 0 && !(volume.getLastPoolId() != null && !volume.getLastPoolId().equals(volume.getPoolId()))) {
@ -500,15 +499,21 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
Account caller = UserContext.current().getCaller();
// Verify parameters
SnapshotInfo snapshotCheck = this.snapshotFactory.getSnapshot(snapshotId);
SnapshotVO snapshotCheck = this._snapshotDao.findById(snapshotId);
if (snapshotCheck == null) {
throw new InvalidParameterValueException("unable to find a snapshot with id " + snapshotId);
}
_accountMgr.checkAccess(caller, null, true, snapshotCheck);
SnapshotStrategy snapshotStrategy = null;
for (SnapshotStrategy strategy : this.snapshotStrategies) {
if (strategy.canHandle(snapshotCheck)) {
snapshotStrategy = strategy;
break;
}
}
try {
boolean result = this.snapshotSrv.deleteSnapshot(snapshotCheck);
boolean result = snapshotStrategy.deleteSnapshot(snapshotId);
if (result) {
if (snapshotCheck.getState() == Snapshot.State.BackedUp) {
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_DELETE, snapshotCheck.getAccountId(),
@ -529,7 +534,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
@Override
public String getSecondaryStorageURL(SnapshotVO snapshot) {
SnapshotDataStoreVO snapshotStore = this._snapshotStoreDao.findBySnapshot(snapshot.getId());
SnapshotDataStoreVO snapshotStore = this._snapshotStoreDao.findBySnapshot(snapshot.getId(), DataStoreRole.Image);
if (snapshotStore != null){
DataStore store = this.dataStoreMgr.getDataStore(snapshotStore.getDataStoreId(), DataStoreRole.Image);
if ( store != null ){
@ -904,44 +909,76 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
return null;
}
@Override
public SnapshotVO allocSnapshot(Long volumeId, Long policyId) throws ResourceAllocationException {
Account caller = UserContext.current().getCaller();
private boolean hostSupportSnapsthot(HostVO host) {
if (host.getHypervisorType() != HypervisorType.KVM) {
return true;
}
// Determine host capabilities
String caps = host.getCapabilities();
VolumeVO volume = _volsDao.findById(volumeId);
if (volume == null) {
throw new InvalidParameterValueException("Creating snapshot failed due to volume:" + volumeId + " doesn't exist");
}
DataCenter zone = _dcDao.findById(volume.getDataCenterId());
if (zone == null) {
throw new InvalidParameterValueException("Can't find zone by id " + volume.getDataCenterId());
}
if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getType())) {
throw new PermissionDeniedException("Cannot perform this operation, Zone is currently disabled: " + zone.getName());
}
if (volume.getState() != Volume.State.Ready) {
throw new InvalidParameterValueException("VolumeId: " + volumeId + " is not in " + Volume.State.Ready + " state but " + volume.getState() + ". Cannot take snapshot.");
}
if ( volume.getTemplateId() != null ) {
VMTemplateVO template = _templateDao.findById(volume.getTemplateId());
if( template != null && template.getTemplateType() == Storage.TemplateType.SYSTEM ) {
throw new InvalidParameterValueException("VolumeId: " + volumeId + " is for System VM , Creating snapshot against System VM volumes is not supported");
}
}
StoragePoolVO storagePoolVO = _storagePoolDao.findById(volume.getPoolId());
if (storagePoolVO == null) {
throw new InvalidParameterValueException("VolumeId: " + volumeId + " please attach this volume to a VM before create snapshot for it");
}
ClusterVO cluster = _clusterDao.findById(storagePoolVO.getClusterId());
if (caps != null) {
String[] tokens = caps.split(",");
for (String token : tokens) {
if (token.contains("snapshot")) {
return true;
}
}
}
return false;
}
private boolean supportedByHypervisor(VolumeInfo volume) {
StoragePool storagePool = (StoragePool)volume.getDataStore();
ClusterVO cluster = _clusterDao.findById(storagePool.getClusterId());
if (cluster != null && cluster.getHypervisorType() == HypervisorType.Ovm) {
throw new InvalidParameterValueException("Ovm won't support taking snapshot");
}
if (volume.getHypervisorType().equals(HypervisorType.KVM)) {
List<HostVO> hosts = _resourceMgr.listAllHostsInCluster(cluster.getId());
if (hosts != null && !hosts.isEmpty()) {
HostVO host = hosts.get(0);
if (!hostSupportSnapsthot(host)) {
throw new CloudRuntimeException("KVM Snapshot is not supported on cluster: " + host.getId());
}
}
}
// if volume is attached to a vm in destroyed or expunging state; disallow
if (volume.getInstanceId() != null) {
UserVmVO userVm = _vmDao.findById(volume.getInstanceId());
if (userVm != null) {
if (userVm.getState().equals(State.Destroyed) || userVm.getState().equals(State.Expunging)) {
throw new CloudRuntimeException("Creating snapshot failed due to volume:" + volume.getId() + " is associated with vm:" + userVm.getInstanceName() + " is in "
+ userVm.getState().toString() + " state");
}
if(userVm.getHypervisorType() == HypervisorType.VMware || userVm.getHypervisorType() == HypervisorType.KVM) {
List<SnapshotVO> activeSnapshots = _snapshotDao.listByInstanceId(volume.getInstanceId(), Snapshot.State.Creating, Snapshot.State.CreatedOnPrimary, Snapshot.State.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");
}
List<VMSnapshotVO> activeVMSnapshots = _vmSnapshotDao.listByInstanceId(userVm.getId(),
VMSnapshot.State.Creating, VMSnapshot.State.Reverting, VMSnapshot.State.Expunging);
if (activeVMSnapshots.size() > 0) {
throw new CloudRuntimeException(
"There is other active vm snapshot tasks on the instance to which the volume is attached, please try again later");
}
}
}
return true;
}
@Override
public SnapshotInfo takeSnapshot(VolumeInfo volume) throws ResourceAllocationException {
Account caller = UserContext.current().getCaller();
supportedByHypervisor(volume);
CreateSnapshotPayload snapInfo = (CreateSnapshotPayload)volume.getpayload();
Long policyId = snapInfo.getSnapshotPolicyId();
// Verify permissions
_accountMgr.checkAccess(caller, null, true, volume);
Type snapshotType = getSnapshotType(policyId);
@ -975,14 +1012,13 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
}
String snapshotName = vmDisplayName + "_" + volume.getName() + "_" + timeString;
// Create the Snapshot object and save it so we can return it to the
// user
HypervisorType hypervisorType = this._volsDao.getHypervisorType(volumeId);
SnapshotVO snapshotVO = new SnapshotVO(volume.getDataCenterId(), volume.getAccountId(), volume.getDomainId(), volume.getId(), volume.getDiskOfferingId(), null, snapshotName,
HypervisorType hypervisorType = volume.getHypervisorType();
SnapshotVO snapshotVO = new SnapshotVO(volume.getDataCenterId(), volume.getAccountId(), volume.getDomainId(), volume.getId(), volume.getDiskOfferingId(), snapshotName,
(short) snapshotType.ordinal(), snapshotType.name(), volume.getSize(), hypervisorType);
SnapshotVO snapshot = _snapshotDao.persist(snapshotVO);
if (snapshot == null) {
throw new CloudRuntimeException("Failed to create snapshot for volume: "+volumeId);
throw new CloudRuntimeException("Failed to create snapshot for volume: " + volume.getId());
}
if (backup) {
_resourceLimitMgr.incrementResourceCount(volume.getAccountId(), ResourceType.secondary_storage,
@ -991,7 +1027,19 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
_resourceLimitMgr.incrementResourceCount(volume.getAccountId(), ResourceType.primary_storage,
new Long(volume.getSize()));
}
return snapshot;
SnapshotInfo snap = this.snapshotFactory.getSnapshot(snapshot.getId(), volume.getDataStore());
boolean processed = false;
for (SnapshotStrategy strategy : snapshotStrategies) {
if (strategy.canHandle(snap)) {
processed = true;
snap = strategy.takeSnapshot(snap);
break;
}
}
if (!processed) {
throw new CloudRuntimeException("Can't find snapshot strategy to deal with snapshot:" + snapshot.getId());
}
return snap;
}
@Override