refactor snapshot, move existing snapshot code into its own snapshotstrategy

This commit is contained in:
Edison Su 2013-02-13 11:11:45 -08:00 committed by Edison Su
parent 020be66f9d
commit ff047e75d3
47 changed files with 1627 additions and 1201 deletions

View File

@ -61,22 +61,6 @@ public interface Snapshot extends ControlledEntity, Identity, InternalIdentity,
BackedUp,
Error;
private final static StateMachine2<State, Event, Snapshot> s_fsm = new StateMachine2<State, Event, Snapshot>();
public static StateMachine2<State, Event, Snapshot> getStateMachine() {
return s_fsm;
}
static {
s_fsm.addTransition(null, Event.CreateRequested, Creating);
s_fsm.addTransition(Creating, Event.OperationSucceeded, CreatedOnPrimary);
s_fsm.addTransition(Creating, Event.OperationNotPerformed, BackedUp);
s_fsm.addTransition(Creating, Event.OperationFailed, Error);
s_fsm.addTransition(CreatedOnPrimary, Event.BackupToSecondary, BackingUp);
s_fsm.addTransition(BackingUp, Event.OperationSucceeded, BackedUp);
s_fsm.addTransition(BackingUp, Event.OperationFailed, Error);
}
public String toString() {
return this.name();
}
@ -107,7 +91,7 @@ public interface Snapshot extends ControlledEntity, Identity, InternalIdentity,
Date getCreated();
Type getType();
Type getRecurringType();
State getState();

View File

@ -175,7 +175,7 @@ public class SnapshotVO implements Snapshot {
}
@Override
public Type getType() {
public Type getRecurringType() {
if (snapshotType < 0 || snapshotType >= Type.values().length) {
return null;
}

View File

@ -18,14 +18,22 @@
*/
package org.apache.cloudstack.engine.subsystem.api.storage;
import com.cloud.agent.api.Answer;
public class CopyCommandResult extends CommandResult {
private final String path;
public CopyCommandResult(String path) {
private final Answer answer;
public CopyCommandResult(String path, Answer answer) {
super();
this.path = path;
this.answer = answer;
}
public String getPath() {
return this.path;
}
public Answer getAnswer() {
return this.answer;
}
}

View File

@ -23,4 +23,5 @@ import com.cloud.utils.fsm.StateObject;
public interface DataObjectInStore extends StateObject<ObjectInDataStoreStateMachine.State> {
public String getInstallPath();
public void setInstallPath(String path);
}

View File

@ -30,4 +30,5 @@ public interface DataStoreDriver {
public void deleteAsync(DataObject data, AsyncCompletionCallback<CommandResult> callback);
public void copyAsync(DataObject srcdata, DataObject destData, AsyncCompletionCallback<CopyCommandResult> callback);
public boolean canCopy(DataObject srcData, DataObject destData);
public void resize(DataObject data, AsyncCompletionCallback<CreateCmdResult> callback);
}

View File

@ -49,6 +49,7 @@ public interface ObjectInDataStoreStateMachine extends StateObject<ObjectInDataS
OperationSuccessed,
OperationFailed,
CopyingRequested,
ResizeRequested,
ExpungeRequested
}

View File

@ -16,14 +16,11 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.cloudstack.storage.volume;
package org.apache.cloudstack.engine.subsystem.api.storage;
import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
public interface PrimaryDataStoreDriver extends DataStoreDriver {
public void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback<CommandResult> callback);
public void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback<CreateCmdResult> callback);
public void revertSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback<CommandResult> callback);
}

View File

@ -16,9 +16,13 @@
// under the License.
package org.apache.cloudstack.engine.subsystem.api.storage;
import com.cloud.storage.Snapshot;
public interface SnapshotInfo extends DataObject {
public interface SnapshotInfo extends DataObject, Snapshot {
public SnapshotInfo getParent();
public SnapshotInfo getChild();
public VolumeInfo getBaseVolume();
Long getDataCenterId();
public Long getPrevSnapshotId();
}

View File

@ -0,0 +1,10 @@
package org.apache.cloudstack.engine.subsystem.api.storage;
public interface SnapshotStrategy {
public boolean canHandle(SnapshotInfo snapshot);
public SnapshotInfo takeSnapshot(VolumeInfo volume, Long snapshotId);
public SnapshotInfo backupSnapshot(SnapshotInfo snapshot);
public boolean deleteSnapshot(SnapshotInfo snapshot);
public boolean revertSnapshot(SnapshotInfo snapshot);
}

View File

@ -18,10 +18,13 @@
*/
package org.apache.cloudstack.engine.subsystem.api.storage;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.storage.Volume;
public interface VolumeInfo extends DataObject, Volume {
public boolean isAttachedVM();
public void addPayload(Object data);
public Object getpayload();
public HypervisorType getHypervisorType();
public Long getLastPoolId();
}

View File

@ -74,5 +74,7 @@ public interface VolumeService {
boolean destroyVolume(long volumeId) throws ConcurrentOperationException;
AsyncCallFuture<VolumeApiResult> registerVolume(VolumeInfo volume, DataStore store);
AsyncCallFuture<VolumeApiResult> resize(VolumeInfo volume);
}

View File

@ -38,22 +38,30 @@ import org.apache.log4j.Logger;
import com.cloud.agent.AgentManager;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.DeleteSnapshotBackupCommand;
import com.cloud.agent.api.storage.DeleteVolumeCommand;
import com.cloud.agent.api.to.S3TO;
import com.cloud.agent.api.to.SwiftTO;
import com.cloud.host.HostVO;
import com.cloud.host.dao.HostDao;
import com.cloud.storage.RegisterVolumePayload;
import com.cloud.storage.Storage.ImageFormat;
import com.cloud.storage.SnapshotVO;
import com.cloud.storage.VMTemplateStorageResourceAssoc;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.VMTemplateZoneVO;
import com.cloud.storage.VolumeHostVO;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.SnapshotDao;
import com.cloud.storage.dao.VMTemplateDao;
import com.cloud.storage.dao.VMTemplateHostDao;
import com.cloud.storage.dao.VMTemplateZoneDao;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.storage.dao.VolumeHostDao;
import com.cloud.storage.download.DownloadMonitor;
import com.cloud.storage.s3.S3Manager;
import com.cloud.storage.snapshot.SnapshotManager;
import com.cloud.storage.swift.SwiftManager;
import com.cloud.utils.exception.CloudRuntimeException;
public class AncientImageDataStoreDriverImpl implements ImageDataStoreDriver {
@ -69,7 +77,13 @@ public class AncientImageDataStoreDriverImpl implements ImageDataStoreDriver {
@Inject VolumeDao volumeDao;
@Inject VolumeHostDao volumeHostDao;
@Inject HostDao hostDao;
@Inject SnapshotDao snapshotDao;
@Inject AgentManager agentMgr;
@Inject SnapshotManager snapshotMgr;
@Inject
private SwiftManager _swiftMgr;
@Inject
private S3Manager _s3Mgr;
@Override
public String grantAccess(DataObject data, EndPoint ep) {
// TODO Auto-generated method stub
@ -158,6 +172,49 @@ public class AncientImageDataStoreDriverImpl implements ImageDataStoreDriver {
}
private void deleteSnapshot(DataObject data, AsyncCompletionCallback<CommandResult> callback) {
Long snapshotId = data.getId();
SnapshotVO snapshot = this.snapshotDao.findByIdIncludingRemoved(snapshotId);
CommandResult result = new CommandResult();
if (snapshot == null) {
s_logger.debug("Destroying snapshot " + snapshotId + " backup failed due to unable to find snapshot ");
result.setResult("Unable to find snapshot: " + snapshotId);
callback.complete(result);
return;
}
try {
String secondaryStoragePoolUrl = this.snapshotMgr.getSecondaryStorageURL(snapshot);
Long dcId = snapshot.getDataCenterId();
Long accountId = snapshot.getAccountId();
Long volumeId = snapshot.getVolumeId();
String backupOfSnapshot = snapshot.getBackupSnapshotId();
if (backupOfSnapshot == null) {
callback.complete(result);
return;
}
SwiftTO swift = _swiftMgr.getSwiftTO(snapshot.getSwiftId());
S3TO s3 = _s3Mgr.getS3TO();
DeleteSnapshotBackupCommand cmd = new DeleteSnapshotBackupCommand(
swift, s3, secondaryStoragePoolUrl, dcId, accountId, volumeId,
backupOfSnapshot, false);
Answer answer = agentMgr.sendToSSVM(dcId, cmd);
if ((answer != null) && answer.getResult()) {
snapshot.setBackupSnapshotId(null);
snapshotDao.update(snapshotId, snapshot);
} else if (answer != null) {
result.setResult(answer.getDetails());
}
} catch (Exception e) {
s_logger.debug("failed to delete snapshot: " + snapshotId + ": " + e.toString());
result.setResult(e.toString());
}
callback.complete(result);
}
@Override
public void deleteAsync(DataObject data,
AsyncCompletionCallback<CommandResult> callback) {
@ -165,10 +222,9 @@ public class AncientImageDataStoreDriverImpl implements ImageDataStoreDriver {
deleteVolume(data, callback);
} else if (data.getType() == DataObjectType.TEMPLATE) {
deleteTemplate(data, callback);
} else if (data.getType() == DataObjectType.SNAPSHOT) {
deleteSnapshot(data, callback);
}
}
@Override
@ -184,4 +240,11 @@ public class AncientImageDataStoreDriverImpl implements ImageDataStoreDriver {
return false;
}
@Override
public void resize(DataObject data,
AsyncCompletionCallback<CreateCmdResult> callback) {
// TODO Auto-generated method stub
}
}

View File

@ -116,4 +116,11 @@ public class DefaultImageDataStoreDriverImpl implements ImageDataStoreDriver {
// TODO Auto-generated method stub
}
@Override
public void resize(DataObject data,
AsyncCompletionCallback<CreateCmdResult> callback) {
// TODO Auto-generated method stub
}
}

View File

@ -101,7 +101,7 @@ public class DefaultImageMotionStrategy implements ImageMotionStrategy {
DataStore destStore = destData.getDataStore();
DataStore srcStore = srcData.getDataStore();
EndPoint ep = selector.select(srcData, destData);
CopyCommandResult result = new CopyCommandResult("");
CopyCommandResult result = new CopyCommandResult("", null);
if (ep == null) {
result.setResult("can't find end point");
callback.complete(result);
@ -125,12 +125,12 @@ public class DefaultImageMotionStrategy implements ImageMotionStrategy {
AsyncCompletionCallback<CopyCommandResult> parentCall = context.getParentCallback();
Answer answer = (Answer)callback.getResult();
if (!answer.getResult()) {
CopyCommandResult result = new CopyCommandResult("");
CopyCommandResult result = new CopyCommandResult("", null);
result.setResult(answer.getDetails());
parentCall.complete(result);
} else {
CopyCmdAnswer ans = (CopyCmdAnswer)answer;
CopyCommandResult result = new CopyCommandResult(ans.getPath());
CopyCommandResult result = new CopyCommandResult(ans.getPath(), null);
parentCall.complete(result);
}
return null;

View File

@ -34,7 +34,7 @@ public class MockStorageMotionStrategy implements DataMotionStrategy {
@Override
public Void copyAsync(DataObject srcData, DataObject destData,
AsyncCompletionCallback<CopyCommandResult> callback) {
CopyCommandResult result = new CopyCommandResult("something");
CopyCommandResult result = new CopyCommandResult("something", null);
callback.complete(result);
return null;
}

View File

@ -25,39 +25,55 @@ 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.DataStoreRole;
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.VolumeDataFactory;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager;
import org.apache.cloudstack.storage.snapshot.db.SnapshotDao2;
import org.apache.cloudstack.storage.snapshot.db.SnapshotVO;
import org.springframework.stereotype.Component;
import com.cloud.storage.Snapshot;
import com.cloud.storage.SnapshotVO;
import com.cloud.storage.dao.SnapshotDao;
import com.cloud.utils.exception.CloudRuntimeException;
@Component
public class SnapshotDataFactoryImpl implements SnapshotDataFactory {
@Inject
SnapshotDao2 snapshotDao;
SnapshotDao snapshotDao;
@Inject
ObjectInDataStoreManager objMap;
@Inject
DataStoreManager storeMgr;
@Inject
VolumeDataFactory volumeFactory;
@Override
public SnapshotInfo getSnapshot(long snapshotId, DataStore store) {
SnapshotVO snapshot = snapshotDao.findById(snapshotId);
SnapshotVO snapshot = snapshotDao.findByIdIncludingRemoved(snapshotId);
DataObjectInStore obj = objMap.findObject(snapshot.getUuid(), DataObjectType.SNAPSHOT, store.getUuid(), store.getRole());
if (obj == null) {
return null;
}
SnapshotObject so = new SnapshotObject(snapshot, store);
SnapshotObject so = SnapshotObject.getSnapshotObject(snapshot, store);
return so;
}
@Override
public SnapshotInfo getSnapshot(long snapshotId) {
// TODO Auto-generated method stub
return null;
SnapshotVO snapshot = snapshotDao.findByIdIncludingRemoved(snapshotId);
SnapshotObject so = null;
if (snapshot.getState() == Snapshot.State.BackedUp) {
DataStore store = objMap.findStore(snapshot.getUuid(), DataObjectType.SNAPSHOT, 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) {
// TODO Auto-generated method stub
return null;
throw new CloudRuntimeException("not implemented yet");
}
}

View File

@ -18,21 +18,54 @@
*/
package org.apache.cloudstack.storage.snapshot;
import java.util.Date;
import javax.inject.Inject;
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.ObjectInDataStoreStateMachine.Event;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
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.snapshot.db.SnapshotVO;
import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager;
import org.apache.log4j.Logger;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.storage.Snapshot;
import com.cloud.storage.SnapshotVO;
import com.cloud.storage.dao.SnapshotDao;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.utils.component.ComponentContext;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.fsm.NoTransitionException;
public class SnapshotObject implements SnapshotInfo {
private static final Logger s_logger = Logger.getLogger(SnapshotObject.class);
private SnapshotVO snapshot;
private DataStore store;
public SnapshotObject(SnapshotVO snapshot, DataStore store) {
this.snapshot = snapshot;
this.store = store;
@Inject
protected SnapshotDao snapshotDao;
@Inject
protected VolumeDao volumeDao;
@Inject protected VolumeDataFactory volFactory;
@Inject protected SnapshotStateMachineManager stateMachineMgr;
@Inject
ObjectInDataStoreManager ojbectInStoreMgr;
protected SnapshotObject() {
}
protected void configure(SnapshotVO snapshot, DataStore store) {
this.snapshot = snapshot;
this.store = store;
}
public static SnapshotObject getSnapshotObject(SnapshotVO snapshot, DataStore store) {
SnapshotObject snapObj = ComponentContext.inject(SnapshotObject.class);
snapObj.configure(snapshot, store);
return snapObj;
}
public DataStore getStore() {
@ -53,56 +86,138 @@ public class SnapshotObject implements SnapshotInfo {
@Override
public VolumeInfo getBaseVolume() {
// TODO Auto-generated method stub
return null;
return volFactory.getVolume(this.snapshot.getVolumeId());
}
@Override
public long getId() {
// TODO Auto-generated method stub
return 0;
return this.snapshot.getId();
}
@Override
public String getUri() {
// TODO Auto-generated method stub
return null;
return this.snapshot.getUuid();
}
@Override
public DataStore getDataStore() {
// TODO Auto-generated method stub
return null;
return this.store;
}
@Override
public Long getSize() {
// TODO Auto-generated method stub
return 0L;
return this.getSize();
}
@Override
public DataObjectType getType() {
// TODO Auto-generated method stub
return null;
return DataObjectType.SNAPSHOT;
}
@Override
public DiskFormat getFormat() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getUuid() {
// TODO Auto-generated method stub
return null;
return this.snapshot.getUuid();
}
@Override
public void processEvent(Event event) {
// TODO Auto-generated method stub
}
@Override
public void processEvent(
ObjectInDataStoreStateMachine.Event event) {
try {
ojbectInStoreMgr.update(this, event);
} catch (Exception e) {
s_logger.debug("Failed to update state:" + e.toString());
throw new CloudRuntimeException("Failed to update state: " + e.toString());
}
}
@Override
public long getAccountId() {
return this.snapshot.getAccountId();
}
@Override
public long getVolumeId() {
return this.snapshot.getVolumeId();
}
@Override
public String getPath() {
return this.snapshot.getPath();
}
public void setPath(String path) {
this.snapshot.setPath(path);
}
@Override
public String getName() {
return this.snapshot.getName();
}
@Override
public Date getCreated() {
return this.snapshot.getCreated();
}
@Override
public Type getRecurringType() {
return this.snapshot.getRecurringType();
}
@Override
public State getState() {
return this.snapshot.getState();
}
@Override
public HypervisorType getHypervisorType() {
return this.snapshot.getHypervisorType();
}
@Override
public boolean isRecursive() {
return this.snapshot.isRecursive();
}
@Override
public short getsnapshotType() {
return this.snapshot.getsnapshotType();
}
@Override
public long getDomainId() {
return this.snapshot.getDomainId();
}
public void setPrevSnapshotId(Long id) {
this.snapshot.setPrevSnapshotId(id);
}
@Override
public Long getDataCenterId() {
return this.snapshot.getDataCenterId();
}
public void processEvent(Snapshot.Event event)
throws NoTransitionException {
stateMachineMgr.processEvent(this.snapshot, event);
}
@Override
public Long getPrevSnapshotId() {
return this.snapshot.getPrevSnapshotId();
}
public void setBackupSnapshotId(String id) {
this.snapshot.setBackupSnapshotId(id);
}
public String getBackupSnapshotId() {
return this.snapshot.getBackupSnapshotId();
}
}

View File

@ -22,6 +22,10 @@ import org.springframework.stereotype.Component;
@Component
public class SnapshotServiceImpl implements SnapshotService {
public SnapshotServiceImpl() {
}
@Override
public SnapshotEntity getSnapshotEntity(long snapshotId) {
@ -46,5 +50,7 @@ public class SnapshotServiceImpl implements SnapshotService {
// TODO Auto-generated method stub
return false;
}
}

View File

@ -0,0 +1,9 @@
package org.apache.cloudstack.storage.snapshot;
import com.cloud.storage.Snapshot.Event;
import com.cloud.storage.SnapshotVO;
import com.cloud.utils.fsm.NoTransitionException;
public interface SnapshotStateMachineManager {
public void processEvent(SnapshotVO snapshot, Event event) throws NoTransitionException;
}

View File

@ -0,0 +1,37 @@
package org.apache.cloudstack.storage.snapshot;
import javax.inject.Inject;
import org.springframework.stereotype.Component;
import com.cloud.storage.Snapshot;
import com.cloud.storage.Snapshot.Event;
import com.cloud.storage.Snapshot.State;
import com.cloud.storage.SnapshotVO;
import com.cloud.storage.dao.SnapshotDao;
import com.cloud.storage.listener.SnapshotStateListener;
import com.cloud.utils.fsm.NoTransitionException;
import com.cloud.utils.fsm.StateMachine2;
@Component
public class SnapshotStateMachineManagerImpl implements
SnapshotStateMachineManager {
private StateMachine2<State, Event, SnapshotVO> stateMachine = new StateMachine2<State, Event, SnapshotVO>();
@Inject
protected SnapshotDao snapshotDao;
public SnapshotStateMachineManagerImpl() {
stateMachine.addTransition(null, Event.CreateRequested, Snapshot.State.Creating);
stateMachine.addTransition(Snapshot.State.Creating, Event.OperationSucceeded, Snapshot.State.CreatedOnPrimary);
stateMachine.addTransition(Snapshot.State.Creating, Event.OperationNotPerformed, Snapshot.State.BackedUp);
stateMachine.addTransition(Snapshot.State.Creating, Event.OperationFailed, Snapshot.State.Error);
stateMachine.addTransition(Snapshot.State.CreatedOnPrimary, Event.BackupToSecondary, Snapshot.State.BackingUp);
stateMachine.addTransition(Snapshot.State.BackingUp, Event.OperationSucceeded, Snapshot.State.BackedUp);
stateMachine.addTransition(Snapshot.State.BackingUp, Event.OperationFailed, Snapshot.State.Error);
stateMachine.registerListener(new SnapshotStateListener());
}
public void processEvent(SnapshotVO snapshot, Event event) throws NoTransitionException {
stateMachine.transitTo(snapshot, event, null, snapshotDao);
}
}

View File

@ -0,0 +1,562 @@
package org.apache.cloudstack.storage.snapshot.strategy;
import java.util.List;
import java.util.concurrent.ExecutionException;
import javax.inject.Inject;
import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult;
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.DataObject;
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.DataStoreRole;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event;
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
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.SnapshotStrategy;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
import org.apache.cloudstack.framework.async.AsyncCallFuture;
import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher;
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
import org.apache.cloudstack.framework.async.AsyncRpcConext;
import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager;
import org.apache.cloudstack.storage.motion.DataMotionService;
import org.apache.cloudstack.storage.snapshot.SnapshotObject;
import org.apache.cloudstack.storage.snapshot.SnapshotStateMachineManager;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.BackupSnapshotAnswer;
import com.cloud.agent.api.DeleteSnapshotBackupCommand;
import com.cloud.agent.api.to.S3TO;
import com.cloud.agent.api.to.SwiftTO;
import com.cloud.configuration.Resource.ResourceType;
import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.dc.ClusterVO;
import com.cloud.dc.dao.ClusterDao;
import com.cloud.event.EventTypes;
import com.cloud.event.UsageEventUtils;
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.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.StoragePoolDao;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.storage.s3.S3Manager;
import com.cloud.storage.snapshot.SnapshotManager;
import com.cloud.storage.swift.SwiftManager;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.db.DB;
import com.cloud.utils.db.Transaction;
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;
@Component
public class AncientSnasphotStrategy implements SnapshotStrategy {
private static final Logger s_logger = Logger.getLogger(AncientSnasphotStrategy.class);
@Inject
protected VolumeDao _volsDao;
@Inject
protected UserVmDao _vmDao;
@Inject
protected StoragePoolDao _storagePoolDao;
@Inject
protected ClusterDao _clusterDao;
@Inject
protected SnapshotDao snapshotDao;
@Inject
private ResourceManager _resourceMgr;
@Inject
protected SnapshotDao _snapshotDao;
@Inject
protected SnapshotManager snapshotMgr;
@Inject
protected VolumeManager volumeMgr;
@Inject
private ConfigurationDao _configDao;
@Inject
protected SnapshotStateMachineManager stateMachineManager;
@Inject
private VolumeDao volumeDao;
@Inject
SnapshotDataFactory snapshotfactory;
@Inject
DataStoreManager dataStoreMgr;
@Inject
DataMotionService motionSrv;
@Inject
ObjectInDataStoreManager objInStoreMgr;
@Override
public boolean canHandle(SnapshotInfo snapshot) {
return true;
}
static private class CreateSnapshotContext<T> extends AsyncRpcConext<T> {
final VolumeInfo volume;
final SnapshotInfo snapshot;
final AsyncCallFuture<SnapshotResult> future;
public CreateSnapshotContext(AsyncCompletionCallback<T> callback, VolumeInfo volume,
SnapshotInfo snapshot,
AsyncCallFuture<SnapshotResult> future) {
super(callback);
this.volume = volume;
this.snapshot = snapshot;
this.future = future;
}
}
static private class DeleteSnapshotContext<T> extends AsyncRpcConext<T> {
final SnapshotInfo snapshot;
final AsyncCallFuture<SnapshotResult> future;
public DeleteSnapshotContext(AsyncCompletionCallback<T> callback, SnapshotInfo snapshot,
AsyncCallFuture<SnapshotResult> future) {
super(callback);
this.snapshot = snapshot;
this.future = future;
}
}
static private class CopySnapshotContext<T> extends AsyncRpcConext<T> {
final SnapshotInfo srcSnapshot;
final SnapshotInfo destSnapshot;
final AsyncCallFuture<SnapshotResult> future;
public CopySnapshotContext(AsyncCompletionCallback<T> callback,
SnapshotInfo srcSnapshot,
SnapshotInfo destSnapshot,
AsyncCallFuture<SnapshotResult> future) {
super(callback);
this.srcSnapshot = srcSnapshot;
this.destSnapshot = destSnapshot;
this.future = future;
}
}
protected Void createSnapshotAsyncCallback(AsyncCallbackDispatcher<AncientSnasphotStrategy, CreateCmdResult> callback,
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);
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());
}
snapResult.setResult(result.getResult());
future.complete(snapResult);
return null;
}
try {
SnapshotVO preSnapshotVO = this.snapshotMgr.getParentSnapshot(volume, snapshot);
String 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.setSwiftId(preSnapshotVO.getSwiftId());
snapshotVO.setPrevSnapshotId(preSnapshotVO.getId());
snapshotVO.setSecHostId(preSnapshotVO.getSecHostId());
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()));
}
} catch (Exception e) {
s_logger.debug("Failed to create snapshot: ", e);
snapResult.setResult(e.toString());
}
future.complete(snapResult);
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);
}
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());
}
AsyncCallFuture<SnapshotResult> future = new AsyncCallFuture<SnapshotResult>();
CreateSnapshotContext<CommandResult> context = new CreateSnapshotContext<CommandResult>(
null, volume, snapshot, future);
AsyncCallbackDispatcher<AncientSnasphotStrategy, CreateCmdResult> caller = AsyncCallbackDispatcher
.create(this);
caller.setCallback(
caller.getTarget().createSnapshotAsyncCallback(null, null))
.setContext(context);
PrimaryDataStoreDriver primaryStore = (PrimaryDataStoreDriver)volume.getDataStore().getDriver();
primaryStore.takeSnapshot(snapshot, caller);
SnapshotResult result;
try {
result = future.get();
if (result.isFailed()) {
s_logger.debug("Failed to create snapshot:" + result.getResult());
throw new CloudRuntimeException(result.getResult());
}
return result.snashot;
} catch (InterruptedException e) {
s_logger.debug("Failed to create snapshot", e);
throw new CloudRuntimeException("Failed to create snapshot", e);
} catch (ExecutionException e) {
s_logger.debug("Failed to create snapshot", e);
throw new CloudRuntimeException("Failed to create snapshot", e);
}
}
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);
try {
snapObj.processEvent(Snapshot.Event.BackupToSecondary);
ZoneScope scope = new ZoneScope(snapshot.getDataCenterId());
List<DataStore> stores = this.dataStoreMgr.getImageStores(scope);
if (stores.size() != 1) {
throw new CloudRuntimeException("find out more than one image stores");
}
DataStore imageStore = stores.get(0);
SnapshotInfo snapshotOnImageStore = (SnapshotInfo)imageStore.create(snapshot);
snapshotOnImageStore.processEvent(Event.CreateOnlyRequested);
CopySnapshotContext<CommandResult> context = new CopySnapshotContext<CommandResult>(null, snapshot,
snapshotOnImageStore, future);
AsyncCallbackDispatcher<AncientSnasphotStrategy, CopyCommandResult> caller = AsyncCallbackDispatcher
.create(this);
caller.setCallback(
caller.getTarget().copySnapshotAsyncCallback(null, null))
.setContext(context);
this.motionSrv.copyAsync(snapshot, snapshotOnImageStore, caller);
} catch (Exception e) {
s_logger.debug("Failed to copy snapshot", e);
result.setResult("Failed to copy snapshot:" +e.toString());
future.complete(result);
}
try {
SnapshotResult res = future.get();
SnapshotInfo destSnapshot = res.snashot;
return destSnapshot;
} catch (InterruptedException e) {
s_logger.debug("failed copy snapshot", e);
throw new CloudRuntimeException("Failed to copy snapshot" , e);
} catch (ExecutionException e) {
s_logger.debug("Failed to copy snapshot", e);
throw new CloudRuntimeException("Failed to copy snapshot" , e);
}
}
protected Void copySnapshotAsyncCallback(AsyncCallbackDispatcher<AncientSnasphotStrategy, CopyCommandResult> callback,
CopySnapshotContext<CommandResult> context) {
CopyCommandResult result = callback.getResult();
SnapshotInfo destSnapshot = context.destSnapshot;
SnapshotObject srcSnapshot = (SnapshotObject)context.srcSnapshot;
AsyncCallFuture<SnapshotResult> future = context.future;
SnapshotResult snapResult = new SnapshotResult(destSnapshot);
if (result.isFailed()) {
snapResult.setResult(result.getResult());
future.complete(snapResult);
return null;
}
try {
BackupSnapshotAnswer answer = (BackupSnapshotAnswer)result.getAnswer();
DataObjectInStore dataInStore = objInStoreMgr.findObject(destSnapshot, destSnapshot.getDataStore());
dataInStore.setInstallPath(answer.getBackupSnapshotName());
objInStoreMgr.update(destSnapshot, Event.OperationSuccessed);
srcSnapshot.processEvent(Snapshot.Event.OperationSucceeded);
snapResult = new SnapshotResult(this.snapshotfactory.getSnapshot(destSnapshot.getId()));
future.complete(snapResult);
} catch (Exception e) {
s_logger.debug("Failed to update snapshot state", e);
snapResult.setResult(e.toString());
future.complete(snapResult);
}
return null;
}
@DB
protected boolean destroySnapshotBackUp(SnapshotVO snapshot) {
DataStore store = objInStoreMgr.findStore(snapshot.getUuid(), DataObjectType.SNAPSHOT, DataStoreRole.Image);
if (store == null) {
s_logger.debug("Can't find snapshot" + snapshot.getId() + " backed up into image store");
return false;
}
try {
SnapshotInfo snapshotInfo = this.snapshotfactory.getSnapshot(snapshot.getId(), store);
snapshotInfo.processEvent(ObjectInDataStoreStateMachine.Event.DestroyRequested);
AsyncCallFuture<SnapshotResult> future = new AsyncCallFuture<SnapshotResult>();
DeleteSnapshotContext<CommandResult> context = new DeleteSnapshotContext<CommandResult>(null,
snapshotInfo, future);
AsyncCallbackDispatcher<AncientSnasphotStrategy, CommandResult> caller = AsyncCallbackDispatcher
.create(this);
caller.setCallback(
caller.getTarget().deleteSnapshotCallback(null, null))
.setContext(context);
store.getDriver().deleteAsync(snapshotInfo, caller);
SnapshotResult result = future.get();
if (result.isFailed()) {
s_logger.debug("Failed to delete snapsoht: " + result.getResult());
}
return result.isSuccess();
} catch (Exception e) {
s_logger.debug("Failed to delete snapshot", e);
return false;
}
}
protected Void deleteSnapshotCallback(AsyncCallbackDispatcher<AncientSnasphotStrategy, CommandResult> callback,
DeleteSnapshotContext<CommandResult> context) {
CommandResult result = callback.getResult();
AsyncCallFuture<SnapshotResult> future = context.future;
SnapshotInfo snapshot = context.snapshot;
if (result.isFailed()) {
s_logger.debug("delete snapshot failed" + result.getResult());
snapshot.processEvent(ObjectInDataStoreStateMachine.Event.OperationFailed);
SnapshotResult res = new SnapshotResult(context.snapshot);
future.complete(res);
return null;
}
snapshot.processEvent(ObjectInDataStoreStateMachine.Event.OperationSuccessed);
SnapshotResult res = new SnapshotResult(context.snapshot);
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;
}
@Override
public boolean revertSnapshot(SnapshotInfo snapshot) {
// TODO Auto-generated method stub
return false;
}
}

View File

@ -1,44 +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.strategy;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
import org.apache.cloudstack.storage.snapshot.SnapshotStrategy;
import org.springframework.stereotype.Component;
@Component
public class HypervisorBasedSnapshot implements SnapshotStrategy {
@Override
public boolean takeSnapshot(SnapshotInfo snapshot) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean revertSnapshot(SnapshotInfo snapshot) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean deleteSnapshot(SnapshotInfo snapshot) {
// TODO Auto-generated method stub
return false;
}
}

View File

@ -1,42 +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.strategy;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
import org.apache.cloudstack.storage.snapshot.SnapshotStrategy;
public class StorageBasedSnapshot implements SnapshotStrategy {
@Override
public boolean takeSnapshot(SnapshotInfo snapshot) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean revertSnapshot(SnapshotInfo snapshot) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean deleteSnapshot(SnapshotInfo snapshot) {
// TODO Auto-generated method stub
return false;
}
}

View File

@ -19,7 +19,7 @@
package org.apache.cloudstack.storage.datastore;
import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener;
import org.apache.cloudstack.storage.volume.PrimaryDataStoreDriver;
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
public interface PrimaryDataStoreProviderManager {

View File

@ -28,6 +28,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole;
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.datastore.db.PrimaryDataStoreDao;
@ -36,6 +37,8 @@ import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.BackupSnapshotAnswer;
import com.cloud.agent.api.BackupSnapshotCommand;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand;
import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand;
@ -47,7 +50,9 @@ import com.cloud.agent.api.storage.CopyVolumeCommand;
import com.cloud.agent.api.storage.CreateAnswer;
import com.cloud.agent.api.storage.CreateCommand;
import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer;
import com.cloud.agent.api.to.S3TO;
import com.cloud.agent.api.to.StorageFilerTO;
import com.cloud.agent.api.to.SwiftTO;
import com.cloud.configuration.Config;
import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.exception.StorageUnavailableException;
@ -72,7 +77,9 @@ import com.cloud.storage.dao.VMTemplateHostDao;
import com.cloud.storage.dao.VMTemplatePoolDao;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.storage.dao.VolumeHostDao;
import com.cloud.storage.s3.S3Manager;
import com.cloud.storage.snapshot.SnapshotManager;
import com.cloud.storage.swift.SwiftManager;
import com.cloud.template.TemplateManager;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.db.DB;
@ -112,6 +119,10 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
@Inject VMTemplatePoolDao templatePoolDao;
@Inject
VolumeManager volumeMgr;
@Inject
private SwiftManager _swiftMgr;
@Inject
private S3Manager _s3Mgr;
@Override
public boolean canHandle(DataObject srcData, DataObject destData) {
@ -120,7 +131,7 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
}
@DB
protected String copyVolumeFromImage(DataObject srcData, DataObject destData) {
protected Answer copyVolumeFromImage(DataObject srcData, DataObject destData) {
String value = configDao.getValue(Config.RecreateSystemVmEnabled.key());
int _copyvolumewait = NumbersUtil.parseInt(value,
Integer.parseInt(Config.CopyVolumeWait.getDefaultValue()));
@ -162,16 +173,17 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
this.volDao.update(vol.getId(), vol);
volumeHostDao.remove(volumeHostVO.getId());
txn.commit();
return errMsg;
return cvAnswer;
}
private void copyTemplate(DataObject srcData, DataObject destData) {
private Answer copyTemplate(DataObject srcData, DataObject destData) {
VMTemplateVO template = this.templateDao.findById(srcData.getId());
templateMgr.prepareTemplateForCreate(template,
(StoragePool) destData.getDataStore());
return null;
}
protected String copyFromSnapshot(DataObject snapObj, DataObject volObj) {
protected Answer copyFromSnapshot(DataObject snapObj, DataObject volObj) {
SnapshotVO snapshot = this.snapshotDao.findById(snapObj.getId());
StoragePool pool = (StoragePool) volObj.getDataStore();
String vdiUUID = null;
@ -227,8 +239,8 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
if ((answer != null) && answer.getResult()) {
snapshotDao.updateSnapshotVersion(volumeId, "2.1", "2.2");
} else {
return "Unable to upgrade snapshot from 2.1 to 2.2 for "
+ snapshot.getId();
throw new CloudRuntimeException("Unable to upgrade snapshot from 2.1 to 2.2 for "
+ snapshot.getId());
}
}
}
@ -277,11 +289,10 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
snapshotMgr.deleteSnapshotsDirForVolume(
secondaryStoragePoolUrl, dcId, accountId, volumeId);
}
snapshotDao.unlockFromLockTable(snapshotId.toString());
}
}
protected String cloneVolume(DataObject template, DataObject volume) {
protected Answer cloneVolume(DataObject template, DataObject volume) {
VolumeInfo volInfo = (VolumeInfo)volume;
DiskOfferingVO offering = diskOfferingDao.findById(volInfo.getDiskOfferingId());
VMTemplateStoragePoolVO tmpltStoredOn = templatePoolDao.findByPoolTemplate(template.getDataStore().getId(), template.getId());
@ -298,8 +309,7 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
answer = storagMgr.sendToPool(pool, null, cmd);
} catch (StorageUnavailableException e) {
s_logger.debug("Failed to send to storage pool", e);
errMsg = e.toString();
return errMsg;
throw new CloudRuntimeException("Failed to send to storage pool", e);
}
if (answer.getResult()) {
@ -327,10 +337,10 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
errMsg = answer.getDetails();
}
return errMsg;
return answer;
}
protected String copyVolumeBetweenPools(DataObject srcData, DataObject destData) {
protected Answer copyVolumeBetweenPools(DataObject srcData, DataObject destData) {
VolumeInfo volume = (VolumeInfo)srcData;
VolumeInfo destVolume = (VolumeInfo)destData;
String secondaryStorageURL = this.templateMgr.getSecondaryStorageURL(volume
@ -380,41 +390,45 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
VolumeVO destVol = this.volDao.findById(destVolume.getId());
destVol.setPath(cvAnswer.getVolumePath());
this.volDao.update(destVol.getId(), destVol);
return null;
return cvAnswer;
}
@Override
public Void copyAsync(DataObject srcData, DataObject destData,
AsyncCompletionCallback<CopyCommandResult> callback) {
Answer answer = null;
String errMsg = null;
try {
if (destData.getType() == DataObjectType.VOLUME
&& srcData.getType() == DataObjectType.VOLUME && srcData.getDataStore().getRole() == DataStoreRole.Image) {
errMsg = copyVolumeFromImage(srcData, destData);
answer = copyVolumeFromImage(srcData, destData);
} else if (destData.getType() == DataObjectType.TEMPLATE
&& srcData.getType() == DataObjectType.TEMPLATE) {
copyTemplate(srcData, destData);
answer = copyTemplate(srcData, destData);
} else if (srcData.getType() == DataObjectType.SNAPSHOT
&& destData.getType() == DataObjectType.VOLUME) {
errMsg = copyFromSnapshot(srcData, destData);
answer = copyFromSnapshot(srcData, destData);
} else if (srcData.getType() == DataObjectType.SNAPSHOT
&& destData.getType() == DataObjectType.TEMPLATE) {
errMsg = createTemplateFromSnashot(srcData, destData);
answer = createTemplateFromSnashot(srcData, destData);
} else if (srcData.getType() == DataObjectType.VOLUME
&& destData.getType() == DataObjectType.TEMPLATE) {
errMsg = createTemplateFromVolume(srcData, destData);
answer = createTemplateFromVolume(srcData, destData);
} else if (srcData.getType() == DataObjectType.TEMPLATE
&& destData.getType() == DataObjectType.VOLUME) {
errMsg = cloneVolume(srcData, destData);
answer = cloneVolume(srcData, destData);
} else if (destData.getType() == DataObjectType.VOLUME
&& srcData.getType() == DataObjectType.VOLUME && srcData.getDataStore().getRole() == DataStoreRole.Primary) {
errMsg = copyVolumeBetweenPools(srcData, destData);
answer = copyVolumeBetweenPools(srcData, destData);
} else if (srcData.getType() == DataObjectType.SNAPSHOT &&
destData.getType() == DataObjectType.SNAPSHOT) {
answer = copySnapshot(srcData, destData);
}
} catch (Exception e) {
s_logger.debug("copy failed", e);
errMsg = e.toString();
}
CopyCommandResult result = new CopyCommandResult(null);
CopyCommandResult result = new CopyCommandResult(null, answer);
result.setResult(errMsg);
callback.complete(result);
@ -422,7 +436,7 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
}
@DB
protected String createTemplateFromSnashot(DataObject srcData,
protected Answer createTemplateFromSnashot(DataObject srcData,
DataObject destData) {
long snapshotId = srcData.getId();
SnapshotVO snapshot = snapshotDao.findById(snapshotId);
@ -538,7 +552,7 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
}
@DB
protected String sendCommand(Command cmd, StoragePool pool,
protected Answer sendCommand(Command cmd, StoragePool pool,
long templateId, long zoneId, long hostId) {
CreatePrivateTemplateAnswer answer = null;
@ -551,11 +565,8 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
e);
}
if (answer == null) {
return "Failed to execute CreatePrivateTemplateFromSnapshotCommand";
} else if (!answer.getResult()) {
return "Failed to execute CreatePrivateTemplateFromSnapshotCommand"
+ answer.getDetails();
if (answer == null || !answer.getResult()) {
return answer;
}
VMTemplateVO privateTemplate = templateDao.findById(templateId);
@ -594,10 +605,10 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
templateHostVO.setPhysicalSize(answer.getphysicalSize());
templateHostDao.persist(templateHostVO);
txn.close();
return null;
return answer;
}
private String createTemplateFromVolume(DataObject srcObj,
private Answer createTemplateFromVolume(DataObject srcObj,
DataObject destObj) {
long volumeId = srcObj.getId();
VolumeVO volume = this.volDao.findById(volumeId);
@ -633,5 +644,82 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
return sendCommand(cmd, pool, template.getId(), zoneId,
secondaryStorageHost.getId());
}
private HostVO getSecHost(long volumeId, long dcId) {
Long id = snapshotDao.getSecHostId(volumeId);
if ( id != null) {
return hostDao.findById(id);
}
return this.templateMgr.getSecondaryStorageHost(dcId);
}
protected Answer copySnapshot(DataObject srcObject, DataObject destObject) {
SnapshotInfo srcSnapshot = (SnapshotInfo)srcObject;
VolumeInfo baseVolume = srcSnapshot.getBaseVolume();
Long dcId = baseVolume.getDataCenterId();
Long accountId = baseVolume.getAccountId();
HostVO secHost = getSecHost(baseVolume.getId(), baseVolume.getDataCenterId());
String secondaryStoragePoolUrl = secHost.getStorageUrl();
String snapshotUuid = srcSnapshot.getPath();
// In order to verify that the snapshot is not empty,
// we check if the parent of the snapshot is not the same as the parent of the previous snapshot.
// We pass the uuid of the previous snapshot to the plugin to verify this.
SnapshotVO prevSnapshot = null;
String prevSnapshotUuid = null;
String prevBackupUuid = null;
SwiftTO swift = _swiftMgr.getSwiftTO();
S3TO s3 = _s3Mgr.getS3TO();
long prevSnapshotId = srcSnapshot.getPrevSnapshotId();
if (prevSnapshotId > 0) {
prevSnapshot = snapshotDao.findByIdIncludingRemoved(prevSnapshotId);
if ( prevSnapshot.getBackupSnapshotId() != null && swift == null) {
if (prevSnapshot.getVersion() != null && prevSnapshot.getVersion().equals("2.2")) {
prevBackupUuid = prevSnapshot.getBackupSnapshotId();
prevSnapshotUuid = prevSnapshot.getPath();
}
} else if ((prevSnapshot.getSwiftId() != null && swift != null)
|| (prevSnapshot.getS3Id() != null && s3 != null)) {
prevBackupUuid = prevSnapshot.getBackupSnapshotId();
prevSnapshotUuid = prevSnapshot.getPath();
}
}
boolean isVolumeInactive = this.volumeMgr.volumeInactive(baseVolume);
String vmName = this.volumeMgr.getVmNameOnVolume(baseVolume);
StoragePool srcPool = (StoragePool)dataStoreMgr.getPrimaryDataStore(baseVolume.getPoolId());
String value = configDao.getValue(Config.BackupSnapshotWait.toString());
int _backupsnapshotwait = NumbersUtil.parseInt(value, Integer.parseInt(Config.BackupSnapshotWait.getDefaultValue()));
BackupSnapshotCommand backupSnapshotCommand = new BackupSnapshotCommand(secondaryStoragePoolUrl, dcId, accountId, baseVolume.getId(), srcSnapshot.getId(), baseVolume.getPath(), srcPool, snapshotUuid,
srcSnapshot.getName(), prevSnapshotUuid, prevBackupUuid, isVolumeInactive, vmName, _backupsnapshotwait);
if ( swift != null ) {
backupSnapshotCommand.setSwift(swift);
} else if (s3 != null) {
backupSnapshotCommand.setS3(s3);
}
BackupSnapshotAnswer answer = (BackupSnapshotAnswer) this.snapshotMgr.sendToPool(baseVolume, backupSnapshotCommand);
if (answer != null && answer.getResult()) {
SnapshotVO snapshotVO = this.snapshotDao.findById(srcSnapshot.getId());
if (backupSnapshotCommand.getSwift() != null ) {
snapshotVO.setSwiftId(swift.getId());
snapshotVO.setBackupSnapshotId(answer.getBackupSnapshotName());
} else if (backupSnapshotCommand.getS3() != null) {
snapshotVO.setS3Id(s3.getId());
snapshotVO.setBackupSnapshotId(answer.getBackupSnapshotName());
} else {
snapshotVO.setSecHostId(secHost.getId());
snapshotVO.setBackupSnapshotId(answer.getBackupSnapshotName());
}
if (answer.isFull()) {
snapshotVO.setPrevSnapshotId(0L);
}
this.snapshotDao.update(srcSnapshot.getId(), snapshotVO);
}
return answer;
}
}

View File

@ -105,13 +105,6 @@ public class SnapshotEntityImpl implements SnapshotEntity {
return null;
}
@Override
public Type getType() {
// TODO Auto-generated method stub
return null;
}
@Override
public HypervisorType getHypervisorType() {
// TODO Auto-generated method stub
@ -190,4 +183,10 @@ public class SnapshotEntityImpl implements SnapshotEntity {
return null;
}
@Override
public Type getRecurringType() {
// TODO Auto-generated method stub
return null;
}
}

View File

@ -1,25 +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.subsystem.api.storage.SnapshotInfo;
public interface SnapshotStrategy {
public boolean takeSnapshot(SnapshotInfo snapshot);
public boolean revertSnapshot(SnapshotInfo snapshot);
public boolean deleteSnapshot(SnapshotInfo snapshot);
}

View File

@ -31,6 +31,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole;
import org.apache.cloudstack.engine.subsystem.api.storage.ImageDataFactory;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreLifeCycle;
import org.apache.cloudstack.engine.subsystem.api.storage.Scope;
import org.apache.cloudstack.engine.subsystem.api.storage.ScopeType;
@ -42,7 +43,6 @@ import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
import org.apache.cloudstack.engine.subsystem.api.storage.disktype.DiskFormat;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.storage.volume.PrimaryDataStoreDriver;
import org.apache.cloudstack.storage.volume.VolumeObject;
import org.apache.log4j.Logger;

View File

@ -29,261 +29,325 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
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.EndPoint;
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.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.volume.PrimaryDataStoreDriver;
import org.apache.cloudstack.storage.volume.VolumeObject;
import org.apache.log4j.Logger;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.ManageSnapshotAnswer;
import com.cloud.agent.api.ManageSnapshotCommand;
import com.cloud.agent.api.storage.CreateAnswer;
import com.cloud.agent.api.storage.CreateCommand;
import com.cloud.agent.api.storage.DestroyCommand;
import com.cloud.agent.api.storage.ResizeVolumeAnswer;
import com.cloud.agent.api.storage.ResizeVolumeCommand;
import com.cloud.agent.api.to.StorageFilerTO;
import com.cloud.exception.StorageUnavailableException;
import com.cloud.host.HostVO;
import com.cloud.host.dao.HostDao;
import com.cloud.storage.DiskOfferingVO;
import com.cloud.storage.ResizeVolumePayload;
import com.cloud.storage.Storage;
import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.storage.SnapshotVO;
import com.cloud.storage.StorageManager;
import com.cloud.storage.StoragePool;
import com.cloud.storage.VMTemplateHostVO;
import com.cloud.storage.VMTemplateStoragePoolVO;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.VolumeManager;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.DiskOfferingDao;
import com.cloud.storage.dao.SnapshotDao;
import com.cloud.storage.dao.VMTemplateDao;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.storage.snapshot.SnapshotManager;
import com.cloud.template.TemplateManager;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.vm.DiskProfile;
import com.cloud.vm.dao.VMInstanceDao;
public class AncientPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver {
private static final Logger s_logger = Logger
.getLogger(AncientPrimaryDataStoreDriverImpl.class);
@Inject DiskOfferingDao diskOfferingDao;
@Inject VMTemplateDao templateDao;
@Inject VolumeDao volumeDao;
@Inject TemplateManager templateMgr;
@Inject HostDao hostDao;
@Inject StorageManager storageMgr;
@Inject VMInstanceDao vmDao;
@Inject PrimaryDataStoreDao primaryStoreDao;
@Override
public String grantAccess(DataObject data, EndPoint ep) {
// TODO Auto-generated method stub
return null;
}
private static final Logger s_logger = Logger
.getLogger(AncientPrimaryDataStoreDriverImpl.class);
@Inject DiskOfferingDao diskOfferingDao;
@Inject VMTemplateDao templateDao;
@Inject VolumeDao volumeDao;
@Inject TemplateManager templateMgr;
@Inject HostDao hostDao;
@Inject StorageManager storageMgr;
@Inject VolumeManager volumeMgr;
@Inject VMInstanceDao vmDao;
@Inject SnapshotDao snapshotDao;
@Inject PrimaryDataStoreDao primaryStoreDao;
@Inject SnapshotManager snapshotMgr;
@Override
public String grantAccess(DataObject data, EndPoint ep) {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean revokeAccess(DataObject data, EndPoint ep) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean revokeAccess(DataObject data, EndPoint ep) {
// TODO Auto-generated method stub
return false;
}
@Override
public Set<DataObject> listObjects(DataStore store) {
// TODO Auto-generated method stub
return null;
}
@Override
public Set<DataObject> listObjects(DataStore store) {
// TODO Auto-generated method stub
return null;
}
public boolean createVolume(
VolumeInfo volume) throws StorageUnavailableException {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Creating volume: " + volume);
}
public boolean 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);
VMTemplateVO template = null;
if (volume.getTemplateId() != null) {
template = templateDao.findById(volume.getTemplateId());
}
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 = null;
VMTemplateStoragePoolVO tmpltStoredOn = null;
for (int i = 0; i < 2; i++) {
if (template != null
&& template.getFormat() != Storage.ImageFormat.ISO) {
if (pool.getPoolType() == StoragePoolType.CLVM) {
// prepareISOForCreate does what we need, which is to
// tell us where the template is
VMTemplateHostVO tmpltHostOn = templateMgr
.prepareISOForCreate(template, pool);
if (tmpltHostOn == null) {
s_logger.debug("cannot find template "
+ template.getId() + " "
+ template.getName());
throw new CloudRuntimeException("cannot find template"
+ template.getId()
+ template.getName());
}
HostVO secondaryStorageHost = hostDao
.findById(tmpltHostOn.getHostId());
String tmpltHostUrl = secondaryStorageHost
.getStorageUrl();
String fullTmpltUrl = tmpltHostUrl + "/"
+ tmpltHostOn.getInstallPath();
cmd = new CreateCommand(diskProfile, fullTmpltUrl,
new StorageFilerTO(pool));
} else {
tmpltStoredOn = templateMgr.prepareTemplateForCreate(
template, pool);
if (tmpltStoredOn == null) {
s_logger.debug("Cannot use this pool " + pool
+ " because we can't propagate template "
+ template);
throw new CloudRuntimeException("Cannot use this pool " + pool
+ " because we can't propagate template "
+ template);
}
cmd = new CreateCommand(diskProfile,
tmpltStoredOn.getLocalDownloadPath(),
new StorageFilerTO(pool));
}
} else {
if (template != null
&& Storage.ImageFormat.ISO == template.getFormat()) {
VMTemplateHostVO tmpltHostOn = templateMgr
.prepareISOForCreate(template, pool);
if (tmpltHostOn == null) {
throw new CloudRuntimeException(
"Did not find ISO in secondry storage in zone "
+ pool.getDataCenterId());
}
}
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;
} else {
if (tmpltStoredOn != null
&& (answer instanceof CreateAnswer)
&& ((CreateAnswer) answer)
.templateReloadRequested()) {
if (!templateMgr
.resetTemplateDownloadStateOnPool(tmpltStoredOn
.getId())) {
break; // break out of template-redeploy retry loop
}
} else {
break;
}
}
}
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("Unable to create volume " + volume.getId());
}
return false;
}
@Override
public void createAsync(DataObject data,
AsyncCompletionCallback<CreateCmdResult> callback) {
// TODO Auto-generated method stub
String errMsg = null;
if (data.getType() == DataObjectType.VOLUME) {
try {
createVolume((VolumeInfo)data);
} catch (StorageUnavailableException e) {
s_logger.debug("failed to create volume", e);
errMsg = e.toString();
} catch (Exception e) {
s_logger.debug("failed to create volume", e);
errMsg = e.toString();
}
}
CreateCmdResult result = new CreateCmdResult(null, null);
if (errMsg != null) {
result.setResult(errMsg);
}
callback.complete(result);
}
@Override
public void deleteAsync(DataObject data,
AsyncCompletionCallback<CommandResult> callback) {
String vmName = null;
VolumeVO vol = this.volumeDao.findById(data.getId());
StoragePool pool = (StoragePool)data.getDataStore();
DestroyCommand cmd = new DestroyCommand(pool, vol, vmName);
CommandResult result = new CommandResult();
try {
Answer answer = this.storageMgr.sendToPool(pool, cmd);
if (answer != null && !answer.getResult()) {
result.setResult(answer.getDetails());
s_logger.info("Will retry delete of " + vol + " from " + pool.getId());
}
} catch (StorageUnavailableException e) {
s_logger.error("Storage is unavailable currently. Will retry delete of "
+ vol + " from " + pool.getId(), e);
result.setResult(e.toString());
} catch (Exception ex) {
s_logger.debug("Unable to destoy volume" + vol + " from " + pool.getId(), ex);
result.setResult(ex.toString());
}
callback.complete(result);
}
@Override
public void copyAsync(DataObject srcdata, DataObject destData,
AsyncCompletionCallback<CopyCommandResult> callback) {
// TODO Auto-generated method stub
}
@Override
public boolean canCopy(DataObject srcData, DataObject destData) {
// TODO Auto-generated method stub
return false;
}
@Override
public void takeSnapshot(SnapshotInfo snapshot,
AsyncCompletionCallback<CreateCmdResult> callback) {
VolumeInfo volume = snapshot.getBaseVolume();
String vmName = this.volumeMgr.getVmNameOnVolume(volume);
SnapshotVO preSnapshotVO = this.snapshotMgr.getParentSnapshot(volume, snapshot);
StoragePool srcPool = (StoragePool)volume.getDataStore();
ManageSnapshotCommand cmd = new ManageSnapshotCommand(snapshot.getId(), volume.getPath(), srcPool, preSnapshotVO.getPath(), snapshot.getName(), vmName);
ManageSnapshotAnswer answer = (ManageSnapshotAnswer) this.snapshotMgr.sendToPool(volume, cmd);
DiskOfferingVO offering = diskOfferingDao.findById(volume.getDiskOfferingId());
DiskProfile diskProfile = new DiskProfile(volume, offering,
null);
VMTemplateVO template = null;
if (volume.getTemplateId() != null) {
template = templateDao.findById(volume.getTemplateId());
}
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 = null;
VMTemplateStoragePoolVO tmpltStoredOn = null;
for (int i = 0; i < 2; i++) {
if (template != null
&& template.getFormat() != Storage.ImageFormat.ISO) {
if (pool.getPoolType() == StoragePoolType.CLVM) {
// prepareISOForCreate does what we need, which is to
// tell us where the template is
VMTemplateHostVO tmpltHostOn = templateMgr
.prepareISOForCreate(template, pool);
if (tmpltHostOn == null) {
s_logger.debug("cannot find template "
+ template.getId() + " "
+ template.getName());
throw new CloudRuntimeException("cannot find template"
+ template.getId()
+ template.getName());
}
HostVO secondaryStorageHost = hostDao
.findById(tmpltHostOn.getHostId());
String tmpltHostUrl = secondaryStorageHost
.getStorageUrl();
String fullTmpltUrl = tmpltHostUrl + "/"
+ tmpltHostOn.getInstallPath();
cmd = new CreateCommand(diskProfile, fullTmpltUrl,
new StorageFilerTO(pool));
} else {
tmpltStoredOn = templateMgr.prepareTemplateForCreate(
template, pool);
if (tmpltStoredOn == null) {
s_logger.debug("Cannot use this pool " + pool
+ " because we can't propagate template "
+ template);
throw new CloudRuntimeException("Cannot use this pool " + pool
+ " because we can't propagate template "
+ template);
}
cmd = new CreateCommand(diskProfile,
tmpltStoredOn.getLocalDownloadPath(),
new StorageFilerTO(pool));
}
} else {
if (template != null
&& Storage.ImageFormat.ISO == template.getFormat()) {
VMTemplateHostVO tmpltHostOn = templateMgr
.prepareISOForCreate(template, pool);
if (tmpltHostOn == null) {
throw new CloudRuntimeException(
"Did not find ISO in secondry storage in zone "
+ pool.getDataCenterId());
}
}
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;
} else {
if (tmpltStoredOn != null
&& (answer instanceof CreateAnswer)
&& ((CreateAnswer) answer)
.templateReloadRequested()) {
if (!templateMgr
.resetTemplateDownloadStateOnPool(tmpltStoredOn
.getId())) {
break; // break out of template-redeploy retry loop
}
} else {
break;
}
}
}
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("Unable to create volume " + volume.getId());
}
return false;
}
@Override
public void createAsync(DataObject data,
AsyncCompletionCallback<CreateCmdResult> callback) {
// TODO Auto-generated method stub
String errMsg = null;
if (data.getType() == DataObjectType.VOLUME) {
try {
createVolume((VolumeInfo)data);
} catch (StorageUnavailableException e) {
s_logger.debug("failed to create volume", e);
errMsg = e.toString();
} catch (Exception e) {
s_logger.debug("failed to create volume", e);
errMsg = e.toString();
}
}
CreateCmdResult result = new CreateCmdResult(null, null);
if (errMsg != null) {
result.setResult(errMsg);
CreateCmdResult result = null;
if ((answer != null) && answer.getResult()) {
result = new CreateCmdResult(answer.getSnapshotPath(), null);
} else {
result = new CreateCmdResult(null, null);
}
callback.complete(result);
}
}
@Override
public void deleteAsync(DataObject data,
AsyncCompletionCallback<CommandResult> callback) {
@Override
public void revertSnapshot(SnapshotInfo snapshot,
AsyncCompletionCallback<CommandResult> callback) {
// TODO Auto-generated method stub
String vmName = null;
VolumeVO vol = this.volumeDao.findById(data.getId());
}
@Override
public void resize(DataObject data,
AsyncCompletionCallback<CreateCmdResult> callback) {
VolumeObject vol = (VolumeObject)data;
StoragePool pool = (StoragePool)data.getDataStore();
ResizeVolumePayload resizeParameter = (ResizeVolumePayload)vol.getpayload();
StoragePool pool = (StoragePool)data.getDataStore();
ResizeVolumeCommand resizeCmd = new ResizeVolumeCommand(
vol.getPath(), new StorageFilerTO(pool), vol.getSize(),
resizeParameter.newSize, resizeParameter.shrinkOk, resizeParameter.instanceName);
CreateCmdResult result = new CreateCmdResult(null, null);
try {
ResizeVolumeAnswer answer = (ResizeVolumeAnswer) this.storageMgr.sendToPool(pool,
resizeParameter.hosts, resizeCmd);
if (answer != null && answer.getResult()) {
long finalSize = answer.getNewSize();
s_logger.debug("Resize: volume started at size " + vol.getSize()
+ " and ended at size " + finalSize);
DestroyCommand cmd = new DestroyCommand(pool, vol, vmName);
vol.setSize(finalSize);
vol.update();
} else if (answer != null) {
result.setResult(answer.getDetails());
} else {
s_logger.debug("return a null answer, mark it as failed for unknown reason");
result.setResult("return a null answer, mark it as failed for unknown reason");
}
CommandResult result = new CommandResult();
try {
Answer answer = this.storageMgr.sendToPool(pool, cmd);
if (answer != null && !answer.getResult()) {
result.setResult(answer.getDetails());
s_logger.info("Will retry delete of " + vol + " from " + pool.getId());
}
} catch (StorageUnavailableException e) {
s_logger.error("Storage is unavailable currently. Will retry delete of "
+ vol + " from " + pool.getId(), e);
result.setResult(e.toString());
} catch (Exception ex) {
s_logger.debug("Unable to destoy volume" + vol + " from " + pool.getId(), ex);
result.setResult(ex.toString());
}
callback.complete(result);
}
} catch (Exception e) {
s_logger.debug("sending resize command failed", e);
result.setResult(e.toString());
}
@Override
public void copyAsync(DataObject srcdata, DataObject destData,
AsyncCompletionCallback<CopyCommandResult> callback) {
// TODO Auto-generated method stub
}
@Override
public boolean canCopy(DataObject srcData, DataObject destData) {
// TODO Auto-generated method stub
return false;
}
@Override
public void takeSnapshot(SnapshotInfo snapshot,
AsyncCompletionCallback<CommandResult> callback) {
// TODO Auto-generated method stub
}
@Override
public void revertSnapshot(SnapshotInfo snapshot,
AsyncCompletionCallback<CommandResult> callback) {
// TODO Auto-generated method stub
}
callback.complete(result);
}
}

View File

@ -27,6 +27,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher;
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
@ -36,7 +37,6 @@ import org.apache.cloudstack.storage.command.CreateObjectCommand;
import org.apache.cloudstack.storage.command.DeleteCommand;
import org.apache.cloudstack.storage.datastore.DataObjectManager;
import org.apache.cloudstack.storage.endpoint.EndPointSelector;
import org.apache.cloudstack.storage.volume.PrimaryDataStoreDriver;
import org.apache.log4j.Logger;
import com.cloud.agent.api.Answer;
@ -210,13 +210,6 @@ public class DefaultPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
return null;
}
@Override
public void takeSnapshot(SnapshotInfo snapshot,
AsyncCompletionCallback<CommandResult> callback) {
// TODO Auto-generated method stub
}
@Override
public void revertSnapshot(SnapshotInfo snapshot,
AsyncCompletionCallback<CommandResult> callback) {
@ -238,5 +231,19 @@ public class DefaultPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
// TODO Auto-generated method stub
}
@Override
public void resize(DataObject data,
AsyncCompletionCallback<CreateCmdResult> callback) {
// TODO Auto-generated method stub
}
@Override
public void takeSnapshot(SnapshotInfo snapshot,
AsyncCompletionCallback<CreateCmdResult> callback) {
// TODO Auto-generated method stub
}
}

View File

@ -27,13 +27,13 @@ import javax.inject.Inject;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager;
import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener;
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
import org.apache.cloudstack.storage.datastore.DefaultPrimaryDataStore;
import org.apache.cloudstack.storage.datastore.PrimaryDataStore;
import org.apache.cloudstack.storage.datastore.PrimaryDataStoreProviderManager;
import org.apache.cloudstack.storage.datastore.db.DataStoreProviderDao;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.storage.volume.PrimaryDataStoreDriver;
import org.springframework.stereotype.Component;
@Component

View File

@ -23,10 +23,10 @@ import java.util.Map;
import javax.inject.Inject;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreLifeCycle;
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
import org.apache.cloudstack.storage.datastore.PrimaryDataStoreProviderManager;
import org.apache.cloudstack.storage.datastore.driver.AncientPrimaryDataStoreDriverImpl;
import org.apache.cloudstack.storage.datastore.lifecycle.AncientPrimaryDataStoreLifeCyclImpl;
import org.apache.cloudstack.storage.volume.PrimaryDataStoreDriver;
import org.springframework.stereotype.Component;
import com.cloud.utils.component.ComponentContext;

View File

@ -22,10 +22,10 @@ import javax.inject.Inject;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreLifeCycle;
import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener;
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
import org.apache.cloudstack.storage.datastore.PrimaryDataStoreProviderManager;
import org.apache.cloudstack.storage.datastore.driver.DefaultPrimaryDataStoreDriverImpl;
import org.apache.cloudstack.storage.datastore.lifecycle.DefaultPrimaryDataStoreLifeCycleImpl;
import org.apache.cloudstack.storage.volume.PrimaryDataStoreDriver;
import org.springframework.stereotype.Component;
import com.cloud.utils.component.ComponentContext;

View File

@ -30,6 +30,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.disktype.DiskFormat;
import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager;
import org.apache.log4j.Logger;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.storage.Volume;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.VolumeDao;
@ -73,6 +74,10 @@ public class VolumeObject implements VolumeInfo {
public void setPath(String uuid) {
volumeVO.setPath(uuid);
}
public void setSize(Long size) {
volumeVO.setSize(size);
}
public Volume.State getState() {
return volumeVO.getState();
@ -182,6 +187,8 @@ public class VolumeObject implements VolumeInfo {
volEvent = Volume.Event.OperationSucceeded;
} else if (event == ObjectInDataStoreStateMachine.Event.OperationFailed) {
volEvent = Volume.Event.OperationFailed;
} else if (event == ObjectInDataStoreStateMachine.Event.ResizeRequested) {
volEvent = Volume.Event.ResizeRequested;
}
this.stateTransit(volEvent);
} catch (Exception e) {
@ -310,4 +317,14 @@ public class VolumeObject implements VolumeInfo {
public Object getpayload() {
return this.payload;
}
@Override
public HypervisorType getHypervisorType() {
return this.volumeDao.getHypervisorType(this.volumeVO.getId());
}
@Override
public Long getLastPoolId() {
return this.volumeVO.getLastPoolId();
}
}

View File

@ -56,9 +56,6 @@ import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.dao.VMInstanceDao;
//1. change volume state
//2. orchestrator of volume, control most of the information of volume, storage pool id, voluem state, scope etc.
@Component
public class VolumeServiceImpl implements VolumeService {
private static final Logger s_logger = Logger
@ -423,8 +420,49 @@ public class VolumeServiceImpl implements VolumeService {
public AsyncCallFuture<VolumeApiResult> createVolumeFromSnapshot(
VolumeInfo volume, DataStore store, SnapshotInfo snapshot) {
AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
VolumeApiResult result = new VolumeApiResult(volume);
return null;
try {
DataObject volumeOnStore = store.create(volume);
volume.processEvent(Event.CreateOnlyRequested);
CreateVolumeFromBaseImageContext<VolumeApiResult> context = new CreateVolumeFromBaseImageContext<VolumeApiResult>(null,
(VolumeObject)volume, store, volumeOnStore, future);
AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
caller.setCallback(caller.getTarget().createVolumeFromSnapshotCallback(null, null))
.setContext(context);
this.motionSrv.copyAsync(snapshot, volumeOnStore, caller);
} catch (Exception e) {
s_logger.debug("create volume from snapshot failed", e);
VolumeApiResult result = new VolumeApiResult(volume);
result.setResult(e.toString());
future.complete(result);
}
return future;
}
protected Void createVolumeFromSnapshotCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback,
CreateVolumeFromBaseImageContext<VolumeApiResult> context) {
CopyCommandResult result = callback.getResult();
VolumeInfo volume = context.vo;
VolumeApiResult apiResult = new VolumeApiResult(volume);
Event event = null;
if (result.isFailed()) {
apiResult.setResult(result.getResult());
event = Event.OperationFailed;
} else {
event = Event.OperationSuccessed;
}
try {
volume.processEvent(event);
} catch (Exception e) {
s_logger.debug("create volume from snapshot failed", e);
apiResult.setResult(e.toString());
}
AsyncCallFuture<VolumeApiResult> future = context.future;
future.complete(apiResult);
return null;
}
protected VolumeVO duplicateVolumeOnAnotherStorage(Volume volume, StoragePool pool) {
@ -552,5 +590,61 @@ public class VolumeServiceImpl implements VolumeService {
context.future.complete(res);
return null;
}
@Override
public AsyncCallFuture<VolumeApiResult> resize(VolumeInfo volume) {
AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
VolumeApiResult result = new VolumeApiResult(volume);
try {
volume.processEvent(Event.ResizeRequested);
} catch (Exception e) {
s_logger.debug("Failed to change state to resize", e);
result.setResult(e.toString());
future.complete(result);
return future;
}
CreateVolumeContext<VolumeApiResult> context = new CreateVolumeContext<VolumeApiResult>(null, volume, future);
AsyncCallbackDispatcher<VolumeServiceImpl, CreateCmdResult> caller = AsyncCallbackDispatcher.create(this);
caller.setCallback(caller.getTarget().registerVolumeCallback(null, null))
.setContext(context);
volume.getDataStore().getDriver().resize(volume, caller);
return future;
}
protected Void resizeVolumeCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CreateCmdResult> callback, CreateVolumeContext<VolumeApiResult> context) {
CreateCmdResult result = callback.getResult();
AsyncCallFuture<VolumeApiResult> future = context.future;
VolumeInfo volume = (VolumeInfo)context.volume;
if (result.isFailed()) {
try {
volume.processEvent(Event.OperationFailed);
} catch (Exception e) {
s_logger.debug("Failed to change state", e);
}
VolumeApiResult res = new VolumeApiResult(volume);
res.setResult(result.getResult());
future.complete(res);
return null;
}
try {
volume.processEvent(Event.OperationSuccessed);
} catch(Exception e) {
s_logger.debug("Failed to change state", e);
VolumeApiResult res = new VolumeApiResult(volume);
res.setResult(result.getResult());
future.complete(res);
return null;
}
VolumeApiResult res = new VolumeApiResult(volume);
future.complete(res);
return null;
}
}

View File

@ -24,9 +24,9 @@ import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
import org.apache.cloudstack.storage.volume.PrimaryDataStoreDriver;
public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
@ -72,17 +72,25 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
return false;
}
@Override
public void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback<CommandResult> callback) {
// TODO Auto-generated method stub
}
@Override
public void revertSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback<CommandResult> callback) {
// TODO Auto-generated method stub
}
@Override
public void resize(DataObject data,
AsyncCompletionCallback<CreateCmdResult> callback) {
// TODO Auto-generated method stub
}
@Override
public void takeSnapshot(SnapshotInfo snapshot,
AsyncCompletionCallback<CreateCmdResult> callback) {
// TODO Auto-generated method stub
}
}

View File

@ -618,7 +618,7 @@ public class ApiDBUtils {
public static String getSnapshotIntervalTypes(long snapshotId) {
SnapshotVO snapshot = _snapshotDao.findById(snapshotId);
return snapshot.getType().name();
return snapshot.getRecurringType().name();
}
public static String getStoragePoolTags(long poolId) {

View File

@ -341,7 +341,7 @@ public class ApiResponseHelper implements ResponseGenerator {
populateOwner(snapshotResponse, snapshot);
VolumeVO volume = findVolumeById(snapshot.getVolumeId());
String snapshotTypeStr = snapshot.getType().name();
String snapshotTypeStr = snapshot.getRecurringType().name();
snapshotResponse.setSnapshotType(snapshotTypeStr);
if (volume != null) {
snapshotResponse.setVolumeId(volume.getUuid());

View File

@ -137,7 +137,8 @@ public enum Config {
SnapshotMonthlyMax("Snapshots", SnapshotManager.class, Integer.class, "snapshot.max.monthly", "8", "Maximum monthly snapshots for a volume", null),
SnapshotPollInterval("Snapshots", SnapshotManager.class, Integer.class, "snapshot.poll.interval", "300", "The time interval in seconds when the management server polls for snapshots to be scheduled.", null),
SnapshotDeltaMax("Snapshots", SnapshotManager.class, Integer.class, "snapshot.delta.max", "16", "max delta snapshots between two full snapshots.", null),
BackupSnapshotAferTakingSnapshot("Snapshots", SnapshotManager.class, Boolean.class, "snapshot.backup.rightafter", "true", "backup snapshot right after snapshot is taken", null),
// Advanced
JobExpireMinutes("Advanced", ManagementServer.class, String.class, "job.expire.minutes", "1440", "Time (in minutes) for async-jobs to be kept in system", null),
JobCancelThresholdMinutes("Advanced", ManagementServer.class, String.class, "job.cancel.threshold.minutes", "60", "Time (in minutes) for async-jobs to be forcely cancelled if it has been in process for long", null),

View File

@ -0,0 +1,14 @@
package com.cloud.storage;
public class ResizeVolumePayload {
public final Long newSize;
public final boolean shrinkOk;
public final String instanceName;
public final long[] hosts;
public ResizeVolumePayload(Long newSize, boolean shrinkOk, String instanceName, long[] hosts) {
this.newSize = newSize;
this.shrinkOk = shrinkOk;
this.instanceName = instanceName;
this.hosts = hosts;
}
}

View File

@ -52,9 +52,9 @@ public interface VolumeManager extends VolumeApiService {
boolean volumeOnSharedStoragePool(VolumeVO volume);
boolean volumeInactive(VolumeVO volume);
boolean volumeInactive(Volume volume);
String getVmNameOnVolume(VolumeVO volume);
String getVmNameOnVolume(Volume volume);
VolumeVO allocVolume(CreateVolumeCmd cmd)
throws ResourceAllocationException;

View File

@ -66,12 +66,6 @@ import com.cloud.agent.AgentManager;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.AttachVolumeAnswer;
import com.cloud.agent.api.AttachVolumeCommand;
import com.cloud.agent.api.storage.CopyVolumeAnswer;
import com.cloud.agent.api.storage.CopyVolumeCommand;
import com.cloud.agent.api.storage.DestroyCommand;
import com.cloud.agent.api.storage.ResizeVolumeAnswer;
import com.cloud.agent.api.storage.ResizeVolumeCommand;
import com.cloud.agent.api.to.StorageFilerTO;
import com.cloud.agent.api.to.VolumeTO;
import com.cloud.alert.AlertManager;
import com.cloud.api.ApiDBUtils;
@ -763,7 +757,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
}
@Override
public boolean volumeInactive(VolumeVO volume) {
public boolean volumeInactive(Volume volume) {
Long vmId = volume.getInstanceId();
if (vmId != null) {
UserVm vm = _userVmDao.findById(vmId);
@ -779,7 +773,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
}
@Override
public String getVmNameOnVolume(VolumeVO volume) {
public String getVmNameOnVolume(Volume volume) {
Long vmId = volume.getInstanceId();
if (vmId != null) {
VMInstanceVO vm = _vmInstanceDao.findById(vmId);
@ -1013,7 +1007,6 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
public VolumeVO resizeVolume(ResizeVolumeCmd cmd) {
Long newSize = null;
boolean shrinkOk = cmd.getShrinkOk();
boolean success = false;
VolumeVO volume = _volsDao.findById(cmd.getEntityId());
if (volume == null) {
@ -1170,64 +1163,31 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
"VM must be stopped or disk detached in order to resize with the Xen HV");
}
}
ResizeVolumePayload payload = new ResizeVolumePayload(newSize, shrinkOk, instanceName, hosts);
try {
try {
stateTransitTo(volume, Volume.Event.ResizeRequested);
} catch (NoTransitionException etrans) {
throw new CloudRuntimeException(
"Unable to change volume state for resize: "
+ etrans.toString());
}
VolumeInfo vol = this.volFactory.getVolume(volume.getId());
vol.addPayload(payload);
AsyncCallFuture<VolumeApiResult> future = this.volService.resize(vol);
future.get();
volume = _volsDao.findById(volume.getId());
ResizeVolumeCommand resizeCmd = new ResizeVolumeCommand(
volume.getPath(), new StorageFilerTO(pool), currentSize,
newSize, shrinkOk, instanceName);
ResizeVolumeAnswer answer = (ResizeVolumeAnswer) this.storageMgr.sendToPool(pool,
hosts, resizeCmd);
if (newDiskOffering != null) {
volume.setDiskOfferingId(cmd.getNewDiskOfferingId());
}
_volsDao.update(volume.getId(), volume);
/*
* need to fetch/store new volume size in database. This value comes
* from hypervisor rather than trusting that a success means we have
* a volume of the size we requested
*/
if (answer != null && answer.getResult()) {
long finalSize = answer.getNewSize();
s_logger.debug("Resize: volume started at size " + currentSize
+ " and ended at size " + finalSize);
volume.setSize(finalSize);
if (newDiskOffering != null) {
volume.setDiskOfferingId(cmd.getNewDiskOfferingId());
}
_volsDao.update(volume.getId(), volume);
success = true;
return volume;
} else if (answer != null) {
s_logger.debug("Resize: returned '" + answer.getDetails() + "'");
}
} catch (StorageUnavailableException e) {
s_logger.debug("volume failed to resize: " + e);
return null;
} finally {
if (success) {
try {
stateTransitTo(volume, Volume.Event.OperationSucceeded);
} catch (NoTransitionException etrans) {
throw new CloudRuntimeException(
"Failed to change volume state: "
+ etrans.toString());
}
} else {
try {
stateTransitTo(volume, Volume.Event.OperationFailed);
} catch (NoTransitionException etrans) {
throw new CloudRuntimeException(
"Failed to change volume state: "
+ etrans.toString());
}
}
}
return volume;
} catch (InterruptedException e) {
s_logger.debug("failed get resize volume result", e);
} catch (ExecutionException e) {
s_logger.debug("failed get resize volume result", e);
} catch (Exception e) {
s_logger.debug("failed get resize volume result", e);
}
return null;
}

View File

@ -25,7 +25,7 @@ import com.cloud.utils.fsm.StateDao;
import java.util.List;
public interface SnapshotDao extends GenericDao<SnapshotVO, Long>, StateDao<Snapshot.State, Snapshot.Event, Snapshot> {
public interface SnapshotDao extends GenericDao<SnapshotVO, Long>, StateDao<Snapshot.State, Snapshot.Event, SnapshotVO> {
List<SnapshotVO> listByVolumeId(long volumeId);
List<SnapshotVO> listByVolumeId(Filter filter, long volumeId);
SnapshotVO findNextSnapshot(long parentSnapId);

View File

@ -324,7 +324,7 @@ public class SnapshotDaoImpl extends GenericDaoBase<SnapshotVO, Long> implements
}
@Override
public boolean updateState(State currentState, Event event, State nextState, Snapshot snapshot, Object data) {
public boolean updateState(State currentState, Event event, State nextState, SnapshotVO snapshot, Object data) {
Transaction txn = Transaction.currentTxn();
txn.start();
SnapshotVO snapshotVO = (SnapshotVO)snapshot;

View File

@ -17,24 +17,24 @@
package com.cloud.storage.listener;
import com.cloud.event.EventCategory;
import com.cloud.storage.Snapshot;
import com.cloud.storage.Snapshot.Event;
import com.cloud.storage.Snapshot.State;
import com.cloud.server.ManagementServer;
import com.cloud.utils.fsm.StateListener;
import org.apache.cloudstack.framework.events.EventBus;
import org.apache.cloudstack.framework.events.EventBusException;
import org.apache.log4j.Logger;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import javax.inject.Inject;
public class SnapshotStateListener implements StateListener<State, Event, Snapshot> {
import org.apache.cloudstack.framework.events.EventBus;
import org.apache.cloudstack.framework.events.EventBusException;
import org.apache.log4j.Logger;
import com.cloud.event.EventCategory;
import com.cloud.server.ManagementServer;
import com.cloud.storage.Snapshot;
import com.cloud.storage.Snapshot.Event;
import com.cloud.storage.Snapshot.State;
import com.cloud.storage.SnapshotVO;
import com.cloud.utils.fsm.StateListener;
public class SnapshotStateListener implements StateListener<State, Event, SnapshotVO> {
// get the event bus provider if configured
@Inject protected EventBus _eventBus;
@ -46,13 +46,13 @@ public class SnapshotStateListener implements StateListener<State, Event, Snapsh
}
@Override
public boolean preStateTransitionEvent(State oldState, Event event, State newState, Snapshot vo, boolean status, Object opaque) {
public boolean preStateTransitionEvent(State oldState, Event event, State newState, SnapshotVO vo, boolean status, Object opaque) {
pubishOnEventBus(event.name(), "preStateTransitionEvent", vo, oldState, newState);
return true;
}
@Override
public boolean postStateTransitionEvent(State oldState, Event event, State newState, Snapshot vo, boolean status, Object opaque) {
public boolean postStateTransitionEvent(State oldState, Event event, State newState, SnapshotVO vo, boolean status, Object opaque) {
pubishOnEventBus(event.name(), "postStateTransitionEvent", vo, oldState, newState);
return true;
}

View File

@ -18,13 +18,19 @@ package com.cloud.storage.snapshot;
import java.util.List;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.host.HostVO;
import com.cloud.storage.Snapshot;
import com.cloud.storage.SnapshotPolicyVO;
import com.cloud.storage.SnapshotVO;
import com.cloud.storage.Volume;
import com.cloud.storage.VolumeVO;
import com.cloud.utils.db.Filter;
import com.cloud.utils.fsm.NoTransitionException;
/**
*
@ -38,66 +44,6 @@ public interface SnapshotManager {
public static final int MONTHLYMAX = 12;
public static final int DELTAMAX = 16;
/**
* After successfully creating a snapshot of a volume, copy the snapshot to the secondary storage for 1) reliability 2) So
* that storage space on Primary is conserved.
*
* @param snapshot
* Info about the created snapshot on primary storage.
* @param startEventId
* event id of the scheduled event for this snapshot
* @return True if the snapshot was successfully backed up.
*/
public boolean backupSnapshotToSecondaryStorage(SnapshotVO snapshot);
/**
* Once a snapshot has completed, 1) If success, update the database entries 2) If success and there are excess snapshots
* for any of the policies given, delete the oldest one. 3) Schedule the next recurring snapshot.
*
* @param volumeId
* The volume for which the snapshot is being taken
* @param snapshotId
* The snapshot which has just completed
* @param policyIds
* The list of policyIds to which this snapshot belongs to
* @param backedUp
* If true, the snapshot has been successfully created.
*/
void postCreateSnapshot(Long volumeId, Long snapshotId, Long policyId, boolean backedUp);
/**
* Destroys the specified snapshot from secondary storage
*/
boolean destroySnapshot(long userId, long snapshotId, long policyId);
/**
* Deletes snapshot scheduling policy. Delete will fail if this policy is assigned to one or more volumes
*/
boolean deletePolicy(long userId, Long policyId);
/**
* Lists all snapshots for the volume which are created using schedule of the specified policy
*/
/*
* List<SnapshotVO> listSnapsforPolicy(long policyId, Filter filter);
*/
/**
* List all policies which are assigned to the specified volume
*/
List<SnapshotPolicyVO> listPoliciesforVolume(long volumeId);
/**
* List all policies to which a specified snapshot belongs. For ex: A snapshot may belong to a hourly snapshot and a daily
* snapshot run at the same time
*/
/*
* List<SnapshotPolicyVO> listPoliciesforSnapshot(long snapshotId);
*/
/**
* List all snapshots for a specified volume irrespective of the policy which created the snapshot
*/
List<SnapshotVO> listSnapsforVolume(long volumeId);
void deletePoliciesForVolume(Long volumeId);
/**
@ -109,35 +55,20 @@ public interface SnapshotManager {
* The account which is to be deleted.
*/
boolean deleteSnapshotDirsForAccount(long accountId);
SnapshotPolicyVO getPolicyForVolume(long volumeId);
boolean destroySnapshotBackUp(long snapshotId);
/**
* Create a snapshot of a volume
*
* @param cmd
* the API command wrapping the parameters for creating the snapshot (mainly volumeId)
* @return the Snapshot that was created
*/
SnapshotVO createSnapshotOnPrimary(VolumeVO volume, Long polocyId, Long snapshotId) throws ResourceAllocationException;
List<SnapshotPolicyVO> listPoliciesforSnapshot(long snapshotId);
List<SnapshotVO> listSnapsforPolicy(long policyId, Filter filter);
void downloadSnapshotsFromSwift(SnapshotVO ss);
void downloadSnapshotsFromS3(SnapshotVO snapshot);
HostVO getSecondaryStorageHost(SnapshotVO snapshot);
String getSecondaryStorageURL(SnapshotVO snapshot);
void deleteSnapshotsForVolume (String secondaryStoragePoolUrl, Long dcId, Long accountId, Long volumeId );
void deleteSnapshotsDirForVolume(String secondaryStoragePoolUrl, Long dcId, Long accountId, Long volumeId);
boolean canOperateOnVolume(Volume volume);
Answer sendToPool(Volume vol, Command cmd);
SnapshotVO getParentSnapshot(VolumeInfo volume, Snapshot snapshot);
Snapshot backupSnapshot(Long snapshotId);
}

View File

@ -32,20 +32,21 @@ import org.apache.cloudstack.api.command.user.snapshot.DeleteSnapshotPoliciesCmd
import org.apache.cloudstack.api.command.user.snapshot.ListSnapshotPoliciesCmd;
import org.apache.cloudstack.api.command.user.snapshot.ListSnapshotsCmd;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
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.SnapshotStrategy;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import com.cloud.agent.AgentManager;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.BackupSnapshotAnswer;
import com.cloud.agent.api.BackupSnapshotCommand;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.DeleteSnapshotBackupCommand;
import com.cloud.agent.api.DeleteSnapshotsDirCommand;
import com.cloud.agent.api.DownloadSnapshotFromS3Command;
import com.cloud.agent.api.ManageSnapshotAnswer;
import com.cloud.agent.api.ManageSnapshotCommand;
import com.cloud.agent.api.downloadSnapshotFromSwiftCommand;
import com.cloud.agent.api.to.S3TO;
import com.cloud.agent.api.to.SwiftTO;
@ -65,7 +66,6 @@ import com.cloud.event.EventTypes;
import com.cloud.event.EventVO;
import com.cloud.event.UsageEventUtils;
import com.cloud.event.dao.EventDao;
import com.cloud.event.dao.UsageEventDao;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.ResourceAllocationException;
@ -75,7 +75,6 @@ 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.Snapshot;
import com.cloud.storage.Snapshot.Type;
@ -83,7 +82,6 @@ import com.cloud.storage.SnapshotPolicyVO;
import com.cloud.storage.SnapshotScheduleVO;
import com.cloud.storage.SnapshotVO;
import com.cloud.storage.Storage;
import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.storage.StorageManager;
import com.cloud.storage.StoragePool;
import com.cloud.storage.VMTemplateVO;
@ -97,7 +95,6 @@ import com.cloud.storage.dao.SnapshotScheduleDao;
import com.cloud.storage.dao.StoragePoolDao;
import com.cloud.storage.dao.VMTemplateDao;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.storage.listener.SnapshotStateListener;
import com.cloud.storage.s3.S3Manager;
import com.cloud.storage.secondary.SecondaryStorageVmManager;
import com.cloud.storage.swift.SwiftManager;
@ -123,14 +120,8 @@ import com.cloud.utils.db.Filter;
import com.cloud.utils.db.JoinBuilder;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.fsm.NoTransitionException;
import com.cloud.utils.fsm.StateMachine2;
import com.cloud.vm.UserVmVO;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachine.State;
import com.cloud.vm.dao.UserVmDao;
import org.apache.cloudstack.api.command.user.snapshot.CreateSnapshotPolicyCmd;
@ -189,8 +180,6 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
@Inject
protected ClusterDao _clusterDao;
@Inject
private UsageEventDao _usageEventDao;
@Inject
private ResourceLimitService _resourceLimitMgr;
@Inject
private SwiftManager _swiftMgr;
@ -199,12 +188,8 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
@Inject
private SecondaryStorageVmManager _ssvmMgr;
@Inject
private ResourceManager _resourceMgr;
@Inject
private DomainManager _domainMgr;
@Inject
private VolumeDao _volumeDao;
@Inject
private ResourceTagDao _resourceTagDao;
@Inject
private ConfigurationDao _configDao;
@ -216,21 +201,20 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
@Inject TemplateManager templateMgr;
@Inject VolumeManager volumeMgr;
@Inject DataStoreManager dataStoreMgr;
@Inject List<SnapshotStrategy> snapshotStrategies;
@Inject VolumeDataFactory volFactory;
@Inject SnapshotDataFactory snapshotFactory;
private int _totalRetries;
private int _pauseInterval;
private int _deltaSnapshotMax;
private int _backupsnapshotwait;
private StateMachine2<Snapshot.State, Snapshot.Event, Snapshot> _snapshotFsm;
protected SearchBuilder<SnapshotVO> PolicySnapshotSearch;
protected SearchBuilder<SnapshotPolicyVO> PoliciesForSnapSearch;
protected Answer sendToPool(Volume vol, Command cmd) {
@Override
public Answer sendToPool(Volume vol, Command cmd) {
StoragePool pool = (StoragePool)dataStoreMgr.getPrimaryDataStore(vol.getPoolId());
long[] hostIdsToTryFirst = null;
@ -282,127 +266,11 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
return null;
}
@Override
public SnapshotVO createSnapshotOnPrimary(VolumeVO volume, Long policyId, Long snapshotId) {
SnapshotVO snapshot = _snapshotDao.findById(snapshotId);
if (snapshot == null) {
throw new CloudRuntimeException("Can not find snapshot " + snapshotId);
}
try {
stateTransitTo(snapshot, Snapshot.Event.CreateRequested);
} catch (NoTransitionException nte) {
s_logger.debug("Failed to update snapshot state due to " + nte.getMessage());
}
// Send a ManageSnapshotCommand to the agent
String vmName = this.volumeMgr.getVmNameOnVolume(volume);
long volumeId = volume.getId();
long preId = _snapshotDao.getLastSnapshot(volumeId, snapshotId);
String preSnapshotPath = null;
SnapshotVO preSnapshotVO = null;
if (preId != 0 && !(volume.getLastPoolId() != null && !volume.getLastPoolId().equals(volume.getPoolId()))) {
preSnapshotVO = _snapshotDao.findByIdIncludingRemoved(preId);
if (preSnapshotVO != null && preSnapshotVO.getBackupSnapshotId() != null) {
preSnapshotPath = preSnapshotVO.getPath();
}
}
StoragePool srcPool = (StoragePool)dataStoreMgr.getPrimaryDataStore(volume.getPoolId());
// RBD volumes do not support snapshotting in the way CloudStack does it.
// For now we leave the snapshot feature disabled for RBD volumes
if (srcPool.getPoolType() == StoragePoolType.RBD) {
throw new CloudRuntimeException("RBD volumes do not support snapshotting");
}
ManageSnapshotCommand cmd = new ManageSnapshotCommand(snapshotId, volume.getPath(), srcPool, preSnapshotPath, snapshot.getName(), vmName);
ManageSnapshotAnswer answer = (ManageSnapshotAnswer) sendToPool(volume, cmd);
// Update the snapshot in the database
if ((answer != null) && answer.getResult()) {
// The snapshot was successfully created
if (preSnapshotPath != null && preSnapshotPath.equals(answer.getSnapshotPath())) {
// empty snapshot
s_logger.debug("CreateSnapshot: this is empty snapshot ");
try {
snapshot.setPath(preSnapshotPath);
snapshot.setBackupSnapshotId(preSnapshotVO.getBackupSnapshotId());
snapshot.setSwiftId(preSnapshotVO.getSwiftId());
snapshot.setPrevSnapshotId(preId);
snapshot.setSecHostId(preSnapshotVO.getSecHostId());
stateTransitTo(snapshot, Snapshot.Event.OperationNotPerformed);
} catch (NoTransitionException nte) {
s_logger.debug("CreateSnapshot: failed to update state of snapshot due to " + nte.getMessage());
}
} else {
long preSnapshotId = 0;
if (preSnapshotVO != null && preSnapshotVO.getBackupSnapshotId() != null) {
preSnapshotId = preId;
// default delta snap number is 16
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;
volume.setLastPoolId(volume.getPoolId());
_volumeDao.update(volume.getId(), volume);
}
snapshot = updateDBOnCreate(snapshotId, answer.getSnapshotPath(), preSnapshotId);
}
// Get the snapshot_schedule table entry for this snapshot and
// policy id.
// Set the snapshotId to retrieve it back later.
if (policyId != Snapshot.MANUAL_POLICY_ID) {
SnapshotScheduleVO snapshotSchedule = _snapshotScheduleDao.getCurrentSchedule(volumeId, policyId, true);
assert snapshotSchedule != null;
snapshotSchedule.setSnapshotId(snapshotId);
_snapshotScheduleDao.update(snapshotSchedule.getId(), snapshotSchedule);
}
} else {
if (answer != null) {
s_logger.error(answer.getDetails());
}
try {
stateTransitTo(snapshot, Snapshot.Event.OperationFailed);
} catch (NoTransitionException nte) {
s_logger.debug("Failed to update snapshot state due to " + nte.getMessage());
}
throw new CloudRuntimeException("Creating snapshot for volume " + volumeId + " on primary storage failed.");
}
return snapshot;
}
public SnapshotVO createSnapshotImpl(long volumeId, long policyId) throws ResourceAllocationException {
return null;
}
@Override
@DB
@ActionEvent(eventType = EventTypes.EVENT_SNAPSHOT_CREATE, eventDescription = "creating snapshot", async = true)
public SnapshotVO createSnapshot(Long volumeId, Long policyId, Long snapshotId, Account snapshotOwner) {
VolumeVO volume = _volsDao.findById(volumeId);
public Snapshot createSnapshot(Long volumeId, Long policyId, Long snapshotId, Account snapshotOwner) {
VolumeInfo volume = this.volFactory.getVolume(volumeId);
if (volume == null) {
throw new InvalidParameterValueException("No such volume exist");
}
@ -411,120 +279,50 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
throw new InvalidParameterValueException("Volume is not in ready state");
}
SnapshotVO snapshot = null;
SnapshotInfo snapshot = null;
boolean backedUp = false;
UserVmVO uservm = null;
// 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);
SnapshotStrategy strategy = null;
for (SnapshotStrategy st : snapshotStrategies) {
if (st.canHandle(snap)) {
strategy = st;
break;
}
}
try {
Long poolId = volume.getPoolId();
if (poolId == null) {
throw new CloudRuntimeException("You cannot take a snapshot of a volume until it has been attached to an instance");
}
if (_volsDao.getHypervisorType(volume.getId()).equals(HypervisorType.KVM)) {
uservm = _vmDao.findById(volume.getInstanceId());
if (uservm != null && uservm.getType() != VirtualMachine.Type.User) {
throw new CloudRuntimeException("Can't take a snapshot on system vm ");
}
StoragePoolVO storagePool = _storagePoolDao.findById(volume.getPoolId());
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 is attached to a vm in taking vm snapshot; 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:" + volumeId + " 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");
} */
}
}
snapshot = createSnapshotOnPrimary(volume, policyId, snapshotId);
if (snapshot != null) {
if (snapshot.getState() == Snapshot.State.CreatedOnPrimary) {
backedUp = backupSnapshotToSecondaryStorage(snapshot);
} else if (snapshot.getState() == Snapshot.State.BackedUp) {
// For empty snapshot we set status to BackedUp in createSnapshotOnPrimary
backedUp = true;
} else {
throw new CloudRuntimeException("Failed to create snapshot: " + snapshot + " on primary storage");
}
if (!backedUp) {
throw new CloudRuntimeException("Created snapshot: " + snapshot + " on primary but failed to backup on secondary");
}
} else {
throw new CloudRuntimeException("Failed to create snapshot: " + snapshot + " on primary storage");
}
} finally {
// Cleanup jobs to do after the snapshot has been created; decrement resource count
if (snapshot != null) {
postCreateSnapshot(volumeId, snapshot.getId(), policyId, backedUp);
//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());
}
if( !backedUp ) {
} else {
_resourceLimitMgr.incrementResourceCount(snapshotOwner.getId(), ResourceType.snapshot);
}
}
/*
try {
_storageMgr.stateTransitTo(volume, Volume.Event.OperationSucceeded);
} catch (NoTransitionException e) {
s_logger.debug("Failed to transit volume state: " + e.toString());
}*/
snapshot = strategy.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());
}
_resourceLimitMgr.incrementResourceCount(snapshotOwner.getId(), ResourceType.snapshot);
}
Boolean backup = Boolean.parseBoolean(this._configDao.getValue(Config.BackupSnapshotAferTakingSnapshot.toString()));
if (backup) {
this.backupSnapshot(snapshotId);
}
} catch(Exception e) {
s_logger.debug("Failed to create snapshot", e);
throw new CloudRuntimeException("Failed to create snapshot", e);
}
return snapshot;
}
private SnapshotVO updateDBOnCreate(Long id, String snapshotPath, long preSnapshotId) {
SnapshotVO createdSnapshot = _snapshotDao.findByIdIncludingRemoved(id);
createdSnapshot.setPath(snapshotPath);
createdSnapshot.setPrevSnapshotId(preSnapshotId);
try {
stateTransitTo(createdSnapshot, Snapshot.Event.OperationSucceeded);
} catch (NoTransitionException nte) {
s_logger.debug("Faile to update state of snapshot due to " + nte.getMessage());
}
return createdSnapshot;
}
private static void checkObjectStorageConfiguration(SwiftTO swift, S3TO s3) {
private void checkObjectStorageConfiguration(SwiftTO swift, S3TO s3) {
if (swift != null && s3 != null) {
throw new CloudRuntimeException(
@ -533,26 +331,6 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
}
@Override
public void deleteSnapshotsForVolume (String secondaryStoragePoolUrl, Long dcId, Long accountId, Long volumeId ){
SwiftTO swift = _swiftMgr.getSwiftTO();
S3TO s3 = _s3Mgr.getS3TO();
checkObjectStorageConfiguration(swift, s3);
DeleteSnapshotBackupCommand cmd = new DeleteSnapshotBackupCommand(
swift, s3, secondaryStoragePoolUrl, dcId, accountId, volumeId,
null, true);
try {
Answer ans = _agentMgr.sendToSSVM(dcId, cmd);
if ( ans == null || !ans.getResult() ) {
s_logger.warn("DeleteSnapshotBackupCommand failed due to " + ans.getDetails() + " volume id: " + volumeId);
}
} catch (Exception e) {
s_logger.warn("DeleteSnapshotBackupCommand failed due to" + e.toString() + " volume id: " + volumeId);
}
}
@Override
public void deleteSnapshotsDirForVolume(String secondaryStoragePoolUrl, Long dcId, Long accountId, Long volumeId) {
DeleteSnapshotsDirCommand cmd = new DeleteSnapshotsDirCommand(secondaryStoragePoolUrl, dcId, accountId, volumeId);
@ -566,6 +344,23 @@ 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);
}
SnapshotStrategy strategy = null;
for (SnapshotStrategy st : snapshotStrategies) {
if (st.canHandle(snapshot)) {
strategy = st;
break;
}
}
return strategy.backupSnapshot(snapshot);
}
@Override
public void downloadSnapshotsFromSwift(SnapshotVO ss) {
@ -652,133 +447,17 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
}
}
@Override
@DB
public boolean backupSnapshotToSecondaryStorage(SnapshotVO ss) {
long snapshotId = ss.getId();
SnapshotVO snapshot = _snapshotDao.acquireInLockTable(snapshotId);
if (snapshot == null) {
throw new CloudRuntimeException("Can not acquire lock for snapshot: " + ss);
}
try {
try {
stateTransitTo(snapshot, Snapshot.Event.BackupToSecondary);
} catch (NoTransitionException nte) {
s_logger.debug("Failed to update the state of snapshot while backing up snapshot");
}
public SnapshotVO getParentSnapshot(VolumeInfo volume, Snapshot snapshot) {
long preId = _snapshotDao.getLastSnapshot(volume.getId(), snapshot.getId());
long volumeId = snapshot.getVolumeId();
VolumeVO volume = _volsDao.lockRow(volumeId, true);
Long dcId = volume.getDataCenterId();
Long accountId = volume.getAccountId();
HostVO secHost = getSecHost(volumeId, volume.getDataCenterId());
String secondaryStoragePoolUrl = secHost.getStorageUrl();
String snapshotUuid = snapshot.getPath();
// In order to verify that the snapshot is not empty,
// we check if the parent of the snapshot is not the same as the parent of the previous snapshot.
// We pass the uuid of the previous snapshot to the plugin to verify this.
SnapshotVO prevSnapshot = null;
String prevSnapshotUuid = null;
String prevBackupUuid = null;
SwiftTO swift = _swiftMgr.getSwiftTO();
S3TO s3 = _s3Mgr.getS3TO();
checkObjectStorageConfiguration(swift, s3);
long prevSnapshotId = snapshot.getPrevSnapshotId();
if (prevSnapshotId > 0) {
prevSnapshot = _snapshotDao.findByIdIncludingRemoved(prevSnapshotId);
if ( prevSnapshot.getBackupSnapshotId() != null && swift == null) {
if (prevSnapshot.getVersion() != null && prevSnapshot.getVersion().equals("2.2")) {
prevBackupUuid = prevSnapshot.getBackupSnapshotId();
prevSnapshotUuid = prevSnapshot.getPath();
}
} else if ((prevSnapshot.getSwiftId() != null && swift != null)
|| (prevSnapshot.getS3Id() != null && s3 != null)) {
prevBackupUuid = prevSnapshot.getBackupSnapshotId();
prevSnapshotUuid = prevSnapshot.getPath();
}
}
boolean isVolumeInactive = this.volumeMgr.volumeInactive(volume);
String vmName = this.volumeMgr.getVmNameOnVolume(volume);
StoragePool srcPool = (StoragePool)dataStoreMgr.getPrimaryDataStore(volume.getPoolId());
BackupSnapshotCommand backupSnapshotCommand = new BackupSnapshotCommand(secondaryStoragePoolUrl, dcId, accountId, volumeId, snapshot.getId(), volume.getPath(), srcPool, snapshotUuid,
snapshot.getName(), prevSnapshotUuid, prevBackupUuid, isVolumeInactive, vmName, _backupsnapshotwait);
if ( swift != null ) {
backupSnapshotCommand.setSwift(swift);
} else if (s3 != null) {
backupSnapshotCommand.setS3(s3);
}
String backedUpSnapshotUuid = null;
// By default, assume failed.
boolean backedUp = false;
BackupSnapshotAnswer answer = (BackupSnapshotAnswer) sendToPool(volume, backupSnapshotCommand);
if (answer != null && answer.getResult()) {
backedUpSnapshotUuid = answer.getBackupSnapshotName();
if (backedUpSnapshotUuid != null) {
backedUp = true;
}
} else if (answer != null) {
s_logger.error(answer.getDetails());
}
// Update the status in all cases.
Transaction txn = Transaction.currentTxn();
txn.start();
if (backedUp) {
if (backupSnapshotCommand.getSwift() != null ) {
snapshot.setSwiftId(swift.getId());
snapshot.setBackupSnapshotId(backedUpSnapshotUuid);
} else if (backupSnapshotCommand.getS3() != null) {
snapshot.setS3Id(s3.getId());
snapshot.setBackupSnapshotId(backedUpSnapshotUuid);
} else {
snapshot.setSecHostId(secHost.getId());
snapshot.setBackupSnapshotId(backedUpSnapshotUuid);
}
if (answer.isFull()) {
snapshot.setPrevSnapshotId(0);
}
try {
stateTransitTo(snapshot, Snapshot.Event.OperationSucceeded);
} catch (NoTransitionException nte) {
s_logger.debug("Failed to update the state of snapshot while backing up snapshot");
}
} else {
try {
stateTransitTo(snapshot, Snapshot.Event.OperationFailed);
} catch (NoTransitionException nte) {
s_logger.debug("Failed to update the state of snapshot while backing up snapshot");
}
s_logger.warn("Failed to back up snapshot on secondary storage, deleting the record from the DB");
_snapshotDao.remove(snapshotId);
}
txn.commit();
return backedUp;
} finally {
if (snapshot != null) {
_snapshotDao.releaseFromLockTable(snapshotId);
}
}
}
private HostVO getSecHost(long volumeId, long dcId) {
Long id = _snapshotDao.getSecHostId(volumeId);
if ( id != null) {
return _hostDao.findById(id);
}
return this.templateMgr.getSecondaryStorageHost(dcId);
SnapshotVO preSnapshotVO = null;
if (preId != 0 && !(volume.getLastPoolId() != null && !volume.getLastPoolId().equals(volume.getPoolId()))) {
preSnapshotVO = _snapshotDao.findByIdIncludingRemoved(preId);
}
return preSnapshotVO;
}
private Long getSnapshotUserId() {
@ -789,11 +468,15 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
return userId;
}
@Override
@DB
public void postCreateSnapshot(Long volumeId, Long snapshotId, Long policyId, boolean backedUp) {
private void postCreateSnapshot(Long volumeId, Long snapshotId, Long policyId) {
Long userId = getSnapshotUserId();
SnapshotVO snapshot = _snapshotDao.findById(snapshotId);
if (policyId != Snapshot.MANUAL_POLICY_ID) {
SnapshotScheduleVO snapshotSchedule = _snapshotScheduleDao.getCurrentSchedule(volumeId, policyId, true);
assert snapshotSchedule != null;
snapshotSchedule.setSnapshotId(snapshotId);
_snapshotScheduleDao.update(snapshotSchedule.getId(), snapshotSchedule);
}
if (snapshot != null && snapshot.isRecursive()) {
postCreateRecurringSnapshotForPolicy(userId, volumeId, snapshotId, policyId);
@ -803,7 +486,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
private void postCreateRecurringSnapshotForPolicy(long userId, long volumeId, long snapshotId, long policyId) {
// Use count query
SnapshotVO spstVO = _snapshotDao.findById(snapshotId);
Type type = spstVO.getType();
Type type = spstVO.getRecurringType();
int maxSnaps = type.getMax();
List<SnapshotVO> snaps = listSnapsforVolumeType(volumeId, type);
@ -815,7 +498,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
SnapshotVO oldestSnapshot = snaps.get(0);
long oldSnapId = oldestSnapshot.getId();
s_logger.debug("Max snaps: " + policy.getMaxSnaps() + " exceeded for snapshot policy with Id: " + policyId + ". Deleting oldest snapshot: " + oldSnapId);
if(deleteSnapshotInternal(oldSnapId)){
if(deleteSnapshot(oldSnapId)){
//log Snapshot delete event
ActionEventUtils.onCompletedActionEvent(User.UID_SYSTEM, oldestSnapshot.getAccountId(), EventVO.LEVEL_INFO, EventTypes.EVENT_SNAPSHOT_DELETE, "Successfully deleted oldest snapshot: " + oldSnapId, 0);
}
@ -830,98 +513,38 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
Account caller = UserContext.current().getCaller();
// Verify parameters
Snapshot snapshotCheck = _snapshotDao.findById(snapshotId);
SnapshotInfo snapshotCheck = this.snapshotFactory.getSnapshot(snapshotId);
if (snapshotCheck == null) {
throw new InvalidParameterValueException("unable to find a snapshot with id " + snapshotId);
}
_accountMgr.checkAccess(caller, null, true, snapshotCheck);
if( !Snapshot.State.BackedUp.equals(snapshotCheck.getState() ) ) {
throw new InvalidParameterValueException("Can't delete snapshotshot " + snapshotId + " due to it is not in BackedUp Status");
SnapshotStrategy strategy = null;
for (SnapshotStrategy st : snapshotStrategies) {
if (st.canHandle(snapshotCheck)) {
strategy = st;
break;
}
}
try {
boolean result = strategy.deleteSnapshot(snapshotCheck);
if (result) {
if (snapshotCheck.getState() == Snapshot.State.BackedUp) {
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_DELETE, snapshotCheck.getAccountId(),
snapshotCheck.getDataCenterId(), snapshotId, snapshotCheck.getName(), null, null, 0L,
snapshotCheck.getClass().getName(), snapshotCheck.getUuid());
}
_resourceLimitMgr.decrementResourceCount(snapshotCheck.getAccountId(), ResourceType.snapshot);
}
return result;
} catch (Exception e) {
s_logger.debug("Failed to delete snapshot: " + snapshotCheck.getId() + ":" + e.toString());
throw new CloudRuntimeException("Failed to delete snapshot:" + e.toString());
}
return deleteSnapshotInternal(snapshotId);
}
@DB
private boolean deleteSnapshotInternal(Long snapshotId) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Calling deleteSnapshot for snapshotId: " + snapshotId);
}
SnapshotVO lastSnapshot = null;
SnapshotVO snapshot = _snapshotDao.findById(snapshotId);
if (snapshot.getBackupSnapshotId() != null) {
List<SnapshotVO> snaps = _snapshotDao.listByBackupUuid(snapshot.getVolumeId(), snapshot.getBackupSnapshotId());
if (snaps != null && snaps.size() > 1) {
snapshot.setBackupSnapshotId(null);
_snapshotDao.update(snapshot.getId(), snapshot);
}
}
Transaction txn = Transaction.currentTxn();
txn.start();
_snapshotDao.remove(snapshotId);
if (snapshot.getState() == Snapshot.State.BackedUp) {
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_DELETE, snapshot.getAccountId(),
snapshot.getDataCenterId(), snapshotId, snapshot.getName(), null, null, 0L,
snapshot.getClass().getName(), snapshot.getUuid());
}
_resourceLimitMgr.decrementResourceCount(snapshot.getAccountId(), ResourceType.snapshot);
txn.commit();
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(lastId)) {
} else {
s_logger.debug("Destroying snapshot backup failed " + lastSnapshot);
break;
}
}
}
lastId = lastSnapshot.getPrevSnapshotId();
if (lastId == 0) {
break;
}
lastSnapshot = _snapshotDao.findByIdIncludingRemoved(lastId);
}
}
return true;
}
@Override
@DB
public boolean destroySnapshot(long userId, long snapshotId, long policyId) {
return true;
}
@Override
public HostVO getSecondaryStorageHost(SnapshotVO snapshot) {
private HostVO getSecondaryStorageHost(SnapshotVO snapshot) {
HostVO secHost = null;
if( snapshot.getSwiftId() == null || snapshot.getSwiftId() == 0) {
secHost = _hostDao.findById(snapshot.getSecHostId());
@ -941,51 +564,6 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
throw new CloudRuntimeException("Can not find secondary storage");
}
@Override
@DB
public boolean destroySnapshotBackUp(long snapshotId) {
boolean success = false;
String details;
SnapshotVO snapshot = _snapshotDao.findByIdIncludingRemoved(snapshotId);
if (snapshot == null) {
throw new CloudRuntimeException("Destroying snapshot " + snapshotId + " backup failed due to unable to find snapshot ");
}
String secondaryStoragePoolUrl = getSecondaryStorageURL(snapshot);
Long dcId = snapshot.getDataCenterId();
Long accountId = snapshot.getAccountId();
Long volumeId = snapshot.getVolumeId();
String backupOfSnapshot = snapshot.getBackupSnapshotId();
if (backupOfSnapshot == null) {
return true;
}
SwiftTO swift = _swiftMgr.getSwiftTO(snapshot.getSwiftId());
S3TO s3 = _s3Mgr.getS3TO();
checkObjectStorageConfiguration(swift, s3);
DeleteSnapshotBackupCommand cmd = new DeleteSnapshotBackupCommand(
swift, s3, secondaryStoragePoolUrl, dcId, accountId, volumeId,
backupOfSnapshot, false);
Answer answer = _agentMgr.sendToSSVM(dcId, cmd);
if ((answer != null) && answer.getResult()) {
snapshot.setBackupSnapshotId(null);
_snapshotDao.update(snapshotId, snapshot);
success = true;
details = "Successfully deleted snapshot " + snapshotId + " for volumeId: " + volumeId;
s_logger.debug(details);
} else if (answer != null) {
details = "Failed to destroy snapshot id:" + snapshotId + " for volume: " + volumeId + " due to ";
if (answer.getDetails() != null) {
details += answer.getDetails();
}
s_logger.error(details);
}
return success;
}
@Override
public Pair<List<? extends Snapshot>, Integer> listSnapshots(ListSnapshotsCmd cmd) {
Long volumeId = cmd.getVolumeId();
@ -1161,7 +739,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
List<SnapshotVO> snapshots = listSnapsforVolume(volumeId);
for (SnapshotVO snapshot : snapshots) {
if (_snapshotDao.expunge(snapshot.getId())) {
if (snapshot.getType() == Type.MANUAL) {
if (snapshot.getRecurringType() == Type.MANUAL) {
_resourceLimitMgr.decrementResourceCount(accountId, ResourceType.snapshot);
}
@ -1271,8 +849,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
return policy;
}
@Override
public boolean deletePolicy(long userId, Long policyId) {
protected boolean deletePolicy(long userId, Long policyId) {
SnapshotPolicyVO snapshotPolicy = _snapshotPolicyDao.findById(policyId);
_snapSchedMgr.removeSchedule(snapshotPolicy.getVolumeId(), snapshotPolicy.getId());
return _snapshotPolicyDao.remove(policyId);
@ -1290,31 +867,16 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
return new Pair<List<? extends SnapshotPolicy>, Integer>(result.first(), result.second());
}
@Override
public List<SnapshotPolicyVO> listPoliciesforVolume(long volumeId) {
private List<SnapshotPolicyVO> listPoliciesforVolume(long volumeId) {
return _snapshotPolicyDao.listByVolumeId(volumeId);
}
@Override
public List<SnapshotPolicyVO> listPoliciesforSnapshot(long snapshotId) {
SearchCriteria<SnapshotPolicyVO> sc = PoliciesForSnapSearch.create();
sc.setJoinParameters("policyRef", "snapshotId", snapshotId);
return _snapshotPolicyDao.search(sc, null);
}
@Override
public List<SnapshotVO> listSnapsforPolicy(long policyId, Filter filter) {
SearchCriteria<SnapshotVO> sc = PolicySnapshotSearch.create();
sc.setJoinParameters("policy", "policyId", policyId);
return _snapshotDao.search(sc, filter);
}
@Override
public List<SnapshotVO> listSnapsforVolume(long volumeId) {
private List<SnapshotVO> listSnapsforVolume(long volumeId) {
return _snapshotDao.listByVolumeId(volumeId);
}
public List<SnapshotVO> listSnapsforVolumeType(long volumeId, Type type) {
private List<SnapshotVO> listSnapsforVolumeType(long volumeId, Type type) {
return _snapshotDao.listByVolumeIdType(volumeId, type);
}
@ -1333,9 +895,6 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
}
}
/**
* {@inheritDoc}
*/
@Override
public List<SnapshotScheduleVO> findRecurringSnapshotSchedule(ListRecurringSnapshotScheduleCmd cmd) {
Long volumeId = cmd.getVolumeId();
@ -1374,12 +933,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
return snapshotSchedules;
}
@Override
public SnapshotPolicyVO getPolicyForVolume(long volumeId) {
return _snapshotPolicyDao.findOneByVolume(volumeId);
}
public Type getSnapshotType(Long policyId) {
private Type getSnapshotType(Long policyId) {
if (policyId.equals(Snapshot.MANUAL_POLICY_ID)) {
return Type.MANUAL;
} else {
@ -1389,7 +943,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
}
}
public Type getSnapshotType(IntervalType intvType) {
private Type getSnapshotType(IntervalType intvType) {
if (intvType.equals(IntervalType.HOURLY)) {
return Type.HOURLY;
} else if (intvType.equals(IntervalType.DAILY)) {
@ -1489,15 +1043,11 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
Type.DAILY.setMax(NumbersUtil.parseInt(_configDao.getValue("snapshot.max.daily"), DAILYMAX));
Type.WEEKLY.setMax(NumbersUtil.parseInt(_configDao.getValue("snapshot.max.weekly"), WEEKLYMAX));
Type.MONTHLY.setMax(NumbersUtil.parseInt(_configDao.getValue("snapshot.max.monthly"), MONTHLYMAX));
_deltaSnapshotMax = NumbersUtil.parseInt(_configDao.getValue("snapshot.delta.max"), DELTAMAX);
_totalRetries = NumbersUtil.parseInt(_configDao.getValue("total.retries"), 4);
_pauseInterval = 2 * NumbersUtil.parseInt(_configDao.getValue("ping.interval"), 60);
s_logger.info("Snapshot Manager is configured.");
_snapshotFsm = Snapshot.State.getStateMachine();
_snapshotFsm.registerListener(new SnapshotStateListener());
return true;
}
@ -1558,24 +1108,6 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
return success;
}
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;
}
@Override
public boolean canOperateOnVolume(Volume volume) {
@ -1586,8 +1118,4 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
}
return true;
}
protected boolean stateTransitTo(Snapshot snapshot, Snapshot.Event e) throws NoTransitionException {
return _snapshotFsm.transitTo(snapshot, e, null, _snapshotDao);
}
}