Return-Path: X-Original-To: apmail-cloudstack-commits-archive@www.apache.org Delivered-To: apmail-cloudstack-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 161AA1056B for ; Tue, 30 Apr 2013 02:38:11 +0000 (UTC) Received: (qmail 48133 invoked by uid 500); 30 Apr 2013 02:38:11 -0000 Delivered-To: apmail-cloudstack-commits-archive@cloudstack.apache.org Received: (qmail 48090 invoked by uid 500); 30 Apr 2013 02:38:11 -0000 Mailing-List: contact commits-help@cloudstack.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@cloudstack.apache.org Delivered-To: mailing list commits@cloudstack.apache.org Received: (qmail 48057 invoked by uid 99); 30 Apr 2013 02:38:11 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 30 Apr 2013 02:38:11 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id F199D883E14; Tue, 30 Apr 2013 02:38:10 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: edison@apache.org To: commits@cloudstack.apache.org Date: Tue, 30 Apr 2013 02:38:10 -0000 Message-Id: X-Mailer: ASF-Git Admin Mailer Subject: [1/5] refactor snapshot Updated Branches: refs/heads/object_store 35264f708 -> 99dcb23b1 http://git-wip-us.apache.org/repos/asf/cloudstack/blob/37cbe889/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java ---------------------------------------------------------------------- diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java index 9f47e06..98527a9 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java @@ -141,58 +141,22 @@ public class XenServerStorageResource { } protected CreateObjectAnswer getTemplateSize(CreateObjectCommand cmd, String templateUrl) { - Connection conn = hypervisorResource.getConnection(); + /*Connection conn = hypervisorResource.getConnection(); long size = this.getTemplateSize(conn, templateUrl); - return new CreateObjectAnswer(cmd, templateUrl, size); + return new CreateObjectAnswer(cmd, templateUrl, size);*/ + return null; } protected CreateObjectAnswer execute(CreateObjectCommand cmd) { - String uriString = cmd.getObjectUri(); - DecodedDataObject obj = null; - - Connection conn = hypervisorResource.getConnection(); - VDI vdi = null; - boolean result = false; - String errorMsg = null; - - try { - obj = Decoder.decode(uriString); - - DecodedDataStore store = obj.getStore(); - if (obj.getObjType().equalsIgnoreCase("template") && store.getRole().equalsIgnoreCase("image")) { - return getTemplateSize(cmd, obj.getPath()); - } - - long size = obj.getSize(); - String name = obj.getName(); - String storeUuid = store.getUuid(); - SR primaryDataStoreSR = getSRByNameLabel(conn, storeUuid); - vdi = createVdi(conn, name, primaryDataStoreSR, size); - VDI.Record record = vdi.getRecord(conn); - result = true; - return new CreateObjectAnswer(cmd, record.uuid, record.virtualSize); - } catch (BadServerResponse e) { - s_logger.debug("Failed to create volume", e); - errorMsg = e.toString(); - } catch (XenAPIException e) { - s_logger.debug("Failed to create volume", e); - errorMsg = e.toString(); - } catch (XmlRpcException e) { - s_logger.debug("Failed to create volume", e); - errorMsg = e.toString(); - } catch (URISyntaxException e) { - s_logger.debug("Failed to create volume", e); - errorMsg = e.toString(); - } finally { - if (!result && vdi != null) { - try { - deleteVDI(conn, vdi); - } catch (Exception e) { - s_logger.debug("Faled to delete vdi: " + vdi.toString()); - } - } - } - - return new CreateObjectAnswer(cmd, false, errorMsg); + DataTO data = cmd.getData(); + try { + if (data.getObjectType() == DataObjectType.VOLUME) { + return createVolume(data); + } + return new CreateObjectAnswer("not supported type"); + } catch (Exception e) { + s_logger.debug("Failed to create object: " + data.getObjectType() + ": " + e.toString()); + return new CreateObjectAnswer(e.toString()); + } } protected Answer execute(DeleteVolumeCommand cmd) { @@ -735,20 +699,30 @@ public class XenServerStorageResource { return new CopyCmdAnswer("not implemented yet"); } - protected CreateObjectAnswer createVolume(DataTO data) { - /* + protected CreateObjectAnswer createVolume(DataTO data) throws BadServerResponse, XenAPIException, XmlRpcException { + VolumeObjectTO volume = (VolumeObjectTO)data; + + Connection conn = hypervisorResource.getConnection(); + PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)data.getDataStore(); + SR poolSr = hypervisorResource.getStorageRepository(conn, primaryStore.getUuid()); VDI.Record vdir = new VDI.Record(); - vdir.nameLabel = dskch.getName(); + vdir.nameLabel = volume.getName(); vdir.SR = poolSr; vdir.type = Types.VdiType.USER; - vdir.virtualSize = dskch.getSize(); + vdir.virtualSize = volume.getSize(); + VDI vdi; + vdi = VDI.create(conn, vdir); - VDI.Record vdir; vdir = vdi.getRecord(conn); - s_logger.debug("Succesfully created VDI for " + cmd + ". Uuid = " + vdir.uuid);*/ - return null; + VolumeObjectTO newVol = new VolumeObjectTO(); + newVol.setName(vdir.nameLabel); + newVol.setSize(vdir.virtualSize); + newVol.setPath(vdir.uuid); + + return new CreateObjectAnswer(newVol); } + protected CopyCmdAnswer cloneVolumeFromBaseTemplate(DataTO srcData, DataTO destData) { Connection conn = hypervisorResource.getConnection(); PrimaryDataStoreTO pool = (PrimaryDataStoreTO)destData.getDataStore(); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/37cbe889/plugins/storage/image/sample/src/org/apache/cloudstack/storage/datastore/driver/SampleImageStoreDriverImpl.java ---------------------------------------------------------------------- diff --git a/plugins/storage/image/sample/src/org/apache/cloudstack/storage/datastore/driver/SampleImageStoreDriverImpl.java b/plugins/storage/image/sample/src/org/apache/cloudstack/storage/datastore/driver/SampleImageStoreDriverImpl.java index 91f9cd0..e477b57 100644 --- a/plugins/storage/image/sample/src/org/apache/cloudstack/storage/datastore/driver/SampleImageStoreDriverImpl.java +++ b/plugins/storage/image/sample/src/org/apache/cloudstack/storage/datastore/driver/SampleImageStoreDriverImpl.java @@ -96,12 +96,12 @@ public class SampleImageStoreDriverImpl implements ImageStoreDriver { callback.complete(result); return; } - CreateObjectCommand createCmd = new CreateObjectCommand(data.getUri()); + CreateObjectCommand createCmd = new CreateObjectCommand(data.getTO()); CreateObjectAnswer answer = (CreateObjectAnswer)ep.sendMessage(createCmd); if (answer.getResult()) { //update imagestorevo - result = new CreateCmdResult(answer.getPath(), null); + result = new CreateCmdResult(null, null); } else { result.setResult(answer.getDetails()); } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/37cbe889/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java ---------------------------------------------------------------------- diff --git a/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java b/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java index ea4c561..5e82a7e 100644 --- a/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java +++ b/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java @@ -34,6 +34,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; +import org.apache.cloudstack.storage.command.CreateObjectCommand; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.volume.VolumeObject; import org.apache.log4j.Logger; @@ -108,46 +109,15 @@ public class CloudStackPrimaryDataStoreDriverImpl implements PrimaryDataStoreDri return null; } - public boolean createVolume( + public Answer createVolume( VolumeInfo volume) throws StorageUnavailableException { if (s_logger.isDebugEnabled()) { s_logger.debug("Creating volume: " + volume); } - - DiskOfferingVO offering = diskOfferingDao.findById(volume.getDiskOfferingId()); - DiskProfile diskProfile = new DiskProfile(volume, offering, - null); - - StoragePool pool = (StoragePool)volume.getDataStore(); - VolumeVO vol = volumeDao.findById(volume.getId()); - if (pool != null) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Trying to create in " + pool); - } - vol.setPoolId(pool.getId()); - - CreateCommand cmd = new CreateCommand(diskProfile, new StorageFilerTO( - pool)); - - Answer answer = storageMgr.sendToPool(pool, null, cmd); - if (answer.getResult()) { - CreateAnswer createAnswer = (CreateAnswer) answer; - vol.setFolder(pool.getPath()); - vol.setPath(createAnswer.getVolume().getPath()); - vol.setSize(createAnswer.getVolume().getSize()); - vol.setPoolType(pool.getPoolType()); - vol.setPoolId(pool.getId()); - vol.setPodId(pool.getPodId()); - this.volumeDao.update(vol.getId(), vol); - return true; - } - - } - - if (s_logger.isDebugEnabled()) { - s_logger.debug("Unable to create volume " + volume.getId()); - } - return false; + + CreateObjectCommand cmd = new CreateObjectCommand(volume.getTO()); + Answer answer = storageMgr.sendToPool((StoragePool)volume.getDataStore(), null, cmd); + return answer; } @Override @@ -155,9 +125,10 @@ public class CloudStackPrimaryDataStoreDriverImpl implements PrimaryDataStoreDri AsyncCompletionCallback callback) { // TODO Auto-generated method stub String errMsg = null; + Answer answer = null; if (data.getType() == DataObjectType.VOLUME) { try { - createVolume((VolumeInfo)data); + answer = createVolume((VolumeInfo)data); } catch (StorageUnavailableException e) { s_logger.debug("failed to create volume", e); errMsg = e.toString(); @@ -166,13 +137,12 @@ public class CloudStackPrimaryDataStoreDriverImpl implements PrimaryDataStoreDri errMsg = e.toString(); } } - CreateCmdResult result = new CreateCmdResult(null, null); + CreateCmdResult result = new CreateCmdResult(null, answer); if (errMsg != null) { result.setResult(errMsg); } callback.complete(result); - } @Override http://git-wip-us.apache.org/repos/asf/cloudstack/blob/37cbe889/server/src/com/cloud/storage/CreateSnapshotPayload.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/storage/CreateSnapshotPayload.java b/server/src/com/cloud/storage/CreateSnapshotPayload.java new file mode 100644 index 0000000..cafe46c --- /dev/null +++ b/server/src/com/cloud/storage/CreateSnapshotPayload.java @@ -0,0 +1,14 @@ +package com.cloud.storage; + +public class CreateSnapshotPayload { + private Long snapshotPolicyId; + + public Long getSnapshotPolicyId() { + return snapshotPolicyId; + } + + public void setSnapshotPolicyId(Long snapshotPolicyId) { + this.snapshotPolicyId = snapshotPolicyId; + } + +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/37cbe889/server/src/com/cloud/storage/StorageManagerImpl.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index e615967..05b2257 100755 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -1931,7 +1931,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C _accountMgr.checkAccessAndSpecifyAuthority(UserContext.current().getCaller(), store.getDataCenterId()); // Verify that there are no live snapshot, template, volume on the image store to be deleted - List snapshots = _snapshotStoreDao.listByStoreId(storeId); + List snapshots = _snapshotStoreDao.listByStoreId(storeId, DataStoreRole.Image); if ( snapshots != null && snapshots.size() > 0 ){ throw new CloudRuntimeException("Cannot delete image store with active snapshots backup!"); } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/37cbe889/server/src/com/cloud/storage/VolumeManagerImpl.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/storage/VolumeManagerImpl.java b/server/src/com/cloud/storage/VolumeManagerImpl.java index 57241b1..3177a59 100644 --- a/server/src/com/cloud/storage/VolumeManagerImpl.java +++ b/server/src/com/cloud/storage/VolumeManagerImpl.java @@ -85,6 +85,7 @@ import com.cloud.configuration.Resource.ResourceType; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.consoleproxy.ConsoleProxyManager; import com.cloud.dc.ClusterVO; +import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenterVO; import com.cloud.dc.HostPodVO; import com.cloud.dc.dao.ClusterDao; @@ -166,6 +167,7 @@ import com.cloud.vm.dao.DomainRouterDao; import com.cloud.vm.dao.SecondaryStorageVmDao; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; +import com.cloud.vm.snapshot.VMSnapshot; import com.cloud.vm.snapshot.VMSnapshotVO; import com.cloud.vm.snapshot.dao.VMSnapshotDao; @@ -2463,5 +2465,47 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { throw new CloudRuntimeException("Failed to destroy volume" + volume.getId(), e); } } + + + + + @Override + public Snapshot takeSnapshot(Long volumeId, Long policyId) throws ResourceAllocationException { + Account caller = UserContext.current().getCaller(); + + VolumeInfo volume = this.volFactory.getVolume(volumeId); + if (volume == null) { + throw new InvalidParameterValueException("Creating snapshot failed due to volume:" + volumeId + " doesn't exist"); + } + DataCenter zone = _dcDao.findById(volume.getDataCenterId()); + if (zone == null) { + throw new InvalidParameterValueException("Can't find zone by id " + volume.getDataCenterId()); + } + + if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getType())) { + throw new PermissionDeniedException("Cannot perform this operation, Zone is currently disabled: " + zone.getName()); + } + + if (volume.getState() != Volume.State.Ready) { + throw new InvalidParameterValueException("VolumeId: " + volumeId + " is not in " + Volume.State.Ready + " state but " + volume.getState() + ". Cannot take snapshot."); + } + + if ( volume.getTemplateId() != null ) { + VMTemplateVO template = _templateDao.findById(volume.getTemplateId()); + if( template != null && template.getTemplateType() == Storage.TemplateType.SYSTEM ) { + throw new InvalidParameterValueException("VolumeId: " + volumeId + " is for System VM , Creating snapshot against System VM volumes is not supported"); + } + } + + StoragePool storagePool = (StoragePool)volume.getDataStore(); + if (storagePool == null) { + throw new InvalidParameterValueException("VolumeId: " + volumeId + " please attach this volume to a VM before create snapshot for it"); + } + + CreateSnapshotPayload payload = new CreateSnapshotPayload(); + payload.setSnapshotPolicyId(policyId); + return this.volService.takeSnapshot(volume); + + } } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/37cbe889/server/src/com/cloud/storage/dao/SnapshotDao.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/storage/dao/SnapshotDao.java b/server/src/com/cloud/storage/dao/SnapshotDao.java index e6aecc7..46f2fa9 100644 --- a/server/src/com/cloud/storage/dao/SnapshotDao.java +++ b/server/src/com/cloud/storage/dao/SnapshotDao.java @@ -16,6 +16,7 @@ // under the License. package com.cloud.storage.dao; +import com.cloud.storage.DataStoreRole; import com.cloud.storage.Snapshot; import com.cloud.storage.Snapshot.Type; import com.cloud.storage.SnapshotVO; @@ -29,7 +30,7 @@ public interface SnapshotDao extends GenericDao, StateDao listByVolumeId(long volumeId); List listByVolumeId(Filter filter, long volumeId); SnapshotVO findNextSnapshot(long parentSnapId); - long getLastSnapshot(long volumeId, long snapId); + long getLastSnapshot(long volumeId, DataStoreRole role); List listByVolumeIdType(long volumeId, Type type); List listByVolumeIdIncludingRemoved(long volumeId); List listByBackupUuid(long volumeId, String backupUuid); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/37cbe889/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java b/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java index 2dd5da1..24d4c65 100644 --- a/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java +++ b/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java @@ -28,6 +28,7 @@ import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import com.cloud.server.ResourceTag.TaggedResourceType; +import com.cloud.storage.DataStoreRole; import com.cloud.storage.Snapshot; import com.cloud.storage.Snapshot.Event; import com.cloud.storage.Snapshot.State; @@ -55,7 +56,7 @@ import com.cloud.vm.dao.VMInstanceDao; public class SnapshotDaoImpl extends GenericDaoBase implements SnapshotDao { public static final Logger s_logger = Logger.getLogger(SnapshotDaoImpl.class.getName()); //TODO: we should remove these direct sqls - private static final String GET_LAST_SNAPSHOT = "SELECT id FROM snapshots where volume_id = ? AND id != ? AND path IS NOT NULL ORDER BY created DESC"; + private static final String GET_LAST_SNAPSHOT = "SELECT snapshots.id FROM snapshot_store_ref, snapshots where snapshots.id = snapshot_store_ref.snapshot_id AND snapshosts.volume_id = ? AND snapshot_store_ref.role = ? ORDER BY created DESC"; private static final String UPDATE_SNAPSHOT_VERSION = "UPDATE snapshots SET version = ? WHERE volume_id = ? AND version = ?"; private static final String GET_SECHOST_ID = "SELECT store_id FROM snapshots, snapshot_store_ref where snapshots.id = snapshot_store_ref.snapshot_id AND volume_id = ? AND backup_snap_id IS NOT NULL AND sechost_id IS NOT NULL LIMIT 1"; private static final String UPDATE_SECHOST_ID = "UPDATE snapshots SET sechost_id = ? WHERE data_center_id = ?"; @@ -212,14 +213,14 @@ public class SnapshotDaoImpl extends GenericDaoBase implements return null; } @Override - public long getLastSnapshot(long volumeId, long snapId) { + public long getLastSnapshot(long volumeId, DataStoreRole role) { Transaction txn = Transaction.currentTxn(); PreparedStatement pstmt = null; String sql = GET_LAST_SNAPSHOT; try { pstmt = txn.prepareAutoCloseStatement(sql); pstmt.setLong(1, volumeId); - pstmt.setLong(2, snapId); + pstmt.setString(2, role.toString()); ResultSet rs = pstmt.executeQuery(); if (rs.next()) { return rs.getLong(1); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/37cbe889/server/src/com/cloud/storage/snapshot/SnapshotManager.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/storage/snapshot/SnapshotManager.java b/server/src/com/cloud/storage/snapshot/SnapshotManager.java index 8181330..983b50c 100755 --- a/server/src/com/cloud/storage/snapshot/SnapshotManager.java +++ b/server/src/com/cloud/storage/snapshot/SnapshotManager.java @@ -18,6 +18,7 @@ package com.cloud.storage.snapshot; import java.util.List; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import com.cloud.agent.api.Answer; @@ -68,7 +69,10 @@ public interface SnapshotManager { Answer sendToPool(Volume vol, Command cmd); - SnapshotVO getParentSnapshot(VolumeInfo volume, Snapshot snapshot); + SnapshotVO getParentSnapshot(VolumeInfo volume); Snapshot backupSnapshot(Long snapshotId); + + SnapshotInfo takeSnapshot(VolumeInfo volume) + throws ResourceAllocationException; } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/37cbe889/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java index 11408f9..c18ffa8 100755 --- a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java +++ b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java @@ -38,6 +38,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotService; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotStrategy; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; @@ -82,7 +83,9 @@ import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.org.Grouping; import com.cloud.projects.Project.ListProjectResourcesCriteria; +import com.cloud.resource.ResourceManager; import com.cloud.server.ResourceTag.TaggedResourceType; +import com.cloud.storage.CreateSnapshotPayload; import com.cloud.storage.Snapshot; import com.cloud.storage.Snapshot.Type; import com.cloud.storage.DataStoreRole; @@ -128,8 +131,12 @@ import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.UserVmVO; import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.dao.UserVmDao; +import com.cloud.vm.snapshot.VMSnapshot; +import com.cloud.vm.snapshot.VMSnapshotVO; import com.cloud.vm.snapshot.dao.VMSnapshotDao; @Component @@ -202,6 +209,10 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, @Inject VolumeDataFactory volFactory; @Inject SnapshotDataFactory snapshotFactory; @Inject EndPointSelector _epSelector; + @Inject + private ResourceManager _resourceMgr; + @Inject + protected List snapshotStrategies; private int _totalRetries; @@ -278,32 +289,25 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, throw new InvalidParameterValueException("Volume is not in ready state"); } - SnapshotInfo snapshot = null; - + boolean backedUp = false; // does the caller have the authority to act on this volume _accountMgr.checkAccess(UserContext.current().getCaller(), null, true, volume); - - SnapshotInfo snap = this.snapshotFactory.getSnapshot(snapshotId); + SnapshotInfo snapshot = this.snapshotFactory.getSnapshot(snapshotId, DataStoreRole.Primary); try { - snapshot = this.snapshotSrv.takeSnapshot(volume, snapshotId); - if (snapshot != null) { - postCreateSnapshot(volumeId, snapshot.getId(), policyId); - //Check if the snapshot was removed while backingUp. If yes, do not log snapshot create usage event - SnapshotVO freshSnapshot = _snapshotDao.findById(snapshot.getId()); - if ((freshSnapshot != null) && backedUp) { - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_CREATE, snapshot.getAccountId(), - snapshot.getDataCenterId(), snapshotId, snapshot.getName(), null, null, - volume.getSize(), snapshot.getClass().getName(), snapshot.getUuid()); - } - - _resourceLimitMgr.incrementResourceCount(snapshotOwner.getId(), ResourceType.snapshot); - } - if (backup) { - this.backupSnapshot(snapshotId); + 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); + } catch(Exception e) { s_logger.debug("Failed to create snapshot", e); if (backup) { @@ -337,16 +341,11 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, @Override public Snapshot backupSnapshot(Long snapshotId) { - SnapshotInfo snapshot = this.snapshotFactory.getSnapshot(snapshotId); - if (snapshot == null) { - throw new CloudRuntimeException("Can't find snapshot:" + snapshotId); - } - - if (snapshot.getState() == Snapshot.State.BackedUp) { - return snapshot; + SnapshotInfo snapshot = this.snapshotFactory.getSnapshot(snapshotId, DataStoreRole.Image); + if (snapshot != null) { + throw new CloudRuntimeException("Already in the backup snapshot:" + snapshotId); } - return this.snapshotSrv.backupSnapshot(snapshot); } @@ -436,8 +435,8 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, } @Override - public SnapshotVO getParentSnapshot(VolumeInfo volume, Snapshot snapshot) { - long preId = _snapshotDao.getLastSnapshot(volume.getId(), snapshot.getId()); + public SnapshotVO getParentSnapshot(VolumeInfo volume) { + long preId = _snapshotDao.getLastSnapshot(volume.getId(), DataStoreRole.Primary); SnapshotVO preSnapshotVO = null; if (preId != 0 && !(volume.getLastPoolId() != null && !volume.getLastPoolId().equals(volume.getPoolId()))) { @@ -500,15 +499,21 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, Account caller = UserContext.current().getCaller(); // Verify parameters - SnapshotInfo snapshotCheck = this.snapshotFactory.getSnapshot(snapshotId); + SnapshotVO snapshotCheck = this._snapshotDao.findById(snapshotId); if (snapshotCheck == null) { throw new InvalidParameterValueException("unable to find a snapshot with id " + snapshotId); } _accountMgr.checkAccess(caller, null, true, snapshotCheck); - + SnapshotStrategy snapshotStrategy = null; + for (SnapshotStrategy strategy : this.snapshotStrategies) { + if (strategy.canHandle(snapshotCheck)) { + snapshotStrategy = strategy; + break; + } + } try { - boolean result = this.snapshotSrv.deleteSnapshot(snapshotCheck); + boolean result = snapshotStrategy.deleteSnapshot(snapshotId); if (result) { if (snapshotCheck.getState() == Snapshot.State.BackedUp) { UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_DELETE, snapshotCheck.getAccountId(), @@ -529,7 +534,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, @Override public String getSecondaryStorageURL(SnapshotVO snapshot) { - SnapshotDataStoreVO snapshotStore = this._snapshotStoreDao.findBySnapshot(snapshot.getId()); + SnapshotDataStoreVO snapshotStore = this._snapshotStoreDao.findBySnapshot(snapshot.getId(), DataStoreRole.Image); if (snapshotStore != null){ DataStore store = this.dataStoreMgr.getDataStore(snapshotStore.getDataStoreId(), DataStoreRole.Image); if ( store != null ){ @@ -904,44 +909,76 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, return null; } - @Override - public SnapshotVO allocSnapshot(Long volumeId, Long policyId) throws ResourceAllocationException { - Account caller = UserContext.current().getCaller(); - - VolumeVO volume = _volsDao.findById(volumeId); - if (volume == null) { - throw new InvalidParameterValueException("Creating snapshot failed due to volume:" + volumeId + " doesn't exist"); - } - DataCenter zone = _dcDao.findById(volume.getDataCenterId()); - if (zone == null) { - throw new InvalidParameterValueException("Can't find zone by id " + volume.getDataCenterId()); - } - - if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getType())) { - throw new PermissionDeniedException("Cannot perform this operation, Zone is currently disabled: " + zone.getName()); - } - - if (volume.getState() != Volume.State.Ready) { - throw new InvalidParameterValueException("VolumeId: " + volumeId + " is not in " + Volume.State.Ready + " state but " + volume.getState() + ". Cannot take snapshot."); - } - - if ( volume.getTemplateId() != null ) { - VMTemplateVO template = _templateDao.findById(volume.getTemplateId()); - if( template != null && template.getTemplateType() == Storage.TemplateType.SYSTEM ) { - throw new InvalidParameterValueException("VolumeId: " + volumeId + " is for System VM , Creating snapshot against System VM volumes is not supported"); - } - } - - StoragePoolVO storagePoolVO = _storagePoolDao.findById(volume.getPoolId()); - if (storagePoolVO == null) { - throw new InvalidParameterValueException("VolumeId: " + volumeId + " please attach this volume to a VM before create snapshot for it"); - } - - ClusterVO cluster = _clusterDao.findById(storagePoolVO.getClusterId()); + + + 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; + } + + private boolean supportedByHypervisor(VolumeInfo volume) { + StoragePool storagePool = (StoragePool)volume.getDataStore(); + ClusterVO cluster = _clusterDao.findById(storagePool.getClusterId()); if (cluster != null && cluster.getHypervisorType() == HypervisorType.Ovm) { throw new InvalidParameterValueException("Ovm won't support taking snapshot"); } - + + if (volume.getHypervisorType().equals(HypervisorType.KVM)) { + List 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 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 activeVMSnapshots = _vmSnapshotDao.listByInstanceId(userVm.getId(), + VMSnapshot.State.Creating, VMSnapshot.State.Reverting, VMSnapshot.State.Expunging); + if (activeVMSnapshots.size() > 0) { + throw new CloudRuntimeException( + "There is other active vm snapshot tasks on the instance to which the volume is attached, please try again later"); + } + } + } + + return true; + } + @Override + public SnapshotInfo takeSnapshot(VolumeInfo volume) throws ResourceAllocationException { + Account caller = UserContext.current().getCaller(); + + supportedByHypervisor(volume); + CreateSnapshotPayload snapInfo = (CreateSnapshotPayload)volume.getpayload(); + Long policyId = snapInfo.getSnapshotPolicyId(); // Verify permissions _accountMgr.checkAccess(caller, null, true, volume); Type snapshotType = getSnapshotType(policyId); @@ -975,14 +1012,13 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, } String snapshotName = vmDisplayName + "_" + volume.getName() + "_" + timeString; - // Create the Snapshot object and save it so we can return it to the - // user - HypervisorType hypervisorType = this._volsDao.getHypervisorType(volumeId); - SnapshotVO snapshotVO = new SnapshotVO(volume.getDataCenterId(), volume.getAccountId(), volume.getDomainId(), volume.getId(), volume.getDiskOfferingId(), null, snapshotName, + HypervisorType hypervisorType = volume.getHypervisorType(); + SnapshotVO snapshotVO = new SnapshotVO(volume.getDataCenterId(), volume.getAccountId(), volume.getDomainId(), volume.getId(), volume.getDiskOfferingId(), snapshotName, (short) snapshotType.ordinal(), snapshotType.name(), volume.getSize(), hypervisorType); + SnapshotVO snapshot = _snapshotDao.persist(snapshotVO); if (snapshot == null) { - throw new CloudRuntimeException("Failed to create snapshot for volume: "+volumeId); + throw new CloudRuntimeException("Failed to create snapshot for volume: " + volume.getId()); } if (backup) { _resourceLimitMgr.incrementResourceCount(volume.getAccountId(), ResourceType.secondary_storage, @@ -991,7 +1027,19 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, _resourceLimitMgr.incrementResourceCount(volume.getAccountId(), ResourceType.primary_storage, new Long(volume.getSize())); } - return snapshot; + SnapshotInfo snap = this.snapshotFactory.getSnapshot(snapshot.getId(), volume.getDataStore()); + boolean processed = false; + for (SnapshotStrategy strategy : snapshotStrategies) { + if (strategy.canHandle(snap)) { + processed = true; + snap = strategy.takeSnapshot(snap); + break; + } + } + if (!processed) { + throw new CloudRuntimeException("Can't find snapshot strategy to deal with snapshot:" + snapshot.getId()); + } + return snap; } @Override