From c921118c5800a2bc326c2dda24a0934ce03f80a8 Mon Sep 17 00:00:00 2001 From: Edison Su Date: Tue, 22 Jan 2013 11:20:03 -0800 Subject: [PATCH] add image create test case --- .../api/storage/CreateCmdResult.java | 8 +++- .../subsystem/api/storage/DataObject.java | 2 +- .../subsystem/api/storage/ScopeType.java | 4 +- .../storage/image/ImageDataFactoryImpl.java | 10 +++- .../storage/image/ImageServiceImpl.java | 5 ++ .../DefaultImageDataStoreDriverImpl.java | 28 ++++++++++- .../image/manager/ImageDataManagerImpl.java | 4 +- .../image/store/HttpDataStoreImpl.java | 17 ++++--- .../storage/image/store/TemplateObject.java | 21 ++++++--- .../DefaultImageDataStoreLifeCycle.java | 12 +++-- .../storage/test/volumeServiceTest.java | 46 +++++++++++++++++-- .../storage/snapshot/SnapshotObject.java | 4 +- ...umeAnswer.java => CreateObjectAnswer.java} | 23 ++++++---- .../storage/db/ObjectInDataStoreDaoImpl.java | 43 +++++++++++++++-- .../storage/db/ObjectInDataStoreVO.java | 36 ++++++++++++++- .../endpoint/DefaultEndPointSelector.java | 6 ++- .../image/datastore/ImageDataStoreHelper.java | 9 +++- .../storage/image/db/ImageDataStoreVO.java | 28 +++++++++++ .../storage/image/db/ImageDataVO.java | 3 +- .../DefaultPrimaryDataStoreDriverImpl.java | 8 ++-- .../storage/volume/VolumeObject.java | 2 +- .../resource/XenServerStorageResource.java | 23 +++++++--- .../cloudstack/storage/test/VolumeTest.java | 4 +- setup/db/4.1-new-db-schema.sql | 34 +++++++++++--- 24 files changed, 313 insertions(+), 67 deletions(-) rename engine/storage/src/org/apache/cloudstack/storage/command/{CreateVolumeAnswer.java => CreateObjectAnswer.java} (70%) diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/CreateCmdResult.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/CreateCmdResult.java index 8934416b177..b6d5b689951 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/CreateCmdResult.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/CreateCmdResult.java @@ -20,12 +20,18 @@ package org.apache.cloudstack.engine.subsystem.api.storage; public class CreateCmdResult extends CommandResult { private String path; - public CreateCmdResult(String path) { + private Long size; + public CreateCmdResult(String path, Long size) { super(); this.path = path; + this.size = size; } public String getPath() { return this.path; } + + public Long getSize() { + return this.size; + } } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataObject.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataObject.java index 1732ec1b24c..812db48cf8c 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataObject.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataObject.java @@ -24,7 +24,7 @@ public interface DataObject { public long getId(); public String getUri(); public DataStore getDataStore(); - public long getSize(); + public Long getSize(); public DataObjectType getType(); public DiskFormat getFormat(); public String getUuid(); diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ScopeType.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ScopeType.java index d1606e18a74..a3d21ce9bef 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ScopeType.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ScopeType.java @@ -21,5 +21,7 @@ package org.apache.cloudstack.engine.subsystem.api.storage; public enum ScopeType { HOST, CLUSTER, - ZONE; + ZONE, + REGION, + GLOBAL; } diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/ImageDataFactoryImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/ImageDataFactoryImpl.java index ea25b7cf452..b6a45b5f6bb 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/ImageDataFactoryImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/ImageDataFactoryImpl.java @@ -40,11 +40,17 @@ public class ImageDataFactoryImpl implements ImageDataFactory { DataStoreManager storeMgr; @Override public TemplateInfo getTemplate(long templateId, DataStore store) { + ImageDataVO templ = imageDataDao.findById(templateId); + if (store == null) { + TemplateObject tmpl = TemplateObject.getTemplate(templ, null); + return tmpl; + } ObjectInDataStoreVO obj = objMap.findObject(templateId, DataObjectType.TEMPLATE, store.getId(), store.getRole()); if (obj == null) { - return null; + TemplateObject tmpl = TemplateObject.getTemplate(templ, null); + return tmpl; } - ImageDataVO templ = imageDataDao.findById(templateId); + TemplateObject tmpl = TemplateObject.getTemplate(templ, store); return tmpl; } diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/ImageServiceImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/ImageServiceImpl.java index 99b57e87733..b1e2a601d6b 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/ImageServiceImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/ImageServiceImpl.java @@ -78,6 +78,7 @@ public class ImageServiceImpl implements ImageService { TemplateInfo templateOnStore = null; if (obj == null) { templateOnStore = objectInDataStoreMgr.create(template, store); + obj = objectInDataStoreMgr.findObject(template.getId(), template.getType(), store.getId(), store.getRole()); } else { CommandResult result = new CommandResult(); result.setResult("duplicate template on the storage"); @@ -128,6 +129,10 @@ public class ImageServiceImpl implements ImageService { ObjectInDataStoreVO obj = context.obj; obj.setInstallPath(callbackResult.getPath()); + if (callbackResult.getSize() != null) { + obj.setSize(callbackResult.getSize()); + } + try { objectInDataStoreMgr.update(templateOnStore, Event.OperationSuccessed); } catch (NoTransitionException e) { diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/driver/DefaultImageDataStoreDriverImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/driver/DefaultImageDataStoreDriverImpl.java index 8c83ff23e70..b713fa66a53 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/driver/DefaultImageDataStoreDriverImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/driver/DefaultImageDataStoreDriverImpl.java @@ -20,6 +20,8 @@ package org.apache.cloudstack.storage.image.driver; import java.util.Set; +import javax.inject.Inject; + import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult; @@ -28,11 +30,15 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; +import org.apache.cloudstack.storage.command.CreateObjectAnswer; +import org.apache.cloudstack.storage.command.CreateObjectCommand; +import org.apache.cloudstack.storage.endpoint.EndPointSelector; import org.apache.cloudstack.storage.image.ImageDataStoreDriver; //http-read-only based image store public class DefaultImageDataStoreDriverImpl implements ImageDataStoreDriver { - + @Inject + EndPointSelector selector; public DefaultImageDataStoreDriverImpl() { } @@ -57,10 +63,28 @@ public class DefaultImageDataStoreDriverImpl implements ImageDataStoreDriver { public void createAsync(DataObject data, AsyncCompletionCallback callback) { //for default http data store, can create http based template/iso - CreateCmdResult result = new CreateCmdResult(""); + CreateCmdResult result = new CreateCmdResult("", null); if (!data.getUri().startsWith("http")) { result.setResult("can't register an image which is not a http link"); callback.complete(result); + return; + } + + if (data.getSize() == null && data.getType() == DataObjectType.TEMPLATE) { + //the template size is unknown during registration, need to find out the size of template + EndPoint ep = selector.select(data); + if (ep == null) { + result.setResult("can't find storage client for:" + data.getId() + "," + data.getType()); + callback.complete(result); + return; + } + CreateObjectCommand createCmd = new CreateObjectCommand(data.getUri()); + CreateObjectAnswer answer = (CreateObjectAnswer)ep.sendMessage(createCmd); + if (answer.getResult()) { + result = new CreateCmdResult(answer.getPath(), answer.getSize()); + } else { + result.setResult(answer.getDetails()); + } } callback.complete(result); diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageDataManagerImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageDataManagerImpl.java index 09303aa1bb1..d90f2b64e24 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageDataManagerImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageDataManagerImpl.java @@ -21,11 +21,13 @@ package org.apache.cloudstack.storage.image.manager; import org.apache.cloudstack.storage.image.TemplateEvent; import org.apache.cloudstack.storage.image.TemplateState; import org.apache.cloudstack.storage.image.db.ImageDataVO; +import org.springframework.stereotype.Component; import com.cloud.utils.fsm.StateMachine2; +@Component public class ImageDataManagerImpl implements ImageDataManager { - private final static StateMachine2 + private final StateMachine2 stateMachine = new StateMachine2(); public ImageDataManagerImpl() { diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/HttpDataStoreImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/HttpDataStoreImpl.java index 1c135a87ed2..e1fdd3d5b63 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/HttpDataStoreImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/HttpDataStoreImpl.java @@ -45,12 +45,16 @@ public class HttpDataStoreImpl implements ImageDataStore { ImageDataDao imageDao; @Inject private ObjectInDataStoreManager objectInStoreMgr; - ImageDataStoreDriver driver; - ImageDataStoreVO imageDataStoreVO; - ImageDataStoreProvider provider; + protected ImageDataStoreDriver driver; + protected ImageDataStoreVO imageDataStoreVO; + protected ImageDataStoreProvider provider; boolean needDownloadToCacheStorage = false; - private HttpDataStoreImpl(ImageDataStoreVO dataStoreVO, ImageDataStoreDriver imageDataStoreDriver, + protected HttpDataStoreImpl() { + + } + + protected void configure(ImageDataStoreVO dataStoreVO, ImageDataStoreDriver imageDataStoreDriver, ImageDataStoreProvider provider) { this.driver = imageDataStoreDriver; this.imageDataStoreVO = dataStoreVO; @@ -59,8 +63,9 @@ public class HttpDataStoreImpl implements ImageDataStore { public static HttpDataStoreImpl getDataStore(ImageDataStoreVO dataStoreVO, ImageDataStoreDriver imageDataStoreDriver, ImageDataStoreProvider provider) { - HttpDataStoreImpl instance = new HttpDataStoreImpl(dataStoreVO, imageDataStoreDriver, provider); - return ComponentContext.inject(instance); + HttpDataStoreImpl instance = (HttpDataStoreImpl)ComponentContext.inject(HttpDataStoreImpl.class); + instance.configure(dataStoreVO, imageDataStoreDriver, provider); + return instance; } @Override diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java index fb4f9ca8e95..f926a66383a 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java @@ -49,14 +49,18 @@ public class TemplateObject implements TemplateInfo { @Inject ObjectInDataStoreManager ojbectInStoreMgr; - private TemplateObject(ImageDataVO template, DataStore dataStore) { + protected TemplateObject() { + } + + protected void configure(ImageDataVO template, DataStore dataStore) { this.imageVO = template; this.dataStore = dataStore; } public static TemplateObject getTemplate(ImageDataVO vo, DataStore store) { - TemplateObject to = new TemplateObject(vo, store); - return ComponentContext.inject(to); + TemplateObject to = ComponentContext.inject(TemplateObject.class); + to.configure(vo, store); + return to; } public void setImageStoreId(long id) { @@ -90,7 +94,7 @@ public class TemplateObject implements TemplateInfo { } else { ObjectInDataStoreVO obj = ojbectInStoreMgr.findObject(this.imageVO.getId(), DataObjectType.TEMPLATE, this.dataStore.getId(), this.dataStore.getRole()); if (obj.getState() != ObjectInDataStoreStateMachine.State.Ready) { - return this.dataStore.getUri() + File.separator + "&objType=" + DataObjectType.TEMPLATE + "&size=" + this.imageVO.getSize(); + return this.dataStore.getUri() + File.separator + "&objType=" + DataObjectType.TEMPLATE + "&size=" + this.imageVO.getSize() + "&path=" + this.imageVO.getUrl(); } else { return this.dataStore.getUri() + File.separator + "&objType=" + DataObjectType.TEMPLATE + "&path=" + obj.getInstallPath(); } @@ -98,9 +102,12 @@ public class TemplateObject implements TemplateInfo { } @Override - public long getSize() { - // TODO Auto-generated method stub - return 0; + public Long getSize() { + if (this.dataStore == null) { + return null; + } + ObjectInDataStoreVO obj = ojbectInStoreMgr.findObject(this.imageVO.getId(), DataObjectType.TEMPLATE, this.dataStore.getId(), this.dataStore.getRole()); + return obj.getSize(); } @Override diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/lifecycle/DefaultImageDataStoreLifeCycle.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/lifecycle/DefaultImageDataStoreLifeCycle.java index 9189963b466..07d52b40682 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/lifecycle/DefaultImageDataStoreLifeCycle.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/lifecycle/DefaultImageDataStoreLifeCycle.java @@ -23,20 +23,26 @@ import javax.inject.Inject; import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; +import org.apache.cloudstack.storage.image.datastore.ImageDataStoreHelper; +import org.apache.cloudstack.storage.image.datastore.ImageDataStoreManager; import org.apache.cloudstack.storage.image.db.ImageDataStoreDao; +import org.apache.cloudstack.storage.image.db.ImageDataStoreVO; public class DefaultImageDataStoreLifeCycle implements ImageDataStoreLifeCycle { @Inject protected ImageDataStoreDao imageStoreDao; - + @Inject + ImageDataStoreHelper imageStoreHelper; + @Inject + ImageDataStoreManager imageStoreMgr; public DefaultImageDataStoreLifeCycle() { } @Override public DataStore initialize(Map dsInfos) { - // TODO Auto-generated method stub - return null; + ImageDataStoreVO ids = imageStoreHelper.createImageDataStore(dsInfos); + return imageStoreMgr.getImageDataStore(ids.getId()); } diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/volumeServiceTest.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/volumeServiceTest.java index 0d4a5402d8d..eeb7b54cc50 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/volumeServiceTest.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/volumeServiceTest.java @@ -32,19 +32,25 @@ import javax.naming.ConfigurationException; import org.apache.cloudstack.engine.cloud.entity.api.TemplateEntity; import org.apache.cloudstack.engine.cloud.entity.api.VolumeEntity; import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope; +import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult; +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.DataStoreLifeCycle; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.ScopeType; import org.apache.cloudstack.engine.subsystem.api.storage.type.RootDisk; +import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.cloudstack.storage.HypervisorHostEndPoint; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreVO; import org.apache.cloudstack.storage.datastore.provider.DataStoreProvider; import org.apache.cloudstack.storage.datastore.provider.DataStoreProviderManager; import org.apache.cloudstack.storage.endpoint.EndPointSelector; +import org.apache.cloudstack.storage.image.ImageDataFactory; import org.apache.cloudstack.storage.image.ImageService; +import org.apache.cloudstack.storage.image.TemplateInfo; import org.apache.cloudstack.storage.image.db.ImageDataDao; import org.apache.cloudstack.storage.image.db.ImageDataVO; import org.apache.cloudstack.storage.volume.VolumeService; @@ -52,6 +58,7 @@ 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.Assert; import org.testng.annotations.Test; import com.cloud.agent.AgentManager; @@ -69,6 +76,7 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.org.Cluster.ClusterType; import com.cloud.org.Managed.ManagedState; import com.cloud.resource.ResourceState; +import com.cloud.storage.Storage; import com.cloud.storage.Storage.TemplateType; @ContextConfiguration(locations={"classpath:/storageContext.xml"}) @@ -99,6 +107,8 @@ public class volumeServiceTest extends CloudStackTestNGBase { AgentManager agentMgr; @Inject EndPointSelector selector; + @Inject + ImageDataFactory imageDataFactory; Long dcId; Long clusterId; Long podId; @@ -188,6 +198,7 @@ public class volumeServiceTest extends CloudStackTestNGBase { eps.add(HypervisorHostEndPoint.getHypervisorHostEndPoint(host.getId(), host.getPrivateIpAddress())); Mockito.when(selector.selectAll(Mockito.any(DataStore.class))).thenReturn(eps); + Mockito.when(selector.select(Mockito.any(DataObject.class))).thenReturn(eps.get(0)); } private ImageDataVO createImageData() { @@ -200,7 +211,7 @@ public class volumeServiceTest extends CloudStackTestNGBase { image.setFeatured(true); image.setRequireHvm(true); image.setBits(64); - //image.setFormat(new VHD().toString()); + image.setFormat(Storage.ImageFormat.VHD.toString()); image.setAccountId(1); image.setEnablePassword(true); image.setEnableSshKey(true); @@ -209,12 +220,20 @@ public class volumeServiceTest extends CloudStackTestNGBase { image.setPrepopulate(true); image.setCrossZones(true); image.setExtractable(true); + + //image.setImageDataStoreId(storeId); image = imageDataDao.persist(image); + return image; } private TemplateEntity createTemplate() { try { + DataStore store = createImageStore(); + ImageDataVO image = createImageData(); + TemplateInfo template = imageDataFactory.getTemplate(image.getId(), store); + AsyncCallFuture future = imageService.createTemplateAsync(template, store); + future.get(); /*imageProviderMgr.configure("image Provider", new HashMap()); ImageDataVO image = createImageData(); ImageDataStoreProvider defaultProvider = imageProviderMgr.getProvider("DefaultProvider"); @@ -225,15 +244,17 @@ public class volumeServiceTest extends CloudStackTestNGBase { return te;*/ return null; } catch (Exception e) { - return null; + Assert.fail("failed", e); + return null; } } + @Test public void createTemplateTest() { createTemplate(); } - @Test + //@Test public void testCreatePrimaryStorage() { DataStoreProvider provider = dataStoreProviderMgr.getDataStoreProvider("default primary data store provider"); Map params = new HashMap(); @@ -261,6 +282,25 @@ public class volumeServiceTest extends CloudStackTestNGBase { ClusterScope scope = new ClusterScope(clusterId, podId, dcId); lifeCycle.attachCluster(store, scope); } + + private DataStore createImageStore() { + DataStoreProvider provider = dataStoreProviderMgr.getDataStoreProvider("default image data store"); + Map params = new HashMap(); + String name = UUID.randomUUID().toString(); + params.put("name", name); + params.put("uuid", name); + params.put("protocol", "http"); + params.put("scope", ScopeType.GLOBAL.toString()); + params.put("provider", Long.toString(provider.getId())); + DataStoreLifeCycle lifeCycle = provider.getLifeCycle(); + DataStore store = lifeCycle.initialize(params); + return store; + } + @Test + public void testcreateImageStore() { + createImageStore(); + } + @Test public PrimaryDataStoreInfo createPrimaryDataStore() { diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java index 8c048439fe4..6ce17973375 100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java @@ -74,9 +74,9 @@ public class SnapshotObject implements SnapshotInfo { } @Override - public long getSize() { + public Long getSize() { // TODO Auto-generated method stub - return 0; + return 0L; } @Override diff --git a/engine/storage/src/org/apache/cloudstack/storage/command/CreateVolumeAnswer.java b/engine/storage/src/org/apache/cloudstack/storage/command/CreateObjectAnswer.java similarity index 70% rename from engine/storage/src/org/apache/cloudstack/storage/command/CreateVolumeAnswer.java rename to engine/storage/src/org/apache/cloudstack/storage/command/CreateObjectAnswer.java index 42674de3cf2..43540de2bd3 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/command/CreateVolumeAnswer.java +++ b/engine/storage/src/org/apache/cloudstack/storage/command/CreateObjectAnswer.java @@ -21,23 +21,28 @@ package org.apache.cloudstack.storage.command; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; -public class CreateVolumeAnswer extends Answer { - private String volumeUuid; - - protected CreateVolumeAnswer() { +public class CreateObjectAnswer extends Answer { + private String path; + private Long size; + protected CreateObjectAnswer() { super(); } - public CreateVolumeAnswer(Command cmd, String volumeUuid) { + public CreateObjectAnswer(Command cmd, String path, Long size) { super(cmd); - this.volumeUuid = volumeUuid; + this.path = path; + this.size = size; } - public CreateVolumeAnswer(Command cmd, boolean status, String result) { + public CreateObjectAnswer(Command cmd, boolean status, String result) { super(cmd, status, result); } - public String getVolumeUuid() { - return this.volumeUuid; + public String getPath() { + return this.path; + } + + public Long getSize() { + return this.size; } } diff --git a/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreDaoImpl.java b/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreDaoImpl.java index ac75a9abed6..7bd9f587404 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreDaoImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreDaoImpl.java @@ -15,21 +15,58 @@ // specific language governing permissions and limitations // under the License. package org.apache.cloudstack.storage.db; +import java.util.Date; + import org.springframework.stereotype.Component; import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine.Event; import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine.State; +import org.apache.cloudstack.storage.volume.db.VolumeVO; +import org.apache.log4j.Logger; import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria2; +import com.cloud.utils.db.SearchCriteriaService; +import com.cloud.utils.db.UpdateBuilder; @Component public class ObjectInDataStoreDaoImpl extends GenericDaoBase implements ObjectInDataStoreDao { - + private static final Logger s_logger = Logger.getLogger(ObjectInDataStoreDaoImpl.class); @Override public boolean updateState(State currentState, Event event, State nextState, ObjectInDataStoreVO vo, Object data) { - // TODO Auto-generated method stub - return false; + Long oldUpdated = vo.getUpdatedCount(); + Date oldUpdatedTime = vo.getUpdated(); + + SearchCriteria sc = this.createSearchCriteria(); + sc.setParameters("id", vo.getId()); + sc.setParameters("state", currentState); + sc.setParameters("updatedCount", vo.getUpdatedCount()); + + vo.incrUpdatedCount(); + + UpdateBuilder builder = getUpdateBuilder(vo); + builder.set(vo, "state", nextState); + builder.set(vo, "updated", new Date()); + + int rows = update((ObjectInDataStoreVO) vo, sc); + if (rows == 0 && s_logger.isDebugEnabled()) { + ObjectInDataStoreVO dbVol = findByIdIncludingRemoved(vo.getId()); + if (dbVol != null) { + StringBuilder str = new StringBuilder("Unable to update ").append(vo.toString()); + str.append(": DB Data={id=").append(dbVol.getId()).append("; state=").append(dbVol.getState()).append("; updatecount=").append(dbVol.getUpdatedCount()).append(";updatedTime=") + .append(dbVol.getUpdated()); + str.append(": New Data={id=").append(vo.getId()).append("; state=").append(nextState).append("; event=").append(event).append("; updatecount=").append(vo.getUpdatedCount()) + .append("; updatedTime=").append(vo.getUpdated()); + str.append(": stale Data={id=").append(vo.getId()).append("; state=").append(currentState).append("; event=").append(event).append("; updatecount=").append(oldUpdated) + .append("; updatedTime=").append(oldUpdatedTime); + } else { + s_logger.debug("Unable to update objectIndatastore: id=" + vo.getId() + ", as there is no such object exists in the database anymore"); + } + } + return rows > 0; } } diff --git a/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreVO.java b/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreVO.java index 91506e455af..e208d4072ea 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreVO.java +++ b/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreVO.java @@ -51,7 +51,7 @@ public class ObjectInDataStoreVO implements StateObject params) { - ImageDataStoreVO store = new ImageDataStoreVO(); + ImageDataStoreVO store = imageStoreDao.findByUuid(params.get("uuid")); + if (store != null) { + throw new CloudRuntimeException("duplicate uuid"); + } + store = new ImageDataStoreVO(); store.setName(params.get("name")); store.setProtocol(params.get("protocol")); store.setProvider(Long.parseLong(params.get("provider"))); + store.setScope(Enum.valueOf(ScopeType.class, params.get("scope"))); + store.setUuid(params.get("uuid")); store = imageStoreDao.persist(store); return store; } diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageDataStoreVO.java b/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageDataStoreVO.java index 0eb7536c6af..c7b8e2d1228 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageDataStoreVO.java +++ b/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageDataStoreVO.java @@ -20,10 +20,14 @@ package org.apache.cloudstack.storage.image.db; import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; import javax.persistence.Id; import javax.persistence.Table; import javax.persistence.TableGenerator; +import org.apache.cloudstack.engine.subsystem.api.storage.ScopeType; + @Entity @Table(name = "image_data_store") public class ImageDataStoreVO { @@ -35,6 +39,9 @@ public class ImageDataStoreVO { @Column(name = "name", nullable = false) private String name; + @Column(name = "uuid", nullable = false) + private String uuid; + @Column(name = "protocol", nullable = false) private String protocol; @@ -44,6 +51,11 @@ public class ImageDataStoreVO { @Column(name = "data_center_id") private long dcId; + @Column(name = "scope") + @Enumerated(value = EnumType.STRING) + private ScopeType scope; + + public long getId() { return this.id; } @@ -79,4 +91,20 @@ public class ImageDataStoreVO { public long getDcId() { return this.dcId; } + + public ScopeType getScope() { + return this.scope; + } + + public void setScope(ScopeType scope) { + this.scope = scope; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public String getUuid() { + return this.uuid; + } } diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageDataVO.java b/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageDataVO.java index f7274c3931c..38025969053 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageDataVO.java +++ b/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageDataVO.java @@ -80,7 +80,7 @@ public class ImageDataVO implements Identity, StateObject { @Temporal(value = TemporalType.TIMESTAMP) @Column(name = GenericDao.CREATED_COLUMN) - private final Date created = null; + private Date created = null; @Column(name = GenericDao.REMOVED) @Temporal(TemporalType.TIMESTAMP) @@ -155,6 +155,7 @@ public class ImageDataVO implements Identity, StateObject { public ImageDataVO() { this.uuid = UUID.randomUUID().toString(); this.state = TemplateState.Allocated; + this.created = new Date(); } public boolean getEnablePassword() { diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/driver/DefaultPrimaryDataStoreDriverImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/driver/DefaultPrimaryDataStoreDriverImpl.java index ab57d6e80c8..39b2aef86b2 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/driver/DefaultPrimaryDataStoreDriverImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/driver/DefaultPrimaryDataStoreDriverImpl.java @@ -30,7 +30,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.CreateObjectCommand; -import org.apache.cloudstack.storage.command.CreateVolumeAnswer; +import org.apache.cloudstack.storage.command.CreateObjectAnswer; import org.apache.cloudstack.storage.command.DeleteCommand; import org.apache.cloudstack.storage.endpoint.EndPointSelector; import org.apache.cloudstack.storage.snapshot.SnapshotInfo; @@ -70,11 +70,11 @@ public class DefaultPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver public Void createAsyncCallback(AsyncCallbackDispatcher callback, CreateVolumeContext context) { CreateCmdResult result = null; - CreateVolumeAnswer volAnswer = (CreateVolumeAnswer) callback.getResult(); + CreateObjectAnswer volAnswer = (CreateObjectAnswer) callback.getResult(); if (volAnswer.getResult()) { - result = new CreateCmdResult(volAnswer.getVolumeUuid()); + result = new CreateCmdResult(volAnswer.getPath(), volAnswer.getSize()); } else { - result = new CreateCmdResult(""); + result = new CreateCmdResult("", null); result.setResult(volAnswer.getDetails()); } 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 3b7600c8f29..5ae587c323c 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 @@ -78,7 +78,7 @@ public class VolumeObject implements VolumeInfo { } @Override - public long getSize() { + public Long getSize() { return volumeVO.getSize(); } 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 b0ddb8eb091..1aa96c39980 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 @@ -36,7 +36,7 @@ import org.apache.cloudstack.storage.command.CopyCmd; import org.apache.cloudstack.storage.command.CopyCmdAnswer; import org.apache.cloudstack.storage.command.CreateObjectCommand; import org.apache.cloudstack.storage.command.CreatePrimaryDataStoreCmd; -import org.apache.cloudstack.storage.command.CreateVolumeAnswer; +import org.apache.cloudstack.storage.command.CreateObjectAnswer; import org.apache.cloudstack.storage.command.CreateVolumeFromBaseImageCommand; import org.apache.cloudstack.storage.command.StorageSubSystemCommand; import org.apache.cloudstack.storage.datastore.protocol.DataStoreProtocol; @@ -130,7 +130,12 @@ public class XenServerStorageResource { return params; } - protected CreateVolumeAnswer execute(CreateObjectCommand cmd) { + protected CreateObjectAnswer getTemplateSize(CreateObjectCommand cmd, String templateUrl) { + Connection conn = hypervisorResource.getConnection(); + long size = this.getTemplateSize(conn, templateUrl); + return new CreateObjectAnswer(cmd, templateUrl, size); + } + protected CreateObjectAnswer execute(CreateObjectCommand cmd) { String uriString = cmd.getObjectUri(); Map params = null; @@ -139,7 +144,11 @@ public class XenServerStorageResource { params = getParameters(uri); } catch (URISyntaxException e1) { s_logger.debug("uri exception", e1); - return new CreateVolumeAnswer(cmd, false, e1.toString()); + return new CreateObjectAnswer(cmd, false, e1.toString()); + } + + if (params.get("objType").equalsIgnoreCase("template")) { + return getTemplateSize(cmd, params.get("path")); } long size = Long.parseLong(params.get("size")); @@ -154,7 +163,7 @@ public class XenServerStorageResource { vdi = createVdi(conn, name, primaryDataStoreSR, size); VDI.Record record = vdi.getRecord(conn); result = true; - return new CreateVolumeAnswer(cmd, record.uuid); + return new CreateObjectAnswer(cmd, record.uuid, record.virtualSize); } catch (BadServerResponse e) { s_logger.debug("Failed to create volume", e); errorMsg = e.toString(); @@ -174,7 +183,7 @@ public class XenServerStorageResource { } } - return new CreateVolumeAnswer(cmd, false, errorMsg); + return new CreateObjectAnswer(cmd, false, errorMsg); } protected Answer execute(DeleteVolumeCommand cmd) { @@ -208,7 +217,7 @@ public class XenServerStorageResource { VDI baseVdi = VDI.getByUuid(conn, baseImage.getPathOnPrimaryDataStore()); VDI newVol = baseVdi.createClone(conn, new HashMap()); newVol.setNameLabel(conn, volume.getName()); - return new CreateVolumeAnswer(cmd, newVol.getUuid(conn)); + return new CreateObjectAnswer(cmd, newVol.getUuid(conn), newVol.getVirtualSize(conn)); } catch (BadServerResponse e) { return new Answer(cmd, false, e.toString()); } catch (XenAPIException e) { @@ -579,7 +588,7 @@ public class XenServerStorageResource { params = getParameters(uri); } catch (URISyntaxException e1) { s_logger.debug("uri exception", e1); - return new CreateVolumeAnswer(cmd, false, e1.toString()); + return new CreateObjectAnswer(cmd, false, e1.toString()); } SR sr = hypervisorResource.getStorageRepository(conn, params.get("storeUuid")); hypervisorResource.setupHeartbeatSr(conn, sr, false); diff --git a/plugins/storage/volume/solidfire/test/org/apache/cloudstack/storage/test/VolumeTest.java b/plugins/storage/volume/solidfire/test/org/apache/cloudstack/storage/test/VolumeTest.java index 1bd51b21427..20cb8fb60f6 100644 --- a/plugins/storage/volume/solidfire/test/org/apache/cloudstack/storage/test/VolumeTest.java +++ b/plugins/storage/volume/solidfire/test/org/apache/cloudstack/storage/test/VolumeTest.java @@ -26,7 +26,7 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo; -import org.apache.cloudstack.storage.command.CreateVolumeAnswer; +import org.apache.cloudstack.storage.command.CreateObjectAnswer; import org.apache.cloudstack.storage.command.CreateVolumeFromBaseImageCommand; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.provider.PrimaryDataStoreProvider; @@ -112,7 +112,7 @@ public class VolumeTest { results.add(host); Mockito.when(hostDao.listAll()).thenReturn(results); Mockito.when(hostDao.findHypervisorHostInCluster(Mockito.anyLong())).thenReturn(results); - CreateVolumeAnswer createVolumeFromImageAnswer = new CreateVolumeAnswer(null,UUID.randomUUID().toString()); + CreateObjectAnswer createVolumeFromImageAnswer = new CreateObjectAnswer(null,UUID.randomUUID().toString()); try { Mockito.when(agentMgr.send(Mockito.anyLong(), Mockito.any(CreateVolumeFromBaseImageCommand.class))).thenReturn(createVolumeFromImageAnswer); diff --git a/setup/db/4.1-new-db-schema.sql b/setup/db/4.1-new-db-schema.sql index fb809207710..d5415373eec 100644 --- a/setup/db/4.1-new-db-schema.sql +++ b/setup/db/4.1-new-db-schema.sql @@ -16,6 +16,8 @@ -- under the License. alter table vm_template add image_data_store_id bigint unsigned; +alter table vm_template add size bigint unsigned; +alter table vm_template add state varchar(255); alter table storage_pool add storage_provider_id bigint unsigned; alter table storage_pool add scope varchar(255); alter table storage_pool modify id bigint unsigned AUTO_INCREMENT UNIQUE NOT NULL; @@ -48,6 +50,26 @@ alter table cluster add column owner varchar(255); alter table cluster add column created datetime COMMENT 'date created'; alter table cluster add column lastUpdated datetime COMMENT 'last updated'; alter table cluster add column engine_state varchar(32) NOT NULL DEFAULT 'Disabled' COMMENT 'the engine state of the zone'; +CREATE TABLE `cloud`.`object_datastore_ref` ( + `id` bigint unsigned NOT NULL auto_increment, + `datastore_id` bigint unsigned NOT NULL, + `datastore_role` varchar(255) NOT NULL, + `object_id` bigint unsigned NOT NULL, + `object_type` varchar(255) NOT NULL, + `created` DATETIME NOT NULL, + `last_updated` DATETIME, + `job_id` varchar(255), + `download_pct` int(10) unsigned, + `download_state` varchar(255), + `error_str` varchar(255), + `local_path` varchar(255), + `install_path` varchar(255), + `size` bigint unsigned COMMENT 'the size of the template on the pool', + `state` varchar(255) NOT NULL, + `update_count` bigint unsigned NOT NULL, + `updated` DATETIME NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; CREATE TABLE `cloud`.`data_store_provider` ( `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', @@ -56,18 +78,16 @@ CREATE TABLE `cloud`.`data_store_provider` ( PRIMARY KEY(`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE `cloud`.`image_data_store_provider` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', - `name` varchar(255) NOT NULL COMMENT 'name of data store provider', - PRIMARY KEY(`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - CREATE TABLE `cloud`.`image_data_store` ( `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', `name` varchar(255) NOT NULL COMMENT 'name of data store', `image_provider_id` bigint unsigned NOT NULL COMMENT 'id of image_data_store_provider', + `protocol` varchar(255) NOT NULL COMMENT 'protocol of data store', + `data_center_id` bigint unsigned COMMENT 'datacenter id of data store', + `scope` varchar(255) COMMENT 'scope of data store', + `uuid` varchar(255) COMMENT 'uuid of data store', PRIMARY KEY(`id`), - CONSTRAINT `fk_tags__image_data_store_provider_id` FOREIGN KEY(`image_provider_id`) REFERENCES `image_data_store_provider`(`id`) + CONSTRAINT `fk_tags__image_data_store_provider_id` FOREIGN KEY(`image_provider_id`) REFERENCES `data_store_provider`(`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `cloud`.`vm_compute_tags` (