From 9f7bad2cef25fdf02683f0f0e0f0e14084aefbbf Mon Sep 17 00:00:00 2001 From: Edison Su Date: Mon, 6 May 2013 18:26:33 -0700 Subject: [PATCH] fix creating snapshot --- .../storage/command/DownloadCommand.java | 1 + .../motion/AncientDataMotionStrategy.java | 2 +- .../cloudstack/storage/test/SnapshotTest.java | 352 +++++++++++++++++- .../storage/snapshot/SnapshotServiceImpl.java | 10 +- .../snapshot/XenserverSnapshotStrategy.java | 2 +- .../cloudstack/storage/LocalHostEndpoint.java | 24 +- .../ObjectInDataStoreManagerImpl.java | 4 + .../storage/volume/VolumeObject.java | 2 + .../storage/volume/VolumeServiceImpl.java | 27 +- .../resource/XenServerStorageResource.java | 52 +-- .../CloudStackPrimaryDataStoreDriverImpl.java | 4 +- .../SamplePrimaryDataStoreDriverImpl.java | 4 +- .../com/cloud/storage/VolumeManagerImpl.java | 1 + setup/db/db/schema-410to420.sql | 2 +- 14 files changed, 434 insertions(+), 53 deletions(-) diff --git a/engine/api/src/org/apache/cloudstack/storage/command/DownloadCommand.java b/engine/api/src/org/apache/cloudstack/storage/command/DownloadCommand.java index 5388f0a9ebd..7e3d65c7bde 100644 --- a/engine/api/src/org/apache/cloudstack/storage/command/DownloadCommand.java +++ b/engine/api/src/org/apache/cloudstack/storage/command/DownloadCommand.java @@ -65,6 +65,7 @@ public class DownloadCommand extends AbstractDownloadCommand implements Internal } public DownloadCommand(TemplateObjectTO template, Long maxDownloadSizeInBytes) { + super(template.getName(), template.getOrigUrl(), template.getFormat(), template.getAccountId()); this._store = template.getDataStore(); this.installPath = template.getPath(); diff --git a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java index 32f9a9aa101..db3971c673e 100644 --- a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java +++ b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java @@ -370,7 +370,7 @@ public class AncientDataMotionStrategy implements DataMotionStrategy { DataObject cacheData = null; try { - if (destData.getDataStore().getRole() != DataStoreRole.ImageCache) { + if (needCacheStorage(srcData, destData)) { cacheData = cacheMgr.getCacheObject(srcData, destData.getDataStore().getScope()); CopyCommand cmd = new CopyCommand(srcData.getTO(), destData.getTO(), _backupsnapshotwait); diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTest.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTest.java index afd63f5bfdd..203f762a0e4 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTest.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTest.java @@ -18,6 +18,356 @@ */ package org.apache.cloudstack.storage.test; -public class SnapshotTest { +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.ExecutionException; + +import javax.inject.Inject; + +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.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager; +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.TemplateDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateService; +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.engine.subsystem.api.storage.type.RootDisk; +import org.apache.cloudstack.framework.async.AsyncCallFuture; +import org.apache.cloudstack.storage.RemoteHostEndPoint; +import org.apache.cloudstack.storage.command.CopyCmdAnswer; +import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; +import org.apache.cloudstack.storage.to.TemplateObjectTO; +import org.apache.cloudstack.storage.volume.db.VolumeDao2; +import org.apache.cloudstack.storage.volume.db.VolumeVO; +import org.mockito.Mockito; +import org.springframework.test.context.ContextConfiguration; +import org.testng.AssertJUnit; +import org.testng.annotations.Test; + +import com.cloud.agent.AgentManager; +import com.cloud.dc.ClusterVO; +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.HostPodVO; +import com.cloud.dc.DataCenter.NetworkType; +import com.cloud.dc.dao.ClusterDao; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.dc.dao.HostPodDao; +import com.cloud.host.Host; +import com.cloud.host.HostVO; +import com.cloud.host.Host.Type; +import com.cloud.host.dao.HostDao; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.org.Cluster.ClusterType; +import com.cloud.org.Managed.ManagedState; +import com.cloud.resource.ResourceManager; +import com.cloud.resource.ResourceState; +import com.cloud.storage.DataStoreRole; +import com.cloud.storage.ScopeType; +import com.cloud.storage.Snapshot; +import com.cloud.storage.SnapshotVO; +import com.cloud.storage.Storage; +import com.cloud.storage.StoragePoolStatus; +import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.Storage.StoragePoolType; +import com.cloud.storage.Storage.TemplateType; +import com.cloud.storage.dao.SnapshotDao; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.utils.component.ComponentContext; + +@ContextConfiguration(locations={"classpath:/storageContext.xml"}) +public class SnapshotTest extends CloudStackTestNGBase { + @Inject + ImageStoreDao imageStoreDao; + ImageStoreVO imageStore; + Long dcId; + Long clusterId; + Long podId; + HostVO host; + String primaryName = "my primary data store"; + DataStore primaryStore; + @Inject + HostDao hostDao; + @Inject + TemplateService imageService; + @Inject + VolumeService volumeService; + @Inject + VMTemplateDao imageDataDao; + @Inject + VolumeDao2 volumeDao; + @Inject + HostPodDao podDao; + @Inject + ClusterDao clusterDao; + @Inject + DataCenterDao dcDao; + @Inject + PrimaryDataStoreDao primaryStoreDao; + @Inject + DataStoreProviderManager dataStoreProviderMgr; + @Inject + TemplateDataStoreDao templateStoreDao; + @Inject + TemplateDataFactory templateFactory; + @Inject + PrimaryDataStoreDao primaryDataStoreDao; + @Inject + AgentManager agentMgr; + @Inject + DataStoreManager dataStoreMgr; + @Inject + ResourceManager resourceMgr; + @Inject + VolumeDataFactory volFactory; + @Inject SnapshotDataFactory snapshotFactory; + @Inject + List snapshotStrategies; + @Inject + SnapshotService snapshotSvr; + @Inject + SnapshotDao snapshotDao; + @Inject + EndPointSelector epSelector; + long primaryStoreId; + VMTemplateVO image; + String imageStoreName = "testImageStore"; + @Test(priority = -1) + public void setUp() { + ComponentContext.initComponentsLifeCycle(); + + host = hostDao.findByGuid(this.getHostGuid()); + if (host != null) { + dcId = host.getDataCenterId(); + clusterId = host.getClusterId(); + podId = host.getPodId(); + imageStore = this.imageStoreDao.findByName(imageStoreName); + } else { + //create data center + DataCenterVO dc = new DataCenterVO(UUID.randomUUID().toString(), "test", "8.8.8.8", null, "10.0.0.1", null, "10.0.0.1/24", + null, null, NetworkType.Basic, null, null, true, true, null, null); + dc = dcDao.persist(dc); + dcId = dc.getId(); + //create pod + + HostPodVO pod = new HostPodVO(UUID.randomUUID().toString(), dc.getId(), this.getHostGateway(), this.getHostCidr(), 8, "test"); + pod = podDao.persist(pod); + podId = pod.getId(); + //create xen cluster + ClusterVO cluster = new ClusterVO(dc.getId(), pod.getId(), "devcloud cluster"); + cluster.setHypervisorType(HypervisorType.XenServer.toString()); + cluster.setClusterType(ClusterType.CloudManaged); + cluster.setManagedState(ManagedState.Managed); + cluster = clusterDao.persist(cluster); + clusterId = cluster.getId(); + //create xen host + + host = new HostVO(this.getHostGuid()); + host.setName("devcloud xen host"); + host.setType(Host.Type.Routing); + host.setPrivateIpAddress(this.getHostIp()); + host.setDataCenterId(dc.getId()); + host.setVersion("6.0.1"); + host.setAvailable(true); + host.setSetup(true); + host.setPodId(podId); + host.setLastPinged(0); + host.setResourceState(ResourceState.Enabled); + host.setHypervisorType(HypervisorType.XenServer); + host.setClusterId(cluster.getId()); + + host = hostDao.persist(host); + + imageStore = new ImageStoreVO(); + imageStore.setName(imageStoreName); + imageStore.setDataCenterId(dcId); + imageStore.setProviderName("CloudStack ImageStore Provider"); + imageStore.setRole(DataStoreRole.Image); + imageStore.setUrl(this.getSecondaryStorage()); + imageStore.setUuid(UUID.randomUUID().toString()); + imageStore.setProtocol("nfs"); + imageStore = imageStoreDao.persist(imageStore); + } + + image = new VMTemplateVO(); + image.setTemplateType(TemplateType.USER); + image.setUrl(this.getTemplateUrl()); + image.setUniqueName(UUID.randomUUID().toString()); + image.setName(UUID.randomUUID().toString()); + image.setPublicTemplate(true); + image.setFeatured(true); + image.setRequiresHvm(true); + image.setBits(64); + image.setFormat(Storage.ImageFormat.VHD); + image.setEnablePassword(true); + image.setEnableSshKey(true); + image.setGuestOSId(1); + image.setBootable(true); + image.setPrepopulate(true); + image.setCrossZones(true); + image.setExtractable(true); + + image = imageDataDao.persist(image); + + /*TemplateDataStoreVO templateStore = new TemplateDataStoreVO(); + + templateStore.setDataStoreId(imageStore.getId()); + templateStore.setDownloadPercent(100); + templateStore.setDownloadState(Status.DOWNLOADED); + templateStore.setDownloadUrl(imageStore.getUrl()); + templateStore.setInstallPath(this.getImageInstallPath()); + templateStore.setTemplateId(image.getId()); + templateStoreDao.persist(templateStore);*/ + + + DataStore store = this.dataStoreMgr.getDataStore(imageStore.getId(), DataStoreRole.Image); + TemplateInfo template = templateFactory.getTemplate(image.getId()); + DataObject templateOnStore = store.create(template); + TemplateObjectTO to = new TemplateObjectTO(); + to.setPath(this.getImageInstallPath()); + CopyCmdAnswer answer = new CopyCmdAnswer(to); + templateOnStore.processEvent(Event.CreateOnlyRequested); + templateOnStore.processEvent(Event.OperationSuccessed, answer); + + + } + + @Override + protected void injectMockito() { + List hosts = new ArrayList(); + hosts.add(this.host); + Mockito.when(resourceMgr.listAllUpAndEnabledHosts((Type) Mockito.any(), Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong())).thenReturn(hosts); + + RemoteHostEndPoint ep = RemoteHostEndPoint.getHypervisorHostEndPoint(this.host.getId(), this.host.getPrivateIpAddress()); + Mockito.when(epSelector.select(Mockito.any(DataObject.class), Mockito.any(DataObject.class))).thenReturn(ep); + Mockito.when(epSelector.select(Mockito.any(DataObject.class))).thenReturn(ep); + Mockito.when(epSelector.select(Mockito.any(DataStore.class))).thenReturn(ep); + } + + public DataStore createPrimaryDataStore() { + try { + String uuid = UUID.nameUUIDFromBytes(this.getPrimaryStorageUrl().getBytes()).toString(); + List pools = primaryDataStoreDao.findPoolByName(this.primaryName); + if (pools.size() > 0) { + return this.dataStoreMgr.getPrimaryDataStore(pools.get(0).getId()); + } + + /*DataStoreProvider provider = dataStoreProviderMgr.getDataStoreProvider("cloudstack primary data store provider"); + Map params = new HashMap(); + URI uri = new URI(this.getPrimaryStorageUrl()); + params.put("url", this.getPrimaryStorageUrl()); + params.put("server", uri.getHost()); + params.put("path", uri.getPath()); + params.put("protocol", Storage.StoragePoolType.NetworkFilesystem); + params.put("zoneId", dcId); + params.put("clusterId", clusterId); + params.put("name", this.primaryName); + params.put("port", 1); + params.put("podId", this.podId); + params.put("roles", DataStoreRole.Primary.toString()); + params.put("uuid", uuid); + params.put("providerName", String.valueOf(provider.getName())); + + DataStoreLifeCycle lifeCycle = provider.getDataStoreLifeCycle(); + DataStore store = lifeCycle.initialize(params); + ClusterScope scope = new ClusterScope(clusterId, podId, dcId); + lifeCycle.attachCluster(store, scope);*/ + + StoragePoolVO pool = new StoragePoolVO(); + pool.setClusterId(clusterId); + pool.setDataCenterId(dcId); + URI uri = new URI(this.getPrimaryStorageUrl()); + pool.setHostAddress(uri.getHost()); + pool.setPath(uri.getPath()); + pool.setPort(0); + pool.setName(this.primaryName); + pool.setUuid(this.getPrimaryStorageUuid()); + pool.setStatus(StoragePoolStatus.Up); + pool.setPoolType(StoragePoolType.NetworkFilesystem); + pool.setPodId(podId); + pool.setScope(ScopeType.CLUSTER); + pool.setStorageProviderName("cloudstack primary data store provider"); + pool = this.primaryStoreDao.persist(pool); + DataStore store = this.dataStoreMgr.getPrimaryDataStore(pool.getId()); + return store; + } catch (Exception e) { + return null; + } + } + + private SnapshotVO createSnapshotInDb(VolumeInfo volume) { + Snapshot.Type snapshotType = Snapshot.Type.MANUAL; + SnapshotVO snapshotVO = new SnapshotVO(volume.getDataCenterId(), 2, 1, volume.getId(), 1L, UUID.randomUUID().toString(), + (short) snapshotType.ordinal(), snapshotType.name(), volume.getSize(), HypervisorType.XenServer); + return this.snapshotDao.persist(snapshotVO); + } + + private VolumeVO createVolume(Long templateId, long dataStoreId) { + VolumeVO volume = new VolumeVO(1000, new RootDisk().toString(), UUID.randomUUID().toString(), templateId); + volume.setDataCenterId(this.dcId); + volume.setPoolId(dataStoreId); + volume = volumeDao.persist(volume); + return volume; + } + + + public VolumeInfo createCopyBaseImage() { + DataStore primaryStore = createPrimaryDataStore(); + primaryStoreId = primaryStore.getId(); + primaryStore = this.dataStoreMgr.getPrimaryDataStore(primaryStoreId); + VolumeVO volume = createVolume(image.getId(), primaryStore.getId()); + VolumeInfo volInfo = this.volFactory.getVolume(volume.getId()); + AsyncCallFuture future = this.volumeService.createVolumeFromTemplateAsync(volInfo, this.primaryStoreId, this.templateFactory.getTemplate(this.image.getId())); + + VolumeApiResult result; + try { + result = future.get(); + return result.getVolume(); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ExecutionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return null; + } + + @Test + public void createSnapshot() { + VolumeInfo vol = createCopyBaseImage(); + SnapshotVO snapshotVO = createSnapshotInDb(vol); + SnapshotInfo snapshot = this.snapshotFactory.getSnapshot(snapshotVO.getId(), vol.getDataStore()); + for (SnapshotStrategy strategy : this.snapshotStrategies) { + if (strategy.canHandle(snapshot)) { + strategy.takeSnapshot(snapshot); + } + } + } + + //@Test + public void testCreateDataDisk() { + DataStore primaryStore = createPrimaryDataStore(); + primaryStoreId = primaryStore.getId(); + primaryStore = this.dataStoreMgr.getPrimaryDataStore(primaryStoreId); + VolumeVO volume = createVolume(null, primaryStore.getId()); + VolumeInfo volInfo = this.volFactory.getVolume(volume.getId()); + this.volumeService.createVolumeAsync(volInfo, primaryStore); + } } diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java index 79237c4ffc6..12d80576c85 100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java @@ -42,6 +42,7 @@ 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.command.CommandResult; +import org.apache.cloudstack.storage.command.CopyCmdAnswer; import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; @@ -170,6 +171,7 @@ public class SnapshotServiceImpl implements SnapshotService { try { snapshot.processEvent(Event.OperationSuccessed, result.getAnswer()); + snapshot.processEvent(Snapshot.Event.OperationSucceeded); } catch (Exception e) { s_logger.debug("Failed to create snapshot: ", e); snapResult.setResult(e.toString()); @@ -323,12 +325,8 @@ public class SnapshotServiceImpl implements SnapshotService { } try { - BackupSnapshotAnswer answer = (BackupSnapshotAnswer)result.getAnswer(); - - DataObjectInStore dataInStore = objInStoreMgr.findObject(destSnapshot, destSnapshot.getDataStore()); - dataInStore.setInstallPath(answer.getBackupSnapshotName()); - objInStoreMgr.update(destSnapshot, Event.OperationSuccessed); - + CopyCmdAnswer answer = (CopyCmdAnswer)result.getAnswer(); + destSnapshot.processEvent(Event.OperationSuccessed, result.getAnswer()); srcSnapshot.processEvent(Snapshot.Event.OperationSucceeded); snapResult = new SnapshotResult(this.snapshotfactory.getSnapshot(destSnapshot.getId(), destSnapshot.getDataStore()), answer); future.complete(snapResult); diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java index df2264a3a4a..271bee5cf8b 100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java @@ -56,7 +56,7 @@ public class XenserverSnapshotStrategy extends SnapshotStrategyBase { @Override public SnapshotInfo backupSnapshot(SnapshotInfo snapshot) { SnapshotInfo parentSnapshot = snapshot.getParent(); - if (parentSnapshot.getPath().equalsIgnoreCase(snapshot.getPath())) { + if (parentSnapshot != null && parentSnapshot.getPath().equalsIgnoreCase(snapshot.getPath())) { s_logger.debug("backup an empty snapshot"); //don't need to backup this snapshot SnapshotDataStoreVO parentSnapshotOnBackupStore = this.snapshotStoreDao.findBySnapshot(parentSnapshot.getId(), DataStoreRole.Image); diff --git a/engine/storage/src/org/apache/cloudstack/storage/LocalHostEndpoint.java b/engine/storage/src/org/apache/cloudstack/storage/LocalHostEndpoint.java index 170772596a0..1ae13b630d0 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/LocalHostEndpoint.java +++ b/engine/storage/src/org/apache/cloudstack/storage/LocalHostEndpoint.java @@ -63,19 +63,31 @@ public class LocalHostEndpoint implements EndPoint { private class CmdRunner2 implements Runnable { final Command cmd; - final AsyncCompletionCallback callback; - public CmdRunner2(Command cmd, AsyncCompletionCallback callback) { + final Listener listener; + public CmdRunner2(Command cmd, Listener listener) { this.cmd = cmd; - this.callback = callback; + this.listener = listener; } @Override public void run() { try { DownloadAnswer answer = (DownloadAnswer) sendMessage(cmd); - callback.complete(answer); + Answer[] answers = new Answer[1]; + answers[0] = answer; + listener.processAnswers(getId(), 0, answers); + if (listener instanceof DownloadListener) { + DownloadListener dwldListener = (DownloadListener)listener; + dwldListener.getCallback().complete(answer); + } } catch (Exception ex) { DownloadAnswer fail = new DownloadAnswer("Error in handling DownloadCommand : " + ex.getMessage(), VMTemplateStorageResourceAssoc.Status.DOWNLOAD_ERROR); - callback.complete(fail); + Answer[] answers = new Answer[1]; + answers[0] = fail; + listener.processAnswers(getId(), 0, answers); + if (listener instanceof DownloadListener) { + DownloadListener dwldListener = (DownloadListener)listener; + dwldListener.getCallback().complete(fail); + } } } } @@ -89,7 +101,7 @@ public class LocalHostEndpoint implements EndPoint { public void sendMessageAsyncWithListener(Command cmd, Listener listner) { if (listner instanceof DownloadListener) { DownloadListener listener = (DownloadListener)listner; - executor.schedule(new CmdRunner2(cmd, listener.getCallback()), 10, TimeUnit.SECONDS); + executor.schedule(new CmdRunner2(cmd, listener), 10, TimeUnit.SECONDS); } } public ServerResource getResource() { diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java index 1d891e53ddc..763d2cabf7c 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java @@ -227,6 +227,8 @@ public class ObjectInDataStoreManagerImpl implements ObjectInDataStoreManager { this.stateMachines.transitTo(obj, event, null, templatePoolDao); + } else if (data.getType() == DataObjectType.SNAPSHOT && data.getDataStore().getRole() == DataStoreRole.Primary) { + this.stateMachines.transitTo(obj, event, null, snapshotDataStoreDao); } else { throw new CloudRuntimeException("Invalid data or store type: " + data.getType() + " " + data.getDataStore().getRole()); } @@ -270,6 +272,8 @@ public class ObjectInDataStoreManagerImpl implements ObjectInDataStoreManager { } } else if (type == DataObjectType.TEMPLATE && role == DataStoreRole.Primary) { vo = templatePoolDao.findByPoolTemplate(dataStoreId, objId); + } else if (type == DataObjectType.SNAPSHOT && role == DataStoreRole.Primary) { + vo = snapshotDataStoreDao.findByStoreSnapshot(role, dataStoreId, objId); } else { s_logger.debug("Invalid data or store type: " + type + " " + role); throw new CloudRuntimeException("Invalid data or store type: " + type + " " + role); diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java index 1aee5d304a0..be7bd12104d 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java @@ -380,6 +380,7 @@ public class VolumeObject implements VolumeInfo { VolumeObjectTO newVol = (VolumeObjectTO)cpyAnswer.getNewData(); vol.setPath(newVol.getPath()); vol.setSize(newVol.getSize()); + vol.setPoolId(this.getDataStore().getId()); volumeDao.update(vol.getId(), vol); } else if (answer instanceof CreateObjectAnswer) { CreateObjectAnswer createAnswer =(CreateObjectAnswer)answer; @@ -387,6 +388,7 @@ public class VolumeObject implements VolumeInfo { VolumeVO vol = this.volumeDao.findById(this.getId()); vol.setPath(newVol.getPath()); vol.setSize(newVol.getSize()); + vol.setPoolId(this.getDataStore().getId()); volumeDao.update(vol.getId(), vol); } } else if (this.dataStore.getRole() == DataStoreRole.Image) { diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java index 74e01be4892..57dd6608854 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java @@ -358,17 +358,28 @@ public class VolumeServiceImpl implements VolumeService { templateOnPrimaryStoreObj.processEvent(Event.CreateOnlyRequested); } catch (Exception e) { try { - templateOnPrimaryStoreObj = waitForTemplateDownloaded(dataStore, template); - } finally { - if (templateOnPrimaryStoreObj == null) { - VolumeApiResult result = new VolumeApiResult(volume); - result.setResult(e.toString()); - caller.complete(result); - return; - } + templateOnPrimaryStoreObj = waitForTemplateDownloaded(dataStore, template); + } catch(Exception e1) { + s_logger.debug("wait for template:" + template.getId() + " downloading finished, but failed"); + VolumeApiResult result = new VolumeApiResult(volume); + result.setResult(e1.toString()); + caller.complete(result); + return; + } + if (templateOnPrimaryStoreObj == null) { + VolumeApiResult result = new VolumeApiResult(volume); + result.setResult("wait for template:" + template.getId() + " downloading finished, but failed"); + caller.complete(result); + return; + } else { + s_logger.debug("waiting for template:" + template.getId() + " downloading finished, success"); + VolumeApiResult result = new VolumeApiResult(volume); + future.complete(result); + return; } } + try { motionSrv.copyAsync(template, templateOnPrimaryStoreObj, caller); } catch (Exception e) { 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 42099499ce5..ab01c7262e8 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 @@ -170,35 +170,35 @@ public class XenServerStorageResource { String snapshotUUID = null; try { - String volumeUUID = snapshotTO.getVolume().getPath(); - VDI volume = VDI.getByUuid(conn, volumeUUID); + String volumeUUID = snapshotTO.getVolume().getPath(); + VDI volume = VDI.getByUuid(conn, volumeUUID); - VDI snapshot = volume.snapshot(conn, new HashMap()); + VDI snapshot = volume.snapshot(conn, new HashMap()); - if (snapshotName != null) { - snapshot.setNameLabel(conn, snapshotName); + if (snapshotName != null) { + snapshot.setNameLabel(conn, snapshotName); + } + + snapshotUUID = snapshot.getUuid(conn); + String preSnapshotUUID = snapshotTO.getParentSnapshotPath(); + //check if it is a empty snapshot + if( preSnapshotUUID != null) { + SR sr = volume.getSR(conn); + String srUUID = sr.getUuid(conn); + String type = sr.getType(conn); + Boolean isISCSI = IsISCSI(type); + String snapshotParentUUID = getVhdParent(conn, srUUID, snapshotUUID, isISCSI); + + String preSnapshotParentUUID = getVhdParent(conn, srUUID, preSnapshotUUID, isISCSI); + if( snapshotParentUUID != null && snapshotParentUUID.equals(preSnapshotParentUUID)) { + // this is empty snapshot, remove it + snapshot.destroy(conn); + snapshotUUID = preSnapshotUUID; } - - snapshotUUID = snapshot.getUuid(conn); - String preSnapshotUUID = snapshotTO.getPath(); - //check if it is a empty snapshot - if( preSnapshotUUID != null) { - SR sr = volume.getSR(conn); - String srUUID = sr.getUuid(conn); - String type = sr.getType(conn); - Boolean isISCSI = IsISCSI(type); - String snapshotParentUUID = getVhdParent(conn, srUUID, snapshotUUID, isISCSI); - - String preSnapshotParentUUID = getVhdParent(conn, srUUID, preSnapshotUUID, isISCSI); - if( snapshotParentUUID != null && snapshotParentUUID.equals(preSnapshotParentUUID)) { - // this is empty snapshot, remove it - snapshot.destroy(conn); - snapshotUUID = preSnapshotUUID; - } - } - SnapshotObjectTO newSnapshot = new SnapshotObjectTO(); - newSnapshot.setPath(snapshotUUID); - return new CreateObjectAnswer(newSnapshot); + } + SnapshotObjectTO newSnapshot = new SnapshotObjectTO(); + newSnapshot.setPath(snapshotUUID); + return new CreateObjectAnswer(newSnapshot); } catch (XenAPIException e) { details += ", reason: " + e.toString(); s_logger.warn(details, e); 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 6acded982a9..912a11ee66e 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 @@ -190,7 +190,8 @@ public class CloudStackPrimaryDataStoreDriverImpl implements PrimaryDataStoreDri DataTO snapshotTO = snapshot.getTO(); CreateObjectCommand cmd = new CreateObjectCommand(snapshotTO); - Answer answer = storageMgr.sendToPool((StoragePool)snapshot.getDataStore(), null, cmd); + EndPoint ep = this.epSelecotor.select(snapshot); + Answer answer = ep.sendMessage(cmd); result = new CreateCmdResult(null, answer); if (answer != null && !answer.getResult()) { @@ -198,6 +199,7 @@ public class CloudStackPrimaryDataStoreDriverImpl implements PrimaryDataStoreDri } callback.complete(result); + return; } catch (Exception e) { s_logger.debug("Failed to take snapshot: " + snapshot.getId(), e); result = new CreateCmdResult(null, null); diff --git a/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java b/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java index c8a2a0c2e55..f530362896c 100644 --- a/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java +++ b/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java @@ -105,14 +105,14 @@ public class SamplePrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver @Override public void deleteAsync(DataObject vo, AsyncCompletionCallback callback) { - DeleteCommand cmd = new DeleteCommand(vo.getUri()); + /*DeleteCommand cmd = new DeleteCommand(vo.getUri()); EndPoint ep = selector.select(vo); AsyncRpcConext context = new AsyncRpcConext(callback); AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); caller.setCallback(caller.getTarget().deleteCallback(null, null)) .setContext(context); - ep.sendMessageAsync(cmd, caller); + ep.sendMessageAsync(cmd, caller);*/ } public Void deleteCallback(AsyncCallbackDispatcher callback, AsyncRpcConext context) { diff --git a/server/src/com/cloud/storage/VolumeManagerImpl.java b/server/src/com/cloud/storage/VolumeManagerImpl.java index 23e329558c7..39d3ce20c16 100644 --- a/server/src/com/cloud/storage/VolumeManagerImpl.java +++ b/server/src/com/cloud/storage/VolumeManagerImpl.java @@ -2487,6 +2487,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { payload.setSnapshotId(snapshotId); payload.setSnapshotPolicyId(policyId); payload.setAccount(account); + volume.addPayload(payload); return this.volService.takeSnapshot(volume); } diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql index ad8bdc44bd4..a88af23e81e 100644 --- a/setup/db/db/schema-410to420.sql +++ b/setup/db/db/schema-410to420.sql @@ -170,7 +170,7 @@ CREATE TABLE `cloud`.`snapshot_store_ref` ( `parent_snapshot_id` bigint unsigned DEFAULT 0, `install_path` varchar(255), `state` varchar(255) NOT NULL, - `destroyed` tinyint(1) COMMENT 'indicates whether the snapshot_store entry was destroyed by the user or not', + `removed` datetime COMMENT 'date removed if not null', `update_count` bigint unsigned, `updated` datetime, PRIMARY KEY (`id`),