mirror of
				https://github.com/apache/cloudstack.git
				synced 2025-10-26 08:42:29 +01:00 
			
		
		
		
	Adding support for creating a volume from a snapshot when the snapshot is on managed storage
This commit is contained in:
		
							parent
							
								
									240e8ef8ac
								
							
						
					
					
						commit
						0f84e042b9
					
				| @ -29,8 +29,9 @@ public final class CopyCommand extends Command implements StorageSubSystemComman | ||||
|     private DataTO srcTO; | ||||
|     private DataTO destTO; | ||||
|     private DataTO cacheTO; | ||||
|     boolean executeInSequence = false; | ||||
|     Map<String, String> options = new HashMap<String, String>(); | ||||
|     private boolean executeInSequence = false; | ||||
|     private Map<String, String> options = new HashMap<String, String>(); | ||||
|     private Map<String, String> options2 = new HashMap<String, String>(); | ||||
| 
 | ||||
|     public CopyCommand(DataTO srcData, DataTO destData, int timeout, boolean executeInSequence) { | ||||
|         super(); | ||||
| @ -81,6 +82,14 @@ public final class CopyCommand extends Command implements StorageSubSystemComman | ||||
|         return options; | ||||
|     } | ||||
| 
 | ||||
|     public void setOptions2(Map<String, String> options2) { | ||||
|         this.options2 = options2; | ||||
|     } | ||||
| 
 | ||||
|     public Map<String, String> getOptions2() { | ||||
|         return options2; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void setExecuteInSequence(boolean inSeq) { | ||||
|         this.executeInSequence = inSeq; | ||||
|  | ||||
| @ -125,4 +125,5 @@ public interface VolumeOrchestrationService { | ||||
| 
 | ||||
|     void updateVolumeDiskChain(long volumeId, String path, String chainInfo); | ||||
| 
 | ||||
|     VolumeInfo updateHypervisorSnapshotReserveForVolume(DiskOffering diskOffering, VolumeInfo volumeInfo, HypervisorType hyperType); | ||||
| } | ||||
|  | ||||
| @ -36,6 +36,7 @@ import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationSer | ||||
| import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo; | ||||
| 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.DataStoreCapabilities; | ||||
| import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver; | ||||
| import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; | ||||
| import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore; | ||||
| @ -59,6 +60,7 @@ import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO; | ||||
| import org.apache.cloudstack.storage.command.CommandResult; | ||||
| import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; | ||||
| import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; | ||||
| import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO; | ||||
| import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; | ||||
| import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; | ||||
| import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO; | ||||
| @ -374,16 +376,23 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati | ||||
| 
 | ||||
|         VolumeInfo vol = volFactory.getVolume(volume.getId()); | ||||
|         DataStore store = dataStoreMgr.getDataStore(pool.getId(), DataStoreRole.Primary); | ||||
|         SnapshotInfo snapInfo = snapshotFactory.getSnapshot(snapshot.getId(), DataStoreRole.Image); | ||||
|         // sync snapshot to region store if necessary | ||||
|         DataStore snapStore = snapInfo.getDataStore(); | ||||
|         long snapVolId = snapInfo.getVolumeId(); | ||||
|         try { | ||||
|             _snapshotSrv.syncVolumeSnapshotsToRegionStore(snapVolId, snapStore); | ||||
|         } catch (Exception ex) { | ||||
|             // log but ignore the sync error to avoid any potential S3 down issue, it should be sync next time | ||||
|             s_logger.warn(ex.getMessage(), ex); | ||||
|         DataStoreRole dataStoreRole = getDataStoreRole(snapshot); | ||||
|         SnapshotInfo snapInfo = snapshotFactory.getSnapshot(snapshot.getId(), dataStoreRole); | ||||
| 
 | ||||
|         // don't try to perform a sync if the DataStoreRole of the snapshot is equal to DataStoreRole.Primary | ||||
|         if (!DataStoreRole.Primary.equals(dataStoreRole)) { | ||||
|             try { | ||||
|                 // sync snapshot to region store if necessary | ||||
|                 DataStore snapStore = snapInfo.getDataStore(); | ||||
|                 long snapVolId = snapInfo.getVolumeId(); | ||||
| 
 | ||||
|                 _snapshotSrv.syncVolumeSnapshotsToRegionStore(snapVolId, snapStore); | ||||
|             } catch (Exception ex) { | ||||
|                 // log but ignore the sync error to avoid any potential S3 down issue, it should be sync next time | ||||
|                 s_logger.warn(ex.getMessage(), ex); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // create volume on primary from snapshot | ||||
|         AsyncCallFuture<VolumeApiResult> future = volService.createVolumeFromSnapshot(vol, store, snapInfo); | ||||
|         try { | ||||
| @ -403,6 +412,30 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public DataStoreRole getDataStoreRole(Snapshot snapshot) { | ||||
|         SnapshotDataStoreVO snapshotStore = _snapshotDataStoreDao.findBySnapshot(snapshot.getId(), DataStoreRole.Primary); | ||||
| 
 | ||||
|         if (snapshotStore == null) { | ||||
|             return DataStoreRole.Image; | ||||
|         } | ||||
| 
 | ||||
|         long storagePoolId = snapshotStore.getDataStoreId(); | ||||
|         DataStore dataStore = dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); | ||||
| 
 | ||||
|         Map<String, String> mapCapabilities = dataStore.getDriver().getCapabilities(); | ||||
| 
 | ||||
|         if (mapCapabilities != null) { | ||||
|             String value = mapCapabilities.get(DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT.toString()); | ||||
|             Boolean supportsStorageSystemSnapshots = new Boolean(value); | ||||
| 
 | ||||
|             if (supportsStorageSystemSnapshots) { | ||||
|                 return DataStoreRole.Primary; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return DataStoreRole.Image; | ||||
|     } | ||||
| 
 | ||||
|     protected DiskProfile createDiskCharacteristics(VolumeInfo volume, VirtualMachineTemplate template, DataCenter dc, DiskOffering diskOffering) { | ||||
|         if (volume.getVolumeType() == Type.ROOT && Storage.ImageFormat.ISO != template.getFormat()) { | ||||
|             TemplateDataStoreVO ss = _vmTemplateStoreDao.findByTemplateZoneDownloadStatus(template.getId(), dc.getId(), VMTemplateStorageResourceAssoc.Status.DOWNLOADED); | ||||
| @ -517,7 +550,8 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati | ||||
|     // The disk offering can collect this information and pass it on to the volume that's about to be created. | ||||
|     // Ex. if you want a 10 GB CloudStack volume to reside on managed storage on Xen, this leads to an SR | ||||
|     // that is a total size of (10 GB * (hypervisorSnapshotReserveSpace / 100) + 10 GB). | ||||
|     private VolumeInfo updateHypervisorSnapshotReserveForVolume(DiskOffering diskOffering, VolumeInfo volumeInfo, HypervisorType hyperType) { | ||||
|     @Override | ||||
|     public VolumeInfo updateHypervisorSnapshotReserveForVolume(DiskOffering diskOffering, VolumeInfo volumeInfo, HypervisorType hyperType) { | ||||
|         Integer hypervisorSnapshotReserve = diskOffering.getHypervisorSnapshotReserve(); | ||||
| 
 | ||||
|         if (hyperType == HypervisorType.KVM) { | ||||
|  | ||||
| @ -92,12 +92,18 @@ public class SnapshotVO implements Snapshot { | ||||
|     @Column(name = "uuid") | ||||
|     String uuid; | ||||
| 
 | ||||
|     @Column(name = "min_iops") | ||||
|     Long minIops; | ||||
| 
 | ||||
|     @Column(name = "max_iops") | ||||
|     Long maxIops; | ||||
| 
 | ||||
|     public SnapshotVO() { | ||||
|         uuid = UUID.randomUUID().toString(); | ||||
|     } | ||||
| 
 | ||||
|     public SnapshotVO(long dcId, long accountId, long domainId, Long volumeId, Long diskOfferingId, String name, short snapshotType, String typeDescription, long size, | ||||
|             HypervisorType hypervisorType) { | ||||
|             Long minIops, Long maxIops, HypervisorType hypervisorType) { | ||||
|         dataCenterId = dcId; | ||||
|         this.accountId = accountId; | ||||
|         this.domainId = domainId; | ||||
| @ -107,6 +113,8 @@ public class SnapshotVO implements Snapshot { | ||||
|         this.snapshotType = snapshotType; | ||||
|         this.typeDescription = typeDescription; | ||||
|         this.size = size; | ||||
|         this.minIops = minIops; | ||||
|         this.maxIops = maxIops; | ||||
|         state = State.Allocated; | ||||
|         this.hypervisorType = hypervisorType; | ||||
|         version = "2.2"; | ||||
| @ -184,6 +192,14 @@ public class SnapshotVO implements Snapshot { | ||||
|         return size; | ||||
|     } | ||||
| 
 | ||||
|     public Long getMinIops() { | ||||
|         return minIops; | ||||
|     } | ||||
| 
 | ||||
|     public Long getMaxIops() { | ||||
|         return maxIops; | ||||
|     } | ||||
| 
 | ||||
|     public String getTypeDescription() { | ||||
|         return typeDescription; | ||||
|     } | ||||
|  | ||||
| @ -164,7 +164,7 @@ public class VolumeVO implements Volume { | ||||
|     String reservationId; | ||||
| 
 | ||||
|     @Column(name = "hv_ss_reserve") | ||||
|     Integer hypervisorSnapshotReserve; | ||||
|     private Integer hypervisorSnapshotReserve; | ||||
| 
 | ||||
|     // Real Constructor | ||||
|     public VolumeVO(Type type, String name, long dcId, long domainId, | ||||
| @ -628,7 +628,6 @@ public class VolumeVO implements Volume { | ||||
|     @Override | ||||
|     public Integer getHypervisorSnapshotReserve() { | ||||
|         return hypervisorSnapshotReserve; | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|  | ||||
| @ -27,6 +27,8 @@ import javax.inject.Inject; | ||||
| import org.apache.log4j.Logger; | ||||
| import org.springframework.stereotype.Component; | ||||
| 
 | ||||
| import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService; | ||||
| import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo; | ||||
| import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; | ||||
| import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy; | ||||
| import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; | ||||
| @ -34,8 +36,13 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; | ||||
| import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities; | ||||
| import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; | ||||
| import org.apache.cloudstack.engine.subsystem.api.storage.StrategyPriority; | ||||
| import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; | ||||
| 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.VolumeService; | ||||
| import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; | ||||
| import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService.VolumeApiResult; | ||||
| import org.apache.cloudstack.framework.async.AsyncCallFuture; | ||||
| import org.apache.cloudstack.framework.async.AsyncCompletionCallback; | ||||
| import org.apache.cloudstack.framework.config.dao.ConfigurationDao; | ||||
| import org.apache.cloudstack.storage.command.CopyCommand; | ||||
| @ -56,8 +63,15 @@ import com.cloud.org.Grouping.AllocationState; | ||||
| import com.cloud.resource.ResourceState; | ||||
| import com.cloud.server.ManagementService; | ||||
| import com.cloud.storage.DataStoreRole; | ||||
| import com.cloud.storage.DiskOfferingVO; | ||||
| import com.cloud.storage.SnapshotVO; | ||||
| import com.cloud.storage.VolumeVO; | ||||
| import com.cloud.storage.Storage.ImageFormat; | ||||
| import com.cloud.storage.dao.DiskOfferingDao; | ||||
| import com.cloud.storage.dao.SnapshotDao; | ||||
| import com.cloud.storage.dao.SnapshotDetailsDao; | ||||
| import com.cloud.storage.dao.SnapshotDetailsVO; | ||||
| import com.cloud.storage.dao.VolumeDao; | ||||
| import com.cloud.utils.NumbersUtil; | ||||
| import com.cloud.utils.exception.CloudRuntimeException; | ||||
| import com.cloud.vm.VirtualMachineManager; | ||||
| @ -68,16 +82,30 @@ public class StorageSystemDataMotionStrategy implements DataMotionStrategy { | ||||
| 
 | ||||
|     @Inject private AgentManager _agentMgr; | ||||
|     @Inject private ConfigurationDao _configDao; | ||||
|     @Inject private DiskOfferingDao _diskOfferingDao; | ||||
|     @Inject private HostDao _hostDao; | ||||
|     @Inject private ManagementService _mgr; | ||||
|     @Inject private PrimaryDataStoreDao _storagePoolDao; | ||||
|     @Inject private SnapshotDao _snapshotDao; | ||||
|     @Inject private SnapshotDetailsDao _snapshotDetailsDao; | ||||
|     @Inject private VolumeService _volService; | ||||
|     @Inject private VolumeDao _volumeDao; | ||||
|     @Inject private VolumeDataFactory _volumeDataFactory; | ||||
|     @Inject private VolumeOrchestrationService _volumeMgr; | ||||
|     @Inject private VolumeService _volumeService; | ||||
| 
 | ||||
|     @Override | ||||
|     public StrategyPriority canHandle(DataObject srcData, DataObject destData) { | ||||
|         if (srcData instanceof SnapshotInfo && destData.getDataStore().getRole() == DataStoreRole.Image || destData.getDataStore().getRole() == DataStoreRole.ImageCache) { | ||||
|             DataStore dataStore = srcData.getDataStore(); | ||||
|         if (srcData instanceof SnapshotInfo) { | ||||
|             if (canHandle(srcData.getDataStore()) || canHandle(destData.getDataStore())) { | ||||
|                 return StrategyPriority.HIGHEST; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return StrategyPriority.CANT_HANDLE; | ||||
|     } | ||||
| 
 | ||||
|     private boolean canHandle(DataStore dataStore) { | ||||
|         if (dataStore.getRole() == DataStoreRole.Primary) { | ||||
|             Map<String, String> mapCapabilities = dataStore.getDriver().getCapabilities(); | ||||
| 
 | ||||
|             if (mapCapabilities != null) { | ||||
| @ -87,12 +115,12 @@ public class StorageSystemDataMotionStrategy implements DataMotionStrategy { | ||||
|                 if (supportsStorageSystemSnapshots) { | ||||
|                     s_logger.info("Using 'StorageSystemDataMotionStrategy'"); | ||||
| 
 | ||||
|                     return StrategyPriority.HIGHEST; | ||||
|                     return true; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return StrategyPriority.CANT_HANDLE; | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
| @ -102,75 +130,207 @@ public class StorageSystemDataMotionStrategy implements DataMotionStrategy { | ||||
| 
 | ||||
|     @Override | ||||
|     public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) { | ||||
|         if (srcData instanceof SnapshotInfo && destData.getDataStore().getRole() == DataStoreRole.Image || destData.getDataStore().getRole() == DataStoreRole.ImageCache) { | ||||
|         if (srcData instanceof SnapshotInfo) { | ||||
|             SnapshotInfo snapshotInfo = (SnapshotInfo)srcData; | ||||
|             HostVO hostVO = getHost(srcData); | ||||
|             DataStore srcDataStore = srcData.getDataStore(); | ||||
| 
 | ||||
|             String value = _configDao.getValue(Config.PrimaryStorageDownloadWait.toString()); | ||||
|             int primaryStorageDownloadWait = NumbersUtil.parseInt(value, Integer.parseInt(Config.PrimaryStorageDownloadWait.getDefaultValue())); | ||||
|             CopyCommand copyCommand = new CopyCommand(srcData.getTO(), destData.getTO(), primaryStorageDownloadWait, VirtualMachineManager.ExecuteInSequence.value()); | ||||
|             validate(snapshotInfo); | ||||
| 
 | ||||
|             CopyCmdAnswer copyCmdAnswer = null; | ||||
|             boolean canHandleSrc = canHandle(srcData.getDataStore()); | ||||
| 
 | ||||
|             if (canHandleSrc && destData instanceof TemplateInfo && | ||||
|                     (destData.getDataStore().getRole() == DataStoreRole.Image || destData.getDataStore().getRole() == DataStoreRole.ImageCache)) { | ||||
|                 return handleCreateTemplateFromSnapshot(snapshotInfo, (TemplateInfo)destData, callback); | ||||
|             } | ||||
| 
 | ||||
|             if (destData instanceof VolumeInfo) { | ||||
|                 VolumeInfo volumeInfo = (VolumeInfo)destData; | ||||
| 
 | ||||
|                 boolean canHandleDest = canHandle(destData.getDataStore()); | ||||
| 
 | ||||
|                 if (canHandleSrc && canHandleDest) { | ||||
|                     return handleCreateVolumeFromSnapshotBothOnStorageSystem(snapshotInfo, volumeInfo, callback); | ||||
|                 } | ||||
| 
 | ||||
|                 if (canHandleSrc) { | ||||
|                     // return handleCreateVolumeFromSnapshotOnlySourceOnStorageSystem(); | ||||
|                 } | ||||
| 
 | ||||
|                 if (canHandleDest) { | ||||
|                     // return handleCreateVolumeFromSnapshotOnlyDestinationOnStorageSystem(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         throw new UnsupportedOperationException("This operation is not supported."); | ||||
|     } | ||||
| 
 | ||||
|     private void validate(SnapshotInfo snapshotInfo) { | ||||
|         long volumeId = snapshotInfo.getVolumeId(); | ||||
| 
 | ||||
|         VolumeVO volumeVO = _volumeDao.findByIdIncludingRemoved(volumeId); | ||||
| 
 | ||||
|         if (volumeVO.getFormat() != ImageFormat.VHD) { | ||||
|             throw new CloudRuntimeException("Only the " + ImageFormat.VHD.toString() + " image type is currently supported."); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private Void handleCreateTemplateFromSnapshot(SnapshotInfo snapshotInfo, TemplateInfo templateInfo, AsyncCompletionCallback<CopyCommandResult> callback) { | ||||
|         HostVO hostVO = getHost(snapshotInfo.getDataStore().getId()); | ||||
|         DataStore srcDataStore = snapshotInfo.getDataStore(); | ||||
| 
 | ||||
|         String value = _configDao.getValue(Config.PrimaryStorageDownloadWait.toString()); | ||||
|         int primaryStorageDownloadWait = NumbersUtil.parseInt(value, Integer.parseInt(Config.PrimaryStorageDownloadWait.getDefaultValue())); | ||||
|         CopyCommand copyCommand = new CopyCommand(snapshotInfo.getTO(), templateInfo.getTO(), primaryStorageDownloadWait, VirtualMachineManager.ExecuteInSequence.value()); | ||||
| 
 | ||||
|         CopyCmdAnswer copyCmdAnswer = null; | ||||
| 
 | ||||
|         try { | ||||
|             _volumeService.grantAccess(snapshotInfo, hostVO, srcDataStore); | ||||
| 
 | ||||
|             Map<String, String> srcDetails = getSnapshotDetails(_storagePoolDao.findById(srcDataStore.getId()), snapshotInfo); | ||||
| 
 | ||||
|             copyCommand.setOptions(srcDetails); | ||||
| 
 | ||||
|             copyCmdAnswer = (CopyCmdAnswer)_agentMgr.send(hostVO.getId(), copyCommand); | ||||
|         } | ||||
|         catch (Exception ex) { | ||||
|             throw new CloudRuntimeException(ex.getMessage()); | ||||
|         } | ||||
|         finally { | ||||
|             try { | ||||
|                 _volService.grantAccess(snapshotInfo, hostVO, srcDataStore); | ||||
| 
 | ||||
|                 Map<String, String> srcDetails = getSourceDetails(_storagePoolDao.findById(srcDataStore.getId()), snapshotInfo); | ||||
| 
 | ||||
|                 copyCommand.setOptions(srcDetails); | ||||
| 
 | ||||
|                 copyCmdAnswer = (CopyCmdAnswer)_agentMgr.send(hostVO.getId(), copyCommand); | ||||
|                 _volumeService.revokeAccess(snapshotInfo, hostVO, srcDataStore); | ||||
|             } | ||||
|             catch (Exception ex) { | ||||
|                 throw new CloudRuntimeException(ex.getMessage()); | ||||
|                 s_logger.debug(ex.getMessage(), ex); | ||||
|             } | ||||
|             finally { | ||||
|                 try { | ||||
|                     _volService.revokeAccess(snapshotInfo, hostVO, srcDataStore); | ||||
|                 } | ||||
|                 catch (Exception ex) { | ||||
|                     s_logger.debug(ex.getMessage(), ex); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             String errMsg = null; | ||||
| 
 | ||||
|             if (copyCmdAnswer == null || !copyCmdAnswer.getResult()) { | ||||
|                 if (copyCmdAnswer != null && copyCmdAnswer.getDetails() != null && !copyCmdAnswer.getDetails().isEmpty()) { | ||||
|                     errMsg = copyCmdAnswer.getDetails(); | ||||
|                 } | ||||
|                 else { | ||||
|                     errMsg = "Unable to perform host-side operation"; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             CopyCommandResult result = new CopyCommandResult(null, copyCmdAnswer); | ||||
| 
 | ||||
|             result.setResult(errMsg); | ||||
| 
 | ||||
|             callback.complete(result); | ||||
|         } | ||||
| 
 | ||||
|         String errMsg = null; | ||||
| 
 | ||||
|         if (copyCmdAnswer == null || !copyCmdAnswer.getResult()) { | ||||
|             if (copyCmdAnswer != null && copyCmdAnswer.getDetails() != null && !copyCmdAnswer.getDetails().isEmpty()) { | ||||
|                 errMsg = copyCmdAnswer.getDetails(); | ||||
|             } | ||||
|             else { | ||||
|                 errMsg = "Unable to perform host-side operation"; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         CopyCommandResult result = new CopyCommandResult(null, copyCmdAnswer); | ||||
| 
 | ||||
|         result.setResult(errMsg); | ||||
| 
 | ||||
|         callback.complete(result); | ||||
| 
 | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     private Map<String, String> getSourceDetails(StoragePoolVO storagePoolVO, SnapshotInfo snapshotInfo) { | ||||
|         Map<String, String> srcDetails = new HashMap<String, String>(); | ||||
|     private Void handleCreateVolumeFromSnapshotBothOnStorageSystem(SnapshotInfo snapshotInfo, VolumeInfo volumeInfo, AsyncCompletionCallback<CopyCommandResult> callback) { | ||||
|         try { | ||||
|             // at this point, the snapshotInfo and volumeInfo should have the same disk offering ID (so either one should be OK to get a DiskOfferingVO instance) | ||||
|             DiskOfferingVO diskOffering = _diskOfferingDao.findByIdIncludingRemoved(volumeInfo.getDiskOfferingId()); | ||||
|             SnapshotVO snapshot = _snapshotDao.findById(snapshotInfo.getId()); | ||||
| 
 | ||||
|         srcDetails.put(DiskTO.STORAGE_HOST, storagePoolVO.getHostAddress()); | ||||
|         srcDetails.put(DiskTO.STORAGE_PORT, String.valueOf(storagePoolVO.getPort())); | ||||
|             // update the volume's hypervisor_ss_reserve from its disk offering (used for managed storage) | ||||
|             _volumeMgr.updateHypervisorSnapshotReserveForVolume(diskOffering, volumeInfo, snapshot.getHypervisorType()); | ||||
| 
 | ||||
|             AsyncCallFuture<VolumeApiResult> future = _volumeService.createVolumeAsync(volumeInfo, volumeInfo.getDataStore()); | ||||
| 
 | ||||
|             VolumeApiResult result = future.get(); | ||||
| 
 | ||||
|             if (result.isFailed()) { | ||||
|                 s_logger.debug("Failed to create a volume: " + result.getResult()); | ||||
| 
 | ||||
|                 throw new CloudRuntimeException(result.getResult()); | ||||
|             } | ||||
|         } | ||||
|         catch (Exception ex) { | ||||
|             throw new CloudRuntimeException(ex.getMessage()); | ||||
|         } | ||||
| 
 | ||||
|         volumeInfo = _volumeDataFactory.getVolume(volumeInfo.getId(), volumeInfo.getDataStore()); | ||||
| 
 | ||||
|         volumeInfo.processEvent(Event.MigrationRequested); | ||||
| 
 | ||||
|         volumeInfo = _volumeDataFactory.getVolume(volumeInfo.getId(), volumeInfo.getDataStore()); | ||||
| 
 | ||||
|         HostVO hostVO = getHost(snapshotInfo.getDataStore().getId()); | ||||
| 
 | ||||
|         String value = _configDao.getValue(Config.PrimaryStorageDownloadWait.toString()); | ||||
|         int primaryStorageDownloadWait = NumbersUtil.parseInt(value, Integer.parseInt(Config.PrimaryStorageDownloadWait.getDefaultValue())); | ||||
|         CopyCommand copyCommand = new CopyCommand(snapshotInfo.getTO(), volumeInfo.getTO(), primaryStorageDownloadWait, VirtualMachineManager.ExecuteInSequence.value()); | ||||
| 
 | ||||
|         CopyCmdAnswer copyCmdAnswer = null; | ||||
| 
 | ||||
|         try { | ||||
|             _volumeService.grantAccess(snapshotInfo, hostVO, snapshotInfo.getDataStore()); | ||||
|             _volumeService.grantAccess(volumeInfo, hostVO, volumeInfo.getDataStore()); | ||||
| 
 | ||||
|             Map<String, String> srcDetails = getSnapshotDetails(_storagePoolDao.findById(snapshotInfo.getDataStore().getId()), snapshotInfo); | ||||
| 
 | ||||
|             copyCommand.setOptions(srcDetails); | ||||
| 
 | ||||
|             Map<String, String> destDetails = getVolumeDetails(volumeInfo); | ||||
| 
 | ||||
|             copyCommand.setOptions2(destDetails); | ||||
| 
 | ||||
|             copyCmdAnswer = (CopyCmdAnswer)_agentMgr.send(hostVO.getId(), copyCommand); | ||||
|         } | ||||
|         catch (Exception ex) { | ||||
|             throw new CloudRuntimeException(ex.getMessage()); | ||||
|         } | ||||
|         finally { | ||||
|             try { | ||||
|                 _volumeService.revokeAccess(snapshotInfo, hostVO, snapshotInfo.getDataStore()); | ||||
|             } | ||||
|             catch (Exception ex) { | ||||
|                 s_logger.debug(ex.getMessage(), ex); | ||||
|             } | ||||
| 
 | ||||
|             try { | ||||
|                 _volumeService.revokeAccess(volumeInfo, hostVO, volumeInfo.getDataStore()); | ||||
|             } | ||||
|             catch (Exception ex) { | ||||
|                 s_logger.debug(ex.getMessage(), ex); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         String errMsg = null; | ||||
| 
 | ||||
|         if (copyCmdAnswer == null || !copyCmdAnswer.getResult()) { | ||||
|             if (copyCmdAnswer != null && copyCmdAnswer.getDetails() != null && !copyCmdAnswer.getDetails().isEmpty()) { | ||||
|                 errMsg = copyCmdAnswer.getDetails(); | ||||
|             } | ||||
|             else { | ||||
|                 errMsg = "Unable to perform host-side operation"; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         CopyCommandResult result = new CopyCommandResult(null, copyCmdAnswer); | ||||
| 
 | ||||
|         result.setResult(errMsg); | ||||
| 
 | ||||
|         callback.complete(result); | ||||
| 
 | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     private Map<String, String> getSnapshotDetails(StoragePoolVO storagePoolVO, SnapshotInfo snapshotInfo) { | ||||
|         Map<String, String> details = new HashMap<String, String>(); | ||||
| 
 | ||||
|         details.put(DiskTO.STORAGE_HOST, storagePoolVO.getHostAddress()); | ||||
|         details.put(DiskTO.STORAGE_PORT, String.valueOf(storagePoolVO.getPort())); | ||||
| 
 | ||||
|         long snapshotId = snapshotInfo.getId(); | ||||
| 
 | ||||
|         srcDetails.put(DiskTO.IQN, getProperty(snapshotId, DiskTO.IQN)); | ||||
|         details.put(DiskTO.IQN, getProperty(snapshotId, DiskTO.IQN)); | ||||
| 
 | ||||
|         srcDetails.put(DiskTO.CHAP_INITIATOR_USERNAME, getProperty(snapshotId, DiskTO.CHAP_INITIATOR_USERNAME)); | ||||
|         srcDetails.put(DiskTO.CHAP_INITIATOR_SECRET, getProperty(snapshotId, DiskTO.CHAP_INITIATOR_SECRET)); | ||||
|         srcDetails.put(DiskTO.CHAP_TARGET_USERNAME, getProperty(snapshotId, DiskTO.CHAP_TARGET_USERNAME)); | ||||
|         srcDetails.put(DiskTO.CHAP_TARGET_SECRET, getProperty(snapshotId, DiskTO.CHAP_TARGET_SECRET)); | ||||
|         details.put(DiskTO.CHAP_INITIATOR_USERNAME, getProperty(snapshotId, DiskTO.CHAP_INITIATOR_USERNAME)); | ||||
|         details.put(DiskTO.CHAP_INITIATOR_SECRET, getProperty(snapshotId, DiskTO.CHAP_INITIATOR_SECRET)); | ||||
|         details.put(DiskTO.CHAP_TARGET_USERNAME, getProperty(snapshotId, DiskTO.CHAP_TARGET_USERNAME)); | ||||
|         details.put(DiskTO.CHAP_TARGET_SECRET, getProperty(snapshotId, DiskTO.CHAP_TARGET_SECRET)); | ||||
| 
 | ||||
|         return srcDetails; | ||||
|         return details; | ||||
|     } | ||||
| 
 | ||||
|     private String getProperty(long snapshotId, String property) { | ||||
| @ -183,8 +343,31 @@ public class StorageSystemDataMotionStrategy implements DataMotionStrategy { | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     public HostVO getHost(DataObject srcData) { | ||||
|         long dataStoreId = srcData.getDataStore().getId(); | ||||
|     private Map<String, String> getVolumeDetails(VolumeInfo volumeInfo) { | ||||
|         Map<String, String> sourceDetails = new HashMap<String, String>(); | ||||
| 
 | ||||
|         VolumeVO volumeVO = _volumeDao.findById(volumeInfo.getId()); | ||||
| 
 | ||||
|         long storagePoolId = volumeVO.getPoolId(); | ||||
|         StoragePoolVO storagePoolVO = _storagePoolDao.findById(storagePoolId); | ||||
| 
 | ||||
|         sourceDetails.put(DiskTO.STORAGE_HOST, storagePoolVO.getHostAddress()); | ||||
|         sourceDetails.put(DiskTO.STORAGE_PORT, String.valueOf(storagePoolVO.getPort())); | ||||
|         sourceDetails.put(DiskTO.IQN, volumeVO.get_iScsiName()); | ||||
| 
 | ||||
|         ChapInfo chapInfo = _volumeService.getChapInfo(volumeInfo, volumeInfo.getDataStore()); | ||||
| 
 | ||||
|         if (chapInfo != null) { | ||||
|             sourceDetails.put(DiskTO.CHAP_INITIATOR_USERNAME, chapInfo.getInitiatorUsername()); | ||||
|             sourceDetails.put(DiskTO.CHAP_INITIATOR_SECRET, chapInfo.getInitiatorSecret()); | ||||
|             sourceDetails.put(DiskTO.CHAP_TARGET_USERNAME, chapInfo.getTargetUsername()); | ||||
|             sourceDetails.put(DiskTO.CHAP_TARGET_SECRET, chapInfo.getTargetSecret()); | ||||
|         } | ||||
| 
 | ||||
|         return sourceDetails; | ||||
|     } | ||||
| 
 | ||||
|     public HostVO getHost(long dataStoreId) { | ||||
|         StoragePoolVO storagePoolVO = _storagePoolDao.findById(dataStoreId); | ||||
| 
 | ||||
|         List<? extends Cluster> clusters = _mgr.searchForClusters(storagePoolVO.getDataCenterId(), new Long(0), Long.MAX_VALUE, HypervisorType.XenServer.toString()); | ||||
|  | ||||
| @ -154,10 +154,6 @@ public class VolumeObject implements VolumeInfo { | ||||
|         return volumeVO.getMaxIops(); | ||||
|     } | ||||
| 
 | ||||
|     public void setHypervisorSnapshotReserve(Integer hypervisorSnapshotReserve) { | ||||
|         volumeVO.setHypervisorSnapshotReserve(hypervisorSnapshotReserve); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public Integer getHypervisorSnapshotReserve() { | ||||
|         return volumeVO.getHypervisorSnapshotReserve(); | ||||
|  | ||||
| @ -1589,6 +1589,10 @@ public class XenServerStorageProcessor implements StorageProcessor { | ||||
|         DataTO destData = cmd.getDestTO(); | ||||
|         DataStoreTO imageStore = srcData.getDataStore(); | ||||
| 
 | ||||
|         if (srcData.getDataStore() instanceof PrimaryDataStoreTO && destData.getDataStore() instanceof PrimaryDataStoreTO) { | ||||
|             return createVolumeFromSnapshot2(cmd); | ||||
|         } | ||||
| 
 | ||||
|         if (!(imageStore instanceof NfsTO)) { | ||||
|             return new CopyCmdAnswer("unsupported protocol"); | ||||
|         } | ||||
| @ -1647,6 +1651,51 @@ public class XenServerStorageProcessor implements StorageProcessor { | ||||
|         return new CopyCmdAnswer(details); | ||||
|     } | ||||
| 
 | ||||
|     protected Answer createVolumeFromSnapshot2(CopyCommand cmd) { | ||||
|         try { | ||||
|             Connection conn = hypervisorResource.getConnection(); | ||||
| 
 | ||||
|             Map<String, String> srcOptions = cmd.getOptions(); | ||||
| 
 | ||||
|             String src_iScsiName = srcOptions.get(DiskTO.IQN); | ||||
|             String srcStorageHost = srcOptions.get(DiskTO.STORAGE_HOST); | ||||
|             String srcChapInitiatorUsername = srcOptions.get(DiskTO.CHAP_INITIATOR_USERNAME); | ||||
|             String srcChapInitiatorSecret = srcOptions.get(DiskTO.CHAP_INITIATOR_SECRET); | ||||
| 
 | ||||
|             SR srcSr = hypervisorResource.getIscsiSR(conn, src_iScsiName, srcStorageHost, src_iScsiName, srcChapInitiatorUsername, srcChapInitiatorSecret, false); | ||||
| 
 | ||||
|             Map<String, String> destOptions = cmd.getOptions2(); | ||||
| 
 | ||||
|             String dest_iScsiName = destOptions.get(DiskTO.IQN); | ||||
|             String destStorageHost = destOptions.get(DiskTO.STORAGE_HOST); | ||||
|             String destChapInitiatorUsername = destOptions.get(DiskTO.CHAP_INITIATOR_USERNAME); | ||||
|             String destChapInitiatorSecret = destOptions.get(DiskTO.CHAP_INITIATOR_SECRET); | ||||
| 
 | ||||
|             SR destSr = hypervisorResource.getIscsiSR(conn, dest_iScsiName, destStorageHost, dest_iScsiName, destChapInitiatorUsername, destChapInitiatorSecret, false); | ||||
| 
 | ||||
|             // there should only be one VDI in this SR | ||||
|             VDI srcVdi = srcSr.getVDIs(conn).iterator().next(); | ||||
| 
 | ||||
|             VDI vdiCopy = srcVdi.copy(conn, destSr); | ||||
| 
 | ||||
|             VolumeObjectTO newVol = new VolumeObjectTO(); | ||||
| 
 | ||||
|             newVol.setSize(vdiCopy.getVirtualSize(conn)); | ||||
|             newVol.setPath(vdiCopy.getUuid(conn)); | ||||
|             newVol.setFormat(ImageFormat.VHD); | ||||
| 
 | ||||
|             hypervisorResource.removeSR(conn, srcSr); | ||||
|             hypervisorResource.removeSR(conn, destSr); | ||||
| 
 | ||||
|             return new CopyCmdAnswer(newVol); | ||||
|         } | ||||
|         catch (Exception ex) { | ||||
|             s_logger.warn("Failed to copy snapshot to volume: " + ex.toString(), ex); | ||||
| 
 | ||||
|             return new CopyCmdAnswer(ex.getMessage()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public Answer deleteSnapshot(DeleteCommand cmd) { | ||||
|         SnapshotObjectTO snapshot = (SnapshotObjectTO) cmd.getData(); | ||||
|  | ||||
| @ -656,7 +656,11 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor { | ||||
|         DataTO destData = cmd.getDestTO(); | ||||
|         PrimaryDataStoreTO pool = (PrimaryDataStoreTO)destData.getDataStore(); | ||||
|         VolumeObjectTO volume = (VolumeObjectTO)destData; | ||||
|                 DataStoreTO imageStore = srcData.getDataStore(); | ||||
|         DataStoreTO imageStore = srcData.getDataStore(); | ||||
| 
 | ||||
|         if (srcData.getDataStore() instanceof PrimaryDataStoreTO && destData.getDataStore() instanceof PrimaryDataStoreTO) { | ||||
|             return createVolumeFromSnapshot2(cmd); | ||||
|         } | ||||
| 
 | ||||
|         if (!(imageStore instanceof NfsTO)) { | ||||
|             return new CopyCmdAnswer("unsupported protocol"); | ||||
|  | ||||
| @ -483,7 +483,7 @@ public class ApiResponseHelper implements ResponseGenerator { | ||||
|         if (snapshot instanceof SnapshotInfo) { | ||||
|             snapshotInfo = (SnapshotInfo)snapshot; | ||||
|         } else { | ||||
|             DataStoreRole dataStoreRole = getDataStoreRole(snapshot); | ||||
|             DataStoreRole dataStoreRole = getDataStoreRole(snapshot, _snapshotStoreDao, _dataStoreMgr); | ||||
| 
 | ||||
|             snapshotInfo = snapshotfactory.getSnapshot(snapshot.getId(), dataStoreRole); | ||||
|         } | ||||
| @ -509,15 +509,15 @@ public class ApiResponseHelper implements ResponseGenerator { | ||||
|         return snapshotResponse; | ||||
|     } | ||||
| 
 | ||||
|     private DataStoreRole getDataStoreRole(Snapshot snapshot) { | ||||
|         SnapshotDataStoreVO snapshotStore = _snapshotStoreDao.findBySnapshot(snapshot.getId(), DataStoreRole.Primary); | ||||
|     public static DataStoreRole getDataStoreRole(Snapshot snapshot, SnapshotDataStoreDao snapshotStoreDao, DataStoreManager dataStoreMgr) { | ||||
|         SnapshotDataStoreVO snapshotStore = snapshotStoreDao.findBySnapshot(snapshot.getId(), DataStoreRole.Primary); | ||||
| 
 | ||||
|         if (snapshotStore == null) { | ||||
|             return DataStoreRole.Image; | ||||
|         } | ||||
| 
 | ||||
|         long storagePoolId = snapshotStore.getDataStoreId(); | ||||
|         DataStore dataStore = _dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); | ||||
|         DataStore dataStore = dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); | ||||
| 
 | ||||
|         Map<String, String> mapCapabilities = dataStore.getDriver().getCapabilities(); | ||||
| 
 | ||||
|  | ||||
| @ -522,6 +522,9 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic | ||||
|             size = snapshotCheck.getSize(); // ; disk offering is used for tags | ||||
|             // purposes | ||||
| 
 | ||||
|             minIops = snapshotCheck.getMinIops(); | ||||
|             maxIops = snapshotCheck.getMaxIops(); | ||||
| 
 | ||||
|             provisioningType = diskOffering.getProvisioningType(); | ||||
|             // check snapshot permissions | ||||
|             _accountMgr.checkAccess(caller, null, true, snapshotCheck); | ||||
|  | ||||
| @ -87,6 +87,7 @@ 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.ImageFormat; | ||||
| import com.cloud.storage.StorageManager; | ||||
| import com.cloud.storage.StoragePool; | ||||
| import com.cloud.storage.VMTemplateVO; | ||||
| @ -1132,13 +1133,18 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, | ||||
|         StoragePoolVO storagePool = _storagePoolDao.findById(volume.getDataStore().getId()); | ||||
|         if (storagePool.getScope() == ScopeType.ZONE) { | ||||
|             hypervisorType = storagePool.getHypervisor(); | ||||
| 
 | ||||
|             // at the time being, managed storage only supports XenServer, ESX(i), and KVM (i.e. not Hyper-V), so the VHD file type can be mapped to XenServer | ||||
|             if (storagePool.isManaged() && HypervisorType.Any.equals(hypervisorType) && ImageFormat.VHD.equals(volume.getFormat())) { | ||||
|                 hypervisorType = HypervisorType.XenServer; | ||||
|             } | ||||
|         } else { | ||||
|             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); | ||||
|                 (short)snapshotType.ordinal(), snapshotType.name(), volume.getSize(), volume.getMinIops(), volume.getMaxIops(), hypervisorType); | ||||
| 
 | ||||
|         SnapshotVO snapshot = _snapshotDao.persist(snapshotVO); | ||||
|         if (snapshot == null) { | ||||
|  | ||||
| @ -54,7 +54,6 @@ import org.apache.cloudstack.api.command.user.template.UpdateTemplatePermissions | ||||
| import org.apache.cloudstack.context.CallContext; | ||||
| import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService; | ||||
| import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; | ||||
| import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities; | ||||
| import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; | ||||
| import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; | ||||
| import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; | ||||
| @ -81,7 +80,6 @@ import org.apache.cloudstack.storage.command.CommandResult; | ||||
| import org.apache.cloudstack.storage.command.DettachCommand; | ||||
| import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; | ||||
| import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; | ||||
| import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO; | ||||
| import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; | ||||
| import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; | ||||
| import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO; | ||||
| @ -97,6 +95,7 @@ import com.cloud.agent.api.to.DataTO; | ||||
| import com.cloud.agent.api.to.DiskTO; | ||||
| import com.cloud.agent.api.to.NfsTO; | ||||
| import com.cloud.api.ApiDBUtils; | ||||
| import com.cloud.api.ApiResponseHelper; | ||||
| import com.cloud.api.query.dao.UserVmJoinDao; | ||||
| import com.cloud.api.query.vo.UserVmJoinVO; | ||||
| import com.cloud.configuration.Config; | ||||
| @ -1379,7 +1378,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, | ||||
|             AsyncCallFuture<TemplateApiResult> future = null; | ||||
| 
 | ||||
|             if (snapshotId != null) { | ||||
|                 DataStoreRole dataStoreRole = getDataStoreRole(snapshot); | ||||
|                 DataStoreRole dataStoreRole = ApiResponseHelper.getDataStoreRole(snapshot, _snapshotStoreDao, _dataStoreMgr); | ||||
| 
 | ||||
|                 SnapshotInfo snapInfo = _snapshotFactory.getSnapshot(snapshotId, dataStoreRole); | ||||
| 
 | ||||
| @ -1474,30 +1473,6 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private DataStoreRole getDataStoreRole(Snapshot snapshot) { | ||||
|         SnapshotDataStoreVO snapshotStore = _snapshotStoreDao.findBySnapshot(snapshot.getId(), DataStoreRole.Primary); | ||||
| 
 | ||||
|         if (snapshotStore == null) { | ||||
|             return DataStoreRole.Image; | ||||
|         } | ||||
| 
 | ||||
|         long storagePoolId = snapshotStore.getDataStoreId(); | ||||
|         DataStore dataStore = _dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); | ||||
| 
 | ||||
|         Map<String, String> mapCapabilities = dataStore.getDriver().getCapabilities(); | ||||
| 
 | ||||
|         if (mapCapabilities != null) { | ||||
|             String value = mapCapabilities.get(DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT.toString()); | ||||
|             Boolean supportsStorageSystemSnapshots = new Boolean(value); | ||||
| 
 | ||||
|             if (supportsStorageSystemSnapshots) { | ||||
|                 return DataStoreRole.Primary; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return DataStoreRole.Image; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating template", create = true) | ||||
|     public VMTemplateVO createPrivateTemplateRecord(CreateTemplateCmd cmd, Account templateOwner) throws ResourceAllocationException { | ||||
|  | ||||
| @ -19,6 +19,9 @@ | ||||
| -- Schema upgrade from 4.5.0 to 4.6.0 | ||||
| -- | ||||
| 
 | ||||
| ALTER TABLE `cloud`.`snapshots` ADD COLUMN `min_iops` bigint(20) unsigned COMMENT 'Minimum IOPS'; | ||||
| ALTER TABLE `cloud`.`snapshots` ADD COLUMN `max_iops` bigint(20) unsigned COMMENT 'Maximum IOPS'; | ||||
| 
 | ||||
| INSERT IGNORE INTO `cloud`.`configuration` VALUES ("Advanced", 'DEFAULT', 'management-server', "stats.output.uri", "", "URI to additionally send StatsCollector statistics to", "", NULL, NULL, 0); | ||||
| 
 | ||||
| DROP VIEW IF EXISTS `cloud`.`domain_view`; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user