mirror of https://github.com/apache/cloudstack.git
refactor snapshot, move existing snapshot code into its own snapshotstrategy
This commit is contained in:
parent
020be66f9d
commit
ff047e75d3
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ public interface ObjectInDataStoreStateMachine extends StateObject<ObjectInDataS
|
|||
OperationSuccessed,
|
||||
OperationFailed,
|
||||
CopyingRequested,
|
||||
ResizeRequested,
|
||||
ExpungeRequested
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue